Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combine mload_32bytes and mstore_32bytes flags #1252

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 4 additions & 12 deletions evm/src/all_stark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,25 +125,17 @@ fn ctl_arithmetic<F: Field>() -> CrossTableLookup<F> {
}

fn ctl_byte_packing<F: Field>() -> CrossTableLookup<F> {
let cpu_packing_looking = TableWithColumns::new(
let cpu_byte32_looking = TableWithColumns::new(
Table::Cpu,
cpu_stark::ctl_data_byte_packing(),
Some(cpu_stark::ctl_filter_byte_packing()),
);
let cpu_unpacking_looking = TableWithColumns::new(
Table::Cpu,
cpu_stark::ctl_data_byte_unpacking(),
Some(cpu_stark::ctl_filter_byte_unpacking()),
cpu_stark::ctl_data_byte32(),
Some(cpu_stark::ctl_filter_byte32()),
);
let byte_packing_looked = TableWithColumns::new(
Table::BytePacking,
byte_packing_stark::ctl_looked_data(),
Some(byte_packing_stark::ctl_looked_filter()),
);
CrossTableLookup::new(
vec![cpu_packing_looking, cpu_unpacking_looking],
byte_packing_looked,
)
CrossTableLookup::new(vec![cpu_byte32_looking], byte_packing_looked)
}

fn ctl_keccak<F: Field>() -> CrossTableLookup<F> {
Expand Down
3 changes: 1 addition & 2 deletions evm/src/cpu/columns/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ pub struct OpsColumnsView<T: Copy> {
pub dup: T,
pub swap: T,
pub context_op: T,
pub mstore_32bytes: T,
pub mload_32bytes: T,
pub memop_32bytes: T,
pub exit_kernel: T,
pub m_op_general: T,

Expand Down
36 changes: 7 additions & 29 deletions evm/src/cpu/cpu_stark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,38 +125,16 @@ pub fn ctl_arithmetic_shift_rows<F: Field>() -> TableWithColumns<F> {
TableWithColumns::new(Table::Cpu, columns, Some(Column::single(COL_MAP.op.shift)))
}

pub fn ctl_data_byte_packing<F: Field>() -> Vec<Column<F>> {
/// We use the same columns for `memop_32bytes` and `is_keccak_sponge`.
/// However, while `MLOAD_32BYTES` and `KeccakSponge` share the same
/// data structure for the memory columns, MSTORE_32BYTES reads from
/// GP channel 4, instead of pushing into it.
pub fn ctl_data_byte32<F: Field>() -> Vec<Column<F>> {
ctl_data_keccak_sponge()
}
Comment on lines +132 to 134
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: as we're re-using ctl_data_keccak_sponge both for MLOAD_32BYTES and MSTORE_32BYTES, perhaps a tiny comment explaining the distinction may be useful? (as the doc there is valid for MLOAD but the last memory channel is being read in the case of MSTORE, not pushed to).


pub fn ctl_filter_byte_packing<F: Field>() -> Column<F> {
Column::single(COL_MAP.op.mload_32bytes)
}

pub fn ctl_data_byte_unpacking<F: Field>() -> Vec<Column<F>> {
// When executing MSTORE_32BYTES, the GP memory channels are used as follows:
// GP channel 0: stack[-1] = context
// GP channel 1: stack[-2] = segment
// GP channel 2: stack[-3] = virt
// GP channel 3: stack[-4] = val
// GP channel 4: stack[-5] = len
let context = Column::single(COL_MAP.mem_channels[0].value[0]);
let segment = Column::single(COL_MAP.mem_channels[1].value[0]);
let virt = Column::single(COL_MAP.mem_channels[2].value[0]);
let val = Column::singles(COL_MAP.mem_channels[3].value);
let len = Column::single(COL_MAP.mem_channels[4].value[0]);

let num_channels = F::from_canonical_usize(NUM_CHANNELS);
let timestamp = Column::linear_combination([(COL_MAP.clock, num_channels)]);

let mut res = vec![context, segment, virt, len, timestamp];
res.extend(val);

res
}

pub fn ctl_filter_byte_unpacking<F: Field>() -> Column<F> {
Column::single(COL_MAP.op.mstore_32bytes)
pub fn ctl_filter_byte32<F: Field>() -> Column<F> {
Column::single(COL_MAP.op.memop_32bytes)
}

pub const MEM_CODE_CHANNEL_IDX: usize = 0;
Expand Down
42 changes: 35 additions & 7 deletions evm/src/cpu/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::cpu::columns::{CpuColumnsView, COL_MAP};
/// behavior.
/// Note: invalid opcodes are not represented here. _Any_ opcode is permitted to decode to
/// `is_invalid`. The kernel then verifies that the opcode was _actually_ invalid.
const OPCODES: [(u8, usize, bool, usize); 16] = [
const OPCODES: [(u8, usize, bool, usize); 14] = [
// (start index of block, number of top bits to check (log2), kernel-only, flag column)
// ADD, MUL, SUB, DIV, MOD, LT, GT and BYTE flags are handled partly manually here, and partly through the Arithmetic table CTL.
// ADDMOD, MULMOD and SUBMOD flags are handled partly manually here, and partly through the Arithmetic table CTL.
Expand All @@ -39,26 +39,26 @@ const OPCODES: [(u8, usize, bool, usize); 16] = [
(0x58, 0, false, COL_MAP.op.pc),
(0x5b, 0, false, COL_MAP.op.jumpdest),
(0x5f, 0, false, COL_MAP.op.push0),
(0x60, 5, false, COL_MAP.op.push), // 0x60-0x7f
(0x80, 4, false, COL_MAP.op.dup), // 0x80-0x8f
(0x90, 4, false, COL_MAP.op.swap), // 0x90-0x9f
(0xee, 0, true, COL_MAP.op.mstore_32bytes),
(0x60, 5, false, COL_MAP.op.push), // 0x60-0x7f
(0x80, 4, false, COL_MAP.op.dup), // 0x80-0x8f
(0x90, 4, false, COL_MAP.op.swap), // 0x90-0x9f
(0xf6, 1, true, COL_MAP.op.context_op), // 0xf6-0xf7
(0xf8, 0, true, COL_MAP.op.mload_32bytes),
(0xf9, 0, true, COL_MAP.op.exit_kernel),
// MLOAD_GENERAL and MSTORE_GENERAL flags are handled manually here.
// MLOAD_32BYTES and MSTORE_32BYTES flags are handled manually here.
];

/// List of combined opcodes requiring a special handling.
/// Each index in the list corresponds to an arbitrary combination
/// of opcodes defined in evm/src/cpu/columns/ops.rs.
const COMBINED_OPCODES: [usize; 6] = [
const COMBINED_OPCODES: [usize; 7] = [
COL_MAP.op.logic_op,
COL_MAP.op.fp254_op,
COL_MAP.op.binary_op,
COL_MAP.op.ternary_op,
COL_MAP.op.shift,
COL_MAP.op.m_op_general,
COL_MAP.op.memop_32bytes,
];

pub fn generate<F: RichField>(lv: &mut CpuColumnsView<F>) {
Expand Down Expand Up @@ -104,6 +104,10 @@ pub fn generate<F: RichField>(lv: &mut CpuColumnsView<F>) {
if opcode == 0xfb || opcode == 0xfc {
lv.op.m_op_general = F::from_bool(kernel);
}

if opcode == 0xee || opcode == 0xf8 {
lv.op.memop_32bytes = F::from_bool(kernel);
}
}

/// Break up an opcode (which is 8 bits long) into its eight bits.
Expand Down Expand Up @@ -192,6 +196,13 @@ pub fn eval_packed_generic<P: PackedField>(
* (opcode - P::Scalar::from_canonical_usize(0xfc_usize))
* lv.op.m_op_general;
yield_constr.constraint(m_op_constr);

// Manually check lv.memop_32bytes.
yield_constr.constraint((P::ONES - kernel_mode) * lv.op.memop_32bytes);
let memop_32bytes_constr = (opcode - P::Scalar::from_canonical_usize(0xee_usize))
* (opcode - P::Scalar::from_canonical_usize(0xf8_usize))
* lv.op.memop_32bytes;
yield_constr.constraint(memop_32bytes_constr);
}

pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
Expand Down Expand Up @@ -294,4 +305,21 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
m_op_constr = builder.mul_extension(m_op_constr, lv.op.m_op_general);

yield_constr.constraint(builder, m_op_constr);

// Manually check lv.memop_32bytes.
let mload_32bytes_opcode =
builder.constant_extension(F::Extension::from_canonical_usize(0xf8_usize));
let mstore_32bytes_opcode =
builder.constant_extension(F::Extension::from_canonical_usize(0xee_usize));

let constr = builder.mul_extension(is_not_kernel_mode, lv.op.memop_32bytes);
yield_constr.constraint(builder, constr);

let mload_32bytes_constr = builder.sub_extension(opcode, mload_32bytes_opcode);
let mstore_32bytes_constr = builder.sub_extension(opcode, mstore_32bytes_opcode);
let mut memop_32bytes_constr =
builder.mul_extension(mstore_32bytes_constr, mload_32bytes_constr);
memop_32bytes_constr = builder.mul_extension(memop_32bytes_constr, lv.op.memop_32bytes);

yield_constr.constraint(builder, memop_32bytes_constr);
}
3 changes: 1 addition & 2 deletions evm/src/cpu/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ const SIMPLE_OPCODES: OpsColumnsView<Option<u32>> = OpsColumnsView {
dup: G_VERYLOW,
swap: G_VERYLOW,
context_op: KERNEL_ONLY_INSTR,
mstore_32bytes: KERNEL_ONLY_INSTR,
mload_32bytes: KERNEL_ONLY_INSTR,
memop_32bytes: KERNEL_ONLY_INSTR,
exit_kernel: None,
m_op_general: KERNEL_ONLY_INSTR,
syscall: None,
Expand Down
6 changes: 3 additions & 3 deletions evm/src/cpu/kernel/asm/core/create_addresses.asm
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ global get_create_address:
global get_create2_address:
// stack: sender, code_hash, salt, retdest
PUSH 0xff PUSH 0 %mstore_kernel_general
%stack (sender, code_hash, salt, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 1, sender, 20, get_create2_address_contd, salt, code_hash, retdest)
%stack (sender, code_hash, salt, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 1, 20, sender, get_create2_address_contd, salt, code_hash, retdest)
%jump(mstore_unpacking)
get_create2_address_contd:
POP
%stack (salt, code_hash, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 21, salt, 32, get_create2_address_contd2, code_hash, retdest)
%stack (salt, code_hash, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 21, 32, salt, get_create2_address_contd2, code_hash, retdest)
%jump(mstore_unpacking)
get_create2_address_contd2:
POP
%stack (code_hash, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 53, code_hash, 32, get_create2_address_finish, retdest)
%stack (code_hash, retdest) -> (0, @SEGMENT_KERNEL_GENERAL, 53, 32, code_hash, get_create2_address_finish, retdest)
%jump(mstore_unpacking)
get_create2_address_finish:
POP
Expand Down
4 changes: 2 additions & 2 deletions evm/src/cpu/kernel/asm/core/precompiles/bn_add.asm
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ bn_add_return:
// Store the result (x, y) to the parent's return data using `mstore_unpacking`.
%mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 64)
%mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT)
%stack (parent_ctx, x, y) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, x, 32, bn_add_contd6, parent_ctx, y)
%stack (parent_ctx, x, y) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, 32, x, bn_add_contd6, parent_ctx, y)
%jump(mstore_unpacking)
bn_add_contd6:
POP
%stack (parent_ctx, y) -> (parent_ctx, @SEGMENT_RETURNDATA, 32, y, 32, pop_and_return_success)
%stack (parent_ctx, y) -> (parent_ctx, @SEGMENT_RETURNDATA, 32, 32, y, pop_and_return_success)
%jump(mstore_unpacking)
4 changes: 2 additions & 2 deletions evm/src/cpu/kernel/asm/core/precompiles/bn_mul.asm
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ bn_mul_return:
// Store the result (Px, Py) to the parent's return data using `mstore_unpacking`.
%mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 64)
%mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT)
%stack (parent_ctx, Px, Py) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, Px, 32, bn_mul_contd6, parent_ctx, Py)
%stack (parent_ctx, Px, Py) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, 32, Px, bn_mul_contd6, parent_ctx, Py)
%jump(mstore_unpacking)
bn_mul_contd6:
POP
%stack (parent_ctx, Py) -> (parent_ctx, @SEGMENT_RETURNDATA, 32, Py, 32, pop_and_return_success)
%stack (parent_ctx, Py) -> (parent_ctx, @SEGMENT_RETURNDATA, 32, 32, Py, pop_and_return_success)
%jump(mstore_unpacking)
2 changes: 1 addition & 1 deletion evm/src/cpu/kernel/asm/core/precompiles/ecrec.asm
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ ecrec_return:
// Store the result address to the parent's return data using `mstore_unpacking`.
%mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 32)
%mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT)
%stack (parent_ctx, address) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, address, 32, pop_and_return_success)
%stack (parent_ctx, address) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, 32, address, pop_and_return_success)
%jump(mstore_unpacking)

