Skip to content

Commit 0f52ead

Browse files
committed
feat(chain): Add SyncRequestExt::check_unconfirmed_statuses
This is a convenience method for adding unconfirmed txs alongside their associated spks the the sync request. This way, we will be able to detect evictions of these transactions from the mempool.
1 parent 4b754e1 commit 0f52ead

File tree

2 files changed

+58
-2
lines changed

2 files changed

+58
-2
lines changed

crates/chain/src/indexer/keychain_txout.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ use crate::{
77
spk_client::{FullScanRequestBuilder, SyncRequestBuilder},
88
spk_iter::BIP32_MAX_INDEX,
99
spk_txout::SpkTxOutIndex,
10-
DescriptorExt, DescriptorId, Indexed, Indexer, KeychainIndexed, SpkIterator,
10+
Anchor, CanonicalIter, CanonicalReason, ChainOracle, DescriptorExt, DescriptorId, Indexed,
11+
Indexer, KeychainIndexed, SpkIterator,
1112
};
1213
use alloc::{borrow::ToOwned, vec::Vec};
1314
use bitcoin::{Amount, OutPoint, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};
1415
use core::{
16+
convert::Infallible,
1517
fmt::Debug,
1618
ops::{Bound, RangeBounds},
1719
};
@@ -879,6 +881,20 @@ pub trait SyncRequestBuilderExt<K> {
879881

880882
/// Add [`Script`](bitcoin::Script)s that are revealed by the `indexer` but currently unused.
881883
fn unused_spks_from_indexer(self, indexer: &KeychainTxOutIndex<K>) -> Self;
884+
885+
/// Add unconfirmed txids and their associated spks.
886+
///
887+
/// We expect that the chain source should include these txids in their spk histories. If not,
888+
/// the transaction has been evicted for some reason and we will inform the receiving
889+
/// structures in the response.
890+
fn check_unconfirmed_statuses<A, C>(
891+
self,
892+
indexer: &KeychainTxOutIndex<K>,
893+
canonical_iter: CanonicalIter<A, C>,
894+
) -> Self
895+
where
896+
A: Anchor,
897+
C: ChainOracle<Error = Infallible>;
882898
}
883899

884900
impl<K: Clone + Ord + core::fmt::Debug> SyncRequestBuilderExt<K> for SyncRequestBuilder<(K, u32)> {
@@ -892,6 +908,29 @@ impl<K: Clone + Ord + core::fmt::Debug> SyncRequestBuilderExt<K> for SyncRequest
892908
fn unused_spks_from_indexer(self, indexer: &KeychainTxOutIndex<K>) -> Self {
893909
self.spks_with_indexes(indexer.unused_spks())
894910
}
911+
912+
fn check_unconfirmed_statuses<A, C>(
913+
self,
914+
indexer: &KeychainTxOutIndex<K>,
915+
canonical_iter: CanonicalIter<A, C>,
916+
) -> Self
917+
where
918+
A: Anchor,
919+
C: ChainOracle<Error = Infallible>,
920+
{
921+
self.expected_txs(
922+
canonical_iter
923+
.map(|res| res.expect("infallible"))
924+
.filter(|(_, _, reason)| matches!(reason, CanonicalReason::ObservedIn { .. }))
925+
.flat_map(|(txid, tx, _)| {
926+
indexer
927+
.inner
928+
.relevant_spks_of_tx(tx.as_ref())
929+
.into_iter()
930+
.map(move |spk| (txid, spk))
931+
}),
932+
)
933+
}
895934
}
896935

897936
/// Trait to extend [`FullScanRequestBuilder`].

crates/chain/src/indexer/spk_txout.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use core::ops::RangeBounds;
44

55
use crate::{
6-
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap},
6+
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet},
77
Indexer,
88
};
99
use bitcoin::{Amount, OutPoint, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};
@@ -334,4 +334,21 @@ impl<I: Clone + Ord + core::fmt::Debug> SpkTxOutIndex<I> {
334334
.any(|output| self.spk_indices.contains_key(&output.script_pubkey));
335335
input_matches || output_matches
336336
}
337+
338+
/// Find relevant script pubkeys associated with a transaction.
339+
///
340+
/// The script pubkeys of the transaction's outputs and previous outputs as scanned.
341+
pub fn relevant_spks_of_tx(&self, tx: &Transaction) -> HashSet<ScriptBuf> {
342+
let spks_from_inputs = tx.input.iter().filter_map(|txin| {
343+
self.txouts
344+
.get(&txin.previous_output)
345+
.map(|(_, prev_txo)| prev_txo.script_pubkey.clone())
346+
});
347+
let spks_from_outputs = tx
348+
.output
349+
.iter()
350+
.filter(|txout| self.spk_indices.contains_key(&txout.script_pubkey))
351+
.map(|txo| txo.script_pubkey.clone());
352+
spks_from_inputs.chain(spks_from_outputs).collect()
353+
}
337354
}

0 commit comments

Comments
 (0)