我正在试图找到这个问题的解决方案,处理事务确认顺序和设置0
值
pragma solidity ^0.5.17;
contract Test {
uint256 amount;
constructor() public {}
function join() public {
amount += 100;
}
function leave() public {
amount -= 100;
}
}
给定这些事务(在ropsten上测试(:
tx 1(呼叫加入已确认amount == 100
tx 2(呼叫加入(油价1(待定amount == 100 should tx3 get mined first
tx 3(电话休假(油价100(待定amount == 0
然而,只要amount
被设置回0
,tx 2
将总是以out of gas
错误而失败。如果该值高于0
,则不会发生这种情况。我的理解是,将值设置为0
状态而不是正整数会花费更多的气体,而气体估计没有考虑到这一点。我试过delete
,希望这能给汽油退款,以补偿过低的汽油限额,但还是失败了。
有没有一种优雅的方法来处理这种情况?我能想到的唯一方法是高估所有join
事务的气体,这有其明显的缺点,或者永远不要将amount
设置回0
。
您的观察结果是正确的。
通过将其设置为0,您可以删除存储空间,并获得汽油退款。这就是为什么它需要更少的气体。但汽油退款有上限,所以你不能用它来存储ETH。
在一个槽中存储一个值需要花费20000天然气(来源:https://github.com/ethereum/go-ethereum/blob/d13c59fef0926af0ef0cff0a2e793f95d46442f0/params/protocol_params.go#L41(
从存储槽加载一个值需要花费2200气体(来源:https://github.com/ethereum/go-ethereum/blob/d13c59fef0926af0ef0cff0a2e793f95d46442f0/params/protocol_params.go#L89)
这就是为什么你会看到不同的天然气消耗值。
只需将你的gasLimit设置为一些经验发现的粗略估计值。
对您的交易进行跟踪,您将看到所有的天然气消耗值。
现在,汽油退款的工作方式是,在状态转换功能期间,你会被要求为你的合同提供全额汽油。在此运行过程中,所有气体退款都会累积在StateDB(临时状态对象(中。在状态转换功能结束时,您将获得合同将要进行的所有存储释放的退款。这就是为什么你必须设置Etherscan显示的更高的天然气限额,因为假设你的合同需要15000天然气才能运行,在存储释放后(比如5000天然气(,Etherscan将显示交易需要10000天然气。这不是真的,因为你最后得到了汽油退款,但一开始你需要全部的汽油(15000(。汽油退款由矿工赞助,他的账户将获得更少的ETH,因为他向您支付这些退款。