Smart-Contract-Wallets

如何在 web3j 中讀取我的智能合約中的方法返回的值

  • August 19, 2022

我正在關註一個教程,其中講師呼叫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用來執行你的交易時,假設你的交易只會讀取智能合約的狀態而不修改它,那麼任何節點都可以為你提供該資訊,並且該交易不需要被探勘,也不需要需要通過網路廣播。這就是為什麼當你呼叫一個聲明為viewpure因為它不會修改狀態的智能合約函式時你會立即收到結果的原因。

共享智能合約程式碼和 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}")

並且繁榮它對我來說工作正常。

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