Ethereum Internal Transaction에 대하여

2 minute read

Internal 트랜잭션이란?

일반적인 EOA -> CA 트랜잭션을 A라고 할 때, A가 실행되면서 CA의 내부에서 A에 대한 결과로 서브 트랜잭션들이 수행되는데 이것을 Internal Transaction이라고 한다. On-chain 상에 기록되는 정보는 오직 A 까지이며 서브 트랜잭션들은 On-chain 상에 기록되지 않는다. 그렇다면, Internal 트랜잭션 정보들은 어떻게 얻을 수 있을까?

Internal 트랜잭션 특징

  • Normal Tx가 성공했다고 해서 모든 internal tx가 성공하는 것은 아니다. (특정 internal tx 실패 시, 해당 서브트리의 internal tx 모두 실패)
  • Internal Tx의 gas는 tx에 종속된다.
  • on-chain 상에 기록되지 않기 때문에, geth, parity 등의 이더리움 클라이언트 API를 사용해야 한다.
  • Internal Tx를 통해 이더 전송, function call, contract creation 등이 가능하다. (주체가 EOA일 뿐이다)
  • Normal Tx에 종속돼서 일어난다. (parent hash가 존재)

Internal 트랜잭션 정보 얻는 법

web3 같은 라이브러리를 이용해서는 해당 정보들을 얻어올 수 없고 geth, parity 같은 이더리움 클라이언트 노드를 이용해야 한다. (여기서는 parity를 사용한다.)

https://openethereum.github.io/JSONRPC-trace-module#trace_block

위의 링크를 들어가보면, trace module이라고 적혀있는 것을 확인할 수 있다. 이 말 처럼, Internal 트랜잭션을 얻어오기 위해선 특정 블록, 특정 트랜잭션 단위로
해당 정보를 replay 시켜야 한다. 이더스캔을 써보면 Internal Txns 필드를 볼 수 있는데, 이 칸 역시 이때까지의 모든 블록을 replay해서 얻은 정보를 가공해 제공하는 것이라고 생각한다.

  const res = await axios.post('parity rpc 호출 가능한 uri', {
    method: 'trace_block',
    params: ['0x...'],
    id: 1,
    jsonrpc: '2.0',
  });

node.js에서는 위와 같은 방식으로 호출이 가능하다.

Internal 트랜잭션 정보

  • 5개 (내가 확인한 개수)의 주요 인터널 트랜잭션이 존재한다.
  • type이 ‘call’인 것과 ‘create’, ‘suicide’이 존재하며, 두 타입에 대해서 action, result 필드가 미묘하게 달라지는 것을 확인할 수 있다.

1. delegate call

  • A 컨트랙트에서 B 컨트랙트 호출 시, B의 스토리지를 변경시키지 않고, B의 코드를 A에서 실행한다. (caller의 상태만 바꿀 수 있고, callee의 상태 를 바꿀 수 없다.)
  • msg.sender, msg.value가 컨트랙트 A 호출 시와 같고, 변동되지 않는다.
  action: {
    callType: 'delegatecall',
    from: '0xae76c84c9262cdb9abc0c2c8888e62db8e22a0bf',
    gas: '0xdcb4',
    input: '0x6b1d4db700000000000000000000000000000000000000000000002025873626bea40000000000000000000000000000000000000000000000000000000000005eb0177b',
    to: '0x2157a7894439191e520825fe9399ab8655e0f708',
    value: '0x827329bfb5e68c9'
  },
  blockHash: '0xaa20f7bde5be60603f11a45fc4923aab7552be775403fc00c2e6b805e6297dbe',
  blockNumber: 10000000,
  result: {
    gasUsed: '0x7a47',
    output: '0x0000000000000000000000000000000000000000000000000827329bfb5e68c9'
  },
  subtraces: 2,
  traceAddress: [ 0 ],
  transactionHash: '0x3829fcf58a8357fd765b7f2916083405dddcde69dac837a5346e666fb6cd0add',
  transactionPosition: 18,
  type: 'call'
}

2. static call

  • 상태를 변경하거나 읽는 경우를 구분하기 위해 사용하며, 다른 컨트랙트로 redirect되어도 상태 변경이 일어나지 않음을 보장한다.
  • msg.sender는 컨트랙트 A가 된다.
{
  action: {
    callType: 'staticcall',
    from: '0xae76c84c9262cdb9abc0c2c8888e62db8e22a0bf',
    gas: '0xc805',
    input: '0x70a08231000000000000000000000000ae76c84c9262cdb9abc0c2c8888e62db8e22a0bf',
    to: '0xe41d2489571d322189246dafa5ebde1f4699f498',
    value: '0x0'
  },
  blockHash: '0xaa20f7bde5be60603f11a45fc4923aab7552be775403fc00c2e6b805e6297dbe',
  blockNumber: 10000000,
  result: {
    gasUsed: '0x4d5',
    output: '0x0000000000000000000000000000000000000000000037b98d72379c5068c813'
  },
  subtraces: 0,
  traceAddress: [ 0, 0 ],
  transactionHash: '0x3829fcf58a8357fd765b7f2916083405dddcde69dac837a5346e666fb6cd0add',
  transactionPosition: 18,
  type: 'call'
}

