Web3js 调用和 truffle 调用行为不同

Posted

技术标签:

【中文标题】Web3js 调用和 truffle 调用行为不同【英文标题】:Web3js invocation and truffle invocation behaving differently 【发布时间】:2021-02-28 08:20:39 【问题描述】:

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

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

现在我的问题是 -

    为什么 truffle 调用正在创建事务,但 Web3js 调用没有创建任何事务?我怎样才能使它们的行为相同? 使用 truffle 调用时(我的意思是返回事务时),如何获取方法调用的返回值?

软件版本:

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

【问题讨论】:

【参考方案1】:

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

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

要让 Web3.js 修改 EVM 状态,您需要使用 send() 而不是 call()。这是另一个弱类型问题,因为不应混淆视图和编写函数。

试试:

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

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

附言。我推荐 OpenZeppelin SDK (Node.js / TypeScript) 而不是 Truffle。使用 TypeScript 输入更加理智,也可以用作前端和后端代码中的 Web3.js 替代品。或者使用 Python 和 Web3.py 甚至更好,因为如果您能负担得起切换语言的费用,它们会为您的问题中的猜谜游戏留下更少的空间。

【讨论】:

感谢您的评论。但是让我们把松露放在一边,我仍然很困惑为什么从 web3js 调用add(11, 88) 并没有持久化结果?我的意思是如果我调用result()(这是一个为result公共变量自动生成的getter函数),它返回默认值777,而不是99。关于SDK和语言,在我的web3代码中,我没有使用任何松露相关库。它唯一的 web3js。而且我不是 Python 人,而是 Java 和 Nodejs 人。 非常感谢。不是send()是低级方法,linksuggested是要避免,而是建议使用transfer() 你把事情搞混了。当您的问题在 JavaScript 中时,您指的是 Solidity 文档。它们是两种不同的编程语言和两种不同的运行时环境。

以上是关于Web3js 调用和 truffle 调用行为不同的主要内容,如果未能解决你的问题,请参考以下文章

使用 web3js 和 galanche 调用具有价值的以太坊智能合约

使用 Trezor(硬件钱包)将签名交易发送到 Ropsten 或 Truffle 开发网络

从 web3js 调用 Factory 合约的子函数

truffle的调用nodeJs的问题

使用Ganache,web3js和remix在个人区块链上部署并调用合约

使用 truffle 在solidity 中调用函数时出现新的 BigNumber() 错误。如何修复错误?