revm_interpreter/instructions/
data.rs

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