fix: use unchecked sender recovery when loading from disk (#5919)

This commit is contained in:
Matthias Seitz
2024-01-02 16:00:53 +01:00
committed by GitHub
parent 962809e199
commit 5f53545f45
3 changed files with 50 additions and 6 deletions

View File

@ -64,16 +64,37 @@ impl Block {
///
/// If the number of senders does not match the number of transactions in the block
/// and the signer recovery for one of the transactions fails.
///
/// Note: this is expected to be called with blocks read from disk.
#[track_caller]
pub fn with_senders(self, senders: Vec<Address>) -> BlockWithSenders {
pub fn with_senders_unchecked(self, senders: Vec<Address>) -> BlockWithSenders {
self.try_with_senders_unchecked(senders).expect("stored block is valid")
}
/// Transform into a [`BlockWithSenders`] using the given senders.
///
/// If the number of senders does not match the number of transactions in the block, this falls
/// back to manually recovery, but _without ensuring that the signature has a low `s` value_.
/// See also [TransactionSigned::recover_signer_unchecked]
///
/// Returns an error if a signature is invalid.
#[track_caller]
pub fn try_with_senders_unchecked(
self,
senders: Vec<Address>,
) -> Result<BlockWithSenders, Self> {
let senders = if self.body.len() == senders.len() {
senders
} else {
TransactionSigned::recover_signers(&self.body, self.body.len())
.expect("stored block is valid")
let Some(senders) =
TransactionSigned::recover_signers_unchecked(&self.body, self.body.len())
else {
return Err(self);
};
senders
};
BlockWithSenders { block: self, senders }
Ok(BlockWithSenders { block: self, senders })
}
/// **Expensive**. Transform into a [`BlockWithSenders`] by recovering senders in the contained

View File

@ -996,7 +996,7 @@ impl TransactionSigned {
self.signature.recover_signer_unchecked(signature_hash)
}
/// Recovers a list of signers from a transaction list iterator
/// Recovers a list of signers from a transaction list iterator.
///
/// Returns `None`, if some transaction's signature is invalid, see also
/// [Self::recover_signer].
@ -1011,6 +1011,22 @@ impl TransactionSigned {
}
}
/// Recovers a list of signers from a transaction list iterator _without ensuring that the
/// signature has a low `s` value_.
///
/// Returns `None`, if some transaction's signature is invalid, see also
/// [Self::recover_signer_unchecked].
pub fn recover_signers_unchecked<'a, T>(txes: T, num_txes: usize) -> Option<Vec<Address>>
where
T: IntoParallelIterator<Item = &'a Self> + IntoIterator<Item = &'a Self> + Send,
{
if num_txes < *PARALLEL_SENDER_RECOVERY_THRESHOLD {
txes.into_iter().map(|tx| tx.recover_signer_unchecked()).collect()
} else {
txes.into_par_iter().map(|tx| tx.recover_signer_unchecked()).collect()
}
}
/// Returns the [TransactionSignedEcRecovered] transaction with the given sender.
#[inline]
pub const fn with_signer(self, signer: Address) -> TransactionSignedEcRecovered {

View File

@ -1348,7 +1348,14 @@ impl<TX: DbTx> BlockReader for DatabaseProvider<TX> {
})
.collect();
Ok(Some(Block { header, body, ommers, withdrawals }.with_senders(senders)))
let block = Block { header, body, ommers, withdrawals };
let block = block
// Note: we're using unchecked here because we know the block contains valid txs wrt to
// its height and can ignore the s value check so pre EIP-2 txs are allowed
.try_with_senders_unchecked(senders)
.map_err(|_| ProviderError::SenderRecoveryError)?;
Ok(Some(block))
}
fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Block>> {