3. call

  • A 컨트랙트에서 B 컨트랙트 호출 시, B의 스토리지를 변경시키고, msg.sender는 컨트랙트 A가 된다.
  • 실제 이더 전송, 토큰 전송 등의 주체가 되는 콜타입
{
  action: {
    callType: 'call',
    from: '0xae76c84c9262cdb9abc0c2c8888e62db8e22a0bf',
    gas: '0xa979',
    input: '0xa9059cbb0000000000000000000000008455a0a413b5304a6780f4a249315de75640094100000000000000000000000000000000000000000000002025873626bea40000',
    to: '0xe41d2489571d322189246dafa5ebde1f4699f498',
    value: '0x0'
  },
  blockHash: '0xaa20f7bde5be60603f11a45fc4923aab7552be775403fc00c2e6b805e6297dbe',
  blockNumber: 10000000,
  result: {
    gasUsed: '0x41d2',
    output: '0x0000000000000000000000000000000000000000000000000000000000000001'
  },
  subtraces: 0,
  traceAddress: [ 0, 1 ],
  transactionHash: '0x3829fcf58a8357fd765b7f2916083405dddcde69dac837a5346e666fb6cd0add',
  transactionPosition: 18,
  type: 'call'
}

4. create

  • 새로운 컨트랙트를 생성한다.
{
  action: {
    creationMethod: 'create',
    from: '0x8a91c9a16cd62693649d80afa85a09dbbdcb8508',
    gas: '0x16e230',
    init: '0x608060405234801561001057600080fd5b506040516020806101f6833981018060405261002f9190810190610109565b60008054600160a060020a031916600160a060020a0383811691909117918290556040517f095ea7b300000000000000000000000000000000000000000000000000000000815291169063095ea7b39061009190339060001990600401610165565b602060405180830381600087803b1580156100ab57600080fd5b505af11580156100bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506100e3919081019061012f565b50506101a5565b60006100f68251610180565b9392505050565b60006100f6825161018f565b60006020828403121561011b57600080fd5b600061012784846100ea565b949350505050565b60006020828403121561014157600080fd5b600061012784846100fd565b61015681610180565b82525050565b61015681610194565b60408101610173828561014d565b6100f6602083018461015c565b600160a060020a031690565b90565b151590565b600061019f8261018c565b92915050565b6043806101b36000396000f3006080604052600080fd00a265627a7a723058204db7b4c23d84c45bc6bfca313e9bf687bc7d21aece12952499166b478d5fb0496c6578706572696d656e74616cf500370000000000000000000000008e870d67f660d95d5be530380d0ec0bd388289e1',
    value: '0x0'
  },
  blockHash: '0xaa20f7bde5be60603f11a45fc4923aab7552be775403fc00c2e6b805e6297dbe',
  blockNumber: 10000000,
  result: {
    address: '0xbce5fe052b25e422550f6012fdd1941f9353f001',
    code: '0x6080604052600080fd00a265627a7a723058204db7b4c23d84c45bc6bfca313e9bf687bc7d21aece12952499166b478d5fb0496c6578706572696d656e74616cf50037',
    gasUsed: '0xfd0b'
  },
  subtraces: 1,
  traceAddress: [ 0 ],
  transactionHash: '0xa9b04ff42f93868886c1258ba59967ceb6aafa0118655032210a867bdad7cff1',
  transactionPosition: 24,
  type: 'create'
}

5. suicide (self-destruct)

  • 배포된 컨트랙트에 존재하는 이더를 특정 주소로 보내고, 더 이상 사용하지 않는 컨트랙트라는 걸 명시

self-destruct 관련 정보

    {
        "action": {
            "address": "0x6f268ae132e4a05197cdd0ca4cb0f29e92edfe2f",
            "balance": "0x0",
            "refundAddress": "0x0000000000b3f879cb30fe243b4dfee438691c04"
        },
        "blockHash": "0xb73b9ffc32d91b4b712aaa281993668a2345fafcb150c3fd3c0586efeb87070a",
        "blockNumber": 10000004,
        "result": null,
        "subtraces": 0,
        "traceAddress": [
            5,
            0,
            0,
            0
        ],
        "transactionHash": "0x3a0fda35d511cf590ac5138dd95604cff5a922722b5d1a751c7b20b37ead55d1",
        "transactionPosition": 115,
        "type": "suicide"
    }

Categories:

Updated: