Solidity

Web3 常量方法呼叫的結果不一致

  • February 9, 2022

部署了本地私有乙太坊環境。在嘗試呼叫solidity合約的常量方法時,結果不一致。

有時會返回結果,但大多數情況下不會。

當我嘗試從 geth 命令行獲取數據時,每次都能成功列出結果。

在下面的 Nodejs 程式碼中,創建了一個 20 次迭代的循環來獲取資產價格。有時 10-15 次正確返回結果,並且很多次在沒有找到任何迭代結果,而是說 0。

契約

pragma solidity ^0.4.9;

contract Asset {

   address public owner;
   struct Asset {
       string title;
       string description;
       uint  assetTime;
       uint price;
   }

   Asset[] public  assets;

   event LogAssetAdded(address indexed fromAddress, string description);

   // add asset
   function addAsset(string  description1, string title1, uint price1,uint assetTime1) 
     returns (uint, string, string, uint, uint) {
       uint assetID = assets.length++;
       Asset o = assets[assetID];

       o.description = description1;
       o.assetTime=assetTime1;
       o.title = title1;
       o.price = price1;

       LogAssetAdded(msg.sender, description1);

       return (assetID, assets[assetID].description, assets[assetID].title, assets[assetID].price, 
         assets[assetID].assetTime);
   }

   //return the  number of assets 
   function assetCount() public constant returns(uint) {
       uint assetCount =assets.length;
       return(assetCount);
   }

   function getAssetPrice(uint assetID) public constant returns(uint) {
       return assets[assetID].price;
   }

   function getDefAssetPrice() public constant returns(uint) {
       return assets[assets.length-1].price;
   }

   function getDefAssetTitle() public constant returns(string) {
       return assets[assets.length-1].title;
   }

   function getDefAssetTime() public constant returns(uint) {
       return assets[assets.length-1].assetTime;
   }
}

NodeJs 客戶端程式碼

const rpcURL = 'http://localhost:9081'
var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:9081"));

const fs = require("fs");

let abi ='<<Apply ABI>>';

let bytecode = '<<Apply Bytecode >>'
let gasEstimate = web3.eth.estimateGas({data: bytecode});

let assetContract = web3.eth.contract(JSON.parse(abi));
const account = '<<Provide from account>>';

var contractAddress = '<<Provide Contract Address>>';

var ctr1 = 0;
var contract = assetContract.at(contractAddress);

// Method to create asset
function addAsset(){
   contract.addAsset.sendTransaction("Asset Description", " Asset Title", 41202, 41203, {from: account, gas: 400000} 
   , function(err, result){
       if(err){
           console.log('Error '+ err);    
       }
       else{
           console.log('Transaction Hash: '+ result);
           getAssetPrice();
       }
   });
}

// Method to fetch asset price
function getAssetPrice(){  
   for(var i=0;i<20;i++){
     contract.getAssetPrice(0, (error, result) => {
       if (!error && result>0) {
           ctr1++;
           console.log(ctr1 +": getAssetPrice: "+ result);
       }
       if (!error){
            console.log("Error occurred: "+ error);
       }
   });
}

addAsset();
//getAssetPrice()

依賴項

"web3": "^0.19",
"solc": "^0.4.9"

格特版

v1.9.0 windows-amd64, go1.10.3

Geth 實例命令

geth --mine --minerthreads=1 --datadir D:/Ethereum/env-II/data/node1 --networkid 4224 --nodiscover --rpc --rpcport "9081" --port "30301" --rpccorsdomain "*" --nat "any" --rpcapi eth,web3,personal,net,miner --unlock 0 --password "D:/Ethereum/env-II/pwd.txt"  --rpcaddr 0.0.0.0 --verbosity 2 console

Geth 命令行結果

> var assetContractRef = eth.contract('<<Contract abi>>');
> var assetContract = assetContractRef.at('<<Contract address>>')
> assetContract.getAssetPrice(1);
> 41202

使用 Call 呼叫的結果

Option 1: contract.getAssetPrice(0).call((error, result) => {                            

TypeError: contract.getCallPrice(...).call is not a function

Option 2: contract.getAssetPrice.call(0, (error, result) => {

Faced same result i.e. inconsistent output.

筆記

我已經嘗試過這種實現,使用 Web3 1.0.0-beta.52 以及稍微修改的 nodejs 程式碼,即特定於 web3 1.0.0 簽名,但面臨同樣不一致的結果。如果需要,也可以共享該版本的 Nodejs 程式碼。

您可能希望.call()在呼叫常量(視圖)方法時使用。查看 Web3js 文件的此頁面以熟悉:https ://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#methods-mymethod-call

乍一看,我認為您需要更改的只是這一行:

contract.getAssetPrice(0, (error, result) => {

對此:

contract.getAssetPrice(0).call((error, result) => {

您在一定時間內多次發送請求。您的結果可能是由於 TCP 連接造成的。您正在使用http,嘗試使用websocket 作為提供者

var web3 = new Web3(new Web3.providers.WebsocketProvider("http://localhost:9081"));

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