feat: truncate blob pool when discarding worst (#5634)

This commit is contained in:
Dan Cline
2023-11-30 06:41:28 -05:00
committed by GitHub
parent d93eac2193
commit a7f474cb0b
3 changed files with 36 additions and 25 deletions

View File

@ -65,6 +65,10 @@ impl TxPoolArgs {
max_txs: self.queued_max_count,
max_size: self.queued_max_size * 1024 * 1024,
},
blob_limit: SubPoolLimit {
max_txs: self.queued_max_count,
max_size: self.queued_max_size * 1024 * 1024,
},
max_account_slots: self.max_account_slots,
price_bumps: PriceBumpConfig {
default_price_bump: self.price_bump,

View File

@ -26,6 +26,8 @@ pub struct PoolConfig {
pub basefee_limit: SubPoolLimit,
/// Max number of transaction in the queued sub-pool
pub queued_limit: SubPoolLimit,
/// Max number of transactions in the blob sub-pool
pub blob_limit: SubPoolLimit,
/// Max number of executable transaction slots guaranteed per account
pub max_account_slots: usize,
/// Price bump (in %) for the transaction pool underpriced check.
@ -41,6 +43,7 @@ impl Default for PoolConfig {
pending_limit: Default::default(),
basefee_limit: Default::default(),
queued_limit: Default::default(),
blob_limit: Default::default(),
max_account_slots: TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER,
price_bumps: Default::default(),
local_transactions_config: Default::default(),

View File

@ -92,8 +92,13 @@ pub struct TxPool<T: TransactionOrdering> {
/// Holds all parked transactions that currently violate the dynamic fee requirement but could
/// be moved to pending if the base fee changes in their favor (decreases) in future blocks.
basefee_pool: ParkedPool<BasefeeOrd<T::Transaction>>,
/// All blob transactions in the pool
blob_transactions: BlobTransactions<T::Transaction>,
/// Blob transactions in the pool that are __not pending__.
///
/// This means they either do not satisfy the dynamic fee requirement or the blob fee
/// requirement. These transactions can be moved to pending if the base fee or blob fee changes
/// in their favor (decreases) in future blocks. The transaction may need both the base fee and
/// blob fee to decrease to become executable.
blob_pool: BlobTransactions<T::Transaction>,
/// All transactions in the pool.
all_transactions: AllTransactions<T::Transaction>,
/// Transaction pool metrics
@ -110,7 +115,7 @@ impl<T: TransactionOrdering> TxPool<T> {
pending_pool: PendingPool::new(ordering),
queued_pool: Default::default(),
basefee_pool: Default::default(),
blob_transactions: Default::default(),
blob_pool: Default::default(),
all_transactions: AllTransactions::new(&config),
config,
metrics: Default::default(),
@ -136,8 +141,8 @@ impl<T: TransactionOrdering> TxPool<T> {
basefee_size: self.basefee_pool.size(),
queued: self.queued_pool.len(),
queued_size: self.queued_pool.size(),
blob: self.blob_transactions.len(),
blob_size: self.blob_transactions.size(),
blob: self.blob_pool.len(),
blob_size: self.blob_pool.size(),
total: self.all_transactions.len(),
}
}
@ -182,9 +187,8 @@ impl<T: TransactionOrdering> TxPool<T> {
(Ordering::Less, Ordering::Equal) | (_, Ordering::Less) => {
// decreased blob fee or base fee: recheck blob pool and promote all that are now
// valid
let removed = self
.blob_transactions
.enforce_pending_fees(&self.all_transactions.pending_fees);
let removed =
self.blob_pool.enforce_pending_fees(&self.all_transactions.pending_fees);
for tx in removed {
let to = {
let tx =
@ -216,9 +220,8 @@ impl<T: TransactionOrdering> TxPool<T> {
// decreased blob fee or base fee: recheck blob pool and promote all that are now
// valid
let removed = self
.blob_transactions
.enforce_pending_fees(&self.all_transactions.pending_fees);
let removed =
self.blob_pool.enforce_pending_fees(&self.all_transactions.pending_fees);
for tx in removed {
let to = {
let tx =
@ -355,7 +358,7 @@ impl<T: TransactionOrdering> TxPool<T> {
// base fee decreased, we need to move transactions from the basefee pool to the
// pending pool and satisfy blob fee transactions as well
let unlocked_with_blob =
self.blob_transactions.satisfy_attributes(best_transactions_attributes);
self.blob_pool.satisfy_attributes(best_transactions_attributes);
Box::new(self.pending_pool.best_with_unlocked(
unlocked_with_blob,
@ -389,7 +392,7 @@ impl<T: TransactionOrdering> TxPool<T> {
SubPool::Queued => self.queued_pool.contains(id),
SubPool::Pending => self.pending_pool.contains(id),
SubPool::BaseFee => self.basefee_pool.contains(id),
SubPool::Blob => self.blob_transactions.contains(id),
SubPool::Blob => self.blob_pool.contains(id),
}
}
@ -695,7 +698,7 @@ impl<T: TransactionOrdering> TxPool<T> {
SubPool::Queued => self.queued_pool.remove_transaction(tx),
SubPool::Pending => self.pending_pool.remove_transaction(tx),
SubPool::BaseFee => self.basefee_pool.remove_transaction(tx),
SubPool::Blob => self.blob_transactions.remove_transaction(tx),
SubPool::Blob => self.blob_pool.remove_transaction(tx),
}
}
@ -710,7 +713,7 @@ impl<T: TransactionOrdering> TxPool<T> {
SubPool::Pending => self.pending_pool.prune_transaction(tx),
SubPool::Queued => self.queued_pool.remove_transaction(tx),
SubPool::BaseFee => self.basefee_pool.remove_transaction(tx),
SubPool::Blob => self.blob_transactions.remove_transaction(tx),
SubPool::Blob => self.blob_pool.remove_transaction(tx),
}
}
@ -756,7 +759,7 @@ impl<T: TransactionOrdering> TxPool<T> {
self.basefee_pool.add_transaction(tx);
}
SubPool::Blob => {
self.blob_transactions.add_transaction(tx);
self.blob_pool.add_transaction(tx);
}
}
}
@ -807,6 +810,7 @@ impl<T: TransactionOrdering> TxPool<T> {
self, removed, [
pending_limit => pending_pool,
basefee_limit => basefee_pool,
blob_limit => blob_pool,
queued_limit => queued_pool
]
);
@ -840,7 +844,7 @@ impl<T: TransactionOrdering> TxPool<T> {
self.pending_pool.assert_invariants();
self.basefee_pool.assert_invariants();
self.queued_pool.assert_invariants();
self.blob_transactions.assert_invariants();
self.blob_pool.assert_invariants();
}
}
@ -1912,7 +1916,7 @@ mod tests {
pool.add_transaction(validated, on_chain_balance, on_chain_nonce).unwrap();
// assert pool lengths
assert!(pool.blob_transactions.is_empty());
assert!(pool.blob_pool.is_empty());
assert_eq!(pool.pending_pool.len(), 1);
// check tx state and derived subpool
@ -1930,7 +1934,7 @@ mod tests {
assert_eq!(internal_tx.subpool, SubPool::Blob);
// make sure the blob transaction was promoted into the pending pool
assert_eq!(pool.blob_transactions.len(), 1);
assert_eq!(pool.blob_pool.len(), 1);
assert!(pool.pending_pool.is_empty());
}
@ -1953,7 +1957,7 @@ mod tests {
// assert pool lengths
assert!(pool.pending_pool.is_empty());
assert_eq!(pool.blob_transactions.len(), 1);
assert_eq!(pool.blob_pool.len(), 1);
// check tx state and derived subpool
let internal_tx = pool.all_transactions.txs.get(&id).unwrap();
@ -1971,7 +1975,7 @@ mod tests {
// make sure the blob transaction was promoted into the pending pool
assert_eq!(pool.pending_pool.len(), 1);
assert!(pool.blob_transactions.is_empty());
assert!(pool.blob_pool.is_empty());
}
/// A struct representing a txpool promotion test instance
@ -2012,25 +2016,25 @@ mod tests {
) {
match check_subpool {
SubPool::Blob => {
assert_eq!(pool.blob_transactions.len(), 1, "{failure_message}");
assert_eq!(pool.blob_pool.len(), 1, "{failure_message}");
assert!(pool.pending_pool.is_empty(), "{failure_message}");
assert!(pool.basefee_pool.is_empty(), "{failure_message}");
assert!(pool.queued_pool.is_empty(), "{failure_message}");
}
SubPool::Pending => {
assert!(pool.blob_transactions.is_empty(), "{failure_message}");
assert!(pool.blob_pool.is_empty(), "{failure_message}");
assert_eq!(pool.pending_pool.len(), 1, "{failure_message}");
assert!(pool.basefee_pool.is_empty(), "{failure_message}");
assert!(pool.queued_pool.is_empty(), "{failure_message}");
}
SubPool::BaseFee => {
assert!(pool.blob_transactions.is_empty(), "{failure_message}");
assert!(pool.blob_pool.is_empty(), "{failure_message}");
assert!(pool.pending_pool.is_empty(), "{failure_message}");
assert_eq!(pool.basefee_pool.len(), 1, "{failure_message}");
assert!(pool.queued_pool.is_empty(), "{failure_message}");
}
SubPool::Queued => {
assert!(pool.blob_transactions.is_empty(), "{failure_message}");
assert!(pool.blob_pool.is_empty(), "{failure_message}");
assert!(pool.pending_pool.is_empty(), "{failure_message}");
assert!(pool.basefee_pool.is_empty(), "{failure_message}");
assert_eq!(pool.queued_pool.len(), 1, "{failure_message}");