Skip to content

Commit fd576d6

Browse files
committed
feat(chain): introduce TxCache to SyncRequest and FullScanRequest
This transaction cache can be provided so the chain-source can avoid re-fetching transactions.
1 parent c3295e3 commit fd576d6

File tree

1 file changed

+64
-4
lines changed

1 file changed

+64
-4
lines changed

crates/chain/src/spk_client.rs

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
//! Helper types for spk-based blockchain clients.
22
3+
use crate::{
4+
collections::BTreeMap, local_chain::CheckPoint, ConfirmationTimeHeightAnchor, TxGraph,
5+
};
6+
use alloc::{boxed::Box, sync::Arc, vec::Vec};
7+
use bitcoin::{OutPoint, Script, ScriptBuf, Transaction, Txid};
38
use core::{fmt::Debug, marker::PhantomData, ops::RangeBounds};
9+
use std::collections::HashMap;
410

5-
use alloc::{boxed::Box, collections::BTreeMap, vec::Vec};
6-
use bitcoin::{OutPoint, Script, ScriptBuf, Txid};
7-
8-
use crate::{local_chain::CheckPoint, ConfirmationTimeHeightAnchor, TxGraph};
11+
/// A cache of [`Arc`]-wrapped full transactions, identified by their [`Txid`]s.
12+
///
13+
/// This is used by the chain-source to avoid re-fetching full transactions.
14+
pub type TxCache = HashMap<Txid, Arc<Transaction>>;
915

1016
/// Data required to perform a spk-based blockchain client sync.
1117
///
@@ -17,6 +23,8 @@ pub struct SyncRequest {
1723
///
1824
/// [`LocalChain::tip`]: crate::local_chain::LocalChain::tip
1925
pub chain_tip: CheckPoint,
26+
/// Cache of full transactions, so the chain-source can avoid re-fetching.
27+
pub tx_cache: TxCache,
2028
/// Transactions that spend from or to these indexed script pubkeys.
2129
pub spks: Box<dyn ExactSizeIterator<Item = ScriptBuf> + Send>,
2230
/// Transactions with these txids.
@@ -30,12 +38,37 @@ impl SyncRequest {
3038
pub fn from_chain_tip(cp: CheckPoint) -> Self {
3139
Self {
3240
chain_tip: cp,
41+
tx_cache: TxCache::new(),
3342
spks: Box::new(core::iter::empty()),
3443
txids: Box::new(core::iter::empty()),
3544
outpoints: Box::new(core::iter::empty()),
3645
}
3746
}
3847

48+
/// Add to the [`Transaction`] cache that allows the chain source to avoid re-fetching full
49+
/// transactions.
50+
///
51+
/// This consumes the [`SyncRequest`] and returns the updated one.
52+
#[must_use]
53+
pub fn cache_txs<T>(mut self, full_txs: impl IntoIterator<Item = (Txid, T)>) -> Self
54+
where
55+
T: Into<Arc<Transaction>>,
56+
{
57+
self.tx_cache = full_txs
58+
.into_iter()
59+
.map(|(txid, tx)| (txid, tx.into()))
60+
.collect();
61+
self
62+
}
63+
64+
/// Add all transactions from [`TxGraph`] into the [`Transaction`] cache.
65+
///
66+
/// This consumes the [`SyncRequest`] and returns the updated one.
67+
#[must_use]
68+
pub fn cache_graph_txs<A>(self, graph: &TxGraph<A>) -> Self {
69+
self.cache_txs(graph.full_txs().map(|tx_node| (tx_node.txid, tx_node.tx)))
70+
}
71+
3972
/// Set the [`Script`]s that will be synced against.
4073
///
4174
/// This consumes the [`SyncRequest`] and returns the updated one.
@@ -194,6 +227,8 @@ pub struct FullScanRequest<K> {
194227
///
195228
/// [`LocalChain::tip`]: crate::local_chain::LocalChain::tip
196229
pub chain_tip: CheckPoint,
230+
/// Cache of full transactions, so the chain-source can avoid re-fetching.
231+
pub tx_cache: TxCache,
197232
/// Iterators of script pubkeys indexed by the keychain index.
198233
pub spks_by_keychain: BTreeMap<K, Box<dyn Iterator<Item = (u32, ScriptBuf)> + Send>>,
199234
}
@@ -204,10 +239,35 @@ impl<K: Ord + Clone> FullScanRequest<K> {
204239
pub fn from_chain_tip(chain_tip: CheckPoint) -> Self {
205240
Self {
206241
chain_tip,
242+
tx_cache: TxCache::new(),
207243
spks_by_keychain: BTreeMap::new(),
208244
}
209245
}
210246

247+
/// Add to the [`Transaction`] cache that allows the chain source to avoid re-fetching full
248+
/// transactions.
249+
///
250+
/// This consumes the [`SyncRequest`] and returns the updated one.
251+
#[must_use]
252+
pub fn cache_txs<T>(mut self, full_txs: impl IntoIterator<Item = (Txid, T)>) -> Self
253+
where
254+
T: Into<Arc<Transaction>>,
255+
{
256+
self.tx_cache = full_txs
257+
.into_iter()
258+
.map(|(txid, tx)| (txid, tx.into()))
259+
.collect();
260+
self
261+
}
262+
263+
/// Add all transactions from [`TxGraph`] into the [`Transaction`] cache.
264+
///
265+
/// This consumes the [`SyncRequest`] and returns the updated one.
266+
#[must_use]
267+
pub fn cache_graph_txs<A>(self, graph: &TxGraph<A>) -> Self {
268+
self.cache_txs(graph.full_txs().map(|tx_node| (tx_node.txid, tx_node.tx)))
269+
}
270+
211271
/// Construct a new [`FullScanRequest`] from a given `chain_tip` and `index`.
212272
///
213273
/// Unbounded script pubkey iterators for each keychain (`K`) are extracted using

0 commit comments

Comments
 (0)