Solidity

從合約供應氣體到執行功能

  • February 3, 2022

假設我有這樣的東西

function usuallyCheapFunction() external {
   ... do something cheap...
   if(rareCondition == true) {
       expensiveCleanupFunction();
   }
}

function expensiveCleanupFunction() internal {
  ... shuffle around some storage ...
}

使用者會呼叫通常CheapFunction() 來做某事,期望便宜的交易價格。有時合約需要進行一些昂貴的清理——在這種情況下,是否可以從合約中提供 gas 來呼叫昂貴的CleanupFunction(),這樣呼叫就不會導致燃料不足?如果是這樣,這會是什麼樣子?

目前無法從合約餘額中支付 gas,儘管這可能會在未來發生變化,但智能合約可能會退還 gas 交易發布者在管家功能上花費的費用:

modifier refundable () {
   uint256 gasBefore = gasleft ();
   _;
   tx.origin.send (tx.gasprice * (gasleft () - gasBefore));
}

function expensiveCleanupFunction() refundable internal {
   ... shuffle around some storage ...
}

但是,如果智能合約沒有足夠的乙太幣,這將不會退還 gas。如果您即使在餘額不足的情況下也需要退款,請執行以下操作:

mapping (address => uint256) private refundBalance;

modifier refundable () {
   uint256 gasBefore = gasleft ();
   _;
   uint256 toRefund = tx.gasprice * (gasleft () - gasBefore);
   if (!tx.origin.send (toRefund))
       refundBalance [tx.origin] += toRefund;
}

function withdraw () public {
   uint256 toTransfer = refundBalance [msg.sender];
   refundBalance [msg.sender] = 0;
   msg.sender.transfer (toTransfer);
}

function expensiveCleanupFunction () refundable internal {
   ... shuffle around some storage ...
}

因此,如果即時退款失敗,智能合約會增加使用者的退款餘額,一旦智能合約餘額被補足,使用者就可以撤回退款。

不可能在單個事務中執行此操作,因為 Solidity 中的每個操作都編譯為一個操作碼,並且每個操作碼都有相關的成本。所有這些成本都大於 0,因此無法“清理”交易並允許其使用更多氣體(即生成更多操作碼)。

通常,如果您遇到這種情況,最好重構合約,使其行為方式不會在單個交易中使用太多的 gas。如果可能,您可以將單個函式拆分為多個函式,在不同的點(不同的交易)呼叫,以保存合約的狀態。

有關操作碼成本的列表,請參閱repo。

引用自:https://ethereum.stackexchange.com/questions/57107