如何在 web3j 中讀取我的智能合約中的方法返回的值
我正在關註一個教程,其中講師呼叫
contract.getConuter().send
它返回智能合約上計數器的值,但在我的情況下,它是返回TranscriptReciept
對象。Solidity 合約
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; 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; } }
試圖獲得價值
getCounter()
val identityContract = HelloWorld_sol_HelloWorld.load( deployedContractAddress, web3j, getCredentialsFromPrivateKey(), DefaultGasProvider.GAS_PRICE, DefaultGasProvider.GAS_LIMIT ) Log.d(TAG, "counter Result: ${identityContract.getCounter().sendAsync().get()}")
你能告訴我們那個智能合約的程式碼嗎?
該
getCounter
函式可能被聲明為非純/視圖,並且.send
實際上正在發送您的交易以進行探勘,因為它可能會改變智能合約的狀態,而不是簡單地向您發送counter
. 因此,它可能會更新計數器然後返回它。這就是您收到收據的原因。智能合約無法立即返回計數器的新值,因為該交易尚未被探勘,您需要等待它被探勘,因此您會得到一張收據,您可以使用它來等待交易被探勘然後嘗試獲取新的計數器值。可能會做類似
await transcriptReciept.wait(1)
等待一次確認的事情(以便您的交易在一個區塊中被探勘)。然後,您可以嘗試訪問新的計數器值,await contract.counter()
以防counter
狀態變數被聲明為公共或外部。當您
send
的交易將修改狀態時,您的交易將通過網路廣播進行驗證,將被探勘並且包含它的塊將通過網路廣播。當你
call
用來執行你的交易時,假設你的交易只會讀取智能合約的狀態而不修改它,那麼任何節點都可以為你提供該資訊,並且該交易不需要被探勘,也不需要需要通過網路廣播。這就是為什麼當你呼叫一個聲明為view
或pure
因為它不會修改狀態的智能合約函式時你會立即收到結果的原因。共享智能合約程式碼和 javascript 腳本,看看這是否真的在做。
我能夠使用 Javascript 重現它
web3
:const Web3 = require("web3"); const web3 = new Web3("http://127.0.0.1:7545"); const abi = [ { inputs: [], name: "add", outputs: [], stateMutability: "nonpayable", type: "function", }, { inputs: [], name: "subtract", outputs: [], stateMutability: "nonpayable", type: "function", }, { inputs: [], name: "getCounter", outputs: [ { internalType: "uint256", name: "", type: "uint256", }, ], stateMutability: "view", type: "function", }, ]; const helloWorldContract = new web3.eth.Contract( abi, "0xA253E8C4F4cA396feefF080e5f61EDB0952bF28e", { from: "0xD743192B367b781b8fedacf4a77A2CBA6e58C15d", } ); // With `send` it returns a transaction receipt, with `call` it returns the value right away. const response = helloWorldContract.methods.getCounter().send(); response.then((response) => { console.log("response: ", response); });
使用
.send()
,它返回交易收據:response: { transactionHash: '0x4dbc1cc7d6115af7c9492c6bc5fec7aa6c39b71b64af947bab4e0e266454a547', transactionIndex: 0, blockHash: '0xa9fe04aaaa95dff2856fbc59f8d38b2ae190f6589bfec9075a4fac28eb570cff', blockNumber: 9, from: '0xd743192b367b781b8fedacf4a77a2cba6e58c15d', to: '0xa253e8c4f4ca396feeff080e5f61edb0952bf28e', gasUsed: 22223, cumulativeGasUsed: 22223, contractAddress: null, status: true, logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', events: {} }
使用
.call
,它返回值:const Web3 = require("web3"); const web3 = new Web3("http://127.0.0.1:7545"); const abi = [ { inputs: [], name: "add", outputs: [], stateMutability: "nonpayable", type: "function", }, { inputs: [], name: "subtract", outputs: [], stateMutability: "nonpayable", type: "function", }, { inputs: [], name: "getCounter", outputs: [ { internalType: "uint256", name: "", type: "uint256", }, ], stateMutability: "view", type: "function", }, ]; const helloWorldContract = new web3.eth.Contract( abi, "0xA253E8C4F4cA396feefF080e5f61EDB0952bF28e", { from: "0xD743192B367b781b8fedacf4a77A2CBA6e58C15d", } ); // With `send` it returns a transaction receipt, with `call` it returns the value right away. const response = helloWorldContract.methods.getCounter().call(); response.then((response) => { console.log("response: ", response); }); ```js response: 5
所以,試著
contract.getCounter.send()
用contract.getCounter.call()
.對於
Web3j
,試試這個:https ://docs.web3j.io/4.8.7/smart_contracts/interacting_with_smart_contract/#calling-constant-methods“常量方法是那些讀取智能合約中的值,並且不改變智能合約狀態的方法。這些方法具有與生成它們的智能合約相同的方法簽名:”
Type result = contract.someMethod(<param1>, ...).send();
最後,在以不同的方式完成之後,我現在可以使用 web3j 讀取智能合約中函式返回的值。
首先像這樣創建
Function
類型變數org.web3j.abi.datatypes.Function
val function = Function( "getCounter", //make sure this name is same as your function name in solidity file. Collections.emptyList(), listOf(object : TypeReference<Uint?>() {}) ) val encodedFunction = FunctionEncoder.encode(function)
然後提出請求
val response = web3j.ethCall( Transaction.createEthCallTransaction(null, deployedContractAddress, encodedFunction), DefaultBlockParameterName.LATEST ) .sendAsync().get() val results = FunctionReturnDecoder.decode(response.value, function.outputParameters) val preValue = results[0] as Uint Log.d(TAG, "loadContract: Counter Value: ${preValue.value}")
並且繁榮它對我來說工作正常。