From 2fc574f32999fbfd966ad137c9b3cfc190e48e48 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Tue, 29 Aug 2023 09:25:34 -0700 Subject: [PATCH] feat: validate blobs (#4388) --- crates/primitives/src/transaction/mod.rs | 32 +++++++++++++++++++++ crates/rpc/rpc/src/eth/error.rs | 10 ++++++- crates/transaction-pool/src/error.rs | 9 +++++- crates/transaction-pool/src/traits.rs | 11 +++++-- crates/transaction-pool/src/validate/eth.rs | 24 ++++++++++++---- 5 files changed, 77 insertions(+), 9 deletions(-) diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index bce71de9a..ae420d4f7 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -414,6 +414,38 @@ impl Transaction { pub fn is_eip4844(&self) -> bool { matches!(self, Transaction::Eip4844(_)) } + + /// Returns the [TxLegacy] variant if the transaction is a legacy transaction. + pub fn as_legacy(&self) -> Option<&TxLegacy> { + match self { + Transaction::Legacy(tx) => Some(tx), + _ => None, + } + } + + /// Returns the [TxEip2930] variant if the transaction is an EIP-2930 transaction. + pub fn as_eip2830(&self) -> Option<&TxEip2930> { + match self { + Transaction::Eip2930(tx) => Some(tx), + _ => None, + } + } + + /// Returns the [TxEip1559] variant if the transaction is an EIP-1559 transaction. + pub fn as_eip1559(&self) -> Option<&TxEip1559> { + match self { + Transaction::Eip1559(tx) => Some(tx), + _ => None, + } + } + + /// Returns the [TxEip4844] variant if the transaction is an EIP-4844 transaction. + pub fn as_eip4844(&self) -> Option<&TxEip4844> { + match self { + Transaction::Eip4844(tx) => Some(tx), + _ => None, + } + } } impl Compact for Transaction { diff --git a/crates/rpc/rpc/src/eth/error.rs b/crates/rpc/rpc/src/eth/error.rs index 044f56212..ea281c431 100644 --- a/crates/rpc/rpc/src/eth/error.rs +++ b/crates/rpc/rpc/src/eth/error.rs @@ -5,7 +5,9 @@ use jsonrpsee::{ core::Error as RpcError, types::{error::CALL_EXECUTION_FAILED_CODE, ErrorObject}, }; -use reth_primitives::{abi::decode_revert_reason, Address, Bytes, U256}; +use reth_primitives::{ + abi::decode_revert_reason, Address, BlobTransactionValidationError, Bytes, U256, +}; use reth_revm::tracing::js::JsInspectorError; use reth_rpc_types::{error::EthRpcErrorCode, BlockError, CallInputError}; use reth_transaction_pool::error::{InvalidPoolTransactionError, PoolError, PoolTransactionError}; @@ -473,6 +475,9 @@ pub enum RpcPoolError { /// Unable to find the blob for an EIP4844 transaction #[error("blob not found for EIP4844 transaction")] MissingEip4844Blob, + /// Thrown if validating the blob sidecar for the transaction failed. + #[error(transparent)] + InvalidEip4844Blob(BlobTransactionValidationError), #[error(transparent)] Other(Box), } @@ -512,6 +517,9 @@ impl From for RpcPoolError { InvalidPoolTransactionError::Underpriced => RpcPoolError::Underpriced, InvalidPoolTransactionError::Other(err) => RpcPoolError::PoolTransactionError(err), InvalidPoolTransactionError::MissingEip4844Blob => RpcPoolError::MissingEip4844Blob, + InvalidPoolTransactionError::InvalidEip4844Blob(err) => { + RpcPoolError::InvalidEip4844Blob(err) + } } } } diff --git a/crates/transaction-pool/src/error.rs b/crates/transaction-pool/src/error.rs index fd2ca0bf7..658f10d32 100644 --- a/crates/transaction-pool/src/error.rs +++ b/crates/transaction-pool/src/error.rs @@ -1,6 +1,6 @@ //! Transaction pool errors -use reth_primitives::{Address, InvalidTransactionError, TxHash}; +use reth_primitives::{Address, BlobTransactionValidationError, InvalidTransactionError, TxHash}; /// Transaction pool result type. pub type PoolResult = Result; @@ -141,6 +141,9 @@ pub enum InvalidPoolTransactionError { /// Thrown if we're unable to find the blob for a transaction that was previously extracted #[error("blob not found for EIP4844 transaction")] MissingEip4844Blob, + /// Thrown if validating the blob sidecar for the transaction failed. + #[error(transparent)] + InvalidEip4844Blob(BlobTransactionValidationError), /// Any other error that occurred while inserting/validating that is transaction specific #[error("{0:?}")] Other(Box), @@ -203,6 +206,10 @@ impl InvalidPoolTransactionError { // find the previously extracted blob false } + InvalidPoolTransactionError::InvalidEip4844Blob(_) => { + // This is only reachable when the blob is invalid + true + } } } } diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index 53c7d9f71..7b94d354d 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -9,8 +9,8 @@ use reth_primitives::{ Address, BlobTransactionSidecar, BlobTransactionValidationError, FromRecoveredPooledTransaction, FromRecoveredTransaction, IntoRecoveredTransaction, PeerId, PooledTransactionsElement, PooledTransactionsElementEcRecovered, SealedBlock, Transaction, - TransactionKind, TransactionSignedEcRecovered, TxHash, EIP1559_TX_TYPE_ID, EIP4844_TX_TYPE_ID, - H256, U256, + TransactionKind, TransactionSignedEcRecovered, TxEip4844, TxHash, EIP1559_TX_TYPE_ID, + EIP4844_TX_TYPE_ID, H256, U256, }; use reth_rlp::Encodable; use std::{ @@ -656,6 +656,9 @@ pub trait EthPoolTransaction: PoolTransaction { /// Extracts the blob sidecar from the transaction. fn take_blob(&mut self) -> EthBlobTransactionSidecar; + /// Returns the transaction as EIP-4844 transaction if it is one. + fn as_eip4844(&self) -> Option<&TxEip4844>; + /// Validates the blob sidecar of the transaction with the given settings. fn validate_blob( &self, @@ -845,6 +848,10 @@ impl EthPoolTransaction for EthPooledTransaction { } } + fn as_eip4844(&self) -> Option<&TxEip4844> { + self.transaction.as_eip4844() + } + fn validate_blob( &self, sidecar: &BlobTransactionSidecar, diff --git a/crates/transaction-pool/src/validate/eth.rs b/crates/transaction-pool/src/validate/eth.rs index a61fec1ec..785fd0f60 100644 --- a/crates/transaction-pool/src/validate/eth.rs +++ b/crates/transaction-pool/src/validate/eth.rs @@ -74,7 +74,6 @@ pub(crate) struct EthTransactionValidatorInner { /// Toggle to determine if a local transaction should be propagated propagate_local_transactions: bool, /// Stores the setup and parameters needed for validating KZG proofs. - #[allow(unused)] kzg_settings: Arc, /// Marker for the transaction type _marker: PhantomData, @@ -198,7 +197,7 @@ where } } - let mut blob_sidecar = None; + let mut maybe_blob_sidecar = None; // blob tx checks if transaction.is_eip4844() { @@ -230,8 +229,23 @@ where } } EthBlobTransactionSidecar::Present(blob) => { - //TODO(mattsse): verify the blob - blob_sidecar = Some(blob); + if let Some(eip4844) = transaction.as_eip4844() { + // validate the blob + if let Err(err) = eip4844.validate_blob(&blob, &self.kzg_settings) { + return TransactionValidationOutcome::Invalid( + transaction, + InvalidPoolTransactionError::InvalidEip4844Blob(err), + ) + } + // store the extracted blob + maybe_blob_sidecar = Some(blob); + } else { + // this should not happen + return TransactionValidationOutcome::Invalid( + transaction, + InvalidTransactionError::TxTypeNotSupported.into(), + ) + } } } } @@ -281,7 +295,7 @@ where TransactionValidationOutcome::Valid { balance: account.balance, state_nonce: account.nonce, - transaction: ValidTransaction::new(transaction, blob_sidecar), + transaction: ValidTransaction::new(transaction, maybe_blob_sidecar), // by this point assume all external transactions should be propagated propagate: match origin { TransactionOrigin::External => true,