1use core::fmt;
2
3use eth_valkyoth_codec::{
4 DecodeError, DecodeLimits, decode_rlp_scalar, decode_rlp_u64, decode_rlp_u256_bytes,
5 encode_rlp_integer, encode_rlp_scalar, encoded_rlp_integer_len, encoded_rlp_scalar_len,
6};
7
8use crate::{Address, B256, BlockNumber, ChainId, Gas, Nonce, PrimitiveError, UnixTimestamp, Wei};
9
10#[non_exhaustive]
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub enum PrimitiveRlpError {
19 Decode(DecodeError),
21 Primitive(PrimitiveError),
23 FixedWidthScalar {
25 expected: usize,
27 found: usize,
29 },
30}
31
32impl From<DecodeError> for PrimitiveRlpError {
33 fn from(error: DecodeError) -> Self {
34 Self::Decode(error)
35 }
36}
37
38impl From<PrimitiveError> for PrimitiveRlpError {
39 fn from(error: PrimitiveError) -> Self {
40 Self::Primitive(error)
41 }
42}
43
44impl fmt::Display for PrimitiveRlpError {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 match self {
47 Self::Decode(error) => write!(f, "RLP decode error: {error}"),
48 Self::Primitive(error) => write!(f, "primitive domain error: {error}"),
49 Self::FixedWidthScalar { expected, found } => write!(
50 f,
51 "RLP scalar payload has wrong byte width for this primitive: expected {expected}, found {found}"
52 ),
53 }
54 }
55}
56
57#[cfg(feature = "std")]
58impl std::error::Error for PrimitiveRlpError {
59 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
60 match self {
61 Self::Decode(error) => Some(error),
62 Self::Primitive(error) => Some(error),
63 Self::FixedWidthScalar { .. } => None,
64 }
65 }
66}
67
68macro_rules! rlp_u64_bridge {
69 ($name:ident) => {
70 impl $name {
71 pub fn encoded_rlp_len(self) -> Result<usize, PrimitiveRlpError> {
73 encoded_u64_len(self.get())
74 }
75
76 pub fn encode_rlp(self, output: &mut [u8]) -> Result<usize, PrimitiveRlpError> {
81 encode_u64(self.get(), output)
82 }
83
84 pub fn try_from_rlp(
86 input: &[u8],
87 limits: DecodeLimits,
88 ) -> Result<Self, PrimitiveRlpError> {
89 decode_rlp_u64(input, limits)
90 .map(Self::new)
91 .map_err(Into::into)
92 }
93 }
94 };
95}
96
97impl ChainId {
98 pub fn encoded_rlp_len(self) -> Result<usize, PrimitiveRlpError> {
100 encoded_u64_len(self.get())
101 }
102
103 pub fn encode_rlp(self, output: &mut [u8]) -> Result<usize, PrimitiveRlpError> {
108 encode_u64(self.get(), output)
109 }
110
111 pub fn try_from_rlp(input: &[u8], limits: DecodeLimits) -> Result<Self, PrimitiveRlpError> {
118 decode_rlp_u64(input, limits)
119 .map(Self::new)
120 .map_err(Into::into)
121 }
122
123 pub fn try_from_rlp_signed(
128 input: &[u8],
129 limits: DecodeLimits,
130 ) -> Result<Self, PrimitiveRlpError> {
131 let chain_id = Self::try_from_rlp(input, limits)?;
132 if chain_id.get() == 0 {
133 return Err(PrimitiveRlpError::Primitive(
134 PrimitiveError::ReservedLegacyType,
135 ));
136 }
137 Ok(chain_id)
138 }
139}
140
141rlp_u64_bridge!(BlockNumber);
142rlp_u64_bridge!(Gas);
143rlp_u64_bridge!(Nonce);
144rlp_u64_bridge!(UnixTimestamp);
145
146impl Wei {
147 pub fn encoded_rlp_len(self) -> Result<usize, PrimitiveRlpError> {
149 let bytes = self.to_be_bytes();
150 encoded_rlp_integer_len(trim_u256_payload(&bytes)).map_err(Into::into)
151 }
152
153 pub fn encode_rlp(self, output: &mut [u8]) -> Result<usize, PrimitiveRlpError> {
158 let bytes = self.to_be_bytes();
159 encode_rlp_integer(trim_u256_payload(&bytes), output).map_err(Into::into)
160 }
161
162 pub fn try_from_rlp(input: &[u8], limits: DecodeLimits) -> Result<Self, PrimitiveRlpError> {
164 decode_rlp_u256_bytes(input, limits)
165 .map(Self::from_be_bytes)
166 .map_err(Into::into)
167 }
168}
169
170impl Address {
171 pub fn encoded_rlp_len(self) -> Result<usize, PrimitiveRlpError> {
176 encoded_rlp_scalar_len(&self.to_bytes()).map_err(Into::into)
177 }
178
179 pub fn encode_rlp(self, output: &mut [u8]) -> Result<usize, PrimitiveRlpError> {
184 encode_rlp_scalar(&self.to_bytes(), output).map_err(Into::into)
185 }
186
187 pub fn try_from_rlp(input: &[u8], limits: DecodeLimits) -> Result<Self, PrimitiveRlpError> {
189 let scalar = decode_rlp_scalar(input, limits)?;
190 let found = scalar.payload().len();
191 let bytes: [u8; 20] =
192 scalar
193 .payload()
194 .try_into()
195 .map_err(|_| PrimitiveRlpError::FixedWidthScalar {
196 expected: 20,
197 found,
198 })?;
199 Ok(Self::from_bytes(bytes))
200 }
201}
202
203impl B256 {
204 pub fn encoded_rlp_len(self) -> Result<usize, PrimitiveRlpError> {
209 encoded_rlp_scalar_len(&self.to_bytes()).map_err(Into::into)
210 }
211
212 pub fn encode_rlp(self, output: &mut [u8]) -> Result<usize, PrimitiveRlpError> {
217 encode_rlp_scalar(&self.to_bytes(), output).map_err(Into::into)
218 }
219
220 pub fn try_from_rlp(input: &[u8], limits: DecodeLimits) -> Result<Self, PrimitiveRlpError> {
222 let scalar = decode_rlp_scalar(input, limits)?;
223 let found = scalar.payload().len();
224 let bytes: [u8; 32] =
225 scalar
226 .payload()
227 .try_into()
228 .map_err(|_| PrimitiveRlpError::FixedWidthScalar {
229 expected: 32,
230 found,
231 })?;
232 Ok(Self::from_bytes(bytes))
233 }
234}
235
236fn encoded_u64_len(value: u64) -> Result<usize, PrimitiveRlpError> {
237 let bytes = value.to_be_bytes();
238 encoded_rlp_integer_len(trim_u64_payload(&bytes)).map_err(Into::into)
239}
240
241fn encode_u64(value: u64, output: &mut [u8]) -> Result<usize, PrimitiveRlpError> {
242 let bytes = value.to_be_bytes();
243 encode_rlp_integer(trim_u64_payload(&bytes), output).map_err(Into::into)
244}
245
246fn trim_u64_payload(bytes: &[u8; 8]) -> &[u8] {
247 let start = bytes.iter().position(|byte| *byte != 0).unwrap_or(8);
252 bytes.get(start..).unwrap_or(&[])
253}
254
255fn trim_u256_payload(bytes: &[u8; 32]) -> &[u8] {
256 let start = bytes.iter().position(|byte| *byte != 0).unwrap_or(32);
260 bytes.get(start..).unwrap_or(&[])
261}