Go-Ethereum
操作碼 PUSH、DUP 和 SWAP?
我研究了 EVM 實現和它們使用的字節碼序列。我想知道有三個操作碼被 EVM 辨識但實際上是無效的操作碼。
B0 PUSH B1 DUP B2 SWAP
如果我
B0
使用 Geth-EVM 執行操作碼,我會得到以下輸出:./geth-evm-1.8.0-stable --json --code b0 run {"pc":0,"op":176,"gas":"0x2540be400","gasCost":"0x0","memory":"0x","memSize":0,"stack":[],"depth":1,"opName":"PUSH","error":"invalid opcode 0xb0"} {"output":"","gasUsed":"0x2540be400","time":137988,"error":"invalid opcode 0xb0"} {"output":"","gasUsed":"0x2540be400","time":210042,"error":"invalid opcode 0xb0"}
可以看到,操作碼
B0
被辨識並作為PUSH
操作碼處理。同時錯誤欄位寫入invalid opcode 0xb0
。其他兩個操作碼也是如此。我還使用 Parity-EVM 實現對此進行了測試。Parity 不知道操作碼並直接列印錯誤:./parity-evm --json --code b0 {"pc":0,"op":176,"opName":"","gas":"0xffffffffffffffff","gasCost":"0x0","memory":"0x","stack":[],"storage":{},"depth":1} {"error":"EVM: Bad instruction b0","gasUsed":"ffffffffffffffff","time":9881}
為什麼這些操作碼存在,出於什麼原因?為什麼 go-ethereum 的 EVM 知道操作碼但不知道 Parity 的實現?
編輯:
我還在
const
go-ethereum 原始碼中發現了這一點:// unofficial opcodes used for parsing const ( PUSH OpCode = 0xb0 + iota DUP SWAP )
他們提到,他們用它來解析並且他們是非官方的。
規格
我不知道它們的用途,但它們是特定於實現的。事實上,根據乙太坊虛擬機 (EVM) 規範(黃皮書,附錄 H),沒有
0xB0, 0xB1, 0xB2
. 此外,沒有PUSH,DUP
和SWAP
操作碼,而是:
0x60 PUSH1, 0x61 PUSH2,..., 0x7f PUSH32
0x80 DUP1, 0x81 DUP2, ..., 0x8f DUP16
0x90 SWAP1, 0x91 SWAP2, ..., 0x9f SWAP16
GETH EVM
通過檢查 geth 程式碼可以看到,他們
PUSH, DUP and SWAP
在文件中定義了三個額外的操作碼core/vm/opcodes.go
。該文件core/vm/instructions.go
實現了不同的操作碼,很容易看出沒有像 (和) 這樣的函式opPUSH1
,而是只有三個帶有這些標頭檔的函式:opDUP1``opSWAP1
makePush(size int64)
makeDup(size int64)
makeSwap(size int64)
是的,它們用於解析,因為它們將不同的 PUSH1 等案例減少到只有一個案例,在文件中很容易看到
core/vm/jump_table