BlockChain Tech

Transaction Data 살펴보기 (feat. ABI)

RyuK-H 2019. 4. 10. 12:13

 Transaction을 구성하는 여러가지 요소들이 있다.

대부분 쉽게 이해할 수 있는 반면, Data라는 친구는 명확하게 어떤 것을 해주는 항목인지 알기 힘들다.

 

오늘은 Transaction의 Data가 어떤 역할을 하는지 알아보도록 하자.

 

'etherscan.io'에서 조회한 Transaction의 모습

Transaction의 구성요소

  • nonce: 해당 계좌에서 발생된 Transaction의 수
  • from: receive address
  • to: sender address
  • value: 수신자에게 보내는 Ether 수량
  • gas limit: 가스의 최대 사용량
  • gas price: 가스 가격
  • data: 가변길이의 바이너리 데이터
  • v, r, s: ECDSA 서명 구성 요소

Transfer Transaction

    var transaction = {
    nonce: web3.toHex(nonce),
    gasPrice: eb3.toHex(web3.toWei(1, 'Gwei').toNumber()),
    gasLimit: web3.toHex(100000),
    to: '0xe456064545F872B311aE7432689a0fECE90C9a29',
    value: web3.toHex(web3.toWei(0.1, 'ether').toNumber()),
    data: '0x0'
};

일반적인 송금에서는 data에 아무런 값을 넣어주지 않아도 된다. (않아 보다는 할 필요가 전혀 없다.)

 

Contract Execution Transaction

    var transaction = {
    nonce: web3.toHex(nonce),
    gasPrice: eb3.toHex(web3.toWei(1, 'Gwei').toNumber()),
    gasLimit: web3.toHex(5000000),
    to: contractAddress,
    value: '0x0',
    data: '0x18b0c3fd'
};

Contract Execution Transaction의 경우 receive address가 일반 EA(External Account )가 아닌 CA(Contract Account)인 점

그리고, data에 어떠한 값이 들어간 점이 달라졌다.


 

Transaction을 '어떠한 명령'을 수행하라는 주문서라고 생각해보자.

 

Transfer

(1)From(2)To에게 (3)Value 만큼을 (4)GasLimit * GasPrice 만큼의 수수료를 내고 수행해달라!

 

굉장히 단순하고 쉽게 실행이 되지만, Contract Method를 호출하게될 때는 어떤 형대로 진행이 될까?

 

Contract Execution

(1)From (2)Contract에게 (3)Value 만큼을 (4)GasLimit * GasPrice 만큼의 수수료를 내고 (5)Data에 16진수를 수행해달라!

 


Data에 16진수

16진수라는 데이터를 가지고, 어떤 함수에 어떤 인자값을 넣었는지 어떻게 알 수 있을까?

Solidity docs에서 그 해답을 찾을 수 있다. (링크)

Contract를 호출 할 때에는 ABI Spec에 맞추어 data를 변환 해야하고, 그 data를 Transaction에 추가한다. 

pragma solidity >=0.4.16 <0.7.0;

contract Foo {
  function bar(bytes3[2] memory) public pure {}
  function baz(uint32 x, bool y) public pure returns (bool r) { r = x > 32 || y; }
  function sam(bytes memory, bool, uint[] memory) public pure {}
}

(1) CA(Contract Account)의 Contract Address를 통하여 'Foo' Contract의 접근

 

(2) 호출하고 싶은 Method ID 입력

>  Method ID는 각 function마다 다른 값을 갖을 수 있다.

 the first 4 bytes of the Keccak hash of the ASCII form of the signature

>  ASCII 서명 방식의 Keccak해시 값의 처음 4 bytes

>  bytes4(keccak256('transferFrom(address,address,uint256)')) 를 통해 얻을 수 있다.

>  정말 말 그대로 해당 함수의 interface를 해시화 하고, 앞의 4 bytes를 가지고 오면 Method ID가 된다.

>  Solidity에서는 'selector'라는 Method를 통해 Method ID를 추출할 수 있다. (ex. this.bar.selector)

 

bytes4(keccak256('function bar(bytes3[2])'))

=> 0xfce353f6

 

(3) 인자값이 들어가야할 경우 32bytes 형식으로 변환하여 Method ID 뒤에 연결한다.

>  ["abc", "def"] 라는 인자를 function bar와 함께 호출하고 싶다면

>  abc = 0x6162630000000000000000000000000000000000000000000000000000000000

>  def = 0x6465660000000000000000000000000000000000000000000000000000000000

>  이대로 Method ID와 합성을 해주면 된다.

 

Transaction에 포함시킬 Data

"0xfce353f661626300000000000000000000000000000000000000000000000000000000006465660000000000000000000000000000000000000000000000000000000000"

 

Argument가 왜 저런 모습의 16진수가 되는건가요?

- 사전에 EVM에서 약속된 ABI Spec에 따라 변환되어야 하기 때문에 그렇다.

> Encoding 규칙에 대해서 나열할 순 없으니 (링크) 를 참조하자!

 

https://solidity.readthedocs.io/en/v0.4.21/abi-spec.html


 

Etheruem ABI Encoding / Decoding은 다양한 사이트에서 실험해볼 수 있다.

https://adibas03.github.io/online-ethereum-abi-encoder-decoder/#/decode

 

string "ryu" Encoding 결과
Encoding 결과 값을 다시 Decoding

 

[추가] Ethereum Contract ABI Converter

https://abi.sonnguyen.ws/

https://abi.hashex.org/