From 907c9c0d930c440d4e017848b7258b443a2cabc7 Mon Sep 17 00:00:00 2001 From: Thomas Coratger Date: Mon, 21 Oct 2024 01:06:37 +0200 Subject: [PATCH] consensus: impl recover_signers for BlockBody --- Cargo.toml | 1 + crates/consensus/Cargo.toml | 3 +- crates/consensus/src/block.rs | 11 ++++++- crates/consensus/src/transaction/envelope.rs | 33 ++++++++++++++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e8fdf955220..8edec924cde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -146,6 +146,7 @@ derive_more = { version = "1.0.0", default-features = false } strum = { version = "0.26", default-features = false } http = "1.1.0" jsonwebtoken = "9.3.0" +rayon = "1.7" ## serde serde = { version = "1.0", default-features = false, features = [ diff --git a/crates/consensus/Cargo.toml b/crates/consensus/Cargo.toml index 03d4c01f163..ac10d55eebb 100644 --- a/crates/consensus/Cargo.toml +++ b/crates/consensus/Cargo.toml @@ -42,6 +42,7 @@ derive_more = { workspace = true, features = [ "into_iterator" ], default-features = false } auto_impl.workspace = true +rayon = { workspace = true, optional = true } [dev-dependencies] alloy-eips = { workspace = true, features = ["arbitrary"] } @@ -58,7 +59,7 @@ tokio = { workspace = true, features = ["macros"] } [features] default = ["std"] std = ["alloy-eips/std", "c-kzg?/std"] -k256 = ["alloy-primitives/k256", "alloy-eips/k256"] +k256 = ["alloy-primitives/k256", "alloy-eips/k256", "rayon"] kzg = ["dep:c-kzg", "alloy-eips/kzg", "std"] arbitrary = ["std", "dep:arbitrary", "alloy-eips/arbitrary"] serde = [ diff --git a/crates/consensus/src/block.rs b/crates/consensus/src/block.rs index 2aece0da2d5..094c09259df 100644 --- a/crates/consensus/src/block.rs +++ b/crates/consensus/src/block.rs @@ -1,8 +1,9 @@ //! Block Type -use crate::Header; +use crate::{Header, TxEnvelope}; use alloc::vec::Vec; use alloy_eips::eip4895::Withdrawals; +use alloy_primitives::Address; use alloy_rlp::{Decodable, Encodable, RlpDecodable, RlpEncodable}; /// Ethereum full block. @@ -34,6 +35,14 @@ pub struct BlockBody { pub withdrawals: Option, } +impl BlockBody { + /// Recover signer addresses for all transactions in the block body. + #[cfg(feature = "k256")] + pub fn recover_signers(&self) -> Result, alloy_primitives::SignatureError> { + TxEnvelope::recover_signers(&self.transactions, self.transactions.len()) + } +} + /// We need to implement RLP traits manually because we currently don't have a way to flatten /// [`BlockBody`] into [`Block`]. mod block_rlp { diff --git a/crates/consensus/src/transaction/envelope.rs b/crates/consensus/src/transaction/envelope.rs index 73549a4db4b..30fbf83d671 100644 --- a/crates/consensus/src/transaction/envelope.rs +++ b/crates/consensus/src/transaction/envelope.rs @@ -10,6 +10,16 @@ use alloy_rlp::{Decodable, Encodable, Header}; use crate::transaction::eip4844::{TxEip4844, TxEip4844Variant, TxEip4844WithSidecar}; +/// Expected number of transactions where we can expect a speed-up by recovering the senders in +/// parallel. +#[cfg(feature = "k256")] +pub(crate) static PARALLEL_SENDER_RECOVERY_THRESHOLD: std::sync::LazyLock = + std::sync::LazyLock::new(|| match rayon::current_num_threads() { + 0..=1 => usize::MAX, + 2..=8 => 10, + _ => 5, + }); + /// Ethereum `TransactionType` flags as specified in EIPs [2718], [1559], [2930], /// [4844], and [7702]. /// @@ -241,6 +251,29 @@ impl TxEnvelope { } } + /// Recovers a list of signers from a transaction list iterator. + /// + /// Returns `None` if some transaction's signature is invalid; + /// See also [`Self::recover_signer`]. + #[cfg(feature = "k256")] + pub fn recover_signers<'a, T>( + txes: T, + num_txes: usize, + ) -> Result, alloy_primitives::SignatureError> + where + T: rayon::prelude::IntoParallelIterator + + IntoIterator + + Send, + { + use rayon::iter::ParallelIterator; + + if num_txes < *PARALLEL_SENDER_RECOVERY_THRESHOLD { + txes.into_iter().map(|tx| tx.recover_signer()).collect() + } else { + txes.into_par_iter().map(|tx| tx.recover_signer()).collect() + } + } + /// Calculate the signing hash for the transaction. pub fn signature_hash(&self) -> B256 { match self {