diff --git a/crates/codecs/Cargo.toml b/crates/codecs/Cargo.toml index 45b054a706..ebeee8380b 100644 --- a/crates/codecs/Cargo.toml +++ b/crates/codecs/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/foundry-rs/reth" readme = "README.md" [features] -default = ["scale"] +default = ["compact"] compact = ["codecs-derive/compact"] scale = ["codecs-derive/scale"] postcard = ["codecs-derive/postcard"] diff --git a/crates/codecs/derive/Cargo.toml b/crates/codecs/derive/Cargo.toml index f4a88c6a26..86871ce44a 100644 --- a/crates/codecs/derive/Cargo.toml +++ b/crates/codecs/derive/Cargo.toml @@ -19,7 +19,7 @@ serde = { version = "1.0.*", default-features = false } parity-scale-codec = { version = "3.2.1", features = ["derive", "bytes"] } [features] -default = ["scale"] +default = ["compact"] compact = [] scale = [] postcard = [] diff --git a/crates/codecs/derive/src/compact/flags.rs b/crates/codecs/derive/src/compact/flags.rs index 25a7384478..56ec97aad7 100644 --- a/crates/codecs/derive/src/compact/flags.rs +++ b/crates/codecs/derive/src/compact/flags.rs @@ -71,6 +71,9 @@ fn build_struct_field_flags( // Find out the adequate bit size for the length of each field, if applicable. for (name, ftype, is_compact) in fields { + // This happens when dealing with a wrapper struct eg. Struct(pub U256). + let name = if name.is_empty() { "placeholder" } else { name }; + if *is_compact { if is_flag_type(ftype) { let name = format_ident!("{name}_len"); diff --git a/crates/codecs/derive/src/compact/generator.rs b/crates/codecs/derive/src/compact/generator.rs index 027d9d63ef..cd9771aa1e 100644 --- a/crates/codecs/derive/src/compact/generator.rs +++ b/crates/codecs/derive/src/compact/generator.rs @@ -50,7 +50,13 @@ pub fn generate_from_to(ident: &Ident, fields: &FieldList) -> TokenStream2 { /// Generates code to implement the [`Compact`] trait method `to_compact`. fn generate_from_compact(fields: &FieldList, ident: &Ident) -> Vec { let mut lines = vec![]; - let known_types = ["H256", "H160", "Address", "Bloom", "Vec"]; + let mut known_types = vec!["H256", "H160", "Address", "Bloom", "Vec"]; + + // Only types without `bytes::Bytes` should be added here. It's currently manually added, since + // it's hard to figure out with derive_macro which types have bytes::Bytes fields. + // + // This removes the requirement of the field to be placed last in the struct. + known_types.append(&mut vec!["TransactionKind", "AccessList", "Signature"]); // let mut handle = FieldListHandler::new(fields); let is_enum = fields.iter().any(|field| matches!(field, FieldTypes::EnumVariant(_))); @@ -66,24 +72,31 @@ fn generate_from_compact(fields: &FieldList, ident: &Ident) -> Vec }; }); } else { - lines.append(&mut StructHandler::new(fields).generate_from(known_types.as_slice())); - - let fields = fields.iter().filter_map(|field| { - if let FieldTypes::StructField((name, _, _)) = field { - let ident = format_ident!("{name}"); - return Some(quote! { - #ident: #ident, - }) - } - None - }); + let mut struct_handler = StructHandler::new(fields); + lines.append(&mut struct_handler.generate_from(known_types.as_slice())); // Builds the object instantiation. - lines.push(quote! { - let obj = #ident { - #(#fields)* - }; - }); + if struct_handler.is_wrapper { + lines.push(quote! { + let obj = #ident(placeholder); + }); + } else { + let fields = fields.iter().filter_map(|field| { + if let FieldTypes::StructField((name, _, _)) = field { + let ident = format_ident!("{name}"); + return Some(quote! { + #ident: #ident, + }) + } + None + }); + + lines.push(quote! { + let obj = #ident { + #(#fields)* + }; + }); + } } lines diff --git a/crates/codecs/derive/src/compact/mod.rs b/crates/codecs/derive/src/compact/mod.rs index f4ca02683e..3801322173 100644 --- a/crates/codecs/derive/src/compact/mod.rs +++ b/crates/codecs/derive/src/compact/mod.rs @@ -124,16 +124,14 @@ fn load_field(field: &syn::Field, fields: &mut FieldList, is_enum: bool) { /// Given the field type in a string format, return the amount of bits necessary to save its maximum /// length. pub fn get_bit_size(ftype: &str) -> u8 { - if ftype == "u64" || ftype == "BlockNumber" || ftype == "TxNumber" || ftype == "ChainId" { - return 4 - } else if ftype == "TxType" { - return 2 - } else if ftype == "bool" || ftype == "Option" { - return 1 - } else if ftype == "U256" { - return 6 + match ftype { + "bool" | "Option" => 1, + "TxType" => 2, + "u64" | "BlockNumber" | "TxNumber" | "ChainId" => 4, + "u128" => 5, + "U256" | "TxHash" => 6, + _ => 0, } - 0 } /// Given the field type in a string format, checks if its type should be added to the diff --git a/crates/codecs/derive/src/compact/structs.rs b/crates/codecs/derive/src/compact/structs.rs index bbc21206ab..978eb858aa 100644 --- a/crates/codecs/derive/src/compact/structs.rs +++ b/crates/codecs/derive/src/compact/structs.rs @@ -4,11 +4,16 @@ use super::*; pub struct StructHandler<'a> { fields_iterator: std::iter::Peekable>, lines: Vec, + pub is_wrapper: bool, } impl<'a> StructHandler<'a> { pub fn new(fields: &'a FieldList) -> Self { - StructHandler { lines: vec![], fields_iterator: fields.iter().peekable() } + StructHandler { + lines: vec![], + fields_iterator: fields.iter().peekable(), + is_wrapper: false, + } } pub fn next_field(&mut self) -> Option<&'a FieldTypes> { @@ -18,8 +23,6 @@ impl<'a> StructHandler<'a> { pub fn generate_to(mut self) -> Vec { while let Some(field) = self.next_field() { match field { - // The following method will advance the - // `fields_iterator` by itself and stop right before the next variant. FieldTypes::EnumVariant(_) => unreachable!(), FieldTypes::EnumUnnamedField(_) => unreachable!(), FieldTypes::StructField(field_descriptor) => self.to(field_descriptor), @@ -28,11 +31,9 @@ impl<'a> StructHandler<'a> { self.lines } - pub fn generate_from(mut self, known_types: &[&str]) -> Vec { + pub fn generate_from(&mut self, known_types: &[&str]) -> Vec { while let Some(field) = self.next_field() { match field { - // The following method will advance the - // `fields_iterator` by itself and stop right before the next variant. FieldTypes::EnumVariant(_) => unreachable!(), FieldTypes::EnumUnnamedField(_) => unreachable!(), FieldTypes::StructField(field_descriptor) => { @@ -40,13 +41,30 @@ impl<'a> StructHandler<'a> { } } } - self.lines + self.lines.clone() } /// Generates `to_compact` code for a struct field. fn to(&mut self, field_descriptor: &StructFieldDescriptor) { let (name, ftype, is_compact) = field_descriptor; + // Should only happen on wrapper structs like `Struct(pub Field)` + if name.is_empty() { + self.is_wrapper = true; + + self.lines.push(quote! { + let _len = self.0.to_compact(&mut buffer); + }); + + if is_flag_type(ftype) { + self.lines.push(quote! { + flags.set_placeholder_len(_len as u8); + }) + } + + return + } + let name = format_ident!("{name}"); let set_len_method = format_ident!("set_{name}_len"); let len = format_ident!("{name}_len"); @@ -77,8 +95,14 @@ impl<'a> StructHandler<'a> { fn from(&mut self, field_descriptor: &StructFieldDescriptor, known_types: &[&str]) { let (name, ftype, is_compact) = field_descriptor; - let name = format_ident!("{name}"); - let len = format_ident!("{name}_len"); + let (name, len) = if name.is_empty() { + self.is_wrapper = true; + + // Should only happen on wrapper structs like `Struct(pub Field)` + (format_ident!("placeholder"), format_ident!("placeholder_len")) + } else { + (format_ident!("{name}"), format_ident!("{name}_len")) + }; assert!( known_types.contains(&ftype.as_str()) || diff --git a/crates/codecs/derive/src/lib.rs b/crates/codecs/derive/src/lib.rs index 72199f9de5..3a54125449 100644 --- a/crates/codecs/derive/src/lib.rs +++ b/crates/codecs/derive/src/lib.rs @@ -12,7 +12,10 @@ pub fn derive(input: TokenStream) -> TokenStream { #[proc_macro_attribute] #[rustfmt::skip] #[allow(unreachable_code)] -pub fn main_codec(args: TokenStream, input: TokenStream) -> TokenStream { +pub fn main_codec(args: TokenStream, input: TokenStream) -> TokenStream { + #[cfg(feature = "compact")] + return use_compact(args, input); + #[cfg(feature = "scale")] return use_scale(args, input); @@ -21,9 +24,6 @@ pub fn main_codec(args: TokenStream, input: TokenStream) -> TokenStream { #[cfg(feature = "no_codec")] return no_codec(args, input); - - #[cfg(feature = "compact")] - return use_compact(args, input); // no features no_codec(args, input) diff --git a/crates/codecs/src/lib.rs b/crates/codecs/src/lib.rs index 5ff3f2ea72..4b49dae4b8 100644 --- a/crates/codecs/src/lib.rs +++ b/crates/codecs/src/lib.rs @@ -28,26 +28,34 @@ pub trait Compact { Self: Sized; } -impl Compact for u64 { - fn to_compact(self, buf: &mut impl bytes::BufMut) -> usize { - let leading = self.leading_zeros() as usize / 8; - buf.put_slice(&self.to_be_bytes()[leading..]); - 8 - leading - } +macro_rules! impl_uint_compact { + ($($name:tt),+) => { + $( + impl Compact for $name { + fn to_compact(self, buf: &mut impl bytes::BufMut) -> usize { + let leading = self.leading_zeros() as usize / 8; + buf.put_slice(&self.to_be_bytes()[leading..]); + std::mem::size_of::<$name>() - leading + } - fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) { - if len > 0 { - let mut arr = [0; 8]; - arr[8 - len..].copy_from_slice(&buf[..len]); + fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) { + if len > 0 { + let mut arr = [0; std::mem::size_of::<$name>()]; + arr[std::mem::size_of::<$name>() - len..].copy_from_slice(&buf[..len]); - buf.advance(len); + buf.advance(len); - return (u64::from_be_bytes(arr), buf) - } - (0, buf) - } + return ($name::from_be_bytes(arr), buf) + } + (0, buf) + } + } + )+ + }; } +impl_uint_compact!(u64, u128); + impl Compact for Vec where T: Compact + Default, @@ -144,12 +152,12 @@ impl Compact for Bytes { } macro_rules! impl_hash_compact { - ($(($name:tt, $size:tt)),+) => { + ($($name:tt),+) => { $( impl Compact for $name { fn to_compact(self, buf: &mut impl bytes::BufMut) -> usize { buf.put_slice(&self.0); - $size + std::mem::size_of::<$name>() } fn from_compact(mut buf: &[u8], len: usize) -> (Self,&[u8]) { @@ -158,9 +166,9 @@ macro_rules! impl_hash_compact { } let v = $name::from_slice( - buf.get(..$size).expect("size not matching"), + buf.get(..std::mem::size_of::<$name>()).expect("size not matching"), ); - buf.advance($size); + buf.advance(std::mem::size_of::<$name>()); (v, buf) } } @@ -168,7 +176,7 @@ macro_rules! impl_hash_compact { }; } -impl_hash_compact!((H256, 32), (H160, 20)); +impl_hash_compact!(H256, H160); impl Compact for Bloom { fn to_compact(self, buf: &mut impl bytes::BufMut) -> usize { @@ -337,7 +345,7 @@ mod tests { assert_eq!(u64::from_compact(&buf, 8), (0xffffffffffffffffu64, vec![].as_slice())); } - #[use_compact] + #[main_codec] #[derive(Debug, PartialEq, Clone)] pub struct TestStruct { f_u64: u64, @@ -389,7 +397,7 @@ mod tests { ); } - #[use_compact] + #[main_codec] #[derive(Debug, PartialEq, Clone, Default)] pub enum TestEnum { #[default] diff --git a/crates/consensus/src/verification.rs b/crates/consensus/src/verification.rs index ae78540478..855e6cf0fa 100644 --- a/crates/consensus/src/verification.rs +++ b/crates/consensus/src/verification.rs @@ -6,7 +6,8 @@ use reth_interfaces::{ Result as RethResult, }; use reth_primitives::{ - Account, BlockLocked, BlockNumber, SealedHeader, Transaction, EMPTY_OMMER_ROOT, H256, U256, + Account, BlockLocked, BlockNumber, SealedHeader, Transaction, TxEip1559, TxEip2930, TxLegacy, + EMPTY_OMMER_ROOT, H256, U256, }; use std::time::SystemTime; @@ -74,21 +75,26 @@ pub fn validate_transaction_regarding_header( base_fee: Option, ) -> Result<(), Error> { let chain_id = match transaction { - Transaction::Legacy { chain_id, .. } => { + Transaction::Legacy(TxLegacy { chain_id, .. }) => { // EIP-155: Simple replay attack protection: https://eips.ethereum.org/EIPS/eip-155 if config.spurious_dragon_hard_fork_block <= at_block_number && chain_id.is_some() { return Err(Error::TransactionOldLegacyChainId) } *chain_id } - Transaction::Eip2930 { chain_id, .. } => { + Transaction::Eip2930(TxEip2930 { chain_id, .. }) => { // EIP-2930: Optional access lists: https://eips.ethereum.org/EIPS/eip-2930 (New transaction type) if config.berlin_hard_fork_block > at_block_number { return Err(Error::TransactionEip2930Disabled) } Some(*chain_id) } - Transaction::Eip1559 { chain_id, max_fee_per_gas, max_priority_fee_per_gas, .. } => { + Transaction::Eip1559(TxEip1559 { + chain_id, + max_fee_per_gas, + max_priority_fee_per_gas, + .. + }) => { // EIP-1559: Fee market change for ETH 1.0 chain https://eips.ethereum.org/EIPS/eip-1559 if config.berlin_hard_fork_block > at_block_number { return Err(Error::TransactionEip1559Disabled) @@ -130,13 +136,13 @@ pub fn validate_transaction_regarding_account( } let (nonce, gas_price, gas_limit, value) = match transaction { - Transaction::Legacy { nonce, gas_price, gas_limit, value, .. } => { + Transaction::Legacy(TxLegacy { nonce, gas_price, gas_limit, value, .. }) => { (nonce, gas_price, gas_limit, value) } - Transaction::Eip2930 { nonce, gas_price, gas_limit, value, .. } => { + Transaction::Eip2930(TxEip2930 { nonce, gas_price, gas_limit, value, .. }) => { (nonce, gas_price, gas_limit, value) } - Transaction::Eip1559 { nonce, gas_limit, max_fee_per_gas, value, .. } => { + Transaction::Eip1559(TxEip1559 { nonce, gas_limit, max_fee_per_gas, value, .. }) => { (nonce, max_fee_per_gas, gas_limit, value) } }; diff --git a/crates/executor/src/executor.rs b/crates/executor/src/executor.rs index d9abaaf1b6..5e9d4dee5e 100644 --- a/crates/executor/src/executor.rs +++ b/crates/executor/src/executor.rs @@ -360,7 +360,7 @@ mod tests { impl AccountProvider for StateProviderTest { fn basic_account(&self, address: Address) -> reth_interfaces::Result> { - let ret = Ok(self.accounts.get(&address).map(|(_, acc)| acc.clone())); + let ret = Ok(self.accounts.get(&address).map(|(_, acc)| *acc)); ret } } @@ -374,8 +374,7 @@ mod tests { Ok(self .accounts .get(&account) - .map(|(storage, _)| storage.get(&storage_key).cloned()) - .flatten()) + .and_then(|(storage, _)| storage.get(&storage_key).cloned())) } fn bytecode_by_hash(&self, code_hash: H256) -> reth_interfaces::Result> { diff --git a/crates/executor/src/revm_wrap.rs b/crates/executor/src/revm_wrap.rs index 371a06f2fd..e96ad3864e 100644 --- a/crates/executor/src/revm_wrap.rs +++ b/crates/executor/src/revm_wrap.rs @@ -1,7 +1,7 @@ use reth_interfaces::{provider::StateProvider, Error}; use reth_primitives::{ - Header, Transaction, TransactionKind, TransactionSignedEcRecovered, H160, H256, KECCAK_EMPTY, - U256, + Header, Transaction, TransactionKind, TransactionSignedEcRecovered, TxEip1559, TxEip2930, + TxLegacy, H160, H256, KECCAK_EMPTY, U256, }; use revm::{ db::{CacheDB, DatabaseRef}, @@ -79,7 +79,15 @@ pub fn fill_block_env(block_env: &mut BlockEnv, header: &Header) { pub fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSignedEcRecovered) { tx_env.caller = transaction.signer(); match transaction.as_ref().as_ref() { - Transaction::Legacy { nonce, chain_id, gas_price, gas_limit, to, value, input } => { + Transaction::Legacy(TxLegacy { + nonce, + chain_id, + gas_price, + gas_limit, + to, + value, + input, + }) => { tx_env.gas_limit = *gas_limit; tx_env.gas_price = (*gas_price).into(); tx_env.gas_priority_fee = None; @@ -92,7 +100,7 @@ pub fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSignedEcRecovere tx_env.chain_id = *chain_id; tx_env.nonce = Some(*nonce); } - Transaction::Eip2930 { + Transaction::Eip2930(TxEip2930 { nonce, chain_id, gas_price, @@ -101,7 +109,7 @@ pub fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSignedEcRecovere value, input, access_list, - } => { + }) => { tx_env.gas_limit = *gas_limit; tx_env.gas_price = (*gas_price).into(); tx_env.gas_priority_fee = None; @@ -124,7 +132,7 @@ pub fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSignedEcRecovere }) .collect(); } - Transaction::Eip1559 { + Transaction::Eip1559(TxEip1559 { nonce, chain_id, gas_limit, @@ -134,7 +142,7 @@ pub fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSignedEcRecovere value, input, access_list, - } => { + }) => { tx_env.gas_limit = *gas_limit; tx_env.gas_price = (*max_fee_per_gas).into(); tx_env.gas_priority_fee = Some((*max_priority_fee_per_gas).into()); diff --git a/crates/interfaces/src/db/codecs/compact.rs b/crates/interfaces/src/db/codecs/compact.rs index 8dcebfa803..fec2d3a8b9 100644 --- a/crates/interfaces/src/db/codecs/compact.rs +++ b/crates/interfaces/src/db/codecs/compact.rs @@ -2,7 +2,9 @@ use crate::db::{ models::{accounts::AccountBeforeTx, StoredBlockBody}, Compress, Decompress, Error, }; -use reth_codecs::Compact; +use bytes::Buf; +use modular_bitfield::prelude::*; +use reth_codecs::{main_codec, Compact}; use reth_primitives::*; /// Implements compression for Compact type. @@ -33,4 +35,42 @@ macro_rules! impl_compression_for_compact { } impl_compression_for_compact!(Header, Account, Log, Receipt, TxType, StorageEntry, StoredBlockBody); -impl_compression_for_compact!(AccountBeforeTx); +impl_compression_for_compact!(AccountBeforeTx, TransactionSigned); +impl_compression_for_compact!(CompactU256); + +/// Adds wrapper structs for some primitive types so they can use StructFlags from Compact, when +/// used as pure table values. +macro_rules! add_wrapper_struct { + ($(($name:tt, $wrapper:tt)),+) => { + $( + /// Wrapper struct so it can use StructFlags from Compact, when used as pure table values. + #[main_codec] + #[derive(Debug, Clone, PartialEq, Eq, Default)] + pub struct $wrapper(pub $name); + + impl From<$name> for $wrapper { + fn from(value: $name) -> Self { + $wrapper(value) + } + } + + impl From<$wrapper> for $name { + fn from(value: $wrapper) -> Self { + value.0 + } + } + + impl std::ops::Deref for $wrapper { + type Target = $name; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + )+ + }; +} + +add_wrapper_struct!((U256, CompactU256)); +add_wrapper_struct!((u64, CompactU64)); diff --git a/crates/interfaces/src/db/codecs/mod.rs b/crates/interfaces/src/db/codecs/mod.rs index 6e70ec2094..fe3d07df42 100644 --- a/crates/interfaces/src/db/codecs/mod.rs +++ b/crates/interfaces/src/db/codecs/mod.rs @@ -1,6 +1,8 @@ //! Integrates different codecs into table::Encode and table::Decode mod compact; +pub use compact::CompactU256; + pub mod fuzz; mod postcard; #[cfg(not(feature = "bench-postcard"))] diff --git a/crates/interfaces/src/db/codecs/scale.rs b/crates/interfaces/src/db/codecs/scale.rs index 10ecc72bd1..4210c29535 100644 --- a/crates/interfaces/src/db/codecs/scale.rs +++ b/crates/interfaces/src/db/codecs/scale.rs @@ -43,5 +43,4 @@ impl ScaleValue for Vec {} impl sealed::Sealed for Vec {} impl_compression_for_scale!(U256, H256, H160); -impl_compression_for_scale!(TransactionSigned); impl_compression_for_scale!(u8, u32, u16, u64); diff --git a/crates/interfaces/src/db/models/accounts.rs b/crates/interfaces/src/db/models/accounts.rs index 3abcbcda78..13eae8fcc5 100644 --- a/crates/interfaces/src/db/models/accounts.rs +++ b/crates/interfaces/src/db/models/accounts.rs @@ -8,12 +8,12 @@ use crate::{ impl_fixed_arbitrary, }; use bytes::Bytes; -use reth_codecs::{use_compact, Compact}; +use reth_codecs::{main_codec, Compact}; use reth_primitives::{Account, Address, TxNumber}; use serde::{Deserialize, Serialize}; /// Account as it is saved inside [`AccountChangeSet`]. [`Address`] is the subkey. -#[use_compact] +#[main_codec] #[derive(Debug, Default, Clone, PartialEq)] pub struct AccountBeforeTx { /// Address for the account. Acts as `DupSort::SubKey`. diff --git a/crates/interfaces/src/db/models/blocks.rs b/crates/interfaces/src/db/models/blocks.rs index 5b35108c87..c365479b5a 100644 --- a/crates/interfaces/src/db/models/blocks.rs +++ b/crates/interfaces/src/db/models/blocks.rs @@ -9,7 +9,7 @@ use crate::{ }; use bytes::{Buf, Bytes}; use modular_bitfield::prelude::*; -use reth_codecs::{use_compact, Compact}; +use reth_codecs::{main_codec, Compact}; use reth_primitives::{BlockHash, BlockNumber, Header, TxNumber, H256}; use serde::{Deserialize, Serialize}; @@ -24,7 +24,7 @@ pub type NumTransactions = u64; /// The [TxNumber]s for all the transactions in the block are `base_tx_id..(base_tx_id + /// tx_amount)`. #[derive(Debug, Default, PartialEq, Clone)] -#[use_compact] +#[main_codec] pub struct StoredBlockBody { /// The ID of the first transaction in the block. pub base_tx_id: TxNumber, diff --git a/crates/interfaces/src/db/models/mod.rs b/crates/interfaces/src/db/models/mod.rs index 04fea81575..a89c3edebe 100644 --- a/crates/interfaces/src/db/models/mod.rs +++ b/crates/interfaces/src/db/models/mod.rs @@ -17,11 +17,11 @@ use crate::db::{ /// Macro that implements [`Encode`] and [`Decode`] for uint types. macro_rules! impl_uints { - ($(($name:tt, $size:tt)),+) => { + ($($name:tt),+) => { $( impl Encode for $name { - type Encoded = [u8; $size]; + type Encoded = [u8; std::mem::size_of::<$name>()]; fn encode(self) -> Self::Encoded { self.to_be_bytes() @@ -43,7 +43,7 @@ macro_rules! impl_uints { }; } -impl_uints!((u64, 8), (u32, 4), (u16, 2), (u8, 1)); +impl_uints!(u64, u32, u16, u8); impl Encode for Vec { type Encoded = Vec; diff --git a/crates/interfaces/src/db/tables.rs b/crates/interfaces/src/db/tables.rs index 6b663f7c6c..6a37336b57 100644 --- a/crates/interfaces/src/db/tables.rs +++ b/crates/interfaces/src/db/tables.rs @@ -1,6 +1,7 @@ //! Declaration of all Database tables. use crate::db::{ + codecs::CompactU256, models::{ accounts::{AccountBeforeTx, TxNumberAddress}, blocks::{BlockNumHash, HeaderHash, NumTransactions, StoredBlockBody}, @@ -108,7 +109,7 @@ table!( table!( /// Stores the total difficulty from a block header. - HeaderTD => BlockNumHash => RlpTotalDifficulty); + HeaderTD => BlockNumHash => CompactU256); table!( /// Stores the block number corresponding to an header. @@ -244,8 +245,6 @@ pub type ConfigValue = Vec; /// Temporary placeholder type for DB. pub type BlockNumHashTxNumber = Vec; /// Temporary placeholder type for DB. -pub type RlpTotalDifficulty = Vec; -/// Temporary placeholder type for DB. pub type AddressStorageKey = Vec; /// Temporary placeholder type for DB. pub type Bytecode = Vec; diff --git a/crates/interfaces/src/test_utils/generators.rs b/crates/interfaces/src/test_utils/generators.rs index b9a0328117..118a4ede98 100644 --- a/crates/interfaces/src/test_utils/generators.rs +++ b/crates/interfaces/src/test_utils/generators.rs @@ -1,7 +1,7 @@ use rand::{thread_rng, Rng}; use reth_primitives::{ proofs, Address, BlockLocked, Bytes, Header, SealedHeader, Signature, Transaction, - TransactionKind, TransactionSigned, H256, U256, + TransactionKind, TransactionSigned, TxLegacy, H256, U256, }; use secp256k1::{KeyPair, Message as SecpMessage, Secp256k1, SecretKey}; @@ -46,7 +46,7 @@ pub fn random_header(number: u64, parent: Option) -> SealedHeader { /// - The chain ID, which is always 1 /// - The input, which is always nothing pub fn random_tx() -> Transaction { - Transaction::Legacy { + Transaction::Legacy(TxLegacy { chain_id: Some(1), nonce: rand::random::().into(), gas_price: rand::random::().into(), @@ -54,7 +54,7 @@ pub fn random_tx() -> Transaction { to: TransactionKind::Call(Address::random()), value: rand::random::().into(), input: Bytes::default(), - } + }) } /// Generates a random legacy [Transaction] that is signed. @@ -154,14 +154,14 @@ pub fn random_block_range(rng: std::ops::Range, head: H256) -> Vec, + /// A scalar value equal to the number of transactions sent by the sender; formally Tn. + pub nonce: u64, + /// A scalar value equal to the number of + /// Wei to be paid per unit of gas for all computation + /// costs incurred as a result of the execution of this transaction; formally Tp. + /// + /// As ethereum circulation is around 120mil eth as of 2022 that is around + /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: + /// 340282366920938463463374607431768211455 + pub gas_price: u128, + /// A scalar value equal to the maximum + /// amount of gas that should be used in executing + /// this transaction. This is paid up-front, before any + /// computation is done and may not be increased + /// later; formally Tg. + pub gas_limit: u64, + /// The 160-bit address of the message call’s recipient or, for a contract creation + /// transaction, ∅, used here to denote the only member of B0 ; formally Tt. + pub to: TransactionKind, + /// A scalar value equal to the number of Wei to + /// be transferred to the message call’s recipient or, + /// in the case of contract creation, as an endowment + /// to the newly created account; formally Tv. + /// + /// As ethereum circulation is around 120mil eth as of 2022 that is around + /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: + /// 340282366920938463463374607431768211455 + pub value: u128, + /// Input has two uses depending if transaction is Create or Call (if `to` field is None or + /// Some). pub init: An unlimited size byte array specifying the + /// EVM-code for the account initialisation procedure CREATE, + /// data: An unlimited size byte array specifying the + /// input data of the message call, formally Td. + pub input: Bytes, +} + +/// Transaction with an [`AccessList`] ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930)). +#[main_codec] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +pub struct TxEip2930 { + /// Added as EIP-pub 155: Simple replay attack protection + pub chain_id: ChainId, + /// A scalar value equal to the number of transactions sent by the sender; formally Tn. + pub nonce: u64, + /// A scalar value equal to the number of + /// Wei to be paid per unit of gas for all computation + /// costs incurred as a result of the execution of this transaction; formally Tp. + /// + /// As ethereum circulation is around 120mil eth as of 2022 that is around + /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: + /// 340282366920938463463374607431768211455 + pub gas_price: u128, + /// A scalar value equal to the maximum + /// amount of gas that should be used in executing + /// this transaction. This is paid up-front, before any + /// computation is done and may not be increased + /// later; formally Tg. + pub gas_limit: u64, + /// The 160-bit address of the message call’s recipient or, for a contract creation + /// transaction, ∅, used here to denote the only member of B0 ; formally Tt. + pub to: TransactionKind, + /// A scalar value equal to the number of Wei to + /// be transferred to the message call’s recipient or, + /// in the case of contract creation, as an endowment + /// to the newly created account; formally Tv. + /// + /// As ethereum circulation is around 120mil eth as of 2022 that is around + /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: + /// 340282366920938463463374607431768211455 + pub value: u128, + /// The accessList specifies a list of addresses and storage keys; + /// these addresses and storage keys are added into the `accessed_addresses` + /// and `accessed_storage_keys` global sets (introduced in EIP-2929). + /// A gas cost is charged, though at a discount relative to the cost of + /// accessing outside the list. + pub access_list: AccessList, + /// Input has two uses depending if transaction is Create or Call (if `to` field is None or + /// Some). pub init: An unlimited size byte array specifying the + /// EVM-code for the account initialisation procedure CREATE, + /// data: An unlimited size byte array specifying the + /// input data of the message call, formally Td. + pub input: Bytes, +} + +/// A transaction with a priority fee ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)). +#[main_codec] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +pub struct TxEip1559 { + /// Added as EIP-pub 155: Simple replay attack protection + pub chain_id: u64, + /// A scalar value equal to the number of transactions sent by the sender; formally Tn. + pub nonce: u64, + /// A scalar value equal to the maximum + /// amount of gas that should be used in executing + /// this transaction. This is paid up-front, before any + /// computation is done and may not be increased + /// later; formally Tg. + pub gas_limit: u64, + /// A scalar value equal to the maximum + /// amount of gas that should be used in executing + /// this transaction. This is paid up-front, before any + /// computation is done and may not be increased + /// later; formally Tg. + /// + /// As ethereum circulation is around 120mil eth as of 2022 that is around + /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: + /// 340282366920938463463374607431768211455 + pub max_fee_per_gas: u128, + /// Max Priority fee that transaction is paying + /// + /// As ethereum circulation is around 120mil eth as of 2022 that is around + /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: + /// 340282366920938463463374607431768211455 + pub max_priority_fee_per_gas: u128, + /// The 160-bit address of the message call’s recipient or, for a contract creation + /// transaction, ∅, used here to denote the only member of B0 ; formally Tt. + pub to: TransactionKind, + /// A scalar value equal to the number of Wei to + /// be transferred to the message call’s recipient or, + /// in the case of contract creation, as an endowment + /// to the newly created account; formally Tv. + /// + /// As ethereum circulation is around 120mil eth as of 2022 that is around + /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: + /// 340282366920938463463374607431768211455 + pub value: u128, + /// The accessList specifies a list of addresses and storage keys; + /// these addresses and storage keys are added into the `accessed_addresses` + /// and `accessed_storage_keys` global sets (introduced in EIP-2929). + /// A gas cost is charged, though at a discount relative to the cost of + /// accessing outside the list. + pub access_list: AccessList, + /// Input has two uses depending if transaction is Create or Call (if `to` field is None or + /// Some). pub init: An unlimited size byte array specifying the + /// EVM-code for the account initialisation procedure CREATE, + /// data: An unlimited size byte array specifying the + /// input data of the message call, formally Td. + pub input: Bytes, +} + /// A raw transaction. /// /// Transaction types were introduced in [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718). @@ -20,142 +167,17 @@ mod util; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Transaction { /// Legacy transaction. - Legacy { - /// Added as EIP-155: Simple replay attack protection - chain_id: Option, - /// A scalar value equal to the number of transactions sent by the sender; formally Tn. - nonce: u64, - /// A scalar value equal to the number of - /// Wei to be paid per unit of gas for all computation - /// costs incurred as a result of the execution of this transaction; formally Tp. - /// - /// As ethereum circulation is around 120mil eth as of 2022 that is around - /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: - /// 340282366920938463463374607431768211455 - gas_price: u128, - /// A scalar value equal to the maximum - /// amount of gas that should be used in executing - /// this transaction. This is paid up-front, before any - /// computation is done and may not be increased - /// later; formally Tg. - gas_limit: u64, - /// The 160-bit address of the message call’s recipient or, for a contract creation - /// transaction, ∅, used here to denote the only member of B0 ; formally Tt. - to: TransactionKind, - /// A scalar value equal to the number of Wei to - /// be transferred to the message call’s recipient or, - /// in the case of contract creation, as an endowment - /// to the newly created account; formally Tv. - /// - /// As ethereum circulation is around 120mil eth as of 2022 that is around - /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: - /// 340282366920938463463374607431768211455 - value: u128, - /// Input has two uses depending if transaction is Create or Call (if `to` field is None or - /// Some). init: An unlimited size byte array specifying the - /// EVM-code for the account initialisation procedure CREATE, - /// data: An unlimited size byte array specifying the - /// input data of the message call, formally Td. - input: Bytes, - }, + Legacy(TxLegacy), /// Transaction with an [`AccessList`] ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930)). - Eip2930 { - /// Added as EIP-155: Simple replay attack protection - chain_id: ChainId, - /// A scalar value equal to the number of transactions sent by the sender; formally Tn. - nonce: u64, - /// A scalar value equal to the number of - /// Wei to be paid per unit of gas for all computation - /// costs incurred as a result of the execution of this transaction; formally Tp. - /// - /// As ethereum circulation is around 120mil eth as of 2022 that is around - /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: - /// 340282366920938463463374607431768211455 - gas_price: u128, - /// A scalar value equal to the maximum - /// amount of gas that should be used in executing - /// this transaction. This is paid up-front, before any - /// computation is done and may not be increased - /// later; formally Tg. - gas_limit: u64, - /// The 160-bit address of the message call’s recipient or, for a contract creation - /// transaction, ∅, used here to denote the only member of B0 ; formally Tt. - to: TransactionKind, - /// A scalar value equal to the number of Wei to - /// be transferred to the message call’s recipient or, - /// in the case of contract creation, as an endowment - /// to the newly created account; formally Tv. - /// - /// As ethereum circulation is around 120mil eth as of 2022 that is around - /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: - /// 340282366920938463463374607431768211455 - value: u128, - /// Input has two uses depending if transaction is Create or Call (if `to` field is None or - /// Some). init: An unlimited size byte array specifying the - /// EVM-code for the account initialisation procedure CREATE, - /// data: An unlimited size byte array specifying the - /// input data of the message call, formally Td. - input: Bytes, - /// The accessList specifies a list of addresses and storage keys; - /// these addresses and storage keys are added into the `accessed_addresses` - /// and `accessed_storage_keys` global sets (introduced in EIP-2929). - /// A gas cost is charged, though at a discount relative to the cost of - /// accessing outside the list. - access_list: AccessList, - }, + Eip2930(TxEip2930), /// A transaction with a priority fee ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)). - Eip1559 { - /// Added as EIP-155: Simple replay attack protection - chain_id: u64, - /// A scalar value equal to the number of transactions sent by the sender; formally Tn. - nonce: u64, - /// A scalar value equal to the maximum - /// amount of gas that should be used in executing - /// this transaction. This is paid up-front, before any - /// computation is done and may not be increased - /// later; formally Tg. - gas_limit: u64, - /// A scalar value equal to the maximum - /// amount of gas that should be used in executing - /// this transaction. This is paid up-front, before any - /// computation is done and may not be increased - /// later; formally Tg. - /// - /// As ethereum circulation is around 120mil eth as of 2022 that is around - /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: - /// 340282366920938463463374607431768211455 - max_fee_per_gas: u128, - /// Max Priority fee that transaction is paying - /// - /// As ethereum circulation is around 120mil eth as of 2022 that is around - /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: - /// 340282366920938463463374607431768211455 - max_priority_fee_per_gas: u128, - /// The 160-bit address of the message call’s recipient or, for a contract creation - /// transaction, ∅, used here to denote the only member of B0 ; formally Tt. - to: TransactionKind, - /// A scalar value equal to the number of Wei to - /// be transferred to the message call’s recipient or, - /// in the case of contract creation, as an endowment - /// to the newly created account; formally Tv. - /// - /// As ethereum circulation is around 120mil eth as of 2022 that is around - /// 120000000000000000000000000 wei we are safe to use u128 as its max number is: - /// 340282366920938463463374607431768211455 - value: u128, - /// Input has two uses depending if transaction is Create or Call (if `to` field is None or - /// Some). init: An unlimited size byte array specifying the - /// EVM-code for the account initialisation procedure CREATE, - /// data: An unlimited size byte array specifying the - /// input data of the message call, formally Td. - input: Bytes, - /// The accessList specifies a list of addresses and storage keys; - /// these addresses and storage keys are added into the `accessed_addresses` - /// and `accessed_storage_keys` global sets (introduced in EIP-2929). - /// A gas cost is charged, though at a discount relative to the cost of - /// accessing outside the list. - access_list: AccessList, - }, + Eip1559(TxEip1559), +} + +impl Default for Transaction { + fn default() -> Self { + Self::Legacy(TxLegacy::default()) + } } impl Transaction { @@ -170,9 +192,9 @@ impl Transaction { /// Sets the transaction's chain id to the provided value. pub fn set_chain_id(&mut self, chain_id: u64) { match self { - Transaction::Legacy { chain_id: ref mut c, .. } => *c = Some(chain_id), - Transaction::Eip2930 { chain_id: ref mut c, .. } => *c = chain_id, - Transaction::Eip1559 { chain_id: ref mut c, .. } => *c = chain_id, + Transaction::Legacy(TxLegacy { chain_id: ref mut c, .. }) => *c = Some(chain_id), + Transaction::Eip2930(TxEip2930 { chain_id: ref mut c, .. }) => *c = chain_id, + Transaction::Eip1559(TxEip1559 { chain_id: ref mut c, .. }) => *c = chain_id, } } @@ -180,9 +202,9 @@ impl Transaction { /// [`TransactionKind::Create`] if the transaction is a contract creation. pub fn kind(&self) -> &TransactionKind { match self { - Transaction::Legacy { to, .. } | - Transaction::Eip2930 { to, .. } | - Transaction::Eip1559 { to, .. } => to, + Transaction::Legacy(TxLegacy { to, .. }) | + Transaction::Eip2930(TxEip2930 { to, .. }) | + Transaction::Eip1559(TxEip1559 { to, .. }) => to, } } @@ -198,46 +220,45 @@ impl Transaction { /// Gets the transaction's value field. pub fn value(&self) -> &u128 { match self { - Transaction::Legacy { value, .. } => value, - Transaction::Eip2930 { value, .. } => value, - Transaction::Eip1559 { value, .. } => value, + Transaction::Legacy(TxLegacy { value, .. }) => value, + Transaction::Eip2930(TxEip2930 { value, .. }) => value, + Transaction::Eip1559(TxEip1559 { value, .. }) => value, } } /// Get the transaction's nonce. pub fn nonce(&self) -> u64 { match self { - Transaction::Legacy { nonce, .. } => *nonce, - Transaction::Eip2930 { nonce, .. } => *nonce, - Transaction::Eip1559 { nonce, .. } => *nonce, + Transaction::Legacy(TxLegacy { nonce, .. }) => *nonce, + Transaction::Eip2930(TxEip2930 { nonce, .. }) => *nonce, + Transaction::Eip1559(TxEip1559 { nonce, .. }) => *nonce, } } /// Get the gas limit of the transaction. pub fn gas_limit(&self) -> u64 { match self { - Transaction::Legacy { gas_limit, .. } | - Transaction::Eip2930 { gas_limit, .. } | - Transaction::Eip1559 { gas_limit, .. } => *gas_limit, + Transaction::Legacy(TxLegacy { gas_limit, .. }) | + Transaction::Eip2930(TxEip2930 { gas_limit, .. }) | + Transaction::Eip1559(TxEip1559 { gas_limit, .. }) => *gas_limit, } } /// Max fee per gas for eip1559 transaction, for legacy transactions this is gas_price pub fn max_fee_per_gas(&self) -> u128 { match self { - Transaction::Legacy { gas_price, .. } | Transaction::Eip2930 { gas_price, .. } => { - *gas_price - } - Transaction::Eip1559 { max_fee_per_gas, .. } => *max_fee_per_gas, + Transaction::Legacy(TxLegacy { gas_price, .. }) | + Transaction::Eip2930(TxEip2930 { gas_price, .. }) => *gas_price, + Transaction::Eip1559(TxEip1559 { max_fee_per_gas, .. }) => *max_fee_per_gas, } } /// Get the transaction's input field. pub fn input(&self) -> &Bytes { match self { - Transaction::Legacy { input, .. } => input, - Transaction::Eip2930 { input, .. } => input, - Transaction::Eip1559 { input, .. } => input, + Transaction::Legacy(TxLegacy { input, .. }) => input, + Transaction::Eip2930(TxEip2930 { input, .. }) => input, + Transaction::Eip1559(TxEip1559 { input, .. }) => input, } } @@ -265,7 +286,7 @@ impl Transaction { pub(crate) fn encode_eip155_fields(&self, out: &mut dyn bytes::BufMut) { // if this is a legacy transaction without a chain ID, it must be pre-EIP-155 // and does not need to encode the chain ID for the signature hash encoding - if let Transaction::Legacy { chain_id: Some(id), .. } = self { + if let Transaction::Legacy(TxLegacy { chain_id: Some(id), .. }) = self { // EIP-155 encodes the chain ID and two zeroes id.encode(out); 0x00u8.encode(out); @@ -276,7 +297,7 @@ impl Transaction { /// Outputs the length of EIP-155 fields. Only outputs a non-zero value for EIP-155 legacy /// transactions. pub(crate) fn eip155_fields_len(&self) -> usize { - if let Transaction::Legacy { chain_id: Some(id), .. } = self { + if let Transaction::Legacy(TxLegacy { chain_id: Some(id), .. }) = self { // EIP-155 encodes the chain ID and two zeroes, so we add 2 to the length of the chain // ID to get the length of all 3 fields // len(chain_id) + (0x00) + (0x00) @@ -306,7 +327,15 @@ impl Transaction { /// eip155 fields. pub(crate) fn fields_len(&self) -> usize { match self { - Transaction::Legacy { chain_id: _, nonce, gas_price, gas_limit, to, value, input } => { + Transaction::Legacy(TxLegacy { + chain_id: _, + nonce, + gas_price, + gas_limit, + to, + value, + input, + }) => { let mut len = 0; len += nonce.length(); len += gas_price.length(); @@ -316,7 +345,7 @@ impl Transaction { len += input.0.length(); len } - Transaction::Eip2930 { + Transaction::Eip2930(TxEip2930 { chain_id, nonce, gas_price, @@ -325,7 +354,7 @@ impl Transaction { value, input, access_list, - } => { + }) => { let mut len = 0; len += chain_id.length(); len += nonce.length(); @@ -337,7 +366,7 @@ impl Transaction { len += access_list.length(); len } - Transaction::Eip1559 { + Transaction::Eip1559(TxEip1559 { chain_id, nonce, gas_limit, @@ -347,7 +376,7 @@ impl Transaction { value, input, access_list, - } => { + }) => { let mut len = 0; len += chain_id.length(); len += nonce.length(); @@ -366,7 +395,15 @@ impl Transaction { /// Encodes only the transaction's fields into the desired buffer, without a RLP header. pub(crate) fn encode_fields(&self, out: &mut dyn bytes::BufMut) { match self { - Transaction::Legacy { chain_id: _, nonce, gas_price, gas_limit, to, value, input } => { + Transaction::Legacy(TxLegacy { + chain_id: _, + nonce, + gas_price, + gas_limit, + to, + value, + input, + }) => { nonce.encode(out); gas_price.encode(out); gas_limit.encode(out); @@ -374,7 +411,7 @@ impl Transaction { value.encode(out); input.0.encode(out); } - Transaction::Eip2930 { + Transaction::Eip2930(TxEip2930 { chain_id, nonce, gas_price, @@ -383,7 +420,7 @@ impl Transaction { value, input, access_list, - } => { + }) => { chain_id.encode(out); nonce.encode(out); gas_price.encode(out); @@ -393,7 +430,7 @@ impl Transaction { input.0.encode(out); access_list.encode(out); } - Transaction::Eip1559 { + Transaction::Eip1559(TxEip1559 { chain_id, nonce, gas_limit, @@ -403,7 +440,7 @@ impl Transaction { value, input, access_list, - } => { + }) => { chain_id.encode(out); nonce.encode(out); max_priority_fee_per_gas.encode(out); @@ -449,9 +486,10 @@ impl Encodable for Transaction { /// Whether or not the transaction is a contract creation. #[main_codec] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub enum TransactionKind { /// A transaction that creates a contract. + #[default] Create, /// A transaction that calls a contract or transfer. Call(Address), @@ -490,16 +528,16 @@ impl Decodable for TransactionKind { /// Signed transaction. #[main_codec] -#[derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref, Default)] pub struct TransactionSigned { - /// Raw transaction info - #[deref] - #[as_ref] - pub transaction: Transaction, /// Transaction hash pub hash: TxHash, /// The transaction signature values pub signature: Signature, + /// Raw transaction info + #[deref] + #[as_ref] + pub transaction: Transaction, } impl Encodable for TransactionSigned { @@ -540,7 +578,7 @@ impl Decodable for TransactionSigned { // decode common fields let transaction = match tx_type { - 1 => Transaction::Eip2930 { + 1 => Transaction::Eip2930(TxEip2930 { chain_id: Decodable::decode(buf)?, nonce: Decodable::decode(buf)?, gas_price: Decodable::decode(buf)?, @@ -549,8 +587,8 @@ impl Decodable for TransactionSigned { value: Decodable::decode(buf)?, input: Bytes(Decodable::decode(buf)?), access_list: Decodable::decode(buf)?, - }, - 2 => Transaction::Eip1559 { + }), + 2 => Transaction::Eip1559(TxEip1559 { chain_id: Decodable::decode(buf)?, nonce: Decodable::decode(buf)?, max_priority_fee_per_gas: Decodable::decode(buf)?, @@ -560,7 +598,7 @@ impl Decodable for TransactionSigned { value: Decodable::decode(buf)?, input: Bytes(Decodable::decode(buf)?), access_list: Decodable::decode(buf)?, - }, + }), _ => return Err(DecodeError::Custom("unsupported typed transaction type")), }; @@ -574,7 +612,7 @@ impl Decodable for TransactionSigned { signed.hash = keccak256(&original_encoding[..first_header.payload_length]).into(); Ok(signed) } else { - let mut transaction = Transaction::Legacy { + let mut transaction = Transaction::Legacy(TxLegacy { nonce: Decodable::decode(buf)?, gas_price: Decodable::decode(buf)?, gas_limit: Decodable::decode(buf)?, @@ -582,7 +620,7 @@ impl Decodable for TransactionSigned { value: Decodable::decode(buf)?, input: Bytes(Decodable::decode(buf)?), chain_id: None, - }; + }); let (signature, extracted_id) = Signature::decode_eip155_inner(buf)?; if let Some(id) = extracted_id { transaction.set_chain_id(id); @@ -630,7 +668,7 @@ impl TransactionSigned { /// Inner encoding function that is used for both rlp [`Encodable`] trait and for calculating /// hash that for eip2728 does not require rlp header pub(crate) fn encode_inner(&self, out: &mut dyn bytes::BufMut, with_header: bool) { - if let Transaction::Legacy { chain_id, .. } = self.transaction { + if let Transaction::Legacy(TxLegacy { chain_id, .. }) = self.transaction { let header = Header { list: true, payload_length: self.payload_len() }; header.encode(out); self.transaction.encode_fields(out); @@ -688,7 +726,7 @@ impl TransactionSigned { /// Output the length of the inner transaction and signature fields. pub(crate) fn inner_tx_len(&self) -> usize { let mut len = self.transaction.fields_len(); - if let Transaction::Legacy { chain_id, .. } = self.transaction { + if let Transaction::Legacy(TxLegacy { chain_id, .. }) = self.transaction { if let Some(id) = chain_id { len += self.signature.eip155_payload_len(id); } else { @@ -719,14 +757,14 @@ impl TransactionSigned { /// Signed transaction with recovered signer. #[main_codec] -#[derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref, Default)] pub struct TransactionSignedEcRecovered { + /// Signer of the transaction + signer: Address, /// Signed transaction #[deref] #[as_ref] signed_transaction: TransactionSigned, - /// Signer of the transaction - signer: Address, } impl Encodable for TransactionSignedEcRecovered { @@ -792,7 +830,7 @@ impl IntoRecoveredTransaction for TransactionSignedEcRecovered { #[cfg(test)] mod tests { use crate::{ - transaction::{signature::Signature, TransactionKind}, + transaction::{signature::Signature, TransactionKind, TxEip1559, TxEip2930, TxLegacy}, AccessList, Address, Bytes, Transaction, TransactionSigned, H256, U256, }; use bytes::BytesMut; @@ -803,7 +841,7 @@ mod tests { #[test] fn test_decode_create() { // tests that a contract creation tx encodes and decodes properly - let request = Transaction::Eip2930 { + let request = Transaction::Eip2930(TxEip2930 { chain_id: 1u64, nonce: 0, gas_price: 1, @@ -812,7 +850,7 @@ mod tests { value: 3, input: Bytes::from(vec![1, 2]), access_list: Default::default(), - }; + }); let signature = Signature { odd_y_parity: true, r: U256::default(), s: U256::default() }; let tx = TransactionSigned::from_transaction_and_signature(request, signature); @@ -834,7 +872,7 @@ mod tests { #[test] fn test_decode_call() { - let request = Transaction::Eip2930 { + let request = Transaction::Eip2930(TxEip2930 { chain_id: 1u64, nonce: 0, gas_price: 1, @@ -843,7 +881,7 @@ mod tests { value: 3, input: Bytes::from(vec![1, 2]), access_list: Default::default(), - }; + }); let signature = Signature { odd_y_parity: true, r: U256::default(), s: U256::default() }; @@ -871,7 +909,7 @@ mod tests { #[test] fn decode_multiple_network_txs() { let bytes_first = &mut &hex::decode("f86b02843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba00eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5aea03a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18").unwrap()[..]; - let expected_request = Transaction::Legacy { + let expected_request = Transaction::Legacy(TxLegacy { chain_id: Some(4u64), nonce: 2, gas_price: 1000000000, @@ -881,7 +919,7 @@ mod tests { ), value: 1000000000000000, input: Bytes::default(), - }; + }); let expected_signature = Signature { odd_y_parity: false, r: U256::from_str("eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae") @@ -899,7 +937,7 @@ mod tests { ); let bytes_second = &mut &hex::decode("f86b01843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac3960468702769bb01b2a00802ba0e24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0aa05406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631da").unwrap()[..]; - let expected_request = Transaction::Legacy { + let expected_request = Transaction::Legacy(TxLegacy { chain_id: Some(4), nonce: 1u64, gas_price: 1000000000, @@ -909,7 +947,7 @@ mod tests { )), value: 693361000000000u64.into(), input: Default::default(), - }; + }); let expected_signature = Signature { odd_y_parity: false, r: U256::from_str("e24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0a") @@ -923,7 +961,7 @@ mod tests { assert_eq!(expected, TransactionSigned::decode(bytes_second).unwrap()); let bytes_third = &mut &hex::decode("f86b0384773594008398968094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba0ce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071a03ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88").unwrap()[..]; - let expected_request = Transaction::Legacy { + let expected_request = Transaction::Legacy(TxLegacy { chain_id: Some(4), nonce: 3, gas_price: 2000000000, @@ -933,7 +971,7 @@ mod tests { )), value: 1000000000000000u64.into(), input: Bytes::default(), - }; + }); let expected_signature = Signature { odd_y_parity: false, @@ -948,7 +986,7 @@ mod tests { assert_eq!(expected, TransactionSigned::decode(bytes_third).unwrap()); let bytes_fourth = &mut &hex::decode("b87502f872041a8459682f008459682f0d8252089461815774383099e24810ab832a5b2a5425c154d58829a2241af62c000080c001a059e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafda0016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469").unwrap()[..]; - let expected = Transaction::Eip1559 { + let expected = Transaction::Eip1559(TxEip1559 { chain_id: 4, nonce: 26, max_priority_fee_per_gas: 1500000000, @@ -960,7 +998,7 @@ mod tests { value: 3000000000000000000u64.into(), input: Default::default(), access_list: Default::default(), - }; + }); let expected_signature = Signature { odd_y_parity: true, @@ -975,7 +1013,7 @@ mod tests { assert_eq!(expected, TransactionSigned::decode(bytes_fourth).unwrap()); let bytes_fifth = &mut &hex::decode("f8650f84832156008287fb94cf7f9e66af820a19257a2108375b180b0ec491678204d2802ca035b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981a0612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860").unwrap()[..]; - let expected = Transaction::Legacy { + let expected = Transaction::Legacy(TxLegacy { chain_id: Some(4), nonce: 15, gas_price: 2200000000, @@ -985,7 +1023,7 @@ mod tests { )), value: 1234u64.into(), input: Bytes::default(), - }; + }); let signature = Signature { odd_y_parity: true, r: U256::from_str("35b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981") @@ -1022,7 +1060,7 @@ mod tests { let hash: H256 = hex!("bb3a336e3f823ec18197f1e13ee875700f08f03e2cab75f0d0b118dabb44cba0").into(); - let tx = Transaction::Legacy { + let tx = Transaction::Legacy(TxLegacy { chain_id: Some(1), nonce: 0x18, gas_price: 0xfa56ea00, @@ -1030,7 +1068,7 @@ mod tests { to: TransactionKind::Call( hex!("06012c8cf97bead5deae237070f9587f8e7a266d").into()), value: 0x1c6bf526340000u64.into(), input: hex!("f7d8c88300000000000000000000000000000000000000000000000000000000000cee6100000000000000000000000000000000000000000000000000000000000ac3e1").into(), - }; + }); let sig = Signature { r: hex!("2a378831cf81d99a3f06a18ae1b6ca366817ab4d88a70053c41d7a8f0368e031").into(), @@ -1051,7 +1089,7 @@ mod tests { let hash: H256 = hex!("0ec0b6a2df4d87424e5f6ad2a654e27aaeb7dac20ae9e8385cc09087ad532ee0").into(); - let tx = Transaction::Eip1559 { + let tx = Transaction::Eip1559( TxEip1559 { chain_id: 1, nonce: 0x42, gas_limit: 44386, @@ -1061,7 +1099,7 @@ mod tests { max_fee_per_gas: 0x4a817c800, max_priority_fee_per_gas: 0x3b9aca00, access_list: AccessList::default(), - }; + }); let sig = Signature { r: hex!("840cfc572845f5786e702984c2a582528cad4b49b2a10b9db1be7fca90058565").into(), diff --git a/crates/primitives/src/transaction/signature.rs b/crates/primitives/src/transaction/signature.rs index 3116b93ccb..68ffd6639e 100644 --- a/crates/primitives/src/transaction/signature.rs +++ b/crates/primitives/src/transaction/signature.rs @@ -1,12 +1,14 @@ use crate::{transaction::util::secp256k1, Address, H256, U256}; -use reth_codecs::main_codec; +use bytes::Buf; +use modular_bitfield::prelude::*; +use reth_codecs::{main_codec, Compact}; use reth_rlp::{Decodable, DecodeError, Encodable}; /// r, s: Values corresponding to the signature of the /// transaction and used to determine the sender of /// the transaction; formally Tr and Ts. This is expanded in Appendix F of yellow paper. #[main_codec] -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] pub struct Signature { /// The R field of the signature; the point on the curve. pub r: U256, diff --git a/crates/primitives/src/transaction/tx_type.rs b/crates/primitives/src/transaction/tx_type.rs index 7a00dff9e0..1e17405b51 100644 --- a/crates/primitives/src/transaction/tx_type.rs +++ b/crates/primitives/src/transaction/tx_type.rs @@ -1,8 +1,8 @@ -use reth_codecs::{main_codec, Compact}; +use reth_codecs::Compact; +use serde::{Deserialize, Serialize}; /// Transaction Type -#[main_codec] -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)] pub enum TxType { /// Legacy transaction pre EIP-2929 #[default] diff --git a/crates/stages/src/error.rs b/crates/stages/src/error.rs index 9ab07435ce..a1bd0d60ab 100644 --- a/crates/stages/src/error.rs +++ b/crates/stages/src/error.rs @@ -66,6 +66,12 @@ pub enum DatabaseIntegrityError { /// The block number key number: BlockNumber, }, + /// The total difficulty from the block header is missing. + #[error("Total difficulty not found for block #{number}")] + TotalDifficulty { + /// The block number key + number: BlockNumber, + }, } /// A pipeline execution error. diff --git a/crates/stages/src/stages/headers.rs b/crates/stages/src/stages/headers.rs index 66cba852db..78c5108791 100644 --- a/crates/stages/src/stages/headers.rs +++ b/crates/stages/src/stages/headers.rs @@ -7,7 +7,7 @@ use reth_interfaces::{ db::{models::blocks::BlockNumHash, tables, Database, DbCursorRO, DbCursorRW, DbTx, DbTxMut}, p2p::headers::{client::HeadersClient, downloader::HeaderDownloader, error::DownloadError}, }; -use reth_primitives::{rpc::BigEndianHash, BlockNumber, SealedHeader, H256, U256}; +use reth_primitives::{BlockNumber, SealedHeader, H256, U256}; use std::{fmt::Debug, sync::Arc}; use tracing::*; @@ -119,8 +119,10 @@ impl HeaderStage { height: BlockNumber, ) -> Result<(), StageError> { let block_key = db.get_block_numhash(height)?; - let td: Vec = db.get::(block_key)?.unwrap(); // TODO: - self.client.update_status(height, block_key.hash(), H256::from_slice(&td).into_uint()); + let td: U256 = *db + .get::(block_key)? + .ok_or(DatabaseIntegrityError::TotalDifficulty { number: height })?; + self.client.update_status(height, block_key.hash(), td); Ok(()) } @@ -144,7 +146,7 @@ impl HeaderStage { let mut cursor_header = db.cursor_mut::()?; let mut cursor_canonical = db.cursor_mut::()?; let mut cursor_td = db.cursor_mut::()?; - let mut td = U256::from_big_endian(&cursor_td.last()?.map(|(_, v)| v).unwrap()); + let mut td: U256 = cursor_td.last()?.map(|(_, v)| v).unwrap().into(); let mut latest = None; // Since the headers were returned in descending order, @@ -165,7 +167,7 @@ impl HeaderStage { db.put::(block_hash, header.number)?; cursor_header.append(key, header)?; cursor_canonical.append(key.number(), key.hash())?; - cursor_td.append(key, H256::from_uint(&td).as_bytes().to_vec())?; + cursor_td.append(key, td.into())?; } Ok(latest) @@ -380,12 +382,10 @@ mod tests { let parent_td = tx.get::( (header.number - 1, header.parent_hash).into(), )?; - let td = tx.get::(key)?.unwrap(); + let td: U256 = *tx.get::(key)?.unwrap(); assert_eq!( - parent_td.map( - |td| U256::from_big_endian(&td) + header.difficulty - ), - Some(U256::from_big_endian(&td)) + parent_td.map(|td| *td + header.difficulty), + Some(td) ); } } diff --git a/crates/stages/src/test_utils/test_db.rs b/crates/stages/src/test_utils/test_db.rs index 3b05b56b65..a59272e938 100644 --- a/crates/stages/src/test_utils/test_db.rs +++ b/crates/stages/src/test_utils/test_db.rs @@ -5,7 +5,7 @@ use reth_db::{ use reth_interfaces::db::{ self, models::BlockNumHash, tables, DbCursorRO, DbCursorRW, DbTx, DbTxMut, Table, }; -use reth_primitives::{BigEndianHash, BlockNumber, SealedHeader, H256, U256}; +use reth_primitives::{BlockNumber, SealedHeader, U256}; use std::{borrow::Borrow, sync::Arc}; use crate::db::StageDB; @@ -167,9 +167,8 @@ impl TestStageDB { self.commit(|tx| { let headers = headers.collect::>(); - let mut td = U256::from_big_endian( - &tx.cursor::()?.last()?.map(|(_, v)| v).unwrap_or_default(), - ); + let mut td: U256 = + tx.cursor::()?.last()?.map(|(_, v)| v).unwrap_or_default().into(); for header in headers { let key: BlockNumHash = (header.number, header.hash()).into(); @@ -179,7 +178,7 @@ impl TestStageDB { tx.put::(key, header.clone().unseal())?; td += header.difficulty; - tx.put::(key, H256::from_uint(&td).as_bytes().to_vec())?; + tx.put::(key, td.into())?; } Ok(()) diff --git a/crates/transaction-pool/src/test_util/mock.rs b/crates/transaction-pool/src/test_util/mock.rs index de71464ea8..b4f3b1cd3f 100644 --- a/crates/transaction-pool/src/test_util/mock.rs +++ b/crates/transaction-pool/src/test_util/mock.rs @@ -12,8 +12,8 @@ use rand::{ prelude::Distribution, }; use reth_primitives::{ - Address, FromRecoveredTransaction, Transaction, TransactionSignedEcRecovered, TxHash, H256, - U256, + Address, FromRecoveredTransaction, Transaction, TransactionSignedEcRecovered, TxEip1559, + TxHash, TxLegacy, H256, U256, }; use std::{ops::Range, sync::Arc, time::Instant}; @@ -342,17 +342,23 @@ impl FromRecoveredTransaction for MockTransaction { let transaction = tx.into_signed(); let hash = transaction.hash; match transaction.transaction { - Transaction::Legacy { chain_id, nonce, gas_price, gas_limit, to, value, input } => { - MockTransaction::Legacy { - hash, - sender, - nonce, - gas_price: gas_price.into(), - gas_limit, - value: value.into(), - } - } - Transaction::Eip1559 { + Transaction::Legacy(TxLegacy { + chain_id, + nonce, + gas_price, + gas_limit, + to, + value, + input, + }) => MockTransaction::Legacy { + hash, + sender, + nonce, + gas_price: gas_price.into(), + gas_limit, + value: value.into(), + }, + Transaction::Eip1559(TxEip1559 { chain_id, nonce, gas_limit, @@ -362,7 +368,7 @@ impl FromRecoveredTransaction for MockTransaction { value, input, access_list, - } => MockTransaction::Eip1559 { + }) => MockTransaction::Eip1559 { hash, sender, nonce,