]> Untitled Git - bdk/commitdiff
feat(chain): introduce `TxCache` to `SyncRequest` and `FullScanRequest`
author志宇 <hello@evanlinjin.me>
Wed, 1 May 2024 08:24:21 +0000 (16:24 +0800)
committer志宇 <hello@evanlinjin.me>
Fri, 10 May 2024 06:11:19 +0000 (14:11 +0800)
This transaction cache can be provided so the chain-source can avoid
re-fetching transactions.

crates/chain/src/spk_client.rs

index 5b2366e922f1c823e287b62524c053d23f6a22d6..19813c560e43da4dc06840fd73d67dd2798263ad 100644 (file)
@@ -1,11 +1,18 @@
 //! Helper types for spk-based blockchain clients.
 
+use crate::{
+    collections::{BTreeMap, HashMap},
+    local_chain::CheckPoint,
+    ConfirmationTimeHeightAnchor, TxGraph,
+};
+use alloc::{boxed::Box, sync::Arc, vec::Vec};
+use bitcoin::{OutPoint, Script, ScriptBuf, Transaction, Txid};
 use core::{fmt::Debug, marker::PhantomData, ops::RangeBounds};
 
-use alloc::{boxed::Box, collections::BTreeMap, vec::Vec};
-use bitcoin::{OutPoint, Script, ScriptBuf, Txid};
-
-use crate::{local_chain::CheckPoint, ConfirmationTimeHeightAnchor, TxGraph};
+/// 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.
 ///
@@ -17,6 +24,8 @@ 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.
@@ -30,12 +39,36 @@ 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.
@@ -194,6 +227,8 @@ 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>>,
 }
@@ -204,10 +239,34 @@ 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