Skip to content

Commit c14504e

Browse files
feat(chain)!: Introduce descriptor in keychain...
...txout index changeset Fixes #1101
1 parent a97d662 commit c14504e

File tree

3 files changed

+106
-41
lines changed

3 files changed

+106
-41
lines changed

crates/chain/src/keychain/txout_index.rs

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use core::{fmt::Debug, ops::Deref};
1212
use crate::Append;
1313

1414
/// Represents updates to the derivation index of a [`KeychainTxOutIndex`].
15-
/// It maps each keychain `K` to its last revealed index.
15+
/// It maps each keychain `K` to a descriptor and its last revealed index.
1616
///
1717
/// It can be applied to [`KeychainTxOutIndex`] with [`apply_changeset`]. [`ChangeSet] are
1818
/// monotone in that they will never decrease the revealed derivation index.
@@ -32,26 +32,32 @@ use crate::Append;
3232
)
3333
)]
3434
#[must_use]
35-
pub struct ChangeSet<K>(pub BTreeMap<K, u32>);
35+
pub struct ChangeSet<K>(pub BTreeMap<K, (Descriptor<DescriptorPublicKey>, u32)>);
3636

3737
impl<K> ChangeSet<K> {
3838
/// Get the inner map of the keychain to its new derivation index.
39-
pub fn as_inner(&self) -> &BTreeMap<K, u32> {
39+
pub fn as_inner(&self) -> &BTreeMap<K, (Descriptor<DescriptorPublicKey>, u32)> {
4040
&self.0
4141
}
4242
}
4343

4444
impl<K: Ord> Append for ChangeSet<K> {
4545
/// Append another [`ChangeSet`] into self.
4646
///
47-
/// If the keychain already exists, increase the index when the other's index > self's index.
48-
/// If the keychain did not exist, append the new keychain.
47+
/// For each keychain in the given [`ChangeSet`]:
48+
/// - If the keychain already exists in the old [`ChangeSet`], and the two descriptors are the
49+
/// same, we increase the index when new index > old index.
50+
/// - If the keychain already exists, but with a different descriptor, we overwrite the
51+
/// original descriptor with the changeset one.
52+
/// - If the keychain did not exist, append the new keychain.
4953
fn append(&mut self, mut other: Self) {
50-
self.0.iter_mut().for_each(|(key, index)| {
51-
if let Some(other_index) = other.0.remove(key) {
52-
*index = other_index.max(*index);
54+
for (key, (descriptor, index)) in &mut self.0 {
55+
if let Some((other_descriptor, other_index)) = other.0.remove(key) {
56+
if other_descriptor == *descriptor {
57+
*index = other_index.max(*index);
58+
}
5359
}
54-
});
60+
}
5561

5662
self.0.append(&mut other.0);
5763
}
@@ -68,8 +74,8 @@ impl<K> Default for ChangeSet<K> {
6874
}
6975
}
7076

71-
impl<K> AsRef<BTreeMap<K, u32>> for ChangeSet<K> {
72-
fn as_ref(&self) -> &BTreeMap<K, u32> {
77+
impl<K> AsRef<BTreeMap<K, (Descriptor<DescriptorPublicKey>, u32)>> for ChangeSet<K> {
78+
fn as_ref(&self) -> &BTreeMap<K, (Descriptor<DescriptorPublicKey>, u32)> {
7379
&self.0
7480
}
7581
}
@@ -169,7 +175,16 @@ impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K> {
169175
}
170176

171177
fn initial_changeset(&self) -> Self::ChangeSet {
172-
super::ChangeSet(self.last_revealed.clone())
178+
let changeset = self
179+
.keychains
180+
.clone()
181+
.into_iter()
182+
.map(|(key, descriptor)| {
183+
let index = self.last_revealed.get(&key).expect("Must be here");
184+
(key, (descriptor, *index))
185+
})
186+
.collect();
187+
super::ChangeSet(changeset)
173188
}
174189

175190
fn apply_changeset(&mut self, changeset: Self::ChangeSet) {
@@ -488,7 +503,9 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
488503
debug_assert!(_old_index < Some(index));
489504
(
490505
SpkIterator::new_with_range(descriptor.clone(), next_reveal_index..index + 1),
491-
super::ChangeSet(core::iter::once((keychain.clone(), index)).collect()),
506+
super::ChangeSet(
507+
core::iter::once((keychain.clone(), (descriptor.clone(), index))).collect(),
508+
),
492509
)
493510
}
494511
None => (
@@ -621,6 +638,12 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
621638
/// Applies the derivation changeset to the [`KeychainTxOutIndex`], extending the number of
622639
/// derived scripts per keychain, as specified in the `changeset`.
623640
pub fn apply_changeset(&mut self, changeset: super::ChangeSet<K>) {
624-
let _ = self.reveal_to_target_multi(&changeset.0);
641+
let _ = self.reveal_to_target_multi(
642+
&changeset
643+
.0
644+
.into_iter()
645+
.map(|(key, (_, index))| (key, index))
646+
.collect(),
647+
);
625648
}
626649
}

crates/chain/tests/test_indexed_tx_graph.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fn insert_relevant_txs() {
3030
let spk_1 = descriptor.at_derivation_index(9).unwrap().script_pubkey();
3131

3232
let mut graph = IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<()>>::default();
33-
graph.index.add_keychain((), descriptor);
33+
graph.index.add_keychain((), descriptor.clone());
3434
graph.index.set_lookahead(&(), 10);
3535

3636
let tx_a = Transaction {
@@ -70,7 +70,7 @@ fn insert_relevant_txs() {
7070
txs: txs.clone().into(),
7171
..Default::default()
7272
},
73-
indexer: keychain::ChangeSet([((), 9_u32)].into()),
73+
indexer: keychain::ChangeSet([((), (descriptor, 9_u32))].into()),
7474
};
7575

7676
assert_eq!(

crates/chain/tests/test_keychain_txout_index.rs

Lines changed: 67 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -46,52 +46,91 @@ fn spk_at_index(descriptor: &Descriptor<DescriptorPublicKey>, index: u32) -> Scr
4646
fn append_keychain_derivation_indices() {
4747
#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Debug)]
4848
enum Keychain {
49+
Zero,
4950
One,
5051
Two,
5152
Three,
5253
Four,
5354
}
54-
let mut lhs_di = BTreeMap::<Keychain, u32>::default();
55-
let mut rhs_di = BTreeMap::<Keychain, u32>::default();
56-
lhs_di.insert(Keychain::One, 7);
57-
lhs_di.insert(Keychain::Two, 0);
58-
rhs_di.insert(Keychain::One, 3);
59-
rhs_di.insert(Keychain::Two, 5);
60-
lhs_di.insert(Keychain::Three, 3);
61-
rhs_di.insert(Keychain::Four, 4);
55+
56+
let descriptors: Vec<_> = common::DESCRIPTORS
57+
.into_iter()
58+
.map(|s| {
59+
Descriptor::parse_descriptor(&Secp256k1::signing_only(), s)
60+
.unwrap()
61+
.0
62+
})
63+
.collect();
64+
65+
let mut lhs_di = BTreeMap::<Keychain, (Descriptor<DescriptorPublicKey>, u32)>::default();
66+
let mut rhs_di = BTreeMap::<Keychain, (Descriptor<DescriptorPublicKey>, u32)>::default();
67+
lhs_di.insert(Keychain::Zero, (descriptors[0].clone(), 1));
68+
lhs_di.insert(Keychain::One, (descriptors[1].clone(), 7));
69+
lhs_di.insert(Keychain::Two, (descriptors[2].clone(), 0));
70+
71+
lhs_di.insert(Keychain::Zero, (descriptors[1].clone(), 13));
72+
rhs_di.insert(Keychain::One, (descriptors[1].clone(), 3));
73+
rhs_di.insert(Keychain::Two, (descriptors[2].clone(), 5));
74+
lhs_di.insert(Keychain::Three, (descriptors[3].clone(), 3));
75+
rhs_di.insert(Keychain::Four, (descriptors[4].clone(), 4));
6276

6377
let mut lhs = ChangeSet(lhs_di);
6478
let rhs = ChangeSet(rhs_di);
6579
lhs.append(rhs);
6680

81+
// Descriptor gets updated
82+
assert_eq!(
83+
lhs.0.get(&Keychain::Zero),
84+
(Some(&(descriptors[1].clone(), 13)))
85+
);
6786
// Exiting index doesn't update if the new index in `other` is lower than `self`.
68-
assert_eq!(lhs.0.get(&Keychain::One), Some(&7));
87+
assert_eq!(
88+
lhs.0.get(&Keychain::One),
89+
(Some(&(descriptors[1].clone(), 7)))
90+
);
6991
// Existing index updates if the new index in `other` is higher than `self`.
70-
assert_eq!(lhs.0.get(&Keychain::Two), Some(&5));
92+
assert_eq!(
93+
lhs.0.get(&Keychain::Two),
94+
Some(&(descriptors[2].clone(), 5))
95+
);
7196
// Existing index is unchanged if keychain doesn't exist in `other`.
72-
assert_eq!(lhs.0.get(&Keychain::Three), Some(&3));
97+
assert_eq!(
98+
lhs.0.get(&Keychain::Three),
99+
Some(&(descriptors[3].clone(), 3))
100+
);
73101
// New keychain gets added if the keychain is in `other` but not in `self`.
74-
assert_eq!(lhs.0.get(&Keychain::Four), Some(&4));
102+
assert_eq!(
103+
lhs.0.get(&Keychain::Four),
104+
Some(&(descriptors[4].clone(), 4))
105+
);
75106
}
76107

77108
#[test]
78109
fn test_set_all_derivation_indices() {
79110
use bdk_chain::indexed_tx_graph::Indexer;
80111

81-
let (mut txout_index, _, _) = init_txout_index();
82-
let derive_to: BTreeMap<_, _> =
83-
[(TestKeychain::External, 12), (TestKeychain::Internal, 24)].into();
112+
let (mut txout_index, external_desc, internal_desc) = init_txout_index();
113+
let result: BTreeMap<_, _> = [
114+
(TestKeychain::External, (external_desc, 12)),
115+
(TestKeychain::Internal, (internal_desc, 24)),
116+
]
117+
.into();
118+
let derive_to = result
119+
.clone()
120+
.into_iter()
121+
.map(|(k, (_, i))| (k, i))
122+
.collect();
84123
assert_eq!(
85124
txout_index.reveal_to_target_multi(&derive_to).1.as_inner(),
86-
&derive_to
125+
&result
87126
);
88127
assert_eq!(txout_index.last_revealed_indices(), &derive_to);
89128
assert_eq!(
90129
txout_index.reveal_to_target_multi(&derive_to).1,
91130
keychain::ChangeSet::default(),
92131
"no changes if we set to the same thing"
93132
);
94-
assert_eq!(txout_index.initial_changeset().as_inner(), &derive_to);
133+
assert_eq!(txout_index.initial_changeset().as_inner(), &result);
95134
}
96135

97136
#[test]
@@ -123,7 +162,7 @@ fn test_lookahead() {
123162
);
124163
assert_eq!(
125164
revealed_changeset.as_inner(),
126-
&[(TestKeychain::External, index)].into()
165+
&[(TestKeychain::External, (external_desc.clone(), index))].into()
127166
);
128167

129168
assert_eq!(
@@ -175,7 +214,7 @@ fn test_lookahead() {
175214
);
176215
assert_eq!(
177216
revealed_changeset.as_inner(),
178-
&[(TestKeychain::Internal, 24)].into()
217+
&[(TestKeychain::Internal, (internal_desc.clone(), 24))].into()
179218
);
180219
assert_eq!(
181220
txout_index.inner().all_spks().len(),
@@ -284,7 +323,7 @@ fn test_scan_with_lookahead() {
284323
let changeset = txout_index.index_txout(op, &txout);
285324
assert_eq!(
286325
changeset.as_inner(),
287-
&[(TestKeychain::External, spk_i)].into()
326+
&[(TestKeychain::External, (external_desc.clone(), spk_i))].into()
288327
);
289328
assert_eq!(
290329
txout_index.last_revealed_index(&TestKeychain::External),
@@ -328,7 +367,7 @@ fn test_wildcard_derivations() {
328367
assert_eq!(txout_index.next_index(&TestKeychain::External), (0, true));
329368
let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External);
330369
assert_eq!(spk, (0_u32, external_spk_0.as_script()));
331-
assert_eq!(changeset.as_inner(), &[(TestKeychain::External, 0)].into());
370+
assert_eq!(changeset.as_inner(), &[(TestKeychain::External, (external_desc.clone(), 0))].into());
332371
let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External);
333372
assert_eq!(spk, (0_u32, external_spk_0.as_script()));
334373
assert_eq!(changeset.as_inner(), &[].into());
@@ -352,7 +391,7 @@ fn test_wildcard_derivations() {
352391
let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External);
353392
assert_eq!(spk, (26, external_spk_26.as_script()));
354393

355-
assert_eq!(changeset.as_inner(), &[(TestKeychain::External, 26)].into());
394+
assert_eq!(changeset.as_inner(), &[(TestKeychain::External, (external_desc.clone(), 26))].into());
356395

357396
let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External);
358397
assert_eq!(spk, (16, external_spk_16.as_script()));
@@ -366,7 +405,7 @@ fn test_wildcard_derivations() {
366405

367406
let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External);
368407
assert_eq!(spk, (27, external_spk_27.as_script()));
369-
assert_eq!(changeset.as_inner(), &[(TestKeychain::External, 27)].into());
408+
assert_eq!(changeset.as_inner(), &[(TestKeychain::External, (external_desc, 27))].into());
370409
}
371410

372411
#[test]
@@ -380,7 +419,7 @@ fn test_non_wildcard_derivations() {
380419
.unwrap()
381420
.script_pubkey();
382421

383-
txout_index.add_keychain(TestKeychain::External, no_wildcard_descriptor);
422+
txout_index.add_keychain(TestKeychain::External, no_wildcard_descriptor.clone());
384423

385424
// given:
386425
// - `txout_index` with no stored scripts
@@ -391,7 +430,10 @@ fn test_non_wildcard_derivations() {
391430
assert_eq!(txout_index.next_index(&TestKeychain::External), (0, true));
392431
let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External);
393432
assert_eq!(spk, (0, external_spk.as_script()));
394-
assert_eq!(changeset.as_inner(), &[(TestKeychain::External, 0)].into());
433+
assert_eq!(
434+
changeset.as_inner(),
435+
&[(TestKeychain::External, (no_wildcard_descriptor, 0))].into()
436+
);
395437

396438
let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External);
397439
assert_eq!(spk, (0, external_spk.as_script()));

0 commit comments

Comments
 (0)