mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-30 03:01:58 -04:00
feat(p2p): integrate txpool in p2p (#208)
This commit is contained in:
@@ -87,9 +87,9 @@ use crate::{
|
||||
traits::{NewTransactionEvent, PoolStatus, TransactionOrigin},
|
||||
validate::ValidPoolTransaction,
|
||||
};
|
||||
use futures::channel::mpsc::Receiver;
|
||||
use reth_primitives::{BlockID, TxHash, U256, U64};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use tokio::sync::mpsc::Receiver;
|
||||
|
||||
mod config;
|
||||
pub mod error;
|
||||
@@ -131,11 +131,12 @@ where
|
||||
origin: TransactionOrigin,
|
||||
transactions: impl IntoIterator<Item = V::Transaction>,
|
||||
) -> PoolResult<HashMap<TxHash, TransactionValidationOutcome<V::Transaction>>> {
|
||||
let outcome =
|
||||
futures::future::join_all(transactions.into_iter().map(|tx| self.validate(origin, tx)))
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<HashMap<_, _>>();
|
||||
let outcome = futures_util::future::join_all(
|
||||
transactions.into_iter().map(|tx| self.validate(origin, tx)),
|
||||
)
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
Ok(outcome)
|
||||
}
|
||||
@@ -209,6 +210,10 @@ where
|
||||
self.pool.add_transaction_listener()
|
||||
}
|
||||
|
||||
fn pooled_transactions(&self) -> Vec<TxHash> {
|
||||
self.pool.pooled_transactions()
|
||||
}
|
||||
|
||||
fn best_transactions(
|
||||
&self,
|
||||
) -> Box<dyn BestTransactions<Item = Arc<ValidPoolTransaction<Self::Transaction>>>> {
|
||||
@@ -222,6 +227,10 @@ where
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn retain_unknown(&self, hashes: &mut Vec<TxHash>) {
|
||||
self.pool.retain_unknown(hashes)
|
||||
}
|
||||
|
||||
fn get(&self, tx_hash: &TxHash) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
|
||||
self.inner().get(tx_hash)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! Listeners for the transaction-pool
|
||||
|
||||
use crate::pool::events::TransactionEvent;
|
||||
use futures::channel::mpsc::UnboundedSender;
|
||||
use reth_primitives::H256;
|
||||
use std::{collections::HashMap, hash};
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
|
||||
type EventSink<Hash> = UnboundedSender<TransactionEvent<Hash>>;
|
||||
|
||||
@@ -75,7 +75,7 @@ struct PoolEventNotifier<Hash> {
|
||||
|
||||
impl<Hash: Clone> PoolEventNotifier<Hash> {
|
||||
fn notify(&mut self, event: TransactionEvent<Hash>) {
|
||||
self.senders.retain(|sender| sender.unbounded_send(event.clone()).is_ok())
|
||||
self.senders.retain(|sender| sender.send(event.clone()).is_ok())
|
||||
}
|
||||
|
||||
fn is_done(&self) -> bool {
|
||||
|
||||
@@ -73,7 +73,6 @@ use crate::{
|
||||
};
|
||||
use best::BestTransactions;
|
||||
pub use events::TransactionEvent;
|
||||
use futures::channel::mpsc::{channel, Receiver, Sender};
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use reth_primitives::{Address, TxHash, H256};
|
||||
use std::{
|
||||
@@ -81,6 +80,7 @@ use std::{
|
||||
sync::Arc,
|
||||
time::Instant,
|
||||
};
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::warn;
|
||||
|
||||
mod best;
|
||||
@@ -107,9 +107,9 @@ pub struct PoolInner<V: TransactionValidator, T: TransactionOrdering> {
|
||||
/// Manages listeners for transaction state change events.
|
||||
event_listener: RwLock<PoolEventListener<TxHash>>,
|
||||
/// Listeners for new ready transactions.
|
||||
pending_transaction_listener: Mutex<Vec<Sender<TxHash>>>,
|
||||
pending_transaction_listener: Mutex<Vec<mpsc::Sender<TxHash>>>,
|
||||
/// Listeners for new transactions added to the pool.
|
||||
transaction_listener: Mutex<Vec<Sender<NewTransactionEvent<T::Transaction>>>>,
|
||||
transaction_listener: Mutex<Vec<mpsc::Sender<NewTransactionEvent<T::Transaction>>>>,
|
||||
}
|
||||
|
||||
// === impl PoolInner ===
|
||||
@@ -149,17 +149,23 @@ where
|
||||
|
||||
/// Adds a new transaction listener to the pool that gets notified about every new _ready_
|
||||
/// transaction
|
||||
pub fn add_pending_listener(&self) -> Receiver<TxHash> {
|
||||
pub fn add_pending_listener(&self) -> mpsc::Receiver<TxHash> {
|
||||
const TX_LISTENER_BUFFER_SIZE: usize = 2048;
|
||||
let (tx, rx) = channel(TX_LISTENER_BUFFER_SIZE);
|
||||
let (tx, rx) = mpsc::channel(TX_LISTENER_BUFFER_SIZE);
|
||||
self.pending_transaction_listener.lock().push(tx);
|
||||
rx
|
||||
}
|
||||
|
||||
/// Returns hashes of _all_ transactions in the pool.
|
||||
pub(crate) fn pooled_transactions(&self) -> Vec<TxHash> {
|
||||
let pool = self.pool.read();
|
||||
pool.all().hashes_iter().collect()
|
||||
}
|
||||
|
||||
/// Adds a new transaction listener to the pool that gets notified about every new transaction
|
||||
pub fn add_transaction_listener(&self) -> Receiver<NewTransactionEvent<T::Transaction>> {
|
||||
pub fn add_transaction_listener(&self) -> mpsc::Receiver<NewTransactionEvent<T::Transaction>> {
|
||||
const TX_LISTENER_BUFFER_SIZE: usize = 1024;
|
||||
let (tx, rx) = channel(TX_LISTENER_BUFFER_SIZE);
|
||||
let (tx, rx) = mpsc::channel(TX_LISTENER_BUFFER_SIZE);
|
||||
self.transaction_listener.lock().push(tx);
|
||||
rx
|
||||
}
|
||||
@@ -256,8 +262,8 @@ where
|
||||
let mut transaction_listeners = self.pending_transaction_listener.lock();
|
||||
transaction_listeners.retain_mut(|listener| match listener.try_send(*ready) {
|
||||
Ok(()) => true,
|
||||
Err(e) => {
|
||||
if e.is_full() {
|
||||
Err(err) => {
|
||||
if matches!(err, mpsc::error::TrySendError::Full(_)) {
|
||||
warn!(
|
||||
target: "txpool",
|
||||
"[{:?}] dropping full ready transaction listener",
|
||||
@@ -277,8 +283,8 @@ where
|
||||
|
||||
transaction_listeners.retain_mut(|listener| match listener.try_send(event.clone()) {
|
||||
Ok(()) => true,
|
||||
Err(e) => {
|
||||
if e.is_full() {
|
||||
Err(err) => {
|
||||
if matches!(err, mpsc::error::TrySendError::Full(_)) {
|
||||
warn!(
|
||||
target: "txpool",
|
||||
"dropping full transaction listener",
|
||||
@@ -325,6 +331,12 @@ where
|
||||
self.pool.read().best_transactions()
|
||||
}
|
||||
|
||||
/// Removes all transactions transactions that are missing in the pool.
|
||||
pub(crate) fn retain_unknown(&self, hashes: &mut Vec<TxHash>) {
|
||||
let pool = self.pool.read();
|
||||
hashes.retain(|tx| !pool.contains(tx))
|
||||
}
|
||||
|
||||
/// Returns the transaction by hash.
|
||||
pub(crate) fn get(
|
||||
&self,
|
||||
|
||||
@@ -102,6 +102,11 @@ impl<T: TransactionOrdering> TxPool<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns access to the [`AllTransactions`] container.
|
||||
pub(crate) fn all(&self) -> &AllTransactions<T::Transaction> {
|
||||
&self.all_transactions
|
||||
}
|
||||
|
||||
/// Returns stats about the pool.
|
||||
pub(crate) fn status(&self) -> PoolStatus {
|
||||
PoolStatus {
|
||||
@@ -417,10 +422,6 @@ impl<T: TransactionOrdering> TxPool<T> {
|
||||
#[cfg(test)]
|
||||
#[allow(missing_docs)]
|
||||
impl<T: TransactionOrdering> TxPool<T> {
|
||||
pub(crate) fn all(&self) -> &AllTransactions<T::Transaction> {
|
||||
&self.all_transactions
|
||||
}
|
||||
|
||||
pub(crate) fn pending(&self) -> &PendingPool<T> {
|
||||
&self.pending_pool
|
||||
}
|
||||
@@ -463,6 +464,11 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
Self { max_account_slots, ..Default::default() }
|
||||
}
|
||||
|
||||
/// Returns an iterator over all _unique_ hashes in the pool
|
||||
pub(crate) fn hashes_iter(&self) -> impl Iterator<Item = TxHash> + '_ {
|
||||
self.by_hash.keys().copied()
|
||||
}
|
||||
|
||||
/// Returns if the transaction for the given hash is already included in this pool
|
||||
pub(crate) fn contains(&self, tx_hash: &TxHash) -> bool {
|
||||
self.by_hash.contains_key(tx_hash)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{error::PoolResult, pool::state::SubPool, validate::ValidPoolTransaction, BlockID};
|
||||
use futures::{channel::mpsc::Receiver, future::Shared};
|
||||
use reth_primitives::{Address, FromRecoveredTransaction, TxHash, H256, U256};
|
||||
use std::{fmt, sync::Arc};
|
||||
use tokio::sync::mpsc::Receiver;
|
||||
|
||||
/// General purpose abstraction fo a transaction-pool.
|
||||
///
|
||||
@@ -27,6 +27,8 @@ pub trait TransactionPool: Send + Sync + 'static {
|
||||
///
|
||||
/// This is intended to be used by the network to insert incoming transactions received over the
|
||||
/// p2p network.
|
||||
///
|
||||
/// Consumer: P2P
|
||||
async fn add_external_transaction(&self, transaction: Self::Transaction) -> PoolResult<TxHash> {
|
||||
self.add_transaction(TransactionOrigin::External, transaction).await
|
||||
}
|
||||
@@ -59,6 +61,13 @@ pub trait TransactionPool: Send + Sync + 'static {
|
||||
/// Returns a new stream that yields new valid transactions added to the pool.
|
||||
fn transactions_listener(&self) -> Receiver<NewTransactionEvent<Self::Transaction>>;
|
||||
|
||||
/// Returns hashes of all transactions in the pool.
|
||||
///
|
||||
/// Note: This returns a `Vec` but should guarantee that all hashes are unique.
|
||||
///
|
||||
/// Consumer: P2P
|
||||
fn pooled_transactions(&self) -> Vec<TxHash>;
|
||||
|
||||
/// Returns an iterator that yields transactions that are ready for block production.
|
||||
///
|
||||
/// Consumer: Block production
|
||||
@@ -76,6 +85,13 @@ pub trait TransactionPool: Send + Sync + 'static {
|
||||
tx_hashes: &[TxHash],
|
||||
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>>;
|
||||
|
||||
/// Retains only those hashes that are unknown to the pool.
|
||||
/// In other words, removes all transactions from the given set that are currently present in
|
||||
/// the pool.
|
||||
///
|
||||
/// Consumer: P2P
|
||||
fn retain_unknown(&self, hashes: &mut Vec<TxHash>);
|
||||
|
||||
/// Returns if the transaction for the given hash is already included in this pool.
|
||||
fn contains(&self, tx_hash: &TxHash) -> bool {
|
||||
self.get(tx_hash).is_some()
|
||||
|
||||
Reference in New Issue
Block a user