feat: integrate price bump (#4398)

This commit is contained in:
Matthias Seitz
2023-08-29 11:22:28 -07:00
committed by GitHub
parent 0c7a93717a
commit 505be45559
4 changed files with 67 additions and 35 deletions

View File

@ -2,8 +2,9 @@
use clap::Args;
use reth_transaction_pool::{
PoolConfig, SubPoolLimit, DEFAULT_PRICE_BUMP, TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER,
TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT, TXPOOL_SUBPOOL_MAX_TXS_DEFAULT,
PoolConfig, PriceBumpConfig, SubPoolLimit, DEFAULT_PRICE_BUMP, REPLACE_BLOB_PRICE_BUMP,
TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER, TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT,
TXPOOL_SUBPOOL_MAX_TXS_DEFAULT,
};
/// Parameters for debugging purposes
@ -37,6 +38,10 @@ pub struct TxPoolArgs {
/// Price bump (in %) for the transaction pool underpriced check.
#[arg(long = "txpool.pricebump", help_heading = "TxPool", default_value_t = DEFAULT_PRICE_BUMP)]
pub price_bump: u128,
/// Price bump percentage to replace an already existing blob transaction
#[arg(long = "blobpool.pricebump", help_heading = "TxPool", default_value_t = REPLACE_BLOB_PRICE_BUMP)]
pub blob_transaction_price_bump: u128,
}
impl TxPoolArgs {
@ -56,7 +61,10 @@ impl TxPoolArgs {
max_size: self.queued_max_size * 1024 * 1024,
},
max_account_slots: self.max_account_slots,
price_bump: self.price_bump,
price_bumps: PriceBumpConfig {
default_price_bump: self.price_bump,
replace_blob_tx_price_bump: self.blob_transaction_price_bump,
},
}
}
}

View File

