Skip to content

fix: remove naive seen_txns cache #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/tasks/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ impl BlockBuilder {
tracing::error!(error = %e, "error polling transactions");
}
}
self.tx_poller.evict();
}

async fn _get_bundles(&mut self, in_progress: &mut InProgressBlock) {
Expand Down
53 changes: 2 additions & 51 deletions src/tasks/tx_poller.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
use std::time::Duration;
use std::{collections::HashMap, time};

use alloy::consensus::TxEnvelope;
use alloy_primitives::TxHash;

use eyre::Error;
use reqwest::{Client, Url};
use serde::{Deserialize, Serialize};
use serde_json::from_slice;

pub use crate::config::BuilderConfig;

use metrics::counter;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TxPoolResponse {
transactions: Vec<TxEnvelope>,
Expand All @@ -24,63 +17,21 @@ pub struct TxPoller {
pub config: BuilderConfig,
// Reqwest client for fetching transactions from the tx-pool
pub client: Client,
// Maintain a set of transaction hashes to their expiration times
pub seen_txns: HashMap<TxHash, time::Instant>,
}

/// TxPoller implements a poller that fetches unique transactions from the transaction pool.
impl TxPoller {
/// returns a new TxPoller with the given config.
pub fn new(config: &BuilderConfig) -> Self {
Self { config: config.clone(), client: Client::new(), seen_txns: HashMap::new() }
Self { config: config.clone(), client: Client::new() }
}

/// polls the tx-pool for unique transactions and evicts expired transactions.
/// unique transactions that haven't been seen before are sent into the builder pipeline.
pub async fn check_tx_cache(&mut self) -> Result<Vec<TxEnvelope>, Error> {
let mut unique: Vec<TxEnvelope> = Vec::new();

let url: Url = Url::parse(&self.config.tx_pool_url)?.join("transactions")?;
let result = self.client.get(url).send().await?;
let response: TxPoolResponse = from_slice(result.text().await?.as_bytes())?;

response.transactions.iter().for_each(|entry| {
self.check_seen_txs(entry.clone(), &mut unique);
});

Ok(unique)
}

/// checks if the transaction has been seen before and if not, adds it to the unique transactions list.
fn check_seen_txs(&mut self, tx: TxEnvelope, unique: &mut Vec<TxEnvelope>) {
self.seen_txns.entry(*tx.tx_hash()).or_insert_with(|| {
// add to unique transactions
unique.push(tx.clone());
counter!("builder.unique_txs").increment(1);
// expiry is now + cache_duration
time::Instant::now() + Duration::from_secs(self.config.tx_pool_cache_duration)
});
}

/// removes entries from seen_txns that have lived past expiry
pub fn evict(&mut self) {
let expired_keys: Vec<TxHash> = self
.seen_txns
.iter()
.filter_map(
|(key, &expiration)| {
if !expiration.elapsed().is_zero() {
Some(*key)
} else {
None
}
},
)
.collect();

for key in expired_keys {
self.seen_txns.remove(&key);
counter!("builder.evicted_txs").increment(1);
}
Ok(response.transactions)
}
}
Loading