web3js调用send()方法报错out of gas原因solidity

前情提要:solidity中send(), call(), transfer()简介
.transfer(uint256 amount): 发送特定数量(wei为单位)的以太坊到对应地址,当出现错误时会引发异常,此过程所有更改都将被还原。固定需要耗费2300个gas(该费用不可更改)。

.send(uint256 amount) returns(bool): 发送特定数量(wei为单位)的以太坊到对应地址,当出现错误时会返回flase,而不返回异常。固定需要耗费2300个gas(该费用不可更改)。
【警告】send() 执行有一些风险:如果调用栈的深度超过1024或gas耗光,交易都会失败。因此,为了保证安全,必须检查send的返回值,如果交易失败,会回退以太币。

.call(...) returns(bool): 低级调用函数,不依赖于ABI接口,可根据需求调用任何函数。若合约ABI接口不可用,可用call()调用函数。当失败时返回false。由于call()方法的调用不涉及检查和验证,因此需谨慎使用。

注意:在solidity中transfer()方法优于send()方法,send()方法应谨慎使用。
=======================分界线==============================
  在web3js中,myContract.methods.myMethod.send()用于向合约发送交易来执行其方法,注意这会改变合约状态。由于solidity中的send()方法调用时的gasLimit固定在2300个gas,尽管2300个gas费用足以完成转账的功能,若是想要执行过多其他的操作,如:更改contract内全局变量、触发event事件、执行循环、其他需要消耗gas的操作,这都会导致报错。
  但myContract.methods.myMethod.call()不会报错,因为call()将在不发送交易的情况下调用该“常量”方法并在 EVM 中执行其智能合约方法。是只读操作,不会产生交易,也不消耗gas,主要用于调用pure函数,constant函数和view函数,注意此种调用方式无法改变智能合约状态(即不能更改全局变量,不能触发event等)。
  所以在web3js端调用myContract.methods.myMethod.send()方法时报错out of gas,可能不是你的智能合约函数写的有问题,要解决该问题则需要将函数中实现的功能进行拆分,去掉不必要的计算和变量。注:myContract.methods.myMethod.send()只能调用payable函数,myContract.methods.myMethod.call()什么函数都可以调用(internal function和private function除外)。

下面是我的代码报错示例:

代码运行环境:remix编写智能合约,ganache部署私链,nodejs运行web3js代码。

 对应的solidity代码对应出错的function部分:

  可以看到该函数需要触发两次event,两次强制类型转换,更改四个全局变量,这点功能就报错,经过验证,在该函数中删除一部分代码就可以用web3js调用send()方法并返回正确的交易哈希值。

  最终解决方法:由于send()方法内置的2300个gas不能更改,就只能拆分功能,用多个function实现再调用。

//solidity代码
function storeInfos(
      bytes memory sigi_val,
      bytes memory sigi_extra,
      bytes memory ri_val,
      bytes memory ri_extra,
      bytes memory chali_val,
      bytes memory chali_extra,
      uint targetCSPAddressUint,
      bytes32 plKeccak
      ) public payable{
      emit recordSigRi(sigi_val,sigi_extra,ri_val,ri_extra);//触发event
      emit recordChali(chali_val,chali_extra);//触发event

      transferAmount[0] = msg.value;//更改全局变量

      uint160 targetCSPAddressUint160 = uint160(targetCSPAddressUint);//强制类型转换
      address targetCSPAddress = address(targetCSPAddressUint160);//强制类型转换

      DO = address(msg.sender);//更改全局变量
      CSP = targetCSPAddress;//更改全局变量

      resultHash = plKeccak;//更改全局变量
 }

总结:solidity虽然是图灵完备的语言,但相比于java,python等成熟的计算机语言,真的是太弱了。

 

posted on 2022-07-03 11:06  尽管我们手中空无一物  阅读(415)  评论(0编辑  收藏  举报