@ -5,9 +5,16 @@ use crate::{
pub use access_list::{AccessList, AccessListItem, AccessListWithGasUsed};
use bytes::{Buf, BytesMut};
use derive_more::{AsRef, Deref};
pub use eip1559::TxEip1559;
pub use eip2930::TxEip2930;
pub use eip4844::{
BlobTransaction, BlobTransactionSidecar, BlobTransactionValidationError, TxEip4844,
};
pub use error::InvalidTransactionError;
pub use legacy::TxLegacy;
pub use meta::TransactionMeta;
use once_cell::sync::Lazy;
pub use pooled::{PooledTransactionsElement, PooledTransactionsElementEcRecovered};
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
use reth_codecs::{add_arbitrary_tests, derive_arbitrary, Compact};
use reth_rlp::{Decodable, DecodeError, Encodable, Header, EMPTY_LIST_CODE, EMPTY_STRING_CODE};
@ -18,14 +25,6 @@ pub use tx_type::{
TxType, EIP1559_TX_TYPE_ID, EIP2930_TX_TYPE_ID, EIP4844_TX_TYPE_ID, LEGACY_TX_TYPE_ID,
};
pub use eip1559::TxEip1559;
pub use eip2930::TxEip2930;
pub use eip4844::{
BlobTransaction, BlobTransactionSidecar, BlobTransactionValidationError, TxEip4844,
};
pub use legacy::TxLegacy;
pub use pooled::{PooledTransactionsElement, PooledTransactionsElementEcRecovered};
mod access_list;
mod eip1559;
mod eip2930;

View File

@ -1,3 +1,5 @@
use reth_primitives::EIP4844_TX_TYPE_ID;
/// Guarantees max transactions for one sender, compatible with geth/erigon
pub const TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER: usize = 16;
@ -11,6 +13,8 @@ pub const TXPOOL_SUBPOOL_MAX_SIZE_MB_DEFAULT: usize = 20;
pub const DEFAULT_PRICE_BUMP: u128 = 10;
/// Replace blob price bump (in %) for the transaction pool underpriced check.
///
/// This enforces that a blob transaction requires a 100% price bump to be replaced
pub const REPLACE_BLOB_PRICE_BUMP: u128 = 100;
/// Configuration options for the Transaction pool.
@ -25,7 +29,7 @@ pub struct PoolConfig {
/// Max number of executable transaction slots guaranteed per account
pub max_account_slots: usize,
/// Price bump (in %) for the transaction pool underpriced check.
pub price_bump: u128,
pub price_bumps: PriceBumpConfig,
}
impl Default for PoolConfig {
@ -35,7 +39,7 @@ impl Default for PoolConfig {
basefee_limit: Default::default(),
queued_limit: Default::default(),
max_account_slots: TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER,
price_bump: PriceBumpConfig::default().default_price_bump,
price_bumps: Default::default(),
}
}
}
@ -68,7 +72,7 @@ impl Default for SubPoolLimit {
}
/// Price bump config (in %) for the transaction pool underpriced check.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct PriceBumpConfig {
/// Default price bump (in %) for the transaction pool underpriced check.
pub default_price_bump: u128,
@ -76,6 +80,17 @@ pub struct PriceBumpConfig {
pub replace_blob_tx_price_bump: u128,
}
impl PriceBumpConfig {
/// Returns the price bump required to replace the given transaction type.
#[inline]
pub(crate) fn price_bump(&self, tx_type: u8) -> u128 {
if tx_type == EIP4844_TX_TYPE_ID {
return self.replace_blob_tx_price_bump
}
self.default_price_bump
}
}
impl Default for PriceBumpConfig {
fn default() -> Self {
Self {

View File

@ -13,7 +13,8 @@ use crate::{
AddedPendingTransaction, AddedTransaction, OnNewCanonicalStateOutcome,
},
traits::{BlockInfo, PoolSize},
PoolConfig, PoolResult, PoolTransaction, TransactionOrdering, ValidPoolTransaction, U256,
PoolConfig, PoolResult, PoolTransaction, PriceBumpConfig, TransactionOrdering,
ValidPoolTransaction, U256,
};
use fnv::FnvHashMap;
use reth_primitives::{
@ -99,7 +100,7 @@ impl<T: TransactionOrdering> TxPool<T> {
pending_pool: PendingPool::new(ordering),
queued_pool: Default::default(),
basefee_pool: Default::default(),
all_transactions: AllTransactions::new(config.max_account_slots),
all_transactions: AllTransactions::new(&config),
config,
metrics: Default::default(),
}
@ -682,12 +683,18 @@ pub(crate) struct AllTransactions<T: PoolTransaction> {
last_seen_block_hash: H256,
/// Expected base fee for the pending block.
pending_basefee: u64,
/// Configured price bump settings for replacements
price_bumps: PriceBumpConfig,
}
impl<T: PoolTransaction> AllTransactions<T> {
/// Create a new instance
fn new(max_account_slots: usize) -> Self {
Self { max_account_slots, ..Default::default() }
fn new(config: &PoolConfig) -> Self {
Self {
max_account_slots: config.max_account_slots,
price_bumps: config.price_bumps,
..Default::default()
}
}
/// Returns an iterator over all _unique_ hashes in the pool
@ -1031,23 +1038,26 @@ impl<T: PoolTransaction> AllTransactions<T> {
Ok(transaction)
}
/// Returns true if `transaction_a` is underpriced compared to `transaction_B`.
/// Returns true if the replacement candidate is underpriced and can't replace the existing
/// transaction.
fn is_underpriced(
transaction_a: &ValidPoolTransaction<T>,
transaction_b: &ValidPoolTransaction<T>,
price_bump: u128,
existing_transaction: &ValidPoolTransaction<T>,
maybe_replacement: &ValidPoolTransaction<T>,
price_bumps: &PriceBumpConfig,
) -> bool {
let tx_a_max_priority_fee_per_gas =
transaction_a.transaction.max_priority_fee_per_gas().unwrap_or(0);
let tx_b_max_priority_fee_per_gas =
transaction_b.transaction.max_priority_fee_per_gas().unwrap_or(0);
let price_bump = price_bumps.price_bump(existing_transaction.tx_type());
transaction_a.max_fee_per_gas() <=
transaction_b.max_fee_per_gas() * (100 + price_bump) / 100 ||
(tx_a_max_priority_fee_per_gas <=
tx_b_max_priority_fee_per_gas * (100 + price_bump) / 100 &&
tx_a_max_priority_fee_per_gas != 0 &&
tx_b_max_priority_fee_per_gas != 0)
let existing_max_priority_fee_per_gas =
maybe_replacement.transaction.max_priority_fee_per_gas().unwrap_or(0);
let replacement_max_priority_fee_per_gas =
existing_transaction.transaction.max_priority_fee_per_gas().unwrap_or(0);
maybe_replacement.max_fee_per_gas() <=
existing_transaction.max_fee_per_gas() * (100 + price_bump) / 100 ||
(existing_max_priority_fee_per_gas <=
replacement_max_priority_fee_per_gas * (100 + price_bump) / 100 &&
existing_max_priority_fee_per_gas != 0 &&
replacement_max_priority_fee_per_gas != 0)
}
/// Inserts a new transaction into the pool.
@ -1117,11 +1127,10 @@ impl<T: PoolTransaction> AllTransactions<T> {
Entry::Occupied(mut entry) => {
// Transaction already exists
// Ensure the new transaction is not underpriced
if Self::is_underpriced(
transaction.as_ref(),
entry.get().transaction.as_ref(),
PoolConfig::default().price_bump,
transaction.as_ref(),
&self.price_bumps,
) {
return Err(InsertErr::Underpriced {
transaction: pool_tx.transaction,
@ -1257,6 +1266,7 @@ impl<T: PoolTransaction> Default for AllTransactions<T> {
last_seen_block_number: 0,
last_seen_block_hash: Default::default(),
pending_basefee: Default::default(),
price_bumps: Default::default(),
}
}
}