mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-25 23:28:03 -05:00
feat: use generic SignedTx in SenderRecoveryStage (#12996)
This commit is contained in:
@@ -9,6 +9,7 @@ use reth_db::{
|
||||
};
|
||||
use reth_db_api::table::{Decompress, DupSort, Table};
|
||||
use reth_db_common::DbTool;
|
||||
use reth_node_api::{ReceiptTy, TxTy};
|
||||
use reth_node_builder::NodeTypesWithDB;
|
||||
use reth_provider::{providers::ProviderNodeTypes, StaticFileProviderFactory};
|
||||
use reth_static_file_types::StaticFileSegment;
|
||||
@@ -65,14 +66,12 @@ impl Command {
|
||||
StaticFileSegment::Headers => {
|
||||
(table_key::<tables::Headers>(&key)?, <HeaderWithHashMask<Header>>::MASK)
|
||||
}
|
||||
StaticFileSegment::Transactions => (
|
||||
table_key::<tables::Transactions>(&key)?,
|
||||
<TransactionMask<<Transactions as Table>::Value>>::MASK,
|
||||
),
|
||||
StaticFileSegment::Receipts => (
|
||||
table_key::<tables::Receipts>(&key)?,
|
||||
<ReceiptMask<<Receipts as Table>::Value>>::MASK,
|
||||
),
|
||||
StaticFileSegment::Transactions => {
|
||||
(table_key::<tables::Transactions>(&key)?, <TransactionMask<TxTy<N>>>::MASK)
|
||||
}
|
||||
StaticFileSegment::Receipts => {
|
||||
(table_key::<tables::Receipts>(&key)?, <ReceiptMask<ReceiptTy<N>>>::MASK)
|
||||
}
|
||||
};
|
||||
|
||||
let content = tool.provider_factory.static_file_provider().find_static_file(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! API of a signed transaction.
|
||||
|
||||
use crate::{FillTxEnv, InMemorySize, MaybeArbitrary, MaybeCompact, MaybeSerde, TxType};
|
||||
use alloc::fmt;
|
||||
use alloc::{fmt, vec::Vec};
|
||||
use alloy_eips::eip2718::{Decodable2718, Encodable2718};
|
||||
use alloy_primitives::{keccak256, Address, PrimitiveSignature, TxHash, B256};
|
||||
use core::hash::Hash;
|
||||
@@ -61,7 +61,13 @@ pub trait SignedTransaction:
|
||||
///
|
||||
/// Returns `None` if the transaction's signature is invalid, see also
|
||||
/// `reth_primitives::transaction::recover_signer_unchecked`.
|
||||
fn recover_signer_unchecked(&self) -> Option<Address>;
|
||||
fn recover_signer_unchecked(&self) -> Option<Address> {
|
||||
self.recover_signer_unchecked_with_buf(&mut Vec::new())
|
||||
}
|
||||
|
||||
/// 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.
|
||||
fn recover_signer_unchecked_with_buf(&self, buf: &mut Vec<u8>) -> Option<Address>;
|
||||
|
||||
/// Calculate transaction hash, eip2728 transaction does not contain rlp header and start with
|
||||
/// tx type.
|
||||
|
||||
@@ -1245,14 +1245,15 @@ impl SignedTransaction for TransactionSigned {
|
||||
recover_signer(&self.signature, signature_hash)
|
||||
}
|
||||
|
||||
fn recover_signer_unchecked(&self) -> Option<Address> {
|
||||
fn recover_signer_unchecked_with_buf(&self, buf: &mut Vec<u8>) -> Option<Address> {
|
||||
// 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.encode_for_signing(buf);
|
||||
let signature_hash = keccak256(buf);
|
||||
recover_signer_unchecked(&self.signature, signature_hash)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,11 @@ use super::{
|
||||
use crate::{
|
||||
BlobTransaction, Transaction, TransactionSigned, TransactionSignedEcRecovered, TxType,
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use alloy_consensus::{
|
||||
constants::EIP4844_TX_TYPE_ID,
|
||||
transaction::{TxEip1559, TxEip2930, TxEip4844, TxLegacy},
|
||||
Signed, TxEip4844WithSidecar,
|
||||
SignableTransaction, Signed, TxEip4844WithSidecar,
|
||||
};
|
||||
use alloy_eips::{
|
||||
eip2718::{Decodable2718, Eip2718Result, Encodable2718},
|
||||
@@ -27,6 +28,7 @@ use bytes::Buf;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use derive_more::{AsRef, Deref};
|
||||
use reth_primitives_traits::{InMemorySize, SignedTransaction};
|
||||
use revm_primitives::keccak256;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A response to `GetPooledTransactions`. This can include either a blob transaction, or a
|
||||
@@ -153,6 +155,18 @@ impl PooledTransactionsElement {
|
||||
}
|
||||
}
|
||||
|
||||
/// This encodes the transaction _without_ the signature, and is only suitable for creating a
|
||||
/// hash intended for signing.
|
||||
pub fn encode_for_signing(&self, out: &mut dyn bytes::BufMut) {
|
||||
match self {
|
||||
Self::Legacy(tx) => tx.tx().encode_for_signing(out),
|
||||
Self::Eip2930(tx) => tx.tx().encode_for_signing(out),
|
||||
Self::Eip1559(tx) => tx.tx().encode_for_signing(out),
|
||||
Self::BlobTransaction(tx) => tx.tx().encode_for_signing(out),
|
||||
Self::Eip7702(tx) => tx.tx().encode_for_signing(out),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create [`TransactionSignedEcRecovered`] by converting this transaction into
|
||||
/// [`TransactionSigned`] and [`Address`] of the signer.
|
||||
pub fn into_ecrecovered_transaction(self, signer: Address) -> TransactionSignedEcRecovered {
|
||||
@@ -600,8 +614,9 @@ impl SignedTransaction for PooledTransactionsElement {
|
||||
recover_signer(self.signature(), signature_hash)
|
||||
}
|
||||
|
||||
fn recover_signer_unchecked(&self) -> Option<Address> {
|
||||
let signature_hash = self.signature_hash();
|
||||
fn recover_signer_unchecked_with_buf(&self, buf: &mut Vec<u8>) -> Option<Address> {
|
||||
self.encode_for_signing(buf);
|
||||
let signature_hash = keccak256(buf);
|
||||
recover_signer_unchecked(self.signature(), signature_hash)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use alloy_primitives::{Address, TxNumber};
|
||||
use reth_config::config::SenderRecoveryConfig;
|
||||
use reth_consensus::ConsensusError;
|
||||
use reth_db::{static_file::TransactionMask, tables, RawValue};
|
||||
use reth_db::{static_file::TransactionMask, table::Value, tables, RawValue};
|
||||
use reth_db_api::{
|
||||
cursor::DbCursorRW,
|
||||
transaction::{DbTx, DbTxMut},
|
||||
DbTxUnwindExt,
|
||||
};
|
||||
use reth_primitives::{GotExpected, StaticFileSegment, TransactionSignedNoHash};
|
||||
use reth_primitives::{GotExpected, NodePrimitives, StaticFileSegment};
|
||||
use reth_primitives_traits::SignedTransaction;
|
||||
use reth_provider::{
|
||||
BlockReader, DBProvider, HeaderProvider, ProviderError, PruneCheckpointReader,
|
||||
StaticFileProviderFactory, StatsReader,
|
||||
@@ -59,7 +60,7 @@ impl<Provider> Stage<Provider> for SenderRecoveryStage
|
||||
where
|
||||
Provider: DBProvider<Tx: DbTxMut>
|
||||
+ BlockReader
|
||||
+ StaticFileProviderFactory
|
||||
+ StaticFileProviderFactory<Primitives: NodePrimitives<SignedTx: Value + SignedTransaction>>
|
||||
+ StatsReader
|
||||
+ PruneCheckpointReader,
|
||||
{
|
||||
@@ -233,7 +234,9 @@ fn setup_range_recovery<Provider>(
|
||||
provider: &Provider,
|
||||
) -> mpsc::Sender<Vec<(Range<u64>, RecoveryResultSender)>>
|
||||
where
|
||||
Provider: DBProvider + HeaderProvider + StaticFileProviderFactory,
|
||||
Provider: DBProvider
|
||||
+ HeaderProvider
|
||||
+ StaticFileProviderFactory<Primitives: NodePrimitives<SignedTx: Value + SignedTransaction>>,
|
||||
{
|
||||
let (tx_sender, tx_receiver) = mpsc::channel::<Vec<(Range<u64>, RecoveryResultSender)>>();
|
||||
let static_file_provider = provider.static_file_provider();
|
||||
@@ -254,9 +257,9 @@ where
|
||||
chunk_range.clone(),
|
||||
|cursor, number| {
|
||||
Ok(cursor
|
||||
.get_one::<TransactionMask<RawValue<TransactionSignedNoHash>>>(
|
||||
number.into(),
|
||||
)?
|
||||
.get_one::<TransactionMask<
|
||||
RawValue<<Provider::Primitives as NodePrimitives>::SignedTx>,
|
||||
>>(number.into())?
|
||||
.map(|tx| (number, tx)))
|
||||
},
|
||||
|_| true,
|
||||
@@ -300,17 +303,18 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn recover_sender(
|
||||
(tx_id, tx): (TxNumber, TransactionSignedNoHash),
|
||||
fn recover_sender<T: SignedTransaction>(
|
||||
(tx_id, tx): (TxNumber, T),
|
||||
rlp_buf: &mut Vec<u8>,
|
||||
) -> Result<(u64, Address), Box<SenderRecoveryStageError>> {
|
||||
rlp_buf.clear();
|
||||
// We call [Signature::encode_and_recover_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
|
||||
.encode_and_recover_unchecked(rlp_buf)
|
||||
.recover_signer_unchecked_with_buf(rlp_buf)
|
||||
.ok_or(SenderRecoveryStageError::FailedRecovery(FailedSenderRecoveryError { tx: tx_id }))?;
|
||||
|
||||
Ok((tx_id, sender))
|
||||
|
||||
Reference in New Issue
Block a user