Как разрешаются JUMP и JUMPDEST для байт-кода Ethereum?
Я искал информацию о том, как Ethereum справляется с прыжками и пунктами назначения прыжков. Из разных блогов и желтой бумаги я обнаружил следующее:
Операнд, взятый JUMP
и первый из двух операндов, взятых JUMPI
являются значением PC
устанавливается на (предположим, первое значение стека!= 0 в случае JUMPI
).
Однако, глядя на код создания этого контракта (как коды операций), первые несколько кодов операций / значений:
PUSH1 0x60
PUSH1 0x40
MSTORE
CALLDATASIZE
ISZERO
PUSH2 0x00f8
JUMPI
Насколько я понимаю, это означает, что если значение помещается в стек ISZERO
!= 0 тогда PC
изменится на 0x00f8
как JUMPI
берет два из стека, проверяет, является ли секунда 0 и если не устанавливает PC
к значению своего первого операнда.
У меня проблема в том, что 0x00f8
в десятичном виде 248
, Похоже, что 248-я позиция в контракте MSTORE
и не JUMPDEST
, что приведет к сбою контракта при его исполнении, так как JUMP*
может указывать только на действительный JUMPDEST
,
Предположительно контракты не переходят к недействительным пунктам назначения специально?
Если бы кто-нибудь мог объяснить, как разрешаются прыжки и места назначения прыжков, я был бы очень благодарен.
2 ответа
В случае, если это помогает другим:
Путаница возникла из чтения EVM побайтово, а не слово за словом.
Из примера в вопросе, 0x00f8
будет 248-й байт, а не 248-е слово.
Поскольку каждый код операции имеет длину 1 байт PC
обычно увеличивается на 1 при чтении кода операции.
Однако в случае PUSH
инструкция, информация о том, сколько из следующих байтов должно быть взято как его операнд, также включена.
Например PUSH2
занимает 2 байта, которые следуют за ним, PUSH6
занимает 6 байтов, которые следуют за ним, и так далее. Вот PC
будет увеличен на 1 для PUSH
а затем 2 или 6 соответственно для каждого байта данных, используемых PUSH
,
Просто хочу отметить, что есть разница в JUMP и JUMPI.
JUMP просто берет 1 элемент из стека, т.е. пункт назначения. Как правило, это смещение в шестнадцатеричном формате, помещаемое в стек
JUMPI - это условный переход, который берет 2 верхних элемента из стека, т.е. назначение и условие.
В приведенном вами примере условие ISZERO (проверяет, равен ли самый верхний элемент стека 0 или нет).
Таким образом, если это возвращает true, оно будет JUMP к назначению, которое является смещением 0x00f8(248 в десятичном виде).
Если условие ложно, оно просто увеличит счетчик программы на 1.
В упомянутом вами контракте это код операции JUMPDEST по адресу (Счетчик программ)248.
Счетчик программы зависит от кода операции. Сколько байтов вставляет код операции в стек и т. Д. например
PUSH1 0x60 - PC[0]
PUSH1 0x40 - PC[2]
MSTORE - PC[4]
CALLDATASIZE- PC[5]
ISZERO - PC[6]
PUSH2 0x00f8- PC[7]
JUMPI - PC[10]
Возможно, этот сайт поможет вам лучше понять коды операций https://ethervm.io/