1use std::{
2 cmp::min,
3 fmt::Display,
4 num::NonZeroUsize,
5 sync::{LazyLock, Mutex},
6};
7
8use crate::utils::keccak;
9use bytes::Bytes;
10use ethereum_types::{Address, H256, U256};
11use ethrex_crypto::{Crypto, CryptoError};
12use lru::LruCache;
13pub use mempool::MempoolTransaction;
14
15const MAX_SIGNER_CACHE_ENTRIES: usize = 100_000;
16
17pub static GLOBAL_SIGNER_CACHE: LazyLock<Mutex<LruCache<H256, Address>>> = LazyLock::new(|| {
28 Mutex::new(LruCache::new(
29 NonZeroUsize::new(MAX_SIGNER_CACHE_ENTRIES).expect("MAX_SIGNER_CACHE_ENTRIES is non-zero"),
30 ))
31});
32use rkyv::{Archive, Deserialize as RDeserialize, Serialize as RSerialize};
33use serde::{Serialize, ser::SerializeStruct};
34pub use serde_impl::{
35 AccessListEntry, AuthorizationTupleEntry, GenericTransaction, GenericTransactionError,
36};
37
38pub const EIP1559_DEFAULT_SERIALIZED_LENGTH: usize = 15;
40
41use ethrex_rlp::{
42 constants::RLP_NULL,
43 decode::{RLPDecode, decode_rlp_item},
44 encode::{PayloadRLPEncode, RLPEncode},
45 error::RLPDecodeError,
46 structs::{Decoder, Encoder},
47};
48
49#[cfg(all(feature = "eip-8025", target_arch = "riscv64"))]
50use super::eip8025_cell::OnceCell;
51use crate::types::{AccessList, AuthorizationList, BlobsBundle};
52#[cfg(not(all(feature = "eip-8025", target_arch = "riscv64")))]
53use once_cell::sync::OnceCell;
54
55#[derive(Clone, Debug, PartialEq, Eq, Serialize, RSerialize, RDeserialize, Archive)]
64#[serde(untagged)]
65pub enum Transaction {
66 LegacyTransaction(LegacyTransaction),
67 EIP2930Transaction(EIP2930Transaction),
68 EIP1559Transaction(EIP1559Transaction),
69 EIP4844Transaction(EIP4844Transaction),
70 EIP7702Transaction(EIP7702Transaction),
71 PrivilegedL2Transaction(PrivilegedL2Transaction),
72 FeeTokenTransaction(FeeTokenTransaction),
73}
74
75#[derive(Clone, Debug, PartialEq, Eq)]
79pub enum P2PTransaction {
80 LegacyTransaction(LegacyTransaction),
81 EIP2930Transaction(EIP2930Transaction),
82 EIP1559Transaction(EIP1559Transaction),
83 EIP4844TransactionWithBlobs(WrappedEIP4844Transaction),
84 EIP7702Transaction(EIP7702Transaction),
85 FeeTokenTransaction(FeeTokenTransaction),
86}
87
88impl TryInto<Transaction> for P2PTransaction {
89 type Error = String;
90
91 fn try_into(self) -> Result<Transaction, Self::Error> {
92 match self {
93 P2PTransaction::LegacyTransaction(itx) => Ok(Transaction::LegacyTransaction(itx)),
94 P2PTransaction::EIP2930Transaction(itx) => Ok(Transaction::EIP2930Transaction(itx)),
95 P2PTransaction::EIP1559Transaction(itx) => Ok(Transaction::EIP1559Transaction(itx)),
96 P2PTransaction::EIP7702Transaction(itx) => Ok(Transaction::EIP7702Transaction(itx)),
97 _ => Err("Can't convert blob p2p transaction into regular transaction. Blob bundle would be lost.".to_string()),
98 }
99 }
100}
101
102impl RLPEncode for P2PTransaction {
103 fn encode(&self, buf: &mut dyn bytes::BufMut) {
104 match self {
105 P2PTransaction::LegacyTransaction(t) => t.encode(buf),
106 tx => <[u8] as RLPEncode>::encode(&tx.encode_canonical_to_vec(), buf),
107 };
108 }
109}
110
111impl RLPDecode for P2PTransaction {
112 fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
113 let (is_list, payload, remainder) = decode_rlp_item(rlp)?;
114 if !is_list {
115 let tx_type = payload.first().ok_or(RLPDecodeError::InvalidLength)?;
116 let tx_encoding = &payload.get(1..).ok_or(RLPDecodeError::InvalidLength)?;
117 match *tx_type {
119 0x0 => LegacyTransaction::decode(tx_encoding)
121 .map(|tx| (P2PTransaction::LegacyTransaction(tx), remainder)), 0x1 => EIP2930Transaction::decode(tx_encoding)
124 .map(|tx| (P2PTransaction::EIP2930Transaction(tx), remainder)),
125 0x2 => EIP1559Transaction::decode(tx_encoding)
127 .map(|tx| (P2PTransaction::EIP1559Transaction(tx), remainder)),
128 0x3 => WrappedEIP4844Transaction::decode(tx_encoding)
130 .map(|tx| (P2PTransaction::EIP4844TransactionWithBlobs(tx), remainder)),
131 0x4 => EIP7702Transaction::decode(tx_encoding)
133 .map(|tx| (P2PTransaction::EIP7702Transaction(tx), remainder)),
134 0x7d => FeeTokenTransaction::decode(tx_encoding)
136 .map(|tx| (P2PTransaction::FeeTokenTransaction(tx), remainder)),
137 ty => Err(RLPDecodeError::Custom(format!(
138 "Invalid transaction type: {ty}"
139 ))),
140 }
141 } else {
142 LegacyTransaction::decode_unfinished(rlp)
144 .map(|(tx, rem)| (P2PTransaction::LegacyTransaction(tx), rem))
145 }
146 }
147}
148
149#[derive(Clone, Debug, PartialEq, Eq)]
150pub struct WrappedEIP4844Transaction {
151 pub tx: EIP4844Transaction,
152 pub wrapper_version: Option<u8>,
153 pub blobs_bundle: BlobsBundle,
154}
155
156impl RLPEncode for WrappedEIP4844Transaction {
157 fn encode(&self, buf: &mut dyn bytes::BufMut) {
158 let encoder = Encoder::new(buf);
159 encoder
160 .encode_field(&self.tx)
161 .encode_optional_field(&self.wrapper_version)
162 .encode_field(&self.blobs_bundle.blobs)
163 .encode_field(&self.blobs_bundle.commitments)
164 .encode_field(&self.blobs_bundle.proofs)
165 .finish();
166 }
167}
168
169impl RLPDecode for WrappedEIP4844Transaction {
170 fn decode_unfinished(rlp: &[u8]) -> Result<(WrappedEIP4844Transaction, &[u8]), RLPDecodeError> {
171 let decoder = Decoder::new(rlp)?;
172 let Ok((tx, decoder)) = decoder.decode_field("tx") else {
173 let (tx, rest) = EIP4844Transaction::decode_unfinished(rlp)?;
175 return Ok((
176 WrappedEIP4844Transaction {
177 tx,
178 wrapper_version: None,
179 blobs_bundle: BlobsBundle::empty(),
181 },
182 rest,
183 ));
184 };
185
186 let (wrapper_version, decoder) = decoder.decode_optional_field();
187 let (blobs, decoder) = decoder.decode_field("blobs")?;
188 let (commitments, decoder) = decoder.decode_field("commitments")?;
189 let (proofs, decoder) = decoder.decode_field("proofs")?;
190
191 let wrapped = WrappedEIP4844Transaction {
192 tx,
193 wrapper_version,
194 blobs_bundle: BlobsBundle {
195 blobs,
196 commitments,
197 proofs,
198 version: wrapper_version.unwrap_or_default(),
199 },
200 };
201 Ok((wrapped, decoder.finish()?))
202 }
203}
204
205#[derive(Clone, Debug, PartialEq, Eq, Default, RSerialize, RDeserialize, Archive)]
206pub struct LegacyTransaction {
207 pub nonce: u64,
208 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
209 pub gas_price: U256,
210 pub gas: u64,
211 pub to: TxKind,
214 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
215 pub value: U256,
216 #[rkyv(with=crate::rkyv_utils::BytesWrapper)]
217 pub data: Bytes,
218 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
219 pub v: U256,
220 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
221 pub r: U256,
222 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
223 pub s: U256,
224 #[rkyv(with=rkyv::with::Skip)]
225 pub inner_hash: OnceCell<H256>,
226 #[rkyv(with=rkyv::with::Skip)]
227 pub sender_cache: OnceCell<Address>,
228}
229
230#[derive(Clone, Debug, PartialEq, Eq, Default, RSerialize, RDeserialize, Archive)]
231pub struct EIP2930Transaction {
232 pub chain_id: u64,
233 pub nonce: u64,
234 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
235 pub gas_price: U256,
236 pub gas_limit: u64,
237 pub to: TxKind,
238 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
239 pub value: U256,
240 #[rkyv(with=crate::rkyv_utils::BytesWrapper)]
241 pub data: Bytes,
242 #[rkyv(with=rkyv::with::Map<crate::rkyv_utils::AccessListItemWrapper>)]
243 pub access_list: AccessList,
244 pub signature_y_parity: bool,
245 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
246 pub signature_r: U256,
247 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
248 pub signature_s: U256,
249 #[rkyv(with=rkyv::with::Skip)]
250 pub inner_hash: OnceCell<H256>,
251 #[rkyv(with=rkyv::with::Skip)]
252 pub sender_cache: OnceCell<Address>,
253 #[rkyv(with=rkyv::with::Skip)]
254 pub cached_canonical: OnceCell<Vec<u8>>,
255}
256
257#[derive(Clone, Debug, PartialEq, Eq, Default, RSerialize, RDeserialize, Archive)]
258pub struct EIP1559Transaction {
259 pub chain_id: u64,
260 pub nonce: u64,
261 pub max_priority_fee_per_gas: u64,
262 pub max_fee_per_gas: u64,
263 pub gas_limit: u64,
264 pub to: TxKind,
265 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
266 pub value: U256,
267 #[rkyv(with=crate::rkyv_utils::BytesWrapper)]
268 pub data: Bytes,
269 #[rkyv(with=rkyv::with::Map<crate::rkyv_utils::AccessListItemWrapper>)]
270 pub access_list: AccessList,
271 pub signature_y_parity: bool,
272 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
273 pub signature_r: U256,
274 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
275 pub signature_s: U256,
276 #[rkyv(with=rkyv::with::Skip)]
277 pub inner_hash: OnceCell<H256>,
278 #[rkyv(with=rkyv::with::Skip)]
279 pub sender_cache: OnceCell<Address>,
280 #[rkyv(with=rkyv::with::Skip)]
281 pub cached_canonical: OnceCell<Vec<u8>>,
282}
283
284#[derive(Clone, Debug, PartialEq, Eq, Default, RSerialize, RDeserialize, Archive)]
285pub struct EIP4844Transaction {
286 pub chain_id: u64,
287 pub nonce: u64,
288 pub max_priority_fee_per_gas: u64,
289 pub max_fee_per_gas: u64,
290 pub gas: u64,
291 #[rkyv(with=crate::rkyv_utils::H160Wrapper)]
292 pub to: Address,
293 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
294 pub value: U256,
295 #[rkyv(with=crate::rkyv_utils::BytesWrapper)]
296 pub data: Bytes,
297 #[rkyv(with=rkyv::with::Map<crate::rkyv_utils::AccessListItemWrapper>)]
298 pub access_list: AccessList,
299 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
300 pub max_fee_per_blob_gas: U256,
301 #[rkyv(with=rkyv::with::Map<crate::rkyv_utils::H256Wrapper>)]
302 pub blob_versioned_hashes: Vec<H256>,
303 pub signature_y_parity: bool,
304 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
305 pub signature_r: U256,
306 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
307 pub signature_s: U256,
308 #[rkyv(with=rkyv::with::Skip)]
309 pub inner_hash: OnceCell<H256>,
310 #[rkyv(with=rkyv::with::Skip)]
311 pub sender_cache: OnceCell<Address>,
312 #[rkyv(with=rkyv::with::Skip)]
313 pub cached_canonical: OnceCell<Vec<u8>>,
314}
315
316#[derive(Clone, Debug, PartialEq, Eq, Default, RSerialize, RDeserialize, Archive)]
317pub struct EIP7702Transaction {
318 pub chain_id: u64,
319 pub nonce: u64,
320 pub max_priority_fee_per_gas: u64,
321 pub max_fee_per_gas: u64,
322 pub gas_limit: u64,
323 #[rkyv(with=crate::rkyv_utils::H160Wrapper)]
324 pub to: Address,
325 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
326 pub value: U256,
327 #[rkyv(with=crate::rkyv_utils::BytesWrapper)]
328 pub data: Bytes,
329 #[rkyv(with=rkyv::with::Map<crate::rkyv_utils::AccessListItemWrapper>)]
330 pub access_list: AccessList,
331 pub authorization_list: AuthorizationList,
332 pub signature_y_parity: bool,
333 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
334 pub signature_r: U256,
335 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
336 pub signature_s: U256,
337 #[rkyv(with=rkyv::with::Skip)]
338 pub inner_hash: OnceCell<H256>,
339 #[rkyv(with=rkyv::with::Skip)]
340 pub sender_cache: OnceCell<Address>,
341 #[rkyv(with=rkyv::with::Skip)]
342 pub cached_canonical: OnceCell<Vec<u8>>,
343}
344#[derive(Clone, Debug, PartialEq, Eq, Default, RSerialize, RDeserialize, Archive)]
345pub struct PrivilegedL2Transaction {
346 pub chain_id: u64,
347 pub nonce: u64,
348 pub max_priority_fee_per_gas: u64,
349 pub max_fee_per_gas: u64,
350 pub gas_limit: u64,
351 pub to: TxKind,
352 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
353 pub value: U256,
354 #[rkyv(with=crate::rkyv_utils::BytesWrapper)]
355 pub data: Bytes,
356 #[rkyv(with=rkyv::with::Map<crate::rkyv_utils::AccessListItemWrapper>)]
357 pub access_list: AccessList,
358 #[rkyv(with=crate::rkyv_utils::H160Wrapper)]
359 pub from: Address,
360 #[rkyv(with=rkyv::with::Skip)]
361 pub inner_hash: OnceCell<H256>,
362 #[rkyv(with=rkyv::with::Skip)]
363 pub sender_cache: OnceCell<Address>,
364 #[rkyv(with=rkyv::with::Skip)]
365 pub cached_canonical: OnceCell<Vec<u8>>,
366}
367
368#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
369pub enum TxType {
370 #[default]
371 Legacy = 0x00,
372 EIP2930 = 0x01,
373 EIP1559 = 0x02,
374 EIP4844 = 0x03,
375 EIP7702 = 0x04,
376 FeeToken = 0x7d,
377 Privileged = 0x7e,
380}
381
382impl From<TxType> for u8 {
383 fn from(val: TxType) -> Self {
384 match val {
385 TxType::Legacy => 0x00,
386 TxType::EIP2930 => 0x01,
387 TxType::EIP1559 => 0x02,
388 TxType::EIP4844 => 0x03,
389 TxType::EIP7702 => 0x04,
390 TxType::FeeToken => 0x7d,
391 TxType::Privileged => 0x7e,
392 }
393 }
394}
395
396impl Display for TxType {
397 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
398 match self {
399 TxType::Legacy => write!(f, "Legacy"),
400 TxType::EIP2930 => write!(f, "EIP2930"),
401 TxType::EIP1559 => write!(f, "EIP1559"),
402 TxType::EIP4844 => write!(f, "EIP4844"),
403 TxType::EIP7702 => write!(f, "EIP7702"),
404 TxType::Privileged => write!(f, "Privileged"),
405 TxType::FeeToken => write!(f, "FeeToken"),
406 }
407 }
408}
409
410impl Transaction {
411 pub fn tx_type(&self) -> TxType {
412 match self {
413 Transaction::LegacyTransaction(_) => TxType::Legacy,
414 Transaction::EIP2930Transaction(_) => TxType::EIP2930,
415 Transaction::EIP1559Transaction(_) => TxType::EIP1559,
416 Transaction::EIP4844Transaction(_) => TxType::EIP4844,
417 Transaction::EIP7702Transaction(_) => TxType::EIP7702,
418 Transaction::FeeTokenTransaction(_) => TxType::FeeToken,
419 Transaction::PrivilegedL2Transaction(_) => TxType::Privileged,
420 }
421 }
422
423 fn calc_effective_gas_price(&self, base_fee_per_gas: Option<u64>) -> Option<U256> {
424 let base_fee = base_fee_per_gas?;
425 let max_fee = self.max_fee_per_gas()?;
426 if max_fee < base_fee {
427 return None;
429 }
430
431 let priority_fee_per_gas = min(self.max_priority_fee()?, max_fee.saturating_sub(base_fee));
432 Some(U256::from(priority_fee_per_gas) + U256::from(base_fee))
433 }
434
435 pub fn effective_gas_price(&self, base_fee_per_gas: Option<u64>) -> Option<U256> {
436 match self.tx_type() {
437 TxType::Legacy => Some(self.gas_price()),
438 TxType::EIP2930 => Some(self.gas_price()),
439 TxType::EIP1559 => self.calc_effective_gas_price(base_fee_per_gas),
440 TxType::EIP4844 => self.calc_effective_gas_price(base_fee_per_gas),
441 TxType::EIP7702 => self.calc_effective_gas_price(base_fee_per_gas),
442 TxType::FeeToken => self.calc_effective_gas_price(base_fee_per_gas),
443 TxType::Privileged => Some(self.gas_price()),
444 }
445 }
446
447 pub fn cost_without_base_fee(&self) -> Option<U256> {
448 let price = match self.tx_type() {
449 TxType::Legacy => self.gas_price(),
450 TxType::EIP2930 => self.gas_price(),
451 TxType::EIP1559 => U256::from(self.max_fee_per_gas()?),
452 TxType::EIP4844 => U256::from(self.max_fee_per_gas()?),
453 TxType::EIP7702 => U256::from(self.max_fee_per_gas()?),
454 TxType::FeeToken => U256::from(self.max_fee_per_gas()?),
455 TxType::Privileged => self.gas_price(),
456 };
457
458 let base = U256::saturating_add(
459 U256::saturating_mul(price, self.gas_limit().into()),
460 self.value(),
461 );
462
463 if let Transaction::EIP4844Transaction(tx) = self {
467 let blob_gas = U256::from(crate::constants::GAS_PER_BLOB)
468 .saturating_mul(U256::from(tx.blob_versioned_hashes.len() as u64));
469 let blob_cost = blob_gas.saturating_mul(tx.max_fee_per_blob_gas);
470 return Some(base.saturating_add(blob_cost));
471 }
472
473 Some(base)
474 }
475
476 pub fn fee_token(&self) -> Option<Address> {
477 if let Transaction::FeeTokenTransaction(tx) = self {
478 Some(tx.fee_token)
479 } else {
480 None
481 }
482 }
483
484 fn cached_canonical_cell(&self) -> Option<&OnceCell<Vec<u8>>> {
487 match self {
488 Transaction::LegacyTransaction(_) => None,
489 Transaction::EIP2930Transaction(t) => Some(&t.cached_canonical),
490 Transaction::EIP1559Transaction(t) => Some(&t.cached_canonical),
491 Transaction::EIP4844Transaction(t) => Some(&t.cached_canonical),
492 Transaction::EIP7702Transaction(t) => Some(&t.cached_canonical),
493 Transaction::PrivilegedL2Transaction(t) => Some(&t.cached_canonical),
494 Transaction::FeeTokenTransaction(t) => Some(&t.cached_canonical),
495 }
496 }
497}
498
499impl RLPEncode for Transaction {
500 fn encode(&self, buf: &mut dyn bytes::BufMut) {
505 match self {
506 Transaction::LegacyTransaction(t) => t.encode(buf),
507 _ => {
508 let canonical = self.encode_canonical_to_vec();
509 <[u8] as RLPEncode>::encode(canonical.as_slice(), buf)
510 }
511 };
512 }
513}
514
515impl RLPDecode for Transaction {
516 fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
521 let (is_list, payload, remainder) = decode_rlp_item(rlp)?;
522 if !is_list {
523 let tx_type = payload.first().ok_or(RLPDecodeError::InvalidLength)?;
524 let tx_encoding = &payload.get(1..).ok_or(RLPDecodeError::InvalidLength)?;
525 match *tx_type {
527 0x0 => LegacyTransaction::decode(tx_encoding)
529 .map(|tx| (Transaction::LegacyTransaction(tx), remainder)), 0x1 => EIP2930Transaction::decode(tx_encoding)
532 .map(|tx| (Transaction::EIP2930Transaction(tx), remainder)),
533 0x2 => EIP1559Transaction::decode(tx_encoding)
535 .map(|tx| (Transaction::EIP1559Transaction(tx), remainder)),
536 0x3 => EIP4844Transaction::decode(tx_encoding)
538 .map(|tx| (Transaction::EIP4844Transaction(tx), remainder)),
539 0x4 => EIP7702Transaction::decode(tx_encoding)
541 .map(|tx| (Transaction::EIP7702Transaction(tx), remainder)),
542 0x7d => FeeTokenTransaction::decode(tx_encoding)
544 .map(|tx| (Transaction::FeeTokenTransaction(tx), remainder)),
545 0x7e => PrivilegedL2Transaction::decode(tx_encoding)
547 .map(|tx| (Transaction::PrivilegedL2Transaction(tx), remainder)),
548 ty => Err(RLPDecodeError::Custom(format!(
549 "Invalid transaction type: {ty}"
550 ))),
551 }
552 } else {
553 LegacyTransaction::decode_unfinished(rlp)
555 .map(|(tx, rem)| (Transaction::LegacyTransaction(tx), rem))
556 }
557 }
558}
559
560#[derive(Clone, Debug, PartialEq, Eq, Default, RSerialize, RDeserialize, Archive)]
562pub enum TxKind {
563 Call(#[rkyv(with=crate::rkyv_utils::H160Wrapper)] Address),
564 #[default]
565 Create,
566}
567
568impl RLPEncode for TxKind {
569 fn encode(&self, buf: &mut dyn bytes::BufMut) {
570 match self {
571 Self::Call(address) => address.encode(buf),
572 Self::Create => buf.put_u8(RLP_NULL),
573 }
574 }
575}
576
577impl RLPDecode for TxKind {
578 fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
579 let first_byte = rlp.first().ok_or(RLPDecodeError::InvalidLength)?;
580 if *first_byte == RLP_NULL {
581 return Ok((Self::Create, &rlp[1..]));
582 }
583 Address::decode_unfinished(rlp).map(|(t, rest)| (Self::Call(t), rest))
584 }
585}
586
587impl RLPEncode for LegacyTransaction {
588 fn encode(&self, buf: &mut dyn bytes::BufMut) {
589 Encoder::new(buf)
590 .encode_field(&self.nonce)
591 .encode_field(&self.gas_price)
592 .encode_field(&self.gas)
593 .encode_field(&self.to)
594 .encode_field(&self.value)
595 .encode_field(&self.data)
596 .encode_field(&self.v)
597 .encode_field(&self.r)
598 .encode_field(&self.s)
599 .finish();
600 }
601}
602
603impl RLPEncode for EIP2930Transaction {
604 fn encode(&self, buf: &mut dyn bytes::BufMut) {
605 Encoder::new(buf)
606 .encode_field(&self.chain_id)
607 .encode_field(&self.nonce)
608 .encode_field(&self.gas_price)
609 .encode_field(&self.gas_limit)
610 .encode_field(&self.to)
611 .encode_field(&self.value)
612 .encode_field(&self.data)
613 .encode_field(&self.access_list)
614 .encode_field(&self.signature_y_parity)
615 .encode_field(&self.signature_r)
616 .encode_field(&self.signature_s)
617 .finish()
618 }
619}
620
621impl RLPEncode for EIP1559Transaction {
622 fn encode(&self, buf: &mut dyn bytes::BufMut) {
623 Encoder::new(buf)
624 .encode_field(&self.chain_id)
625 .encode_field(&self.nonce)
626 .encode_field(&self.max_priority_fee_per_gas)
627 .encode_field(&self.max_fee_per_gas)
628 .encode_field(&self.gas_limit)
629 .encode_field(&self.to)
630 .encode_field(&self.value)
631 .encode_field(&self.data)
632 .encode_field(&self.access_list)
633 .encode_field(&self.signature_y_parity)
634 .encode_field(&self.signature_r)
635 .encode_field(&self.signature_s)
636 .finish()
637 }
638}
639
640impl RLPEncode for EIP4844Transaction {
641 fn encode(&self, buf: &mut dyn bytes::BufMut) {
642 Encoder::new(buf)
643 .encode_field(&self.chain_id)
644 .encode_field(&self.nonce)
645 .encode_field(&self.max_priority_fee_per_gas)
646 .encode_field(&self.max_fee_per_gas)
647 .encode_field(&self.gas)
648 .encode_field(&self.to)
649 .encode_field(&self.value)
650 .encode_field(&self.data)
651 .encode_field(&self.access_list)
652 .encode_field(&self.max_fee_per_blob_gas)
653 .encode_field(&self.blob_versioned_hashes)
654 .encode_field(&self.signature_y_parity)
655 .encode_field(&self.signature_r)
656 .encode_field(&self.signature_s)
657 .finish()
658 }
659}
660
661impl RLPEncode for EIP7702Transaction {
662 fn encode(&self, buf: &mut dyn bytes::BufMut) {
663 Encoder::new(buf)
664 .encode_field(&self.chain_id)
665 .encode_field(&self.nonce)
666 .encode_field(&self.max_priority_fee_per_gas)
667 .encode_field(&self.max_fee_per_gas)
668 .encode_field(&self.gas_limit)
669 .encode_field(&self.to)
670 .encode_field(&self.value)
671 .encode_field(&self.data)
672 .encode_field(&self.access_list)
673 .encode_field(&self.authorization_list)
674 .encode_field(&self.signature_y_parity)
675 .encode_field(&self.signature_r)
676 .encode_field(&self.signature_s)
677 .finish()
678 }
679}
680
681impl RLPEncode for PrivilegedL2Transaction {
682 fn encode(&self, buf: &mut dyn bytes::BufMut) {
683 Encoder::new(buf)
684 .encode_field(&self.chain_id)
685 .encode_field(&self.nonce)
686 .encode_field(&self.max_priority_fee_per_gas)
687 .encode_field(&self.max_fee_per_gas)
688 .encode_field(&self.gas_limit)
689 .encode_field(&self.to)
690 .encode_field(&self.value)
691 .encode_field(&self.data)
692 .encode_field(&self.access_list)
693 .encode_field(&self.from)
694 .finish()
695 }
696}
697
698impl RLPEncode for FeeTokenTransaction {
699 fn encode(&self, buf: &mut dyn bytes::BufMut) {
700 Encoder::new(buf)
701 .encode_field(&self.chain_id)
702 .encode_field(&self.nonce)
703 .encode_field(&self.max_priority_fee_per_gas)
704 .encode_field(&self.max_fee_per_gas)
705 .encode_field(&self.gas_limit)
706 .encode_field(&self.to)
707 .encode_field(&self.value)
708 .encode_field(&self.data)
709 .encode_field(&self.access_list)
710 .encode_field(&self.fee_token)
711 .encode_field(&self.signature_y_parity)
712 .encode_field(&self.signature_r)
713 .encode_field(&self.signature_s)
714 .finish()
715 }
716}
717
718impl PayloadRLPEncode for Transaction {
719 fn encode_payload(&self, buf: &mut dyn bytes::BufMut) {
720 match self {
721 Transaction::LegacyTransaction(tx) => tx.encode_payload(buf),
722 Transaction::EIP1559Transaction(tx) => tx.encode_payload(buf),
723 Transaction::EIP2930Transaction(tx) => tx.encode_payload(buf),
724 Transaction::EIP4844Transaction(tx) => tx.encode_payload(buf),
725 Transaction::EIP7702Transaction(tx) => tx.encode_payload(buf),
726 Transaction::PrivilegedL2Transaction(tx) => tx.encode_payload(buf),
727 Transaction::FeeTokenTransaction(tx) => tx.encode_payload(buf),
728 }
729 }
730}
731
732impl PayloadRLPEncode for LegacyTransaction {
733 fn encode_payload(&self, buf: &mut dyn bytes::BufMut) {
734 Encoder::new(buf)
735 .encode_field(&self.nonce)
736 .encode_field(&self.gas_price)
737 .encode_field(&self.gas)
738 .encode_field(&self.to)
739 .encode_field(&self.value)
740 .encode_field(&self.data)
741 .finish();
742 }
743}
744
745impl PayloadRLPEncode for EIP1559Transaction {
746 fn encode_payload(&self, buf: &mut dyn bytes::BufMut) {
747 Encoder::new(buf)
748 .encode_field(&self.chain_id)
749 .encode_field(&self.nonce)
750 .encode_field(&self.max_priority_fee_per_gas)
751 .encode_field(&self.max_fee_per_gas)
752 .encode_field(&self.gas_limit)
753 .encode_field(&self.to)
754 .encode_field(&self.value)
755 .encode_field(&self.data)
756 .encode_field(&self.access_list)
757 .finish();
758 }
759}
760
761impl PayloadRLPEncode for EIP2930Transaction {
762 fn encode_payload(&self, buf: &mut dyn bytes::BufMut) {
763 Encoder::new(buf)
764 .encode_field(&self.chain_id)
765 .encode_field(&self.nonce)
766 .encode_field(&self.gas_price)
767 .encode_field(&self.gas_limit)
768 .encode_field(&self.to)
769 .encode_field(&self.value)
770 .encode_field(&self.data)
771 .encode_field(&self.access_list)
772 .finish();
773 }
774}
775
776impl PayloadRLPEncode for EIP4844Transaction {
777 fn encode_payload(&self, buf: &mut dyn bytes::BufMut) {
778 Encoder::new(buf)
779 .encode_field(&self.chain_id)
780 .encode_field(&self.nonce)
781 .encode_field(&self.max_priority_fee_per_gas)
782 .encode_field(&self.max_fee_per_gas)
783 .encode_field(&self.gas)
784 .encode_field(&self.to)
785 .encode_field(&self.value)
786 .encode_field(&self.data)
787 .encode_field(&self.access_list)
788 .encode_field(&self.max_fee_per_blob_gas)
789 .encode_field(&self.blob_versioned_hashes)
790 .finish();
791 }
792}
793
794impl PayloadRLPEncode for EIP7702Transaction {
795 fn encode_payload(&self, buf: &mut dyn bytes::BufMut) {
796 Encoder::new(buf)
797 .encode_field(&self.chain_id)
798 .encode_field(&self.nonce)
799 .encode_field(&self.max_priority_fee_per_gas)
800 .encode_field(&self.max_fee_per_gas)
801 .encode_field(&self.gas_limit)
802 .encode_field(&self.to)
803 .encode_field(&self.value)
804 .encode_field(&self.data)
805 .encode_field(&self.access_list)
806 .encode_field(&self.authorization_list)
807 .finish();
808 }
809}
810
811impl PayloadRLPEncode for PrivilegedL2Transaction {
812 fn encode_payload(&self, buf: &mut dyn bytes::BufMut) {
813 Encoder::new(buf)
814 .encode_field(&self.chain_id)
815 .encode_field(&self.nonce)
816 .encode_field(&self.max_priority_fee_per_gas)
817 .encode_field(&self.max_fee_per_gas)
818 .encode_field(&self.gas_limit)
819 .encode_field(&self.to)
820 .encode_field(&self.value)
821 .encode_field(&self.data)
822 .encode_field(&self.access_list)
823 .encode_field(&self.from)
824 .finish();
825 }
826}
827
828impl PayloadRLPEncode for FeeTokenTransaction {
829 fn encode_payload(&self, buf: &mut dyn bytes::BufMut) {
830 Encoder::new(buf)
831 .encode_field(&self.chain_id)
832 .encode_field(&self.nonce)
833 .encode_field(&self.max_priority_fee_per_gas)
834 .encode_field(&self.max_fee_per_gas)
835 .encode_field(&self.gas_limit)
836 .encode_field(&self.to)
837 .encode_field(&self.value)
838 .encode_field(&self.data)
839 .encode_field(&self.access_list)
840 .encode_field(&self.fee_token)
841 .finish();
842 }
843}
844
845impl RLPDecode for LegacyTransaction {
846 fn decode_unfinished(rlp: &[u8]) -> Result<(LegacyTransaction, &[u8]), RLPDecodeError> {
847 let decoder = Decoder::new(rlp)?;
848 let (nonce, decoder) = decoder.decode_field("nonce")?;
849 let (gas_price, decoder) = decoder.decode_field("gas_price")?;
850 let (gas, decoder) = decoder.decode_field("gas")?;
851 let (to, decoder) = decoder.decode_field("to")?;
852 let (value, decoder) = decoder.decode_field("value")?;
853 let (data, decoder) = decoder.decode_field("data")?;
854 let (v, decoder) = decoder.decode_field("v")?;
855 let (r, decoder) = decoder.decode_field("r")?;
856 let (s, decoder) = decoder.decode_field("s")?;
857 let inner_hash = OnceCell::new();
858 let sender_cache = OnceCell::new();
859
860 let tx = LegacyTransaction {
861 nonce,
862 gas_price,
863 gas,
864 to,
865 value,
866 data,
867 v,
868 r,
869 s,
870 inner_hash,
871 sender_cache,
872 };
873 Ok((tx, decoder.finish()?))
874 }
875}
876
877impl RLPDecode for EIP2930Transaction {
878 fn decode_unfinished(rlp: &[u8]) -> Result<(EIP2930Transaction, &[u8]), RLPDecodeError> {
879 let decoder = Decoder::new(rlp)?;
880 let (chain_id, decoder) = decoder.decode_field("chain_id")?;
881 let (nonce, decoder) = decoder.decode_field("nonce")?;
882 let (gas_price, decoder) = decoder.decode_field("gas_price")?;
883 let (gas_limit, decoder) = decoder.decode_field("gas_limit")?;
884 let (to, decoder) = decoder.decode_field("to")?;
885 let (value, decoder) = decoder.decode_field("value")?;
886 let (data, decoder) = decoder.decode_field("data")?;
887 let (access_list, decoder) = decoder.decode_field("access_list")?;
888 let (signature_y_parity, decoder) = decoder.decode_field("signature_y_parity")?;
889 let (signature_r, decoder) = decoder.decode_field("signature_r")?;
890 let (signature_s, decoder) = decoder.decode_field("signature_s")?;
891 let inner_hash = OnceCell::new();
892 let sender_cache = OnceCell::new();
893 let cached_canonical = OnceCell::new();
894
895 let tx = EIP2930Transaction {
896 chain_id,
897 nonce,
898 gas_price,
899 gas_limit,
900 to,
901 value,
902 data,
903 access_list,
904 signature_y_parity,
905 signature_r,
906 signature_s,
907 inner_hash,
908 sender_cache,
909 cached_canonical,
910 };
911 Ok((tx, decoder.finish()?))
912 }
913}
914
915impl RLPDecode for EIP1559Transaction {
916 fn decode_unfinished(rlp: &[u8]) -> Result<(EIP1559Transaction, &[u8]), RLPDecodeError> {
917 let decoder = Decoder::new(rlp)?;
918 let (chain_id, decoder) = decoder.decode_field("chain_id")?;
919 let (nonce, decoder) = decoder.decode_field("nonce")?;
920 let (max_priority_fee_per_gas, decoder) =
921 decoder.decode_field("max_priority_fee_per_gas")?;
922 let (max_fee_per_gas, decoder) = decoder.decode_field("max_fee_per_gas")?;
923 let (gas_limit, decoder) = decoder.decode_field("gas_limit")?;
924 let (to, decoder) = decoder.decode_field("to")?;
925 let (value, decoder) = decoder.decode_field("value")?;
926 let (data, decoder) = decoder.decode_field("data")?;
927 let (access_list, decoder) = decoder.decode_field("access_list")?;
928 let (signature_y_parity, decoder) = decoder.decode_field("signature_y_parity")?;
929 let (signature_r, decoder) = decoder.decode_field("signature_r")?;
930 let (signature_s, decoder) = decoder.decode_field("signature_s")?;
931 let inner_hash = OnceCell::new();
932 let sender_cache = OnceCell::new();
933 let cached_canonical = OnceCell::new();
934
935 let tx = EIP1559Transaction {
936 chain_id,
937 nonce,
938 max_priority_fee_per_gas,
939 max_fee_per_gas,
940 gas_limit,
941 to,
942 value,
943 data,
944 access_list,
945 signature_y_parity,
946 signature_r,
947 signature_s,
948 inner_hash,
949 sender_cache,
950 cached_canonical,
951 };
952 Ok((tx, decoder.finish()?))
953 }
954}
955
956impl RLPDecode for EIP4844Transaction {
957 fn decode_unfinished(rlp: &[u8]) -> Result<(EIP4844Transaction, &[u8]), RLPDecodeError> {
958 let decoder = Decoder::new(rlp)?;
959 let (chain_id, decoder) = decoder.decode_field("chain_id")?;
960 let (nonce, decoder) = decoder.decode_field("nonce")?;
961 let (max_priority_fee_per_gas, decoder) =
962 decoder.decode_field("max_priority_fee_per_gas")?;
963 let (max_fee_per_gas, decoder) = decoder.decode_field("max_fee_per_gas")?;
964 let (gas, decoder) = decoder.decode_field("gas")?;
965 let (to, decoder) = decoder.decode_field("to")?;
966 let (value, decoder) = decoder.decode_field("value")?;
967 let (data, decoder) = decoder.decode_field("data")?;
968 let (access_list, decoder) = decoder.decode_field("access_list")?;
969 let (max_fee_per_blob_gas, decoder) = decoder.decode_field("max_fee_per_blob_gas")?;
970 let (blob_versioned_hashes, decoder) = decoder.decode_field("blob_versioned_hashes")?;
971 let (signature_y_parity, decoder) = decoder.decode_field("signature_y_parity")?;
972 let (signature_r, decoder) = decoder.decode_field("signature_r")?;
973 let (signature_s, decoder) = decoder.decode_field("signature_s")?;
974 let inner_hash = OnceCell::new();
975 let sender_cache = OnceCell::new();
976 let cached_canonical = OnceCell::new();
977
978 let tx = EIP4844Transaction {
979 chain_id,
980 nonce,
981 max_priority_fee_per_gas,
982 max_fee_per_gas,
983 gas,
984 to,
985 value,
986 data,
987 access_list,
988 max_fee_per_blob_gas,
989 blob_versioned_hashes,
990 signature_y_parity,
991 signature_r,
992 signature_s,
993 inner_hash,
994 sender_cache,
995 cached_canonical,
996 };
997 Ok((tx, decoder.finish()?))
998 }
999}
1000
1001impl RLPDecode for EIP7702Transaction {
1002 fn decode_unfinished(rlp: &[u8]) -> Result<(EIP7702Transaction, &[u8]), RLPDecodeError> {
1003 let decoder = Decoder::new(rlp)?;
1004 let (chain_id, decoder) = decoder.decode_field("chain_id")?;
1005 let (nonce, decoder) = decoder.decode_field("nonce")?;
1006 let (max_priority_fee_per_gas, decoder) =
1007 decoder.decode_field("max_priority_fee_per_gas")?;
1008 let (max_fee_per_gas, decoder) = decoder.decode_field("max_fee_per_gas")?;
1009 let (gas_limit, decoder) = decoder.decode_field("gas_limit")?;
1010 let (to, decoder) = decoder.decode_field("to")?;
1011 let (value, decoder) = decoder.decode_field("value")?;
1012 let (data, decoder) = decoder.decode_field("data")?;
1013 let (access_list, decoder) = decoder.decode_field("access_list")?;
1014 let (authorization_list, decoder) = decoder.decode_field("authorization_list")?;
1015 let (signature_y_parity, decoder) = decoder.decode_field("signature_y_parity")?;
1016 let (signature_r, decoder) = decoder.decode_field("signature_r")?;
1017 let (signature_s, decoder) = decoder.decode_field("signature_s")?;
1018 let inner_hash = OnceCell::new();
1019 let sender_cache = OnceCell::new();
1020 let cached_canonical = OnceCell::new();
1021
1022 let tx = EIP7702Transaction {
1023 chain_id,
1024 nonce,
1025 max_priority_fee_per_gas,
1026 max_fee_per_gas,
1027 gas_limit,
1028 to,
1029 value,
1030 data,
1031 access_list,
1032 authorization_list,
1033 signature_y_parity,
1034 signature_r,
1035 signature_s,
1036 inner_hash,
1037 sender_cache,
1038 cached_canonical,
1039 };
1040 Ok((tx, decoder.finish()?))
1041 }
1042}
1043
1044impl RLPDecode for PrivilegedL2Transaction {
1045 fn decode_unfinished(rlp: &[u8]) -> Result<(PrivilegedL2Transaction, &[u8]), RLPDecodeError> {
1046 let decoder = Decoder::new(rlp)?;
1047 let (chain_id, decoder) = decoder.decode_field("chain_id")?;
1048 let (nonce, decoder) = decoder.decode_field("nonce")?;
1049 let (max_priority_fee_per_gas, decoder) =
1050 decoder.decode_field("max_priority_fee_per_gas")?;
1051 let (max_fee_per_gas, decoder) = decoder.decode_field("max_fee_per_gas")?;
1052 let (gas_limit, decoder) = decoder.decode_field::<u64>("gas_limit")?;
1053 let (to, decoder) = decoder.decode_field("to")?;
1054 let (value, decoder) = decoder.decode_field("value")?;
1055 let (data, decoder) = decoder.decode_field("data")?;
1056 let (access_list, decoder) = decoder.decode_field("access_list")?;
1057 let (from, decoder) = decoder.decode_field("from")?;
1058 let inner_hash = OnceCell::new();
1059 let sender_cache = OnceCell::new();
1060 let cached_canonical = OnceCell::new();
1061
1062 let tx = PrivilegedL2Transaction {
1063 chain_id,
1064 nonce,
1065 max_priority_fee_per_gas,
1066 max_fee_per_gas,
1067 gas_limit,
1068 to,
1069 value,
1070 data,
1071 access_list,
1072 from,
1073 inner_hash,
1074 sender_cache,
1075 cached_canonical,
1076 };
1077 Ok((tx, decoder.finish()?))
1078 }
1079}
1080
1081impl RLPDecode for FeeTokenTransaction {
1082 fn decode_unfinished(rlp: &[u8]) -> Result<(FeeTokenTransaction, &[u8]), RLPDecodeError> {
1083 let decoder = Decoder::new(rlp)?;
1084 let (chain_id, decoder) = decoder.decode_field("chain_id")?;
1085 let (nonce, decoder) = decoder.decode_field("nonce")?;
1086 let (max_priority_fee_per_gas, decoder) =
1087 decoder.decode_field("max_priority_fee_per_gas")?;
1088 let (max_fee_per_gas, decoder) = decoder.decode_field("max_fee_per_gas")?;
1089 let (gas_limit, decoder) = decoder.decode_field("gas_limit")?;
1090 let (to, decoder) = decoder.decode_field("to")?;
1091 let (value, decoder) = decoder.decode_field("value")?;
1092 let (data, decoder) = decoder.decode_field("data")?;
1093 let (access_list, decoder) = decoder.decode_field("access_list")?;
1094 let (fee_token, decoder) = decoder.decode_field("fee_token")?;
1095 let (signature_y_parity, decoder) = decoder.decode_field("signature_y_parity")?;
1096 let (signature_r, decoder) = decoder.decode_field("signature_r")?;
1097 let (signature_s, decoder) = decoder.decode_field("signature_s")?;
1098 let inner_hash = OnceCell::new();
1099 let sender_cache = OnceCell::new();
1100 let cached_canonical = OnceCell::new();
1101
1102 let tx = FeeTokenTransaction {
1103 chain_id,
1104 nonce,
1105 max_priority_fee_per_gas,
1106 max_fee_per_gas,
1107 gas_limit,
1108 to,
1109 value,
1110 data,
1111 access_list,
1112 fee_token,
1113 signature_y_parity,
1114 signature_r,
1115 signature_s,
1116 inner_hash,
1117 sender_cache,
1118 cached_canonical,
1119 };
1120 Ok((tx, decoder.finish()?))
1121 }
1122}
1123
1124impl Transaction {
1125 pub fn sender(&self, crypto: &dyn Crypto) -> Result<Address, CryptoError> {
1126 let sender_cache = match self {
1127 Transaction::LegacyTransaction(tx) => &tx.sender_cache,
1128 Transaction::EIP2930Transaction(tx) => &tx.sender_cache,
1129 Transaction::EIP1559Transaction(tx) => &tx.sender_cache,
1130 Transaction::EIP4844Transaction(tx) => &tx.sender_cache,
1131 Transaction::EIP7702Transaction(tx) => &tx.sender_cache,
1132 Transaction::PrivilegedL2Transaction(tx) => &tx.sender_cache,
1133 Transaction::FeeTokenTransaction(tx) => &tx.sender_cache,
1134 };
1135 sender_cache
1136 .get_or_try_init(|| {
1137 let tx_hash = self.hash();
1138 let mut cache = GLOBAL_SIGNER_CACHE
1140 .lock()
1141 .unwrap_or_else(|e| e.into_inner());
1142 if let Some(&addr) = cache.get(&tx_hash) {
1143 return Ok(addr);
1144 }
1145 drop(cache);
1146 let sender = self.compute_sender(crypto)?;
1148 GLOBAL_SIGNER_CACHE
1150 .lock()
1151 .unwrap_or_else(|e| e.into_inner())
1152 .put(tx_hash, sender);
1153 Ok(sender)
1154 })
1155 .copied()
1156 }
1157
1158 fn compute_sender(&self, crypto: &dyn Crypto) -> Result<Address, CryptoError> {
1159 let (buf, sig) = match self {
1160 Transaction::LegacyTransaction(tx) => {
1161 let v = u64::try_from(tx.v).map_err(|_| CryptoError::InvalidSignature)?;
1162 let signature_y_parity = match self.chain_id() {
1163 Some(chain_id) => v.saturating_sub(35 + chain_id * 2) != 0,
1164 None => v.saturating_sub(27) != 0,
1165 };
1166 let mut buf = vec![];
1167 match self.chain_id() {
1168 None => Encoder::new(&mut buf)
1169 .encode_field(&tx.nonce)
1170 .encode_field(&tx.gas_price)
1171 .encode_field(&tx.gas)
1172 .encode_field(&tx.to)
1173 .encode_field(&tx.value)
1174 .encode_field(&tx.data)
1175 .finish(),
1176 Some(chain_id) => Encoder::new(&mut buf)
1177 .encode_field(&tx.nonce)
1178 .encode_field(&tx.gas_price)
1179 .encode_field(&tx.gas)
1180 .encode_field(&tx.to)
1181 .encode_field(&tx.value)
1182 .encode_field(&tx.data)
1183 .encode_field(&chain_id)
1184 .encode_field(&0u8)
1185 .encode_field(&0u8)
1186 .finish(),
1187 }
1188 let mut sig = [0u8; 65];
1189 sig[..32].copy_from_slice(&tx.r.to_big_endian());
1190 sig[32..64].copy_from_slice(&tx.s.to_big_endian());
1191 sig[64] = signature_y_parity as u8;
1192 (buf, sig)
1193 }
1194 Transaction::EIP2930Transaction(tx) => {
1195 let mut buf = vec![self.tx_type() as u8];
1196 Encoder::new(&mut buf)
1197 .encode_field(&tx.chain_id)
1198 .encode_field(&tx.nonce)
1199 .encode_field(&tx.gas_price)
1200 .encode_field(&tx.gas_limit)
1201 .encode_field(&tx.to)
1202 .encode_field(&tx.value)
1203 .encode_field(&tx.data)
1204 .encode_field(&tx.access_list)
1205 .finish();
1206 let mut sig = [0u8; 65];
1207 sig[..32].copy_from_slice(&tx.signature_r.to_big_endian());
1208 sig[32..64].copy_from_slice(&tx.signature_s.to_big_endian());
1209 sig[64] = tx.signature_y_parity as u8;
1210 (buf, sig)
1211 }
1212 Transaction::EIP1559Transaction(tx) => {
1213 let mut buf = vec![self.tx_type() as u8];
1214 Encoder::new(&mut buf)
1215 .encode_field(&tx.chain_id)
1216 .encode_field(&tx.nonce)
1217 .encode_field(&tx.max_priority_fee_per_gas)
1218 .encode_field(&tx.max_fee_per_gas)
1219 .encode_field(&tx.gas_limit)
1220 .encode_field(&tx.to)
1221 .encode_field(&tx.value)
1222 .encode_field(&tx.data)
1223 .encode_field(&tx.access_list)
1224 .finish();
1225 let mut sig = [0u8; 65];
1226 sig[..32].copy_from_slice(&tx.signature_r.to_big_endian());
1227 sig[32..64].copy_from_slice(&tx.signature_s.to_big_endian());
1228 sig[64] = tx.signature_y_parity as u8;
1229 (buf, sig)
1230 }
1231 Transaction::EIP4844Transaction(tx) => {
1232 let mut buf = vec![self.tx_type() as u8];
1233 Encoder::new(&mut buf)
1234 .encode_field(&tx.chain_id)
1235 .encode_field(&tx.nonce)
1236 .encode_field(&tx.max_priority_fee_per_gas)
1237 .encode_field(&tx.max_fee_per_gas)
1238 .encode_field(&tx.gas)
1239 .encode_field(&tx.to)
1240 .encode_field(&tx.value)
1241 .encode_field(&tx.data)
1242 .encode_field(&tx.access_list)
1243 .encode_field(&tx.max_fee_per_blob_gas)
1244 .encode_field(&tx.blob_versioned_hashes)
1245 .finish();
1246 let mut sig = [0u8; 65];
1247 sig[..32].copy_from_slice(&tx.signature_r.to_big_endian());
1248 sig[32..64].copy_from_slice(&tx.signature_s.to_big_endian());
1249 sig[64] = tx.signature_y_parity as u8;
1250 (buf, sig)
1251 }
1252 Transaction::EIP7702Transaction(tx) => {
1253 let mut buf = vec![self.tx_type() as u8];
1254 Encoder::new(&mut buf)
1255 .encode_field(&tx.chain_id)
1256 .encode_field(&tx.nonce)
1257 .encode_field(&tx.max_priority_fee_per_gas)
1258 .encode_field(&tx.max_fee_per_gas)
1259 .encode_field(&tx.gas_limit)
1260 .encode_field(&tx.to)
1261 .encode_field(&tx.value)
1262 .encode_field(&tx.data)
1263 .encode_field(&tx.access_list)
1264 .encode_field(&tx.authorization_list)
1265 .finish();
1266 let mut sig = [0u8; 65];
1267 sig[..32].copy_from_slice(&tx.signature_r.to_big_endian());
1268 sig[32..64].copy_from_slice(&tx.signature_s.to_big_endian());
1269 sig[64] = tx.signature_y_parity as u8;
1270 (buf, sig)
1271 }
1272 Transaction::PrivilegedL2Transaction(tx) => return Ok(tx.from),
1273 Transaction::FeeTokenTransaction(tx) => {
1274 let mut buf = vec![self.tx_type() as u8];
1275 Encoder::new(&mut buf)
1276 .encode_field(&tx.chain_id)
1277 .encode_field(&tx.nonce)
1278 .encode_field(&tx.max_priority_fee_per_gas)
1279 .encode_field(&tx.max_fee_per_gas)
1280 .encode_field(&tx.gas_limit)
1281 .encode_field(&tx.to)
1282 .encode_field(&tx.value)
1283 .encode_field(&tx.data)
1284 .encode_field(&tx.access_list)
1285 .encode_field(&tx.fee_token)
1286 .finish();
1287 let mut sig = [0u8; 65];
1288 sig[..32].copy_from_slice(&tx.signature_r.to_big_endian());
1289 sig[32..64].copy_from_slice(&tx.signature_s.to_big_endian());
1290 sig[64] = tx.signature_y_parity as u8;
1291 (buf, sig)
1292 }
1293 };
1294 let msg = keccak(&buf).to_fixed_bytes();
1295 crypto.recover_signer(&sig, &msg)
1296 }
1297
1298 pub fn gas_limit(&self) -> u64 {
1299 match self {
1300 Transaction::LegacyTransaction(tx) => tx.gas,
1301 Transaction::EIP2930Transaction(tx) => tx.gas_limit,
1302 Transaction::EIP1559Transaction(tx) => tx.gas_limit,
1303 Transaction::EIP7702Transaction(tx) => tx.gas_limit,
1304 Transaction::EIP4844Transaction(tx) => tx.gas,
1305 Transaction::PrivilegedL2Transaction(tx) => tx.gas_limit,
1306 Transaction::FeeTokenTransaction(tx) => tx.gas_limit,
1307 }
1308 }
1309
1310 pub fn gas_price(&self) -> U256 {
1312 match self {
1313 Transaction::LegacyTransaction(tx) => tx.gas_price,
1314 Transaction::EIP2930Transaction(tx) => tx.gas_price,
1315 Transaction::EIP1559Transaction(tx) => U256::from(tx.max_fee_per_gas),
1316 Transaction::EIP7702Transaction(tx) => U256::from(tx.max_fee_per_gas),
1317 Transaction::EIP4844Transaction(tx) => U256::from(tx.max_fee_per_gas),
1318 Transaction::PrivilegedL2Transaction(tx) => U256::from(tx.max_fee_per_gas),
1319 Transaction::FeeTokenTransaction(tx) => U256::from(tx.max_fee_per_gas),
1320 }
1321 }
1322
1323 pub fn to(&self) -> TxKind {
1324 match self {
1325 Transaction::LegacyTransaction(tx) => tx.to.clone(),
1326 Transaction::EIP2930Transaction(tx) => tx.to.clone(),
1327 Transaction::EIP1559Transaction(tx) => tx.to.clone(),
1328 Transaction::EIP4844Transaction(tx) => TxKind::Call(tx.to),
1329 Transaction::EIP7702Transaction(tx) => TxKind::Call(tx.to),
1330 Transaction::PrivilegedL2Transaction(tx) => tx.to.clone(),
1331 Transaction::FeeTokenTransaction(tx) => tx.to.clone(),
1332 }
1333 }
1334
1335 pub fn value(&self) -> U256 {
1336 match self {
1337 Transaction::LegacyTransaction(tx) => tx.value,
1338 Transaction::EIP2930Transaction(tx) => tx.value,
1339 Transaction::EIP1559Transaction(tx) => tx.value,
1340 Transaction::EIP4844Transaction(tx) => tx.value,
1341 Transaction::EIP7702Transaction(tx) => tx.value,
1342 Transaction::PrivilegedL2Transaction(tx) => tx.value,
1343 Transaction::FeeTokenTransaction(tx) => tx.value,
1344 }
1345 }
1346
1347 pub fn max_priority_fee(&self) -> Option<u64> {
1348 match self {
1349 Transaction::LegacyTransaction(_tx) => None,
1350 Transaction::EIP2930Transaction(_tx) => None,
1351 Transaction::EIP1559Transaction(tx) => Some(tx.max_priority_fee_per_gas),
1352 Transaction::EIP4844Transaction(tx) => Some(tx.max_priority_fee_per_gas),
1353 Transaction::EIP7702Transaction(tx) => Some(tx.max_priority_fee_per_gas),
1354 Transaction::PrivilegedL2Transaction(tx) => Some(tx.max_priority_fee_per_gas),
1355 Transaction::FeeTokenTransaction(tx) => Some(tx.max_priority_fee_per_gas),
1356 }
1357 }
1358
1359 pub fn chain_id(&self) -> Option<u64> {
1360 match self {
1361 Transaction::LegacyTransaction(tx) => derive_legacy_chain_id(tx.v),
1362 Transaction::EIP2930Transaction(tx) => Some(tx.chain_id),
1363 Transaction::EIP1559Transaction(tx) => Some(tx.chain_id),
1364 Transaction::EIP4844Transaction(tx) => Some(tx.chain_id),
1365 Transaction::EIP7702Transaction(tx) => Some(tx.chain_id),
1366 Transaction::PrivilegedL2Transaction(tx) => Some(tx.chain_id),
1367 Transaction::FeeTokenTransaction(tx) => Some(tx.chain_id),
1368 }
1369 }
1370
1371 pub fn access_list(&self) -> &AccessList {
1372 static EMPTY_ACCESS_LIST: AccessList = Vec::new();
1373 match self {
1374 Transaction::LegacyTransaction(_tx) => &EMPTY_ACCESS_LIST,
1375 Transaction::EIP2930Transaction(tx) => &tx.access_list,
1376 Transaction::EIP1559Transaction(tx) => &tx.access_list,
1377 Transaction::EIP4844Transaction(tx) => &tx.access_list,
1378 Transaction::EIP7702Transaction(tx) => &tx.access_list,
1379 Transaction::PrivilegedL2Transaction(tx) => &tx.access_list,
1380 Transaction::FeeTokenTransaction(tx) => &tx.access_list,
1381 }
1382 }
1383 pub fn authorization_list(&self) -> Option<&AuthorizationList> {
1384 match self {
1385 Transaction::LegacyTransaction(_) => None,
1386 Transaction::EIP2930Transaction(_) => None,
1387 Transaction::EIP1559Transaction(_) => None,
1388 Transaction::EIP4844Transaction(_) => None,
1389 Transaction::EIP7702Transaction(tx) => Some(&tx.authorization_list),
1390 Transaction::PrivilegedL2Transaction(_) => None,
1391 Transaction::FeeTokenTransaction(_) => None,
1392 }
1393 }
1394
1395 pub fn nonce(&self) -> u64 {
1396 match self {
1397 Transaction::LegacyTransaction(tx) => tx.nonce,
1398 Transaction::EIP2930Transaction(tx) => tx.nonce,
1399 Transaction::EIP1559Transaction(tx) => tx.nonce,
1400 Transaction::EIP4844Transaction(tx) => tx.nonce,
1401 Transaction::EIP7702Transaction(tx) => tx.nonce,
1402 Transaction::PrivilegedL2Transaction(tx) => tx.nonce,
1403 Transaction::FeeTokenTransaction(tx) => tx.nonce,
1404 }
1405 }
1406
1407 pub fn data(&self) -> &Bytes {
1408 match self {
1409 Transaction::LegacyTransaction(tx) => &tx.data,
1410 Transaction::EIP2930Transaction(tx) => &tx.data,
1411 Transaction::EIP1559Transaction(tx) => &tx.data,
1412 Transaction::EIP4844Transaction(tx) => &tx.data,
1413 Transaction::EIP7702Transaction(tx) => &tx.data,
1414 Transaction::PrivilegedL2Transaction(tx) => &tx.data,
1415 Transaction::FeeTokenTransaction(tx) => &tx.data,
1416 }
1417 }
1418
1419 pub fn blob_versioned_hashes(&self) -> Vec<H256> {
1420 match self {
1421 Transaction::LegacyTransaction(_) => Vec::new(),
1422 Transaction::EIP2930Transaction(_) => Vec::new(),
1423 Transaction::EIP1559Transaction(_) => Vec::new(),
1424 Transaction::EIP4844Transaction(tx) => tx.blob_versioned_hashes.clone(),
1425 Transaction::EIP7702Transaction(_) => Vec::new(),
1426 Transaction::PrivilegedL2Transaction(_) => Vec::new(),
1427 Transaction::FeeTokenTransaction(_) => Vec::new(),
1428 }
1429 }
1430
1431 pub fn max_fee_per_blob_gas(&self) -> Option<U256> {
1432 match self {
1433 Transaction::LegacyTransaction(_) => None,
1434 Transaction::EIP2930Transaction(_) => None,
1435 Transaction::EIP1559Transaction(_) => None,
1436 Transaction::EIP4844Transaction(tx) => Some(tx.max_fee_per_blob_gas),
1437 Transaction::EIP7702Transaction(_) => None,
1438 Transaction::PrivilegedL2Transaction(_) => None,
1439 Transaction::FeeTokenTransaction(_) => None,
1440 }
1441 }
1442
1443 pub fn is_contract_creation(&self) -> bool {
1444 match &self {
1445 Transaction::LegacyTransaction(t) => matches!(t.to, TxKind::Create),
1446 Transaction::EIP2930Transaction(t) => matches!(t.to, TxKind::Create),
1447 Transaction::EIP1559Transaction(t) => matches!(t.to, TxKind::Create),
1448 Transaction::EIP4844Transaction(_) => false,
1449 Transaction::EIP7702Transaction(_) => false,
1450 Transaction::PrivilegedL2Transaction(t) => matches!(t.to, TxKind::Create),
1451 Transaction::FeeTokenTransaction(t) => matches!(t.to, TxKind::Create),
1452 }
1453 }
1454
1455 pub fn is_privileged(&self) -> bool {
1456 matches!(self, Transaction::PrivilegedL2Transaction(_))
1457 }
1458
1459 pub fn max_fee_per_gas(&self) -> Option<u64> {
1460 match self {
1461 Transaction::LegacyTransaction(_tx) => None,
1462 Transaction::EIP2930Transaction(_tx) => None,
1463 Transaction::EIP1559Transaction(tx) => Some(tx.max_fee_per_gas),
1464 Transaction::EIP4844Transaction(tx) => Some(tx.max_fee_per_gas),
1465 Transaction::EIP7702Transaction(tx) => Some(tx.max_fee_per_gas),
1466 Transaction::PrivilegedL2Transaction(tx) => Some(tx.max_fee_per_gas),
1467 Transaction::FeeTokenTransaction(tx) => Some(tx.max_fee_per_gas),
1468 }
1469 }
1470
1471 fn compute_hash(&self) -> H256 {
1472 if let Transaction::PrivilegedL2Transaction(tx) = self {
1473 return tx.get_privileged_hash().unwrap_or_default();
1474 }
1475 crate::utils::keccak(self.encode_canonical_to_vec())
1476 }
1477
1478 pub fn hash(&self) -> H256 {
1479 let inner_hash = match self {
1480 Transaction::LegacyTransaction(tx) => &tx.inner_hash,
1481 Transaction::EIP2930Transaction(tx) => &tx.inner_hash,
1482 Transaction::EIP1559Transaction(tx) => &tx.inner_hash,
1483 Transaction::EIP4844Transaction(tx) => &tx.inner_hash,
1484 Transaction::EIP7702Transaction(tx) => &tx.inner_hash,
1485 Transaction::PrivilegedL2Transaction(tx) => &tx.inner_hash,
1486 Transaction::FeeTokenTransaction(tx) => &tx.inner_hash,
1487 };
1488
1489 *inner_hash.get_or_init(|| self.compute_hash())
1490 }
1491
1492 pub fn gas_tip_cap(&self) -> U256 {
1493 self.max_priority_fee()
1494 .map(U256::from)
1495 .unwrap_or_else(|| self.gas_price())
1496 }
1497
1498 pub fn gas_fee_cap(&self) -> U256 {
1499 self.max_fee_per_gas()
1500 .map(U256::from)
1501 .unwrap_or_else(|| self.gas_price())
1502 }
1503
1504 pub fn effective_gas_tip(&self, base_fee: Option<u64>) -> Option<U256> {
1508 let tip_cap = self.gas_tip_cap();
1509 let Some(base_fee) = base_fee else {
1510 return Some(tip_cap);
1511 };
1512 let base_fee = U256::from(base_fee);
1513 let fee_cap = self.gas_fee_cap();
1514 let tip = fee_cap.checked_sub(base_fee)?;
1515 Some(min(tip, tip_cap))
1516 }
1517
1518 pub fn protected(&self) -> bool {
1521 match self {
1522 Transaction::LegacyTransaction(tx) if tx.v.bits() <= 8 => {
1523 let v = tx.v.low_u64();
1524 v != 27 && v != 28 && v != 1 && v != 0
1525 }
1526 _ => true,
1527 }
1528 }
1529}
1530
1531fn derive_legacy_chain_id(v: U256) -> Option<u64> {
1532 let v = u64::try_from(v).ok()?;
1533 if v < 35 { None } else { Some((v - 35) / 2) }
1538}
1539
1540impl TxType {
1541 pub fn from_u8(value: u8) -> Option<Self> {
1542 match value {
1543 0x00 => Some(Self::Legacy),
1544 0x01 => Some(Self::EIP2930),
1545 0x02 => Some(Self::EIP1559),
1546 0x03 => Some(Self::EIP4844),
1547 0x04 => Some(Self::EIP7702),
1548 0x7d => Some(Self::FeeToken),
1549 0x7e => Some(Self::Privileged),
1550 _ => None,
1551 }
1552 }
1553
1554 pub fn is_l2_only(self) -> bool {
1562 match self {
1563 Self::Legacy | Self::EIP2930 | Self::EIP1559 | Self::EIP4844 | Self::EIP7702 => false,
1564 Self::FeeToken | Self::Privileged => true,
1565 }
1566 }
1567}
1568
1569impl PrivilegedL2Transaction {
1570 pub fn get_privileged_hash(&self) -> Option<H256> {
1574 let to = match self.to {
1576 TxKind::Call(to) => to,
1577 _ => return None,
1578 };
1579
1580 let value = self.value.to_big_endian();
1581
1582 let u256_nonce = U256::from(self.nonce);
1585 let nonce = u256_nonce.to_big_endian();
1586
1587 Some(crate::utils::keccak(
1588 [
1589 U256::from(self.chain_id).to_big_endian().as_ref(),
1590 self.from.as_bytes(),
1591 to.as_bytes(),
1592 &nonce,
1593 &value,
1594 &U256::from(self.gas_limit).to_big_endian(),
1595 keccak(&self.data).as_bytes(),
1596 ]
1597 .concat(),
1598 ))
1599 }
1600}
1601
1602#[derive(Clone, Debug, PartialEq, Eq, Default, RSerialize, RDeserialize, Archive)]
1603pub struct FeeTokenTransaction {
1604 pub chain_id: u64,
1605 pub nonce: u64,
1606 pub max_priority_fee_per_gas: u64,
1607 pub max_fee_per_gas: u64,
1608 pub gas_limit: u64,
1609 pub to: TxKind,
1610 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
1611 pub value: U256,
1612 #[rkyv(with=crate::rkyv_utils::BytesWrapper)]
1613 pub data: Bytes,
1614 #[rkyv(with=rkyv::with::Map<crate::rkyv_utils::AccessListItemWrapper>)]
1615 pub access_list: AccessList,
1616 #[rkyv(with=crate::rkyv_utils::H160Wrapper)]
1617 pub fee_token: Address,
1618 pub signature_y_parity: bool,
1619 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
1620 pub signature_r: U256,
1621 #[rkyv(with=crate::rkyv_utils::U256Wrapper)]
1622 pub signature_s: U256,
1623 #[rkyv(with=rkyv::with::Skip)]
1624 pub inner_hash: OnceCell<H256>,
1625 #[rkyv(with=rkyv::with::Skip)]
1626 pub sender_cache: OnceCell<Address>,
1627 #[rkyv(with=rkyv::with::Skip)]
1628 pub cached_canonical: OnceCell<Vec<u8>>,
1629}
1630
1631mod canonic_encoding {
1637 use super::*;
1638
1639 impl Transaction {
1640 pub fn decode_canonical(bytes: &[u8]) -> Result<Self, RLPDecodeError> {
1646 match bytes.first() {
1648 Some(tx_type) if *tx_type < 0x7f => {
1650 let tx_bytes = &bytes[1..];
1652 match *tx_type {
1653 0x0 => {
1655 LegacyTransaction::decode(tx_bytes).map(Transaction::LegacyTransaction)
1656 } 0x1 => EIP2930Transaction::decode(tx_bytes)
1659 .map(Transaction::EIP2930Transaction),
1660 0x2 => EIP1559Transaction::decode(tx_bytes)
1662 .map(Transaction::EIP1559Transaction),
1663 0x3 => EIP4844Transaction::decode(tx_bytes)
1665 .map(Transaction::EIP4844Transaction),
1666 0x4 => EIP7702Transaction::decode(tx_bytes)
1668 .map(Transaction::EIP7702Transaction),
1669 0x7d => FeeTokenTransaction::decode(tx_bytes)
1671 .map(Transaction::FeeTokenTransaction),
1672 0x7e => PrivilegedL2Transaction::decode(tx_bytes)
1674 .map(Transaction::PrivilegedL2Transaction),
1675 ty => Err(RLPDecodeError::Custom(format!(
1676 "Invalid transaction type: {ty}"
1677 ))),
1678 }
1679 }
1680 _ => LegacyTransaction::decode(bytes).map(Transaction::LegacyTransaction),
1682 }
1683 }
1684
1685 pub fn encode_canonical(&self, buf: &mut dyn bytes::BufMut) {
1691 match self {
1692 Transaction::LegacyTransaction(_) => {}
1694 _ => buf.put_u8(self.tx_type() as u8),
1695 }
1696 match self {
1697 Transaction::LegacyTransaction(t) => t.encode(buf),
1698 Transaction::EIP2930Transaction(t) => t.encode(buf),
1699 Transaction::EIP1559Transaction(t) => t.encode(buf),
1700 Transaction::EIP4844Transaction(t) => t.encode(buf),
1701 Transaction::EIP7702Transaction(t) => t.encode(buf),
1702 Transaction::FeeTokenTransaction(t) => t.encode(buf),
1703 Transaction::PrivilegedL2Transaction(t) => t.encode(buf),
1704 };
1705 }
1706
1707 pub fn encode_canonical_to_vec(&self) -> Vec<u8> {
1713 if let Some(cell) = self.cached_canonical_cell() {
1714 return cell
1715 .get_or_init(|| {
1716 let mut buf = Vec::new();
1717 self.encode_canonical(&mut buf);
1718 buf
1719 })
1720 .clone();
1721 }
1722 let mut buf = Vec::new();
1723 self.encode_canonical(&mut buf);
1724 buf
1725 }
1726
1727 pub fn encode_canonical_len(&self) -> usize {
1732 let prefix_len = match self {
1733 Transaction::LegacyTransaction(_) => 0,
1734 _ => 1,
1735 };
1736 let inner_len = match self {
1737 Transaction::LegacyTransaction(t) => t.length(),
1738 Transaction::EIP2930Transaction(t) => t.length(),
1739 Transaction::EIP1559Transaction(t) => t.length(),
1740 Transaction::EIP4844Transaction(t) => t.length(),
1741 Transaction::EIP7702Transaction(t) => t.length(),
1742 Transaction::FeeTokenTransaction(t) => t.length(),
1743 Transaction::PrivilegedL2Transaction(t) => t.length(),
1744 };
1745 prefix_len + inner_len
1746 }
1747 }
1748
1749 impl P2PTransaction {
1750 pub fn tx_type(&self) -> TxType {
1751 match self {
1752 P2PTransaction::LegacyTransaction(_) => TxType::Legacy,
1753 P2PTransaction::EIP2930Transaction(_) => TxType::EIP2930,
1754 P2PTransaction::EIP1559Transaction(_) => TxType::EIP1559,
1755 P2PTransaction::EIP4844TransactionWithBlobs(_) => TxType::EIP4844,
1756 P2PTransaction::EIP7702Transaction(_) => TxType::EIP7702,
1757 P2PTransaction::FeeTokenTransaction(_) => TxType::FeeToken,
1758 }
1759 }
1760
1761 pub fn encode_canonical(&self, buf: &mut dyn bytes::BufMut) {
1762 match self {
1763 P2PTransaction::LegacyTransaction(_) => {}
1765 _ => buf.put_u8(self.tx_type() as u8),
1766 }
1767 match self {
1768 P2PTransaction::LegacyTransaction(t) => t.encode(buf),
1769 P2PTransaction::EIP2930Transaction(t) => t.encode(buf),
1770 P2PTransaction::EIP1559Transaction(t) => t.encode(buf),
1771 P2PTransaction::EIP4844TransactionWithBlobs(t) => t.encode(buf),
1772 P2PTransaction::EIP7702Transaction(t) => t.encode(buf),
1773 P2PTransaction::FeeTokenTransaction(t) => t.encode(buf),
1774 };
1775 }
1776
1777 pub fn encode_canonical_to_vec(&self) -> Vec<u8> {
1778 let mut buf = Vec::new();
1779 self.encode_canonical(&mut buf);
1780 buf
1781 }
1782
1783 pub fn compute_hash(&self) -> H256 {
1784 match self {
1785 P2PTransaction::LegacyTransaction(t) => {
1786 Transaction::LegacyTransaction(t.clone()).compute_hash()
1787 }
1788 P2PTransaction::EIP2930Transaction(t) => {
1789 Transaction::EIP2930Transaction(t.clone()).compute_hash()
1790 }
1791 P2PTransaction::EIP1559Transaction(t) => {
1792 Transaction::EIP1559Transaction(t.clone()).compute_hash()
1793 }
1794 P2PTransaction::EIP4844TransactionWithBlobs(t) => {
1795 Transaction::EIP4844Transaction(t.tx.clone()).compute_hash()
1796 }
1797 P2PTransaction::EIP7702Transaction(t) => {
1798 Transaction::EIP7702Transaction(t.clone()).compute_hash()
1799 }
1800 P2PTransaction::FeeTokenTransaction(t) => {
1801 Transaction::FeeTokenTransaction(t.clone()).compute_hash()
1802 }
1803 }
1804 }
1805 }
1806}
1807
1808mod serde_impl {
1812 use ethereum_types::H160;
1813 use serde::Deserialize;
1814 use serde::{Deserializer, de::Error};
1815 use serde_json::Value;
1816 use std::{collections::HashMap, str::FromStr};
1817
1818 #[cfg(feature = "c-kzg")]
1819 use crate::types::BYTES_PER_BLOB;
1820 use crate::types::{AccessListItem, AuthorizationTuple, BlobsBundleError};
1821
1822 use super::*;
1823
1824 impl Serialize for TxKind {
1825 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1826 where
1827 S: serde::Serializer,
1828 {
1829 match self {
1830 TxKind::Call(address) => serializer.serialize_str(&format!("{address:#x}")),
1831 TxKind::Create => serializer.serialize_none(),
1832 }
1833 }
1834 }
1835
1836 impl<'de> Deserialize<'de> for TxKind {
1837 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1838 where
1839 D: serde::Deserializer<'de>,
1840 {
1841 let str_option = Option::<String>::deserialize(deserializer)?;
1842 match str_option {
1843 Some(str) if !str.is_empty() => Ok(TxKind::Call(
1844 Address::from_str(str.trim_start_matches("0x")).map_err(|_| {
1845 serde::de::Error::custom(format!("Failed to deserialize hex value {str}"))
1846 })?,
1847 )),
1848 _ => Ok(TxKind::Create),
1849 }
1850 }
1851 }
1852
1853 impl Serialize for TxType {
1854 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1855 where
1856 S: serde::Serializer,
1857 {
1858 serializer.serialize_str(&format!("{:#x}", *self as u8))
1859 }
1860 }
1861
1862 impl<'de> Deserialize<'de> for TxType {
1863 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1864 where
1865 D: serde::Deserializer<'de>,
1866 {
1867 let str = String::deserialize(deserializer)?;
1868 let tx_num = u8::from_str_radix(str.trim_start_matches("0x"), 16).map_err(|_| {
1869 serde::de::Error::custom(format!("Failed to deserialize hex value {str}"))
1870 })?;
1871 TxType::from_u8(tx_num).ok_or_else(|| {
1872 serde::de::Error::custom(format!("Invalid transaction type {tx_num}"))
1873 })
1874 }
1875 }
1876
1877 #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
1878 #[serde(rename_all = "camelCase")]
1879 pub struct AccessListEntry {
1880 pub address: Address,
1881 pub storage_keys: Vec<H256>,
1882 }
1883
1884 impl From<&AccessListItem> for AccessListEntry {
1885 fn from(value: &AccessListItem) -> AccessListEntry {
1886 AccessListEntry {
1887 address: value.0,
1888 storage_keys: value.1.clone(),
1889 }
1890 }
1891 }
1892
1893 #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
1894 #[serde(rename_all = "camelCase")]
1895 pub struct AuthorizationTupleEntry {
1896 pub chain_id: U256,
1897 pub address: Address,
1898 #[serde(default, with = "crate::serde_utils::u64::hex_str")]
1899 pub nonce: u64,
1900 pub y_parity: U256,
1901 pub r: U256,
1902 pub s: U256,
1903 }
1904
1905 impl From<&AuthorizationTuple> for AuthorizationTupleEntry {
1906 fn from(value: &AuthorizationTuple) -> AuthorizationTupleEntry {
1907 AuthorizationTupleEntry {
1908 chain_id: value.chain_id,
1909 address: value.address,
1910 nonce: value.nonce,
1911 y_parity: value.y_parity,
1912 r: value.r_signature,
1913 s: value.s_signature,
1914 }
1915 }
1916 }
1917
1918 impl From<AuthorizationTupleEntry> for AuthorizationTuple {
1919 fn from(entry: AuthorizationTupleEntry) -> AuthorizationTuple {
1920 AuthorizationTuple {
1921 chain_id: entry.chain_id,
1922 address: entry.address,
1923 nonce: entry.nonce,
1924 y_parity: entry.y_parity,
1925 r_signature: entry.r,
1926 s_signature: entry.s,
1927 }
1928 }
1929 }
1930
1931 impl Serialize for LegacyTransaction {
1932 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1933 where
1934 S: serde::Serializer,
1935 {
1936 let mut struct_serializer = serializer.serialize_struct("LegacyTransaction", 11)?;
1937 struct_serializer.serialize_field("type", &TxType::Legacy)?;
1938 struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?;
1939 struct_serializer.serialize_field("to", &self.to)?;
1940 struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas))?;
1941 struct_serializer.serialize_field("value", &self.value)?;
1942 struct_serializer.serialize_field("input", &format!("0x{:x}", self.data))?;
1943 struct_serializer.serialize_field("gasPrice", &format!("{:#x}", self.gas_price))?;
1944 struct_serializer.serialize_field(
1945 "chainId",
1946 &format!("{:#x}", derive_legacy_chain_id(self.v).unwrap_or_default()),
1947 )?;
1948 struct_serializer.serialize_field("v", &self.v)?;
1949 struct_serializer.serialize_field("r", &self.r)?;
1950 struct_serializer.serialize_field("s", &self.s)?;
1951 struct_serializer.end()
1952 }
1953 }
1954
1955 impl Serialize for EIP2930Transaction {
1956 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1957 where
1958 S: serde::Serializer,
1959 {
1960 let mut struct_serializer = serializer.serialize_struct("Eip2930Transaction", 12)?;
1961 struct_serializer.serialize_field("type", &TxType::EIP2930)?;
1962 struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?;
1963 struct_serializer.serialize_field("to", &self.to)?;
1964 struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas_limit))?;
1965 struct_serializer.serialize_field("value", &self.value)?;
1966 struct_serializer.serialize_field("input", &format!("0x{:x}", self.data))?;
1967 struct_serializer.serialize_field("gasPrice", &format!("{:#x}", self.gas_price))?;
1968 struct_serializer.serialize_field(
1969 "accessList",
1970 &self
1971 .access_list
1972 .iter()
1973 .map(AccessListEntry::from)
1974 .collect::<Vec<_>>(),
1975 )?;
1976 struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?;
1977 struct_serializer
1978 .serialize_field("yParity", &format!("{:#x}", self.signature_y_parity as u8))?;
1979 struct_serializer
1980 .serialize_field("v", &format!("{:#x}", self.signature_y_parity as u8))?; struct_serializer.serialize_field("r", &self.signature_r)?;
1982 struct_serializer.serialize_field("s", &self.signature_s)?;
1983 struct_serializer.end()
1984 }
1985 }
1986
1987 impl Serialize for EIP1559Transaction {
1988 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1989 where
1990 S: serde::Serializer,
1991 {
1992 let mut struct_serializer = serializer.serialize_struct("Eip1559Transaction", 14)?;
1993 struct_serializer.serialize_field("type", &TxType::EIP1559)?;
1994 struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?;
1995 struct_serializer.serialize_field("to", &self.to)?;
1996 struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas_limit))?;
1997 struct_serializer.serialize_field("value", &self.value)?;
1998 struct_serializer.serialize_field("input", &format!("0x{:x}", self.data))?;
1999 struct_serializer.serialize_field(
2000 "maxPriorityFeePerGas",
2001 &format!("{:#x}", self.max_priority_fee_per_gas),
2002 )?;
2003 struct_serializer
2004 .serialize_field("maxFeePerGas", &format!("{:#x}", self.max_fee_per_gas))?;
2005 struct_serializer
2006 .serialize_field("gasPrice", &format!("{:#x}", self.max_fee_per_gas))?;
2007 struct_serializer.serialize_field(
2008 "accessList",
2009 &self
2010 .access_list
2011 .iter()
2012 .map(AccessListEntry::from)
2013 .collect::<Vec<_>>(),
2014 )?;
2015 struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?;
2016 struct_serializer
2017 .serialize_field("yParity", &format!("{:#x}", self.signature_y_parity as u8))?;
2018 struct_serializer
2019 .serialize_field("v", &format!("{:#x}", self.signature_y_parity as u8))?; struct_serializer.serialize_field("r", &self.signature_r)?;
2021 struct_serializer.serialize_field("s", &self.signature_s)?;
2022 struct_serializer.end()
2023 }
2024 }
2025
2026 impl Serialize for EIP4844Transaction {
2027 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2028 where
2029 S: serde::Serializer,
2030 {
2031 let mut struct_serializer = serializer.serialize_struct("Eip4844Transaction", 15)?;
2032 struct_serializer.serialize_field("type", &TxType::EIP4844)?;
2033 struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?;
2034 struct_serializer.serialize_field("to", &self.to)?;
2035 struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas))?;
2036 struct_serializer.serialize_field("value", &self.value)?;
2037 struct_serializer.serialize_field("input", &format!("0x{:x}", self.data))?;
2038 struct_serializer.serialize_field(
2039 "maxPriorityFeePerGas",
2040 &format!("{:#x}", self.max_priority_fee_per_gas),
2041 )?;
2042 struct_serializer
2043 .serialize_field("maxFeePerGas", &format!("{:#x}", self.max_fee_per_gas))?;
2044 struct_serializer
2045 .serialize_field("gasPrice", &format!("{:#x}", self.max_fee_per_gas))?;
2046 struct_serializer.serialize_field(
2047 "maxFeePerBlobGas",
2048 &format!("{:#x}", self.max_fee_per_blob_gas),
2049 )?;
2050 struct_serializer.serialize_field(
2051 "accessList",
2052 &self
2053 .access_list
2054 .iter()
2055 .map(AccessListEntry::from)
2056 .collect::<Vec<_>>(),
2057 )?;
2058 struct_serializer
2059 .serialize_field("blobVersionedHashes", &self.blob_versioned_hashes)?;
2060 struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?;
2061 struct_serializer
2062 .serialize_field("yParity", &format!("{:#x}", self.signature_y_parity as u8))?;
2063 struct_serializer
2064 .serialize_field("v", &format!("{:#x}", self.signature_y_parity as u8))?; struct_serializer.serialize_field("r", &self.signature_r)?;
2066 struct_serializer.serialize_field("s", &self.signature_s)?;
2067 struct_serializer.end()
2068 }
2069 }
2070
2071 impl Serialize for EIP7702Transaction {
2072 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2073 where
2074 S: serde::Serializer,
2075 {
2076 let mut struct_serializer = serializer.serialize_struct("Eip7702Transaction", 15)?;
2077 struct_serializer.serialize_field("type", &TxType::EIP7702)?;
2078 struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?;
2079 struct_serializer.serialize_field("to", &self.to)?;
2080 struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas_limit))?;
2081 struct_serializer.serialize_field("value", &self.value)?;
2082 struct_serializer.serialize_field("input", &format!("0x{:x}", self.data))?;
2083 struct_serializer.serialize_field(
2084 "maxPriorityFeePerGas",
2085 &format!("{:#x}", self.max_priority_fee_per_gas),
2086 )?;
2087 struct_serializer
2088 .serialize_field("maxFeePerGas", &format!("{:#x}", self.max_fee_per_gas))?;
2089 struct_serializer
2090 .serialize_field("gasPrice", &format!("{:#x}", self.max_fee_per_gas))?;
2091 struct_serializer.serialize_field(
2092 "accessList",
2093 &self
2094 .access_list
2095 .iter()
2096 .map(AccessListEntry::from)
2097 .collect::<Vec<_>>(),
2098 )?;
2099 struct_serializer.serialize_field(
2100 "authorizationList",
2101 &self
2102 .authorization_list
2103 .iter()
2104 .map(AuthorizationTupleEntry::from)
2105 .collect::<Vec<_>>(),
2106 )?;
2107 struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?;
2108 struct_serializer
2109 .serialize_field("yParity", &format!("{:#x}", self.signature_y_parity as u8))?;
2110 struct_serializer
2111 .serialize_field("v", &format!("{:#x}", self.signature_y_parity as u8))?; struct_serializer.serialize_field("r", &self.signature_r)?;
2113 struct_serializer.serialize_field("s", &self.signature_s)?;
2114 struct_serializer.end()
2115 }
2116 }
2117
2118 impl Serialize for PrivilegedL2Transaction {
2119 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2120 where
2121 S: serde::Serializer,
2122 {
2123 let mut struct_serializer = serializer.serialize_struct("Eip1559Transaction", 14)?;
2124 struct_serializer.serialize_field("type", &TxType::Privileged)?;
2125 struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?;
2126 struct_serializer.serialize_field("to", &self.to)?;
2127 struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas_limit))?;
2128 struct_serializer.serialize_field("value", &self.value)?;
2129 struct_serializer.serialize_field("input", &format!("0x{:x}", self.data))?;
2130 struct_serializer.serialize_field(
2131 "maxPriorityFeePerGas",
2132 &format!("{:#x}", self.max_priority_fee_per_gas),
2133 )?;
2134 struct_serializer
2135 .serialize_field("maxFeePerGas", &format!("{:#x}", self.max_fee_per_gas))?;
2136 struct_serializer
2137 .serialize_field("gasPrice", &format!("{:#x}", self.max_fee_per_gas))?;
2138 struct_serializer.serialize_field(
2139 "accessList",
2140 &self
2141 .access_list
2142 .iter()
2143 .map(AccessListEntry::from)
2144 .collect::<Vec<_>>(),
2145 )?;
2146 struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?;
2147 struct_serializer.serialize_field("sender", &self.from)?;
2148 struct_serializer.end()
2149 }
2150 }
2151
2152 impl Serialize for FeeTokenTransaction {
2153 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2154 where
2155 S: serde::Serializer,
2156 {
2157 let mut struct_serializer = serializer.serialize_struct("FeeTokenTransaction", 15)?;
2158 struct_serializer.serialize_field("type", &TxType::FeeToken)?;
2159 struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?;
2160 struct_serializer.serialize_field("to", &self.to)?;
2161 struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas_limit))?;
2162 struct_serializer.serialize_field("value", &self.value)?;
2163 struct_serializer.serialize_field("input", &format!("0x{:x}", self.data))?;
2164 struct_serializer.serialize_field(
2165 "maxPriorityFeePerGas",
2166 &format!("{:#x}", self.max_priority_fee_per_gas),
2167 )?;
2168 struct_serializer
2169 .serialize_field("maxFeePerGas", &format!("{:#x}", self.max_fee_per_gas))?;
2170 struct_serializer
2171 .serialize_field("gasPrice", &format!("{:#x}", self.max_fee_per_gas))?;
2172 struct_serializer.serialize_field(
2173 "accessList",
2174 &self
2175 .access_list
2176 .iter()
2177 .map(AccessListEntry::from)
2178 .collect::<Vec<_>>(),
2179 )?;
2180 struct_serializer.serialize_field("feeToken", &format!("{:#x}", self.fee_token))?;
2181 struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?;
2182 struct_serializer
2183 .serialize_field("yParity", &format!("{:#x}", self.signature_y_parity as u8))?;
2184 struct_serializer
2185 .serialize_field("v", &format!("{:#x}", self.signature_y_parity as u8))?;
2186 struct_serializer.serialize_field("r", &self.signature_r)?;
2187 struct_serializer.serialize_field("s", &self.signature_s)?;
2188 struct_serializer.end()
2189 }
2190 }
2191
2192 impl<'de> Deserialize<'de> for Transaction {
2193 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2194 where
2195 D: serde::Deserializer<'de>,
2196 {
2197 let mut map = <HashMap<String, serde_json::Value>>::deserialize(deserializer)?;
2198 let tx_type =
2199 serde_json::from_value::<TxType>(map.remove("type").unwrap_or(Value::default()))
2200 .unwrap_or_else(|_| {
2201 if map.contains_key("tx_type") {
2202 return TxType::Privileged;
2203 }
2204 TxType::EIP1559
2205 });
2206
2207 let iter = map.into_iter();
2208 match tx_type {
2209 TxType::Legacy => {
2210 LegacyTransaction::deserialize(serde::de::value::MapDeserializer::new(iter))
2211 .map(Transaction::LegacyTransaction)
2212 .map_err(|e| {
2213 serde::de::Error::custom(format!("Couldn't Deserialize Legacy {e}"))
2214 })
2215 }
2216 TxType::EIP2930 => {
2217 EIP2930Transaction::deserialize(serde::de::value::MapDeserializer::new(iter))
2218 .map(Transaction::EIP2930Transaction)
2219 .map_err(|e| {
2220 serde::de::Error::custom(format!("Couldn't Deserialize EIP2930 {e}"))
2221 })
2222 }
2223 TxType::EIP1559 => {
2224 EIP1559Transaction::deserialize(serde::de::value::MapDeserializer::new(iter))
2225 .map(Transaction::EIP1559Transaction)
2226 .map_err(|e| {
2227 serde::de::Error::custom(format!("Couldn't Deserialize EIP1559 {e}"))
2228 })
2229 }
2230 TxType::EIP4844 => {
2231 EIP4844Transaction::deserialize(serde::de::value::MapDeserializer::new(iter))
2232 .map(Transaction::EIP4844Transaction)
2233 .map_err(|e| {
2234 serde::de::Error::custom(format!("Couldn't Deserialize EIP4844 {e}"))
2235 })
2236 }
2237 TxType::EIP7702 => {
2238 EIP7702Transaction::deserialize(serde::de::value::MapDeserializer::new(iter))
2239 .map(Transaction::EIP7702Transaction)
2240 .map_err(|e| {
2241 serde::de::Error::custom(format!("Couldn't Deserialize EIP7702 {e}"))
2242 })
2243 }
2244 TxType::Privileged => PrivilegedL2Transaction::deserialize(
2245 serde::de::value::MapDeserializer::new(iter),
2246 )
2247 .map(Transaction::PrivilegedL2Transaction)
2248 .map_err(|e| {
2249 serde::de::Error::custom(format!("Couldn't Deserialize Privileged: {e}"))
2250 }),
2251 TxType::FeeToken => {
2252 FeeTokenTransaction::deserialize(serde::de::value::MapDeserializer::new(iter))
2253 .map(Transaction::FeeTokenTransaction)
2254 .map_err(|e| {
2255 serde::de::Error::custom(format!("Couldn't Deserialize FeeToken {e}"))
2256 })
2257 }
2258 }
2259 }
2260 }
2261
2262 fn deserialize_input_field(
2263 map: &mut std::collections::HashMap<String, Value>,
2264 ) -> Result<Bytes, serde_json::Error> {
2265 let data_str: String = serde_json::from_value(
2266 map.remove("input")
2267 .ok_or_else(|| serde::de::Error::missing_field("input"))?,
2268 )
2269 .map_err(serde::de::Error::custom)?;
2270 if let Some(stripped) = data_str.strip_prefix("0x") {
2271 match hex::decode(stripped) {
2272 Ok(decoded_bytes) => Ok(Bytes::from(decoded_bytes)),
2273 Err(_) => Err(serde::de::Error::custom(
2274 "Invalid hex format in 'input' field",
2275 ))?,
2276 }
2277 } else {
2278 Err(serde::de::Error::custom(
2279 "'input' field must start with '0x'",
2280 ))?
2281 }
2282 }
2283
2284 fn deserialize_field<'de, T, D>(
2285 map: &mut HashMap<String, serde_json::Value>,
2286 key: &str,
2287 ) -> Result<T, D::Error>
2288 where
2289 D: serde::Deserializer<'de>,
2290 T: serde::de::DeserializeOwned,
2291 {
2292 map.remove(key)
2293 .ok_or_else(|| D::Error::custom(format!("Missing field: {key}")))
2294 .and_then(|value| {
2295 serde_json::from_value(value).map_err(|err| D::Error::custom(err.to_string()))
2296 })
2297 }
2298
2299 fn deserialize_u64_field<'de, D>(
2300 map: &mut HashMap<String, serde_json::Value>,
2301 key: &str,
2302 ) -> Result<u64, D::Error>
2303 where
2304 D: serde::Deserializer<'de>,
2305 {
2306 let value = deserialize_field::<U256, D>(map, key)?;
2307 u64::try_from(value).map_err(|_| D::Error::custom(format!("{key} value overflows u64")))
2308 }
2309
2310 impl<'de> Deserialize<'de> for LegacyTransaction {
2311 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2312 where
2313 D: serde::Deserializer<'de>,
2314 {
2315 let mut map = <HashMap<String, serde_json::Value>>::deserialize(deserializer)?;
2316
2317 Ok(LegacyTransaction {
2318 nonce: deserialize_u64_field::<D>(&mut map, "nonce")?,
2319 gas_price: deserialize_field::<U256, D>(&mut map, "gasPrice")?,
2320 gas: deserialize_u64_field::<D>(&mut map, "gas")?,
2321 to: deserialize_field::<TxKind, D>(&mut map, "to")?,
2322 value: deserialize_field::<U256, D>(&mut map, "value")?,
2323 data: deserialize_input_field(&mut map).map_err(serde::de::Error::custom)?,
2324 v: deserialize_field::<U256, D>(&mut map, "v")?,
2325 r: deserialize_field::<U256, D>(&mut map, "r")?,
2326 s: deserialize_field::<U256, D>(&mut map, "s")?,
2327 ..Default::default()
2328 })
2329 }
2330 }
2331
2332 impl<'de> Deserialize<'de> for EIP2930Transaction {
2333 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2334 where
2335 D: serde::Deserializer<'de>,
2336 {
2337 let mut map = <HashMap<String, serde_json::Value>>::deserialize(deserializer)?;
2338
2339 Ok(EIP2930Transaction {
2340 chain_id: deserialize_u64_field::<D>(&mut map, "chainId")?,
2341 nonce: deserialize_u64_field::<D>(&mut map, "nonce")?,
2342 gas_price: deserialize_field::<U256, D>(&mut map, "gasPrice")?,
2343 gas_limit: deserialize_u64_field::<D>(&mut map, "gas")?,
2344 to: deserialize_field::<TxKind, D>(&mut map, "to")?,
2345 value: deserialize_field::<U256, D>(&mut map, "value")?,
2346 data: deserialize_input_field(&mut map).map_err(serde::de::Error::custom)?,
2347 access_list: deserialize_field::<Vec<AccessListEntry>, D>(&mut map, "accessList")?
2348 .into_iter()
2349 .map(|v| (v.address, v.storage_keys))
2350 .collect::<Vec<_>>(),
2351 signature_y_parity: u8::from_str_radix(
2352 deserialize_field::<String, D>(&mut map, "yParity")?.trim_start_matches("0x"),
2353 16,
2354 )
2355 .map_err(serde::de::Error::custom)?
2356 != 0,
2357 signature_r: deserialize_field::<U256, D>(&mut map, "r")?,
2358 signature_s: deserialize_field::<U256, D>(&mut map, "s")?,
2359 ..Default::default()
2360 })
2361 }
2362 }
2363
2364 impl<'de> Deserialize<'de> for EIP1559Transaction {
2365 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2366 where
2367 D: serde::Deserializer<'de>,
2368 {
2369 let mut map = <HashMap<String, serde_json::Value>>::deserialize(deserializer)?;
2370 Ok(EIP1559Transaction {
2371 chain_id: deserialize_u64_field::<D>(&mut map, "chainId")?,
2372 nonce: deserialize_u64_field::<D>(&mut map, "nonce")?,
2373 max_priority_fee_per_gas: deserialize_u64_field::<D>(
2374 &mut map,
2375 "maxPriorityFeePerGas",
2376 )?,
2377 max_fee_per_gas: deserialize_u64_field::<D>(&mut map, "maxFeePerGas")?,
2378 gas_limit: deserialize_u64_field::<D>(&mut map, "gas")?,
2379 to: deserialize_field::<TxKind, D>(&mut map, "to")?,
2380 value: deserialize_field::<U256, D>(&mut map, "value")?,
2381 data: deserialize_input_field(&mut map).map_err(serde::de::Error::custom)?,
2382 access_list: deserialize_field::<Vec<AccessListEntry>, D>(&mut map, "accessList")?
2383 .into_iter()
2384 .map(|v| (v.address, v.storage_keys))
2385 .collect::<Vec<_>>(),
2386 signature_y_parity: u8::from_str_radix(
2387 deserialize_field::<String, D>(&mut map, "yParity")?.trim_start_matches("0x"),
2388 16,
2389 )
2390 .map_err(serde::de::Error::custom)?
2391 != 0,
2392 signature_r: deserialize_field::<U256, D>(&mut map, "r")?,
2393 signature_s: deserialize_field::<U256, D>(&mut map, "s")?,
2394 ..Default::default()
2395 })
2396 }
2397 }
2398
2399 impl<'de> Deserialize<'de> for EIP4844Transaction {
2400 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2401 where
2402 D: serde::Deserializer<'de>,
2403 {
2404 let mut map = <HashMap<String, serde_json::Value>>::deserialize(deserializer)?;
2405
2406 Ok(EIP4844Transaction {
2407 chain_id: deserialize_u64_field::<D>(&mut map, "chainId")?,
2408 nonce: deserialize_u64_field::<D>(&mut map, "nonce")?,
2409 max_priority_fee_per_gas: deserialize_u64_field::<D>(
2410 &mut map,
2411 "maxPriorityFeePerGas",
2412 )?,
2413 max_fee_per_gas: deserialize_u64_field::<D>(&mut map, "maxFeePerGas")?,
2414 gas: deserialize_u64_field::<D>(&mut map, "gas")?,
2415 to: deserialize_field::<Address, D>(&mut map, "to")?,
2416 value: deserialize_field::<U256, D>(&mut map, "value")?,
2417 data: deserialize_input_field(&mut map).map_err(serde::de::Error::custom)?,
2418 access_list: deserialize_field::<Vec<AccessListEntry>, D>(&mut map, "accessList")?
2419 .into_iter()
2420 .map(|v| (v.address, v.storage_keys))
2421 .collect::<Vec<_>>(),
2422 max_fee_per_blob_gas: deserialize_field::<U256, D>(&mut map, "maxFeePerBlobGas")?,
2423 blob_versioned_hashes: deserialize_field::<Vec<H256>, D>(
2424 &mut map,
2425 "blobVersionedHashes",
2426 )?,
2427 signature_y_parity: u8::from_str_radix(
2428 deserialize_field::<String, D>(&mut map, "yParity")?.trim_start_matches("0x"),
2429 16,
2430 )
2431 .map_err(serde::de::Error::custom)?
2432 != 0,
2433 signature_r: deserialize_field::<U256, D>(&mut map, "r")?,
2434 signature_s: deserialize_field::<U256, D>(&mut map, "s")?,
2435 ..Default::default()
2436 })
2437 }
2438 }
2439
2440 impl<'de> Deserialize<'de> for EIP7702Transaction {
2441 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2442 where
2443 D: serde::Deserializer<'de>,
2444 {
2445 let mut map = <HashMap<String, serde_json::Value>>::deserialize(deserializer)?;
2446
2447 Ok(EIP7702Transaction {
2448 chain_id: deserialize_u64_field::<D>(&mut map, "chainId")?,
2449 nonce: deserialize_u64_field::<D>(&mut map, "nonce")?,
2450 max_priority_fee_per_gas: deserialize_u64_field::<D>(
2451 &mut map,
2452 "maxPriorityFeePerGas",
2453 )?,
2454 max_fee_per_gas: deserialize_u64_field::<D>(&mut map, "maxFeePerGas")?,
2455 gas_limit: deserialize_u64_field::<D>(&mut map, "gas")?,
2456 to: deserialize_field::<Address, D>(&mut map, "to")?,
2457 value: deserialize_field::<U256, D>(&mut map, "value")?,
2458 data: deserialize_input_field(&mut map).map_err(serde::de::Error::custom)?,
2459 access_list: deserialize_field::<Vec<AccessListEntry>, D>(&mut map, "accessList")?
2460 .into_iter()
2461 .map(|v| (v.address, v.storage_keys))
2462 .collect::<Vec<_>>(),
2463 authorization_list: deserialize_field::<Vec<AuthorizationTupleEntry>, D>(
2464 &mut map,
2465 "authorizationList",
2466 )?
2467 .into_iter()
2468 .map(AuthorizationTuple::from)
2469 .collect::<Vec<_>>(),
2470 signature_y_parity: u8::from_str_radix(
2471 deserialize_field::<String, D>(&mut map, "yParity")?.trim_start_matches("0x"),
2472 16,
2473 )
2474 .map_err(serde::de::Error::custom)?
2475 != 0,
2476 signature_r: deserialize_field::<U256, D>(&mut map, "r")?,
2477 signature_s: deserialize_field::<U256, D>(&mut map, "s")?,
2478 ..Default::default()
2479 })
2480 }
2481 }
2482
2483 impl<'de> Deserialize<'de> for PrivilegedL2Transaction {
2484 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2485 where
2486 D: serde::Deserializer<'de>,
2487 {
2488 let mut map = <HashMap<String, serde_json::Value>>::deserialize(deserializer)?;
2489
2490 Ok(PrivilegedL2Transaction {
2491 chain_id: deserialize_u64_field::<D>(&mut map, "chainId")?,
2492 nonce: deserialize_u64_field::<D>(&mut map, "nonce")?,
2493 max_priority_fee_per_gas: deserialize_u64_field::<D>(
2494 &mut map,
2495 "maxPriorityFeePerGas",
2496 )?,
2497 max_fee_per_gas: deserialize_u64_field::<D>(&mut map, "maxFeePerGas")?,
2498 gas_limit: deserialize_u64_field::<D>(&mut map, "gas")?,
2499 to: deserialize_field::<TxKind, D>(&mut map, "to")?,
2500 value: deserialize_field::<U256, D>(&mut map, "value")?,
2501 data: deserialize_input_field(&mut map).map_err(serde::de::Error::custom)?,
2502 access_list: deserialize_field::<Vec<AccessListEntry>, D>(&mut map, "accessList")?
2503 .into_iter()
2504 .map(|v| (v.address, v.storage_keys))
2505 .collect::<Vec<_>>(),
2506 from: deserialize_field::<Address, D>(&mut map, "sender")?,
2507 ..Default::default()
2508 })
2509 }
2510 }
2511
2512 impl<'de> Deserialize<'de> for FeeTokenTransaction {
2513 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2514 where
2515 D: serde::Deserializer<'de>,
2516 {
2517 let mut map = <HashMap<String, serde_json::Value>>::deserialize(deserializer)?;
2518
2519 Ok(FeeTokenTransaction {
2520 chain_id: deserialize_u64_field::<D>(&mut map, "chainId")?,
2521 nonce: deserialize_u64_field::<D>(&mut map, "nonce")?,
2522 max_priority_fee_per_gas: deserialize_u64_field::<D>(
2523 &mut map,
2524 "maxPriorityFeePerGas",
2525 )?,
2526 max_fee_per_gas: deserialize_u64_field::<D>(&mut map, "maxFeePerGas")?,
2527 gas_limit: deserialize_u64_field::<D>(&mut map, "gas")?,
2528 to: deserialize_field::<TxKind, D>(&mut map, "to")?,
2529 value: deserialize_field::<U256, D>(&mut map, "value")?,
2530 data: deserialize_input_field(&mut map).map_err(serde::de::Error::custom)?,
2531 access_list: deserialize_field::<Vec<AccessListEntry>, D>(&mut map, "accessList")?
2532 .into_iter()
2533 .map(|v| (v.address, v.storage_keys))
2534 .collect::<Vec<_>>(),
2535 fee_token: deserialize_field::<Address, D>(&mut map, "feeToken")?,
2536 signature_y_parity: u8::from_str_radix(
2537 deserialize_field::<String, D>(&mut map, "yParity")?.trim_start_matches("0x"),
2538 16,
2539 )
2540 .map_err(serde::de::Error::custom)?
2541 != 0,
2542 signature_r: deserialize_field::<U256, D>(&mut map, "r")?,
2543 signature_s: deserialize_field::<U256, D>(&mut map, "s")?,
2544 ..Default::default()
2545 })
2546 }
2547 }
2548
2549 #[derive(Debug, thiserror::Error)]
2550 pub enum GenericTransactionError {
2551 #[error("Invalid transaction type: {0}")]
2552 InvalidTxType(TxType),
2553 #[error("Blob bundle error: {0}")]
2554 BlobBundleError(#[from] BlobsBundleError),
2555 #[error("Missing field: {0}")]
2556 MissingField(String),
2557 #[error("Invalid field: {0}")]
2558 InvalidField(String),
2559 }
2560
2561 #[derive(Deserialize, Debug, PartialEq, Clone, Default)]
2564 #[serde(rename_all = "camelCase")]
2565 pub struct GenericTransaction {
2566 #[serde(default)]
2567 pub r#type: TxType,
2568 #[serde(default, with = "crate::serde_utils::u64::hex_str_opt")]
2569 pub nonce: Option<u64>,
2570 pub to: TxKind,
2571 #[serde(default)]
2572 pub from: Address,
2573 #[serde(default, with = "crate::serde_utils::u64::hex_str_opt")]
2574 pub gas: Option<u64>,
2575 #[serde(default)]
2576 pub value: U256,
2577 #[serde(default)]
2578 pub gas_price: U256,
2579 #[serde(default, with = "crate::serde_utils::u64::hex_str_opt")]
2580 pub max_priority_fee_per_gas: Option<u64>,
2581 #[serde(default, with = "crate::serde_utils::u64::hex_str_opt")]
2582 pub max_fee_per_gas: Option<u64>,
2583 pub max_fee_per_blob_gas: Option<U256>,
2584 #[serde(default)]
2585 pub access_list: Vec<AccessListEntry>,
2586 #[serde(default)]
2587 pub fee_token: Option<Address>,
2588 #[serde(default)]
2589 pub authorization_list: Option<Vec<AuthorizationTupleEntry>>,
2590 #[serde(default)]
2591 pub blob_versioned_hashes: Vec<H256>,
2592 pub wrapper_version: Option<u8>,
2593 #[serde(default, with = "crate::serde_utils::bytes::vec")]
2594 pub blobs: Vec<Bytes>,
2595 #[serde(default, with = "crate::serde_utils::u64::hex_str_opt")]
2596 pub chain_id: Option<u64>,
2597 #[serde(
2599 flatten,
2600 rename = "input_or_data",
2601 deserialize_with = "deserialize_input",
2602 serialize_with = "crate::serde_utils::bytes::serialize"
2603 )]
2604 pub input: Bytes,
2605 }
2606 pub fn deserialize_input<'de, D>(deserializer: D) -> Result<Bytes, D::Error>
2608 where
2609 D: Deserializer<'de>,
2610 {
2611 let variables = HashMap::<String, Value>::deserialize(deserializer)?;
2614 let data = variables.get("data");
2615 let input = variables.get("input");
2616 let value = match (data, input) {
2617 (None, None) => return Ok(Bytes::new()),
2619 (None, Some(val)) => val,
2620 (Some(val), None) => val,
2621 (Some(val_a), Some(val_b)) => {
2622 if val_a == val_b {
2623 val_a
2624 } else {
2625 return Err(D::Error::custom(
2626 "Transaction has both `data` and `input` fields with different values",
2627 ));
2628 }
2629 }
2630 };
2631 let value = String::deserialize(value).map_err(D::Error::custom)?;
2632 let bytes = hex::decode(value.trim_start_matches("0x"))
2633 .map_err(|e| D::Error::custom(e.to_string()))?;
2634 Ok(Bytes::from(bytes))
2635 }
2636
2637 impl From<EIP1559Transaction> for GenericTransaction {
2638 fn from(value: EIP1559Transaction) -> Self {
2639 Self {
2640 r#type: TxType::EIP1559,
2641 nonce: Some(value.nonce),
2642 to: value.to,
2643 gas: Some(value.gas_limit),
2644 value: value.value,
2645 input: value.data.clone(),
2646 gas_price: U256::from(value.max_fee_per_gas),
2647 max_priority_fee_per_gas: Some(value.max_priority_fee_per_gas),
2648 max_fee_per_gas: Some(value.max_fee_per_gas),
2649 max_fee_per_blob_gas: None,
2650 access_list: value
2651 .access_list
2652 .iter()
2653 .map(AccessListEntry::from)
2654 .collect(),
2655 fee_token: None,
2656 authorization_list: None,
2657 blob_versioned_hashes: vec![],
2658 blobs: vec![],
2659 wrapper_version: None,
2660 chain_id: Some(value.chain_id),
2661 from: Address::default(),
2662 }
2663 }
2664 }
2665
2666 impl TryFrom<GenericTransaction> for EIP1559Transaction {
2667 type Error = GenericTransactionError;
2668
2669 fn try_from(value: GenericTransaction) -> Result<Self, Self::Error> {
2670 if value.r#type != TxType::EIP1559 {
2671 return Err(GenericTransactionError::InvalidTxType(value.r#type));
2672 }
2673
2674 Ok(Self {
2675 nonce: value.nonce.unwrap_or_default(),
2676 to: value.to,
2677 gas_limit: value.gas.unwrap_or_default(),
2678 value: value.value,
2679 data: value.input.clone(),
2680 max_priority_fee_per_gas: value.max_priority_fee_per_gas.unwrap_or_default(),
2681 max_fee_per_gas: value.max_fee_per_gas.unwrap_or(
2682 u64::try_from(value.gas_price).map_err(|_| {
2683 GenericTransactionError::InvalidField("gas_price overflows u64".to_owned())
2684 })?,
2685 ),
2686 access_list: value
2687 .access_list
2688 .into_iter()
2689 .map(|v| (v.address, v.storage_keys))
2690 .collect::<Vec<_>>(),
2691 chain_id: value.chain_id.unwrap_or_default(),
2692 ..Default::default()
2693 })
2694 }
2695 }
2696
2697 impl From<EIP4844Transaction> for GenericTransaction {
2698 fn from(value: EIP4844Transaction) -> Self {
2699 Self {
2700 r#type: TxType::EIP4844,
2701 nonce: Some(value.nonce),
2702 to: TxKind::Call(value.to),
2703 gas: Some(value.gas),
2704 value: value.value,
2705 input: value.data.clone(),
2706 gas_price: U256::from(value.max_fee_per_gas),
2707 max_priority_fee_per_gas: Some(value.max_priority_fee_per_gas),
2708 max_fee_per_gas: Some(value.max_fee_per_gas),
2709 max_fee_per_blob_gas: Some(value.max_fee_per_blob_gas),
2710 access_list: value
2711 .access_list
2712 .iter()
2713 .map(AccessListEntry::from)
2714 .collect(),
2715 fee_token: None,
2716 authorization_list: None,
2717 blob_versioned_hashes: value.blob_versioned_hashes,
2718 blobs: vec![],
2719 wrapper_version: None,
2720 chain_id: Some(value.chain_id),
2721 from: Address::default(),
2722 }
2723 }
2724 }
2725
2726 #[cfg(feature = "c-kzg")]
2727 impl TryFrom<GenericTransaction> for WrappedEIP4844Transaction {
2728 type Error = GenericTransactionError;
2729
2730 fn try_from(value: GenericTransaction) -> Result<Self, Self::Error> {
2731 let blobs = value
2732 .blobs
2733 .iter()
2734 .map(|bytes| {
2735 let slice = bytes.as_ref();
2736 let mut blob = [0u8; BYTES_PER_BLOB];
2737 blob.copy_from_slice(slice);
2738 blob
2739 })
2740 .collect();
2741
2742 let wrapper_version = value.wrapper_version;
2743 Ok(Self {
2744 tx: value.try_into()?,
2745 wrapper_version,
2746 blobs_bundle: BlobsBundle::create_from_blobs(&blobs, wrapper_version)?,
2747 })
2748 }
2749 }
2750
2751 impl TryFrom<GenericTransaction> for EIP4844Transaction {
2752 type Error = GenericTransactionError;
2753
2754 fn try_from(value: GenericTransaction) -> Result<Self, Self::Error> {
2755 if value.r#type != TxType::EIP4844 {
2756 return Err(GenericTransactionError::InvalidTxType(value.r#type));
2757 }
2758 Ok(Self {
2759 nonce: value.nonce.unwrap_or_default(),
2760 to: match value.to {
2761 TxKind::Call(to) => to,
2762 _ => H160::default(),
2763 },
2764 gas: value.gas.unwrap_or_default(),
2765 value: value.value,
2766 data: value.input.clone(),
2767 max_priority_fee_per_gas: value.max_priority_fee_per_gas.unwrap_or_default(),
2768 max_fee_per_gas: value.max_fee_per_gas.unwrap_or(
2769 u64::try_from(value.gas_price).map_err(|_| {
2770 GenericTransactionError::InvalidField("gas_price overflows u64".to_owned())
2771 })?,
2772 ),
2773 max_fee_per_blob_gas: value.max_fee_per_blob_gas.unwrap_or_default(),
2774 access_list: value
2775 .access_list
2776 .into_iter()
2777 .map(|v| (v.address, v.storage_keys))
2778 .collect::<Vec<_>>(),
2779 blob_versioned_hashes: value.blob_versioned_hashes,
2780 chain_id: value.chain_id.unwrap_or_default(),
2781 ..Default::default()
2782 })
2783 }
2784 }
2785
2786 impl From<EIP7702Transaction> for GenericTransaction {
2787 fn from(value: EIP7702Transaction) -> Self {
2788 Self {
2789 r#type: TxType::EIP7702,
2790 nonce: Some(value.nonce),
2791 to: TxKind::Call(value.to),
2792 gas: Some(value.gas_limit),
2793 value: value.value,
2794 input: value.data.clone(),
2795 gas_price: U256::from(value.max_fee_per_gas),
2796 max_priority_fee_per_gas: Some(value.max_priority_fee_per_gas),
2797 max_fee_per_gas: Some(value.max_fee_per_gas),
2798 max_fee_per_blob_gas: None,
2799 access_list: value
2800 .access_list
2801 .iter()
2802 .map(AccessListEntry::from)
2803 .collect(),
2804 fee_token: None,
2805 authorization_list: Some(
2806 value
2807 .authorization_list
2808 .iter()
2809 .map(AuthorizationTupleEntry::from)
2810 .collect(),
2811 ),
2812 blob_versioned_hashes: vec![],
2813 blobs: vec![],
2814 wrapper_version: None,
2815 chain_id: Some(value.chain_id),
2816 from: Address::default(),
2817 }
2818 }
2819 }
2820
2821 impl TryFrom<GenericTransaction> for EIP7702Transaction {
2822 type Error = GenericTransactionError;
2823
2824 fn try_from(value: GenericTransaction) -> Result<Self, Self::Error> {
2825 if value.r#type != TxType::EIP7702 {
2826 return Err(GenericTransactionError::InvalidTxType(value.r#type));
2827 }
2828 let TxKind::Call(to) = value.to else {
2829 return Err(GenericTransactionError::MissingField("to".to_owned()));
2830 };
2831 Ok(Self {
2832 chain_id: value.chain_id.unwrap_or_default(),
2833 nonce: value.nonce.unwrap_or_default(),
2834 max_priority_fee_per_gas: value.max_priority_fee_per_gas.unwrap_or_default(),
2835 max_fee_per_gas: value.max_fee_per_gas.unwrap_or(
2836 u64::try_from(value.gas_price).map_err(|_| {
2837 GenericTransactionError::InvalidField("gas_price overflows u64".to_owned())
2838 })?,
2839 ),
2840 gas_limit: value.gas.unwrap_or_default(),
2841 to,
2842 value: value.value,
2843 data: value.input,
2844 access_list: value
2845 .access_list
2846 .into_iter()
2847 .map(|v| (v.address, v.storage_keys))
2848 .collect::<Vec<_>>(),
2849 authorization_list: value
2850 .authorization_list
2851 .unwrap_or_default()
2852 .into_iter()
2853 .map(AuthorizationTuple::from)
2854 .collect(),
2855 ..Default::default()
2856 })
2857 }
2858 }
2859
2860 impl From<PrivilegedL2Transaction> for GenericTransaction {
2861 fn from(value: PrivilegedL2Transaction) -> Self {
2862 Self {
2863 r#type: TxType::Privileged,
2864 nonce: Some(value.nonce),
2865 to: value.to,
2866 gas: Some(value.gas_limit),
2867 value: value.value,
2868 input: value.data.clone(),
2869 gas_price: U256::from(value.max_fee_per_gas),
2870 max_priority_fee_per_gas: Some(value.max_priority_fee_per_gas),
2871 max_fee_per_gas: Some(value.max_fee_per_gas),
2872 max_fee_per_blob_gas: None,
2873 access_list: value
2874 .access_list
2875 .iter()
2876 .map(AccessListEntry::from)
2877 .collect(),
2878 fee_token: None,
2879 authorization_list: None,
2880 blob_versioned_hashes: vec![],
2881 blobs: vec![],
2882 wrapper_version: None,
2883 chain_id: Some(value.chain_id),
2884 from: value.from,
2885 }
2886 }
2887 }
2888
2889 impl TryFrom<GenericTransaction> for PrivilegedL2Transaction {
2890 type Error = GenericTransactionError;
2891
2892 fn try_from(value: GenericTransaction) -> Result<Self, Self::Error> {
2893 if value.r#type != TxType::Privileged {
2894 return Err(GenericTransactionError::InvalidTxType(value.r#type));
2895 }
2896 Ok(Self {
2897 nonce: value.nonce.unwrap_or_default(),
2898 to: value.to,
2899 gas_limit: value.gas.unwrap_or_default(),
2900 value: value.value,
2901 data: value.input.clone(),
2902 max_priority_fee_per_gas: value.max_priority_fee_per_gas.unwrap_or_default(),
2903 max_fee_per_gas: value.max_fee_per_gas.unwrap_or(
2904 u64::try_from(value.gas_price).map_err(|_| {
2905 GenericTransactionError::InvalidField("gas_price overflows u64".to_owned())
2906 })?,
2907 ),
2908 access_list: value
2909 .access_list
2910 .into_iter()
2911 .map(|v| (v.address, v.storage_keys))
2912 .collect::<Vec<_>>(),
2913 chain_id: value.chain_id.unwrap_or_default(),
2914 from: value.from,
2915 ..Default::default()
2916 })
2917 }
2918 }
2919
2920 impl From<FeeTokenTransaction> for GenericTransaction {
2921 fn from(value: FeeTokenTransaction) -> Self {
2922 Self {
2923 r#type: TxType::FeeToken,
2924 nonce: Some(value.nonce),
2925 to: value.to,
2926 gas: Some(value.gas_limit),
2927 value: value.value,
2928 input: value.data.clone(),
2929 gas_price: U256::from(value.max_fee_per_gas),
2930 max_priority_fee_per_gas: Some(value.max_priority_fee_per_gas),
2931 max_fee_per_gas: Some(value.max_fee_per_gas),
2932 max_fee_per_blob_gas: None,
2933 access_list: value
2934 .access_list
2935 .iter()
2936 .map(AccessListEntry::from)
2937 .collect(),
2938 fee_token: Some(value.fee_token),
2939 authorization_list: None,
2940 blob_versioned_hashes: vec![],
2941 blobs: vec![],
2942 chain_id: Some(value.chain_id),
2943 from: Address::default(),
2944 wrapper_version: None,
2945 }
2946 }
2947 }
2948
2949 impl TryFrom<GenericTransaction> for FeeTokenTransaction {
2950 type Error = GenericTransactionError;
2951
2952 fn try_from(value: GenericTransaction) -> Result<Self, Self::Error> {
2953 if value.r#type != TxType::FeeToken {
2954 return Err(GenericTransactionError::InvalidTxType(value.r#type));
2955 }
2956
2957 Ok(Self {
2958 nonce: value.nonce.unwrap_or_default(),
2959 to: value.to,
2960 gas_limit: value.gas.unwrap_or_default(),
2961 value: value.value,
2962 data: value.input.clone(),
2963 max_priority_fee_per_gas: value.max_priority_fee_per_gas.unwrap_or_default(),
2964 max_fee_per_gas: value.max_fee_per_gas.unwrap_or(
2965 u64::try_from(value.gas_price).map_err(|_| {
2966 GenericTransactionError::InvalidField("gas_price overflows u64".to_owned())
2967 })?,
2968 ),
2969 access_list: value
2970 .access_list
2971 .into_iter()
2972 .map(|v| (v.address, v.storage_keys))
2973 .collect::<Vec<_>>(),
2974 fee_token: value
2975 .fee_token
2976 .ok_or(GenericTransactionError::MissingField(
2977 "fee token".to_owned(),
2978 ))?,
2979 chain_id: value.chain_id.unwrap_or_default(),
2980 ..Default::default()
2981 })
2982 }
2983 }
2984
2985 impl From<LegacyTransaction> for GenericTransaction {
2986 fn from(value: LegacyTransaction) -> Self {
2987 Self {
2988 r#type: TxType::Legacy,
2989 nonce: Some(value.nonce),
2990 to: value.to,
2991 from: Address::default(),
2992 gas: Some(value.gas),
2993 value: value.value,
2994 gas_price: value.gas_price,
2995 max_priority_fee_per_gas: None,
2996 max_fee_per_gas: None,
2997 max_fee_per_blob_gas: None,
2998 access_list: vec![],
2999 fee_token: None,
3000 authorization_list: None,
3001 blob_versioned_hashes: vec![],
3002 blobs: vec![],
3003 wrapper_version: None,
3004 chain_id: None,
3005 input: value.data,
3006 }
3007 }
3008 }
3009
3010 impl From<EIP2930Transaction> for GenericTransaction {
3011 fn from(value: EIP2930Transaction) -> Self {
3012 Self {
3013 r#type: TxType::EIP2930,
3014 nonce: Some(value.nonce),
3015 to: value.to,
3016 from: Address::default(),
3017 gas: Some(value.gas_limit),
3018 value: value.value,
3019 gas_price: value.gas_price,
3020 max_priority_fee_per_gas: None,
3021 max_fee_per_gas: None,
3022 max_fee_per_blob_gas: None,
3023 access_list: value
3024 .access_list
3025 .into_iter()
3026 .map(|(address, storage_keys)| AccessListEntry {
3027 address,
3028 storage_keys,
3029 })
3030 .collect(),
3031 fee_token: None,
3032 authorization_list: None,
3033 blob_versioned_hashes: vec![],
3034 blobs: vec![],
3035 wrapper_version: None,
3036 chain_id: Some(value.chain_id),
3037 input: value.data,
3038 }
3039 }
3040 }
3041
3042 impl From<Transaction> for GenericTransaction {
3043 fn from(value: Transaction) -> Self {
3044 match value {
3045 Transaction::LegacyTransaction(tx) => tx.into(),
3046 Transaction::EIP2930Transaction(tx) => tx.into(),
3047 Transaction::EIP1559Transaction(tx) => tx.into(),
3048 Transaction::EIP4844Transaction(tx) => tx.into(),
3049 Transaction::EIP7702Transaction(tx) => tx.into(),
3050 Transaction::PrivilegedL2Transaction(tx) => tx.into(),
3051 Transaction::FeeTokenTransaction(tx) => tx.into(),
3052 }
3053 }
3054 }
3055}
3056
3057mod mempool {
3058 use super::*;
3059 use std::{
3060 cmp::Ordering,
3061 sync::Arc,
3062 time::{SystemTime, UNIX_EPOCH},
3063 };
3064
3065 #[derive(Debug, Clone, PartialEq, Eq)]
3066 pub struct MempoolTransaction {
3067 timestamp: u128,
3069 sender: Address,
3070 inner: Arc<Transaction>,
3071 }
3072
3073 impl MempoolTransaction {
3074 pub fn new(tx: Transaction, sender: Address) -> Self {
3075 Self {
3076 timestamp: SystemTime::now()
3077 .duration_since(UNIX_EPOCH)
3078 .expect("Invalid system time")
3079 .as_micros(),
3080 sender,
3081 inner: Arc::new(tx),
3082 }
3083 }
3084 pub fn time(&self) -> u128 {
3085 self.timestamp
3086 }
3087
3088 pub fn sender(&self) -> Address {
3089 self.sender
3090 }
3091
3092 pub fn transaction(&self) -> &Transaction {
3093 &self.inner
3094 }
3095 }
3096
3097 impl RLPEncode for MempoolTransaction {
3098 fn encode(&self, buf: &mut dyn bytes::BufMut) {
3099 Encoder::new(buf)
3100 .encode_field(&self.timestamp)
3101 .encode_field(&*self.inner)
3102 .finish();
3103 }
3104 }
3105
3106 impl RLPDecode for MempoolTransaction {
3107 fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
3108 let decoder = Decoder::new(rlp)?;
3109 let (timestamp, decoder) = decoder.decode_field("timestamp")?;
3110 let (sender, decoder) = decoder.decode_field("sender")?;
3111 let (inner, decoder) = decoder.decode_field("inner")?;
3112 Ok((
3113 Self {
3114 timestamp,
3115 sender,
3116 inner: Arc::new(inner),
3117 },
3118 decoder.finish()?,
3119 ))
3120 }
3121 }
3122
3123 impl std::ops::Deref for MempoolTransaction {
3124 type Target = Transaction;
3125
3126 fn deref(&self) -> &Self::Target {
3127 &self.inner
3128 }
3129 }
3130
3131 impl Ord for MempoolTransaction {
3133 fn cmp(&self, other: &Self) -> Ordering {
3134 match (self.tx_type(), other.tx_type()) {
3135 (TxType::Privileged, TxType::Privileged) => {
3136 return self.nonce().cmp(&other.nonce());
3137 }
3138 (TxType::Privileged, _) => return Ordering::Less,
3139 (_, TxType::Privileged) => return Ordering::Greater,
3140 _ => (),
3141 };
3142 match self.nonce().cmp(&other.nonce()) {
3143 Ordering::Equal => other.time().cmp(&self.time()),
3144 ordering => ordering,
3145 }
3146 }
3147 }
3148
3149 impl PartialOrd for MempoolTransaction {
3150 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
3151 Some(self.cmp(other))
3152 }
3153 }
3154}
3155
3156#[cfg(test)]
3157mod tests {
3158
3159 use super::*;
3160 use crate::types::{
3161 AuthorizationTuple, BlockBody, Receipt, compute_receipts_root, compute_transactions_root,
3162 };
3163 use ethereum_types::H160;
3164 use hex_literal::hex;
3165 use serde_impl::{AccessListEntry, GenericTransaction};
3166 use std::str::FromStr;
3167
3168 #[test]
3169 fn legacy_chain_id_handles_out_of_range_v_without_underflow() {
3170 let legacy_chain_id = |v: u64| {
3176 Transaction::LegacyTransaction(LegacyTransaction {
3177 v: U256::from(v),
3178 ..Default::default()
3179 })
3180 .chain_id()
3181 };
3182 for v in [0u64, 1, 26, 27, 28, 34] {
3183 assert_eq!(legacy_chain_id(v), None, "v={v} must yield no chain id");
3184 }
3185 assert_eq!(legacy_chain_id(35), Some(0));
3187 assert_eq!(legacy_chain_id(36), Some(0));
3188 assert_eq!(legacy_chain_id(37), Some(1));
3189 }
3190
3191 #[test]
3192 fn test_compute_transactions_root() {
3193 let mut body = BlockBody::empty();
3194 let tx = LegacyTransaction {
3195 nonce: 0,
3196 gas_price: U256::from(0x0a),
3197 gas: 0x05f5e100,
3198 to: TxKind::Call(hex!("1000000000000000000000000000000000000000").into()),
3199 value: 0.into(),
3200 data: Default::default(),
3201 v: U256::from(0x1b),
3202 r: U256::from_big_endian(&hex!(
3203 "7e09e26678ed4fac08a249ebe8ed680bf9051a5e14ad223e4b2b9d26e0208f37"
3204 )),
3205 s: U256::from_big_endian(&hex!(
3206 "5f6e3f188e3e6eab7d7d3b6568f5eac7d687b08d307d3154ccd8c87b4630509b"
3207 )),
3208 ..Default::default()
3209 };
3210 body.transactions.push(Transaction::LegacyTransaction(tx));
3211 let expected_root =
3212 hex!("8151d548273f6683169524b66ca9fe338b9ce42bc3540046c828fd939ae23bcb");
3213 let result = compute_transactions_root(&body.transactions, ðrex_crypto::NativeCrypto);
3214
3215 assert_eq!(result, expected_root.into());
3216 }
3217 #[test]
3218 fn test_compute_hash() {
3219 let tx_eip2930 = EIP2930Transaction {
3221 chain_id: 3503995874084926u64,
3222 nonce: 7,
3223 gas_price: U256::from(0x2dbf1f9a_u64),
3224 gas_limit: 0x186A0,
3225 to: TxKind::Call(hex!("7dcd17433742f4c0ca53122ab541d0ba67fc27df").into()),
3226 value: 2.into(),
3227 data: Bytes::from(&b"\xdbS\x06$\x8e\x03\x13\xe7emit"[..]),
3228 access_list: vec![(
3229 hex!("7dcd17433742f4c0ca53122ab541d0ba67fc27df").into(),
3230 vec![
3231 hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
3232 hex!("a3d07a7d68fbd49ec2f8e6befdd86c885f86c272819f6f345f365dec35ae6707").into(),
3233 ],
3234 )],
3235 signature_y_parity: false,
3236 signature_r: U256::from_dec_str(
3237 "75813812796588349127366022588733264074091236448495248199152066031778895768879",
3238 )
3239 .unwrap(),
3240 signature_s: U256::from_dec_str(
3241 "25476208226281085290728123165613764315157904411823916642262684106502155457829",
3242 )
3243 .unwrap(),
3244 ..Default::default()
3245 };
3246 let tx = Transaction::EIP2930Transaction(tx_eip2930);
3247
3248 let expected_hash =
3249 hex!("a0762610d794acddd2dca15fb7c437ada3611c886f3bea675d53d8da8a6c41b2");
3250 let hash = tx.compute_hash();
3251 assert_eq!(hash, expected_hash.into());
3252 }
3253
3254 #[test]
3255 fn test_compute_receipts_root() {
3256 let tx_type = TxType::Legacy;
3259 let succeeded = true;
3260 let cumulative_gas_used = 0x5208;
3261 let logs = vec![];
3262 let receipt = Receipt::new(tx_type, succeeded, cumulative_gas_used, logs);
3263
3264 let result = compute_receipts_root(&[receipt], ðrex_crypto::NativeCrypto);
3265 let expected_root =
3266 hex!("056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2");
3267 assert_eq!(result, expected_root.into());
3268 }
3269
3270 #[test]
3271 fn legacy_tx_rlp_decode() {
3272 let encoded_tx = "f86d80843baa0c4082f618946177843db3138ae69679a54b95cf345ed759450d870aa87bee538000808360306ba0151ccc02146b9b11adf516e6787b59acae3e76544fdcd75e77e67c6b598ce65da064c5dd5aae2fbb535830ebbdad0234975cd7ece3562013b63ea18cc0df6c97d4";
3273 let encoded_tx_bytes = hex::decode(encoded_tx).unwrap();
3274 let tx = LegacyTransaction::decode(&encoded_tx_bytes).unwrap();
3275 let expected_tx = LegacyTransaction {
3276 nonce: 0,
3277 gas_price: U256::from(1001000000u64),
3278 gas: 63000,
3279 to: TxKind::Call(Address::from_slice(
3280 &hex::decode("6177843db3138ae69679A54b95cf345ED759450d").unwrap(),
3281 )),
3282 value: 3000000000000000_u64.into(),
3283 data: Bytes::new(),
3284 r: U256::from_str_radix(
3285 "151ccc02146b9b11adf516e6787b59acae3e76544fdcd75e77e67c6b598ce65d",
3286 16,
3287 )
3288 .unwrap(),
3289 s: U256::from_str_radix(
3290 "64c5dd5aae2fbb535830ebbdad0234975cd7ece3562013b63ea18cc0df6c97d4",
3291 16,
3292 )
3293 .unwrap(),
3294 v: 6303851.into(),
3295 ..Default::default()
3296 };
3297 assert_eq!(tx, expected_tx);
3298 }
3299
3300 #[test]
3301 fn eip1559_tx_rlp_decode() {
3302 let encoded_tx = "f86c8330182480114e82f618946177843db3138ae69679a54b95cf345ed759450d870aa87bee53800080c080a0151ccc02146b9b11adf516e6787b59acae3e76544fdcd75e77e67c6b598ce65da064c5dd5aae2fbb535830ebbdad0234975cd7ece3562013b63ea18cc0df6c97d4";
3303 let encoded_tx_bytes = hex::decode(encoded_tx).unwrap();
3304 let tx = EIP1559Transaction::decode(&encoded_tx_bytes).unwrap();
3305 let expected_tx = EIP1559Transaction {
3306 nonce: 0,
3307 max_fee_per_gas: 78,
3308 max_priority_fee_per_gas: 17,
3309 to: TxKind::Call(Address::from_slice(
3310 &hex::decode("6177843db3138ae69679A54b95cf345ED759450d").unwrap(),
3311 )),
3312 value: 3000000000000000_u64.into(),
3313 data: Bytes::new(),
3314 signature_r: U256::from_str_radix(
3315 "151ccc02146b9b11adf516e6787b59acae3e76544fdcd75e77e67c6b598ce65d",
3316 16,
3317 )
3318 .unwrap(),
3319 signature_s: U256::from_str_radix(
3320 "64c5dd5aae2fbb535830ebbdad0234975cd7ece3562013b63ea18cc0df6c97d4",
3321 16,
3322 )
3323 .unwrap(),
3324 signature_y_parity: false,
3325 chain_id: 3151908,
3326 gas_limit: 63000,
3327 access_list: vec![],
3328 ..Default::default()
3329 };
3330 assert_eq!(tx, expected_tx);
3331 }
3332
3333 #[test]
3334 fn deserialize_tx_kind() {
3335 let tx_kind_create = r#""""#;
3336 let tx_kind_call = r#""0x6177843db3138ae69679A54b95cf345ED759450d""#;
3337 let deserialized_tx_kind_create = TxKind::Create;
3338 let deserialized_tx_kind_call = TxKind::Call(Address::from_slice(
3339 &hex::decode("6177843db3138ae69679A54b95cf345ED759450d").unwrap(),
3340 ));
3341 assert_eq!(
3342 deserialized_tx_kind_create,
3343 serde_json::from_str(tx_kind_create).unwrap()
3344 );
3345 assert_eq!(
3346 deserialized_tx_kind_call,
3347 serde_json::from_str(tx_kind_call).unwrap()
3348 )
3349 }
3350
3351 #[test]
3352 fn deserialize_tx_type() {
3353 let tx_type_eip2930 = r#""0x01""#;
3354 let tx_type_eip1559 = r#""0x02""#;
3355 let deserialized_tx_type_eip2930 = TxType::EIP2930;
3356 let deserialized_tx_type_eip1559 = TxType::EIP1559;
3357 assert_eq!(
3358 deserialized_tx_type_eip2930,
3359 serde_json::from_str(tx_type_eip2930).unwrap()
3360 );
3361 assert_eq!(
3362 deserialized_tx_type_eip1559,
3363 serde_json::from_str(tx_type_eip1559).unwrap()
3364 )
3365 }
3366
3367 #[test]
3368 fn deserialize_generic_transaction() {
3369 let generic_transaction = r#"{
3370 "type":"0x01",
3371 "nonce":"0x02",
3372 "to":"",
3373 "from":"0x6177843db3138ae69679A54b95cf345ED759450d",
3374 "gas":"0x5208",
3375 "value":"0x01",
3376 "input":"0x010203040506",
3377 "gasPrice":"0x07",
3378 "accessList": [
3379 {
3380 "address": "0x000f3df6d732807ef1319fb7b8bb8522d0beac02",
3381 "storageKeys": [
3382 "0x000000000000000000000000000000000000000000000000000000000000000c",
3383 "0x000000000000000000000000000000000000000000000000000000000000200b"
3384 ]
3385 }
3386 ]
3387 }"#;
3388 let deserialized_generic_transaction = GenericTransaction {
3389 r#type: TxType::EIP2930,
3390 nonce: Some(2),
3391 to: TxKind::Create,
3392 from: Address::from_slice(
3393 &hex::decode("6177843db3138ae69679A54b95cf345ED759450d").unwrap(),
3394 ),
3395 gas: Some(0x5208),
3396 value: U256::from(1),
3397 input: Bytes::from(hex::decode("010203040506").unwrap()),
3398 gas_price: U256::from(7),
3399 max_priority_fee_per_gas: Default::default(),
3400 max_fee_per_gas: Default::default(),
3401 max_fee_per_blob_gas: Default::default(),
3402 access_list: vec![AccessListEntry {
3403 address: Address::from_slice(
3404 &hex::decode("000f3df6d732807ef1319fb7b8bb8522d0beac02").unwrap(),
3405 ),
3406 storage_keys: vec![H256::from_low_u64_be(12), H256::from_low_u64_be(8203)],
3407 }],
3408 fee_token: None,
3409 blob_versioned_hashes: Default::default(),
3410 blobs: Default::default(),
3411 wrapper_version: None,
3412 chain_id: Default::default(),
3413 authorization_list: None,
3414 };
3415 assert_eq!(
3416 deserialized_generic_transaction,
3417 serde_json::from_str(generic_transaction).unwrap()
3418 )
3419 }
3420
3421 #[test]
3422 fn deserialize_generic_transaction_with_data_and_input_fields() {
3423 let generic_transaction = r#"{
3424 "type":"0x01",
3425 "nonce":"0x02",
3426 "to":"",
3427 "from":"0x6177843db3138ae69679A54b95cf345ED759450d",
3428 "gas":"0x5208",
3429 "value":"0x01",
3430 "input":"0x010203040506",
3431 "data":"0x010203040506",
3432 "gasPrice":"0x07",
3433 "accessList": [
3434 {
3435 "address": "0x000f3df6d732807ef1319fb7b8bb8522d0beac02",
3436 "storageKeys": [
3437 "0x000000000000000000000000000000000000000000000000000000000000000c",
3438 "0x000000000000000000000000000000000000000000000000000000000000200b"
3439 ]
3440 }
3441 ]
3442 }"#;
3443 let deserialized_generic_transaction = GenericTransaction {
3444 r#type: TxType::EIP2930,
3445 nonce: Some(2),
3446 to: TxKind::Create,
3447 from: Address::from_slice(
3448 &hex::decode("6177843db3138ae69679A54b95cf345ED759450d").unwrap(),
3449 ),
3450 gas: Some(0x5208),
3451 value: U256::from(1),
3452 input: Bytes::from(hex::decode("010203040506").unwrap()),
3453 gas_price: U256::from(7),
3454 max_priority_fee_per_gas: Default::default(),
3455 max_fee_per_gas: Default::default(),
3456 max_fee_per_blob_gas: Default::default(),
3457 access_list: vec![AccessListEntry {
3458 address: Address::from_slice(
3459 &hex::decode("000f3df6d732807ef1319fb7b8bb8522d0beac02").unwrap(),
3460 ),
3461 storage_keys: vec![H256::from_low_u64_be(12), H256::from_low_u64_be(8203)],
3462 }],
3463 fee_token: None,
3464 blob_versioned_hashes: Default::default(),
3465 blobs: Default::default(),
3466 wrapper_version: None,
3467 chain_id: Default::default(),
3468 authorization_list: None,
3469 };
3470 assert_eq!(
3471 deserialized_generic_transaction,
3472 serde_json::from_str(generic_transaction).unwrap()
3473 )
3474 }
3475
3476 #[test]
3477 fn deserialize_eip4844_transaction() {
3478 let eip4844_transaction = r#"{
3479 "chainId":"0x01",
3480 "nonce":"0x02",
3481 "maxPriorityFeePerGas":"0x01",
3482 "maxFeePerGas":"0x01",
3483 "gas":"0x5208",
3484 "to":"0x6177843db3138ae69679A54b95cf345ED759450d",
3485 "value":"0x01",
3486 "input":"0x3033",
3487 "accessList": [
3488 {
3489 "address": "0x000f3df6d732807ef1319fb7b8bb8522d0beac02",
3490 "storageKeys": [
3491 "0x000000000000000000000000000000000000000000000000000000000000000c",
3492 "0x000000000000000000000000000000000000000000000000000000000000200b"
3493 ]
3494 }
3495 ],
3496 "maxFeePerBlobGas":"0x03",
3497 "blobVersionedHashes": [
3498 "0x0000000000000000000000000000000000000000000000000000000000000001",
3499 "0x0000000000000000000000000000000000000000000000000000000000000002"
3500 ],
3501 "yParity":"0x0",
3502 "r": "0x01",
3503 "s": "0x02"
3504 }"#;
3505 let deserialized_eip4844_transaction = EIP4844Transaction {
3506 chain_id: 0x01,
3507 nonce: 0x02,
3508 to: Address::from_slice(
3509 &hex::decode("6177843db3138ae69679A54b95cf345ED759450d").unwrap(),
3510 ),
3511 max_priority_fee_per_gas: 1,
3512 max_fee_per_gas: 1,
3513 max_fee_per_blob_gas: U256::from(0x03),
3514 gas: 0x5208,
3515 value: U256::from(0x01),
3516 data: Bytes::from_static(b"03"),
3518 access_list: vec![(
3519 Address::from_slice(
3520 &hex::decode("000f3df6d732807ef1319fb7b8bb8522d0beac02").unwrap(),
3521 ),
3522 vec![H256::from_low_u64_be(12), H256::from_low_u64_be(8203)],
3523 )],
3524 blob_versioned_hashes: vec![H256::from_low_u64_be(1), H256::from_low_u64_be(2)],
3525 signature_y_parity: false,
3526 signature_r: U256::from(0x01),
3527 signature_s: U256::from(0x02),
3528 ..Default::default()
3529 };
3530
3531 assert_eq!(
3532 deserialized_eip4844_transaction,
3533 serde_json::from_str(eip4844_transaction).unwrap()
3534 )
3535 }
3536
3537 #[test]
3538 fn serialize_deserialize_transaction() {
3539 let eip1559 = EIP1559Transaction {
3540 chain_id: 65536999,
3541 nonce: 1,
3542 max_priority_fee_per_gas: 1000,
3543 max_fee_per_gas: 2000,
3544 gas_limit: 21000,
3545 to: TxKind::Call(H160::from_str("0x000a52D537c4150ec274dcE3962a0d179B7E71B0").unwrap()),
3546 value: U256::from(100000),
3547 data: Bytes::from_static(b"03"),
3548 access_list: vec![(
3549 H160::from_str("0x000a52D537c4150ec274dcE3962a0d179B7E71B3").unwrap(),
3550 vec![H256::zero()],
3551 )],
3552 signature_y_parity: true,
3553 signature_r: U256::one(),
3554 signature_s: U256::zero(),
3555 ..Default::default()
3556 };
3557 let tx_to_serialize = Transaction::EIP1559Transaction(eip1559.clone());
3558 let serialized = serde_json::to_string(&tx_to_serialize).expect("Failed to serialize");
3559
3560 let deserialized_tx: Transaction =
3561 serde_json::from_str(&serialized).expect("Failed to deserialize");
3562
3563 assert!(deserialized_tx.tx_type() == TxType::EIP1559);
3564
3565 if let Transaction::EIP1559Transaction(tx) = deserialized_tx {
3566 assert_eq!(tx, eip1559);
3567 }
3568 }
3569
3570 #[test]
3571 fn serialize_deserialize_eip7702transaction() {
3572 let eip7702 = EIP7702Transaction {
3573 chain_id: 65536999,
3574 nonce: 1,
3575 max_priority_fee_per_gas: 1000,
3576 max_fee_per_gas: 2000,
3577 gas_limit: 21000,
3578 to: Address::from_str("0x000a52D537c4150ec274dcE3962a0d179B7E71B0").unwrap(),
3579 value: U256::from(100000),
3580 data: Bytes::from_static(b"03"),
3581 access_list: vec![],
3582 signature_y_parity: true,
3583 signature_r: U256::one(),
3584 signature_s: U256::zero(),
3585 authorization_list: vec![AuthorizationTuple {
3586 chain_id: U256::from(65536999),
3587 address: H160::from_str("0x000a52D537c4150ec274dcE3962a0d179B7E71B1").unwrap(),
3588 nonce: 2,
3589 y_parity: U256::one(),
3590 r_signature: U256::from(22),
3591 s_signature: U256::from(37),
3592 }],
3593 ..Default::default()
3594 };
3595 let tx_to_serialize = Transaction::EIP7702Transaction(eip7702.clone());
3596 let serialized = serde_json::to_string(&tx_to_serialize).expect("Failed to serialize");
3597
3598 let deserialized_tx: Transaction =
3599 serde_json::from_str(&serialized).expect("Failed to deserialize");
3600
3601 assert!(deserialized_tx.tx_type() == TxType::EIP7702);
3602
3603 if let Transaction::EIP7702Transaction(tx) = deserialized_tx {
3604 assert_eq!(tx, eip7702);
3605 }
3606 }
3607
3608 #[test]
3609 fn serialize_deserialize_privileged_l2_transaction() -> Result<(), RLPDecodeError> {
3610 let privileged_l2 = PrivilegedL2Transaction {
3611 chain_id: 65536999,
3612 nonce: 0,
3613 max_priority_fee_per_gas: 875000000,
3614 max_fee_per_gas: 875000000,
3615 gas_limit: 42000u64,
3616 to: TxKind::Call(
3617 Address::from_str("0x8943545177806ed17b9f23f0a21ee5948ecaa776").unwrap(),
3618 ),
3619 value: U256::from(500000000000000000000000000u128),
3620 data: Bytes::new(),
3621 access_list: vec![],
3622 from: Address::from_str("0x8943545177806ed17b9f23f0a21ee5948ecaa776").unwrap(),
3623 ..Default::default()
3624 };
3625
3626 let encoded = PrivilegedL2Transaction::encode_to_vec(&privileged_l2);
3627 println!("encoded length: {}", encoded.len());
3628 assert_eq!(encoded.len(), privileged_l2.length());
3629
3630 let deserialized_tx = PrivilegedL2Transaction::decode(&encoded)?;
3631
3632 assert_eq!(deserialized_tx, privileged_l2);
3633
3634 Ok(())
3635 }
3636
3637 #[test]
3638 fn test_legacy_transaction_into_generic() {
3639 let legacy_tx = LegacyTransaction {
3640 nonce: 1,
3641 gas_price: U256::from(20_000_000_000u64),
3642 gas: 21000,
3643 to: TxKind::Call(
3644 Address::from_str("0x742d35Cc6634C0532925a3b844Bc454e4438f44e").unwrap(),
3645 ),
3646 value: U256::from(1_000_000_000_000_000_000u64),
3647 data: Bytes::default(),
3648 v: U256::from(27),
3649 r: U256::from(1),
3650 s: U256::from(1),
3651 ..Default::default()
3652 };
3653
3654 let generic_tx: GenericTransaction = legacy_tx.into();
3655 assert_eq!(generic_tx.r#type, TxType::Legacy);
3656 assert_eq!(generic_tx.nonce, Some(1));
3657 assert_eq!(generic_tx.gas_price, U256::from(20_000_000_000u64));
3658 assert_eq!(generic_tx.gas, Some(21000));
3659 assert_eq!(generic_tx.max_priority_fee_per_gas, None);
3660 assert_eq!(generic_tx.max_fee_per_gas, None);
3661 assert_eq!(generic_tx.access_list.len(), 0);
3662 assert_eq!(generic_tx.chain_id, None);
3663 }
3664
3665 #[test]
3666 fn test_eip2930_transaction_into_generic() {
3667 let access_list = vec![(
3668 Address::from_str("0x742d35Cc6634C0532925a3b844Bc454e4438f44e").unwrap(),
3669 vec![
3670 H256::from_str(
3671 "0x1234567890123456789012345678901234567890123456789012345678901234",
3672 )
3673 .unwrap(),
3674 ],
3675 )];
3676
3677 let eip2930_tx = EIP2930Transaction {
3678 chain_id: 1,
3679 nonce: 1,
3680 gas_price: U256::from(20_000_000_000u64),
3681 gas_limit: 21000,
3682 to: TxKind::Call(
3683 Address::from_str("0x742d35Cc6634C0532925a3b844Bc454e4438f44e").unwrap(),
3684 ),
3685 value: U256::from(1_000_000_000_000_000_000u64),
3686 data: Bytes::default(),
3687 access_list: access_list.clone(),
3688 signature_y_parity: false,
3689 signature_r: U256::from(1),
3690 signature_s: U256::from(1),
3691 ..Default::default()
3692 };
3693
3694 let generic_tx: GenericTransaction = eip2930_tx.into();
3695 assert_eq!(generic_tx.r#type, TxType::EIP2930);
3696 assert_eq!(generic_tx.nonce, Some(1));
3697 assert_eq!(generic_tx.gas_price, U256::from(20_000_000_000u64));
3698 assert_eq!(generic_tx.gas, Some(21000));
3699 assert_eq!(generic_tx.max_priority_fee_per_gas, None);
3700 assert_eq!(generic_tx.max_fee_per_gas, None);
3701 assert_eq!(generic_tx.chain_id, Some(1));
3702 assert_eq!(generic_tx.access_list.len(), 1);
3703 assert_eq!(generic_tx.access_list[0].address, access_list[0].0);
3704 assert_eq!(generic_tx.access_list[0].storage_keys, access_list[0].1);
3705 }
3706
3707 #[test]
3708 fn recover_address_rejects_high_s_signatures() {
3709 use ethrex_crypto::NativeCrypto;
3710 use k256::ecdsa::SigningKey;
3711
3712 let crypto = NativeCrypto;
3713
3714 let private_key = hex!("4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318");
3717 let signing_key = SigningKey::from_bytes(&private_key.into()).expect("Valid private key");
3718
3719 let msg = b"Test message for high-s signature rejection";
3721 let payload = keccak(msg).to_fixed_bytes();
3723
3724 let (signature, recovery_id) = signing_key
3727 .sign_prehash_recoverable(&payload)
3728 .expect("Signing failed");
3729
3730 let mut sig_bytes = [0u8; 65];
3732 sig_bytes[..64].copy_from_slice(&signature.to_bytes());
3733 sig_bytes[64] = recovery_id.to_byte();
3734
3735 let uncompressed_pub = signing_key.verifying_key().to_encoded_point(false);
3738 let pub_hash = ethrex_crypto::keccak::keccak_hash(&uncompressed_pub.as_bytes()[1..]);
3739 let expected_address = Address::from_slice(&pub_hash[12..]);
3740
3741 let recovered = crypto
3742 .recover_signer(&sig_bytes, &payload)
3743 .expect("Valid low-s signature should recover successfully");
3744 assert_eq!(recovered, expected_address, "Recovered address mismatch");
3745
3746 let n = U256::from_big_endian(&hex!(
3749 "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
3750 ));
3751 let s = U256::from_big_endian(&sig_bytes[32..64]);
3752
3753 let half_n = n / 2;
3755 assert!(
3756 s <= half_n,
3757 "Generated signature was not low-s, cannot test high-s rejection"
3758 );
3759
3760 let s_high = n - s;
3762
3763 let mut sig_high_bytes = sig_bytes;
3764 sig_high_bytes[32..64].copy_from_slice(&s_high.to_big_endian());
3766 sig_high_bytes[64] ^= 1;
3768
3769 assert!(
3772 crypto.recover_signer(&sig_high_bytes, &payload).is_err(),
3773 "High-s signature should be rejected (EIP-2 compliance)"
3774 );
3775 }
3776
3777 #[test]
3778 fn encode_decode_low_size_tx() {
3779 let tx = Transaction::EIP2930Transaction(EIP2930Transaction::default());
3780 let tx_to_encode = tx.clone();
3783 let encoded = tx_to_encode.encode_to_vec();
3784 let decoded_tx = Transaction::decode(&encoded).unwrap();
3785 assert_eq!(tx, decoded_tx);
3786 }
3787
3788 #[test]
3789 fn test_eip1559_simple_transfer_size() {
3790 let tx = Transaction::EIP1559Transaction(EIP1559Transaction::default());
3791 assert_eq!(tx.encode_to_vec().len(), EIP1559_DEFAULT_SERIALIZED_LENGTH);
3792 }
3793
3794 #[test]
3795 fn test_cost_without_base_fee_eip4844_includes_blob_gas() {
3796 use crate::constants::GAS_PER_BLOB;
3800
3801 let max_fee_per_gas: u64 = 100;
3802 let gas: u64 = 21_000;
3803 let value = U256::from(7u64);
3804 let max_fee_per_blob_gas = U256::from(50u64);
3805 let blob_count: usize = 1;
3806
3807 let tx = Transaction::EIP4844Transaction(EIP4844Transaction {
3808 max_fee_per_gas,
3809 gas,
3810 value,
3811 max_fee_per_blob_gas,
3812 blob_versioned_hashes: vec![H256::zero(); blob_count],
3813 ..Default::default()
3814 });
3815
3816 let got = tx.cost_without_base_fee().expect("cost is computable");
3817
3818 let gas_cost = U256::from(max_fee_per_gas) * U256::from(gas);
3819 let blob_gas = U256::from(GAS_PER_BLOB) * U256::from(blob_count as u64);
3820 let blob_cost = blob_gas * max_fee_per_blob_gas;
3821 let expected = gas_cost + blob_cost + value;
3822
3823 assert_eq!(
3824 got, expected,
3825 "blob-gas term missing from cost_without_base_fee() for EIP-4844"
3826 );
3827 }
3828}