如何避免/檢測多個內部交易的耗氣副作用?
在我在 github 中打開一個問題之後,這讓我很困擾。問題中描述的操作發生在 avsa 關於創建 DAO 的教程中,生成了兩個內部事務,如下所示: 很快,內部事務是:
- 將 DAO 中請求操作的狀態更改為“已完成”
- 通過向另一個合約發送交易來實際執行操作
第一個內部事務成功完成 - 這意味著將 DAO 中的操作更新為“已完成”狀態。第二個失敗了,很可能是因為它耗盡了氣體(多次嘗試產生相同的結果,而添加 100,000 氣體使其多次工作)。
我認為在真正的 DAO 中發生這種事情的影響是顯而易見的。我(錯誤地)假設如果第二筆交易用完了gas,那麼整個操作(包括第一筆交易)將恢復。
正如 eth 的評論所建議的那樣,我將就這種情況提出一個具體問題 - 我如何在契約中檢測到它?改變操作的順序會有幫助嗎?
整個操作沒有恢復,因為整個交易的交易來源提供了足夠的氣體。 如果提供的 gas 不足,那麼您將觀察到您所期望的行為,其中兩個內部交易都將被還原。
第二個內部交易因為 gas 用完而被撤銷。為了檢測到這一點,被呼叫的函式可以包含一個
true
返回值(如果需要,使用一個元組)。呼叫者可以顯式地檢查這個true
值,因為氣體不足會返回預設值 0 (false
)。這是發生的事情的一個例子。第一次(內部)交易需要 200 個 gas,第二個交易需要 700 個 gas。整體交易提供了 1000 個 gas。提供給第二個交易的 gas 少於 700。 所有的 gas 都沒有完全提供給第二個內部交易。解釋見底部註釋。
以下是一些可能有幫助的事情:
- 正如您所建議的那樣更改操作的順序可能會有所幫助,因為用完 gas 的交易現在將是第一個並且有所有可用的 gas 開始(而不是要求退還 gas)
- 保持操作順序相同,但對於第一個事務,通過語法限制函式呼叫發送的氣體。
.gas(amount)
這可以讓第二筆交易獲得更多的氣體。(在上面的例子中,它可以明確地將第一次內部交易限制為 220 個 gas,這樣退還的 gas 就只有 20 個。)最簡單的解決方案是讓交易源在交易中提供更多的gas。幾乎沒有缺點,因為所有未使用的 gas 都將被退還,並且由於內部交易可能有大量可用的 gas,因此可以避免極端情況。
注意為什麼不向呼叫提供“所有”氣體(內部交易):
chriseth (Solidity 作者)說:
這是 EVM 的古怪之處之一。你不能只說“把我所有的汽油和電話一起送出去”,你總是必須給出一個明確的號碼。我們確實有 GAS 操作碼,它為我們提供了仍然可用的 gas 量,但問題是執行呼叫本身也會消耗一些 gas,所以我們必須從 GAS 提供的值中減去呼叫成本的 gas 量,並且我們還必須減去執行減法所需的氣體量……
編輯:澄清可能的誤解 1) 契約從不支付汽油——他們可以為另一個契約呼叫保留/委託/限制汽油。2)恢復的交易仍然包含在區塊中並支付gas。