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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use zksync_vm2_interface::{opcodes, Tracer};

use super::common::{boilerplate, boilerplate_ext};
use crate::{
    addressing_modes::{
        Arguments, Destination, Register1, Register2, Source, SLOAD_COST, SSTORE_COST,
    },
    instruction::ExecutionStatus,
    Instruction, VirtualMachine, World,
};

fn sstore<T: Tracer, W: World<T>>(
    vm: &mut VirtualMachine<T, W>,
    world: &mut W,
    tracer: &mut T,
) -> ExecutionStatus {
    boilerplate_ext::<opcodes::StorageWrite, _, _>(vm, world, tracer, |vm, args, world, tracer| {
        let key = Register1::get(args, &mut vm.state);
        let value = Register2::get(args, &mut vm.state);

        let refund =
            vm.world_diff
                .write_storage(world, tracer, vm.state.current_frame.address, key, value);

        assert!(refund <= SSTORE_COST);
        vm.state.current_frame.gas += refund;
    })
}

fn sstore_transient<T: Tracer, W: World<T>>(
    vm: &mut VirtualMachine<T, W>,
    world: &mut W,
    tracer: &mut T,
) -> ExecutionStatus {
    boilerplate::<opcodes::TransientStorageWrite, _, _>(vm, world, tracer, |vm, args| {
        let key = Register1::get(args, &mut vm.state);
        let value = Register2::get(args, &mut vm.state);

        vm.world_diff
            .write_transient_storage(vm.state.current_frame.address, key, value);
    })
}

fn sload<T: Tracer, W: World<T>>(
    vm: &mut VirtualMachine<T, W>,
    world: &mut W,
    tracer: &mut T,
) -> ExecutionStatus {
    boilerplate_ext::<opcodes::StorageRead, _, _>(vm, world, tracer, |vm, args, world, tracer| {
        let key = Register1::get(args, &mut vm.state);

        let (value, refund) =
            vm.world_diff
                .read_storage(world, tracer, vm.state.current_frame.address, key);

        assert!(refund <= SLOAD_COST);
        vm.state.current_frame.gas += refund;

        Register1::set(args, &mut vm.state, value);
    })
}

fn sload_transient<T: Tracer, W: World<T>>(
    vm: &mut VirtualMachine<T, W>,
    world: &mut W,
    tracer: &mut T,
) -> ExecutionStatus {
    boilerplate::<opcodes::TransientStorageRead, _, _>(vm, world, tracer, |vm, args| {
        let key = Register1::get(args, &mut vm.state);
        let value = vm
            .world_diff
            .read_transient_storage(vm.state.current_frame.address, key);

        Register1::set(args, &mut vm.state, value);
    })
}

impl<T: Tracer, W: World<T>> Instruction<T, W> {
    /// Creates a [`StorageWrite`](opcodes::StorageWrite) instruction with the provided params.
    pub fn from_storage_write(src1: Register1, src2: Register2, arguments: Arguments) -> Self {
        Self {
            handler: sstore,
            arguments: arguments.write_source(&src1).write_source(&src2),
        }
    }

    /// Creates a [`TransientStorageWrite`](opcodes::TransientStorageWrite) instruction with the provided params.
    pub fn from_transient_storage_write(
        src1: Register1,
        src2: Register2,
        arguments: Arguments,
    ) -> Self {
        Self {
            handler: sstore_transient,
            arguments: arguments.write_source(&src1).write_source(&src2),
        }
    }

    /// Creates a [`StorageRead`](opcodes::StorageRead) instruction with the provided params.
    pub fn from_storage_read(src: Register1, dst: Register1, arguments: Arguments) -> Self {
        Self {
            handler: sload,
            arguments: arguments.write_source(&src).write_destination(&dst),
        }
    }

    /// Creates a [`TransientStorageRead`](opcodes::TransientStorageRead) instruction with the provided params.
    pub fn from_transient_storage_read(
        src: Register1,
        dst: Register1,
        arguments: Arguments,
    ) -> Self {
        Self {
            handler: sload_transient,
            arguments: arguments.write_source(&src).write_destination(&dst),
        }
    }
}