Contract-Invocation

web3.eth.call。如何設置“數據”參數?

  • August 29, 2017

我通過使用 browser-solidity 來製作字節碼和 web3.eth.sendRawTransaction 來部署我的第一個合約。以下是交易和部署的合約程式碼。

https://ropsten.etherscan.io/tx/0x74426948905cd6e70e8b9d64a660b3c179b7c8a224ca5cd0234842768eb501db

合約程式碼

pragma solidity ^0.4.0;
contract Addition {
 int num = 0;
 function add(int a){
   num += a;
 }
 function get() returns(int){
   return num;
 }
}

然後,我想通過 web3.eth.call 呼叫這兩個方法。但是,我找不到如何生成“數據”參數的方法。你能給我一些建議嗎?

var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.HttpProvider("http://xxx:xxx"));

var result = web3.eth.call({
   to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a", 
   data: "???"
});

https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethcall

我認為需要呼叫gas,但這個例子沒有提到它。在 browser-solidity 上的 JavaScript VM 上,當我執行如下方法時會顯示價格。

Result: "0x"
Transaction cost: 41713 gas. 
Execution cost: 20249 gas.

更新 1

似乎這個頁面描述了它。

然後我想用數字“5”呼叫方法“double”。契約 ABI 文件說您必須獲取 Keccak 雜湊的前 4 個字節。方法簽名是

雙(整數)

這給出了帶有 web3.sha3(“double(int)” 的雜湊:

6740d36c7d42fba12b8eb3b047193c9761224c267d7a2e96dc50949860652317

以“0x”為前綴的前四個字節是:

0x6740d36c

然後文件告訴獲取參數,將其編碼為十六進制並將其填充到 32 個字節。這將是以下,使用數字“5”:

0x0000000000000000000000000000000000000000000000000000000000000000000005

總的來說,編碼後的字元串應該是這樣的:

0x6740d36c00000000000000000000000000000000000000000000000000000000000000000005

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


更新 2

這沒用。

var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.HttpProvider("http://xxx:xxx"));

var result = web3.eth.call({
   to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
   data: "0x6d4ce63c" // var hash = web3.sha3("get()"); get first 4 byte
});

console.log(result); // 0x

var result = web3.eth.call({
   to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
   data: "0x250fc6d90000000000000000000000000000000000000000000000000000000000000001" // var hash = web3.sha3("add(int)"); get first 4 byte and param (1)
});

console.log(result); // 0x

var result = web3.eth.call({
   to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
   data: "0x6d4ce63c" // var hash = web3.sha3("get()"); get first 4 byte
});

console.log(result); // 0x => I expected 1

更新 3

我從 add(int) 更改為 add(int256) 但仍然無法正常工作。

var result = web3.eth.call({
   to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
   data: "0x87db03b70000000000000000000000000000000000000000000000000000000000000001" // var hash = web3.sha3("add(int256)"); get first 4 byte and param (1)
});

但是 browser-solidity 調試器顯示相同的數據。所以我認為這個數據是正確的。


更新 4

看來我必須在通話前發送交易。我能想像。我會試試。

稱呼。這是一個只讀操作,不會消耗任何乙太幣。

交易和通話有什麼區別?


更新 5

雖然我認為找到了答案,但它仍然不起作用。我休息一下。。

(1) sendRawTransaction

var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.HttpProvider("http://xxxx:xxxx"));

var Tx = require('ethereumjs-tx');
var privateKey = new Buffer('xxxx', 'hex')

var rawTx = {
 nonce: '0x03',
 gasPrice: '0x53d9',
 gasLimit: '0x53d9',
 to: '0x692a70d2e424a56d2c6c27aa97d1a86395877b3a',
 data: '0x87db03b70000000000000000000000000000000000000000000000000000000000000001' // add(int256) with param 1
}

var tx = new Tx(rawTx);
tx.sign(privateKey);

var serializedTx = tx.serialize();

console.log('0x' + serializedTx.toString('hex')); // 0xf885038253d98253d994692a70d2e424a56d2c6c27aa97d1a86395877b3a80a487db03b700000000000000000000000000000000000000000000000000000000000000011ba0ec6de7c9c1f31dc95014156479925b2ebd933b715f2bb4450f5d74992d7b3423a016f6a7c6e1885412400a622f82ffa033936c06755896096c7638936c065571c1

web3.eth.sendRawTransaction('0x' + serializedTx.toString('hex'), function(err, hash) {
 if (!err) {
   console.log(hash); // 0x26db79c7c3c65992f17f4f62d5d191705933e785dff54db6d27e6f3a92d7117e
 } else {
   console.log(err);
 }
});

https://ropsten.etherscan.io/tx/0x26db79c7c3c65992f17f4f62d5d191705933e785dff54db6d27e6f3a92d7117e

(2) 呼叫 get()

var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.HttpProvider("http://xxxx:xxxx"));

var result = web3.eth.call({
   to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a",
   data: "0x6d4ce63c"
});

console.log(result); // 0x => I expected 1

你不需要自己做這一切。您可以改為使用getData方法。

var contract = web3.eth.contract(contractABI).at(contractAddress);
var callData = contract.functionName.getData(functionParameters);
var result = web3.eth.call({
   to: "0x692a70d2e424a56d2c6c27aa97d1a86395877b3a", 
   data: callData
});

web3.eth.call 在節點的 VM 中執行呼叫,但這不是探勘的。這是一種試執行。如果您想將交易發送到區塊鏈,請使用web3.eth.sendTransaction.

即使我不得不經歷同樣的過程,直到我發現,以下:

使用有助於做同樣事情的 web3.js 庫。只需使用 NPM(或其他任何地方)下載 web3.js 並獲取任務所需的模組,方法是:

const_ = require('lodash');
const SolidityFunction = require('web3/lib/web3/function');

您可以使用 web3.js 庫和 ABI 來查找函式定義,使用以下程式碼:

var ABI = JSON.parse(<your_ABI>);
var functionDef = new SolidityFunction('', _.find(ABI, { name: '<your_function_name>' }), '');

在此之後,您可以呼叫 toPayload 方法,該方法將幫助您將要傳遞給函式的值轉換為 HEX 數據。

var payloadData = functionDef.toPayload([<value_for_var_1>, <value_for_var_2>, <value_for_var_3>, <value_for_var_4>]).data;

payloadData可用作 DATA 屬性的值。例子:

var rawTx = {
to: <to_address>,
data: payloadData,
value: '0x0',
from: <from_address>,
nonce: nonce,// You need to Get this using web3.eth.getTransactionCount
gasLimit: gasLimit, // Get this by web3.eth.estimateGas
gasPrice: gasPrice // use, web3.eth.gasPrice
}

您可以使用這種方法而忘記要填充多少個零。因為toPayload函式處理一切。您有一個原始交易對象,您可以使用ethereumjs-tx簽署您的交易並使用web3.eth.sendRawTransaction呼叫您的合約函式。

希望這可以幫助。

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