Go-Ethereum

如何使用 eth_call JSON-RPC API 呼叫合約方法

  • August 28, 2017

好的,所以我正在嘗試使用乙太坊 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_callJSON-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沒有探勘參數的情況下執行您的實例,因為gethInternet 上某處的另一個實例將探勘您的交易。使用以下命令刪除探勘選項,或者只使用前面的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會話中使用您的契約

在添加constantdouble函式之前,我得到了以下結果:

> test.double(5)
invalid address

注意:這是關於 JSON RPC 呼叫失敗原因的第一個提示。

geth要在會話中使用你的合約,在添加constantdouble函式之後:

> 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 庫中已經存在的方法,從而使我不必自己實現例如填充的方法?

您能否在另一個問題中問這個問題,因為這個答案已經太長了。

引用自:https://ethereum.stackexchange.com/questions/3514