-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Changes from all commits
a2a6a05
5f69696
387876c
31cb4b0
806e3c8
76425e3
46421f9
155bc1f
0d035d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1413,6 +1413,131 @@ impl<TX: DbTx> BlockReader for DatabaseProvider<TX> { | |
} | ||
Ok(blocks) | ||
} | ||
|
||
fn block_range_with_senders( | ||
&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>()?; | ||
let mut senders_cursor = self.tx.cursor_read::<tables::TxSenders>()?; | ||
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_number, tx)| (tx_number, tx.with_hash()))) | ||
.collect::<Result<Vec<_>, _>>()? | ||
}; | ||
|
||
// 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() | ||
}; | ||
|
||
// Walking range to get the TxNumber along with the Address. | ||
let mut senders = | ||
senders_cursor.walk_range(tx_range)?.collect::<Result<Vec<_>, _>>()?; | ||
|
||
// This approach is similar to what is done in | ||
// `get_take_block_transaction_range`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we use the existing function here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moreover, since this is a read-only method and |
||
if senders.len() != body.len() { | ||
let missing_len = body.len() - senders.len(); | ||
senders.reserve(missing_len); | ||
|
||
let mut missing_senders = Vec::with_capacity(missing_len); | ||
|
||
// Recover the missing senders by tracking the index of body. | ||
{ | ||
let mut senders = senders.iter().peekable(); | ||
|
||
for (i, (tx_number, tx)) in body.iter().enumerate() { | ||
if let Some((sender_tx_number, _)) = senders.peek() { | ||
if sender_tx_number == tx_number { | ||
// If current sender's `TxNumber` matches current | ||
// transaction's | ||
// `TxNumber`, advance the senders iterator. | ||
senders.next(); | ||
} else { | ||
// If current sender's `TxNumber` doesn't match current | ||
// transaction's | ||
// `TxNumber`, add it to missing senders. | ||
missing_senders.push((i, tx_number, tx)); | ||
} | ||
} else { | ||
// If there's no more senders left, but we're still iterating | ||
// over transactions, add | ||
// them to missing senders | ||
missing_senders.push((i, tx_number, tx)); | ||
} | ||
} | ||
} | ||
|
||
// Recover the missing senders | ||
let recovered_senders = TransactionSigned::recover_signers( | ||
missing_senders.iter().map(|(_, _, tx)| *tx).collect::<Vec<_>>(), | ||
missing_senders.len(), | ||
) | ||
.ok_or(ProviderError::SenderRecoveryError)?; | ||
|
||
// Insert the recovered senders into the senders list | ||
for ((i, tx_number, _), sender) in | ||
missing_senders.into_iter().zip(recovered_senders) | ||
{ | ||
// Insert will put recovered senders at necessary positions and shift | ||
// the rest | ||
senders.insert(i, (*tx_number, sender)); | ||
} | ||
} | ||
blocks.push( | ||
Block { | ||
header, | ||
body: body.into_iter().map(|(_, tx)| tx).collect(), | ||
ommers, | ||
withdrawals, | ||
} | ||
.with_senders_unchecked( | ||
senders.into_iter().map(|(_, sender)| sender).collect(), | ||
), | ||
) | ||
} | ||
} | ||
} | ||
Ok(blocks) | ||
} | ||
} | ||
|
||
impl<TX: DbTx> TransactionsProviderExt for DatabaseProvider<TX> { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ptal @joshieDo