Skip to main content

zksync_vm2/instruction_handlers/
context.rs

1use primitive_types::{H160, U256};
2use zkevm_opcode_defs::VmMetaParameters;
3use zksync_vm2_interface::{
4    opcodes::{self, Caller, CodeAddress, ContextU128, ErgsLeft, This, SP},
5    OpcodeType, Tracer,
6};
7
8use super::common::boilerplate;
9use crate::{
10    addressing_modes::{Arguments, Destination, Register1, Source},
11    instruction::ExecutionStatus,
12    state::State,
13    Instruction, VirtualMachine, World,
14};
15
16pub(crate) fn address_into_u256(address: H160) -> U256 {
17    let mut buffer = [0; 32];
18    buffer[12..].copy_from_slice(address.as_bytes());
19    U256::from_big_endian(&buffer)
20}
21
22fn context<T, W: World<T>, Op>(
23    vm: &mut VirtualMachine<T, W>,
24    world: &mut W,
25    tracer: &mut T,
26) -> ExecutionStatus
27where
28    T: Tracer,
29    Op: ContextOp,
30{
31    boilerplate::<Op, _, _>(vm, world, tracer, |vm, args| {
32        let result = Op::get(&vm.state);
33        Register1::set(args, &mut vm.state, result);
34    })
35}
36
37trait ContextOp: OpcodeType {
38    fn get<T, W>(state: &State<T, W>) -> U256;
39}
40
41impl ContextOp for This {
42    fn get<T, W>(state: &State<T, W>) -> U256 {
43        address_into_u256(state.current_frame.address)
44    }
45}
46
47impl ContextOp for Caller {
48    fn get<T, W>(state: &State<T, W>) -> U256 {
49        address_into_u256(state.current_frame.caller)
50    }
51}
52
53impl ContextOp for CodeAddress {
54    fn get<T, W>(state: &State<T, W>) -> U256 {
55        address_into_u256(state.current_frame.code_address)
56    }
57}
58
59impl ContextOp for ErgsLeft {
60    fn get<T, W>(state: &State<T, W>) -> U256 {
61        U256([state.current_frame.gas.into(), 0, 0, 0])
62    }
63}
64
65impl ContextOp for ContextU128 {
66    fn get<T, W>(state: &State<T, W>) -> U256 {
67        state.get_context_u128().into()
68    }
69}
70
71impl ContextOp for SP {
72    fn get<T, W>(state: &State<T, W>) -> U256 {
73        state.current_frame.sp.into()
74    }
75}
76
77fn context_meta<T: Tracer, W: World<T>>(
78    vm: &mut VirtualMachine<T, W>,
79    world: &mut W,
80    tracer: &mut T,
81) -> ExecutionStatus {
82    boilerplate::<opcodes::ContextMeta, _, _>(vm, world, tracer, |vm, args| {
83        let result = VmMetaParameters {
84            heap_size: vm.state.current_frame.heap_size,
85            aux_heap_size: vm.state.current_frame.aux_heap_size,
86            this_shard_id: 0, // TODO properly implement shards
87            caller_shard_id: 0,
88            code_shard_id: 0,
89            // This field is actually pubdata!
90            aux_field_0: if vm.state.current_frame.is_kernel {
91                #[allow(clippy::cast_sign_loss)] // wrapping conversion is intentional
92                {
93                    vm.world_diff.pubdata.0 as u32
94                }
95            } else {
96                0
97            },
98        }
99        .to_u256();
100
101        Register1::set(args, &mut vm.state, result);
102    })
103}
104
105fn set_context_u128<T: Tracer, W: World<T>>(
106    vm: &mut VirtualMachine<T, W>,
107    world: &mut W,
108    tracer: &mut T,
109) -> ExecutionStatus {
110    boilerplate::<opcodes::SetContextU128, _, _>(vm, world, tracer, |vm, args| {
111        let value = Register1::get(args, &mut vm.state).low_u128();
112        vm.state.set_context_u128(value);
113    })
114}
115
116fn increment_tx_number<T: Tracer, W: World<T>>(
117    vm: &mut VirtualMachine<T, W>,
118    world: &mut W,
119    tracer: &mut T,
120) -> ExecutionStatus {
121    boilerplate::<opcodes::IncrementTxNumber, _, _>(vm, world, tracer, |vm, _| {
122        vm.start_new_tx();
123    })
124}
125
126fn aux_mutating<T: Tracer, W: World<T>>(
127    vm: &mut VirtualMachine<T, W>,
128    world: &mut W,
129    tracer: &mut T,
130) -> ExecutionStatus {
131    boilerplate::<opcodes::AuxMutating0, _, _>(vm, world, tracer, |_, _| {
132        // This instruction just crashes or nops
133    })
134}
135
136/// Context-related instructions.
137impl<T: Tracer, W: World<T>> Instruction<T, W> {
138    fn from_context<Op: ContextOp>(out: Register1, arguments: Arguments) -> Self {
139        Self {
140            handler: context::<T, W, Op>,
141            arguments: arguments.write_destination(&out),
142        }
143    }
144
145    /// Creates a [`This`] instruction with the provided params.
146    pub fn from_this(out: Register1, arguments: Arguments) -> Self {
147        Self::from_context::<This>(out, arguments)
148    }
149
150    /// Creates a [`Caller`] instruction with the provided params.
151    pub fn from_caller(out: Register1, arguments: Arguments) -> Self {
152        Self::from_context::<Caller>(out, arguments)
153    }
154
155    /// Creates a [`CodeAddress`] instruction with the provided params.
156    pub fn from_code_address(out: Register1, arguments: Arguments) -> Self {
157        Self::from_context::<CodeAddress>(out, arguments)
158    }
159
160    /// Creates an [`ErgsLeft`] instruction with the provided params.
161    pub fn from_ergs_left(out: Register1, arguments: Arguments) -> Self {
162        Self::from_context::<ErgsLeft>(out, arguments)
163    }
164
165    /// Creates a [`ContextU128`] instruction with the provided params.
166    pub fn from_context_u128(out: Register1, arguments: Arguments) -> Self {
167        Self::from_context::<ContextU128>(out, arguments)
168    }
169
170    /// Creates an [`SP`] instruction with the provided params.
171    pub fn from_context_sp(out: Register1, arguments: Arguments) -> Self {
172        Self::from_context::<SP>(out, arguments)
173    }
174
175    /// Creates a [`ContextMeta`](opcodes::ContextMeta) instruction with the provided params.
176    pub fn from_context_meta(out: Register1, arguments: Arguments) -> Self {
177        Self {
178            handler: context_meta,
179            arguments: arguments.write_destination(&out),
180        }
181    }
182
183    /// Creates a [`SetContextU128`](opcodes::SetContextU128) instruction with the provided params.
184    pub fn from_set_context_u128(src: Register1, arguments: Arguments) -> Self {
185        Self {
186            handler: set_context_u128,
187            arguments: arguments.write_source(&src),
188        }
189    }
190
191    /// Creates an [`IncrementTxNumber`](opcodes::IncrementTxNumber) instruction with the provided params.
192    pub fn from_increment_tx_number(arguments: Arguments) -> Self {
193        Self {
194            handler: increment_tx_number,
195            arguments,
196        }
197    }
198
199    /// Creates an [`AuxMutating0`](opcodes::AuxMutating0) instruction with the provided params.
200    pub fn from_aux_mutating(arguments: Arguments) -> Self {
201        Self {
202            handler: aux_mutating,
203            arguments,
204        }
205    }
206}