diff --git a/crates/primitives/src/block.rs b/crates/primitives/src/block.rs index 37cb5954bf50..ee458137f6f3 100644 --- a/crates/primitives/src/block.rs +++ b/crates/primitives/src/block.rs @@ -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_unchecked(self, senders: Vec
) -> 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 with_senders(self, senders: Vec
) -> BlockWithSenders { + pub fn try_with_senders_unchecked( + self, + senders: Vec
, + ) -> Result { 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 diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 448852582baf..82b08a863548 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -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> + where + T: IntoParallelIterator + IntoIterator + 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 { diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index bce17cccc7c2..52f675873239 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -1348,7 +1348,14 @@ impl BlockReader for DatabaseProvider { }) .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) -> ProviderResult> {