precompile_utils/solidity/codec/
native.rs

1// This file is part of Frontier.
2
3// Copyright (c) Moonsong Labs.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: Apache-2.0
6
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License at
10//
11// 	http://www.apache.org/licenses/LICENSE-2.0
12//
13// Unless required by applicable law or agreed to in writing, software
14// distributed under the License is distributed on an "AS IS" BASIS,
15// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16// See the License for the specific language governing permissions and
17// limitations under the License.
18
19use super::*;
20use crate::solidity::revert::InjectBacktrace;
21use impl_trait_for_tuples::impl_for_tuples;
22use sp_core::{ConstU32, Get, H160};
23
24impl Codec for () {
25	fn read(_reader: &mut Reader) -> MayRevert<Self> {
26		Ok(())
27	}
28
29	fn write(_writer: &mut Writer, _value: Self) {}
30
31	fn has_static_size() -> bool {
32		true
33	}
34
35	fn signature() -> String {
36		String::from("()")
37	}
38}
39
40#[impl_for_tuples(1, 18)]
41impl Codec for Tuple {
42	fn has_static_size() -> bool {
43		for_tuples!(#( Tuple::has_static_size() )&*)
44	}
45
46	fn read(reader: &mut Reader) -> MayRevert<Self> {
47		if Self::has_static_size() {
48			let mut index = 0;
49			Ok(for_tuples!( ( #( {
50				let elem = reader.read::<Tuple>().in_tuple(index)?;
51				index +=1;
52				elem
53			} ),* ) ))
54		} else {
55			let reader = &mut reader.read_pointer()?;
56			let mut index = 0;
57			Ok(for_tuples!( ( #( {
58				let elem = reader.read::<Tuple>().in_tuple(index)?;
59				index +=1;
60				elem
61			} ),* ) ))
62		}
63	}
64
65	fn write(writer: &mut Writer, value: Self) {
66		if Self::has_static_size() {
67			for_tuples!( #( Tuple::write(writer, value.Tuple); )* );
68		} else {
69			let mut inner_writer = Writer::new();
70			for_tuples!( #( Tuple::write(&mut inner_writer, value.Tuple); )* );
71			writer.write_pointer(inner_writer.build());
72		}
73	}
74
75	fn signature() -> String {
76		let mut subtypes = Vec::new();
77		for_tuples!( #( subtypes.push(Tuple::signature()); )* );
78		alloc::format!("({})", subtypes.join(","))
79	}
80
81	fn is_explicit_tuple() -> bool {
82		true
83	}
84}
85
86impl Codec for H256 {
87	fn read(reader: &mut Reader) -> MayRevert<Self> {
88		let range = reader.move_cursor(32)?;
89
90		let data = reader
91			.input
92			.get(range)
93			.ok_or_else(|| RevertReason::read_out_of_bounds("bytes32"))?;
94
95		Ok(H256::from_slice(data))
96	}
97
98	fn write(writer: &mut Writer, value: Self) {
99		writer.data.extend_from_slice(value.as_bytes());
100	}
101
102	fn has_static_size() -> bool {
103		true
104	}
105
106	fn signature() -> String {
107		String::from("bytes32")
108	}
109}
110
111/// The `address` type of Solidity.
112/// H160 could represent 2 types of data (bytes20 and address) that are not encoded the same way.
113/// To avoid issues writing H160 is thus not supported.
114#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
115pub struct Address(pub H160);
116
117impl From<H160> for Address {
118	fn from(a: H160) -> Address {
119		Address(a)
120	}
121}
122
123impl From<Address> for H160 {
124	fn from(a: Address) -> H160 {
125		a.0
126	}
127}
128
129impl Address {
130	pub fn as_u64(&self) -> Option<u64> {
131		let _u64 = self.0.to_low_u64_be();
132		if self.0 == H160::from_low_u64_be(_u64) {
133			Some(_u64)
134		} else {
135			None
136		}
137	}
138}
139
140impl Codec for Address {
141	fn read(reader: &mut Reader) -> MayRevert<Self> {
142		let range = reader.move_cursor(32)?;
143
144		let data = reader
145			.input
146			.get(range)
147			.ok_or_else(|| RevertReason::read_out_of_bounds("address"))?;
148
149		Ok(H160::from_slice(&data[12..32]).into())
150	}
151
152	fn write(writer: &mut Writer, value: Self) {
153		H256::write(writer, value.0.into());
154	}
155
156	fn has_static_size() -> bool {
157		true
158	}
159
160	fn signature() -> String {
161		String::from("address")
162	}
163}
164
165impl Codec for U256 {
166	fn read(reader: &mut Reader) -> MayRevert<Self> {
167		let range = reader.move_cursor(32)?;
168
169		let data = reader
170			.input
171			.get(range)
172			.ok_or_else(|| RevertReason::read_out_of_bounds("uint256"))?;
173
174		Ok(U256::from_big_endian(data))
175	}
176
177	fn write(writer: &mut Writer, value: Self) {
178		writer.data.extend_from_slice(&value.to_big_endian());
179	}
180
181	fn has_static_size() -> bool {
182		true
183	}
184
185	fn signature() -> String {
186		String::from("uint256")
187	}
188}
189
190macro_rules! impl_evmdata_for_uints {
191	($($uint:ty, )*) => {
192		$(
193			impl Codec for $uint {
194				fn read(reader: &mut Reader) -> MayRevert<Self> {
195					let value256: U256 = reader.read()
196					.map_err(|_| RevertReason::read_out_of_bounds(
197						Self::signature()
198					))?;
199
200					value256
201						.try_into()
202						.map_err(|_| RevertReason::value_is_too_large(
203							Self::signature()
204						).into())
205				}
206
207				fn write(writer: &mut Writer, value: Self) {
208					U256::write(writer, value.into());
209				}
210
211				fn has_static_size() -> bool {
212					true
213				}
214
215				fn signature() -> String {
216					alloc::format!("uint{}", core::mem::size_of::<Self>() * 8)
217				}
218			}
219		)*
220	};
221}
222
223impl_evmdata_for_uints!(u8, u16, u32, u64, u128,);
224
225impl Codec for bool {
226	fn read(reader: &mut Reader) -> MayRevert<Self> {
227		let h256 = H256::read(reader).map_err(|_| RevertReason::read_out_of_bounds("bool"))?;
228
229		Ok(!h256.is_zero())
230	}
231
232	fn write(writer: &mut Writer, value: Self) {
233		let mut buffer = [0u8; 32];
234		if value {
235			buffer[31] = 1;
236		}
237
238		writer.data.extend_from_slice(&buffer);
239	}
240
241	fn has_static_size() -> bool {
242		true
243	}
244
245	fn signature() -> String {
246		String::from("bool")
247	}
248}
249
250type ConstU32Max = ConstU32<{ u32::MAX }>;
251
252impl<T: Codec> Codec for Vec<T> {
253	fn read(reader: &mut Reader) -> MayRevert<Self> {
254		BoundedVec::<T, ConstU32Max>::read(reader).map(|x| x.into())
255	}
256
257	fn write(writer: &mut Writer, value: Self) {
258		BoundedVec::<T, ConstU32Max>::write(
259			writer,
260			BoundedVec {
261				inner: value,
262				_phantom: PhantomData,
263			},
264		)
265	}
266
267	fn has_static_size() -> bool {
268		false
269	}
270
271	fn signature() -> String {
272		alloc::format!("{}[]", T::signature())
273	}
274}
275
276/// Wrapper around a Vec that provides a max length bound on read.
277#[derive(Clone, Debug, Eq, PartialEq)]
278pub struct BoundedVec<T, S> {
279	inner: Vec<T>,
280	_phantom: PhantomData<S>,
281}
282
283impl<T: Codec, S: Get<u32>> Codec for BoundedVec<T, S> {
284	fn read(reader: &mut Reader) -> MayRevert<Self> {
285		let mut inner_reader = reader.read_pointer()?;
286
287		let array_size: usize = inner_reader
288			.read::<U256>()
289			.map_err(|_| RevertReason::read_out_of_bounds("length"))?
290			.try_into()
291			.map_err(|_| RevertReason::value_is_too_large("length"))?;
292
293		if array_size > S::get() as usize {
294			return Err(RevertReason::value_is_too_large("length").into());
295		}
296
297		let mut array = vec![];
298
299		let mut item_reader = Reader {
300			input: inner_reader
301				.input
302				.get(32..)
303				.ok_or_else(|| RevertReason::read_out_of_bounds("array content"))?,
304			cursor: 0,
305		};
306
307		for i in 0..array_size {
308			array.push(item_reader.read().in_array(i)?);
309		}
310
311		Ok(BoundedVec {
312			inner: array,
313			_phantom: PhantomData,
314		})
315	}
316
317	fn write(writer: &mut Writer, value: Self) {
318		let value: Vec<_> = value.into();
319		let mut inner_writer = Writer::new().write(U256::from(value.len()));
320
321		for inner in value {
322			// Any offset in items are relative to the start of the item instead of the
323			// start of the array. However if there is offset data it must but appended after
324			// all items (offsets) are written. We thus need to rely on `compute_offsets` to do
325			// that, and must store a "shift" to correct the offsets.
326			let shift = inner_writer.data.len();
327			let item_writer = Writer::new().write(inner);
328
329			inner_writer = inner_writer.write_raw_bytes(&item_writer.data);
330			for mut offset_datum in item_writer.offset_data {
331				offset_datum.offset_shift += 32;
332				offset_datum.offset_position += shift;
333				inner_writer.offset_data.push(offset_datum);
334			}
335		}
336
337		writer.write_pointer(inner_writer.build());
338	}
339
340	fn has_static_size() -> bool {
341		false
342	}
343
344	fn signature() -> String {
345		alloc::format!("{}[]", T::signature())
346	}
347}
348
349impl<T, S> From<Vec<T>> for BoundedVec<T, S> {
350	fn from(value: Vec<T>) -> Self {
351		BoundedVec {
352			inner: value,
353			_phantom: PhantomData,
354		}
355	}
356}
357
358impl<T: Clone, S> From<&[T]> for BoundedVec<T, S> {
359	fn from(value: &[T]) -> Self {
360		BoundedVec {
361			inner: value.to_vec(),
362			_phantom: PhantomData,
363		}
364	}
365}
366
367impl<T: Clone, S, const N: usize> From<[T; N]> for BoundedVec<T, S> {
368	fn from(value: [T; N]) -> Self {
369		BoundedVec {
370			inner: value.to_vec(),
371			_phantom: PhantomData,
372		}
373	}
374}
375
376impl<T, S> From<BoundedVec<T, S>> for Vec<T> {
377	fn from(value: BoundedVec<T, S>) -> Self {
378		value.inner
379	}
380}
381
382impl<T, S> Default for BoundedVec<T, S> {
383	fn default() -> Self {
384		Self {
385			inner: Default::default(),
386			_phantom: PhantomData,
387		}
388	}
389}
390
391impl<T, S> BoundedVec<T, S> {
392	pub fn len(&self) -> usize {
393		self.inner.len()
394	}
395
396	pub fn is_empty(&self) -> bool {
397		self.inner.is_empty()
398	}
399}