Solidity

當我沒有任何事件時,為什麼會從我的 Solidity 程式碼中創建一個“LOG”操作碼?

  • September 7, 2022

我有以下可靠程式碼:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

contract SSimpleStorage {
   uint256 storedNumber;

   function storeNumber(uint256 newNumber) external {
       storedNumber = newNumber;
   }

   function readNumber() external view returns (uint256) {
       return storedNumber;
   }
}

如您所見,沒有發出任何事件。

但是,當我編譯它時,我得到以下操作碼輸出:

編譯命令

solc --optimize --optimize-runs 20000 src/solidity/SSimpleStorage.sol --opcodes

輸出:

PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0xAC DUP1 PUSH2 0x1E PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH1 0x32 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xB6339418 EQ PUSH1 0x37 JUMPI DUP1 PUSH4 0xB63D343F EQ PUSH1 0x49 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x47 PUSH1 0x42 CALLDATASIZE PUSH1 0x4 PUSH1 0x5E JUMP JUMPDEST PUSH1 0x0 SSTORE JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD PUSH1 0x40 MLOAD SWAP1 DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH1 0x6F JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLDATALOAD SWAP2 SWAP1 POP JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 GT SLT DUP9 0xE4 ADDMOD PUSH3 0x74EE3F 0xB3 STOP 0xE8 SWAP6 0xA6 SWAP6 SHL 0x5E 0xAB 0xAE PUSH18 0xA4832B2C422CCC5D7622CEEB64736F6C6343 STOP ADDMOD 0xF STOP CALLER 

如您所見,其中有一個LOG2操作碼。那在那兒做什麼?

更多資訊

我幾乎可以解釋 80% 的二進制/操作碼在做什麼。這些二進制操作碼如下所示:

6080604052348015600f57600080fd5b5060ac8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c8063b6339418146037578063b63d343f146049575b600080fd5b60476042366004605e565b600055565b005b60005460405190815260200160405180910390f35b600060208284031215606f57600080fd5b503591905056fea2646970667358221220111288e4086274ee3fb300e895a6951b5eabae71a4832b2c422ccc5d7622ceeb64736f6c634300080f0033

但是,LOG2令人困惑的是最後一節。

這是到目前為止操作碼所做的事情:

合約創建程式碼

空閒記憶體指針

6080604052

檢查 ETH 是否通過函式呼叫發送,如果是則恢復

348015600f57600080fd

如果沒有使用建構子發送 ETH,則跳轉到此處,並將執行時程式碼複製到記憶體

5b5060ac8061001e600039

返回執行時程式碼。執行時程式碼是放在區塊鏈上的。在我們的合約創建交易中,到此結束。

6000f3fe

執行時程式碼

簽訂契約

空閒記憶體指針

6080604052

檢查 ETH 是否通過函式呼叫發送,如果是則恢復

348015600f57600080fd

短呼叫數據檢查,如果size太小(不夠大,沒有函式選擇器),跳轉到fallback函式(無)

5b5060043610603257

獲取函式選擇器

60003560e01c

檢查函式選擇器是否為b6339418(storeNumber),如果是則將跳轉位置存入棧中

8063b633941814603757

檢查函式選擇器是否為b63d343f(readNumber),如果是則將跳轉位置存入棧中

8063b63d343f14604957

函式體和包裝器

您會注意到它們都以 開頭5b,這是JUMPDEST操作碼,這意味著這些都是跳轉目的地。

備份功能…沒有,所以恢復

5b600080fd

解包calldata,但我們實際上是跳到下面做一些calldata驗證

5b60476042366004605e56

storeNumber 跳轉目的地

寫入storage slot 0,結束通話

5b600055565b00

readNumber 跳轉目的地

從儲存槽 0 讀取

它必須移動記憶體以使其從堆棧中返回,然後以返回結束呼叫。

5b60005460405190815260200160405180910390f3

呼叫數據驗證

我們檢查以確保我們的 calldata 大小正確(我們的商店編號不會太大。這與上面檢查基於大小的函式選擇器的檢查不同。)

5b600060208284031215606f57

如果它太大,我們會還原

600080fd

函式體跳轉位置目前在棧中的低位,將其冒泡並跳轉到它

5b503591905056

不確定部分

如果你到了這一步,顯然出了點問題,但是這裡有很多程式碼,我不確定它是乾什麼用的。

額外的功勞幫助我弄清楚這整件事是為了什麼,但我敢打賭,如果我們明白為什麼有一個 LOG 命令,它會幫助解決這個問題。

a2LOG2操作碼的二進制)

fea2646970667358221220111288e4086274ee3fb300e895a6951b5eabae71a4832b2c422ccc5d7622ceeb64736f6c634300080f0033

我認為這實際上不是程式碼,我認為那是元數據雜湊,也稱為auxdata,它以 開頭a2

a2646970667358221220111288e4086274ee3fb300e895a6951b5eabae71a4832b2c422ccc5d7622ceeb64736f6c634300080f0033

它是描述合約編譯環境的不可訪問的程式碼,如果你用--asm標誌編譯你的程式碼,你可以看到它。

solc --optimize --optimize-runs 20000 src/solidity/SSimpleStorage.sol --asm

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