일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 비동기파일업로드
- 블록 만들기
- cookie-parser 만들어보기
- 세션으로 로그인 구현
- css기초
- 라우터미들웨어 분리
- JWT 하드코딩
- JWT 만들어보기
- useEffect clean up
- 라우터와 미들웨어
- FormData()
- 아이디 중복체크기능
- JWT 로그인 기능 구현
- 시퀄라이즈 기본설정
- nodejs파일업로드
- mysql wsl
- next 매개변수
- Uncaught Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>
- express session
- OAuth 카카오
- express실행
- 라우터 분리
- 라우트 매개변수
- express.static
- ws 라이브러리
- javascript기초
- useContext
- buffer.from
- node.js path
- express router
- Today
- Total
즐코
solidity 시작 - 스마트 컨트랙트 배포와 실행 본문
트랜잭션 객체를 통해 스마트 컨트랙트 내용을 이더리움 네트워크 상에 던지는데 이걸 스마트 컨트랙트를 배포한다고 표현한다.
스마트 컨트랙트 배포를 위해서는 스마트 컨트랙트 내용이 바이트코드로 변환되어 트랜잭션 객체 속에 데이터로 담겨야하는데, 바이트 코드로 변환하기 전 코드는 solidity 로 작성해준다.
솔리디티로 스마트 컨트랙트를 작성하는 방법과 컴파일을 거쳐 이 스마트 컨트랙트가 어떤 흐름으로 배포되고 실행되는지만 간단하게 정리하였다. 솔리디티 문법은 차차 알아갈 예정임
Solidity 시작하기
1. VSC 상에서 solidity extension 깔아주기
2. solidity 기본 작성
루트 디렉토리 내에 Contracts 폴더를 하나 만들어주고 HelloWorld.sol 파일을 만들어봄
타입스크립트로 클래스를 작성하는 것과 비슷하다. 아래 소스코드는 타입스크립트로 만들어본 HelloWorld 클래스이다.
class HelloWorld{
public text: string;
constructor(){
this.text = "Hello World";
}
public getText():string {
return this.text;
}
public setText(value: string):void {
this.text = value;
}
}
솔리디티로는 아래와 같이 작성한다.
1. 저작권 문제로 라이센스를 맨 첫줄에 추가해줘야한다. 주석 처리해서 넣어줘야한다.
// SPDX-License-Identifier: MIT
2. pragma
특정 컴파일러의 버전을 표기하기 위함이다. 버전 앞에 ^ 를 붙이면 그 버전 이상 이라는 뜻이다.
pragma solidity ^0.8.15
3. contract
class와 비슷한 개념이다. 인스턴스를 생성하기 위한 하나의 틀인데, class와 차이가 있다면 인스턴스가 1개만 생성된다는 것이다.
1/ 상태 변수 선언
: 타입스크립트와 비슷하게 [데이터 타입] [변수명] 으로 정의해준다. 해당 코드에선 string 형태의 text라는 변수가 상태 변수이다.
- 상태 변수란? : 블록체인에 영원히 기록되는 변수를 의미한다고 함.. 밑에서 스마트 컨트랙트를 실행시킬 때 call 메소드를 통해서 상태 변수값을 가져올 수 있다. 자세한 건 차차 알아가는걸로,,
2/ 생성자 함수 constructor
: 컨트랙트 생성 시 생성자 함수가 실행되어 컨트랜트 상태가 초기화된다.
현재 코드에서 text라는 상태변수는 "Hello World"가 초기값이라고 볼 수 있다.
3/ 메소드 function
: JS 클래스 문법에서 앞에 public/private 라는 키워드를 붙여 클래스 내의 메소드/속성에 대한 접근성을 컨트롤한 것처럼 솔리디티에서도 public과 같은 키워드를 써주는데 클래스문법과 달리 함수명 이후에 써준다. 타입스크립트처럼 인자와 리턴값도 데이터타입을 명시해준다.
view, returns, memory 와 같은 키워드들은 이후에 솔리디티 문법을 좀 더 자세히 배울 때 익히는 걸로 ㅋ
// Contracts/HelloWorld.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
contract HelloWorld{
string text;
constructor(){
text = "Hello World";
}
function getText() public view returns(string memory){
return text;
}
function setText(string memory value) public {
text = value;
}
}
3. solidity code compile
작성한 솔리디티 코드를 evm에서 돌리려면 evm이 해석할 수 있는 바이너리 코드로 컴파일을 해줘야 한다.
윈도우, 맥에서 다 작용하는 solc라는 컴파일러를 설치해준다.
$ npm i solc
$ npx solc [옵션] [컴파일하고싶은 파일의 경로]
$ npx solc --bin --abi ./Contracts/HelloWorld.sol
컴파일의 목적은 ?
1. bytecode 파일 생성 (.bin)
2. ABI 파일 생성 Application Binary Interface (.abi)
ABI : Application Binary Interface
컨트랙트 내 함수를 호출하거나 데이터를 얻을 때 사용하는 api라고 보면 된다.
컨트랙트는 고유한 주소(CA)값을 가지고 블록체인 상에 바이트코드로 저장된다. 따라서, 컨트랙트 실행자가 이 컨트랙트를 실행시키기 위해 데이터를 어떻게 어떤 형태로 전달해야할지 이 16진수로 이루어진 바이트코드로는 알 수 없다. 이 때, solidity로 작성한 스마트 컨트랙트를 json 형태로 변환한 ABI를 통해서 바이트 코드로 변환된 함수, 변수 등의 필요한 정보에 접근할 수 있고, 유저가 이더리움 상에 요청한 데이터를 보내줄 때 어떤 형태로 보내줄 지에 대해서도 결정해준다.
이때 smart contract는 이전에 했던 코인 거래와 달리, 누가(from) 어떤 코드(data)를 배포할거냐가 중요하기 때문에 트랜잭션 객체 상에 to, value 속성은 필요없다.
이제 geth를 실행하여 geth 콘솔창에서 코드 데이터를 가진 트랜잭션을 발생시키면서 스마트 컨트랙트 배포와 실행을 연습해본다..
4. geth 실행하여 스마트컨트랙트 배포, 실행해보기
트랜잭션 실행 시 아래와 같은 메소드를 사용하는데, 아래 두 가지 방법을 보통 쓴다.
1- eth.unlockAccount('계정', '비번') && eth.sendTransaction({from: '계정', data: '바이트코드' })
2- 또는 personal.sendTransaction({},'비번')
1/ geth 실행
geth 실행 시에 아래와 같은 옵션을 추가해주면, 특정 계정은 비밀번호를 계속 넣어주지 않아도 된다.
우선, geth 실행 전 node/node/password 파일을 생성하여 개인키의 복호화를 위해 계정 생성 시 넣어줬던 비번을 기입해준다.
unlock 부분의 숫자는 eth.accounts 했을 때 나오는 계정 배열 상에서의 인덱스값을 나타낸다.
--allow-insecure-unlock --unlock "0,1" --password "./node/password"
$ geth --networkid 1004 --ws
--ws.port 7979
--ws.origins "*"
--ws.api "eth,admin,miner,txpool,web3,personal,net"
--ws.addr "0.0.0.0"
--datadir ./node
--allow-insecure-unlock
--unlock "0"
--password "./node/password"
2/ 변수 할당
게스-콘솔창에서 아래와 같이 값을 저장할 것이다. const, let같은 키워드가 없어도 아래와 같이 변수가 선언/할당되어진다.
bytecode 와 abi 변수에다가 컴파일 시 만들어진 .bin, .abi를 복사해서 할당해준다.
이 때 bytecode는 16진수 바이트코드이므로 앞에 0x를 따로 붙여준다.
$ bytecode = "0x60806040523480156200001157600080fd5b506040518060400160405280600b81526020017f48656c6c6f20576f726c6400000000000000000000000000000000000000000081525060009081620000589190620002d9565b50620003c0565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620000e157607f821691505b602082108103620000f757620000f662000099565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620001617fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000122565b6200016d868362000122565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620001ba620001b4620001ae8462000185565b6200018f565b62000185565b9050919050565b6000819050919050565b620001d68362000199565b620001ee620001e582620001c1565b8484546200012f565b825550505050565b600090565b62000205620001f6565b62000212818484620001cb565b505050565b5b818110156200023a576200022e600082620001fb565b60018101905062000218565b5050565b601f82111562000289576200025381620000fd565b6200025e8462000112565b810160208510156200026e578190505b620002866200027d8562000112565b83018262000217565b50505b505050565b600082821c905092915050565b6000620002ae600019846008026200028e565b1980831691505092915050565b6000620002c983836200029b565b9150826002028217905092915050565b620002e4826200005f565b67ffffffffffffffff8111156200030057620002ff6200006a565b5b6200030c8254620000c8565b620003198282856200023e565b600060209050601f8311600181146200035157600084156200033c578287015190505b620003488582620002bb565b865550620003b8565b601f1984166200036186620000fd565b60005b828110156200038b5784890151825560018201915060208501945060208101905062000364565b86831015620003ab5784890151620003a7601f8916826200029b565b8355505b6001600288020188555050505b505050505050565b61068580620003d06000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635d3a1f9d1461003b578063e00fe2eb14610057575b600080fd5b61005560048036038101906100509190610274565b610075565b005b61005f610088565b60405161006c9190610345565b60405180910390f35b8060009081610084919061057d565b5050565b60606000805461009790610396565b80601f01602080910402602001604051908101604052809291908181526020018280546100c390610396565b80156101105780601f106100e557610100808354040283529160200191610110565b820191906000526020600020905b8154815290600101906020018083116100f357829003601f168201915b5050505050905090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61018182610138565b810181811067ffffffffffffffff821117156101a05761019f610149565b5b80604052505050565b60006101b361011a565b90506101bf8282610178565b919050565b600067ffffffffffffffff8211156101df576101de610149565b5b6101e882610138565b9050602081019050919050565b82818337600083830152505050565b6000610217610212846101c4565b6101a9565b90508281526020810184848401111561023357610232610133565b5b61023e8482856101f5565b509392505050565b600082601f83011261025b5761025a61012e565b5b813561026b848260208601610204565b91505092915050565b60006020828403121561028a57610289610124565b5b600082013567ffffffffffffffff8111156102a8576102a7610129565b5b6102b484828501610246565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156102f75780820151818401526020810190506102dc565b83811115610306576000848401525b50505050565b6000610317826102bd565b61032181856102c8565b93506103318185602086016102d9565b61033a81610138565b840191505092915050565b6000602082019050818103600083015261035f818461030c565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806103ae57607f821691505b6020821081036103c1576103c0610367565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026104297fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826103ec565b61043386836103ec565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b600061047a6104756104708461044b565b610455565b61044b565b9050919050565b6000819050919050565b6104948361045f565b6104a86104a082610481565b8484546103f9565b825550505050565b600090565b6104bd6104b0565b6104c881848461048b565b505050565b5b818110156104ec576104e16000826104b5565b6001810190506104ce565b5050565b601f82111561053157610502816103c7565b61050b846103dc565b8101602085101561051a578190505b61052e610526856103dc565b8301826104cd565b50505b505050565b600082821c905092915050565b600061055460001984600802610536565b1980831691505092915050565b600061056d8383610543565b9150826002028217905092915050565b610586826102bd565b67ffffffffffffffff81111561059f5761059e610149565b5b6105a98254610396565b6105b48282856104f0565b600060209050601f8311600181146105e757600084156105d5578287015190505b6105df8582610561565b865550610647565b601f1984166105f5866103c7565b60005b8281101561061d578489015182556001820191506020850194506020810190506105f8565b8683101561063a5784890151610636601f891682610543565b8355505b6001600288020188555050505b50505050505056fea2646970667358221220236c63b36a96ae7199144eaf98018ed4d697ef43d02bc4e0906ae979d8d1630c64736f6c634300080f0033"
$ abi = [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"getText","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"value","type":"string"}],"name":"setText","outputs":[],"stateMutability":"nonpayable","type":"function"}]
3/ 스마트 컨트랙트 배포를 위한 트랜잭션 발생!
위에서 설명한대로 to, value없이 from과 data 속성만 넣은 txObject 를 만들어준다.
현재 from은 eth.coinbase로 되어있지만, 스마트 컨트랙트를 배포, 즉 트랜잭션을 발생시킬 계정을 넣어주는 자리이다.
$ txObject = {from: eth.coinbase, data: bytecode }
트랜잭션 발생
(원래는 두번째 인자로 계정 비밀번호를 넣어주어야 하지만 위에서 unlock 옵션으로 geth를 실행했기 때문에 생략해도 된다!)
$ eth.sendTransaction(txObject)
4/ 채굴 고고
miner.start(1) -> miner.stop()
5/ 트랜잭션 세부 내용 확인해보기
- Transaction
$ eth.getTransaction("0xf2d726621e74221389dba711aa4b629cc2a210e1681320e4e099403adbd2a7c7")
기존 트랜잭션 만들 땐 input이 없었는데, 현재 트랜잭션 input 내용엔 data로 넣은 bytecode가 들어갔다.
이 input값으로 해당 거래가 스마트 컨트랙트용인지 아닌지 구분할 수 있겠다.
- Transaction Receipt
$ eth.getTransactionReceipt("0xf2d726621e74221389dba711aa4b629cc2a210e1681320e4e099403adbd2a7c7")
ContractAddress 값이 생겼다. 이게 바로 CA라고한다. (이전 포스팅에서 살짝 언급 https://yjleekr.tistory.com/87 )
- 스마트 컨트랙트가 이더리움 네트워크 상에 배포될 때 생성되는 값
(마이닝 하기 전에는 getTransactionReceipt 값을 받을 수 없다)
- 어떤 특정 블럭에 어떤 트랜잭션 내용인지를 나타내기위한 컨트랙트의 고유키값이라고 보면 쉽다.
이 CA를 통해서 이더리움 네트워크 상에 배포된 스마트 컨트랙트를 실행시킬 수 있다.
즉, 스마트 컨트랙트에 작성된 함수를 호출하거나 상태 변수를 가져올 때 이 CA를 사용하여 스마트 컨트랙트에 접근할 수 있다!
6/ abi를 포함한 contract 객체 생성
스마트 컨트랙트를 json 형태로 변환한 ABI 를 통해서 geth 콘솔창에서 해당 컨트랙트 내부의 메소드를 사용할 수 있게 된다.
출력값을 보면 abi 내용이 추가되어 있음을 확인할 수 있다.
이더리움 네트워크에 배포된 스마트 컨트랙트는 바이트 코드이기 때문에 해당 내용을 실행시키려면 abi를 사용하여 인코딩을 해줘야한다.
따라서, abi 파일 내용을 포함하고 있는 하나의 contract 객체를 만들어줬다고 보면 된다.
$ contract = eth.contract(abi)
7/ 이더리움 네트워크 상에 배포된 컨트랙트에 접근 w/CA!
위에서 설명한대로 스마트 컨트랙트가 블록 채굴로 인해 이더리움 네트워크 상에 배포가 되면 CA (컨트랙트 고유키값)를 얻을 수 있는데, 이 고유한 CA를 사용하여 해당 컨트랙트에 접근할 수 있다. 이를 instance라는 변수에 할당해주었다.
$ instance = contract.at("0x3e2834fac92e0e5e32e445e6fc5b58af9753ee25")
출력값을 보면 솔리디티 코드 상에서 미리 만들어둔 함수가 있다!
- CA를 사용하여 접근한 컨트랙트 객체인 instance를 가지고 컨트랙트 내부의 함수 실행
$ instance.getText({from:eth.coinbase})
인자값으로 컨트랙트를 실행할 계정을 넣어준다.
해당 계정이 컨트랙트 내부의 함수를 실행함으로써 트랜잭션이 생성되어 tx hash값이 출력된다.
"0x7475674340749613043b566c9f28dce0839abe9c8f4674cabdf8e0139fd5adce"
- 컨트랙트 내부의 상태 변수 가져오기 : call() 메소드
$ instance.getText.call()
call() 메소드는 그저 상태 변수를 확인하고 불러오는 용도라 EVM을 돌리지 않기 때문에 가스비가 측정되지 않는다.
** eth.sendTransaction(txObject) 대신 contract.new(txObject)로 스마트 컨트랙트 배포해보기
$ contract = eth.contract(abi)
$ instance = contract.new(txObject) // 트랜잭션 배포
// 아래 스크린샷처럼 txHash 생성
// 이더리움 네트워크 상의 배포를 위해 마이닝 실행
$ miner.start(1)
$ miner.stop()
마이닝 이후, instance 확인 - 스마트 컨트랙트 작성 시 만들었던 getText, setText 함수 존재 여부 확인
상태 변수값을 바꾸는 함수 setText를 실행시킨다는 건 evm을 돌려서 상태변수의 저장 공간을 바꾼다는 의미이다.
call() 메소드와 달리 상태 변수를 변경시키는 것 자체가 트랜잭션을 발생시키기 때문에 수수료를 지불해야한다.
그래서 두번째 인자값으로 트랜잭션을 발생시켜서 수수료를 지불할 계정을 넣어줘야한다.
$ instance.setText('hello yj', {from: eth.coinbase})
// txHash 값 출력됨 "0x8d2d122eddbd3946c1edede35c1a978483b9a15b71d17ddd0761368ceeca805f"
따라서,
txpool에 거래가 쌓임 -> 마이닝 고고 -> instance.getText.call() 하면 바뀐 상태 변수값이 출력됨을 확인할 수 있다!
'BlockChain' 카테고리의 다른 글
truffle - 스마트 컨트랙트 개발 프레임워크 (0) | 2022.07.12 |
---|---|
JS로 스마트 컨트랙트 컴파일, 배포 및 실행 (0) | 2022.07.12 |
RPC 로 geth와 통신 / puppeth / 메타마스크-private 네트워크 연동 (0) | 2022.07.02 |
geth로 네트워크 돌려보기 / private 네트워크 구축해보기 (0) | 2022.07.01 |
React프론트-메타마스크 연동 (ft.WEB3) (0) | 2022.06.30 |