[멋쟁이 사자처럼 블록체인 스쿨 3기] 23-06-12

임형석·2023년 6월 12일
0

Web3.js

터미널에서 web3.js 를 이용해 지갑을 설정하고 컨트랙트의 함수를 실행시켜 보았다.

먼저, 간단한 컨트랙트를 작성하고 테스트 넷에 배포한다.

contract AAA {
  uint public a = 100;

  function setA(uint _a) public {
    a = _a;
  }

  function add(uint _a, uint _b) public pure returns(uint) {
    return _a+_b;
  }
}

그 다음, 터미널에서 web3.js 가 설치된 폴더로 이동한 후 아래의 코드를 순차적으로 실행한다.

var {Web3} = require('web3')

var web3 = new Web3('INFURA API')

var privateKey = '0x PRIVATE KEY' => 개인 키 설정. 0x 로 시작해야 함.

var account = web3.eth.accounts.privateKeyToAccount(privateKey) => 개인 키를 이용해 지갑을 만들고 account 라는 변수로 설정.

web3.eth.accounts.wallet.add(account) => 지갑 관리.

var abi = [ABI] => CA 의 ABI 를 변수로 설정.

var c_address = 'CA' => CA 를 변수로 설정.

var contract = new web3.eth.Contract(abi, c_address) => ABI, CA 를 이용해 컨트랙트 변수를 설정.

contract.methods.a().call().then(console.log) => 위에서 불러온 컨트랙트의 a() 함수를 call. 상태변수 확인.

var tx = {from : account.address, to : c_address, gas : 300000, gasPrice : 3000000, data : contract.methods.setA(123456789).encodeABI()}
=> 함수를 실행 할 트랜잭션을 설정. setA(123456789) 로 실행.

var signPromise = web3.eth.accounts.signTransaction(tx, account.privateKey) => 위에서 설정한 트랜잭션과 개인키를 이용해 서명.

signPromise.then((signedTx)=>{var sentTx = web3.eth.sendSignedTransaction(signedTx.raw || signedTx.rawTransaction); sentTx.on("receipt",receipt=>{console.log(receipt)})}) => 서명을 테스트 넷으로 보냄.

contract.methods.a().call().then(console.log) => 위에서 보낸 서명으로 상태변수 a가 바뀌었는지 확인.


Ethereum Nonce

이더리움의 논스는 각 계정에서 보내는 트랜잭션 마다 할당된 번호이다. 트랜잭션마다 논스는 1씩 증가한다.

왜 논스가 필요할까?

논스는 중복되지 않으며 순차적으로 증가하는데, 만약 같은 논스에 여러 트랜잭션을 받았을 경우, 해당 논스 중 가장 가스비를 많이 지불한 트랜잭션의 거래만을 처리한다.
이더리움에서는 이러한 방식으로 이중 지불 문제를 해결했다.

위에서 실습한 내용에서도 논스 에러를 마주쳤다.

이더리움에는 현재 내 컨트랙트가 논스 값이 1. 다음 논스 값은 2이어야 하지만 서명이 바뀌지 않았기에, 트랜잭션을 일으키면 too low nonce 라는 에러가 뜬다.


event, emit

이더리움의 event 는 기록을 남기는 것으로, 이 기록을 읽거나 추적할 수 있다.

emit event명 형식으로 함수가 실행될 때, 이벤트를 기록할 수 있다.

이렇게 기록되는 이벤트들은 추적 할 수 있다. (listen 또는 monitoring..)

아래 컨트랙트를 작성하고 실험해보았다.

contract event_emit_two {
    event ADD(string add, uint result);
    event SUB(string sub, uint result);
    event MUL(string mul, uint result);
    event DIV(string div, uint result);

    function add(uint a, uint b) public returns(uint c){
        c = a + b;
        emit ADD("Added", c);
        // pure , view 는 emit 불가능.
    }
    
    function add2(uint _a, uint _b) public pure returns(uint){
        return _a +_b;
    }

        function sub(uint a, uint b) public returns(uint c){
        c = a + b;
        emit SUB("sub", c);
        // pure , view 는 emit 불가능.
    }

        function mul(uint a, uint b) public returns(uint c){
        c = a + b;
        emit MUL("mul", c);
        // pure , view 는 emit 불가능.
    }

        function div(uint a, uint b) public returns(uint c){
        c = a + b;
        emit DIV("div", c);
        // pure , view 는 emit 불가능.
    }
}

먼저, event emit 을 기록하지 않는 함수 add2 를 실행했다.

아래 사진과 같이 함수가 call 되었지만 가스비는 소모하지 않았으며, logs 는 비어있다.

두 번쨰로, event emit 을 기록하는 함수 add 를 실행했다.

아래 사진과 같이 함수가 실행되며 EVM 을 통하므로 가스비가 소모된다. 또한, logs 에 event : ADD 라는 기록이 남게된다.

event 를 emit 할때는 pure 또는 view 는 사용할 수 없다.

EVM 을 통해 가스비를 소모하며 체인에 기록하기 때문이다.


event, emit & web3.js

web3.js 를 이용하여 event 를 추적하기.(monitoring 또는 listen..)

위에서 web3.js 를 이용하여 함수를 실행하고 상태변수의 값을 받아왔다.

이걸 응용해서 emit 을 하고, event 의 값을 변경이 있을 때마다 받아올 수 있다.

저번 게시물에서 infura 의 Https API 발급을 받았는데,

이번에는 WebSockets API 를 받는다.

위의 event emit 컨트랙트를 테스트넷에 배포한 후,

배포한 컨트랙트를 이용해 contract 변수 설정 까지.
(첫 번째 터미널 : https API) (두번 째 터미널 : websocket API)

contract.events.ADD({}, {fromBlock : 0 , toBlock : 'latest'}).on('data', function(event) {console.log(event);})

tx 를 add(1,3) 으로 설정.

var tx = {from : account.address, to : c_address, gas : 300000, gasPrice : 3000000, data : contract.methods.add(3,1).encodeABI()}

signPromise 로 서명.

var signPromise = web3.eth.accounts.signTransaction(tx, account.privateKey)

함수 실행.

signPromise.then((signedTx)=>{var sentTx = web3.eth.sendSignedTransaction(signedTx.raw || signedTx.rawTransaction); sentTx.on("receipt",receipt=>{console.log(receipt)})})

실행을 하면 아래와 같은 pending 이 뜬다. 전송이 끝날 때까지 기다린다.

전송이 완료되면 아래와 같은 사진이 뜬다.

tx 해시를 보자. (0x486f...)

그리고 두번 째 터미널을 확인하면, tx 해시가 같은 것을 볼 수 있고,

add(1,3) 함수의 값이 4n 으로 표시되어있다.

vscode 의 터미널에서 실행했다면 두번째 터미널에서는 자동으로 갱신이 되는데,

이렇게 파워쉘을 각각 열어서 실행했다면, 키보드의 아래화살표를 한번 눌러주면 갱신이 된다. (첫 번째 터미널의 pending 이 끝난 후)

0개의 댓글