revm_interpreter/instructions/
data.rs

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