feat: add eth extension trait for EthValidator (#4343)

This commit is contained in:
Matthias Seitz
2023-08-24 19:27:51 +02:00
committed by GitHub
parent 0beaf85f4b
commit f0346c697e
6 changed files with 79 additions and 12 deletions

View File

@@ -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,
}
}
}

View File

@@ -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
}
}
}
}

View File

@@ -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,

View File

@@ -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)

View File

@@ -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,

View File

@@ -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 {