Solidity
從合約供應氣體到執行功能
假設我有這樣的東西
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。