Go-Ethereum
檢索契約變數時,web3j.ethCall 返回 null
環境:
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})
分別進行讀取。