evm_coder/abi/
mod.rs

1//! Implementation of EVM RLP reader/writer
2#![allow(clippy::missing_errors_doc)]
3
4mod traits;
5use core::{fmt, mem, result};
6
7pub use traits::*;
8mod impls;
9
10#[cfg(test)]
11mod test;
12
13#[cfg(not(feature = "std"))]
14use alloc::vec::Vec;
15
16/// Aligment for every simple type in bytes.
17pub const ABI_ALIGNMENT: usize = 32;
18pub const ABI_WORD_SIZE: u32 = 32;
19pub type AbiWord = [u8; ABI_WORD_SIZE as usize];
20
21/// Abi parsing result
22pub type Result<T, E = Error> = result::Result<T, E>;
23
24/// Generic decode failure
25#[derive(Debug)]
26pub enum Error {
27	/// Input was shorter than expected
28	OutOfOffset,
29	/// Something is off about paddings
30	InvalidRange,
31	/// Custom parsing error
32	Custom(&'static str),
33}
34impl fmt::Display for Error {
35	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36		match self {
37			Error::OutOfOffset => write!(f, "out of offset"),
38			Error::InvalidRange => write!(f, "invalid range"),
39			Error::Custom(m) => write!(f, "{m}"),
40		}
41	}
42}
43impl From<&'static str> for Error {
44	fn from(value: &'static str) -> Self {
45		Self::Custom(value)
46	}
47}
48
49/// New abicoder
50#[derive(Debug)]
51pub struct AbiEncoder {
52	out: Vec<u8>,
53	offset: usize,
54	dynamic_offset: usize,
55}
56impl AbiEncoder {
57	fn new(out: Vec<u8>, offset: usize, dynamic_offset: usize) -> Self {
58		assert_eq!((dynamic_offset - offset) % 32, 0);
59		Self {
60			out,
61			offset,
62			dynamic_offset,
63		}
64	}
65	pub fn reserve_head(&mut self, words: u32) {
66		assert_eq!(self.offset, self.dynamic_offset);
67		assert_eq!(self.dynamic_offset, self.out.len());
68		self.out
69			.resize(self.out.len() + words as usize * ABI_WORD_SIZE as usize, 0);
70		self.dynamic_offset += words as usize * ABI_WORD_SIZE as usize;
71	}
72	pub fn append_head(&mut self, word: AbiWord) {
73		assert!(self.offset < self.dynamic_offset);
74		self.out[self.offset..self.offset + 32].copy_from_slice(&word);
75		self.offset += 32;
76	}
77	fn append_tail(&mut self, word: AbiWord) {
78		self.out.extend_from_slice(&word);
79	}
80	fn tail_size(&self) -> u32 {
81		self.out.len() as u32 - self.dynamic_offset as u32
82	}
83	fn encode_tail<T: AbiEncode>(&mut self, data: &T) {
84		let offset = self.out.len();
85		let mut out = mem::take(&mut self.out);
86		let size = T::HEAD_WORDS as usize * ABI_WORD_SIZE as usize;
87		out.resize(out.len() + size, 0);
88		let mut encoder = AbiEncoder::new(
89			out,
90			offset,
91			offset + T::HEAD_WORDS as usize * ABI_WORD_SIZE as usize,
92		);
93		data.enc(&mut encoder);
94		self.out = encoder.into_inner()
95	}
96	fn into_inner(self) -> Vec<u8> {
97		self.out
98	}
99}
100
101#[derive(Clone)]
102pub struct AbiDecoder<'d> {
103	data: &'d [u8],
104	offset: usize,
105	global_frame_offset: usize,
106}
107impl<'d> AbiDecoder<'d> {
108	fn new(data: &'d [u8], global_frame_offset: usize) -> Result<Self> {
109		if data.len() % 32 != 0 {
110			return Err(Error::OutOfOffset);
111		}
112		Ok(Self {
113			data,
114			offset: 0,
115			global_frame_offset,
116		})
117	}
118	pub fn get_head(&mut self) -> Result<AbiWord> {
119		if self.offset >= self.data.len() {
120			return Err(Error::OutOfOffset);
121		}
122		let mut word = [0; ABI_WORD_SIZE as usize];
123		word.copy_from_slice(&self.data[self.offset..self.offset + 32]);
124		self.offset += 32;
125		Ok(word)
126	}
127	pub fn start_frame(&self) -> Self {
128		self.dynamic_at(self.offset as u32).expect("not oob")
129	}
130	pub fn dynamic_at(&self, offset: u32) -> Result<Self> {
131		if offset % 32 != 0 || self.data.len() < offset as usize {
132			// Technically, allowed by spec, yet nothing has such offsets
133			return Err(Error::OutOfOffset);
134		}
135		Self::new(
136			&self.data[offset as usize..],
137			self.global_frame_offset + offset as usize,
138		)
139	}
140}