From 6a7be0c434934175bb6da1f3525c025b3f743824 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Fri, 7 Jun 2024 11:28:12 -0400 Subject: [PATCH] feat(avm): e2e proving of storage (#6967) Co-authored-by: IlyasRidhuan --- avm-transpiler/src/transpile.rs | 8 +- barretenberg/cpp/pil/avm/avm_main.pil | 7 +- .../relations/generated/avm/avm_main.hpp | 120 ++++----- .../vm/avm_trace/avm_deserialization.cpp | 6 +- .../vm/avm_trace/avm_execution.cpp | 11 +- .../barretenberg/vm/avm_trace/avm_trace.cpp | 151 +++++++++-- .../barretenberg/vm/avm_trace/avm_trace.hpp | 4 +- .../vm/generated/avm_verifier.cpp | 21 +- .../vm/tests/avm_execution.test.cpp | 244 +++++++++++++++++- .../barretenberg/vm/tests/avm_kernel.test.cpp | 46 ++-- .../bb-prover/src/avm_proving.test.ts | 10 +- .../simulator/src/avm/opcodes/storage.ts | 4 +- 12 files changed, 489 insertions(+), 143 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index c4402bb2642..099dfcbd06f 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -894,7 +894,7 @@ fn handle_storage_write( }; let src_offset_maybe = inputs[1]; - let (src_offset, src_size) = match src_offset_maybe { + let (src_offset, size) = match src_offset_maybe { ValueOrArray::HeapArray(HeapArray { pointer, size }) => (pointer.0, size), _ => panic!("Storage write address inputs should be an array of values"), }; @@ -904,7 +904,7 @@ fn handle_storage_write( indirect: Some(ZEROTH_OPERAND_INDIRECT), operands: vec![ AvmOperand::U32 { value: src_offset as u32 }, - AvmOperand::U32 { value: src_size as u32 }, + AvmOperand::U32 { value: size as u32 }, AvmOperand::U32 { value: slot_offset as u32 }, ], ..Default::default() @@ -961,7 +961,7 @@ fn handle_storage_read( }; let dest_offset_maybe = destinations[0]; - let (dest_offset, src_size) = match dest_offset_maybe { + let (dest_offset, size) = match dest_offset_maybe { ValueOrArray::HeapArray(HeapArray { pointer, size }) => (pointer.0, size), _ => panic!("Storage write address inputs should be an array of values"), }; @@ -971,7 +971,7 @@ fn handle_storage_read( indirect: Some(FIRST_OPERAND_INDIRECT), operands: vec![ AvmOperand::U32 { value: slot_offset as u32 }, - AvmOperand::U32 { value: src_size as u32 }, + AvmOperand::U32 { value: size as u32 }, AvmOperand::U32 { value: dest_offset as u32 }, ], ..Default::default() diff --git a/barretenberg/cpp/pil/avm/avm_main.pil b/barretenberg/cpp/pil/avm/avm_main.pil index 4ef91489575..3b0ec454890 100644 --- a/barretenberg/cpp/pil/avm/avm_main.pil +++ b/barretenberg/cpp/pil/avm/avm_main.pil @@ -391,7 +391,7 @@ namespace avm_main(256); pol KERNEL_OUTPUT_SELECTORS = ( sel_op_note_hash_exists + sel_op_emit_note_hash + sel_op_nullifier_exists + sel_op_emit_nullifier + sel_op_l1_to_l2_msg_exists + - sel_op_emit_unencrypted_log + sel_op_emit_l2_to_l1_msg + sel_op_sload + sel_op_sstore + sel_op_emit_unencrypted_log + sel_op_emit_l2_to_l1_msg ); #[KERNEL_OUTPUT_ACTIVE_CHECK] KERNEL_OUTPUT_SELECTORS * (1 - q_kernel_output_lookup) = 0; @@ -454,7 +454,10 @@ namespace avm_main(256); // Note: External call gas cost is not constrained pol commit gas_cost_active; pol commit mem_op_activate_gas; // TODO: remove this one - gas_cost_active - OPCODE_SELECTORS - ALL_CTRL_FLOW_SEL - mem_op_activate_gas = 0; + // TODO: remove sload and sstore from here + // This temporarily disables gas tracking for sload and sstore because our gas + // tracking doesn't work properly for instructions that span multiple rows + gas_cost_active - OPCODE_SELECTORS - ALL_CTRL_FLOW_SEL - sel_op_sload - sel_op_sstore - mem_op_activate_gas = 0; // Program counter must increment if not jumping or returning #[PC_INCREMENT] diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp index f8918afc823..22d8bb78bf2 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp @@ -937,14 +937,12 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(78); - auto tmp = (((((((((avm_main_sel_op_note_hash_exists + avm_main_sel_op_emit_note_hash) + - avm_main_sel_op_nullifier_exists) + - avm_main_sel_op_emit_nullifier) + - avm_main_sel_op_l1_to_l2_msg_exists) + - avm_main_sel_op_emit_unencrypted_log) + - avm_main_sel_op_emit_l2_to_l1_msg) + - avm_main_sel_op_sload) + - avm_main_sel_op_sstore) * + auto tmp = (((((((avm_main_sel_op_note_hash_exists + avm_main_sel_op_emit_note_hash) + + avm_main_sel_op_nullifier_exists) + + avm_main_sel_op_emit_nullifier) + + avm_main_sel_op_l1_to_l2_msg_exists) + + avm_main_sel_op_emit_unencrypted_log) + + avm_main_sel_op_emit_l2_to_l1_msg) * (-avm_main_q_kernel_output_lookup + FF(1))); tmp *= scaling_factor; std::get<78>(evals) += tmp; @@ -1061,42 +1059,42 @@ template class avm_mainImpl { Avm_DECLARE_VIEWS(92); auto tmp = - (((avm_main_gas_cost_active - - (((((((avm_main_sel_op_fdiv + - ((((((((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_mul) + - avm_main_sel_op_div) + - avm_main_sel_op_not) + - avm_main_sel_op_eq) + - avm_main_sel_op_lt) + - avm_main_sel_op_lte) + - avm_main_sel_op_shr) + - avm_main_sel_op_shl) + - avm_main_sel_op_cast)) + - ((avm_main_sel_op_and + avm_main_sel_op_or) + avm_main_sel_op_xor)) + - (avm_main_sel_cmov + avm_main_sel_mov)) + - ((((avm_main_sel_op_radix_le + avm_main_sel_op_sha256) + avm_main_sel_op_poseidon2) + - avm_main_sel_op_keccak) + - avm_main_sel_op_pedersen)) + - ((((((((((avm_main_sel_op_sender + avm_main_sel_op_address) + avm_main_sel_op_storage_address) + - avm_main_sel_op_chain_id) + - avm_main_sel_op_version) + - avm_main_sel_op_block_number) + - avm_main_sel_op_coinbase) + - avm_main_sel_op_timestamp) + - avm_main_sel_op_fee_per_l2_gas) + - avm_main_sel_op_fee_per_da_gas) + - avm_main_sel_op_transaction_fee)) + - ((((((((avm_main_sel_op_note_hash_exists + avm_main_sel_op_emit_note_hash) + + (((((avm_main_gas_cost_active - + (((((((avm_main_sel_op_fdiv + + ((((((((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_mul) + + avm_main_sel_op_div) + + avm_main_sel_op_not) + + avm_main_sel_op_eq) + + avm_main_sel_op_lt) + + avm_main_sel_op_lte) + + avm_main_sel_op_shr) + + avm_main_sel_op_shl) + + avm_main_sel_op_cast)) + + ((avm_main_sel_op_and + avm_main_sel_op_or) + avm_main_sel_op_xor)) + + (avm_main_sel_cmov + avm_main_sel_mov)) + + ((((avm_main_sel_op_radix_le + avm_main_sel_op_sha256) + avm_main_sel_op_poseidon2) + + avm_main_sel_op_keccak) + + avm_main_sel_op_pedersen)) + + ((((((((((avm_main_sel_op_sender + avm_main_sel_op_address) + avm_main_sel_op_storage_address) + + avm_main_sel_op_chain_id) + + avm_main_sel_op_version) + + avm_main_sel_op_block_number) + + avm_main_sel_op_coinbase) + + avm_main_sel_op_timestamp) + + avm_main_sel_op_fee_per_l2_gas) + + avm_main_sel_op_fee_per_da_gas) + + avm_main_sel_op_transaction_fee)) + + ((((((avm_main_sel_op_note_hash_exists + avm_main_sel_op_emit_note_hash) + avm_main_sel_op_nullifier_exists) + avm_main_sel_op_emit_nullifier) + avm_main_sel_op_l1_to_l2_msg_exists) + avm_main_sel_op_emit_unencrypted_log) + - avm_main_sel_op_emit_l2_to_l1_msg) + - avm_main_sel_op_sload) + - avm_main_sel_op_sstore)) + - (avm_main_sel_op_dagasleft + avm_main_sel_op_l2gasleft))) - - (((avm_main_sel_jump + avm_main_sel_jumpi) + avm_main_sel_internal_call) + - avm_main_sel_internal_return)) - + avm_main_sel_op_emit_l2_to_l1_msg)) + + (avm_main_sel_op_dagasleft + avm_main_sel_op_l2gasleft))) - + (((avm_main_sel_jump + avm_main_sel_jumpi) + avm_main_sel_internal_call) + + avm_main_sel_internal_return)) - + avm_main_sel_op_sload) - + avm_main_sel_op_sstore) - avm_main_mem_op_activate_gas); tmp *= scaling_factor; std::get<92>(evals) += tmp; @@ -1131,14 +1129,12 @@ template class avm_mainImpl { avm_main_sel_op_fee_per_l2_gas) + avm_main_sel_op_fee_per_da_gas) + avm_main_sel_op_transaction_fee)) + - ((((((((avm_main_sel_op_note_hash_exists + avm_main_sel_op_emit_note_hash) + - avm_main_sel_op_nullifier_exists) + - avm_main_sel_op_emit_nullifier) + - avm_main_sel_op_l1_to_l2_msg_exists) + - avm_main_sel_op_emit_unencrypted_log) + - avm_main_sel_op_emit_l2_to_l1_msg) + - avm_main_sel_op_sload) + - avm_main_sel_op_sstore)) + + ((((((avm_main_sel_op_note_hash_exists + avm_main_sel_op_emit_note_hash) + + avm_main_sel_op_nullifier_exists) + + avm_main_sel_op_emit_nullifier) + + avm_main_sel_op_l1_to_l2_msg_exists) + + avm_main_sel_op_emit_unencrypted_log) + + avm_main_sel_op_emit_l2_to_l1_msg)) + (avm_main_sel_op_dagasleft + avm_main_sel_op_l2gasleft))) * (avm_main_pc_shift - (avm_main_pc + FF(1)))); tmp *= scaling_factor; @@ -1192,14 +1188,12 @@ template class avm_mainImpl { avm_main_sel_op_fee_per_l2_gas) + avm_main_sel_op_fee_per_da_gas) + avm_main_sel_op_transaction_fee)) + - ((((((((avm_main_sel_op_note_hash_exists + avm_main_sel_op_emit_note_hash) + - avm_main_sel_op_nullifier_exists) + - avm_main_sel_op_emit_nullifier) + - avm_main_sel_op_l1_to_l2_msg_exists) + - avm_main_sel_op_emit_unencrypted_log) + - avm_main_sel_op_emit_l2_to_l1_msg) + - avm_main_sel_op_sload) + - avm_main_sel_op_sstore)) + + ((((((avm_main_sel_op_note_hash_exists + avm_main_sel_op_emit_note_hash) + + avm_main_sel_op_nullifier_exists) + + avm_main_sel_op_emit_nullifier) + + avm_main_sel_op_l1_to_l2_msg_exists) + + avm_main_sel_op_emit_unencrypted_log) + + avm_main_sel_op_emit_l2_to_l1_msg)) + (avm_main_sel_op_dagasleft + avm_main_sel_op_l2gasleft)) * (avm_main_call_ptr - avm_main_space_id)); tmp *= scaling_factor; @@ -1576,14 +1570,12 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(139); - auto tmp = (((((((((avm_main_sel_op_note_hash_exists + avm_main_sel_op_emit_note_hash) + - avm_main_sel_op_nullifier_exists) + - avm_main_sel_op_emit_nullifier) + - avm_main_sel_op_l1_to_l2_msg_exists) + - avm_main_sel_op_emit_unencrypted_log) + - avm_main_sel_op_emit_l2_to_l1_msg) + - avm_main_sel_op_sload) + - avm_main_sel_op_sstore) * + auto tmp = (((((((avm_main_sel_op_note_hash_exists + avm_main_sel_op_emit_note_hash) + + avm_main_sel_op_nullifier_exists) + + avm_main_sel_op_emit_nullifier) + + avm_main_sel_op_l1_to_l2_msg_exists) + + avm_main_sel_op_emit_unencrypted_log) + + avm_main_sel_op_emit_l2_to_l1_msg) * (avm_kernel_side_effect_counter_shift - (avm_kernel_side_effect_counter + FF(1)))); tmp *= scaling_factor; std::get<139>(evals) += tmp; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp index 49cf55d0ee2..e0f9deeb613 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp @@ -71,8 +71,8 @@ const std::unordered_map> OPCODE_WIRE_FORMAT = { OpCode::EMITNULLIFIER, getter_format }, // TODO: new format for these { OpCode::EMITUNENCRYPTEDLOG, getter_format }, { OpCode::SENDL2TOL1MSG, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32 } }, - { OpCode::SLOAD, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32 } }, - { OpCode::SSTORE, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32 } }, + { OpCode::SLOAD, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } }, + { OpCode::SSTORE, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } }, /*TODO: leafIndexOffset is not constrained*/ { OpCode::NOTEHASHEXISTS, { OperandType::INDIRECT, @@ -259,7 +259,7 @@ std::vector Deserialization::parse(std::vector const& byte uint8_t tag_u8 = bytecode.at(pos); if (tag_u8 == static_cast(AvmMemoryTag::U0) || tag_u8 > MAX_MEM_TAG) { throw_or_abort("Instruction tag is invalid at position " + std::to_string(pos) + - " value: " + std::to_string(tag_u8) + " for opcode: " + to_hex(opcode)); + " value: " + std::to_string(tag_u8) + " for opcode: " + to_string(opcode)); } operands.emplace_back(static_cast(tag_u8)); break; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp index 3ebe04cea52..15353bb42f8 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp @@ -61,7 +61,6 @@ std::tuple Execution::prove(std::vector Execution::gen_trace(std::vector const& instructio std::get(inst.operands.at(1))); break; case OpCode::SLOAD: - trace_builder.op_sload(std::get(inst.operands.at(1)), std::get(inst.operands.at(2))); + trace_builder.op_sload(std::get(inst.operands.at(0)), + std::get(inst.operands.at(1)), + std::get(inst.operands.at(2)), + std::get(inst.operands.at(3))); break; case OpCode::SSTORE: - trace_builder.op_sstore(std::get(inst.operands.at(1)), std::get(inst.operands.at(2))); + trace_builder.op_sstore(std::get(inst.operands.at(0)), + std::get(inst.operands.at(1)), + std::get(inst.operands.at(2)), + std::get(inst.operands.at(3))); break; case OpCode::L1TOL2MSGEXISTS: trace_builder.op_l1_to_l2_msg_exists(std::get(inst.operands.at(0)), diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp index a19197602c5..f6ada4bd549 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp @@ -1536,7 +1536,7 @@ Row AvmTraceBuilder::create_kernel_output_opcode_with_set_value_from_hint(uint8_ .avm_main_mem_idx_b = direct_metadata_offset, .avm_main_mem_op_a = 1, .avm_main_mem_op_b = 1, - .avm_main_pc = pc++, + .avm_main_pc = pc, // No PC increment here since we do it in the specific ops .avm_main_q_kernel_output_lookup = 1, .avm_main_r_in_tag = static_cast(AvmMemoryTag::FF), .avm_main_rwa = 1, @@ -1656,38 +1656,141 @@ void AvmTraceBuilder::op_nullifier_exists(uint8_t indirect, uint32_t note_offset side_effect_counter++; } -void AvmTraceBuilder::op_sload(uint32_t slot_offset, uint32_t write_offset) +void AvmTraceBuilder::op_sload(uint8_t indirect, uint32_t slot_offset, uint32_t size, uint32_t dest_offset) { - auto const clk = static_cast(main_trace.size()) + 1; + auto clk = static_cast(main_trace.size()) + 1; - // Read the slot - Row row = create_kernel_output_opcode_with_set_value_from_hint(0, clk, write_offset, slot_offset); - // Row row = create_sload(clk, write_offset, value, slot_read.val, slot_offset); - kernel_trace_builder.op_sload(clk, side_effect_counter, row.avm_main_ib, row.avm_main_ia); + // TODO: align usage of indirect with simulator + // TODO: support indirect slot offset + bool dest_offset_is_indirect = is_operand_indirect(indirect, 1); - row.avm_main_sel_op_sload = FF(1); + auto direct_dest_offset = dest_offset; + if (dest_offset_is_indirect) { + auto read_ind_dest_offset = + mem_trace_builder.indirect_read_and_load_from_memory(call_ptr, clk, IndirectRegister::IND_A, dest_offset); + direct_dest_offset = uint32_t(read_ind_dest_offset.val); + } + auto read_dest_value = mem_trace_builder.read_and_load_from_memory( + call_ptr, clk, IntermRegister::IA, direct_dest_offset, AvmMemoryTag::FF, AvmMemoryTag::FF); - // Constrain gas cost - gas_trace_builder.constrain_gas_lookup(clk, OpCode::SLOAD); + AvmMemTraceBuilder::MemRead read_slot = mem_trace_builder.read_and_load_from_memory( + call_ptr, clk, IntermRegister::IB, slot_offset, AvmMemoryTag::FF, AvmMemoryTag::FF); - main_trace.push_back(row); - side_effect_counter++; + main_trace.push_back(Row{ + .avm_main_clk = clk, + .avm_main_ia = read_dest_value.val, + .avm_main_ib = read_slot.val, + .avm_main_ind_a = dest_offset_is_indirect ? dest_offset : 0, + .avm_main_ind_op_a = FF(static_cast(dest_offset_is_indirect)), + .avm_main_internal_return_ptr = FF(internal_return_ptr), + .avm_main_mem_idx_a = FF(direct_dest_offset), + .avm_main_mem_idx_b = FF(slot_offset), + .avm_main_mem_op_a = FF(1), + .avm_main_mem_op_b = FF(1), + .avm_main_pc = pc, // No PC increment here since this is the same opcode as the rows created below + .avm_main_r_in_tag = FF(static_cast(AvmMemoryTag::FF)), + .avm_main_w_in_tag = FF(static_cast(AvmMemoryTag::FF)), + }); + clk++; + + for (uint32_t i = 0; i < size; i++) { + FF value = execution_hints.get_side_effect_hints().at(side_effect_counter); + + mem_trace_builder.write_into_memory( + call_ptr, clk, IntermRegister::IA, direct_dest_offset + i, value, AvmMemoryTag::FF, AvmMemoryTag::FF); + + auto row = Row{ + .avm_main_clk = clk, + .avm_main_ia = value, + .avm_main_ib = read_slot.val + i, // slot increments each time + .avm_main_internal_return_ptr = internal_return_ptr, + .avm_main_mem_idx_a = direct_dest_offset + i, + .avm_main_mem_op_a = 1, + .avm_main_pc = pc, // No PC increment here since this is the same opcode for all loop iterations + .avm_main_q_kernel_output_lookup = 1, + .avm_main_r_in_tag = static_cast(AvmMemoryTag::FF), + .avm_main_rwa = 1, + .avm_main_sel_op_sload = FF(1), + .avm_main_w_in_tag = static_cast(AvmMemoryTag::FF), + }; + + // Output storage read to kernel outputs (performs lookup) + kernel_trace_builder.op_sload(clk, side_effect_counter, row.avm_main_ib, row.avm_main_ia); + + // Constrain gas cost + gas_trace_builder.constrain_gas_lookup(clk, OpCode::SLOAD); + + main_trace.push_back(row); + side_effect_counter++; + clk++; + } + pc++; } -void AvmTraceBuilder::op_sstore(uint32_t slot_offset, uint32_t value_offset) +void AvmTraceBuilder::op_sstore(uint8_t indirect, uint32_t src_offset, uint32_t size, uint32_t slot_offset) { - auto const clk = static_cast(main_trace.size()) + 1; + auto clk = static_cast(main_trace.size()) + 1; - Row row = create_kernel_output_opcode_with_metadata( - 0, clk, value_offset, AvmMemoryTag::FF, slot_offset, AvmMemoryTag::FF); - kernel_trace_builder.op_sstore(clk, side_effect_counter, row.avm_main_ib, row.avm_main_ia); - row.avm_main_sel_op_sstore = FF(1); + // TODO: align usage of indirect with simulator + // TODO: support indirect slot offset + bool src_offset_is_indirect = is_operand_indirect(indirect, 0); - // Constrain gas cost - gas_trace_builder.constrain_gas_lookup(clk, OpCode::SSTORE); + // Resolve loads and indirect + auto direct_src_offset = src_offset; + if (src_offset_is_indirect) { + auto read_ind_src_offset = + mem_trace_builder.indirect_read_and_load_from_memory(call_ptr, clk, IndirectRegister::IND_A, src_offset); + direct_src_offset = uint32_t(read_ind_src_offset.val); + } + auto read_src_value = mem_trace_builder.read_and_load_from_memory( + call_ptr, clk, IntermRegister::IA, direct_src_offset, AvmMemoryTag::FF, AvmMemoryTag::FF); - main_trace.push_back(row); - side_effect_counter++; + auto read_slot = mem_trace_builder.read_and_load_from_memory( + call_ptr, clk, IntermRegister::IB, slot_offset, AvmMemoryTag::FF, AvmMemoryTag::FF); + + main_trace.push_back(Row{ + .avm_main_clk = clk, + .avm_main_ia = read_src_value.val, + .avm_main_ib = read_slot.val, + .avm_main_ind_a = src_offset_is_indirect ? src_offset : 0, + .avm_main_ind_op_a = FF(static_cast(src_offset_is_indirect)), + .avm_main_internal_return_ptr = FF(internal_return_ptr), + .avm_main_mem_idx_a = FF(direct_src_offset), + .avm_main_mem_idx_b = FF(slot_offset), + .avm_main_mem_op_a = FF(1), + .avm_main_mem_op_b = FF(1), + .avm_main_pc = pc, // No PC increment here since this is the same opcode as the rows created below + .avm_main_r_in_tag = FF(static_cast(AvmMemoryTag::FF)), + .avm_main_w_in_tag = FF(static_cast(AvmMemoryTag::FF)), + }); + clk++; + + for (uint32_t i = 0; i < size; i++) { + auto read_a = mem_trace_builder.read_and_load_from_memory( + call_ptr, clk, IntermRegister::IA, direct_src_offset + i, AvmMemoryTag::FF, AvmMemoryTag::U0); + + Row row = Row{ + .avm_main_clk = clk, + .avm_main_ia = read_a.val, + .avm_main_ib = read_slot.val + i, // slot increments each time + .avm_main_internal_return_ptr = internal_return_ptr, + .avm_main_mem_idx_a = direct_src_offset + i, + .avm_main_mem_op_a = 1, + .avm_main_pc = pc, + .avm_main_q_kernel_output_lookup = 1, + .avm_main_r_in_tag = static_cast(AvmMemoryTag::FF), + }; + row.avm_main_sel_op_sstore = FF(1); + kernel_trace_builder.op_sstore(clk, side_effect_counter, row.avm_main_ib, row.avm_main_ia); + + // Constrain gas cost + gas_trace_builder.constrain_gas_lookup(clk, OpCode::SSTORE); + + main_trace.push_back(row); + side_effect_counter++; + clk++; + } + pc++; } /** @@ -4059,8 +4162,8 @@ std::vector AvmTraceBuilder::finalize(uint32_t min_trace_size, bool range_c // to be the same as the previous row This satisfies the `offset' - (offset + operation_selector) = 0` // constraints for (size_t j = kernel_padding_main_trace_bottom; j < clk; j++) { - auto const& prev = main_trace.at(j - 1); - auto& dest = main_trace.at(j); + auto const& prev = main_trace.at(j); + auto& dest = main_trace.at(j + 1); dest.avm_kernel_note_hash_exist_write_offset = prev.avm_kernel_note_hash_exist_write_offset; dest.avm_kernel_emit_note_hash_write_offset = prev.avm_kernel_emit_note_hash_write_offset; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp index 42cab974b86..70d45adb3d5 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp @@ -114,8 +114,8 @@ class AvmTraceBuilder { void op_note_hash_exists(uint8_t indirect, uint32_t note_hash_offset, uint32_t dest_offset); void op_nullifier_exists(uint8_t indirect, uint32_t nullifier_offset, uint32_t dest_offset); - void op_sload(uint32_t slot_offset, uint32_t value_offset); - void op_sstore(uint32_t slot_offset, uint32_t value_offset); + void op_sload(uint8_t indirect, uint32_t slot_offset, uint32_t size, uint32_t dest_offset); + void op_sstore(uint8_t indirect, uint32_t src_offset, uint32_t size, uint32_t slot_offset); // Cast an element pointed by the address a_offset into type specified by dst_tag and // store the result in address given by dst_offset. diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp index c08efde3110..768023f9ff3 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp @@ -745,7 +745,6 @@ bool AvmVerifier::verify_proof(const HonkProof& proof, const std::vector calldata = {}; + std::vector returndata = {}; + + // Generate Hint for Sload operation + // side effect counter 0 = value 42 + auto execution_hints = ExecutionHints().with_storage_value_hints({ { 0, 42 } }); + + auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec, execution_hints); + + // CHECK SLOAD + // Check output data + side effect counters have been set correctly + auto sload_row = + std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_sload == 1; }); + EXPECT_EQ(sload_row->avm_main_ia, 42); // Read value + EXPECT_EQ(sload_row->avm_main_ib, 9); // Storage slot + EXPECT_EQ(sload_row->avm_kernel_side_effect_counter, 0); + + // Get the row of the first read storage read out + uint32_t sload_out_offset = AvmKernelTraceBuilder::START_SLOAD_WRITE_OFFSET; + auto sload_kernel_out_row = + std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.avm_main_clk == sload_out_offset; }); + EXPECT_EQ(sload_kernel_out_row->avm_kernel_kernel_value_out__is_public, 42); // value + EXPECT_EQ(sload_kernel_out_row->avm_kernel_kernel_side_effect_out__is_public, 0); + EXPECT_EQ(sload_kernel_out_row->avm_kernel_kernel_metadata_out__is_public, 9); // slot + + validate_trace(std::move(trace)); +} + +// SLOAD +TEST_F(AvmExecutionTests, kernelOutputStorageLoadOpcodeComplex) +{ + // Sload from a value that has not previously been written to will require a hint to process + std::string bytecode_hex = to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag + "03" // U32 + "00000009" // value 9 + "00000001" // dst_offset 1 + // Cast set to field + + to_hex(OpCode::CAST) + // opcode CAST + "00" // Indirect flag + "06" // tag field + "00000001" // dst 1 + "00000001" // dst 1 + + to_hex(OpCode::SLOAD) + // opcode SLOAD + "00" // Indirect flag (second operand indirect - dest offset) + "00000001" // slot offset 1 + "00000002" // slot offset 2 + "00000002" // write storage value to offset 2 + + to_hex(OpCode::RETURN) + // opcode RETURN + "00" // Indirect flag + "00000000" // ret offset 0 + "00000000"; // ret size 0 + + auto bytecode = hex_to_bytes(bytecode_hex); + auto instructions = Deserialization::parse(bytecode); + + ASSERT_THAT(instructions, SizeIs(4)); + + std::vector calldata = {}; + std::vector returndata = {}; + + // Generate Hint for Sload operation + // side effect counter 0 = value 42 + auto execution_hints = ExecutionHints().with_storage_value_hints({ { 0, 42 }, { 1, 123 } }); + + auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec, execution_hints); + + // CHECK SLOAD + // Check output data + side effect counters have been set correctly + auto sload_row = + std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_sload == 1; }); + EXPECT_EQ(sload_row->avm_main_ia, 42); // Read value + EXPECT_EQ(sload_row->avm_main_ib, 9); // Storage slot + EXPECT_EQ(sload_row->avm_kernel_side_effect_counter, 0); + sload_row++; + EXPECT_EQ(sload_row->avm_main_ia, 123); // Read value + EXPECT_EQ(sload_row->avm_main_ib, 10); // Storage slot + EXPECT_EQ(sload_row->avm_kernel_side_effect_counter, 1); + + // Get the row of the first read storage read out + uint32_t sload_out_offset = AvmKernelTraceBuilder::START_SLOAD_WRITE_OFFSET; + auto sload_kernel_out_row = + std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.avm_main_clk == sload_out_offset; }); + EXPECT_EQ(sload_kernel_out_row->avm_kernel_kernel_value_out__is_public, 42); // value + EXPECT_EQ(sload_kernel_out_row->avm_kernel_kernel_side_effect_out__is_public, 0); + EXPECT_EQ(sload_kernel_out_row->avm_kernel_kernel_metadata_out__is_public, 9); // slot + sload_kernel_out_row++; + EXPECT_EQ(sload_kernel_out_row->avm_kernel_kernel_value_out__is_public, 123); // value + EXPECT_EQ(sload_kernel_out_row->avm_kernel_kernel_side_effect_out__is_public, 1); + EXPECT_EQ(sload_kernel_out_row->avm_kernel_kernel_metadata_out__is_public, 10); // slot + + validate_trace(std::move(trace)); +} + +// SSTORE +TEST_F(AvmExecutionTests, kernelOutputStorageStoreOpcodeSimple) +{ + // SSTORE, write 2 elements of calldata to dstOffset 1 and 2. + std::vector calldata = { 42, 123, 9, 10 }; + std::string bytecode_hex = to_hex(OpCode::CALLDATACOPY) + // opcode CALLDATACOPY + "00" // Indirect flag + "00000000" // cd_offset + "00000004" // copy_size + "00000001" // dst_offset, (i.e. where we store the addr) + + to_hex(OpCode::SSTORE) + // opcode SSTORE + "00" // Indirect flag + "00000001" // src offset + "00000001" // size offset 1 + "00000003" // slot offset + + to_hex(OpCode::RETURN) + // opcode RETURN + "00" // Indirect flag + "00000000" // ret offset 0 + "00000000"; // ret size 0 + + auto bytecode = hex_to_bytes(bytecode_hex); + auto instructions = Deserialization::parse(bytecode); + + ASSERT_THAT(instructions, SizeIs(3)); + + std::vector returndata = {}; + + auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec); + // CHECK SSTORE + auto sstore_row = + std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_sstore == 1; }); + EXPECT_EQ(sstore_row->avm_main_ia, 42); // Read value + EXPECT_EQ(sstore_row->avm_main_ib, 9); // Storage slot + EXPECT_EQ(sstore_row->avm_kernel_side_effect_counter, 0); + + // Get the row of the first storage write out + uint32_t sstore_out_offset = AvmKernelTraceBuilder::START_SSTORE_WRITE_OFFSET; + auto sstore_kernel_out_row = + std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.avm_main_clk == sstore_out_offset; }); + EXPECT_EQ(sstore_kernel_out_row->avm_kernel_kernel_value_out__is_public, 42); // value + EXPECT_EQ(sstore_kernel_out_row->avm_kernel_kernel_side_effect_out__is_public, 0); + EXPECT_EQ(sstore_kernel_out_row->avm_kernel_kernel_metadata_out__is_public, 9); // slot + + validate_trace(std::move(trace)); +} + +// SSTORE +TEST_F(AvmExecutionTests, kernelOutputStorageStoreOpcodeComplex) +{ + // SSTORE, write 2 elements of calldata to dstOffset 1 and 2. + std::vector calldata = { 42, 123, 9, 10 }; + std::string bytecode_hex = to_hex(OpCode::CALLDATACOPY) + // opcode CALLDATACOPY + "00" // Indirect flag + "00000000" // cd_offset + "00000004" // copy_size + "00000001" // dst_offset, (i.e. where we store the addr) + + to_hex(OpCode::SET) + // opcode SET (inidirect SSTORE) + "00" + "03" + "00000001" // Value + "00000010" + // Dest val + to_hex(OpCode::SSTORE) + // opcode SSTORE + "01" // Indirect flag + "00000010" // src offset + "00000002" // size offset 1 + "00000003" // slot offset + + to_hex(OpCode::RETURN) + // opcode RETURN + "00" // Indirect flag + "00000000" // ret offset 0 + "00000000"; // ret size 0 + + auto bytecode = hex_to_bytes(bytecode_hex); + auto instructions = Deserialization::parse(bytecode); + + ASSERT_THAT(instructions, SizeIs(4)); + + std::vector returndata = {}; + + auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec); + // CHECK SSTORE + auto sstore_row = + std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_sstore == 1; }); + EXPECT_EQ(sstore_row->avm_main_ia, 42); // Read value + EXPECT_EQ(sstore_row->avm_main_ib, 9); // Storage slot + EXPECT_EQ(sstore_row->avm_kernel_side_effect_counter, 0); + sstore_row++; + + EXPECT_EQ(sstore_row->avm_main_ia, 123); // Read value + EXPECT_EQ(sstore_row->avm_main_ib, 10); // Storage slot + EXPECT_EQ(sstore_row->avm_kernel_side_effect_counter, 1); + + // Get the row of the first storage write out + uint32_t sstore_out_offset = AvmKernelTraceBuilder::START_SSTORE_WRITE_OFFSET; + auto sstore_kernel_out_row = + std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.avm_main_clk == sstore_out_offset; }); + EXPECT_EQ(sstore_kernel_out_row->avm_kernel_kernel_value_out__is_public, 42); // value + EXPECT_EQ(sstore_kernel_out_row->avm_kernel_kernel_side_effect_out__is_public, 0); + EXPECT_EQ(sstore_kernel_out_row->avm_kernel_kernel_metadata_out__is_public, 9); // slot + sstore_kernel_out_row++; + EXPECT_EQ(sstore_kernel_out_row->avm_kernel_kernel_value_out__is_public, 123); // value + EXPECT_EQ(sstore_kernel_out_row->avm_kernel_kernel_side_effect_out__is_public, 1); + EXPECT_EQ(sstore_kernel_out_row->avm_kernel_kernel_metadata_out__is_public, 10); // slot + + validate_trace(std::move(trace)); +} + // SLOAD and SSTORE TEST_F(AvmExecutionTests, kernelOutputStorageOpcodes) { @@ -1753,11 +1983,13 @@ TEST_F(AvmExecutionTests, kernelOutputStorageOpcodes) + to_hex(OpCode::SLOAD) + // opcode SLOAD "00" // Indirect flag "00000001" // slot offset 1 + "00000001" // size is 1 "00000002" // write storage value to offset 2 + to_hex(OpCode::SSTORE) + // opcode SSTORE "00" // Indirect flag - "00000001" // slot offset 1 - "00000002" // value write offset 2 + "00000002" // src offset 2 (since the sload writes to 2) + "00000001" // size is 1 + "00000001" // slot offset is 1 + to_hex(OpCode::RETURN) + // opcode RETURN "00" // Indirect flag "00000000" // ret offset 0 @@ -1785,7 +2017,7 @@ TEST_F(AvmExecutionTests, kernelOutputStorageOpcodes) EXPECT_EQ(sload_row->avm_main_ib, 9); // Storage slot EXPECT_EQ(sload_row->avm_kernel_side_effect_counter, 0); - // Get the row of the first note hash out + // Get the row of the first storage read out uint32_t sload_out_offset = AvmKernelTraceBuilder::START_SLOAD_WRITE_OFFSET; auto sload_kernel_out_row = std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.avm_main_clk == sload_out_offset; }); @@ -1800,7 +2032,7 @@ TEST_F(AvmExecutionTests, kernelOutputStorageOpcodes) EXPECT_EQ(sstore_row->avm_main_ib, 9); // Storage slot EXPECT_EQ(sstore_row->avm_kernel_side_effect_counter, 1); - // Get the row of the first note hash out + // Get the row of the first storage write out uint32_t sstore_out_offset = AvmKernelTraceBuilder::START_SSTORE_WRITE_OFFSET; auto sstore_kernel_out_row = std::ranges::find_if(trace.begin(), trace.end(), [&](Row r) { return r.avm_main_clk == sstore_out_offset; }); @@ -1813,7 +2045,7 @@ TEST_F(AvmExecutionTests, kernelOutputStorageOpcodes) TEST_F(AvmExecutionTests, kernelOutputHashExistsOpcodes) { - // Sload from a value that has not previously been written to will require a hint to process + // hash exists from a value that has not previously been written to will require a hint to process std::string bytecode_hex = to_hex(OpCode::SET) + // opcode SET "00" // Indirect flag "03" // U32 @@ -1853,7 +2085,7 @@ TEST_F(AvmExecutionTests, kernelOutputHashExistsOpcodes) std::vector calldata = {}; std::vector returndata = {}; - // Generate Hint for Sload operation + // Generate Hint for hash exists operation auto execution_hints = ExecutionHints().with_storage_value_hints({ { 0, 1 }, { 1, 1 }, { 2, 1 } }); auto trace = Execution::gen_trace(instructions, returndata, calldata, public_inputs_vec, execution_hints); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_kernel.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_kernel.test.cpp index 4731055db7a..161ba50d7b9 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_kernel.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_kernel.test.cpp @@ -118,7 +118,8 @@ void expect_output_table_row_with_metadata(std::vector::const_iterator row, FF ind_b, AvmMemoryTag r_in_tag, uint32_t side_effect_counter, - uint32_t rwa = 0) + uint32_t rwa = 0, + bool no_b = false) { expect_output_table_row(row, selector, ia, mem_idx_a, ind_a, r_in_tag, side_effect_counter, rwa); @@ -127,9 +128,12 @@ void expect_output_table_row_with_metadata(std::vector::const_iterator row, // Checks that are fixed for kernel inputs EXPECT_EQ(row->avm_main_rwb, FF(0)); - EXPECT_EQ(row->avm_main_ind_b, ind_b); - EXPECT_EQ(row->avm_main_ind_op_b, FF(ind_b != 0)); - EXPECT_EQ(row->avm_main_mem_op_b, FF(1)); + + if (!no_b) { + EXPECT_EQ(row->avm_main_ind_b, ind_b); + EXPECT_EQ(row->avm_main_ind_op_b, FF(ind_b != 0)); + EXPECT_EQ(row->avm_main_mem_op_b, FF(1)); + } } void expect_output_table_row_with_exists_metadata(std::vector::const_iterator row, @@ -980,9 +984,7 @@ TEST_F(AvmKernelOutputPositiveTests, kernelEmitL2ToL1Msg) /*mem_idx_b=*/recipient_offset, /*ind_a*/ indirect ? indirect_recipient_offset : 0, /*w_in_tag=*/AvmMemoryTag::FF, - /*side_effect_counter=*/0 - - ); + /*side_effect_counter=*/0); check_kernel_outputs(trace.at(output_offset), 1234, /*side_effect_counter=*/0, /*metadata=*/420); }; @@ -1033,8 +1035,10 @@ TEST_F(AvmKernelOutputPositiveTests, kernelEmitUnencryptedLog) TEST_F(AvmKernelOutputPositiveTests, kernelSload) { - uint32_t value_offset = 42; + uint8_t indirect = 0; + uint32_t dest_offset = 42; auto value = 1234; + uint32_t size = 1; uint32_t slot_offset = 420; auto slot = 12345; @@ -1043,12 +1047,12 @@ TEST_F(AvmKernelOutputPositiveTests, kernelSload) auto apply_opcodes = [=](AvmTraceBuilder& trace_builder) { trace_builder.op_set(0, static_cast(slot), slot_offset, AvmMemoryTag::FF); - trace_builder.op_sload(slot_offset, value_offset); + trace_builder.op_sload(indirect, slot_offset, size, dest_offset); }; auto checks = [=]([[maybe_unused]] bool indirect, const std::vector& trace) { std::vector::const_iterator row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_sload == FF(1); }); - EXPECT_TRUE(row != trace.end()); + ASSERT_TRUE(row != trace.end()); // Check the outputs of the trace uint32_t output_offset = AvmKernelTraceBuilder::START_SLOAD_WRITE_OFFSET; @@ -1058,14 +1062,15 @@ TEST_F(AvmKernelOutputPositiveTests, kernelSload) row, /*kernel_in_offset=*/output_offset, /*ia=*/value, // Note the value generated above for public inputs is the same as the index read + 1 - /*mem_idx_a=*/value_offset, + /*mem_idx_a=*/dest_offset, /*ind_a=*/false, /*ib=*/slot, - /*mem_idx_b=*/slot_offset, + /*mem_idx_b=*/0, /*ind_b=*/false, - /*w_in_tag=*/AvmMemoryTag::FF, + /*r_in_tag=*/AvmMemoryTag::FF, /*side_effect_counter=*/0, - /*rwa=*/1); + /*rwa=*/1, + /*no_b=*/true); check_kernel_outputs(trace.at(output_offset), value, /*side_effect_counter=*/0, slot); }; @@ -1079,11 +1084,13 @@ TEST_F(AvmKernelOutputPositiveTests, kernelSstore) auto value = 1234; uint32_t metadata_offset = 420; auto slot = 12345; + uint8_t indirect = 0; + uint32_t size = 1; auto apply_opcodes = [=](AvmTraceBuilder& trace_builder) { trace_builder.op_set(0, static_cast(value), value_offset, AvmMemoryTag::FF); trace_builder.op_set(0, static_cast(slot), metadata_offset, AvmMemoryTag::FF); - trace_builder.op_sstore(metadata_offset, value_offset); + trace_builder.op_sstore(indirect, value_offset, size, metadata_offset); }; auto checks = [=]([[maybe_unused]] bool indirect, const std::vector& trace) { std::vector::const_iterator row = @@ -1101,10 +1108,12 @@ TEST_F(AvmKernelOutputPositiveTests, kernelSstore) /*mem_idx_a=*/value_offset, /*ind_a*/ false, /*ib=*/slot, - /*mem_idx_b=*/metadata_offset, + /*mem_idx_b=*/0, /*ind_b*/ false, /*w_in_tag=*/AvmMemoryTag::FF, - /*side_effect_counter=*/0); + /*side_effect_counter=*/0, + /*rwa=*/0, + /*no_b=*/true); check_kernel_outputs(trace.at(output_offset), value, /*side_effect_counter=*/0, slot); }; @@ -1150,9 +1159,8 @@ TEST_F(AvmKernelOutputPositiveTests, kernelNoteHashExists) /*ind_a*/ indirect ? FF(indirect_value_offset) : FF(0), /*ib=*/exists, /*mem_idx_b=*/metadata_offset, - /*ind_a*/ indirect ? FF(indirect_metadata_offset) : FF(0), + /*ind_b*/ indirect ? FF(indirect_metadata_offset) : FF(0), /*w_in_tag=*/AvmMemoryTag::FF, - /*side_effect_counter=*/0); check_kernel_outputs(trace.at(output_offset), value, /*side_effect_counter=*/0, exists); diff --git a/yarn-project/bb-prover/src/avm_proving.test.ts b/yarn-project/bb-prover/src/avm_proving.test.ts index 4645f8695ac..aec2efd6e53 100644 --- a/yarn-project/bb-prover/src/avm_proving.test.ts +++ b/yarn-project/bb-prover/src/avm_proving.test.ts @@ -29,7 +29,7 @@ import { computeVarArgsHash } from '@aztec/circuits.js/hash'; import { padArrayEnd } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; -import { AvmSimulator, type PublicContractsDB, type PublicExecutionResult } from '@aztec/simulator'; +import { AvmSimulator, type PublicContractsDB, type PublicExecutionResult, type PublicStateDB } from '@aztec/simulator'; import { getAvmTestContractBytecode, initContext, @@ -59,6 +59,10 @@ describe('AVM WitGen, proof generation and verification', () => { ['get_address', []], ['note_hash_exists', [new Fr(1), new Fr(2)]], ['test_get_contract_instance', []], + ['set_storage_single', [new Fr(1)]], + ['set_storage_list', [new Fr(1), new Fr(2)]], + ['read_storage_single', [new Fr(1)]], + ['read_storage_list', [new Fr(1)]], ['new_note_hash', [new Fr(1)]], ['new_nullifier', [new Fr(1)]], ['nullifier_exists', [new Fr(1)]], @@ -142,6 +146,10 @@ const proveAndVerifyAvmTestContract = async (functionName: string, calldata: Fr[ }).withAddress(environment.address); contractsDb.getContractInstance.mockResolvedValue(Promise.resolve(contractInstance)); + const storageDb = mock(); + const storageValue = new Fr(5); + storageDb.storageRead.mockResolvedValue(Promise.resolve(storageValue)); + const hostStorage = initHostStorage({ contractsDb }); const persistableState = new AvmPersistableStateManager(hostStorage); const context = initContext({ env: environment, persistableState }); diff --git a/yarn-project/simulator/src/avm/opcodes/storage.ts b/yarn-project/simulator/src/avm/opcodes/storage.ts index c7ed057d0d4..15320d1112f 100644 --- a/yarn-project/simulator/src/avm/opcodes/storage.ts +++ b/yarn-project/simulator/src/avm/opcodes/storage.ts @@ -31,8 +31,8 @@ export class SStore extends BaseStorageInstruction { static readonly type: string = 'SSTORE'; static readonly opcode = Opcode.SSTORE; - constructor(indirect: number, srcOffset: number, /*temporary*/ srcSize: number, slotOffset: number) { - super(indirect, srcOffset, srcSize, slotOffset); + constructor(indirect: number, srcOffset: number, /*temporary*/ size: number, slotOffset: number) { + super(indirect, srcOffset, size, slotOffset); } public async execute(context: AvmContext): Promise {