Я изучал реализации 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}
Почему существуют эти опкоды и по какой причине? Почему EVM go-ethereum знает коды операций, но не знает реализацию Parity?
РЕДАКТИРОВАТЬ:
Я также нашел это const
в исходном коде go-ethereum:
// unofficial opcodes used for parsing
const (
PUSH OpCode = 0xb0 + iota
DUP
SWAP
)
Они упоминают, что используют его для парсинга и они неофициальны.
Я не знаю, для чего они нужны, но они специфичны для реализации. Действительно, согласно спецификации виртуальной машины Ethereum (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, можно увидеть, что они определяют три дополнительных кода операции 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
кеденк
Бриомкез
кеденк
кеденк