diff --git a/crates/scroll/chainspec/src/constants.rs b/crates/scroll/chainspec/src/constants.rs index d41916c5732..a95fba0ee46 100644 --- a/crates/scroll/chainspec/src/constants.rs +++ b/crates/scroll/chainspec/src/constants.rs @@ -5,6 +5,9 @@ use alloy_primitives::{address, b256, Address, B256}; /// The transaction fee recipient on the L2. pub const SCROLL_FEE_VAULT_ADDRESS: Address = address!("5300000000000000000000000000000000000005"); +/// The maximum size in bytes of the payload for a block. +pub const MAX_TX_PAYLOAD_BYTES_PER_BLOCK: usize = 120 * 1024; + /// The system contract on L2 mainnet. pub const SCROLL_MAINNET_L2_SYSTEM_CONFIG_CONTRACT_ADDRESS: Address = address!("331A873a2a85219863d80d248F9e2978fE88D0Ea"); diff --git a/crates/scroll/chainspec/src/genesis.rs b/crates/scroll/chainspec/src/genesis.rs index c82d8600893..c522461ec01 100644 --- a/crates/scroll/chainspec/src/genesis.rs +++ b/crates/scroll/chainspec/src/genesis.rs @@ -1,9 +1,13 @@ //! Scroll types for genesis data. use crate::{ - constants::{SCROLL_FEE_VAULT_ADDRESS, SCROLL_MAINNET_L1_CONFIG, SCROLL_SEPOLIA_L1_CONFIG}, + constants::{ + MAX_TX_PAYLOAD_BYTES_PER_BLOCK, SCROLL_FEE_VAULT_ADDRESS, SCROLL_MAINNET_L1_CONFIG, + SCROLL_SEPOLIA_L1_CONFIG, + }, SCROLL_DEV_L1_CONFIG, }; + use alloy_primitives::Address; use alloy_serde::OtherFields; use serde::de::Error; @@ -113,6 +117,8 @@ pub struct ScrollChainConfig { /// This is an optional field that, when set, specifies where L2 transaction fees /// will be sent or stored. pub fee_vault_address: Option
, + /// The maximum tx payload size of blocks that we produce. + pub max_tx_payload_bytes_per_block: usize, /// The L1 configuration. /// This field encapsulates specific settings and parameters required for L1 pub l1_config: L1Config, @@ -129,6 +135,7 @@ impl ScrollChainConfig { pub const fn mainnet() -> Self { Self { fee_vault_address: Some(SCROLL_FEE_VAULT_ADDRESS), + max_tx_payload_bytes_per_block: MAX_TX_PAYLOAD_BYTES_PER_BLOCK, l1_config: SCROLL_MAINNET_L1_CONFIG, } } @@ -137,13 +144,18 @@ impl ScrollChainConfig { pub const fn sepolia() -> Self { Self { fee_vault_address: Some(SCROLL_FEE_VAULT_ADDRESS), + max_tx_payload_bytes_per_block: MAX_TX_PAYLOAD_BYTES_PER_BLOCK, l1_config: SCROLL_SEPOLIA_L1_CONFIG, } } /// Returns the [`ScrollChainConfig`] for Scroll dev. pub const fn dev() -> Self { - Self { fee_vault_address: Some(SCROLL_FEE_VAULT_ADDRESS), l1_config: SCROLL_DEV_L1_CONFIG } + Self { + fee_vault_address: Some(SCROLL_FEE_VAULT_ADDRESS), + max_tx_payload_bytes_per_block: MAX_TX_PAYLOAD_BYTES_PER_BLOCK, + l1_config: SCROLL_DEV_L1_CONFIG, + } } } @@ -209,6 +221,7 @@ mod tests { "feynmanTime": 100, "scroll": { "feeVaultAddress": "0x5300000000000000000000000000000000000005", + "maxTxPayloadBytesPerBlock": 122880, "l1Config": { "l1ChainId": 1, "l1MessageQueueAddress": "0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B", @@ -237,6 +250,7 @@ mod tests { }), scroll_chain_config: ScrollChainConfig { fee_vault_address: Some(address!("5300000000000000000000000000000000000005")), + max_tx_payload_bytes_per_block: MAX_TX_PAYLOAD_BYTES_PER_BLOCK, l1_config: L1Config { l1_chain_id: 1, l1_message_queue_address: address!("0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B"), diff --git a/crates/scroll/chainspec/src/lib.rs b/crates/scroll/chainspec/src/lib.rs index 7668044ae61..ccd15550e99 100644 --- a/crates/scroll/chainspec/src/lib.rs +++ b/crates/scroll/chainspec/src/lib.rs @@ -34,10 +34,10 @@ extern crate alloc; mod constants; pub use constants::{ - SCROLL_BASE_FEE_PARAMS_FEYNMAN, SCROLL_DEV_L1_CONFIG, SCROLL_DEV_L1_MESSAGE_QUEUE_ADDRESS, - SCROLL_DEV_L1_MESSAGE_QUEUE_V2_ADDRESS, SCROLL_DEV_L1_PROXY_ADDRESS, - SCROLL_DEV_L2_SYSTEM_CONFIG_CONTRACT_ADDRESS, SCROLL_DEV_MAX_L1_MESSAGES, - SCROLL_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_FEYNMAN, + MAX_TX_PAYLOAD_BYTES_PER_BLOCK, SCROLL_BASE_FEE_PARAMS_FEYNMAN, SCROLL_DEV_L1_CONFIG, + SCROLL_DEV_L1_MESSAGE_QUEUE_ADDRESS, SCROLL_DEV_L1_MESSAGE_QUEUE_V2_ADDRESS, + SCROLL_DEV_L1_PROXY_ADDRESS, SCROLL_DEV_L2_SYSTEM_CONFIG_CONTRACT_ADDRESS, + SCROLL_DEV_MAX_L1_MESSAGES, SCROLL_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_FEYNMAN, SCROLL_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER_FEYNMAN, SCROLL_FEE_VAULT_ADDRESS, SCROLL_MAINNET_GENESIS_HASH, SCROLL_MAINNET_L1_CONFIG, SCROLL_MAINNET_L1_MESSAGE_QUEUE_ADDRESS, SCROLL_MAINNET_L1_MESSAGE_QUEUE_V2_ADDRESS, SCROLL_MAINNET_L1_PROXY_ADDRESS, @@ -624,26 +624,26 @@ mod tests { #[test] fn parse_scroll_hardforks() { let geth_genesis = r#" - { - "config": { - "bernoulliBlock": 10, - "curieBlock": 20, - "darwinTime": 30, - "darwinV2Time": 31, - "scroll": { - "feeVaultAddress": "0x5300000000000000000000000000000000000005", - "l1Config": { - "l1ChainId": 1, - "l1MessageQueueAddress": "0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B", - "l1MessageQueueV2Address": "0x56971da63A3C0205184FEF096E9ddFc7A8C2D18a", - "l2SystemConfigAddress": "0x331A873a2a85219863d80d248F9e2978fE88D0Ea", - "scrollChainAddress": "0xa13BAF47339d63B743e7Da8741db5456DAc1E556", - "numL1MessagesPerBlock": 10 + { + "config": { + "bernoulliBlock": 10, + "curieBlock": 20, + "darwinTime": 30, + "darwinV2Time": 31, + "scroll": { + "feeVaultAddress": "0x5300000000000000000000000000000000000005", + "maxTxPayloadBytesPerBlock": 122880, + "l1Config": { + "l1ChainId": 1, + "l1MessageQueueAddress": "0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B", + "l1MessageQueueV2Address": "0x56971da63A3C0205184FEF096E9ddFc7A8C2D18a", + "l2SystemConfigAddress": "0x331A873a2a85219863d80d248F9e2978fE88D0Ea", + "scrollChainAddress": "0xa13BAF47339d63B743e7Da8741db5456DAc1E556", + "numL1MessagesPerBlock": 10 + } + } } - } - } - } - "#; + }"#; let genesis: Genesis = serde_json::from_str(geth_genesis).unwrap(); let actual_bernoulli_block = genesis.config.extra_fields.get("bernoulliBlock"); @@ -659,6 +659,7 @@ mod tests { scroll_object, &serde_json::json!({ "feeVaultAddress": "0x5300000000000000000000000000000000000005", + "maxTxPayloadBytesPerBlock": 122880, "l1Config": { "l1ChainId": 1, "l1MessageQueueAddress": "0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B", @@ -712,6 +713,7 @@ mod tests { String::from("scroll"), serde_json::json!({ "feeVaultAddress": "0x5300000000000000000000000000000000000005", + "maxTxPayloadBytesPerBlock": 122880, "l1Config": { "l1ChainId": 1, "l1MessageQueueAddress": "0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B", diff --git a/crates/scroll/node/src/builder/pool.rs b/crates/scroll/node/src/builder/pool.rs index 8152a5fe5e7..70faed0f901 100644 --- a/crates/scroll/node/src/builder/pool.rs +++ b/crates/scroll/node/src/builder/pool.rs @@ -68,6 +68,7 @@ where .with_local_transactions_config( pool_config_overrides.clone().apply(ctx.pool_config()).local_transactions_config, ) + .with_max_tx_input_bytes(ctx.chain_spec().chain_config().max_tx_payload_bytes_per_block) .with_additional_tasks( pool_config_overrides .additional_validation_tasks @@ -130,3 +131,158 @@ where Ok(transaction_pool) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::ScrollNode; + + use alloy_consensus::{transaction::Recovered, Header, Signed, TxLegacy}; + use alloy_primitives::{private::rand::random_iter, Bytes, Signature, B256, U256}; + use reth_chainspec::Head; + use reth_db::mock::DatabaseMock; + use reth_node_api::FullNodeTypesAdapter; + use reth_node_builder::common::WithConfigs; + use reth_node_core::node_config::NodeConfig; + use reth_primitives_traits::{ + transaction::error::InvalidTransactionError, GotExpected, GotExpectedBoxed, + }; + use reth_provider::{ + noop::NoopProvider, + test_utils::{ExtendedAccount, MockEthProvider}, + }; + use reth_scroll_chainspec::{ScrollChainSpec, SCROLL_DEV, SCROLL_MAINNET}; + use reth_scroll_primitives::{ScrollBlock, ScrollPrimitives}; + use reth_scroll_txpool::ScrollPooledTransaction; + use reth_tasks::TaskManager; + use reth_transaction_pool::{ + blobstore::NoopBlobStore, + error::{InvalidPoolTransactionError, PoolErrorKind}, + PoolConfig, TransactionOrigin, TransactionPool, + }; + use scroll_alloy_consensus::ScrollTxEnvelope; + use scroll_alloy_evm::curie::L1_GAS_PRICE_ORACLE_ADDRESS; + + async fn pool() -> ( + ScrollTransactionPool, DiskFileBlobStore>, + TaskManager, + ) { + let handle = tokio::runtime::Handle::current(); + let manager = TaskManager::new(handle); + let config = WithConfigs { + config: NodeConfig::new(SCROLL_MAINNET.clone()), + toml_config: Default::default(), + }; + + let pool_builder = ScrollPoolBuilder::::default(); + let ctx = BuilderContext::< + FullNodeTypesAdapter< + ScrollNode, + DatabaseMock, + NoopProvider, + >, + >::new( + Head::default(), + NoopProvider::new(SCROLL_MAINNET.clone()), + manager.executor(), + config, + ); + (pool_builder.build_pool(&ctx).await.unwrap(), manager) + } + + #[tokio::test] + async fn test_validate_one_oversized_transaction() { + // create the pool. + let (pool, manager) = pool().await; + let tx = ScrollTxEnvelope::Legacy(Signed::new_unchecked( + TxLegacy { gas_limit: 21_000, ..Default::default() }, + Signature::new(U256::ZERO, U256::ZERO, false), + Default::default(), + )); + + // Create a pool transaction with an encoded length of 123,904 bytes. + let pool_tx = ScrollPooledTransaction::new( + Recovered::new_unchecked(tx, Default::default()), + 121 * 1024, + ); + + // add the transaction to the pool and expect an `OversizedData` error. + let err = pool.add_transaction(TransactionOrigin::Local, pool_tx).await.unwrap_err(); + assert!(matches!( + err.kind, + PoolErrorKind::InvalidTransaction( + InvalidPoolTransactionError::OversizedData(x, y,) + ) if x == 121*1024 && y == 120*1024, + )); + + // explicitly drop the manager here otherwise the `TransactionValidationTaskExecutor` will + // drop all validation tasks. + drop(manager); + } + + #[tokio::test] + async fn test_validate_one_rollup_fee_exceeds_balance() { + // create the client. + let handle = tokio::runtime::Handle::current(); + let manager = TaskManager::new(handle); + let blob_store = NoopBlobStore::default(); + let signer = Default::default(); + let client = + MockEthProvider::::new().with_chain_spec(SCROLL_DEV.clone()); + let hash = B256::random(); + + // load a header, block, signer and the L1_GAS_PRICE_ORACLE_ADDRESS storage. + client.add_header(hash, Header::default()); + client.add_block(hash, ScrollBlock::default()); + client.add_account(signer, ExtendedAccount::new(0, U256::from(400_000))); + client.add_account( + L1_GAS_PRICE_ORACLE_ADDRESS, + ExtendedAccount::new(0, U256::from(400_000)).extend_storage( + (0u8..8).map(|k| (B256::from(U256::from(k)), U256::from(u64::MAX))), + ), + ); + + // create the validation task. + let validator = TransactionValidationTaskExecutor::eth_builder(client) + .no_eip4844() + .build_with_tasks(manager.executor(), blob_store) + .map(|validator| { + ScrollTransactionValidator::new(validator).require_l1_data_gas_fee(true) + }); + + // create the pool. + let pool = ScrollTransactionPool::new( + validator, + CoinbaseTipOrdering::::default(), + NoopBlobStore::default(), + PoolConfig::default(), + ); + + // prepare a transaction with random input. + let tx = ScrollTxEnvelope::Legacy(Signed::new_unchecked( + TxLegacy { + gas_limit: 55_000, + gas_price: 7, + input: Bytes::from(random_iter::().take(100).collect::>()), + ..Default::default() + }, + Signature::new(U256::ZERO, U256::ZERO, false), + Default::default(), + )); + let pool_tx = + ScrollPooledTransaction::new(Recovered::new_unchecked(tx, signer), 120 * 1024); + + // add the transaction in the pool and expect to hit `InsufficientFunds` error. + let err = pool.add_transaction(TransactionOrigin::Local, pool_tx).await.unwrap_err(); + assert!(matches!( + err.kind, + PoolErrorKind::InvalidTransaction( + InvalidPoolTransactionError::Consensus(InvalidTransactionError::InsufficientFunds(GotExpectedBoxed(expected))) + ) if *expected == GotExpected{ got: U256::from(400000), expected: U256::from_limbs([384999, 1, 0, 0]) } + )); + + // explicitly drop the manager here otherwise the `TransactionValidationTaskExecutor` will + // drop all validation tasks. + drop(manager); + } +} diff --git a/crates/scroll/node/src/test_utils.rs b/crates/scroll/node/src/test_utils.rs index 1e7141895f5..be464870cbf 100644 --- a/crates/scroll/node/src/test_utils.rs +++ b/crates/scroll/node/src/test_utils.rs @@ -9,7 +9,7 @@ use reth_node_api::NodeTypesWithDBAdapter; use reth_payload_builder::EthPayloadBuilderAttributes; use reth_provider::providers::BlockchainProvider; -use reth_scroll_chainspec::ScrollChainSpecBuilder; +use reth_scroll_chainspec::{ScrollChainConfig, ScrollChainSpecBuilder}; use reth_tasks::TaskManager; use scroll_alloy_rpc_types_engine::BlockDataHint; use std::sync::Arc; @@ -31,10 +31,12 @@ pub async fn setup( reth_e2e_test_utils::setup_engine( num_nodes, Arc::new( - ScrollChainSpecBuilder::scroll_mainnet() - .genesis(genesis) - .euclid_v2_activated() - .build(Default::default()), + ScrollChainSpecBuilder::scroll_mainnet().genesis(genesis).euclid_v2_activated().build( + ScrollChainConfig { + max_tx_payload_bytes_per_block: 120 * 1024, + ..Default::default() + }, + ), ), is_dev, Default::default(), diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index 68f8c38e59d..7636b27db4a 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -5,7 +5,7 @@ use crate::{ StateProvider, StateProviderBox, StateProviderFactory, StateReader, StateRootProvider, TransactionVariant, TransactionsProvider, }; -use alloy_consensus::{constants::EMPTY_ROOT_HASH, transaction::TransactionMeta, Header}; +use alloy_consensus::{constants::EMPTY_ROOT_HASH, transaction::TransactionMeta, BlockHeader}; use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumberOrTag}; use alloy_primitives::{ keccak256, map::HashMap, Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue, @@ -19,11 +19,12 @@ use reth_db_api::{ models::{AccountBeforeTx, StoredBlockBodyIndices}, }; use reth_ethereum_engine_primitives::EthEngineTypes; -use reth_ethereum_primitives::{EthPrimitives, Receipt}; +use reth_ethereum_primitives::EthPrimitives; use reth_execution_types::ExecutionOutcome; use reth_node_types::NodeTypes; use reth_primitives_traits::{ - Account, Bytecode, GotExpected, NodePrimitives, RecoveredBlock, SealedHeader, SignerRecoverable, + Account, Block, BlockBody, Bytecode, GotExpected, NodePrimitives, RecoveredBlock, SealedHeader, + SignedTransaction, SignerRecoverable, }; use reth_prune_types::PruneModes; use reth_stages_types::{StageCheckpoint, StageId}; @@ -48,16 +49,14 @@ use tokio::sync::broadcast; /// A mock implementation for Provider interfaces. #[derive(Debug)] -pub struct MockEthProvider< - T: NodePrimitives = reth_ethereum_primitives::EthPrimitives, - ChainSpec = reth_chainspec::ChainSpec, -> { +pub struct MockEthProvider +{ ///local block store pub blocks: Arc>>, /// Local header store - pub headers: Arc>>, + pub headers: Arc::Header>>>, /// Local receipt store indexed by block number - pub receipts: Arc>>>, + pub receipts: Arc>>>, /// Local account store pub accounts: Arc>>, /// Local chain spec @@ -106,31 +105,31 @@ impl MockEthProvider { } } -impl MockEthProvider { +impl MockEthProvider { /// Add block to local block store - pub fn add_block(&self, hash: B256, block: reth_ethereum_primitives::Block) { - self.add_header(hash, block.header.clone()); + pub fn add_block(&self, hash: B256, block: T::Block) { + self.add_header(hash, block.header().clone()); self.blocks.lock().insert(hash, block); } /// Add multiple blocks to local block store - pub fn extend_blocks( - &self, - iter: impl IntoIterator, - ) { + pub fn extend_blocks(&self, iter: impl IntoIterator) { for (hash, block) in iter { - self.add_header(hash, block.header.clone()); + self.add_header(hash, block.header().clone()); self.add_block(hash, block) } } /// Add header to local header store - pub fn add_header(&self, hash: B256, header: Header) { + pub fn add_header(&self, hash: B256, header: ::Header) { self.headers.lock().insert(hash, header); } /// Add multiple headers to local header store - pub fn extend_headers(&self, iter: impl IntoIterator) { + pub fn extend_headers( + &self, + iter: impl IntoIterator::Header)>, + ) { for (hash, header) in iter { self.add_header(hash, header) } @@ -149,12 +148,12 @@ impl MockEthProvider) { + pub fn add_receipts(&self, block_number: BlockNumber, receipts: Vec) { self.receipts.lock().insert(block_number, receipts); } /// Add multiple receipts to local receipt store - pub fn extend_receipts(&self, iter: impl IntoIterator)>) { + pub fn extend_receipts(&self, iter: impl IntoIterator)>) { for (block_number, receipts) in iter { self.add_receipts(block_number, receipts); } @@ -175,10 +174,7 @@ impl MockEthProvider( - self, - chain_spec: C, - ) -> MockEthProvider { + pub fn with_chain_spec(self, chain_spec: C) -> MockEthProvider { MockEthProvider { blocks: self.blocks, headers: self.headers, @@ -300,27 +296,27 @@ impl DBProvider } } -impl HeaderProvider - for MockEthProvider +impl HeaderProvider + for MockEthProvider { - type Header = Header; + type Header = ::Header; - fn header(&self, block_hash: &BlockHash) -> ProviderResult> { + fn header(&self, block_hash: &BlockHash) -> ProviderResult> { let lock = self.headers.lock(); Ok(lock.get(block_hash).cloned()) } - fn header_by_number(&self, num: u64) -> ProviderResult> { + fn header_by_number(&self, num: u64) -> ProviderResult> { let lock = self.headers.lock(); - Ok(lock.values().find(|h| h.number == num).cloned()) + Ok(lock.values().find(|h| h.number() == num).cloned()) } fn header_td(&self, hash: &BlockHash) -> ProviderResult> { let lock = self.headers.lock(); Ok(lock.get(hash).map(|target| { lock.values() - .filter(|h| h.number < target.number) - .fold(target.difficulty, |td, h| td + h.difficulty) + .filter(|h| h.number() < target.number()) + .fold(target.difficulty(), |td, h| td + h.difficulty()) })) } @@ -328,30 +324,36 @@ impl HeaderProvider let lock = self.headers.lock(); let sum = lock .values() - .filter(|h| h.number <= number) - .fold(U256::ZERO, |td, h| td + h.difficulty); + .filter(|h| h.number() <= number) + .fold(U256::ZERO, |td, h| td + h.difficulty()); Ok(Some(sum)) } - fn headers_range(&self, range: impl RangeBounds) -> ProviderResult> { + fn headers_range( + &self, + range: impl RangeBounds, + ) -> ProviderResult> { let lock = self.headers.lock(); let mut headers: Vec<_> = - lock.values().filter(|header| range.contains(&header.number)).cloned().collect(); - headers.sort_by_key(|header| header.number); + lock.values().filter(|header| range.contains(&header.number())).cloned().collect(); + headers.sort_by_key(|header| header.number()); Ok(headers) } - fn sealed_header(&self, number: BlockNumber) -> ProviderResult> { + fn sealed_header( + &self, + number: BlockNumber, + ) -> ProviderResult>> { Ok(self.header_by_number(number)?.map(SealedHeader::seal_slow)) } fn sealed_headers_while( &self, range: impl RangeBounds, - mut predicate: impl FnMut(&SealedHeader) -> bool, - ) -> ProviderResult> { + mut predicate: impl FnMut(&SealedHeader) -> bool, + ) -> ProviderResult>> { Ok(self .headers_range(range)? .into_iter() @@ -373,16 +375,16 @@ where } } -impl TransactionsProvider - for MockEthProvider +impl TransactionsProvider + for MockEthProvider { - type Transaction = reth_ethereum_primitives::TransactionSigned; + type Transaction = T::SignedTx; fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult> { let lock = self.blocks.lock(); let tx_number = lock .values() - .flat_map(|block| &block.body.transactions) + .flat_map(|block| block.body().transactions()) .position(|tx| *tx.tx_hash() == tx_hash) .map(|pos| pos as TxNumber); @@ -392,7 +394,7 @@ impl TransactionsProvider fn transaction_by_id(&self, id: TxNumber) -> ProviderResult> { let lock = self.blocks.lock(); let transaction = - lock.values().flat_map(|block| &block.body.transactions).nth(id as usize).cloned(); + lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned(); Ok(transaction) } @@ -403,14 +405,14 @@ impl TransactionsProvider ) -> ProviderResult> { let lock = self.blocks.lock(); let transaction = - lock.values().flat_map(|block| &block.body.transactions).nth(id as usize).cloned(); + lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned(); Ok(transaction) } fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult> { Ok(self.blocks.lock().iter().find_map(|(_, block)| { - block.body.transactions.iter().find(|tx| *tx.tx_hash() == hash).cloned() + block.body().transactions_iter().find(|tx| *tx.tx_hash() == hash).cloned() })) } @@ -420,16 +422,16 @@ impl TransactionsProvider ) -> ProviderResult> { let lock = self.blocks.lock(); for (block_hash, block) in lock.iter() { - for (index, tx) in block.body.transactions.iter().enumerate() { + for (index, tx) in block.body().transactions_iter().enumerate() { if *tx.tx_hash() == hash { let meta = TransactionMeta { tx_hash: hash, index: index as u64, block_hash: *block_hash, - block_number: block.header.number, - base_fee: block.header.base_fee_per_gas, - excess_blob_gas: block.header.excess_blob_gas, - timestamp: block.header.timestamp, + block_number: block.header().number(), + base_fee: block.header().base_fee_per_gas(), + excess_blob_gas: block.header().excess_blob_gas(), + timestamp: block.header().timestamp(), }; return Ok(Some((tx.clone(), meta))) } @@ -442,10 +444,10 @@ impl TransactionsProvider let lock = self.blocks.lock(); let mut current_tx_number: TxNumber = 0; for block in lock.values() { - if current_tx_number + (block.body.transactions.len() as TxNumber) > id { - return Ok(Some(block.header.number)) + if current_tx_number + (block.body().transaction_count() as TxNumber) > id { + return Ok(Some(block.header().number())) } - current_tx_number += block.body.transactions.len() as TxNumber; + current_tx_number += block.body().transaction_count() as TxNumber; } Ok(None) } @@ -454,7 +456,7 @@ impl TransactionsProvider &self, id: BlockHashOrNumber, ) -> ProviderResult>> { - Ok(self.block(id)?.map(|b| b.body.transactions)) + Ok(self.block(id)?.map(|b| b.body().clone_transactions())) } fn transactions_by_block_range( @@ -464,8 +466,8 @@ impl TransactionsProvider // init btreemap so we can return in order let mut map = BTreeMap::new(); for (_, block) in self.blocks.lock().iter() { - if range.contains(&block.number) { - map.insert(block.number, block.body.transactions.clone()); + if range.contains(&block.header().number()) { + map.insert(block.header().number(), block.body().clone_transactions()); } } @@ -479,7 +481,7 @@ impl TransactionsProvider let lock = self.blocks.lock(); let transactions = lock .values() - .flat_map(|block| &block.body.transactions) + .flat_map(|block| block.body().transactions()) .enumerate() .filter(|&(tx_number, _)| range.contains(&(tx_number as TxNumber))) .map(|(_, tx)| tx.clone()) @@ -495,7 +497,7 @@ impl TransactionsProvider let lock = self.blocks.lock(); let transactions = lock .values() - .flat_map(|block| &block.body.transactions) + .flat_map(|block| block.body().transactions()) .enumerate() .filter_map(|(tx_number, tx)| { if range.contains(&(tx_number as TxNumber)) { @@ -519,7 +521,7 @@ where T: NodePrimitives, ChainSpec: Send + Sync + 'static, { - type Receipt = Receipt; + type Receipt = T::Receipt; fn receipt(&self, _id: TxNumber) -> ProviderResult> { Ok(None) @@ -540,7 +542,7 @@ where // Find block number by hash first let headers_lock = self.headers.lock(); if let Some(header) = headers_lock.get(&hash) { - Ok(receipts_lock.get(&header.number).cloned()) + Ok(receipts_lock.get(&header.number()).cloned()) } else { Ok(None) } @@ -566,7 +568,7 @@ where let mut result = Vec::new(); for block_number in block_range { // Only include blocks that exist in headers (i.e., have been added to the provider) - if headers_lock.values().any(|header| header.number == block_number) { + if headers_lock.values().any(|header| header.number() == block_number) { if let Some(block_receipts) = receipts_lock.get(&block_number) { result.push(block_receipts.clone()); } else { @@ -593,7 +595,7 @@ impl BlockHashReader fn block_hash(&self, number: u64) -> ProviderResult> { let lock = self.headers.lock(); let hash = - lock.iter().find_map(|(hash, header)| (header.number == number).then_some(*hash)); + lock.iter().find_map(|(hash, header)| (header.number() == number).then_some(*hash)); Ok(hash) } @@ -604,9 +606,9 @@ impl BlockHashReader ) -> ProviderResult> { let lock = self.headers.lock(); let mut hashes: Vec<_> = - lock.iter().filter(|(_, header)| (start..end).contains(&header.number)).collect(); + lock.iter().filter(|(_, header)| (start..end).contains(&header.number())).collect(); - hashes.sort_by_key(|(_, header)| header.number); + hashes.sort_by_key(|(_, header)| header.number()); Ok(hashes.into_iter().map(|(hash, _)| *hash).collect()) } @@ -621,16 +623,16 @@ impl BlockNumReader Ok(lock .iter() - .find(|(_, header)| header.number == best_block_number) - .map(|(hash, header)| ChainInfo { best_hash: *hash, best_number: header.number }) + .find(|(_, header)| header.number() == best_block_number) + .map(|(hash, header)| ChainInfo { best_hash: *hash, best_number: header.number() }) .unwrap_or_default()) } fn best_block_number(&self) -> ProviderResult { let lock = self.headers.lock(); lock.iter() - .max_by_key(|h| h.1.number) - .map(|(_, header)| header.number) + .max_by_key(|h| h.1.number()) + .map(|(_, header)| header.number()) .ok_or(ProviderError::BestBlockNotFound) } @@ -640,7 +642,7 @@ impl BlockNumReader fn block_number(&self, hash: B256) -> ProviderResult> { let lock = self.headers.lock(); - Ok(lock.get(&hash).map(|header| header.number)) + Ok(lock.get(&hash).map(|header| header.number())) } } @@ -661,10 +663,10 @@ impl BlockId } //look -impl BlockReader - for MockEthProvider +impl BlockReader + for MockEthProvider { - type Block = reth_ethereum_primitives::Block; + type Block = T::Block; fn find_block_by_hash( &self, @@ -678,7 +680,9 @@ impl BlockReader let lock = self.blocks.lock(); match id { BlockHashOrNumber::Hash(hash) => Ok(lock.get(&hash).cloned()), - BlockHashOrNumber::Number(num) => Ok(lock.values().find(|b| b.number == num).cloned()), + BlockHashOrNumber::Number(num) => { + Ok(lock.values().find(|b| b.header().number() == num).cloned()) + } } } @@ -688,7 +692,7 @@ impl BlockReader fn pending_block_and_receipts( &self, - ) -> ProviderResult, Vec)>> { + ) -> ProviderResult, Vec)>> { Ok(None) } @@ -711,9 +715,12 @@ impl BlockReader fn block_range(&self, range: RangeInclusive) -> ProviderResult> { let lock = self.blocks.lock(); - let mut blocks: Vec<_> = - lock.values().filter(|block| range.contains(&block.number)).cloned().collect(); - blocks.sort_by_key(|block| block.number); + let mut blocks: Vec<_> = lock + .values() + .filter(|block| range.contains(&block.header().number())) + .cloned() + .collect(); + blocks.sort_by_key(|block| block.header().number()); Ok(blocks) } @@ -733,26 +740,29 @@ impl BlockReader } } -impl BlockReaderIdExt - for MockEthProvider +impl BlockReaderIdExt for MockEthProvider where ChainSpec: EthChainSpec + Send + Sync + 'static, + T: NodePrimitives, { - fn block_by_id(&self, id: BlockId) -> ProviderResult> { + fn block_by_id(&self, id: BlockId) -> ProviderResult> { match id { BlockId::Number(num) => self.block_by_number_or_tag(num), BlockId::Hash(hash) => self.block_by_hash(hash.block_hash), } } - fn sealed_header_by_id(&self, id: BlockId) -> ProviderResult> { + fn sealed_header_by_id( + &self, + id: BlockId, + ) -> ProviderResult::Header>>> { self.header_by_id(id)?.map_or_else(|| Ok(None), |h| Ok(Some(SealedHeader::seal_slow(h)))) } - fn header_by_id(&self, id: BlockId) -> ProviderResult> { + fn header_by_id(&self, id: BlockId) -> ProviderResult::Header>> { match self.block_by_id(id)? { None => Ok(None), - Some(block) => Ok(Some(block.header)), + Some(block) => Ok(Some(block.into_header())), } } } @@ -989,9 +999,12 @@ impl ChangeSetReader for MockEthProvi } impl StateReader for MockEthProvider { - type Receipt = Receipt; + type Receipt = T::Receipt; - fn get_state(&self, _block: BlockNumber) -> ProviderResult> { + fn get_state( + &self, + _block: BlockNumber, + ) -> ProviderResult>> { Ok(None) } } @@ -1019,7 +1032,7 @@ mod tests { #[test] fn test_mock_provider_receipts() { - let provider = MockEthProvider::new(); + let provider = MockEthProvider::::new(); let block_hash = BlockHash::random(); let block_number = 1u64; @@ -1050,7 +1063,7 @@ mod tests { #[test] fn test_mock_provider_receipts_multiple_blocks() { - let provider = MockEthProvider::new(); + let provider = MockEthProvider::::new(); let block1_hash = BlockHash::random(); let block2_hash = BlockHash::random();