// On bad input, return empty return data but still return success.
Expand Down
4 changes: 2 additions & 2 deletions evm/src/cpu/kernel/asm/core/precompiles/expmod.asm
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ expmod_contd:
// stack: cur_address=out+l_M_128-1, end_address=out-1, l_M_128, l_M%16, kexit_info
DUP1 %mload_current_general
%stack (cur_limb, cur_address, end_address, l_M_128, l_M_mod16, kexit_info) ->
(@SEGMENT_RETURNDATA, 0, cur_limb, l_M_mod16, cur_address, end_address, l_M_128, kexit_info)
(@SEGMENT_RETURNDATA, 0, l_M_mod16, cur_limb, cur_address, end_address, l_M_128, kexit_info)
%mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT)
%mstore_unpacking
// stack: offset, cur_address, end_address, l_M_128, kexit_info
Expand All @@ -428,7 +428,7 @@ expmod_store_loop:
DUP1 %mload_current_general
%stack (cur_limb, cur_address, offset, end_address, l_M_128, kexit_info) ->
(offset, cur_limb, cur_address, end_address, l_M_128, kexit_info)
%stack (offset, cur_limb) -> (@SEGMENT_RETURNDATA, offset, cur_limb, 16)
%stack (offset, cur_limb) -> (@SEGMENT_RETURNDATA, offset, 16, cur_limb)
%mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT)
%mstore_unpacking
// stack: offset', cur_address, end_address, l_M_128, kexit_info)
Expand Down
2 changes: 1 addition & 1 deletion evm/src/cpu/kernel/asm/core/precompiles/rip160.asm
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@ rip160_contd:
// Store the result hash to the parent's return data using `mstore_unpacking`.
%mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 32)
%mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT)
%stack (parent_ctx, hash) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, hash, 32, pop_and_return_success)
%stack (parent_ctx, hash) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, 32, hash, pop_and_return_success)
%jump(mstore_unpacking)
2 changes: 1 addition & 1 deletion evm/src/cpu/kernel/asm/core/precompiles/sha256.asm
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,5 @@ sha256_contd:
// Store the result hash to the parent's return data using `mstore_unpacking`.
%mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 32)
%mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT)
%stack (parent_ctx, hash) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, hash, 32, pop_and_return_success)
%stack (parent_ctx, hash) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, 32, hash, pop_and_return_success)
%jump(mstore_unpacking)
2 changes: 1 addition & 1 deletion evm/src/cpu/kernel/asm/core/precompiles/snarkv.asm
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,5 @@ got_result:
// Store the result bool (repr. by a U256) to the parent's return data using `mstore_unpacking`.
%mstore_parent_context_metadata(@CTX_METADATA_RETURNDATA_SIZE, 32)
%mload_context_metadata(@CTX_METADATA_PARENT_CONTEXT)
%stack (parent_ctx, address) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, address, 32, pop_and_return_success)
%stack (parent_ctx, address) -> (parent_ctx, @SEGMENT_RETURNDATA, 0, 32, address, pop_and_return_success)
%jump(mstore_unpacking)
7 changes: 3 additions & 4 deletions evm/src/cpu/kernel/asm/main.asm
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,10 @@ initialize_block_bloom:
initialize_bloom_loop:
// stack: i, len, offset, retdest
DUP2 DUP2 EQ %jumpi(initialize_bloom_loop_end)
PUSH 32 // Bloom word length
// stack: word_len, i, len, offset, retdest
// Load the next `block_bloom_before` word.
DUP2 %add_const(8) %mload_kernel(@SEGMENT_GLOBAL_BLOCK_BLOOM)
// stack: bloom_word, word_len, i, len, offset, retdest
DUP1 %add_const(8) %mload_kernel(@SEGMENT_GLOBAL_BLOCK_BLOOM)
PUSH 32 // Bloom word length
// stack: word_len, bloom_word, i, len, offset, retdest
DUP5 PUSH @SEGMENT_BLOCK_BLOOM PUSH 0 // Bloom word address in SEGMENT_BLOCK_BLOOM
%mstore_unpacking
// stack: new_offset, i, len, old_offset, retdest
Expand Down
2 changes: 1 addition & 1 deletion evm/src/cpu/kernel/asm/memory/core.asm
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
// Store a big-endian u32, consisting of 4 bytes (c_3, c_2, c_1, c_0).
%macro mstore_u32
// stack: context, segment, offset, value
%stack (addr: 3, value) -> (addr, value, 4, %%after)
%stack (addr: 3, value) -> (addr, 4, value, %%after)
%jump(mstore_unpacking)
%%after:
// stack: offset
Expand Down
8 changes: 4 additions & 4 deletions evm/src/cpu/kernel/asm/memory/packing.asm
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@ global mload_packing_u64_LE:
// Pre stack: context, segment, offset, value, len, retdest
// Post stack: offset'
global mstore_unpacking:
// stack: context, segment, offset, value, len, retdest
%stack(context, segment, offset, value, len, retdest) -> (context, segment, offset, value, len, offset, len, retdest)
// stack: context, segment, offset, value, len, offset, len, retdest
// stack: context, segment, offset, len, value, retdest
%stack(context, segment, offset, len, value, retdest) -> (context, segment, offset, len, value, offset, len, retdest)
// stack: context, segment, offset, len, value, offset, len, retdest
MSTORE_32BYTES
// stack: offset, len, retdest
ADD SWAP1
// stack: retdest, offset'
JUMP

