Skip to content

Commit fe052e0

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 fe052e0

File tree

1 file changed

+65
-4
lines changed

1 file changed

+65
-4
lines changed

crates/chain/src/spk_client.rs

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

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};
12+
/// A cache of [`Arc`]-wrapped full transactions, identified by their [`Txid`]s.
13+
///
14+
/// This is used by the chain-source to avoid re-fetching full transactions.
15+
pub type TxCache = HashMap<Txid, Arc<Transaction>>;
916

1017
/// Data required to perform a spk-based blockchain client sync.
1118
///
@@ -17,6 +24,8 @@ pub struct SyncRequest {
1724
///
1825
/// [`LocalChain::tip`]: crate::local_chain::LocalChain::tip
1926
pub chain_tip: CheckPoint,
27+
/// Cache of full transactions, so the chain-source can avoid re-fetching.
28+
pub tx_cache: TxCache,
2029
/// Transactions that spend from or to these indexed script pubkeys.
2130
pub spks: Box<dyn ExactSizeIterator<Item = ScriptBuf> + Send>,
2231
/// Transactions with these txids.
@@ -30,12 +39,37 @@ impl SyncRequest {
3039
pub fn from_chain_tip(cp: CheckPoint) -> Self {
3140
Self {
3241
chain_tip: cp,
42+
tx_cache: TxCache::new(),
3343
spks: Box::new(core::iter::empty()),
3444
txids: Box::new(core::iter::empty()),
3545
outpoints: Box::new(core::iter::empty()),
3646
}
3747
}
3848

49+
/// Add to the [`Transaction`] cache that allows the chain source to avoid re-fetching full
50+
/// transactions.
51+
///
52+
/// This consumes the [`SyncRequest`] and returns the updated one.
53+
#[must_use]
54+
pub fn cache_txs<T>(mut self, full_txs: impl IntoIterator<Item = (Txid, T)>) -> Self
55+
where
56+
T: Into<Arc<Transaction>>,
57+
{
58+
self.tx_cache = full_txs
59+
.into_iter()
60+
.map(|(txid, tx)| (txid, tx.into()))
61+
.collect();
62+
self
63+
}
64+
65+
/// Add all transactions from [`TxGraph`] into the [`Transaction`] cache.
66+
///
67+
/// This consumes the [`SyncRequest`] and returns the updated one.
68+
#[must_use]
69+
pub fn cache_graph_txs<A>(self, graph: &TxGraph<A>) -> Self {
70+
self.cache_txs(graph.full_txs().map(|tx_node| (tx_node.txid, tx_node.tx)))
71+
}
72+
3973
/// Set the [`Script`]s that will be synced against.
4074
///
4175
/// This consumes the [`SyncRequest`] and returns the updated one.
@@ -194,6 +228,8 @@ pub struct FullScanRequest<K> {
194228
///
195229
/// [`LocalChain::tip`]: crate::local_chain::LocalChain::tip
196230
pub chain_tip: CheckPoint,
231+
/// Cache of full transactions, so the chain-source can avoid re-fetching.
232+
pub tx_cache: TxCache,
197233
/// Iterators of script pubkeys indexed by the keychain index.
198234
pub spks_by_keychain: BTreeMap<K, Box<dyn Iterator<Item = (u32, ScriptBuf)> + Send>>,
199235
}
@@ -204,10 +240,35 @@ impl<K: Ord + Clone> FullScanRequest<K> {
204240
pub fn from_chain_tip(chain_tip: CheckPoint) -> Self {
205241
Self {
206242
chain_tip,
243+
tx_cache: TxCache::new(),
207244
spks_by_keychain: BTreeMap::new(),
208245
}
209246
}
210247

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

0 commit comments

Comments
 (0)