Skip to content

Commit dd97143

Browse files
committed
feat!: Add #[non_exhaustive] to ChangeSet structs in tx_graph, keychain_txout, local_chain
Add #[non_exhaustive] attribute to the ChangeSet structs to prevent downstream crates from exhaustively matching or constructing instances using struct literal syntax, allowing future additions without breaking compatibility. The change improves forward compatibility by allowing new fields to be added without breaking downstream code in future releases.
1 parent a6bcfdf commit dd97143

File tree

8 files changed

+108
-145
lines changed

8 files changed

+108
-145
lines changed

crates/bitcoind_rpc/tests/test_emitter.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,10 @@ pub fn test_sync_local_chain() -> anyhow::Result<()> {
103103
assert_eq!(
104104
local_chain.apply_update(emission.checkpoint,)?,
105105
if exp_height == exp_hashes.len() - reorged_blocks.len() {
106-
bdk_chain::local_chain::ChangeSet {
107-
blocks: core::iter::once((height, Some(hash)))
108-
.chain((height + 1..exp_hashes.len() as u32).map(|h| (h, None)))
109-
.collect(),
110-
}
106+
bdk_chain::local_chain::ChangeSet::from(
107+
core::iter::once((height, Some(hash)))
108+
.chain((height + 1..exp_hashes.len() as u32).map(|h| (h, None))),
109+
)
111110
} else {
112111
[(height, Some(hash))].into()
113112
},

crates/chain/src/indexed_tx_graph.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ impl<A, I> AsRef<TxGraph<A>> for IndexedTxGraph<A, I> {
471471
))
472472
)]
473473
#[must_use]
474+
#[non_exhaustive]
474475
pub struct ChangeSet<A, IA> {
475476
/// [`TxGraph`] changeset.
476477
pub tx_graph: tx_graph::ChangeSet<A>,

crates/chain/src/indexer/keychain_txout.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,6 +1047,7 @@ impl<K: core::fmt::Display + core::fmt::Debug> core::error::Error for InsertDesc
10471047
#[derive(Clone, Debug, Default, PartialEq)]
10481048
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
10491049
#[must_use]
1050+
#[non_exhaustive]
10501051
pub struct ChangeSet {
10511052
/// Maps each `DescriptorId` to its last revealed derivation index.
10521053
pub last_revealed: BTreeMap<DescriptorId, u32>,

crates/chain/src/local_chain.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ where
432432
/// The [`ChangeSet`] represents changes to [`LocalChain`].
433433
#[derive(Debug, Clone, PartialEq)]
434434
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
435+
#[non_exhaustive]
435436
pub struct ChangeSet<D = BlockHash> {
436437
/// Changes to the [`LocalChain`] blocks.
437438
///

crates/chain/src/tx_graph.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ impl<A: Anchor> From<TxUpdate<A>> for TxGraph<A> {
169169
///
170170
/// [module-level documentation]: crate::tx_graph
171171
#[derive(Clone, Debug, PartialEq)]
172+
#[non_exhaustive]
172173
pub struct TxGraph<A = ConfirmationBlockTime> {
173174
txs: HashMap<Txid, TxNodeInternal>,
174175
spends: BTreeMap<OutPoint, HashSet<Txid>>,
@@ -1056,6 +1057,7 @@ impl<A: Anchor> TxGraph<A> {
10561057
))
10571058
)]
10581059
#[must_use]
1060+
#[non_exhaustive]
10591061
pub struct ChangeSet<A = ()> {
10601062
/// Added transactions.
10611063
pub txs: BTreeSet<Arc<Transaction>>,

crates/chain/tests/test_indexed_tx_graph.rs

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -261,45 +261,41 @@ fn insert_relevant_txs() {
261261

262262
let txs = [tx_c, tx_b, tx_a];
263263

264-
let changeset = indexed_tx_graph::ChangeSet {
265-
tx_graph: tx_graph::ChangeSet {
266-
txs: txs.iter().cloned().map(Arc::new).collect(),
267-
..Default::default()
268-
},
269-
indexer: keychain_txout::ChangeSet {
270-
last_revealed: [(descriptor.descriptor_id(), 9_u32)].into(),
271-
spk_cache: [(descriptor.descriptor_id(), {
272-
let index_after_spk_1 = 9 /* index of spk_1 */ + 1;
273-
SpkIterator::new_with_range(
274-
&descriptor,
275-
// This will also persist the staged spk cache inclusions from prev call to
276-
// `.insert_descriptor`.
277-
0..index_after_spk_1 + lookahead,
278-
)
279-
.collect()
280-
})]
281-
.into(),
282-
},
283-
};
264+
let mut tx_graph_changeset = tx_graph::ChangeSet::default();
265+
tx_graph_changeset.txs = txs.iter().cloned().map(Arc::new).collect();
266+
267+
let mut indexer_changeset = keychain_txout::ChangeSet::default();
268+
indexer_changeset.last_revealed = [(descriptor.descriptor_id(), 9_u32)].into();
269+
indexer_changeset.spk_cache = [(descriptor.descriptor_id(), {
270+
let index_after_spk_1 = 9 /* index of spk_1 */ + 1;
271+
SpkIterator::new_with_range(
272+
&descriptor,
273+
// This will also persist the staged spk cache inclusions from prev call to
274+
// `.insert_descriptor`.
275+
0..index_after_spk_1 + lookahead,
276+
)
277+
.collect()
278+
})]
279+
.into();
280+
281+
let changeset = indexed_tx_graph::ChangeSet::from((tx_graph_changeset, indexer_changeset));
284282

285283
assert_eq!(
286284
graph.batch_insert_relevant(txs.iter().cloned().map(|tx| (tx, None))),
287285
changeset,
288286
);
289287

290288
// The initial changeset will also contain info about the keychain we added
291-
let initial_changeset = indexed_tx_graph::ChangeSet {
292-
tx_graph: changeset.tx_graph,
293-
indexer: keychain_txout::ChangeSet {
294-
last_revealed: changeset.indexer.last_revealed,
295-
spk_cache: [(
296-
descriptor.descriptor_id(),
297-
SpkIterator::new_with_range(&descriptor, 0..=9 /* index of spk_1*/ + lookahead)
298-
.collect(),
299-
)]
300-
.into(),
301-
},
302-
};
289+
let mut initial_indexer_changeset = keychain_txout::ChangeSet::default();
290+
initial_indexer_changeset.last_revealed = changeset.indexer.last_revealed;
291+
initial_indexer_changeset.spk_cache = [(
292+
descriptor.descriptor_id(),
293+
SpkIterator::new_with_range(&descriptor, 0..=9 /* index of spk_1*/ + lookahead).collect(),
294+
)]
295+
.into();
296+
297+
let initial_changeset =
298+
indexed_tx_graph::ChangeSet::from((changeset.tx_graph, initial_indexer_changeset));
303299

304300
assert_eq!(graph.initial_changeset(), initial_changeset);
305301
}

crates/chain/tests/test_keychain_txout_index.rs

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,12 @@ fn merge_changesets_check_last_revealed() {
8989
rhs_di.insert(descriptor_ids[1], 5); // value more than lhs desc 1
9090
lhs_di.insert(descriptor_ids[3], 4); // key doesn't exist in lhs
9191

92-
let mut lhs = ChangeSet {
93-
last_revealed: lhs_di,
94-
..Default::default()
95-
};
96-
let rhs = ChangeSet {
97-
last_revealed: rhs_di,
98-
..Default::default()
99-
};
92+
let mut lhs = ChangeSet::default();
93+
lhs.last_revealed = lhs_di;
94+
95+
let mut rhs = ChangeSet::default();
96+
rhs.last_revealed = rhs_di;
97+
10098
lhs.merge(rhs);
10199

102100
// Existing index doesn't update if the new index in `other` is lower than `self`.
@@ -138,12 +136,13 @@ fn test_set_all_derivation_indices() {
138136
),
139137
]
140138
.into();
139+
140+
let mut expected_changeset = ChangeSet::default();
141+
expected_changeset.last_revealed = last_revealed.clone();
142+
expected_changeset.spk_cache = spk_cache.clone();
141143
assert_eq!(
142144
txout_index.reveal_to_target_multi(&derive_to),
143-
ChangeSet {
144-
last_revealed: last_revealed.clone(),
145-
spk_cache: spk_cache.clone(),
146-
}
145+
expected_changeset
147146
);
148147
assert_eq!(txout_index.last_revealed_indices(), derive_to);
149148
assert_eq!(
@@ -638,16 +637,11 @@ fn lookahead_to_target() {
638637
#[test]
639638
fn applying_changesets_one_by_one_vs_aggregate_must_have_same_result() {
640639
let desc = parse_descriptor(DESCRIPTORS[0]);
641-
let changesets: &[ChangeSet] = &[
642-
ChangeSet {
643-
last_revealed: [(desc.descriptor_id(), 10)].into(),
644-
..Default::default()
645-
},
646-
ChangeSet {
647-
last_revealed: [(desc.descriptor_id(), 12)].into(),
648-
..Default::default()
649-
},
650-
];
640+
let mut changeset_1 = ChangeSet::default();
641+
changeset_1.last_revealed = [(desc.descriptor_id(), 10)].into();
642+
let mut changeset_2 = ChangeSet::default();
643+
changeset_2.last_revealed = [(desc.descriptor_id(), 12)].into();
644+
let changesets: &[ChangeSet] = &[changeset_1, changeset_2];
651645

652646
let mut indexer_a = KeychainTxOutIndex::<TestKeychain>::new(0, true);
653647
let _ = indexer_a

0 commit comments

Comments
 (0)