[bdk_chain_redesign] Make insert_relevant_txs
topologically-agnostic
The `insert_relevant_txs` test has also been changed to used `KeychainTxOutIndex` so that index additions can be checked (`SpkTxOutIndex` has no additions). Additionally, generic bounds of some `IndexedTxGraph` list methods have been fixed.
This commit is contained in:
parent
165b874dfe
commit
ac336aa32f
@ -117,7 +117,7 @@ where
|
|||||||
/// Insert relevant transactions from the given `txs` iterator.
|
/// Insert relevant transactions from the given `txs` iterator.
|
||||||
///
|
///
|
||||||
/// Relevancy is determined by the [`Indexer::is_tx_relevant`] implementation of `I`. Irrelevant
|
/// Relevancy is determined by the [`Indexer::is_tx_relevant`] implementation of `I`. Irrelevant
|
||||||
/// transactions in `txs` will be ignored.
|
/// transactions in `txs` will be ignored. Also, `txs` does not need to be in topological order.
|
||||||
///
|
///
|
||||||
/// `anchors` can be provided to anchor the transactions to blocks. `seen_at` is a unix
|
/// `anchors` can be provided to anchor the transactions to blocks. `seen_at` is a unix
|
||||||
/// timestamp of when the transactions are last seen.
|
/// timestamp of when the transactions are last seen.
|
||||||
@ -127,28 +127,31 @@ where
|
|||||||
anchors: impl IntoIterator<Item = A> + Clone,
|
anchors: impl IntoIterator<Item = A> + Clone,
|
||||||
seen_at: Option<u64>,
|
seen_at: Option<u64>,
|
||||||
) -> IndexedAdditions<A, I::Additions> {
|
) -> IndexedAdditions<A, I::Additions> {
|
||||||
// As mentioned by @LLFourn: This algorithm requires the transactions to be topologically
|
// The algorithm below allows for non-topologically ordered transactions by using two loops.
|
||||||
// sorted because most indexers cannot decide whether something is relevant unless you have
|
// This is achieved by:
|
||||||
// first inserted its ancestors in the index. We can fix this if we instead do this:
|
|
||||||
// 1. insert all txs into the index. If they are irrelevant then that's fine it will just
|
// 1. insert all txs into the index. If they are irrelevant then that's fine it will just
|
||||||
// not store anything about them.
|
// not store anything about them.
|
||||||
// 2. decide whether to insert them into the graph depending on whether `is_tx_relevant`
|
// 2. decide whether to insert them into the graph depending on whether `is_tx_relevant`
|
||||||
// returns true or not. (in a second loop).
|
// returns true or not. (in a second loop).
|
||||||
let txs = txs
|
let mut additions = IndexedAdditions::<A, I::Additions>::default();
|
||||||
.into_iter()
|
let mut transactions = Vec::new();
|
||||||
.inspect(|tx| {
|
for tx in txs.into_iter() {
|
||||||
let _ = self.index.index_tx(tx);
|
additions.index_additions.append(self.index.index_tx(tx));
|
||||||
})
|
transactions.push(tx);
|
||||||
.collect::<Vec<_>>();
|
}
|
||||||
txs.into_iter()
|
additions.append(
|
||||||
.filter_map(|tx| match self.index.is_tx_relevant(tx) {
|
transactions
|
||||||
true => Some(self.insert_tx(tx, anchors.clone(), seen_at)),
|
.into_iter()
|
||||||
false => None,
|
.filter_map(|tx| match self.index.is_tx_relevant(tx) {
|
||||||
})
|
true => Some(self.insert_tx(tx, anchors.clone(), seen_at)),
|
||||||
.fold(Default::default(), |mut acc, other| {
|
false => None,
|
||||||
acc.append(other);
|
})
|
||||||
acc
|
.fold(Default::default(), |mut acc, other| {
|
||||||
})
|
acc.append(other);
|
||||||
|
acc
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
additions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +173,7 @@ impl<A: Anchor, I: OwnedIndexer> IndexedTxGraph<A, I> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_owned_txouts<'a, C: ChainOracle + 'a>(
|
pub fn list_owned_txouts<'a, C: ChainOracle<Error = Infallible> + 'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
chain: &'a C,
|
chain: &'a C,
|
||||||
chain_tip: BlockId,
|
chain_tip: BlockId,
|
||||||
@ -196,14 +199,11 @@ impl<A: Anchor, I: OwnedIndexer> IndexedTxGraph<A, I> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_owned_unspents<'a, C>(
|
pub fn list_owned_unspents<'a, C: ChainOracle<Error = Infallible> + 'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
chain: &'a C,
|
chain: &'a C,
|
||||||
chain_tip: BlockId,
|
chain_tip: BlockId,
|
||||||
) -> impl Iterator<Item = FullTxOut<ObservedAs<A>>> + 'a
|
) -> impl Iterator<Item = FullTxOut<ObservedAs<A>>> + 'a {
|
||||||
where
|
|
||||||
C: ChainOracle + 'a,
|
|
||||||
{
|
|
||||||
self.try_list_owned_unspents(chain, chain_tip)
|
self.try_list_owned_unspents(chain, chain_tip)
|
||||||
.map(|r| r.expect("oracle is infallible"))
|
.map(|r| r.expect("oracle is infallible"))
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,12 @@ mod common;
|
|||||||
|
|
||||||
use bdk_chain::{
|
use bdk_chain::{
|
||||||
indexed_tx_graph::{IndexedAdditions, IndexedTxGraph},
|
indexed_tx_graph::{IndexedAdditions, IndexedTxGraph},
|
||||||
|
keychain::{DerivationAdditions, KeychainTxOutIndex},
|
||||||
tx_graph::Additions,
|
tx_graph::Additions,
|
||||||
BlockId, SpkTxOutIndex,
|
BlockId,
|
||||||
};
|
};
|
||||||
use bitcoin::{hashes::hex::FromHex, OutPoint, Script, Transaction, TxIn, TxOut};
|
use bitcoin::{secp256k1::Secp256k1, OutPoint, Transaction, TxIn, TxOut};
|
||||||
|
use miniscript::Descriptor;
|
||||||
|
|
||||||
/// Ensure [`IndexedTxGraph::insert_relevant_txs`] can successfully index transactions NOT presented
|
/// Ensure [`IndexedTxGraph::insert_relevant_txs`] can successfully index transactions NOT presented
|
||||||
/// in topological order.
|
/// in topological order.
|
||||||
@ -16,13 +18,15 @@ use bitcoin::{hashes::hex::FromHex, OutPoint, Script, Transaction, TxIn, TxOut};
|
|||||||
/// agnostic.
|
/// agnostic.
|
||||||
#[test]
|
#[test]
|
||||||
fn insert_relevant_txs() {
|
fn insert_relevant_txs() {
|
||||||
let mut graph = IndexedTxGraph::<BlockId, SpkTxOutIndex<u32>>::default();
|
const DESCRIPTOR: &str = "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)";
|
||||||
|
let (descriptor, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), DESCRIPTOR)
|
||||||
|
.expect("must be valid");
|
||||||
|
let spk_0 = descriptor.at_derivation_index(0).script_pubkey();
|
||||||
|
let spk_1 = descriptor.at_derivation_index(9).script_pubkey();
|
||||||
|
|
||||||
// insert some spks
|
let mut graph = IndexedTxGraph::<BlockId, KeychainTxOutIndex<()>>::default();
|
||||||
let spk_0 = Script::from_hex("0014034f9515cace31713707dff8194b8f550eb6d336").unwrap();
|
graph.index.add_keychain((), descriptor);
|
||||||
let spk_1 = Script::from_hex("0014beaa39ab2b4f47995c77107d8c3f481d3bd33941").unwrap();
|
graph.index.set_lookahead(&(), 10);
|
||||||
graph.index.insert_spk(0, spk_0.clone());
|
|
||||||
graph.index.insert_spk(1, spk_1.clone());
|
|
||||||
|
|
||||||
let tx_a = Transaction {
|
let tx_a = Transaction {
|
||||||
output: vec![
|
output: vec![
|
||||||
@ -63,7 +67,7 @@ fn insert_relevant_txs() {
|
|||||||
tx: txs.into(),
|
tx: txs.into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
..Default::default()
|
index_additions: DerivationAdditions([((), 9_u32)].into()),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user