From eb4126b78daf6358a9b7ea28212d4f217093a7dc Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 31 Aug 2023 17:54:46 -0700 Subject: [PATCH] feat: add blob count checks (#4447) Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com> --- crates/primitives/src/constants/eip4844.rs | 2 +- crates/rpc/rpc/src/eth/error.rs | 21 ++++++++++++++-- crates/transaction-pool/src/error.rs | 25 ++++++++++++++++--- crates/transaction-pool/src/traits.rs | 5 ++++ crates/transaction-pool/src/validate/eth.rs | 27 +++++++++++++++++++-- 5 files changed, 72 insertions(+), 8 deletions(-) diff --git a/crates/primitives/src/constants/eip4844.rs b/crates/primitives/src/constants/eip4844.rs index cb971c9f1..751ddb739 100644 --- a/crates/primitives/src/constants/eip4844.rs +++ b/crates/primitives/src/constants/eip4844.rs @@ -20,7 +20,7 @@ pub const MAX_DATA_GAS_PER_BLOCK: u64 = 786_432u64; // 0xC0000 pub const TARGET_DATA_GAS_PER_BLOCK: u64 = 393_216u64; // 0x60000 /// Maximum number of data blobs in a single block. -pub const MAX_BLOBS_PER_BLOCK: u64 = MAX_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB; // 786432 / 131072 = 6 +pub const MAX_BLOBS_PER_BLOCK: usize = (MAX_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB) as usize; // 786432 / 131072 = 6 /// Target number of data blobs in a single block. pub const TARGET_BLOBS_PER_BLOCK: u64 = TARGET_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB; // 393216 / 131072 = 3 diff --git a/crates/rpc/rpc/src/eth/error.rs b/crates/rpc/rpc/src/eth/error.rs index 36151b568..eb5897b27 100644 --- a/crates/rpc/rpc/src/eth/error.rs +++ b/crates/rpc/rpc/src/eth/error.rs @@ -473,8 +473,19 @@ pub enum RpcPoolError { #[error("{0:?}")] PoolTransactionError(Box), /// Unable to find the blob for an EIP4844 transaction - #[error("blob not found for EIP4844 transaction")] + #[error("blob sidecar not found for EIP4844 transaction")] MissingEip4844Blob, + /// Thrown if an EIP-4844 without any blobs arrives + #[error("blobless blob transaction")] + NoEip4844Blobs, + /// Thrown if an EIP-4844 without any blobs arrives + #[error("too many blobs in transaction: have {have}, permitted {permitted}")] + TooManyEip4844Blobs { + /// Number of blobs the transaction has + have: usize, + /// Number of maximum blobs the transaction can have + permitted: usize, + }, /// Thrown if validating the blob sidecar for the transaction failed. #[error(transparent)] InvalidEip4844Blob(BlobTransactionValidationError), @@ -516,7 +527,13 @@ impl From for RpcPoolError { InvalidPoolTransactionError::OversizedData(_, _) => RpcPoolError::OversizedData, InvalidPoolTransactionError::Underpriced => RpcPoolError::Underpriced, InvalidPoolTransactionError::Other(err) => RpcPoolError::PoolTransactionError(err), - InvalidPoolTransactionError::MissingEip4844Blob => RpcPoolError::MissingEip4844Blob, + InvalidPoolTransactionError::MissingEip4844BlobSidecar => { + RpcPoolError::MissingEip4844Blob + } + InvalidPoolTransactionError::NoEip4844Blobs => RpcPoolError::NoEip4844Blobs, + InvalidPoolTransactionError::TooManyEip4844Blobs { have, permitted } => { + RpcPoolError::TooManyEip4844Blobs { have, permitted } + } InvalidPoolTransactionError::InvalidEip4844Blob(err) => { RpcPoolError::InvalidEip4844Blob(err) } diff --git a/crates/transaction-pool/src/error.rs b/crates/transaction-pool/src/error.rs index c1e844e09..d9685b3a4 100644 --- a/crates/transaction-pool/src/error.rs +++ b/crates/transaction-pool/src/error.rs @@ -139,8 +139,19 @@ pub enum InvalidPoolTransactionError { #[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, + #[error("blob sidecar not found for EIP4844 transaction")] + MissingEip4844BlobSidecar, + /// Thrown if an EIP-4844 without any blobs arrives + #[error("blobless blob transaction")] + NoEip4844Blobs, + /// Thrown if an EIP-4844 without any blobs arrives + #[error("too many blobs in transaction: have {have}, permitted {permitted}")] + TooManyEip4844Blobs { + /// Number of blobs the transaction has + have: usize, + /// Number of maximum blobs the transaction can have + permitted: usize, + }, /// Thrown if validating the blob sidecar for the transaction failed. #[error(transparent)] InvalidEip4844Blob(BlobTransactionValidationError), @@ -209,7 +220,7 @@ impl InvalidPoolTransactionError { false } InvalidPoolTransactionError::Other(err) => err.is_bad_transaction(), - InvalidPoolTransactionError::MissingEip4844Blob => { + InvalidPoolTransactionError::MissingEip4844BlobSidecar => { // this is only reachable when blob transactions are reinjected and we're unable to // find the previously extracted blob false @@ -223,6 +234,14 @@ impl InvalidPoolTransactionError { // thrown for valid(good) blob transactions false } + InvalidPoolTransactionError::NoEip4844Blobs => { + // this is a malformed transaction and should not be sent over the network + true + } + InvalidPoolTransactionError::TooManyEip4844Blobs { .. } => { + // this is a malformed transaction and should not be sent over the network + true + } } } } diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index 6ef34cb6f..862ce14ba 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -666,6 +666,11 @@ pub trait EthPoolTransaction: PoolTransaction { /// Extracts the blob sidecar from the transaction. fn take_blob(&mut self) -> EthBlobTransactionSidecar; + /// Returns the number of blobs this transaction has. + fn blob_count(&self) -> usize { + self.as_eip4844().map(|tx| tx.blob_versioned_hashes.len()).unwrap_or_default() + } + /// Returns the transaction as EIP-4844 transaction if it is one. fn as_eip4844(&self) -> Option<&TxEip4844>; diff --git a/crates/transaction-pool/src/validate/eth.rs b/crates/transaction-pool/src/validate/eth.rs index 223149b07..814613a50 100644 --- a/crates/transaction-pool/src/validate/eth.rs +++ b/crates/transaction-pool/src/validate/eth.rs @@ -9,7 +9,10 @@ use crate::{ TransactionValidationTaskExecutor, TransactionValidator, }; use reth_primitives::{ - constants::{eip4844::MAINNET_KZG_TRUSTED_SETUP, ETHEREUM_BLOCK_GAS_LIMIT}, + constants::{ + eip4844::{MAINNET_KZG_TRUSTED_SETUP, MAX_BLOBS_PER_BLOCK}, + ETHEREUM_BLOCK_GAS_LIMIT, + }, kzg::KzgSettings, ChainSpec, InvalidTransactionError, SealedBlock, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, LEGACY_TX_TYPE_ID, @@ -209,6 +212,26 @@ where ) } + let blob_count = transaction.blob_count(); + if blob_count == 0 { + // no blobs + return TransactionValidationOutcome::Invalid( + transaction, + InvalidPoolTransactionError::NoEip4844Blobs, + ) + } + + if blob_count > MAX_BLOBS_PER_BLOCK { + // too many blobs + return TransactionValidationOutcome::Invalid( + transaction, + InvalidPoolTransactionError::TooManyEip4844Blobs { + have: blob_count, + permitted: MAX_BLOBS_PER_BLOCK, + }, + ) + } + // extract the blob from the transaction match transaction.take_blob() { EthBlobTransactionSidecar::None => { @@ -224,7 +247,7 @@ where } else { return TransactionValidationOutcome::Invalid( transaction, - InvalidPoolTransactionError::MissingEip4844Blob, + InvalidPoolTransactionError::MissingEip4844BlobSidecar, ) } }