diff --git a/crates/net/network/src/transactions/fetcher.rs b/crates/net/network/src/transactions/fetcher.rs index 65bcf375b1..817e58c48d 100644 --- a/crates/net/network/src/transactions/fetcher.rs +++ b/crates/net/network/src/transactions/fetcher.rs @@ -16,7 +16,7 @@ use std::{ use tokio::sync::{mpsc::error::TrySendError, oneshot, oneshot::error::RecvError}; use tracing::{debug, trace}; -use super::{Peer, PooledTransactions, FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT}; +use super::{Peer, PooledTransactions, POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE}; /// Maximum concurrent [`GetPooledTxRequest`]s to allow per peer. pub(super) const MAX_CONCURRENT_TX_REQUESTS_PER_PEER: u8 = 1; @@ -175,7 +175,7 @@ impl TransactionFetcher { if let Some(size) = self.eth68_meta.peek(&hash) { let next_acc_size = *acc_size_response + size; - if next_acc_size <= FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT { + if next_acc_size <= POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE { // only update accumulated size of tx response if tx will fit in without exceeding // soft limit *acc_size_response = next_acc_size; @@ -205,7 +205,7 @@ impl TransactionFetcher { ) -> Vec { if let Some(hash) = hashes.first() { if let Some(size) = self.eth68_meta.get(hash) { - if *size >= FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT { + if *size >= POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE { return hashes.split_off(1) } } @@ -222,7 +222,8 @@ impl TransactionFetcher { hash=%hash, size=self.eth68_meta.peek(&hash).expect("should find size in `eth68-meta`"), acc_size_response=acc_size_response, - FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT=FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT, + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE= + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE, "no space for hash in `GetPooledTransactions` request to peer" ); @@ -233,7 +234,7 @@ impl TransactionFetcher { // all hashes included in request and there is still space // todo: compare free space with min tx size - if acc_size_response < FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT { + if acc_size_response < POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE { self.fill_eth68_request_for_peer(hashes, peer_id, &mut acc_size_response); } @@ -498,7 +499,7 @@ impl TransactionFetcher { peer_id: PeerId, acc_size_response: &mut usize, ) { - if *acc_size_response >= FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT { + if *acc_size_response >= POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE { return } @@ -522,11 +523,12 @@ impl TransactionFetcher { let mut next_acc_size = *acc_size_response; // 1. Check acc size against limit, if so stop looping. - if next_acc_size >= FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT { + if next_acc_size >= POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE { trace!(target: "net::tx", peer_id=format!("{peer_id:#}"), acc_size_eth68_response=acc_size_response, // no change acc size - FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT=FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT, + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE= + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE, "request to peer full" ); @@ -568,7 +570,8 @@ impl TransactionFetcher { peer_id=format!("{peer_id:#}"), hash=%hash, acc_size_eth68_response=acc_size_response, - FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT=FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT, + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE= + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE, "found buffered hash for request to peer" ); } @@ -629,7 +632,8 @@ impl TransactionFetcher { trace!(target: "net::tx", peer_id=format!("{peer_id:#}"), hash=%hash, - FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT=FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT, + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE= + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE, "found buffered hash for request to peer" ); } @@ -818,12 +822,14 @@ mod test { B256::from_slice(&[6; 32]), ]; let eth68_hashes_sizes = [ - FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT - 4, - FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT, // this one will not fit - 2, // this one will fit - 3, // but now this one won't - 2, /* this one will, no more txns will fit - * after this */ + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE - 4, + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE, // this one will not fit + 2, // this one will fit + 3, // but now this one won't + 2, /* this one will, no more txns + * will + * fit + * after this */ 1, ]; diff --git a/crates/net/network/src/transactions/mod.rs b/crates/net/network/src/transactions/mod.rs index 12ebe6850f..b61272f6ec 100644 --- a/crates/net/network/src/transactions/mod.rs +++ b/crates/net/network/src/transactions/mod.rs @@ -74,12 +74,11 @@ const PEER_TRANSACTION_CACHE_LIMIT: usize = 1024 * 10; /// Soft limit for NewPooledTransactions const NEW_POOLED_TRANSACTION_HASHES_SOFT_LIMIT: usize = 4096; -/// Soft limit for the message of full transactions in bytes. -const FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT: usize = 100 * 1024; - -/// Softlimit for the response size of a GetPooledTransactions message (2MB) -const GET_POOLED_TRANSACTION_SOFT_LIMIT_SIZE: GetPooledTransactionLimit = - GetPooledTransactionLimit::SizeSoftLimit(2 * 1024 * 1024); +/// Soft limit for the response size of a GetPooledTransactions message (2MB) in bytes. Standard +/// maximum response size. See specs +/// +/// . +const POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE: usize = 2 * 1024 * 1024; /// The future for inserting a function into the pool pub type PoolImportFuture = Pin> + Send + 'static>>; @@ -300,9 +299,12 @@ where let _ = response.send(Ok(PooledTransactions::default())); return } - let transactions = self - .pool - .get_pooled_transaction_elements(request.0, GET_POOLED_TRANSACTION_SOFT_LIMIT_SIZE); + let transactions = self.pool.get_pooled_transaction_elements( + request.0, + GetPooledTransactionLimit::ResponseSizeSoftLimit( + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE, + ), + ); // we sent a response at which point we assume that the peer is aware of the // transactions @@ -1112,7 +1114,7 @@ impl PropagateTransaction { } /// Helper type for constructing the full transaction message that enforces the -/// `FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT` +/// [`POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE`]. #[derive(Default)] struct FullTransactionsBuilder { total_size: usize, @@ -1125,7 +1127,7 @@ impl FullTransactionsBuilder { /// Append a transaction to the list if it doesn't exceed the maximum target size. fn push(&mut self, transaction: &PropagateTransaction) { let new_size = self.total_size + transaction.size; - if new_size > FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT { + if new_size > POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE { return } @@ -1790,8 +1792,8 @@ mod tests { let eth_version = EthVersion::Eth68; let unseen_eth68_hashes = [B256::from_slice(&[1; 32]), B256::from_slice(&[2; 32])]; let unseen_eth68_hashes_sizes = [ - FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT / 2, - FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT / 2 - 4, + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE / 2, + POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE / 2 - 4, ]; // hashes and sizes to buffer in reverse order so that seen_eth68_hashes[0] and // seen_eth68_hashes_sizes[0] are lru @@ -1828,7 +1830,9 @@ mod tests { let mut backups = default_cache(); backups.insert(peer_id_other); tx_fetcher.unknown_hashes.insert(hash_other, (0, backups)); - tx_fetcher.eth68_meta.insert(hash_other, FULL_TRANSACTIONS_PACKET_SIZE_SOFT_LIMIT - 2); // a big tx + tx_fetcher + .eth68_meta + .insert(hash_other, POOLED_TRANSACTIONS_RESPONSE_SOFT_LIMIT_BYTE_SIZE - 2); // a big tx tx_fetcher.buffered_hashes.insert(hash_other); let (peer, mut to_mock_session_rx) = new_mock_session(peer_id, eth_version); diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index c3ecac476e..b80d20a08f 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -1134,7 +1134,7 @@ pub enum GetPooledTransactionLimit { /// No limit, return all transactions. None, /// Enforce a size limit on the returned transactions, for example 2MB - SizeSoftLimit(usize), + ResponseSizeSoftLimit(usize), } impl GetPooledTransactionLimit { @@ -1143,7 +1143,7 @@ impl GetPooledTransactionLimit { pub fn exceeds(&self, size: usize) -> bool { match self { GetPooledTransactionLimit::None => false, - GetPooledTransactionLimit::SizeSoftLimit(limit) => size > *limit, + GetPooledTransactionLimit::ResponseSizeSoftLimit(limit) => size > *limit, } } } diff --git a/crates/transaction-pool/src/validate/constants.rs b/crates/transaction-pool/src/validate/constants.rs index 040087bdb0..9e4bf71fad 100644 --- a/crates/transaction-pool/src/validate/constants.rs +++ b/crates/transaction-pool/src/validate/constants.rs @@ -1,17 +1,17 @@ -/// TX_SLOT_SIZE is used to calculate how many data slots a single transaction -/// takes up based on its size. The slots are used as DoS protection, ensuring +/// [`TX_SLOT_BYTE_SIZE`] is used to calculate how many data slots a single transaction +/// takes up based on its byte size. The slots are used as DoS protection, ensuring /// that validating a new transaction remains a constant operation (in reality /// O(maxslots), where max slots are 4 currently). -pub const TX_SLOT_SIZE: usize = 32 * 1024; +pub const TX_SLOT_BYTE_SIZE: usize = 32 * 1024; -/// TX_MAX_SIZE is the maximum size a single transaction can have. This field has +/// [`MAX_TX_INPUT_BYTES`] is the maximum size a single transaction can have. This field has /// non-trivial consequences: larger transactions are significantly harder and /// more expensive to propagate; larger transactions also take more resources /// to validate whether they fit into the pool or not. -pub const TX_MAX_SIZE: usize = 4 * TX_SLOT_SIZE; // 128KB +pub const MAX_TX_INPUT_BYTES: usize = 4 * TX_SLOT_BYTE_SIZE; // 128KB -/// Maximum bytecode to permit for a contract -pub const MAX_CODE_SIZE: usize = 24576; +/// Maximum bytecode to permit for a contract. +pub const MAX_CODE_BYTE_SIZE: usize = 24576; -/// Maximum initcode to permit in a creation transaction and create instructions -pub const MAX_INIT_CODE_SIZE: usize = 2 * MAX_CODE_SIZE; +/// Maximum initcode to permit in a creation transaction and create instructions. +pub const MAX_INIT_CODE_BYTE_SIZE: usize = 2 * MAX_CODE_BYTE_SIZE; diff --git a/crates/transaction-pool/src/validate/eth.rs b/crates/transaction-pool/src/validate/eth.rs index 995386d05f..4894abd122 100644 --- a/crates/transaction-pool/src/validate/eth.rs +++ b/crates/transaction-pool/src/validate/eth.rs @@ -4,7 +4,7 @@ use crate::{ blobstore::BlobStore, error::{Eip4844PoolTransactionError, InvalidPoolTransactionError}, traits::TransactionOrigin, - validate::{ValidTransaction, ValidationTask, MAX_INIT_CODE_SIZE, TX_MAX_SIZE}, + validate::{ValidTransaction, ValidationTask, MAX_INIT_CODE_BYTE_SIZE, MAX_TX_INPUT_BYTES}, EthBlobTransactionSidecar, EthPoolTransaction, LocalTransactionConfig, PoolTransaction, TransactionValidationOutcome, TransactionValidationTaskExecutor, TransactionValidator, }; @@ -201,17 +201,17 @@ where }; // Reject transactions over defined size to prevent DOS attacks - if transaction.size() > TX_MAX_SIZE { + if transaction.size() > MAX_TX_INPUT_BYTES { let size = transaction.size(); return TransactionValidationOutcome::Invalid( transaction, - InvalidPoolTransactionError::OversizedData(size, TX_MAX_SIZE), + InvalidPoolTransactionError::OversizedData(size, MAX_TX_INPUT_BYTES), ) } // Check whether the init code size has been exceeded. if self.fork_tracker.is_shanghai_activated() { - if let Err(err) = ensure_max_init_code_size(&transaction, MAX_INIT_CODE_SIZE) { + if let Err(err) = ensure_max_init_code_size(&transaction, MAX_INIT_CODE_BYTE_SIZE) { return TransactionValidationOutcome::Invalid(transaction, err) } } diff --git a/crates/transaction-pool/src/validate/mod.rs b/crates/transaction-pool/src/validate/mod.rs index 3338aca60b..44ca627a51 100644 --- a/crates/transaction-pool/src/validate/mod.rs +++ b/crates/transaction-pool/src/validate/mod.rs @@ -22,7 +22,9 @@ pub use eth::*; pub use task::{TransactionValidationTaskExecutor, ValidationTask}; /// Validation constants. -pub use constants::{MAX_CODE_SIZE, MAX_INIT_CODE_SIZE, TX_MAX_SIZE, TX_SLOT_SIZE}; +pub use constants::{ + MAX_CODE_BYTE_SIZE, MAX_INIT_CODE_BYTE_SIZE, MAX_TX_INPUT_BYTES, TX_SLOT_BYTE_SIZE, +}; /// A Result type returned after checking a transaction's validity. #[derive(Debug)]