refactor: add alloy_consensus::SignerRecoverable to SingedTransaction supertrait (#16174)

This commit is contained in:
fantasyup
2025-05-13 03:53:18 -04:00
committed by GitHub
parent 1af6ed5387
commit 8829881138
16 changed files with 95 additions and 131 deletions

26
Cargo.lock generated
View File

@@ -376,9 +376,9 @@ dependencies = [
[[package]]
name = "alloy-network-primitives"
version = "0.15.10"
version = "0.15.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2dea138d01f0e9739dee905a9e40a0f2347dd217360d813b6b7967ee8c0a8e"
checksum = "ec185bac9d32df79c1132558a450d48f6db0bfb5adef417dbb1a0258153f879b"
dependencies = [
"alloy-consensus",
"alloy-eips 0.15.11",
@@ -673,7 +673,7 @@ dependencies = [
"alloy-serde 0.15.11",
"alloy-sol-types",
"arbitrary",
"itertools 0.13.0",
"itertools 0.14.0",
"jsonrpsee-types",
"serde",
"serde_json",
@@ -5940,9 +5940,9 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]]
name = "op-alloy-consensus"
version = "0.15.5"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12ea96c143b159b53c34f1bc5ff1b196e92d6bef8e6417900a5a02df2baeaf2a"
checksum = "aec9fec6da224c0a86218a21e8e3c28f49a98dbab4bb5ccbd94f80bfbd6a66fb"
dependencies = [
"alloy-consensus",
"alloy-eips 0.15.11",
@@ -5966,9 +5966,9 @@ checksum = "4ef71f23a8caf6f2a2d5cafbdc44956d44e6014dcb9aa58abf7e4e6481c6ec34"
[[package]]
name = "op-alloy-network"
version = "0.15.5"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "603858def0e89940a53907783340e31347154668ae2c5b1fd0e6d232ac2daf8f"
checksum = "37863a5e1b25e2c17195c5e5b73c5b124a7c6ba54187014c566af73159fea45a"
dependencies = [
"alloy-consensus",
"alloy-network",
@@ -5981,9 +5981,9 @@ dependencies = [
[[package]]
name = "op-alloy-rpc-jsonrpsee"
version = "0.15.5"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9007b06c01d440851a66bef626daee227bdc06fbde97bb86eaad961acbdb1edd"
checksum = "c2be914a77a6540efa286059582b95b8d0185144d8c26e3e04f483ec2f178270"
dependencies = [
"alloy-primitives",
"jsonrpsee",
@@ -5991,9 +5991,9 @@ dependencies = [
[[package]]
name = "op-alloy-rpc-types"
version = "0.15.5"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0521752d6208545dc6015f8a5038d935d5d5c27971b76e4763c00cde6e216ab"
checksum = "72025d75d797b053cc1bfe6b5951ca8970014cc33d5cccd10029caab4d5c9e77"
dependencies = [
"alloy-consensus",
"alloy-eips 0.15.11",
@@ -6009,9 +6009,9 @@ dependencies = [
[[package]]
name = "op-alloy-rpc-types-engine"
version = "0.15.5"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d49b137bebba4ffd4dec9017825aeee83880367dba043f4c65f8a279f82a3991"
checksum = "8e2bbca5c5c85b833810cadde847bad2ebcf5bdd97abbce8ec4cf1565b98c90f"
dependencies = [
"alloy-consensus",
"alloy-eips 0.15.11",

View File

@@ -501,11 +501,11 @@ alloy-transport-ws = { version = "0.15.11", default-features = false }
# op
alloy-op-evm = { version = "0.7.1", default-features = false }
alloy-op-hardforks = "0.2.0"
op-alloy-rpc-types = { version = "0.15.4", default-features = false }
op-alloy-rpc-types-engine = { version = "0.15.4", default-features = false }
op-alloy-network = { version = "0.15.4", default-features = false }
op-alloy-consensus = { version = "0.15.4", default-features = false }
op-alloy-rpc-jsonrpsee = { version = "0.15.4", default-features = false }
op-alloy-rpc-types = { version = "0.15.6", default-features = false }
op-alloy-rpc-types-engine = { version = "0.15.6", default-features = false }
op-alloy-network = { version = "0.15.6", default-features = false }
op-alloy-consensus = { version = "0.15.6", default-features = false }
op-alloy-rpc-jsonrpsee = { version = "0.15.6", default-features = false }
op-alloy-flz = { version = "0.13.0", default-features = false }
# misc

View File

@@ -3,7 +3,7 @@
use alloc::vec::Vec;
use alloy_consensus::{
transaction::{RlpEcdsaDecodableTx, RlpEcdsaEncodableTx},
transaction::{RlpEcdsaDecodableTx, RlpEcdsaEncodableTx, SignerRecoverable},
EthereumTxEnvelope, SignableTransaction, Signed, TxEip1559, TxEip2930, TxEip4844, TxEip7702,
TxLegacy, TxType, Typed2718,
};
@@ -640,16 +640,23 @@ impl reth_codecs::Compact for TransactionSigned {
}
}
impl SignedTransaction for TransactionSigned {
fn tx_hash(&self) -> &TxHash {
self.hash.get_or_init(|| self.recalculate_hash())
}
impl SignerRecoverable for TransactionSigned {
fn recover_signer(&self) -> Result<Address, RecoveryError> {
let signature_hash = self.signature_hash();
recover_signer(&self.signature, signature_hash)
}
fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
let signature_hash = self.signature_hash();
recover_signer_unchecked(&self.signature, signature_hash)
}
}
impl SignedTransaction for TransactionSigned {
fn tx_hash(&self) -> &TxHash {
self.hash.get_or_init(|| self.recalculate_hash())
}
fn recover_signer_unchecked_with_buf(
&self,
buf: &mut Vec<u8>,

View File

@@ -4,7 +4,7 @@
use crate::transaction::OpTransaction;
use alloc::vec::Vec;
use alloy_consensus::{
transaction::{RlpEcdsaDecodableTx, RlpEcdsaEncodableTx},
transaction::{RlpEcdsaDecodableTx, RlpEcdsaEncodableTx, SignerRecoverable},
Sealed, SignableTransaction, Signed, Transaction, TxEip1559, TxEip2930, TxEip7702, TxLegacy,
Typed2718,
};
@@ -103,11 +103,7 @@ impl OpTransactionSigned {
}
}
impl SignedTransaction for OpTransactionSigned {
fn tx_hash(&self) -> &TxHash {
self.hash.get_or_init(|| self.recalculate_hash())
}
impl SignerRecoverable for OpTransactionSigned {
fn recover_signer(&self) -> Result<Address, RecoveryError> {
// Optimism's Deposit transaction does not have a signature. Directly return the
// `from` address.
@@ -131,6 +127,12 @@ impl SignedTransaction for OpTransactionSigned {
let signature_hash = signature_hash(transaction);
recover_signer_unchecked(signature, signature_hash)
}
}
impl SignedTransaction for OpTransactionSigned {
fn tx_hash(&self) -> &TxHash {
self.hash.get_or_init(|| self.recalculate_hash())
}
fn recover_signer_unchecked_with_buf(
&self,

View File

@@ -27,7 +27,7 @@ revm-bytecode.workspace = true
revm-state.workspace = true
# op
op-alloy-consensus = { workspace = true, optional = true }
op-alloy-consensus = { workspace = true, optional = true, features = ["k256"] }
# crypto
secp256k1 = { workspace = true, features = ["recovery"], optional = true }

View File

@@ -3,7 +3,7 @@ use crate::{
transaction::signed::{RecoveryError, SignedTransaction},
};
use alloc::vec::Vec;
use alloy_consensus::Transaction;
use alloy_consensus::{transaction::SignerRecoverable, Transaction};
use alloy_eips::{
eip2718::{Eip2718Error, Eip2718Result, IsTyped2718},
eip2930::AccessList,
@@ -136,6 +136,20 @@ where
}
}
impl<B, T> SignerRecoverable for ExtendedTxEnvelope<B, T>
where
B: SignedTransaction + IsTyped2718,
T: SignedTransaction,
{
fn recover_signer(&self) -> Result<Address, RecoveryError> {
delegate!(self => tx.recover_signer())
}
fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
delegate!(self => tx.recover_signer_unchecked())
}
}
impl<B, T> SignedTransaction for ExtendedTxEnvelope<B, T>
where
B: SignedTransaction + IsTyped2718,
@@ -148,14 +162,6 @@ where
}
}
fn recover_signer(&self) -> Result<Address, RecoveryError> {
delegate!(self => tx.recover_signer())
}
fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
delegate!(self => tx.recover_signer_unchecked())
}
fn recover_signer_unchecked_with_buf(
&self,
buf: &mut Vec<u8>,

View File

@@ -1,12 +1,12 @@
//! API of a signed transaction.
use crate::{
crypto::secp256k1::{recover_signer, recover_signer_unchecked},
InMemorySize, MaybeCompact, MaybeSerde, MaybeSerdeBincodeCompat,
crypto::secp256k1::recover_signer_unchecked, InMemorySize, MaybeCompact, MaybeSerde,
MaybeSerdeBincodeCompat,
};
use alloc::{fmt, vec::Vec};
use alloy_consensus::{
transaction::{Recovered, RlpEcdsaEncodableTx},
transaction::{Recovered, RlpEcdsaEncodableTx, SignerRecoverable},
EthereumTxEnvelope, SignableTransaction,
};
use alloy_eips::eip2718::{Decodable2718, Encodable2718};
@@ -38,6 +38,7 @@ pub trait SignedTransaction:
+ alloy_consensus::Transaction
+ MaybeSerde
+ InMemorySize
+ SignerRecoverable
{
/// Returns reference to transaction hash.
fn tx_hash(&self) -> &TxHash;
@@ -52,17 +53,6 @@ pub trait SignedTransaction:
!self.is_eip4844()
}
/// Recover signer from signature and hash.
///
/// Returns `RecoveryError` if the transaction's signature is invalid following [EIP-2](https://eips.ethereum.org/EIPS/eip-2), see also `reth_primitive_traits::crypto::secp256k1::recover_signer`.
///
/// Note:
///
/// This can fail for some early ethereum mainnet transactions pre EIP-2, use
/// [`Self::recover_signer_unchecked`] if you want to recover the signer without ensuring that
/// the signature has a low `s` value.
fn recover_signer(&self) -> Result<Address, RecoveryError>;
/// Recover signer from signature and hash.
///
/// Returns an error if the transaction's signature is invalid.
@@ -70,15 +60,6 @@ pub trait SignedTransaction:
self.recover_signer()
}
/// Recover signer from signature and hash _without ensuring that the signature has a low `s`
/// value_.
///
/// Returns `RecoveryError` if the transaction's signature is invalid, see also
/// `reth_primitive_traits::crypto::secp256k1::recover_signer_unchecked`.
fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
self.recover_signer_unchecked_with_buf(&mut Vec::new())
}
/// Recover signer from signature and hash _without ensuring that the signature has a low `s`
/// value_.
///
@@ -87,8 +68,9 @@ pub trait SignedTransaction:
self.recover_signer_unchecked()
}
/// Same as [`Self::recover_signer_unchecked`] but receives a buffer to operate on. This is used
/// during batch recovery to avoid allocating a new buffer for each transaction.
/// Same as [`SignerRecoverable::recover_signer_unchecked`] but receives a buffer to operate on.
/// This is used during batch recovery to avoid allocating a new buffer for each
/// transaction.
fn recover_signer_unchecked_with_buf(
&self,
buf: &mut Vec<u8>,
@@ -109,7 +91,7 @@ pub trait SignedTransaction:
/// Tries to recover signer and return [`Recovered`].
///
/// Returns `Err(Self)` if the transaction's signature is invalid, see also
/// [`SignedTransaction::recover_signer`].
/// [`SignerRecoverable::recover_signer`].
#[auto_impl(keep_default_for(&, Arc))]
fn try_into_recovered(self) -> Result<Recovered<Self>, Self> {
match self.recover_signer() {
@@ -151,11 +133,6 @@ where
}
}
fn recover_signer(&self) -> Result<Address, RecoveryError> {
let signature_hash = self.signature_hash();
recover_signer(self.signature(), signature_hash)
}
fn recover_signer_unchecked_with_buf(
&self,
buf: &mut Vec<u8>,
@@ -187,10 +164,6 @@ mod op {
}
}
fn recover_signer(&self) -> Result<Address, RecoveryError> {
recover_signer(self.signature(), self.signature_hash())
}
fn recover_signer_unchecked_with_buf(
&self,
buf: &mut Vec<u8>,
@@ -217,46 +190,6 @@ mod op {
}
}
fn recover_signer(&self) -> Result<Address, RecoveryError> {
let signature_hash = match self {
Self::Legacy(tx) => tx.signature_hash(),
Self::Eip2930(tx) => tx.signature_hash(),
Self::Eip1559(tx) => tx.signature_hash(),
Self::Eip7702(tx) => tx.signature_hash(),
// Optimism's Deposit transaction does not have a signature. Directly return the
// `from` address.
Self::Deposit(tx) => return Ok(tx.from),
};
let signature = match self {
Self::Legacy(tx) => tx.signature(),
Self::Eip2930(tx) => tx.signature(),
Self::Eip1559(tx) => tx.signature(),
Self::Eip7702(tx) => tx.signature(),
Self::Deposit(_) => unreachable!("Deposit transactions should not be handled here"),
};
recover_signer(signature, signature_hash)
}
fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
let signature_hash = match self {
Self::Legacy(tx) => tx.signature_hash(),
Self::Eip2930(tx) => tx.signature_hash(),
Self::Eip1559(tx) => tx.signature_hash(),
Self::Eip7702(tx) => tx.signature_hash(),
// Optimism's Deposit transaction does not have a signature. Directly return the
// `from` address.
Self::Deposit(tx) => return Ok(tx.from),
};
let signature = match self {
Self::Legacy(tx) => tx.signature(),
Self::Eip2930(tx) => tx.signature(),
Self::Eip1559(tx) => tx.signature(),
Self::Eip7702(tx) => tx.signature(),
Self::Deposit(_) => unreachable!("Deposit transactions should not be handled here"),
};
recover_signer_unchecked(signature, signature_hash)
}
fn recover_signer_unchecked_with_buf(
&self,
buf: &mut Vec<u8>,

View File

@@ -1,9 +1,9 @@
#![allow(missing_docs)]
use alloy_consensus::transaction::SignerRecoverable;
use alloy_primitives::hex_literal::hex;
use alloy_rlp::Decodable;
use criterion::{criterion_group, criterion_main, Criterion};
use reth_ethereum_primitives::TransactionSigned;
use reth_primitives_traits::SignedTransaction;
/// Benchmarks the recovery of the public key from the ECDSA message using criterion.
pub fn criterion_benchmark(c: &mut Criterion) {
@@ -12,7 +12,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let raw =hex!("f88b8212b085028fa6ae00830f424094aad593da0c8116ef7d2d594dd6a63241bccfc26c80a48318b64b000000000000000000000000641c5d790f862a58ec7abcfd644c0442e9c201b32aa0a6ef9e170bca5ffb7ac05433b13b7043de667fbb0b4a5e45d3b54fb2d6efcc63a0037ec2c05c3d60c5f5f78244ce0a3859e3a18a36c61efb061b383507d3ce19d2");
let mut pointer = raw.as_ref();
let tx = TransactionSigned::decode(&mut pointer).unwrap();
SignedTransaction::recover_signer(&tx).unwrap();
SignerRecoverable::recover_signer(&tx).unwrap();
}
)
});

View File

@@ -90,7 +90,6 @@ mod tests {
Itertools,
};
use reth_db_api::tables;
use reth_primitives_traits::SignedTransaction;
use reth_provider::{DatabaseProviderFactory, PruneCheckpointReader};
use reth_prune_types::{PruneCheckpoint, PruneMode, PruneProgress, PruneSegment};
use reth_stages::test_utils::{StorageKind, TestStageDB};
@@ -115,7 +114,7 @@ mod tests {
for transaction in &block.body().transactions {
transaction_senders.push((
transaction_senders.len() as u64,
SignedTransaction::recover_signer(transaction).expect("recover signer"),
transaction.recover_signer().expect("recover signer"),
));
}
}

View File

@@ -2,13 +2,15 @@
//! previous blocks.
use super::{EthApiError, EthResult, EthStateCache, RpcInvalidTransactionError};
use alloy_consensus::{constants::GWEI_TO_WEI, BlockHeader, Transaction};
use alloy_consensus::{
constants::GWEI_TO_WEI, transaction::SignerRecoverable, BlockHeader, Transaction,
};
use alloy_eips::BlockNumberOrTag;
use alloy_primitives::{B256, U256};
use alloy_rpc_types_eth::BlockId;
use derive_more::{Deref, DerefMut, From, Into};
use itertools::Itertools;
use reth_primitives_traits::{BlockBody, SignedTransaction};
use reth_primitives_traits::BlockBody;
use reth_rpc_server_types::{
constants,
constants::gas_oracle::{

View File

@@ -18,7 +18,8 @@ pub fn recover_raw_transaction<T: SignedTransaction>(mut data: &[u8]) -> EthResu
let transaction =
T::decode_2718(&mut data).map_err(|_| EthApiError::FailedToDecodeSignedTransaction)?;
transaction.try_into_recovered().or(Err(EthApiError::InvalidTransactionSignature))
SignedTransaction::try_into_recovered(transaction)
.or(Err(EthApiError::InvalidTransactionSignature))
}
/// Performs a binary search within a given block range to find the desired block number.

View File

@@ -1,4 +1,4 @@
use alloy_consensus::BlockHeader;
use alloy_consensus::{transaction::SignerRecoverable, BlockHeader};
use alloy_eips::{eip2718::Encodable2718, BlockId, BlockNumberOrTag};
use alloy_genesis::ChainConfig;
use alloy_primitives::{Address, Bytes, B256};

View File

@@ -19,7 +19,10 @@ use crate::{
TransactionVariant, TransactionsProvider, TransactionsProviderExt, TrieWriter,
WithdrawalsProvider,
};
use alloy_consensus::{transaction::TransactionMeta, BlockHeader, Header, TxReceipt};
use alloy_consensus::{
transaction::{SignerRecoverable, TransactionMeta},
BlockHeader, Header, TxReceipt,
};
use alloy_eips::{eip2718::Encodable2718, eip4895::Withdrawals, BlockHashOrNumber};
use alloy_primitives::{
keccak256,

View File

@@ -6,7 +6,7 @@ use crate::{
to_range, BlockHashReader, BlockNumReader, HeaderProvider, ReceiptProvider,
TransactionsProvider,
};
use alloy_consensus::transaction::TransactionMeta;
use alloy_consensus::transaction::{SignerRecoverable, TransactionMeta};
use alloy_eips::{eip2718::Encodable2718, eip4895::Withdrawals, BlockHashOrNumber};
use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256};
use reth_chainspec::ChainInfo;

View File

@@ -7,7 +7,10 @@ use crate::{
ReceiptProvider, StageCheckpointReader, StatsReader, TransactionVariant, TransactionsProvider,
TransactionsProviderExt, WithdrawalsProvider,
};
use alloy_consensus::{transaction::TransactionMeta, Header};
use alloy_consensus::{
transaction::{SignerRecoverable, TransactionMeta},
Header,
};
use alloy_eips::{eip2718::Encodable2718, eip4895::Withdrawals, BlockHashOrNumber};
use alloy_primitives::{
b256, keccak256, Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256,

View File

@@ -4,6 +4,7 @@ use alloy_consensus::{
secp256k1::{recover_signer, recover_signer_unchecked},
RecoveryError,
},
transaction::SignerRecoverable,
SignableTransaction, Signed, Transaction,
};
use alloy_eips::{eip2718::Eip2718Result, Decodable2718, Encodable2718, Typed2718};
@@ -100,16 +101,23 @@ impl Transaction for CustomTransactionEnvelope {
}
}
impl SignedTransaction for CustomTransactionEnvelope {
fn tx_hash(&self) -> &TxHash {
self.inner.hash()
}
impl SignerRecoverable for CustomTransactionEnvelope {
fn recover_signer(&self) -> Result<Address, RecoveryError> {
let signature_hash = self.inner.signature_hash();
recover_signer(self.inner.signature(), signature_hash)
}
fn recover_signer_unchecked(&self) -> Result<Address, RecoveryError> {
let signature_hash = self.inner.signature_hash();
recover_signer_unchecked(self.inner.signature(), signature_hash)
}
}
impl SignedTransaction for CustomTransactionEnvelope {
fn tx_hash(&self) -> &TxHash {
self.inner.hash()
}
fn recover_signer_unchecked_with_buf(
&self,
buf: &mut Vec<u8>,