mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-28 08:37:59 -05:00
feat: add eth extension trait for EthValidator (#4343)
This commit is contained in:
@@ -470,6 +470,9 @@ pub enum RpcPoolError {
|
||||
/// Custom pool error
|
||||
#[error("{0:?}")]
|
||||
PoolTransactionError(Box<dyn PoolTransactionError>),
|
||||
/// Unable to find the blob for an EIP4844 transaction
|
||||
#[error("blob not found for EIP4844 transaction")]
|
||||
MissingEip4844Blob,
|
||||
#[error(transparent)]
|
||||
Other(Box<dyn std::error::Error + Send + Sync>),
|
||||
}
|
||||
@@ -508,6 +511,7 @@ impl From<InvalidPoolTransactionError> for RpcPoolError {
|
||||
InvalidPoolTransactionError::OversizedData(_, _) => RpcPoolError::OversizedData,
|
||||
InvalidPoolTransactionError::Underpriced => RpcPoolError::Underpriced,
|
||||
InvalidPoolTransactionError::Other(err) => RpcPoolError::PoolTransactionError(err),
|
||||
InvalidPoolTransactionError::MissingEip4844Blob => RpcPoolError::MissingEip4844Blob,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +138,9 @@ pub enum InvalidPoolTransactionError {
|
||||
/// Thrown if the transaction's fee is below the minimum fee
|
||||
#[error("transaction underpriced")]
|
||||
Underpriced,
|
||||
/// Thrown if we're unable to find the blob for a transaction that was previously extracted
|
||||
#[error("blob not found for EIP4844 transaction")]
|
||||
MissingEip4844Blob,
|
||||
/// Any other error that occurred while inserting/validating that is transaction specific
|
||||
#[error("{0:?}")]
|
||||
Other(Box<dyn PoolTransactionError>),
|
||||
@@ -195,6 +198,11 @@ impl InvalidPoolTransactionError {
|
||||
false
|
||||
}
|
||||
InvalidPoolTransactionError::Other(err) => err.is_bad_transaction(),
|
||||
InvalidPoolTransactionError::MissingEip4844Blob => {
|
||||
// this is only reachable when blob transactions are reinjected and we're unable to
|
||||
// find the previously extracted blob
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,9 +180,10 @@ pub use crate::{
|
||||
},
|
||||
traits::{
|
||||
AllPoolTransactions, BestTransactions, BlockInfo, CanonicalStateUpdate, ChangedAccount,
|
||||
EthPooledTransaction, GetPooledTransactionLimit, NewTransactionEvent,
|
||||
PendingTransactionListenerKind, PoolSize, PoolTransaction, PropagateKind,
|
||||
PropagatedTransactions, TransactionOrigin, TransactionPool, TransactionPoolExt,
|
||||
EthBlobTransactionSidecar, EthPoolTransaction, EthPooledTransaction,
|
||||
GetPooledTransactionLimit, NewTransactionEvent, PendingTransactionListenerKind, PoolSize,
|
||||
PoolTransaction, PropagateKind, PropagatedTransactions, TransactionOrigin, TransactionPool,
|
||||
TransactionPoolExt,
|
||||
},
|
||||
validate::{
|
||||
EthTransactionValidator, TransactionValidationOutcome, TransactionValidationTaskExecutor,
|
||||
|
||||
@@ -640,6 +640,13 @@ pub trait PoolTransaction:
|
||||
fn chain_id(&self) -> Option<u64>;
|
||||
}
|
||||
|
||||
/// An extension trait that provides additional interfaces for the
|
||||
/// [EthTransactionValidator](crate::EthTransactionValidator).
|
||||
pub trait EthPoolTransaction: PoolTransaction {
|
||||
/// Extracts the blob sidecar from the transaction.
|
||||
fn take_blob(&mut self) -> EthBlobTransactionSidecar;
|
||||
}
|
||||
|
||||
/// The default [PoolTransaction] for the [Pool](crate::Pool) for Ethereum.
|
||||
///
|
||||
/// This type is essentially a wrapper around [TransactionSignedEcRecovered] with additional fields
|
||||
@@ -659,7 +666,7 @@ pub struct EthPooledTransaction {
|
||||
|
||||
/// Represents the blob sidecar of the [EthPooledTransaction].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) enum EthBlobTransactionSidecar {
|
||||
pub enum EthBlobTransactionSidecar {
|
||||
/// This transaction does not have a blob sidecar
|
||||
None,
|
||||
/// This transaction has a blob sidecar (EIP-4844) but it is missing
|
||||
@@ -812,6 +819,16 @@ impl PoolTransaction for EthPooledTransaction {
|
||||
}
|
||||
}
|
||||
|
||||
impl EthPoolTransaction for EthPooledTransaction {
|
||||
fn take_blob(&mut self) -> EthBlobTransactionSidecar {
|
||||
if self.is_eip4844() {
|
||||
std::mem::replace(&mut self.blob_sidecar, EthBlobTransactionSidecar::Missing)
|
||||
} else {
|
||||
EthBlobTransactionSidecar::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRecoveredTransaction for EthPooledTransaction {
|
||||
fn from_recovered_transaction(tx: TransactionSignedEcRecovered) -> Self {
|
||||
EthPooledTransaction::new(tx)
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
use crate::{
|
||||
blobstore::BlobStore,
|
||||
error::InvalidPoolTransactionError,
|
||||
traits::{PoolTransaction, TransactionOrigin},
|
||||
traits::TransactionOrigin,
|
||||
validate::{ValidTransaction, ValidationTask, MAX_INIT_CODE_SIZE, TX_MAX_SIZE},
|
||||
TransactionValidationOutcome, TransactionValidationTaskExecutor, TransactionValidator,
|
||||
EthBlobTransactionSidecar, EthPoolTransaction, TransactionValidationOutcome,
|
||||
TransactionValidationTaskExecutor, TransactionValidator,
|
||||
};
|
||||
use reth_primitives::{
|
||||
constants::{eip4844::KZG_TRUSTED_SETUP, ETHEREUM_BLOCK_GAS_LIMIT},
|
||||
@@ -32,7 +33,7 @@ pub struct EthTransactionValidator<Client, T> {
|
||||
impl<Client, Tx> TransactionValidator for EthTransactionValidator<Client, Tx>
|
||||
where
|
||||
Client: StateProviderFactory,
|
||||
Tx: PoolTransaction,
|
||||
Tx: EthPoolTransaction,
|
||||
{
|
||||
type Transaction = Tx;
|
||||
|
||||
@@ -57,7 +58,6 @@ pub(crate) struct EthTransactionValidatorInner<Client, T> {
|
||||
/// This type fetches account info from the db
|
||||
client: Client,
|
||||
/// Blobstore used for fetching re-injected blob transactions.
|
||||
#[allow(unused)]
|
||||
blob_store: Box<dyn BlobStore>,
|
||||
/// tracks activated forks relevant for transaction validation
|
||||
fork_tracker: ForkTracker,
|
||||
@@ -93,14 +93,14 @@ impl<Client, Tx> EthTransactionValidatorInner<Client, Tx> {
|
||||
impl<Client, Tx> TransactionValidator for EthTransactionValidatorInner<Client, Tx>
|
||||
where
|
||||
Client: StateProviderFactory,
|
||||
Tx: PoolTransaction,
|
||||
Tx: EthPoolTransaction,
|
||||
{
|
||||
type Transaction = Tx;
|
||||
|
||||
async fn validate_transaction(
|
||||
&self,
|
||||
origin: TransactionOrigin,
|
||||
transaction: Self::Transaction,
|
||||
mut transaction: Self::Transaction,
|
||||
) -> TransactionValidationOutcome<Self::Transaction> {
|
||||
// Checks for tx_type
|
||||
match transaction.tx_type() {
|
||||
@@ -198,6 +198,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
let mut blob_sidecar = None;
|
||||
|
||||
// blob tx checks
|
||||
if transaction.is_eip4844() {
|
||||
// Cancun fork is required for blob txs
|
||||
@@ -207,7 +209,31 @@ where
|
||||
InvalidTransactionError::TxTypeNotSupported.into(),
|
||||
)
|
||||
}
|
||||
// TODO add checks for blob tx
|
||||
|
||||
// extract the blob from the transaction
|
||||
match transaction.take_blob() {
|
||||
EthBlobTransactionSidecar::None => {
|
||||
// this should not happen
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidTransactionError::TxTypeNotSupported.into(),
|
||||
)
|
||||
}
|
||||
EthBlobTransactionSidecar::Missing => {
|
||||
if let Ok(Some(_)) = self.blob_store.get(*transaction.hash()) {
|
||||
// validated transaction is already in the store
|
||||
} else {
|
||||
return TransactionValidationOutcome::Invalid(
|
||||
transaction,
|
||||
InvalidPoolTransactionError::MissingEip4844Blob,
|
||||
)
|
||||
}
|
||||
}
|
||||
EthBlobTransactionSidecar::Present(blob) => {
|
||||
//TODO(mattsse): verify the blob
|
||||
blob_sidecar = Some(blob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let account = match self
|
||||
@@ -255,7 +281,7 @@ where
|
||||
TransactionValidationOutcome::Valid {
|
||||
balance: account.balance,
|
||||
state_nonce: account.nonce,
|
||||
transaction: ValidTransaction::Valid(transaction),
|
||||
transaction: ValidTransaction::new(transaction, blob_sidecar),
|
||||
// by this point assume all external transactions should be propagated
|
||||
propagate: match origin {
|
||||
TransactionOrigin::External => true,
|
||||
|
||||
@@ -86,6 +86,17 @@ pub enum ValidTransaction<T> {
|
||||
},
|
||||
}
|
||||
|
||||
impl<T> ValidTransaction<T> {
|
||||
/// Creates a new valid transaction with an optional sidecar.
|
||||
pub fn new(transaction: T, sidecar: Option<BlobTransactionSidecar>) -> Self {
|
||||
if let Some(sidecar) = sidecar {
|
||||
Self::ValidWithSidecar { transaction, sidecar }
|
||||
} else {
|
||||
Self::Valid(transaction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PoolTransaction> ValidTransaction<T> {
|
||||
#[inline]
|
||||
pub(crate) fn transaction(&self) -> &T {
|
||||
|
||||
Reference in New Issue
Block a user