Openzeppelin

如何訪問通過“return(0, returndatasize())”返回的值?

  • September 1, 2021

我正在查看_delegateOpenZeppelin 的Proxy.sol中的函式:

/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
   assembly {
       // Copy msg.data. We take full control of memory in this inline assembly
       // block because it will not return to Solidity code. We overwrite the
       // Solidity scratch pad at memory position 0.
       calldatacopy(0, 0, calldatasize())

       // Call the implementation.
       // out and outsize are 0 because we don't know the size yet.
       let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

       // Copy the returned data.
       returndatacopy(0, 0, returndatasize())

       switch result
       // delegatecall returns 0 on error.
       case 0 {
           revert(0, returndatasize())
       }
       default {
           return(0, returndatasize())
       }
   }
}

而且我注意到雖然函式聲明缺少 a returns (type),但程式碼通過內聯彙編返回一個值。在我看來,Solidity 一開始就允許對其進行編譯,但無論如何。

我試圖了解在哪裡可以訪問它。顯然,來自 Solidity 的高級呼叫無法訪問返回數據。它是否打算被其他使用returndatacopy指令的低級彙編程式碼使用?(評論中提到的“外部呼叫者”)

solidity編譯器 ( solc ) 會將返回語句轉換為return(ptr, size)操作碼。

呼叫者為了訪問被呼叫者返回的數據,在早期的 EVM 版本中,必須傳遞一個記憶體指針和一個記憶體大小。例如call的最後兩個參數是outoutSize。其他操作碼delegatecall, staticcall,callcode具有相同的參數。

call(gas, address, value, in, insize, out, outsize)

這種機制的一個缺點是呼叫者需要outSize提前知道才能保留記憶體。

隨著delegatecallHomestead 中引入 fork編寫代理是可能的,但存在代理無法預先分配記憶體的問題。

最後,在拜占庭分支中,一些新的操作碼允許代理在呼叫之前不需要分配輸出記憶體:returndatasize()returndatacopy(to, from, size).

呼叫後returndatasize()包含應用程序返回的數據,並且可以使用returndatacopy(to, from, size)將數據複製到呼叫者記憶體中。

let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

delegatecall輸出參數中都設置為零:out = 0outSize = 0

下一條語句將所有返回的數據從位置 0 複製到從 0 開始的代理記憶體。

returndatacopy(0, 0, returndatasize())

筆記:

  • returndatacopy如果函式呼叫失敗,returndatasize也可以用於複製還原原因。

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