如何使用 eth_call JSON-RPC API 呼叫合約方法
好的,所以我正在嘗試使用乙太坊 JSON RPC 介面提供的方法呼叫合約方法。JSON RPC 在 Ubuntu 機器上執行。不幸的是,我無法從我創建的測試契約中真正得到結果。
我做的第一件事是在測試網上啟動 Go Ethereum:
geth --rpc --testnet
然後我打開另一個控制台並打開 JS 控制台
geth attach
然後我使用 Browser Solidity 編譯了我的合約,我的程式碼是:
contract test { function double(int a) returns(int) { return 2*a; } }
這給了我以下字節碼:
606060405260728060106000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480636ffa1caa146037576035565b005b604b60048080359060200190919050506061565b6040518082815260200191505060405180910390f35b6000816002029050606d565b91905056
然後我創建了契約:
curl localhost:8545 -X POST --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from": "0x8aff0a12f3e8d55cc718d36f84e002c335df2f4a", "data": "606060405260728060106000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480636ffa1caa146037576035565b005b604b60048080359060200190919050506061565b6040518082815260200191505060405180910390f35b6000816002029050606d565b91905056"}],"id":1}
這給了我交易雜湊,我用它來獲取合約地址:
curl localhost:8545 -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0x8290c22bd9b4d61bc57222698799edd7bbc8df5214be44e239a95f679249c59c"],"id":1}'
這給了我以下資訊:
{"id":1,"jsonrpc":"2.0","result":{"transactionHash":"0x8290c22bd9b4d61bc57222698799edd7bbc8df5214be44e239a95f679249c59c","transactionIndex":"0x0","blockNumber":"0xd32da","blockHash":"0xf13f185f0eb1e4797885400e3b371c972eedebcf3eef27815a45b649283ec669","cumulativeGasUsed":"0x14293","gasUsed":"0x14293","contractAddress":"0x5c7687810ce3eae6cda44d0e6c896245cd4f97c6","logs":[]}}
然後我想用數字“5”呼叫方法“double”。契約 ABI 文件說您必須獲取 Keccak 雜湊的前 4 個字節。
方法簽名是
double(int)
這給出了帶有 web3.sha3(“double(int)” 的雜湊:
6740d36c7d42fba12b8eb3b047193c9761224c267d7a2e96dc50949860652317
以“0x”為前綴的前四個字節是:
0x6740d36c
然後文件告訴獲取參數,將其編碼為十六進制並將其填充到 32 個字節。這將是以下,使用數字“5”:
0x0000000000000000000000000000000000000000000000000000000000000005
總的來說,編碼後的字元串應該是這樣的:
0x6740d36c0000000000000000000000000000000000000000000000000000000000000005
因此,使用它來呼叫方法:
curl localhost:8545 -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"from": "0x8aff0a12f3e8d55cc718d36f84e002c335df2f4a", "to": "0x5c7687810ce3eae6cda44d0e6c896245cd4f97c6", "data": "0x6740d36c0000000000000000000000000000000000000000000000000000000000000005"}, "latest"],"id":1}'
這給了我這個結果:
{"id":1,"jsonrpc":"2.0","result":"0x"}
我在這裡做錯了什麼還是忘記了重要的一步?
此外,是否有任何方法可以訪問 Go Ethereum 庫中已經存在的方法,從而使我不必自己實現例如填充的方法?
非常感謝您提前!
概括
constant
在我在函式定義中添加一個以表明此函式不會修改區塊鏈之前,您的原始合約程式碼將無法正常工作。- 我不得不使用方法簽名
double(int256)
而不是double(int)
讓eth_call
JSON-RPC 工作。細節
執行您的
geth
實例您可以使用通過 Internet 與其他對等方同步的Testnet 區塊鏈,也可以使用僅在您的電腦上可用且開發速度更快的私有**Dev區塊鏈。**該
--rpc
參數將允許您用於curl
與您的geth
實例進行通信。測試網區塊鏈
您需要創建一個帳戶並探勘一些硬幣,因為您需要硬幣將您的程式碼插入區塊鍊或將交易發送到區塊鏈:
geth --testnet account new Your new account is locked with a password. Please give a password. Do not forget this password. Passphrase: Repeat Passphrase: Address: {aaaa725f2f36a28c01bc47f883534990c9c8bbbb}
您的
geth
實例必須將您的 Testnet 區塊鏈與 Internet 上的其他對等方同步。這可能需要一個小時或更長時間。同步後,您的挖礦操作將開始,您應該在 10 或 20 分鐘內挖出一些硬幣。geth
從挖礦參數開始:geth --testnet --rpc --mine --minerthreads 1 console
要檢查您是否有硬幣,請執行以下命令:
> web3.fromWei(eth.getBalance(eth.accounts[0]), "ether"); 25
如果要退出
geth
,請按 Control-D。如果您願意,您現在可以在
geth
沒有探勘參數的情況下執行您的實例,因為geth
Internet 上某處的另一個實例將探勘您的交易。使用以下命令刪除探勘選項,或者只使用前面的geth
命令:geth --testnet --rpc console
開發區塊鏈
您將需要創建一個帳戶並開採一些硬幣:
geth --dev account new Your new account is locked with a password. Please give a password. Do not forget this password. Passphrase: Repeat Passphrase: Address: {cccc725f2f36a28c01bc47f883534990c9c8dddd}
從和參數開始
geth
,因為您的實例將需要探勘您的私有區塊鏈:--miner``--minerthreads``geth
geth --dev --rpc --mine --minerthreads 1 console
展平程式碼並分配給變數
我必須修改您的程式碼以通過將單詞添加到您的函式定義來使其正確執行,
constant
因為此函式在執行時不會修改區塊鏈。在您的範例中,您的程式碼通常會被格式化以便於閱讀:
contract Test { function double(int a) constant returns(int) { return 2*a; } }
您可以使用Line Break Removal Tool之類的服務來去除換行符,或者查看如何將 Solidity 源文件載入到 geth中以獲取一些替代方法。
您的扁平化程式碼將類似於您發布的範例:
contract Test { function double(int a) constant returns(int) { return 2*a; } }
您需要將程式碼分配給字元串變數:
var testSource='contract Test { function double(int a) constant returns(int) { return 2*a; } }'
請注意,如果將程式碼展平為註釋後的所有文本都將被視為註釋,
//
註釋將導致一些問題。如果您需要在程式碼中添加註釋,請改用//
。/* ... */
編譯你的程式碼
在您的
geth
實例中,鍵入帶有變數賦值的扁平程式碼。不要擔心undefined
結果,因為這是來自以下的正常響應geth
:> var testSource='contract Test { function double(int a) constant returns(int) { return 2*a; } }' undefined
編譯你的程式碼:
> var testCompiled = web3.eth.compile.solidity(testSource); I0503 09:04:15.907715 3190 solidity.go:114] solc, the solidity compiler commandline interface Version: 0.3.2-0/Release-Linux/g++/Interpreter path: /usr/bin/solc undefined
如果您想查看程式碼的二進制形式:
testCompiled { Test: { code: "0x6060604052602a8060106000396000f3606060405260e060020a60003504636ffa1caa8114601a575b005b6002600435026060908152602090f3", info: { abiDefinition: [{...}], compilerOptions: "--bin --abi --userdoc --devdoc --add-std --optimize -o /tmp/solc497335011", compilerVersion: "0.3.2", developerDoc: { methods: {} }, language: "Solidity", languageVersion: "0.3.2", source: "contract Test { function double(int a) constant returns(int) { return 2*a; } }", userDoc: { methods: {} } } } }
如果您想在此
geth
會話之外訪問執行您的函式,您需要為您的合約提供應用程序二進制介面 (ABI) 簽名:> testCompiled.Test.info.abiDefinition [{ constant: true, inputs: [{ name: "a", type: "int256" }], name: "double", outputs: [{ name: "", type: "int256" }], type: "function" }]
注意:這是關於為什麼您的 JSON RPC 呼叫不起作用的第二個提示 - 方法簽名具有
int256
參數a
而不是int
.將您的程式碼插入區塊鏈
執行以下命令將您的程式碼插入到區塊鏈中:
> var testContract = web3.eth.contract(testCompiled.Test.info.abiDefinition); undefined > var test = testContract.new({ from:web3.eth.accounts[0], data: testCompiled.Test.code, gas: 2000000}, function(e, contract) { if (!e) { if (!contract.address) { console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined..."); } else { console.log("Contract mined! Address: " + contract.address); console.log(contract); } } }) I0503 09:09:39.632499 3190 xeth.go:1026] Tx(0x8c15e8b8bb593d4a680b084a455ba82b103e60204638a3674ef1fb90ca0ad4f0) created: 0x7a2d8fa11aa28097135eb514f6a23ba12501191e Contract transaction send: TransactionHash: 0x8c15e8b8bb593d4a680b084a455ba82b103e60204638a3674ef1fb90ca0ad4f0 waiting to be mined... undefined
等待幾分鐘,您將看到以下輸出:
I0503 09:10:34.319772 3190 worker.go:569] commit new work on block 11122 with 0 txs & 0 uncles. Took 431.081µs Contract mined! Address: 0x7a2d8fa11aa28097135eb514f6a23ba12501191e [object Object]
如果你想在
geth
會話之外執行這個合約,你應該保存地址。在同一
geth
會話中使用您的契約在添加
constant
到double
函式之前,我得到了以下結果:> test.double(5) invalid address
注意:這是關於 JSON RPC 呼叫失敗原因的第一個提示。
geth
要在會話中使用你的合約,在添加constant
到double
函式之後:> test.double(5) 10 > test.double(55) 110
使用你的契約
curl
和 JSON-RPC現在我們到了棘手的部分。
你的功能
double(int)
是真的double(int256)
。來自Solidity - 類型:int• / uint•:各種大小的有符號和無符號整數。關鍵字 uint8 到 uint256,步長為 8(無符號 8 到 256 位)和 int8 到 int256。uint 和 int 分別是 uint256 和 int256 的別名。
在
geth
中,我們執行以下命令來查找double(...)
函式的簽名:> web3.sha3('double(int256)') "6ffa1caacdbca40c71e3787a33872771f2864c218eaf6f1b2f862d9323ba1640"
並取前 4 個字節來創建
data
參數0x6ffa1caa0000000000000000000000000000000000000000000000000000000000000005
並使用“Contract mined! parameter”中的地址,我們建構以下
curl
命令:curl localhost:8545 -X POST --data '{"jsonrpc":"2.0", "method":"eth_call", "params":[{"from": "eth.accounts[0]", "to": "0x65da172d668fbaeb1f60e206204c2327400665fd", "data": "0x6ffa1caa0000000000000000000000000000000000000000000000000000000000000005"}], "id":1}'
並從命令行執行此命令:
user@Kumquat:~$ curl localhost:8545 -X POST --data '{"jsonrpc":"2.0", "method":"eth_call", "params":[{"from": "eth.accounts[0]", "to": "0x65da172d668fbaeb1f60e206204c2327400665fd", "data": "0x6ffa1caa0000000000000000000000000000000000000000000000000000000000000005"}], "id":1}' {"id":1,"jsonrpc":"2.0","result":"0x000000000000000000000000000000000000000000000000000000000000000a"}
的結果
0x0000...000a
是值10
。2016 年 10 月 18 日更新
如呼叫合約常量無效函式時 RPC 錯誤“參數無效或缺失值”中所述,您可能必須向
params
列表中添加塊參數。帶有 block 參數的命令將是:user@Kumquat:~$ curl localhost:8545 -X POST --data '{"jsonrpc":"2.0", "method":"eth_call", "params":[{"from": "eth.accounts[0]", "to": "0x65da172d668fbaeb1f60e206204c2327400665fd", "data": "0x6ffa1caa0000000000000000000000000000000000000000000000000000000000000005"}, "latest"], "id":1}' {"id":1,"jsonrpc":"2.0","result":"0x000000000000000000000000000000000000000000000000000000000000000a"}
您可能還必須省略
from
參數。參考:
你的其他問題
此外,是否有任何方法可以訪問 Go Ethereum 庫中已經存在的方法,從而使我不必自己實現例如填充的方法?
您能否在另一個問題中問這個問題,因為這個答案已經太長了。