Web3js 调用和 truffle 调用行为不同

Web3js invocation and truffle invocation behaving differently

我有一份看起来像这样的合同 -

contract Calculator {
    uint public result;

    constructor() public {
       result = 777;   //note the initial value
    }

    function add(uint a, uint b) public returns (uint, address) {
       result = a + b;
       return (result, msg.sender);
    }
}

当我在 truffle 上调用函数时,我得到了正确的交易 -

truffle(development)> await calculator.add(5,11)
{
  tx: '0xa66e94bb28810bb2a861c97ee149718afa599d47b7b1c6e55743ea657fdeef56',
  receipt: {
    transactionHash: '0xa66e94bb28810bb2a861c97ee149718afa599d47b7b1c6e55743ea657fdeef56',
    transactionIndex: 0,
    blockHash: '0x6ae4e3ce65f1e177c419306a50662ed46f40c729a6a18ede028b07e63dd12f61',
    blockNumber: 6,
    from: '0x5d88950b52f89ad66906fc263e8c35ddacff04d4',
    to: '0x7c8beb382c70cbf12b41fd4e5d74cfee53fdc391',
    gasUsed: 26074,
    cumulativeGasUsed: 26074,
    contractAddress: null,
    logs: [ [Object] ],
    status: true,
    logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000200000000000000000000000000000000000000',
    rawLogs: [ [Object] ]
  },
  logs: [
    {
      logIndex: 0,
      transactionIndex: 0,
      transactionHash: '0xa66e94bb28810bb2a861c97ee149718afa599d47b7b1c6e55743ea657fdeef56',
      blockHash: '0x6ae4e3ce65f1e177c419306a50662ed46f40c729a6a18ede028b07e63dd12f61',
      blockNumber: 6,
      address: '0x7C8beb382C70CbF12b41fd4e5d74CfEe53FDc391',
      type: 'mined',
      id: 'log_28a5e84f',
      event: 'Added',
      args: [Result]
    }
  ]
}

我正在使用 Web3js 像这样调用相同的函数 -

const Web3 = require("web3");
const CalculatorContract = require("../build/contracts/Calculator.json");

let web3 = new Web3(new Web3.providers.WebsocketProvider("ws://127.0.0.1:7545"));

async sendTransaction () {
    let accounts = await web3.eth.getAccounts();

    let contractAddress = "0x7C8beb382C70CbF12b41fd4e5d74CfEe53FDc391";
    let calculatorContract = new web3.eth.Contract(CalculatorContract.abi, contractAddress);

    console.log("Calculator adding: ", await calculatorContract.methods.add(11, 88).call({
        from: '0x38e3614A5Cf95f0DBb858D9E3752Ac477DA70ccD'
    }));
    console.log("Calculator result: ", await calculatorContract.methods.result().call());
}

当我调用上面的函数时,我得到这样的输出 -

Calculator adding:  Result {0: '99', 1: '0x5d88950b52F89AD66906fC263E8C35DdacFf04D4'}
Calculator result:  777     //why 777? the last invocation should rewrite 777 to 99

现在我的问题是-

  1. 为什么 truffle 调用创建交易,而 Web3js 调用不创建任何交易?我怎样才能使它们的行为相同?
  2. 当使用 truffle 调用时(我的意思是当事务被 returned 时),我怎样才能得到方法调用的 return 值?

软件版本:

truffle(development)> truffle version
     Truffle v5.1.51 (core: 5.1.51)
     Solidity v0.5.16 (solc-js)
     Node v15.1.0
     Web3.js v1.2.9

Ganache: 2.5.4
Nodejs: v15.1.0
Web3js: ^1.3.0

Web3.js 合约对象不同于 Truffle 合约对象。结构略有不同,当然,因为它们都是无类型的 JavaScript,你不知道输入或输出函数会有什么。

Historically, Ethereum transactions did not have return values。 Web3.js 行为早于这次,可能不支持 return 直接交易价值。然而,EIP 1288 记录了如何通过 getTransactionReceipt()receipt 对象获得 return 值。

要 Web3.js 修改 EVM 状态,您需要执行 send() 而不是 call()。这是另一个弱类型问题,因为不应混淆查看和写入功能。

尝试:

    console.log("Calculator adding: ", await calculatorContract.methods.add(11, 88).send({
        from: '0x38e3614A5Cf95f0DBb858D9E3752Ac477DA70ccD'
    }));

解决 Truffle 与 Web3.js 之间的差异。解决行为差异的最简单方法是根本不使用 Truffle 工件,而是在所有地方使用 Web3.js 合约。

Ps。我推荐 OpenZeppelin SDK (Node.js / TypeScript) 而不是 Truffle。它使用 TypeScript 打字更加理智,也可以用作前端和后端代码中的 Web3.js 替代品。或者使用 Python 和 Web3.py 会更好,因为如果您负担得起切换语言,那么这些猜谜游戏的空间就更小了。