evm_precompiles/
data.rs

1// Copyright 2019-2021 PureStake Inc.
2// This file is part of Moonbeam.
3
4// Moonbeam is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Moonbeam is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Moonbeam. If not, see <http://www.gnu.org/licenses/>.
16
17use super::{error, EvmResult};
18use core::{any::type_name, ops::Range};
19use primitive_types::{H160, H256, U256};
20use std::{convert::TryInto, vec, vec::Vec};
21
22/// The `address` type of Solidity.
23/// H160 could represent 2 types of data (bytes20 and address) that are not encoded the same way.
24/// To avoid issues writing H160 is thus not supported.
25#[derive(Clone, Copy, Debug, Eq, PartialEq)]
26pub struct Address(pub H160);
27
28impl From<H160> for Address {
29    fn from(a: H160) -> Address {
30        Address(a)
31    }
32}
33
34impl From<Address> for H160 {
35    fn from(a: Address) -> H160 {
36        a.0
37    }
38}
39
40/// Wrapper around an EVM input slice, helping to parse it.
41/// Provide functions to parse common types.
42#[derive(Clone, Copy, Debug)]
43pub struct EvmDataReader<'a> {
44    input: &'a [u8],
45    cursor: usize,
46}
47
48impl<'a> EvmDataReader<'a> {
49    /// Create a new input parser.
50    pub fn new(input: &'a [u8]) -> Self {
51        Self { input, cursor: 0 }
52    }
53
54    /// Check the input has at least the correct amount of arguments before the end (32 bytes values).
55    pub fn expect_arguments(&self, args: usize) -> EvmResult {
56        if self.input.len() >= self.cursor + args * 32 {
57            Ok(())
58        } else {
59            Err(error("input doesn't match expected length"))
60        }
61    }
62
63    /// Read data from the input.
64    pub fn read<T: EvmData>(&mut self) -> EvmResult<T> {
65        T::read(self)
66    }
67
68    /// Read raw bytes from the input.
69    /// Doesn't handle any alignement checks, prefer using `read` instead of possible.
70    /// Returns an error if trying to parse out of bounds.
71    pub fn read_raw_bytes(&mut self, len: usize) -> EvmResult<&[u8]> {
72        let range = self.move_cursor(len)?;
73
74        let data = self
75            .input
76            .get(range)
77            .ok_or_else(|| error("tried to parse raw bytes out of bounds"))?;
78
79        Ok(data)
80    }
81
82    /// Parse (4 bytes) selector.
83    /// Returns an error if trying to parse out of bounds.
84    pub fn read_selector<T>(&mut self) -> EvmResult<T>
85    where
86        T: num_enum::TryFromPrimitive<Primitive = u32>,
87    {
88        let mut buffer = [0u8; 4];
89        buffer.copy_from_slice(
90            self.read_raw_bytes(4)
91                .map_err(|_| error("tried to parse selector out of bounds"))?,
92        );
93        T::try_from_primitive(u32::from_be_bytes(buffer)).map_err(|_| {
94            log::trace!(
95                target: "precompile",
96                "Failed to match function selector for {}",
97                type_name::<T>()
98            );
99            error("unknown selector")
100        })
101    }
102
103    /// Move the reading cursor with provided length, and return a range from the previous cursor
104    /// location to the new one.
105    /// Checks cursor overflows.
106    fn move_cursor(&mut self, len: usize) -> EvmResult<Range<usize>> {
107        let start = self.cursor;
108        let end = self
109            .cursor
110            .checked_add(len)
111            .ok_or_else(|| error("data reading cursor overflow"))?;
112
113        self.cursor = end;
114
115        Ok(start..end)
116    }
117}
118
119/// Help build an EVM input/output data.
120#[derive(Clone, Debug)]
121pub struct EvmDataWriter {
122    pub(crate) data: Vec<u8>,
123    arrays: Vec<Array>,
124}
125
126#[derive(Clone, Debug)]
127struct Array {
128    offset_position: usize,
129    data: Vec<u8>,
130    inner_arrays: Vec<Array>,
131}
132
133impl EvmDataWriter {
134    /// Creates a new empty output builder.
135    pub fn new() -> Self {
136        Self {
137            data: vec![],
138            arrays: vec![],
139        }
140    }
141
142    /// Return the built data.
143    pub fn build(mut self) -> Vec<u8> {
144        Self::build_arrays(&mut self.data, self.arrays, 0);
145
146        self.data
147    }
148
149    /// Build the array into data.
150    /// `global_offset` represents the start of the frame we are modifying.
151    /// While the main data will have a `global_offset` of 0, inner arrays will have a
152    /// `global_offset` corresponding to the start its parent array size data.
153    fn build_arrays(output: &mut Vec<u8>, arrays: Vec<Array>, global_offset: usize) {
154        for mut array in arrays {
155            let offset_position = array.offset_position;
156            let offset_position_end = offset_position + 32;
157            let free_space_offset = output.len() + global_offset;
158
159            // Override dummy offset to the offset it will be in the final output.
160            U256::from(free_space_offset)
161                .to_big_endian(&mut output[offset_position..offset_position_end]);
162
163            // Build inner arrays if any.
164            Self::build_arrays(&mut array.data, array.inner_arrays, free_space_offset);
165
166            // Append this data at the end of the current output.
167            output.append(&mut array.data);
168        }
169    }
170
171    /// Write arbitrary bytes.
172    /// Doesn't handle any alignement checks, prefer using `write` instead if possible.
173    pub fn write_raw_bytes(mut self, value: &[u8]) -> Self {
174        self.data.extend_from_slice(value);
175        self
176    }
177
178    /// Write a selector.
179    /// The provided type must impl `Into<u32>`.
180    /// Doesn't handle any alignement checks, should be used only when adding the initial
181    /// selector of a Solidity call data.
182    pub fn write_selector<T: Into<u32>>(self, value: T) -> Self {
183        self.write_raw_bytes(&value.into().to_be_bytes())
184    }
185
186    /// Write data of requested type.
187    pub fn write<T: EvmData>(mut self, value: T) -> Self {
188        T::write(&mut self, value);
189        self
190    }
191}
192
193impl Default for EvmDataWriter {
194    fn default() -> Self {
195        Self::new()
196    }
197}
198
199/// Data that can be converted from and to EVM data types.
200pub trait EvmData: Sized {
201    fn read(reader: &mut EvmDataReader) -> EvmResult<Self>;
202    fn write(writer: &mut EvmDataWriter, value: Self);
203}
204
205impl EvmData for H256 {
206    fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
207        let range = reader.move_cursor(32)?;
208
209        let data = reader
210            .input
211            .get(range)
212            .ok_or_else(|| error("tried to parse H256 out of bounds"))?;
213
214        Ok(H256::from_slice(data))
215    }
216
217    fn write(writer: &mut EvmDataWriter, value: Self) {
218        writer.data.extend_from_slice(value.as_bytes());
219    }
220}
221
222impl EvmData for Address {
223    fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
224        let range = reader.move_cursor(32)?;
225
226        let data = reader
227            .input
228            .get(range)
229            .ok_or_else(|| error("tried to parse H160 out of bounds"))?;
230
231        Ok(H160::from_slice(&data[12..32]).into())
232    }
233
234    fn write(writer: &mut EvmDataWriter, value: Self) {
235        H256::write(writer, value.0.into());
236    }
237}
238
239impl EvmData for U256 {
240    fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
241        let range = reader.move_cursor(32)?;
242
243        let data = reader
244            .input
245            .get(range)
246            .ok_or_else(|| error("tried to parse U256 out of bounds"))?;
247
248        Ok(U256::from_big_endian(data))
249    }
250
251    fn write(writer: &mut EvmDataWriter, value: Self) {
252        let mut buffer = [0u8; 32];
253        value.to_big_endian(&mut buffer);
254        writer.data.extend_from_slice(&buffer);
255    }
256}
257
258macro_rules! impl_evmdata_for_uints {
259    ($($uint:ty, )*) => {
260        $(
261            impl EvmData for $uint {
262                fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
263                    let range = reader.move_cursor(32)?;
264
265                    let data = reader
266                        .input
267                        .get(range)
268                        .ok_or_else(|| error(format!(
269                            "tried to parse {} out of bounds", core::any::type_name::<Self>()
270                        )))?;
271
272                    let mut buffer = [0u8; core::mem::size_of::<Self>()];
273                    buffer.copy_from_slice(&data[32 - core::mem::size_of::<Self>()..]);
274                    Ok(Self::from_be_bytes(buffer))
275                }
276
277                fn write(writer: &mut EvmDataWriter, value: Self) {
278                    let mut buffer = [0u8; 32];
279                    buffer[32 - core::mem::size_of::<Self>()..].copy_from_slice(&value.to_be_bytes());
280                    writer.data.extend_from_slice(&buffer);
281                }
282            }
283        )*
284    };
285}
286impl_evmdata_for_uints!(u16, u32, u64, u128,);
287
288// The implementation for u8 is specific, for performance reasons.
289impl EvmData for u8 {
290    fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
291        let range = reader.move_cursor(32)?;
292
293        let data = reader
294            .input
295            .get(range)
296            .ok_or_else(|| error("tried to parse u64 out of bounds"))?;
297
298        Ok(data[31])
299    }
300
301    fn write(writer: &mut EvmDataWriter, value: Self) {
302        let mut buffer = [0u8; 32];
303        buffer[31] = value;
304
305        writer.data.extend_from_slice(&buffer);
306    }
307}
308
309impl EvmData for bool {
310    fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
311        let h256 = H256::read(reader).map_err(|_| error("tried to parse bool out of bounds"))?;
312
313        Ok(!h256.is_zero())
314    }
315
316    fn write(writer: &mut EvmDataWriter, value: Self) {
317        let mut buffer = [0u8; 32];
318        if value {
319            buffer[31] = 1;
320        }
321
322        writer.data.extend_from_slice(&buffer);
323    }
324}
325
326impl<T: EvmData> EvmData for Vec<T> {
327    fn read(reader: &mut EvmDataReader) -> EvmResult<Self> {
328        let array_start: usize = reader
329            .read::<U256>()
330            .map_err(|_| error("tried to parse array offset out of bounds"))?
331            .try_into()
332            .map_err(|_| error("array offset is too large"))?;
333
334        // We temporarily move the cursor to the offset, we'll set it back afterward.
335        let original_cursor = reader.cursor;
336        reader.cursor = array_start;
337
338        let array_size: usize = reader
339            .read::<U256>()
340            .map_err(|_| error("tried to parse array length out of bounds"))?
341            .try_into()
342            .map_err(|_| error("array length is too large"))?;
343
344        let mut array = vec![];
345
346        for _ in 0..array_size {
347            array.push(reader.read()?);
348        }
349
350        // We set back the cursor to its original location.
351        reader.cursor = original_cursor;
352
353        Ok(array)
354    }
355
356    fn write(writer: &mut EvmDataWriter, value: Self) {
357        let offset_position = writer.data.len();
358        H256::write(writer, H256::repeat_byte(0xff));
359        // 0xff = When debugging it makes spoting offset values easier.
360
361        let mut inner_writer = EvmDataWriter::new();
362
363        // Write length.
364        inner_writer = inner_writer.write(U256::from(value.len()));
365
366        // Write elements of array.
367        for inner in value {
368            inner_writer = inner_writer.write(inner);
369        }
370
371        let array = Array {
372            offset_position,
373            data: inner_writer.data,
374            inner_arrays: inner_writer.arrays,
375        };
376
377        writer.arrays.push(array);
378    }
379}