Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(provider): add block_range_with_senders #5647

17 changes: 11 additions & 6 deletions crates/rpc/rpc/src/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use reth_rpc_api::TraceApiServer;
use reth_rpc_types::{
state::StateOverride,
trace::{filter::TraceFilter, parity::*, tracerequest::TraceCallRequest},
BlockError, BlockOverrides, CallRequest, Index,
BlockOverrides, CallRequest, Index,
};
use revm::{db::CacheDB, primitives::Env};
use std::{collections::HashSet, sync::Arc};
Expand Down Expand Up @@ -257,15 +257,16 @@ where
}

// fetch all blocks in that range
let blocks = self.provider().block_range(start..=end)?;
let blocks = self.provider().block_range_with_senders(start..=end)?;

// find relevant blocks to trace
let mut target_blocks = Vec::new();
for block in blocks {
for block_with_senders in blocks {
let mut transaction_indices = HashSet::new();
let mut highest_matching_index = 0;
for (tx_idx, tx) in block.body.iter().enumerate() {
let from = tx.recover_signer().ok_or(BlockError::InvalidSignature)?;

for (tx_idx, tx) in block_with_senders.block.body.iter().enumerate() {
let from = block_with_senders.senders[tx_idx];
yash-atreya marked this conversation as resolved.
Show resolved Hide resolved
let to = tx.to();
if matcher.matches(from, to) {
let idx = tx_idx as u64;
Expand All @@ -274,7 +275,11 @@ where
}
}
if !transaction_indices.is_empty() {
target_blocks.push((block.number, transaction_indices, highest_matching_index));
target_blocks.push((
block_with_senders.number,
transaction_indices,
highest_matching_index,
));
}
}

Expand Down
7 changes: 7 additions & 0 deletions crates/storage/provider/src/providers/database/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,13 @@ impl<DB: Database> BlockReader for ProviderFactory<DB> {
fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Block>> {
self.provider()?.block_range(range)
}

fn block_range_with_senders(
&self,
range: RangeInclusive<BlockNumber>,
) -> ProviderResult<Vec<BlockWithSenders>> {
self.provider()?.block_range_with_senders(range)
}
}

impl<DB: Database> TransactionsProvider for ProviderFactory<DB> {
Expand Down
63 changes: 63 additions & 0 deletions crates/storage/provider/src/providers/database/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,69 @@ impl<TX: DbTx> BlockReader for DatabaseProvider<TX> {
}
Ok(blocks)
}

fn block_range_with_senders(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ptal @joshieDo

&self,
range: RangeInclusive<BlockNumber>,
) -> ProviderResult<Vec<BlockWithSenders>> {
if range.is_empty() {
return Ok(Vec::new())
}

let len = range.end().saturating_sub(*range.start()) as usize;
let mut blocks = Vec::with_capacity(len);

let mut headers_cursor = self.tx.cursor_read::<tables::Headers>()?;
let mut ommers_cursor = self.tx.cursor_read::<tables::BlockOmmers>()?;
let mut withdrawals_cursor = self.tx.cursor_read::<tables::BlockWithdrawals>()?;
let mut block_body_cursor = self.tx.cursor_read::<tables::BlockBodyIndices>()?;
let mut tx_cursor = self.tx.cursor_read::<tables::Transactions>()?;

for num in range {
if let Some((_, header)) = headers_cursor.seek_exact(num)? {
// If the body indices are not found, this means that the transactions either do
// not exist in the database yet, or they do exit but are
// not indexed. If they exist but are not indexed, we don't
// have enough information to return the block anyways, so
// we skip the block.
if let Some((_, block_body_indices)) = block_body_cursor.seek_exact(num)? {
let tx_range = block_body_indices.tx_num_range();
let body = if tx_range.is_empty() {
Vec::new()
} else {
tx_cursor
.walk_range(tx_range.clone())?
.map(|result| result.map(|(_, tx)| tx.into()))
.collect::<Result<Vec<_>, _>>()?
};

let senders = self.senders_by_tx_range(tx_range)?;

// If we are past shanghai, then all blocks should have a withdrawal list,
// even if empty
let withdrawals =
if self.chain_spec.is_shanghai_active_at_timestamp(header.timestamp) {
Some(
withdrawals_cursor
.seek_exact(num)?
.map(|(_, w)| w.withdrawals)
.unwrap_or_default(),
)
} else {
None
};
let ommers = if self.chain_spec.final_paris_total_difficulty(num).is_some() {
Vec::new()
} else {
ommers_cursor.seek_exact(num)?.map(|(_, o)| o.ommers).unwrap_or_default()
};

blocks.push(Block { header, body, ommers, withdrawals }.with_senders(senders));
}
}
}
Ok(blocks)
}
}

impl<TX: DbTx> TransactionsProviderExt for DatabaseProvider<TX> {
Expand Down
7 changes: 7 additions & 0 deletions crates/storage/provider/src/providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,13 @@ where
fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Block>> {
self.database.provider()?.block_range(range)
}

fn block_range_with_senders(
&self,
range: RangeInclusive<BlockNumber>,
) -> ProviderResult<Vec<BlockWithSenders>> {
self.database.provider()?.block_range_with_senders(range)
}
}

impl<DB, Tree> TransactionsProvider for BlockchainProvider<DB, Tree>
Expand Down
17 changes: 17 additions & 0 deletions crates/storage/provider/src/test_utils/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,23 @@ impl BlockReader for MockEthProvider {

Ok(blocks)
}

fn block_range_with_senders(
&self,
range: RangeInclusive<BlockNumber>,
) -> ProviderResult<Vec<BlockWithSenders>> {
let lock = self.blocks.lock();

let mut blocks: Vec<_> = lock
.values()
.filter(|block| range.contains(&block.number))
.map(|block| BlockWithSenders { block: block.clone(), senders: vec![] })
.collect();

blocks.sort_by_key(|block| block.block.number);

Ok(blocks)
}
}

impl BlockReaderIdExt for MockEthProvider {
Expand Down
7 changes: 7 additions & 0 deletions crates/storage/provider/src/test_utils/noop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ impl BlockReader for NoopProvider {
fn block_range(&self, _range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Block>> {
Ok(vec![])
}

fn block_range_with_senders(
&self,
_range: RangeInclusive<BlockNumber>,
) -> ProviderResult<Vec<reth_primitives::BlockWithSenders>> {
Ok(vec![])
}
}

impl BlockReaderIdExt for NoopProvider {
Expand Down
8 changes: 8 additions & 0 deletions crates/storage/provider/src/traits/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,14 @@ pub trait BlockReader:
///
/// Note: returns only available blocks
fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Block>>;

/// Returns all blocks with senders in the given inclusive range.
///
/// Note: returns only available blocks
fn block_range_with_senders(
&self,
range: RangeInclusive<BlockNumber>,
) -> ProviderResult<Vec<BlockWithSenders>>;
}

/// Trait extension for `BlockReader`, for types that implement `BlockId` conversion.
Expand Down
Loading