%macro mstore_unpacking
%stack (addr: 3, value, len) -> (addr, value, len, %%after)
%stack (addr: 3, len, value) -> (addr, len, value, %%after)
%jump(mstore_unpacking)
%%after:
%endmacro
Expand Down
1 change: 1 addition & 0 deletions evm/src/cpu/kernel/asm/memory/syscalls.asm
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ global sys_mstore:
PUSH @SEGMENT_MAIN_MEMORY
GET_CONTEXT
// stack: addr: 3, value, len, kexit_info
%stack (ADDR: 3, value, len, kexit_info) -> (ADDR, len, value, kexit_info)
MSTORE_32BYTES
// stack: kexit_info
EXIT_KERNEL
Expand Down
8 changes: 4 additions & 4 deletions evm/src/cpu/kernel/asm/mpt/hash/hash.asm
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ mpt_hash_hash_if_rlp:
mpt_hash_hash_rlp:
// stack: result, result_len, retdest
%stack (result, result_len)
// context, segment, offset, value, len, retdest
-> (0, @SEGMENT_RLP_RAW, 0, result, result_len, mpt_hash_hash_rlp_after_unpacking)
// context, segment, offset, len, value, retdest
-> (0, @SEGMENT_RLP_RAW, 0, result_len, result, mpt_hash_hash_rlp_after_unpacking)
%jump(mstore_unpacking)
mpt_hash_hash_rlp_after_unpacking:
// stack: result_len, retdest
Expand Down Expand Up @@ -226,7 +226,7 @@ encode_node_branch_prepend_prefix:
SWAP2 %increment SWAP2 // rlp_pos += 1
%%unpack:
%stack (result_len, result, rlp_pos, rlp_start, base_offset, node_payload_ptr, encode_value, retdest)
-> (rlp_pos, result, result_len, %%after_unpacking,
-> (rlp_pos, result_len, result, %%after_unpacking,
rlp_start, base_offset, node_payload_ptr, encode_value, retdest)
%jump(mstore_unpacking_rlp)
%%after_unpacking:
Expand Down Expand Up @@ -265,7 +265,7 @@ encode_node_extension_after_hex_prefix:
%increment // rlp_pos += 1
encode_node_extension_unpack:
%stack (rlp_pos, rlp_start, result, result_len, node_payload_ptr)
-> (rlp_pos, result, result_len, encode_node_extension_after_unpacking, rlp_start)
-> (rlp_pos, result_len, result, encode_node_extension_after_unpacking, rlp_start)
%jump(mstore_unpacking_rlp)
encode_node_extension_after_unpacking:
// stack: rlp_pos, rlp_start, retdest
Expand Down
Loading