diff --git a/src/decode.rs b/src/decode.rs index 8e74925c..06f835d0 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -236,17 +236,11 @@ fn decode(raw: u64, is_bootloader: bool) -> Instruction { zkevm_opcode_defs::LogOpcode::StorageWrite => { Instruction::from_sstore(src1.try_into().unwrap(), src2, predicate) } - // TODO: This is obviously wrong but I want to nop instead of crashing - zkevm_opcode_defs::LogOpcode::ToL1Message => Instruction::from_nop( - AdvanceStackPointer(RegisterAndImmediate { - immediate: 0, - register: Register::new(0), - }), - AdvanceStackPointer(RegisterAndImmediate { - immediate: 0, - register: Register::new(0), - }), - Predicate::Always, + zkevm_opcode_defs::LogOpcode::ToL1Message => Instruction::from_l2_to_l1_message( + src1.try_into().unwrap(), + src2, + parsed.variant.flags[FIRST_MESSAGE_FLAG_IDX], + predicate, ), zkevm_opcode_defs::LogOpcode::Event => Instruction::from_event( src1.try_into().unwrap(), diff --git a/src/instruction_handlers/event.rs b/src/instruction_handlers/event.rs index d868aa07..4d14f34b 100644 --- a/src/instruction_handlers/event.rs +++ b/src/instruction_handlers/event.rs @@ -2,7 +2,7 @@ use super::{common::instruction_boilerplate_with_panic, free_panic}; use crate::{ addressing_modes::{Arguments, Immediate1, Register1, Register2, Source}, instruction::InstructionResult, - modified_world::Event, + modified_world::{Event, L2ToL1Log}, Instruction, Predicate, VirtualMachine, }; use u256::H160; @@ -31,6 +31,28 @@ fn event(vm: &mut VirtualMachine, instruction: *const Instruction) -> Instructio }) } +fn l2_to_l1(vm: &mut VirtualMachine, instruction: *const Instruction) -> InstructionResult { + instruction_boilerplate_with_panic(vm, instruction, |vm, args, continue_normally| { + if vm.state.current_frame.is_static { + return free_panic(vm); + } + + let key = Register1::get(args, &mut vm.state); + let value = Register2::get(args, &mut vm.state); + let is_service = Immediate1::get(args, &mut vm.state).low_u32() == 1; + vm.world.record_l2_to_l1_log(L2ToL1Log { + key, + value, + is_service, + address: vm.state.current_frame.address, + shard_id: 0, + tx_number: vm.state.transaction_number, + }); + + continue_normally + }) +} + impl Instruction { pub fn from_event( key: Register1, @@ -46,4 +68,19 @@ impl Instruction { .write_source(&Immediate1(is_first.into())), } } + + pub fn from_l2_to_l1_message( + key: Register1, + value: Register2, + is_service: bool, + predicate: Predicate, + ) -> Self { + Self { + handler: l2_to_l1, + arguments: Arguments::new(predicate, 34) + .write_source(&key) + .write_source(&value) + .write_source(&Immediate1(is_service.into())), + } + } } diff --git a/src/lib.rs b/src/lib.rs index a52c718a..c98b5d17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,7 @@ use u256::{H160, U256}; pub use decommit::address_into_u256; pub use decommit::initial_decommit; pub use instruction::{jump_to_beginning, ExecutionEnd, Instruction}; -pub use modified_world::{Event, ExternalSnapshot, ModifiedWorld}; +pub use modified_world::{Event, ExternalSnapshot, L2ToL1Log, ModifiedWorld}; pub use predication::Predicate; pub use program::Program; pub use state::{State, FIRST_HEAP}; diff --git a/src/modified_world.rs b/src/modified_world.rs index 14bac28c..b8cd8fc7 100644 --- a/src/modified_world.rs +++ b/src/modified_world.rs @@ -18,6 +18,7 @@ pub struct ModifiedWorld { // These are rolled back on revert or panic (and when the whole VM is rolled back). storage_changes: RollbackableMap<(H160, U256), U256>, events: RollbackableLog, + l2_to_l1_logs: RollbackableLog, // The field below are only rolled back when the whole VM is rolled back. pub(crate) decommitted_hashes: RollbackableSet, @@ -28,6 +29,7 @@ pub struct ModifiedWorld { pub struct ExternalSnapshot { storage_changes: as Rollback>::Snapshot, events: as Rollback>::Snapshot, + l2_to_l1_logs: as Rollback>::Snapshot, // The field below are only rolled back when the whole VM is rolled back. pub(crate) decommitted_hashes: as Rollback>::Snapshot, @@ -46,12 +48,22 @@ pub struct Event { pub tx_number: u16, } +pub struct L2ToL1Log { + pub key: U256, + pub value: U256, + pub is_service: bool, + pub address: H160, + pub shard_id: u8, + pub tx_number: u16, +} + impl ModifiedWorld { pub fn new(world: Box) -> Self { Self { world, storage_changes: Default::default(), events: Default::default(), + l2_to_l1_logs: Default::default(), decommitted_hashes: Default::default(), read_storage_slots: Default::default(), written_storage_slots: Default::default(), @@ -103,7 +115,7 @@ impl ModifiedWorld { self.storage_changes.as_ref() } - pub fn record_event(&mut self, event: Event) { + pub(crate) fn record_event(&mut self, event: Event) { self.events.push(event); } @@ -111,19 +123,33 @@ impl ModifiedWorld { self.events.as_ref() } + pub(crate) fn record_l2_to_l1_log(&mut self, log: L2ToL1Log) { + self.l2_to_l1_logs.push(log); + } + + pub fn l2_to_l1_logs(&self) -> &[L2ToL1Log] { + self.l2_to_l1_logs.as_ref() + } + pub(crate) fn snapshot(&self) -> Snapshot { - (self.storage_changes.snapshot(), self.events.snapshot()) + ( + self.storage_changes.snapshot(), + self.events.snapshot(), + self.l2_to_l1_logs.snapshot(), + ) } - pub(crate) fn rollback(&mut self, (storage, events): Snapshot) { + pub(crate) fn rollback(&mut self, (storage, events, l2_to_l1_logs): Snapshot) { self.storage_changes.rollback(storage); self.events.rollback(events); + self.l2_to_l1_logs.rollback(l2_to_l1_logs); } pub fn external_snapshot(&mut self) -> ExternalSnapshot { ExternalSnapshot { storage_changes: self.storage_changes.snapshot(), events: self.events.snapshot(), + l2_to_l1_logs: self.l2_to_l1_logs.snapshot(), decommitted_hashes: self.decommitted_hashes.snapshot(), read_storage_slots: self.read_storage_slots.snapshot(), written_storage_slots: self.written_storage_slots.snapshot(), @@ -133,6 +159,7 @@ impl ModifiedWorld { pub fn external_rollback(&mut self, snapshot: ExternalSnapshot) { self.storage_changes.rollback(snapshot.storage_changes); self.events.rollback(snapshot.events); + self.l2_to_l1_logs.rollback(snapshot.l2_to_l1_logs); self.decommitted_hashes .rollback(snapshot.decommitted_hashes); self.read_storage_slots @@ -157,6 +184,7 @@ impl ModifiedWorld { pub(crate) type Snapshot = ( as Rollback>::Snapshot, as Rollback>::Snapshot, + as Rollback>::Snapshot, ); const WARM_READ_REFUND: u32 = STORAGE_ACCESS_COLD_READ_COST - STORAGE_ACCESS_WARM_READ_COST;