Skip to main content

zksync_vm2/instruction_handlers/
event.rs

1use primitive_types::H160;
2use zkevm_opcode_defs::ADDRESS_EVENT_WRITER;
3use zksync_vm2_interface::{opcodes, Event, L2ToL1Log, Tracer};
4
5use super::common::boilerplate_ext;
6use crate::{
7    addressing_modes::{Arguments, Immediate1, Register1, Register2, Source},
8    instruction::ExecutionStatus,
9    Instruction, VirtualMachine, World,
10};
11
12fn event<T: Tracer, W: World<T>>(
13    vm: &mut VirtualMachine<T, W>,
14    world: &mut W,
15    tracer: &mut T,
16) -> ExecutionStatus {
17    boilerplate_ext::<opcodes::Event, _, _>(vm, world, tracer, |vm, args, _, _| {
18        // Record only `EventWriter` events; `zk_evm` records all emitters and filters later. Since
19        // only the `EventWriter` runs this opcode in practice, both agree. See the `Event` docs.
20        if vm.state.current_frame.address == H160::from_low_u64_be(ADDRESS_EVENT_WRITER.into()) {
21            let key = Register1::get(args, &mut vm.state);
22            let value = Register2::get(args, &mut vm.state);
23            let is_first = Immediate1::get(args, &mut vm.state).low_u32() == 1;
24
25            vm.world_diff.record_event(Event {
26                key,
27                value,
28                is_first,
29                shard_id: 0, // shards currently aren't supported
30                tx_number: vm.state.transaction_number,
31            });
32        }
33    })
34}
35
36fn l2_to_l1<T: Tracer, W: World<T>>(
37    vm: &mut VirtualMachine<T, W>,
38    world: &mut W,
39    tracer: &mut T,
40) -> ExecutionStatus {
41    boilerplate_ext::<opcodes::L2ToL1Message, _, _>(vm, world, tracer, |vm, args, _, _| {
42        let key = Register1::get(args, &mut vm.state);
43        let value = Register2::get(args, &mut vm.state);
44        let is_service = Immediate1::get(args, &mut vm.state).low_u32() == 1;
45        vm.world_diff.record_l2_to_l1_log(L2ToL1Log {
46            key,
47            value,
48            is_service,
49            address: vm.state.current_frame.address,
50            shard_id: 0,
51            tx_number: vm.state.transaction_number,
52        });
53    })
54}
55
56impl<T: Tracer, W: World<T>> Instruction<T, W> {
57    /// Creates an [`Event`](opcodes::Event) instruction with the provided params.
58    pub fn from_event(
59        key: Register1,
60        value: Register2,
61        is_first: bool,
62        arguments: Arguments,
63    ) -> Self {
64        Self {
65            handler: event,
66            arguments: arguments
67                .write_source(&key)
68                .write_source(&value)
69                .write_source(&Immediate1(is_first.into())),
70        }
71    }
72
73    /// Creates an [`L2ToL1Message`](opcodes::L2ToL1Message) instruction with the provided params.
74    pub fn from_l2_to_l1_message(
75        key: Register1,
76        value: Register2,
77        is_service: bool,
78        arguments: Arguments,
79    ) -> Self {
80        Self {
81            handler: l2_to_l1,
82            arguments: arguments
83                .write_source(&key)
84                .write_source(&value)
85                .write_source(&Immediate1(is_service.into())),
86        }
87    }
88}