diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 92d55b8d82b0..426607583221 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -856,10 +856,39 @@ impl TransactionSignedNoHash { /// /// Returns `None` if the transaction's signature is invalid, see also [Self::recover_signer]. pub fn recover_signer(&self) -> Option
{ + // Optimism's Deposit transaction does not have a signature. Directly return the + // `from` address. + #[cfg(feature = "optimism")] + if let Transaction::Deposit(TxDeposit { from, .. }) = self.transaction { + return Some(from) + } + let signature_hash = self.signature_hash(); self.signature.recover_signer(signature_hash) } + /// Recover signer from signature and hash _without ensuring that the signature has a low `s` + /// value_. + /// + /// Re-uses a given buffer to avoid numerous reallocations when recovering batches. **Clears the + /// buffer before use.** + /// + /// Returns `None` if the transaction's signature is invalid, see also + /// [Signature::recover_signer_unchecked]. + pub fn encode_and_recover_unchecked(&self, buffer: &mut Vec) -> Option
{ + buffer.clear(); + self.transaction.encode_without_signature(buffer); + + // Optimism's Deposit transaction does not have a signature. Directly return the + // `from` address. + #[cfg(feature = "optimism")] + if let Transaction::Deposit(TxDeposit { from, .. }) = self.transaction { + return Some(from) + } + + self.signature.recover_signer_unchecked(keccak256(buffer)) + } + /// Converts into a transaction type with its hash: [`TransactionSigned`]. /// /// Note: This will recalculate the hash of the transaction. diff --git a/crates/stages/src/stages/sender_recovery.rs b/crates/stages/src/stages/sender_recovery.rs index 4648f9732443..afb65c560605 100644 --- a/crates/stages/src/stages/sender_recovery.rs +++ b/crates/stages/src/stages/sender_recovery.rs @@ -9,7 +9,6 @@ use reth_db::{ }; use reth_interfaces::consensus; use reth_primitives::{ - keccak256, stage::{EntitiesCheckpoint, StageCheckpoint, StageId}, Address, PruneSegment, StaticFileSegment, TransactionSignedNoHash, TxNumber, }; @@ -229,16 +228,13 @@ fn recover_sender( (tx_id, tx): (TxNumber, TransactionSignedNoHash), rlp_buf: &mut Vec, ) -> Result<(u64, Address), Box> { - tx.transaction.encode_without_signature(rlp_buf); - // We call [Signature::recover_signer_unchecked] because transactions run in the pipeline are // known to be valid - this means that we do not need to check whether or not the `s` value is // greater than `secp256k1n / 2` if past EIP-2. There are transactions pre-homestead which have // large `s` values, so using [Signature::recover_signer] here would not be // backwards-compatible. let sender = tx - .signature - .recover_signer_unchecked(keccak256(rlp_buf)) + .encode_and_recover_unchecked(rlp_buf) .ok_or(SenderRecoveryStageError::FailedRecovery(FailedSenderRecoveryError { tx: tx_id }))?; Ok((tx_id, sender))