Skip to content

Commit

Permalink
Merge #1453: refactor(electrum) put the tx cache in electrum
Browse files Browse the repository at this point in the history
2d2656a feat(electrum): re-export `transaction_broadcast` method (志宇)
53fa350 refactor(electrum)!: put the tx cache in electrum (LLFourn)

Pull request description:

  Previously there was a `TxCache` that you passed in as part of the sync request. There are lots of downsides to this:

  1. If the user forgets to do this you cache nothing
  2. where are you meant to keep this cache? The example shows it being recreated every time which seems very suboptimal.
  3. More API and documentation surface area.

  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.

  * [x] This pull request breaks the existing API

ACKs for top commit:
  evanlinjin:
    self-ACK 2d2656a
  notmandatory:
    ACK 2d2656a

Tree-SHA512: 6c29fd4f99ea5bd66234d5cdaf4b157a192ddd3baacc91076e402d8df0de7010bc482e24895e85fcb2f805ec6d1ce6cdb7654f8f552c90ba75ed35f80a00b856
  • Loading branch information
evanlinjin committed Jun 5, 2024
2 parents 363d9f4 + 2d2656a commit 8eef350
Show file tree
Hide file tree
Showing 8 changed files with 308 additions and 352 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 8eef350

Please sign in to comment.