1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use primitive_types::H160;
use zkevm_opcode_defs::ADDRESS_EVENT_WRITER;
use zksync_vm2_interface::{opcodes, Event, L2ToL1Log, Tracer};

use super::common::boilerplate_ext;
use crate::{
    addressing_modes::{Arguments, Immediate1, Register1, Register2, Source},
    instruction::ExecutionStatus,
    Instruction, VirtualMachine,
};

fn event<T: Tracer, W>(
    vm: &mut VirtualMachine<T, W>,
    world: &mut W,
    tracer: &mut T,
) -> ExecutionStatus {
    boilerplate_ext::<opcodes::Event, _, _>(vm, world, tracer, |vm, args, _, _| {
        if vm.state.current_frame.address == H160::from_low_u64_be(ADDRESS_EVENT_WRITER.into()) {
            let key = Register1::get(args, &mut vm.state);
            let value = Register2::get(args, &mut vm.state);
            let is_first = Immediate1::get(args, &mut vm.state).low_u32() == 1;

            vm.world_diff.record_event(Event {
                key,
                value,
                is_first,
                shard_id: 0, // shards currently aren't supported
                tx_number: vm.state.transaction_number,
            });
        }
    })
}

fn l2_to_l1<T: Tracer, W>(
    vm: &mut VirtualMachine<T, W>,
    world: &mut W,
    tracer: &mut T,
) -> ExecutionStatus {
    boilerplate_ext::<opcodes::L2ToL1Message, _, _>(vm, world, tracer, |vm, args, _, _| {
        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_diff.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,
        });
    })
}

impl<T: Tracer, W> Instruction<T, W> {
    /// Creates an [`Event`](opcodes::Event) instruction with the provided params.
    pub fn from_event(
        key: Register1,
        value: Register2,
        is_first: bool,
        arguments: Arguments,
    ) -> Self {
        Self {
            handler: event,
            arguments: arguments
                .write_source(&key)
                .write_source(&value)
                .write_source(&Immediate1(is_first.into())),
        }
    }

    /// Creates an [`L2ToL1Message`](opcodes::L2ToL1Message) instruction with the provided params.
    pub fn from_l2_to_l1_message(
        key: Register1,
        value: Register2,
        is_service: bool,
        arguments: Arguments,
    ) -> Self {
        Self {
            handler: l2_to_l1,
            arguments: arguments
                .write_source(&key)
                .write_source(&value)
                .write_source(&Immediate1(is_service.into())),
        }
    }
}