加密社
最近调试一段solidity代码,本来想测试在收款的时候,记录一个receive 和发出一个log,哪个消耗gas更大
我创建了两个智能合约:一个是TestTransfer
,另一个是TransferCount
。在TestTransfer
合约中,我定义了一个叫做sendOut
的函数,这个函数的作用是从TestTransfer
向TransferCount
合约转账。
我在测试过程中遇到了以下情况:
- 当我试图从
TestTransfer
合约向TransferCount
合约转账时,总是失败。 - 但是,当我直接向
TransferCount
合约转账时,却能够成功。 - 之后我把
TransferCount
合约里的receive()
函数中的代码注释掉了,再试了一次第一步的操作,这次竟然成功了。
问题出在哪里呢?
实际上,问题可能在于TransferCount
合约中的receive()
函数。当我从TestTransfer
合约调用transfer()
向TransferCount
转账时,如果TransferCount
的receive()
函数执行了一些消耗gas的操作,并且这些操作超过了transfer()
方法内默认提供的2300 gas限制,那么整个转账过程就会失败。
解决这个问题的办法就是简化receive()
函数,让它尽可能地少做事情,或者干脆不执行任何操作。这样一来,即使transfer()
方法提供的gas有限,也不会因为gas不够而导致转账失败。
总结来说,为了确保transfer()
能够成功,应该避免在receive()
函数中写入过多的逻辑或操作。
// 指定Solidity版本大于0.8.0
pragma solidity >0.8.0 ;
// 这个合约用来接收Ether,并记录接收次数
contract TransferCount {
// 公开变量,记录fallback函数被调用的次数
uint public fallbackCount = 0;
// 公开变量,记录receive函数被调用的次数
uint public receiveCount = 0;
// 可支付的构造函数
constructor() payable {
// 构造函数体为空
}
// 允许外部向合约发送Ether
function deposit() payable external {
// 函数体为空
}
// 接收Ether时自动调用此函数(如果交易数据为空)
receive() external payable {
// 增加接收次数
receiveCount ++;
// 注意:在此处增加代码可能导致其他合约调用address.transfer时由于gas不足而失败
}
// 当合约接收到带有数据负载的Ether时调用此函数
fallback() external payable {
// 增加fallback函数被调用的次数
fallbackCount ++;
}
}
// 这个合约用来测试向TransferCount合约转账的行为
contract TestTransfer{
// 记录fallback函数被调用的次数
uint public fallbackCount = 0;
// 记录receive函数被调用的次数
uint public receiveCount = 0;
// 存储可支付地址,用于接收Ether
address payable public tc;
// 接收Ether时自动调用此函数(如果交易数据为空)
receive() external payable {
// 增加接收次数
receiveCount ++;
}
// 当合约接收到带有数据负载的Ether时调用此函数
fallback() external payable {
// 增加fallback函数被调用的次数
fallbackCount ++;
}
// 构造函数,初始化可支付地址
constructor(address payable addr) payable {
// 设置可支付地址
tc = addr;
}
// 转账函数,从本合约向指定地址转账
function sendOut(uint amount ) external{
// 确保有足够的余额进行转账
require(amount <= address(this).balance, "insufficient balance");
// 向指定地址转账
payable(tc).transfer(amount);
}
}