revm_interpreter/instructions/
data.rs

1use crate::{
2    gas::{cost_per_word, BASE, DATA_LOAD_GAS, VERYLOW},
3    interpreter_types::{
4        EofData, Immediates, InterpreterTypes, Jumps, MemoryTr, RuntimeFlag, StackTr,
5    },
6};
7use primitives::{B256, U256};
8
9use crate::InstructionContext;
10
11pub fn data_load<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
12    require_eof!(context.interpreter);
13    gas!(context.interpreter, DATA_LOAD_GAS);
14    popn_top!([], offset, context.interpreter);
15
16    let offset_usize = as_usize_saturated!(offset);
17
18    let slice = context.interpreter.bytecode.data_slice(offset_usize, 32);
19
20    let mut word = [0u8; 32];
21    word[..slice.len()].copy_from_slice(slice);
22
23    *offset = U256::from_be_bytes(word);
24}
25
26pub fn data_loadn<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
27    require_eof!(context.interpreter);
28    gas!(context.interpreter, VERYLOW);
29    let offset = context.interpreter.bytecode.read_u16() as usize;
30
31    let slice = context.interpreter.bytecode.data_slice(offset, 32);
32
33    let mut word = [0u8; 32];
34    word[..slice.len()].copy_from_slice(slice);
35
36    push!(context.interpreter, B256::new(word).into());
37
38    // Add +2 to the instruction pointer to skip the offset
39    context.interpreter.bytecode.relative_jump(2);
40}
41
42pub fn data_size<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
43    require_eof!(context.interpreter);
44    gas!(context.interpreter, BASE);
45
46    push!(
47        context.interpreter,
48        U256::from(context.interpreter.bytecode.data_size())
49    );
50}
51
52pub fn data_copy<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
53    require_eof!(context.interpreter);
54    gas!(context.interpreter, VERYLOW);
55    popn!([mem_offset, offset, size], context.interpreter);
56
57    // Sizes more than u64::MAX will spend all the gas in memory resize.
58    let size = as_usize_or_fail!(context.interpreter, size);
59    // Size of zero should not change the memory
60    if size == 0 {
61        return;
62    }
63    // Fail if mem offset is big as it will spend all the gas
64    let mem_offset = as_usize_or_fail!(context.interpreter, mem_offset);
65    resize_memory!(context.interpreter, mem_offset, size);
66
67    gas_or_fail!(context.interpreter, cost_per_word(size, VERYLOW));
68
69    let offset = as_usize_saturated!(offset);
70    let data = context.interpreter.bytecode.data();
71
72    // Set data from the eof to the shared memory. Padded it with zeros.
73    context
74        .interpreter
75        .memory
76        .set_data(mem_offset, offset, size, data);
77}
78
79#[cfg(test)]
80mod test {
81    use bytecode::{Bytecode, Eof};
82    use primitives::{b256, bytes, Bytes};
83    use std::sync::Arc;
84
85    use super::*;
86    use crate::{instruction_table, Interpreter};
87    use bytecode::opcode::{DATACOPY, DATALOAD, DATALOADN, DATASIZE};
88
89    fn dummy_eof(code_bytes: Bytes) -> Bytecode {
90        let bytes = bytes!("ef00010100040200010001ff00000000800000fe");
91        let mut eof = Eof::decode(bytes).unwrap();
92
93        eof.body.data_section =
94            bytes!("000000000000000000000000000000000000000000000000000000000000000102030405");
95        eof.header.data_size = eof.body.data_section.len() as u16;
96
97        eof.header.code_sizes[0] = code_bytes.len() as u16;
98        eof.body.code_section[0] = code_bytes.len();
99        eof.body.code = code_bytes;
100        Bytecode::Eof(Arc::new(eof))
101    }
102
103    #[test]
104    fn dataload_dataloadn() {
105        let table = instruction_table();
106
107        let eof = dummy_eof(Bytes::from([
108            DATALOAD, DATALOADN, 0x00, 0x00, DATALOAD, DATALOADN, 0x00, 35, DATALOAD, DATALOADN,
109            0x00, 36, DATASIZE,
110        ]));
111
112        let mut interpreter = Interpreter::default().with_bytecode(eof);
113        interpreter.runtime_flag.is_eof = true;
114
115        // DATALOAD
116        let _ = interpreter.stack.push(U256::from(0));
117        interpreter.step_dummy(&table);
118        assert_eq!(interpreter.stack.data(), &vec![U256::from(0x01)]);
119        interpreter.stack.pop().unwrap();
120
121        // DATALOADN
122        interpreter.step_dummy(&table);
123        assert_eq!(interpreter.stack.data(), &vec![U256::from(0x01)]);
124        interpreter.stack.pop().unwrap();
125
126        // DATALOAD (padding)
127        let _ = interpreter.stack.push(U256::from(35));
128        interpreter.step_dummy(&table);
129
130        assert_eq!(
131            interpreter.stack.data(),
132            &vec![b256!("0500000000000000000000000000000000000000000000000000000000000000").into()]
133        );
134        interpreter.stack.pop().unwrap();
135
136        // DATALOADN (padding)
137        interpreter.step_dummy(&table);
138        assert_eq!(
139            interpreter.stack.data(),
140            &vec![b256!("0500000000000000000000000000000000000000000000000000000000000000").into()]
141        );
142        interpreter.stack.pop().unwrap();
143
144        // DATALOAD (out of bounds)
145        let _ = interpreter.stack.push(U256::from(36));
146        interpreter.step_dummy(&table);
147        assert_eq!(interpreter.stack.data(), &vec![U256::ZERO]);
148        interpreter.stack.pop().unwrap();
149
150        // DATALOADN (out of bounds)
151        interpreter.step_dummy(&table);
152        assert_eq!(interpreter.stack.data(), &vec![U256::ZERO]);
153        interpreter.stack.pop().unwrap();
154
155        // DATA SIZE
156        interpreter.step_dummy(&table);
157        assert_eq!(interpreter.stack.data(), &vec![U256::from(36)]);
158    }
159
160    #[test]
161    fn data_copy() {
162        let table = instruction_table();
163        let eof = dummy_eof(Bytes::from([DATACOPY, DATACOPY, DATACOPY, DATACOPY]));
164
165        let mut interpreter = Interpreter::default().with_bytecode(eof);
166        interpreter.runtime_flag.is_eof = true;
167
168        // Data copy
169        // size, offset mem_offset,
170        let _ = interpreter.stack.push(U256::from(32));
171        let _ = interpreter.stack.push(U256::from(0));
172        let _ = interpreter.stack.push(U256::from(0));
173
174        interpreter.step_dummy(&table);
175        assert_eq!(
176            *interpreter.memory.context_memory(),
177            bytes!("0000000000000000000000000000000000000000000000000000000000000001")
178        );
179
180        // Data copy (Padding)
181        // size, offset mem_offset,
182        let _ = interpreter.stack.push(U256::from(2));
183        let _ = interpreter.stack.push(U256::from(35));
184        let _ = interpreter.stack.push(U256::from(1));
185        interpreter.step_dummy(&table);
186        assert_eq!(
187            *interpreter.memory.context_memory(),
188            bytes!("0005000000000000000000000000000000000000000000000000000000000001")
189        );
190
191        // Data copy (Out of bounds)
192        // size, offset mem_offset,
193        let _ = interpreter.stack.push(U256::from(2));
194        let _ = interpreter.stack.push(U256::from(37));
195        let _ = interpreter.stack.push(U256::from(1));
196        interpreter.step_dummy(&table);
197        assert_eq!(
198            *interpreter.memory.context_memory(),
199            bytes!("0000000000000000000000000000000000000000000000000000000000000001")
200        );
201
202        // Data copy (Size == 0)
203        // mem_offset, offset, size
204        let _ = interpreter.stack.push(U256::from(0));
205        let _ = interpreter.stack.push(U256::from(37));
206        let _ = interpreter.stack.push(U256::from(1));
207        interpreter.step_dummy(&table);
208        assert_eq!(
209            *interpreter.memory.context_memory(),
210            bytes!("0000000000000000000000000000000000000000000000000000000000000001")
211        );
212    }
213}