From 17dee72c3a8339caddeb2b37f6b3b74c8f8d38de Mon Sep 17 00:00:00 2001 From: joshie <93316087+joshieDo@users.noreply.github.com> Date: Mon, 20 Jan 2025 12:25:46 +0000 Subject: [PATCH] add withdrawals_by_block_range --- .../src/providers/blockchain_provider.rs | 7 ++++ .../provider/src/providers/consistent.rs | 22 +++++++++++ .../provider/src/providers/database/mod.rs | 18 +++++++++ .../src/providers/database/provider.rs | 18 +++++++++ .../provider/src/providers/static_file/jar.rs | 18 +++++++++ .../src/providers/static_file/manager.rs | 16 +++++++- .../storage/provider/src/test_utils/mock.rs | 7 ++++ crates/storage/storage-api/src/chain.rs | 38 ++++++++++--------- crates/storage/storage-api/src/noop.rs | 7 ++++ crates/storage/storage-api/src/withdrawals.rs | 8 ++++ 10 files changed, 141 insertions(+), 18 deletions(-) diff --git a/crates/storage/provider/src/providers/blockchain_provider.rs b/crates/storage/provider/src/providers/blockchain_provider.rs index 92451fab15e7..d9c56138fb86 100644 --- a/crates/storage/provider/src/providers/blockchain_provider.rs +++ b/crates/storage/provider/src/providers/blockchain_provider.rs @@ -457,6 +457,13 @@ impl WithdrawalsProvider for BlockchainProvider { ) -> ProviderResult> { self.consistent_provider()?.withdrawals_by_block(id, timestamp) } + + fn withdrawals_by_block_range( + &self, + range: RangeInclusive, + ) -> ProviderResult> { + self.consistent_provider()?.withdrawals_by_block_range(range) + } } impl OmmersProvider for BlockchainProvider { diff --git a/crates/storage/provider/src/providers/consistent.rs b/crates/storage/provider/src/providers/consistent.rs index 3082faf45b51..6af505d972bf 100644 --- a/crates/storage/provider/src/providers/consistent.rs +++ b/crates/storage/provider/src/providers/consistent.rs @@ -1151,6 +1151,28 @@ impl WithdrawalsProvider for ConsistentProvider { }, ) } + + fn withdrawals_by_block_range( + &self, + range: RangeInclusive, + ) -> ProviderResult> { + self.get_in_memory_or_storage_by_block_range_while( + range, + |db_provider, range, _| db_provider.withdrawals_by_block_range(range), + |block_state, _| { + Some( + block_state + .block_ref() + .recovered_block() + .body() + .withdrawals() + .cloned() + .unwrap_or_default(), + ) + }, + |_| true, + ) + } } impl OmmersProvider for ConsistentProvider { diff --git a/crates/storage/provider/src/providers/database/mod.rs b/crates/storage/provider/src/providers/database/mod.rs index 157922b50362..a78401653a80 100644 --- a/crates/storage/provider/src/providers/database/mod.rs +++ b/crates/storage/provider/src/providers/database/mod.rs @@ -549,6 +549,24 @@ impl WithdrawalsProvider for ProviderFactory { ) -> ProviderResult> { self.provider()?.withdrawals_by_block(id, timestamp) } + + fn withdrawals_by_block_range( + &self, + range: RangeInclusive, + ) -> ProviderResult> { + self.static_file_provider.get_range_with_static_file_or_database( + StaticFileSegment::BlockMeta, + *range.start()..*range.end() + 1, + |static_file, range, _| { + static_file.withdrawals_by_block_range(range.start..=range.end.saturating_sub(1)) + }, + |range, _| { + self.provider()? + .withdrawals_by_block_range(range.start..=range.end.saturating_sub(1)) + }, + |_| true, + ) + } } impl OmmersProvider for ProviderFactory { diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 31105c33665b..57c4a5d9e367 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -1593,6 +1593,24 @@ impl> Withdrawals } Ok(None) } + + fn withdrawals_by_block_range( + &self, + range: RangeInclusive, + ) -> ProviderResult> { + self.static_file_provider.get_range_with_static_file_or_database( + StaticFileSegment::BlockMeta, + *range.start()..*range.end() + 1, + |static_file, range, _| { + static_file.withdrawals_by_block_range(range.start..=range.end.saturating_sub(1)) + }, + |range, _| { + self.cursor_read_collect::(range) + .map(|w| w.into_iter().map(|w| w.withdrawals).collect()) + }, + |_| true, + ) + } } impl OmmersProvider for DatabaseProvider { diff --git a/crates/storage/provider/src/providers/static_file/jar.rs b/crates/storage/provider/src/providers/static_file/jar.rs index 4b6525c1d1dc..d4357404a1ef 100644 --- a/crates/storage/provider/src/providers/static_file/jar.rs +++ b/crates/storage/provider/src/providers/static_file/jar.rs @@ -367,6 +367,24 @@ impl WithdrawalsProvider for StaticFileJarProvider<'_, N> { // Only accepts block number queries Err(ProviderError::UnsupportedProvider) } + + fn withdrawals_by_block_range( + &self, + range: RangeInclusive, + ) -> ProviderResult> { + let mut cursor = self.cursor()?; + let mut withdrawals_by_block = + Vec::with_capacity((range.end() - range.start() + 1) as usize); + + for num in range { + if let Some(withdrawals) = + cursor.get_one::(num.into())?.map(|w| w.withdrawals) + { + withdrawals_by_block.push(withdrawals) + } + } + Ok(withdrawals_by_block) + } } impl> OmmersProvider for StaticFileJarProvider<'_, N> { diff --git a/crates/storage/provider/src/providers/static_file/manager.rs b/crates/storage/provider/src/providers/static_file/manager.rs index 51b68f8f2cc6..87fa0bd03385 100644 --- a/crates/storage/provider/src/providers/static_file/manager.rs +++ b/crates/storage/provider/src/providers/static_file/manager.rs @@ -18,7 +18,7 @@ use reth_db::{ lockfile::StorageLock, static_file::{ iter_static_files, BlockHashMask, BodyIndicesMask, HeaderMask, HeaderWithHashMask, - ReceiptMask, StaticFileCursor, TDWithHashMask, TransactionMask, + ReceiptMask, StaticFileCursor, TDWithHashMask, TransactionMask, WithdrawalsMask, }, table::{Decompress, Value}, tables, @@ -1696,6 +1696,20 @@ impl WithdrawalsProvider for StaticFileProvider { // Only accepts block number queries Err(ProviderError::UnsupportedProvider) } + + fn withdrawals_by_block_range( + &self, + range: RangeInclusive, + ) -> ProviderResult> { + self.fetch_range_with_predicate( + StaticFileSegment::BlockMeta, + *range.start()..*range.end() + 1, + |cursor, number| { + cursor.get_one::(number.into()).map(|w| w.map(|w| w.withdrawals)) + }, + |_| true, + ) + } } impl> OmmersProvider for StaticFileProvider { diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index e6efe8012492..02c8103129c0 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -765,6 +765,13 @@ impl WithdrawalsProvider for MockEthProvider { ) -> ProviderResult> { Ok(None) } + + fn withdrawals_by_block_range( + &self, + _range: RangeInclusive, + ) -> ProviderResult> { + Ok(vec![]) + } } impl OmmersProvider for MockEthProvider { diff --git a/crates/storage/storage-api/src/chain.rs b/crates/storage/storage-api/src/chain.rs index cb2b38dc7b41..5fff2ff889cd 100644 --- a/crates/storage/storage-api/src/chain.rs +++ b/crates/storage/storage-api/src/chain.rs @@ -1,12 +1,12 @@ -use crate::{DBProvider, OmmersProvider, StorageLocation}; -use alloy_consensus::Header; +use crate::{DBProvider, OmmersProvider, StorageLocation, WithdrawalsProvider}; +use alloy_consensus::{BlockHeader, Header}; use alloy_primitives::BlockNumber; use reth_chainspec::{ChainSpecProvider, EthereumHardforks}; use reth_db::{ - cursor::{DbCursorRO, DbCursorRW}, + cursor::DbCursorRW, models::{StoredBlockOmmers, StoredBlockWithdrawals}, tables, - transaction::{DbTx, DbTxMut}, + transaction::DbTxMut, DbTxUnwindExt, }; use reth_primitives::TransactionSigned; @@ -141,7 +141,8 @@ impl BlockBodyReader for EthStorage where Provider: DBProvider + ChainSpecProvider - + OmmersProvider
, + + OmmersProvider
+ + WithdrawalsProvider, T: SignedTransaction, { type Block = reth_primitives::Block; @@ -151,25 +152,28 @@ where provider: &Provider, inputs: Vec>, ) -> ProviderResult::Body>> { + if inputs.is_empty() { + return Ok(vec![]) + } + + let block_range = inputs + .first() + .and_then(|(first, _)| inputs.last().map(|(last, _)| first.number()..=last.number())) + .expect("qed"); + // TODO: Ideally storage should hold its own copy of chain spec let chain_spec = provider.chain_spec(); - let mut withdrawals_cursor = provider.tx_ref().cursor_read::()?; - let mut bodies = Vec::with_capacity(inputs.len()); - for (header, transactions) in inputs { + for ((header, transactions), withdrawals) in + inputs.into_iter().zip(provider.withdrawals_by_block_range(block_range)?) + { // If we are past shanghai, then all blocks should have a withdrawal list, // even if empty - let withdrawals = if chain_spec.is_shanghai_active_at_timestamp(header.timestamp) { - withdrawals_cursor - .seek_exact(header.number)? - .map(|(_, w)| w.withdrawals) - .unwrap_or_default() - .into() - } else { - None - }; + let withdrawals = + chain_spec.is_shanghai_active_at_timestamp(header.timestamp).then_some(withdrawals); + let ommers = if chain_spec.final_paris_total_difficulty(header.number).is_some() { Vec::new() } else { diff --git a/crates/storage/storage-api/src/noop.rs b/crates/storage/storage-api/src/noop.rs index 20d975852f4d..01e09075b951 100644 --- a/crates/storage/storage-api/src/noop.rs +++ b/crates/storage/storage-api/src/noop.rs @@ -538,6 +538,13 @@ impl WithdrawalsProvider for NoopProvider ProviderResult> { Ok(None) } + + fn withdrawals_by_block_range( + &self, + _range: RangeInclusive, + ) -> ProviderResult> { + Ok(vec![]) + } } impl OmmersProvider for NoopProvider { diff --git a/crates/storage/storage-api/src/withdrawals.rs b/crates/storage/storage-api/src/withdrawals.rs index fdfb27aa7072..681a8e9eac43 100644 --- a/crates/storage/storage-api/src/withdrawals.rs +++ b/crates/storage/storage-api/src/withdrawals.rs @@ -1,5 +1,7 @@ use alloy_eips::{eip4895::Withdrawals, BlockHashOrNumber}; +use alloy_primitives::BlockNumber; use reth_storage_errors::provider::ProviderResult; +use std::ops::RangeInclusive; /// Client trait for fetching [`alloy_eips::eip4895::Withdrawal`] related data. #[auto_impl::auto_impl(&, Arc)] @@ -10,4 +12,10 @@ pub trait WithdrawalsProvider: Send + Sync { id: BlockHashOrNumber, timestamp: u64, ) -> ProviderResult>; + + /// Returns the withdrawals per block within the requested block range. + fn withdrawals_by_block_range( + &self, + range: RangeInclusive, + ) -> ProviderResult>; }