Out-of-Gas
當 throw 發生時,整個事務是否會恢復?
我有一個呼叫另一個呼叫另一個合約的合約。如果在第二個合約的某處發生拋出(或氣體不足錯誤),整個交易是否會被還原,或者只是第二個和第三個合約中的東西會恢復,而從第一個合約執行還站著嗎?
在 Solidity 中,預設情況下是的。
在 EVM 級別上,拋出(錯誤跳轉、氣體耗盡或任何其他異常)只會恢復它在內部的呼叫。Solidity 有助於將異常繼續向下堆棧,直到一切都被撤消。
可以使用較低級別的程式碼(特別是 address.call())來防止這種情況。這是一個將其用作即興嘗試擷取結構的範例。
為了補充@Matthew 的答案,這取決於如何在 Solidity 中進行呼叫。
如果
C
呼叫D.foo()
, 並foo
執行 athrow
,那麼是的,整個事務將被還原。如果
C
像 , 一樣執行“較低級別的原始呼叫”D.call(bytes4(sha3('foo()')))
,並且foo
執行 athrow
,則僅foo
還原及其子呼叫。這是因為原始呼叫不會傳播任何異常:原始呼叫D.call
僅返回一個布爾值,指示呼叫是否成功或遇到異常。更多細節
在 Solidity 中,a
throw
通過生成導致無效跳轉目標的字節碼來引發異常。(對於其他情況,請參閱Solidity 編譯到無效跳轉目的地的所有情況。)從 Solidity 的角度來看,未吞下或未擷取/未處理的異常將導致整個事務被還原。
目前在 Solidity 中沒有辦法擷取異常,因此一個異常,例如
throw
,將導致整個事務被還原。但是,原始呼叫“吞沒”異常:原始呼叫不會傳播異常,這就是為什麼只有子呼叫會被還原。