前回、Contractのデプロイまで行きました。今回は、実際にContractに実装したコードを実行させてみます。
1 2 3 |
> curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from": "0x738090af28dca4ff5cc7f9dfc82237b52d7519c5", "to": "0x9001d8425c434c229813fbe9770fdbadb6be3a15", "data": "0x07a10d220000000000000000000000000000000000000000000000000000000000000006"}], "id": 8}' localhost:8545 {"id":8,"jsonrpc":"2.0","result":"0xd83586580405da75fa87ec03b8f7201d1ba6a74bed097b859d41a5e2cf48ed57"} |
デプロイのときと同じように、eth_sendTransactionメソッドでトランザクションを実行します。パラメータのfromとtoはもちろん、トランザクションの送信元のアカウントと受信先であるContractのアドレスです。
公式にも書いてありますけど、dataパラメータは少し面倒なものです。このパラメータは、呼び出すメソッドとパラメータを定義するバイトコードを持ちます。ここに、今回調べるといったABIというのが関わっているらしいです。ちょっとドキュメントを参照してみます。
冒頭の”Basic design”によると、Contractの外部とのインターフェース定義はコンパイル時に決まってしまい、静的であると。Introspectionメカニズムは存在しませんとも書いてある。Introspectionとは何ぞや?調べると、内省とか内観と出てきますね。東洋かぶれのあちらの人が作った単語か?と思ってしまいますが。
つまりは、Contractの内部仕様を外から調べるすべは用意されていないということのようです。仕様を知っているアカウントしか、Contractを実行できないということです。ABIとは、Application Binary Interfaceのことで、Contractを使用する側は、呼び出し時にこの定義をバイトコードとして渡してやる必要があるということのようですね。コンパイル時に返ってきたのは、ABIの文字列表現のようです。
ABIは、以下二つをエンコードした値を含みます。
- 呼び出そうとするメソッドの名前と、引数の型
- メソッドに渡す実引数
1.については、Keccak hash(SHA-3)をかけた結果の最初の4バイトをエンコード結果とします。gethをインストールしてあるなら、この値は次のように得ることができます。
1 2 |
> web3.sha3("multiply(uint)").substring(0, 8) "07a10d22" |
2.については、Argument encodingに各データ型のエンコード方法が書いてあります。たくさんあります。とりあえず、今回のようにuintのパラメータひとつだけで、6を与えるとすると32バイトの6ですので以下のようになります。
1 |
0000000000000000000000000000000000000000000000000000000000000006 |
dataパラメータに渡す値は、2つを結合した次の値になります。
1 |
07a10d220000000000000000000000000000000000000000000000000000000000000006 |
よって、Contract Multiply7のmultiplyメソッドを呼び出すトランザクションは、再掲しますが以下のようになります。
1 2 3 |
> curl --data '{"jsonrpc":"2.0","method": "eth_sendTransaction", "params": [{"from": "0x738090af28dca4ff5cc7f9dfc82237b52d7519c5", "to": "0x9001d8425c434c229813fbe9770fdbadb6be3a15", "data": "0x07a10d220000000000000000000000000000000000000000000000000000000000000006"}], "id": 8}' localhost:8545 {"id":8,"jsonrpc":"2.0","result":"0xd83586580405da75fa87ec03b8f7201d1ba6a74bed097b859d41a5e2cf48ed57"} |
しばらく待ち、マイニングが成功してトランザクションがブロックに登録されたら、結果をeth_getTransactionReceiptで取得できます。
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 |
> curl --data '{"jsonrpc":"2.0","method": "eth_getTransactionReceipt", "params": ["0xd83586580405da75fa87ec03b8f7201d1ba6a74bed097b859d41a5e2cf48ed57"], "id": 9}' localhost:8545 { "id":9, "jsonrpc":"2.0", "result": { "transactionHash":"0xd83586580405da75fa87ec03b8f7201d1ba6a74bed097b859d41a5e2cf48ed57", "transactionIndex":"0x0", "blockNumber":"0x179", "blockHash":"0xc004c55595330967c8c0190ddb0e63cfd78ff4fd7b378c3a5a28b5e5cb087633", "cumulativeGasUsed":"0x5867", "gasUsed":"0x5867", "contractAddress":null, "logs":[ {"address":"0x9001d8425c434c229813fbe9770fdbadb6be3a15", "topics":["0x24abdb5865df5079dcc5ac590ff6f01d5c16edbc5fab4e195d9febd1114503da"], "data":"0x000000000000000000000000000000000000000000000000000000000000002a", "blockNumber":"0x179", "logIndex":"0x0", "blockHash":"0xc004c55595330967c8c0190ddb0e63cfd78ff4fd7b378c3a5a28b5e5cb087633", "transactionHash":"0xd83586580405da75fa87ec03b8f7201d1ba6a74bed097b859d41a5e2cf48ed57", "transactionIndex":"0x0" }] } } |
resultのlogsの中にあるdataが結果のようですね。
1 |
0x000000000000000000000000000000000000000000000000000000000000002a |
これは10進数では42ですので、6*7=42 ですから正しい結果が返ってきています。