Как разрешаются 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.

Предположительно, контракты не переходят к недействительным адресатам намеренно?

Если бы кто-нибудь мог объяснить, как разрешаются прыжки и места назначения прыжков, я был бы очень признателен.


person Rob N    schedule 27.11.2017    source источник


Ответы (2)


В случае, если это поможет другим:

Путаница возникла из-за того, что EVM считывал байт за байтом, а НЕ слово за словом.

Из примера в вопросе 0x00f8 будет 248-м байтом, а не 248-м словом.

Поскольку каждый код операции имеет длину 1 байт, PC обычно увеличивается на 1 при чтении кода операции.

Однако в случае инструкции PUSH также включается информация о том, сколько следующих байтов должно быть взято в качестве ее операнда.

Например, PUSH2 занимает 2 следующих за ним байта, PUSH6 занимает 6 следующих за ним байтов и так далее. Здесь PC будет увеличиваться на 1 для PUSH, а затем на 2 или 6 соответственно для каждого байта данных, используемых PUSH.

person Rob N    schedule 29.11.2017

Просто хочу отметить, что есть разница между JUMP и JUMPI.

JUMP просто берет 1 элемент из стека, то есть пункт назначения. Обычно это смещение в шестнадцатеричном формате, помещаемое в стек.

JUMPI — это условный переход, который берет 2 верхних элемента из стека, т. е. пункт назначения и условие.

В приведенном вами примере условие равно ISZERO (проверяет, равен ли самый верхний элемент стека 0 или нет).
Таким образом, если это возвращает true, он перейдет к месту назначения, которое является смещение 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/

person arun_munagala    schedule 17.08.2018