dukDukz
[블록체인] 스마트 컨트렉트 간단 실습 + Web3 란? 본문
smart contract 간단하게 만들어보기
# 스마트 컨트랙트
: 실제 구동시켜서 해보는것을 할 것이다.
= 코드 실행 (솔리디티) / 스크립트 실행
# 가나쉬
: 메인넷 테스트넷 없이 로컬에서 간단히 돌리는것.
알트코인의 데몬을 간단하게 만든다.(이더리움)
+ 테스트용 100 이더가 채워져있는 10개의 주소가 주어진다. 총 1000개
# 스마트 컨트랙트를 위한 세팅
nodejs 환경에서 세팅이 가능하다.
Truffle
Ganashe
를 node js 환경에서 설치가 가능하다.
$ npm install -g truffle
$ npm install -g ganache-cli
$ npm install web3
# web3 란 무엇인가?
→ rpc 통신을 쉽게 구현할 수 있게 도와주는 라이브러리이다.
# web3 사용 X
거래소에서 join 을 했다고 하면
Next 에서 Server 측으로 요청을 보낸다.
그러면 Server -> Demon 에 요청을 보낸다. 응답을 받아서 다시 Next 에 보낸다.
알트코인 rpc 통신을 하려면
[server 측 내용]
express 를 설치하고
request 를 설치하고
request 에 rpc 통신을 했던 내용을 넣어줘서 응답을 받아서 처리함.
[client react, next, html 페이지] 에서 rpc 통신을 한다고 하면,
# web 3 사용 O
서버가 없어지게 된다.
네트워크 요청은 대부분 비동기 통신이다.
Promise 객체에 대해 좀 더 이해할 수 있는 능력이 필요하다.
오늘은 간단하게 특정 js 파일에서 데몬에게 바로 요청을 보내는 것을 할 것이다.
# ganache / truffle 설치
$ npm install -g ganache-cli
-g : global 설치 : node js 환경이 아니더라도 사용하겠다?
$ npm install -g truffle
web 설치는
$ npm init
$ npm install web3
# 설치되었는지 확인하는 법
$ truffle version
$ ganache-cli --host 0.0.0.0
(npx ganache-cli --host 0.0.0.0)
가나슈는 데몬 즉 서버인것이다.
뭔가 구동이 되어야 하므로 터미널을 하나 새로 열고
여기서 구동시킨다.
# 가스 (gas)
이더리움의 스마트 컨트랙트를 배포하고 실행할 때 사용되는 수수료이다.
hello 라는 글자를 0x44109F218cc5E294a86f0B9F744Cb2eDB88B7BDE 이 주소값에 보내겠다고 해도 수수료를 지불해야 한다.
연산 O(n) 의 횟수에 따라 gas 를 지불하게 된다.
block{
block header{
nonce :
merkelroot :
priviousHash :
...
}
blcok body {
data : ["hello"]
}
}
# 가스 가격 (gas price)
스마트 컨트랙트를 발생할 때, 이것을 작성한 사람이 설정하는 가스 가격이다.
# 가스 한도 (gas limit)
1200 만원 수수료가 1.5 이더 => 수수료가 너무 큰데?
그래서 한도를 정할 수 있다. (최대 수수료)
Gas Limit
==================
6721975
우리는 gas limit 을 쓰겠다.
# 가나쉬 데몬 실행중
Listening on 0.0.0.0:8545
curl "쉘 스크립트"
쉘이라는 단어는 Linux 에서 사용가능한것.
1. eth_accounts
2. eth_getBalance [주소값] => 특정 주소에 있는 eth 확인
wsl 켜고
$ curl -X POST -d '' http://127.0.0.1:8545
2. 계정확인 eth_accounts
$ curl -X POST -d '{"jsonrpc":"2.0","method":"eth_accounts"}' http://127.0.0.1:8545
3. 이더 개수 확인 getBalance
$ curl -X POST -d '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x44109F218cc5E294a86f0B9F744Cb2eDB88B7BDE"]}' http://127.0.0.1:8545
rpc 통신을 통해서 특정 주소에 있는 이더리움 개수를 구할 수 있다.
1) 이제부터 단위 개념을 배워보자
"result":"0x56bc75e2d63100000"
16진수인데 10진수로 변환하면
100,000,000,000,000,000,000 [wei]= 100[ETH]
1 ETH = 10^18 wei
라고 할 수 있다.
rpc 통신을 curl 하지 않고
web3 라이브러리를 통해서 js 코드로 작성해서 해보자
example.js 생성
1. getAccounts()
const Web3 = require('web3')
let connection = new Web3('http://127.0.0.1:8545')
connection.eth.getAccounts() // rpc 통신 요청 - promise 로 하면 됨
.then(data=>{
console.log(data);
})
node example.js 하면
아까와 같은 결과 값을 얻을 수 있다.
2. getBalance()
//eth_getBalance
connection.eth.getBalance('0x44109F218cc5E294a86f0B9F744Cb2eDB88B7BDE')
.then(data=>{
console.log(data);
// 16진수 return 이 아니라 10진수로 return 해줌
})
하고 node example
100000000000000000000 [wei]
-> 10진수로 리턴해준다는..
# web3
rpc 통신하는 부분인데
이전에는 request 를 통해서 작업을 했었다.
# 스마트 컨트랙트를 작성해보자
스마트 컨트랙트 = 코드를 실행시킨다.
어떤 코드를 실행시키는 걸까??
-> 솔리디티 코드를 rpc 통신을 통해서 실행시키는 것이다.
솔리디티 코드와 js 코드가 두개가 존재하는 것인데
솔리디티를 실행시키려면 어떻게 해야 하나??
1. 컴파일 과정을 해야한다.
hello.sol -> 컴파일 -> 두가지 파일 생성됨 (abi, bin 파일 생성됨)
# abi = application binary interface
런타임시 (실행시) 바이너리 코드와 데이터 실행시키기 위한 JSON 파일
# bin
바이너리 파일로 결과물을 준다.
이 두가지 파일을 가지고 실행시키면 원하는 값을 얻을 수 있다.
코드를 실행시키는 키 값이라고 생각하면 되겠다.
1) 솔리디티 코드를 작성
-> vscode 에서 작성하면 됨.
2) 솔리디티 코드를 컴파일 한다.
# 컴파일 도구 설치
$ npm install -g solc
# 확인하기
$ solcjs --version
0.8.9+commit.e5eed63a.Emscripten.clang
# 실행하는 방법
$ solc --abi --bin [파일명]
# 파일 생성
hello.sol
특정 변수의 내용을 넣고
함수안에서 특정 변수를 호출해보자
contract hello{
string value;
constructor(){
value = "hello world"; // memory에 공간 확보하고 넣음
}
function get() public view returns(string memory){
return value;
}
}
1. 왜 여기는 returns 에 s 가 붙냐? - 이건 약속임
2. string 만 그냥 쓰면 오류남 - version up 되면서 생긴 부분 => (string memory)
파일 시스템; 파일에 저장된 내용을 가져올거냐
or 메모리에 저장된 내용을 가져올거냐?
3. 컴파일 하기
$ solcjs --bin --abi .\hello.sol
안되면 앞에 npx
컴파일 되면
hello_sol_hello.abi
hello_sol_hello.bin 이 만들어짐
[파일명]_[확장자]_[컨트랙트명]
4. 이 두가지 파일 + web3를 통해서 (rpc 통신을 통해서) body 영역에 넣어주기
example.js
const contract = new connection.eth.Contract(ABI_CODE,ADDRESS)
이렇게 하는데 지금은 주소 안쓰니까 주소는 생략
const ABI_CODE = JSON.parse('.abi 파일에 있는 애 복사')
const BYTECODE = '.bin 파일에 있는 애 복사'
const contract = new connection.eth.Contract(ABI_CODE)
// 여기 안에 인자값(ABI_CODE)은 string 이 아니라 json 이 되어야함
// 배포 (코드 실행한다.) deploy
contract.deploy({
data : BYTECODE
})
.send({
from:'0x44109F218cc5E294a86f0B9F744Cb2eDB88B7BDE', // 공개 키
gas:'6721975' //gas limit 값 넣음
})
.then(data=>{
// send 의 결과값이 promise 객체로 반환된다.
console.log(data);
})
코드 실행하면 무조건 gas(수수료) 가 발생함
그럼 누구한테 수수료 청구할지?
총 gas 비용이 필요
node example
하면 엄청나게 긴 객체가 나온다..
...
methods: {
get: [Function: bound _createTxObject],
'0x6d4ce63c': [Function: bound _createTxObject],
'get()': [Function: bound _createTxObject]
},
이런 결과가 나오는데 get 에 접근해서 호출해야됨
// send 다음에
.then(data=>{
return data.methods.get().call()
// 얘도 결과가 promise 객체로 나옴
})
.then(result=>{
console.log(result)
})
그럼 결과가 hello world 로 나옴
...
options: {
address: [Getter/Setter],
jsonInterface: [Getter/Setter],
data: undefined,
from: undefined,
gasPrice: undefined,
gas: undefined
},
이렇게 나오는것도 있는데 여기서 address 를 찍어보자
.then(data=>{
console.log(data.options.address);
})
0x7aCC3Ef176203D1f818103B84cC5Bf8602a861C0
// 영수증
그리고 코드 실행을 하면 할수록
//eth_getBalance
connection.eth.getBalance('0x44109F218cc5E294a86f0B9F744Cb2eDB88B7BDE')
.then(data=>{
console.log(data);
})
이렇게 하면 getbalance 가 나오는데 계속 줄어들게 된다.
비용 소모 없이 영수증에 있는 내용을 보고싶다면?
0x7aCC3Ef176203D1f818103B84cC5Bf8602a861C0
그래서 일단은 21~42 번째 주석처리하고
const Web3 = require('web3')
let connection = new Web3('http://127.0.0.1:8545')
// 스마트 컨트랙트
const ABI_CODE = JSON.parse('[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"get","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]')
const BYTECODE = '608060405234801561001057600080fd5b506040518060400160405280600b81526020017f68656c6c6f20776f726c640000000000000000000000000000000000000000008152506000908051906020019061005c929190610062565b50610166565b82805461006e90610134565b90600052602060002090601f01602090048101928261009057600085556100d7565b82601f106100a957805160ff19168380011785556100d7565b828001600101855582156100d7579182015b828111156100d65782518255916020019190600101906100bb565b5b5090506100e491906100e8565b5090565b5b808211156101015760008160009055506001016100e9565b5090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061014c57607f821691505b602082108114156101605761015f610105565b5b50919050565b610232806101756000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80636d4ce63c14610030575b600080fd5b61003861004e565b6040516100459190610179565b60405180910390f35b60606000805461005d906101ca565b80601f0160208091040260200160405190810160405280929190818152602001828054610089906101ca565b80156100d65780601f106100ab576101008083540402835291602001916100d6565b820191906000526020600020905b8154815290600101906020018083116100b957829003601f168201915b5050505050905090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561011a5780820151818401526020810190506100ff565b83811115610129576000848401525b50505050565b6000601f19601f8301169050919050565b600061014b826100e0565b61015581856100eb565b93506101658185602086016100fc565b61016e8161012f565b840191505092915050565b600060208201905081810360008301526101938184610140565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806101e257607f821691505b602082108114156101f6576101f561019b565b5b5091905056fea26469706673582212203d17c006dceed0364ffed7d8294acf7d42605dbfc3672b21d1a7c20cb9f948dc64736f6c63430008090033'
const helloContract = new connection.eth.Contract(ABI_CODE,'0x7aCC3Ef176203D1f818103B84cC5Bf8602a861C0')
helloContract.methods.get().call()
.then(data=>{
console.log(data);
})
이렇게 작성하고 node example.js 하면 hello world 가 잘 뜨고
getbalance 부분에 숫자가 줄지 않는다.
추가 되어있던것을 가져다가 보는것.
deploy 는 배포 (body 에 내용 추가)
이거는 내용을 보여주는것.
'웹 개발 > 블록체인' 카테고리의 다른 글
[블록체인] 투표앱 만들기 (0) | 2021.10.12 |
---|---|
[블록체인] 거래소 기본 개념 (0) | 2021.10.12 |
[블록체인] 솔리디티 언어 연습 (좀비) (0) | 2021.10.11 |
[블록체인] 이더리움 (0) | 2021.10.11 |
[블록체인] 블록체인의 개념 (0) | 2021.10.11 |