Go-Ethereum

檢索契約變數時,web3j.ethCall 返回 null

  • September 26, 2019

環境:

Geth 節點 Geth/v1.9.0-unstable/windows-amd64/go1.12

用於啟動節點挖礦的命令:

  • geth –datadir“。” –networkid 101 -verbosity 6 –port 30301 –rpcport 8101 –nodiscover -rpc –rpcapi “db,eth,net,web3,personal” –vmdebug –mine 控制台 2>>“node01.log”
  • miner.start(2)
  • 個人.unlockAccount(eth.accounts$$ 0 $$)

HelloWorld.sol 合約:

pragma solidity ^0.5;    
contract HelloWorld {      
   uint256 counter = 5;

   function add() public {  //increases counter by 1
       counter++;
   }   
   function subtract() public { //decreases counter by 1
       counter--;
   }   
   function getCounter() public view returns (uint256) {
       return counter;
   } 
}

合約的Java Wrapper Class

生成的函式是:

public RemoteCall<BigInteger> getCounter() {
   final Function function = new Function(FUNC_GETCOUNTER, 
           Arrays.<Type>asList(), 
           Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {}));
   return executeRemoteCallSingleValueReturn(function, BigInteger.class);
}

用於生成 java 類的命令:

web3j truffle generate HelloWorld.json 
     -o java/classes -p com.web3j

Java 與合約的互動

HelloWorld contract = HelloWorld.load(
                   contractAddress,
                   web3j,
                   credentials,
                   GAS_PRICE,
                   GAS_LIMIT);

       System.out.println("Valid: " + contract.isValid());

      // call method getCounter which retrieves contract data
       Function function = new Function(
               "getCounter",
               Arrays.asList(),
               Arrays.asList(new TypeReference<Uint256>() {})
       );

       String encodedFunction = FunctionEncoder.encode(function);

       //unlock account
       PersonalUnlockAccount personalUnlockAccount = admin.personalUnlockAccount(account,password).send();
       if (personalUnlockAccount.accountUnlocked()) {
           System.out.println("Account " + account + " is UNLOCKED.");
       }

       EthCall ethCall = web3j.ethCall(
               Transaction.createEthCallTransaction(credentials.getAddress(), contractAddress, encodedFunction),
               DefaultBlockParameterName.LATEST)
               .sendAsync().get();

       String value = ethCall.getValue();
       List<Type> list = FunctionReturnDecoder.decode(value, function.getOutputParameters());

       System.out.println(list.size());

錯誤:

我已經嘗試過使用 truffle 部署的契約,以及使用 .deploy() 在 web3j 中部署的契約。在這兩種情況下,合約都會被部署,我可以檢查我創建的 geth 私人筆記上的交易雜湊。但在這兩種情況下,我都無法成功呼叫 getCounter() 函式。部署/載入的合約是有效的。我呼叫了 add() 方法,Transaction.createFunctionCallTransaction並設法探勘了交易並獲得了交易雜湊。當我在調試器中呼叫 getCounter() 方法時ethCall.result = "0x"

附加問題:

我讀過這個方法呼叫也應該起作用,因為它只檢索契約數據:

contract.getCounter().send();

但它拋出異常:

org.web3j.tx.exceptions.ContractCallException: Empty value (0x) returned from contract

請提供與我可能做錯的任何提示有關的幫助。謝謝你。

這一行:

contract.getCounter().send();

應該

contract.getCounter().call({from:yourAccount});

原因

當你從乙太坊請求狀態時,它不會花費 gas,因為你只是在讀取一個節點。如果節點在您的電腦上,那麼您只是在讀取硬碟驅動器。另一方面,當您更改狀態時,需要礦工獲取更改並將其添加到區塊鏈中。使用 Web3,您可以表示是呼叫狀態更改函式還是僅使用其中一個send({from:yourAccount)call({from:yourAccount})分別進行讀取。

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