Skip to content

Commit

Permalink
refactor(electrum) put the tx cache in electrum
Browse files Browse the repository at this point in the history
Previously there was a tx cache that you passed in as part of the sync
request. This seems bad and the example show'd that you should copy all
your transactions from the transaction graph into the sync request every
time you sync'd. If you forgot to do this then you would always download everything.

Instead just do a plain old simple cache inside the electrum client.
This way at least you only download transactions once. You can
pre-populate the cache with a method also and I did this in the examples.
  • Loading branch information
LLFourn committed May 31, 2024
1 parent 4a8452f commit 76683ce
Show file tree
Hide file tree
Showing 8 changed files with 302 additions and 353 deletions.
6 changes: 6 additions & 0 deletions crates/chain/src/indexed_tx_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,3 +352,9 @@ pub trait Indexer {
/// Determines whether the transaction should be included in the index.
fn is_tx_relevant(&self, tx: &Transaction) -> bool;
}

impl<A, I> AsRef<TxGraph<A>> for IndexedTxGraph<A, I> {
fn as_ref(&self) -> &TxGraph<A> {
&self.graph
}
}
65 changes: 3 additions & 62 deletions crates/chain/src/spk_client.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
//! Helper types for spk-based blockchain clients.
use crate::{
collections::{BTreeMap, HashMap},
local_chain::CheckPoint,
ConfirmationTimeHeightAnchor, TxGraph,
collections::BTreeMap, local_chain::CheckPoint, ConfirmationTimeHeightAnchor, TxGraph,
};
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use bitcoin::{OutPoint, Script, ScriptBuf, Transaction, Txid};
use alloc::{boxed::Box, vec::Vec};
use bitcoin::{OutPoint, Script, ScriptBuf, Txid};
use core::{fmt::Debug, marker::PhantomData, ops::RangeBounds};

/// A cache of [`Arc`]-wrapped full transactions, identified by their [`Txid`]s.
///
/// This is used by the chain-source to avoid re-fetching full transactions.
pub type TxCache = HashMap<Txid, Arc<Transaction>>;

/// Data required to perform a spk-based blockchain client sync.
///
/// A client sync fetches relevant chain data for a known list of scripts, transaction ids and
Expand All @@ -24,8 +17,6 @@ pub struct SyncRequest {
///
/// [`LocalChain::tip`]: crate::local_chain::LocalChain::tip
pub chain_tip: CheckPoint,
/// Cache of full transactions, so the chain-source can avoid re-fetching.
pub tx_cache: TxCache,
/// Transactions that spend from or to these indexed script pubkeys.
pub spks: Box<dyn ExactSizeIterator<Item = ScriptBuf> + Send>,
/// Transactions with these txids.
Expand All @@ -39,36 +30,12 @@ impl SyncRequest {
pub fn from_chain_tip(cp: CheckPoint) -> Self {
Self {
chain_tip: cp,
tx_cache: TxCache::new(),
spks: Box::new(core::iter::empty()),
txids: Box::new(core::iter::empty()),
outpoints: Box::new(core::iter::empty()),
}
}

/// Add to the [`TxCache`] held by the request.
///
/// This consumes the [`SyncRequest`] and returns the updated one.
#[must_use]
pub fn cache_txs<T>(mut self, full_txs: impl IntoIterator<Item = (Txid, T)>) -> Self
where
T: Into<Arc<Transaction>>,
{
self.tx_cache = full_txs
.into_iter()
.map(|(txid, tx)| (txid, tx.into()))
.collect();
self
}

/// Add all transactions from [`TxGraph`] into the [`TxCache`].
///
/// This consumes the [`SyncRequest`] and returns the updated one.
#[must_use]
pub fn cache_graph_txs<A>(self, graph: &TxGraph<A>) -> Self {
self.cache_txs(graph.full_txs().map(|tx_node| (tx_node.txid, tx_node.tx)))
}

/// Set the [`Script`]s that will be synced against.
///
/// This consumes the [`SyncRequest`] and returns the updated one.
Expand Down Expand Up @@ -227,8 +194,6 @@ pub struct FullScanRequest<K> {
///
/// [`LocalChain::tip`]: crate::local_chain::LocalChain::tip
pub chain_tip: CheckPoint,
/// Cache of full transactions, so the chain-source can avoid re-fetching.
pub tx_cache: TxCache,
/// Iterators of script pubkeys indexed by the keychain index.
pub spks_by_keychain: BTreeMap<K, Box<dyn Iterator<Item = (u32, ScriptBuf)> + Send>>,
}
Expand All @@ -239,34 +204,10 @@ impl<K: Ord + Clone> FullScanRequest<K> {
pub fn from_chain_tip(chain_tip: CheckPoint) -> Self {
Self {
chain_tip,
tx_cache: TxCache::new(),
spks_by_keychain: BTreeMap::new(),
}
}

/// Add to the [`TxCache`] held by the request.
///
/// This consumes the [`SyncRequest`] and returns the updated one.
#[must_use]
pub fn cache_txs<T>(mut self, full_txs: impl IntoIterator<Item = (Txid, T)>) -> Self
where
T: Into<Arc<Transaction>>,
{
self.tx_cache = full_txs
.into_iter()
.map(|(txid, tx)| (txid, tx.into()))
.collect();
self
}

/// Add all transactions from [`TxGraph`] into the [`TxCache`].
///
/// This consumes the [`SyncRequest`] and returns the updated one.
#[must_use]
pub fn cache_graph_txs<A>(self, graph: &TxGraph<A>) -> Self {
self.cache_txs(graph.full_txs().map(|tx_node| (tx_node.txid, tx_node.tx)))
}

/// Construct a new [`FullScanRequest`] from a given `chain_tip` and `index`.
///
/// Unbounded script pubkey iterators for each keychain (`K`) are extracted using
Expand Down
Loading

0 comments on commit 76683ce

Please sign in to comment.