Skip to content

Commit b206a98

Browse files
committed
fix: Even more refactoring to code and documentation
Thank you to @LLFourn and @danielabrozzoni for these suggestions.
1 parent bea8e5a commit b206a98

File tree

6 files changed

+44
-45
lines changed

6 files changed

+44
-45
lines changed

crates/bdk/src/wallet/mod.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ impl<D> Wallet<D> {
500500
// anchor tx to checkpoint with lowest height that is >= position's height
501501
let anchor = self
502502
.chain
503-
.heights()
503+
.blocks()
504504
.range(height..)
505505
.next()
506506
.ok_or(InsertTxError::ConfirmationHeightCannotBeGreaterThanTip {
@@ -1697,13 +1697,12 @@ impl<D> Wallet<D> {
16971697
}
16981698

16991699
/// Applies an update to the wallet and stages the changes (but does not [`commit`] them).
1700-
/// Returns whether the `update` resulted in any changes.
17011700
///
17021701
/// Usually you create an `update` by interacting with some blockchain data source and inserting
17031702
/// transactions related to your wallet into it.
17041703
///
17051704
/// [`commit`]: Self::commit
1706-
pub fn apply_update(&mut self, update: Update) -> Result<bool, CannotConnectError>
1705+
pub fn apply_update(&mut self, update: Update) -> Result<(), CannotConnectError>
17071706
where
17081707
D: PersistBackend<ChangeSet>,
17091708
{
@@ -1717,9 +1716,8 @@ impl<D> Wallet<D> {
17171716
self.indexed_graph.apply_update(update.graph),
17181717
));
17191718

1720-
let changed = !changeset.is_empty();
17211719
self.persist.stage(changeset);
1722-
Ok(changed)
1720+
Ok(())
17231721
}
17241722

17251723
/// Commits all curently [`staged`] changed to the persistence backend returning and error when

crates/chain/src/local_chain.rs

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,19 @@ use alloc::sync::Arc;
88
use bitcoin::BlockHash;
99

1010
/// A structure that represents changes to [`LocalChain`].
11+
///
12+
/// The key represents the block height, and the value either represents added a new [`CheckPoint`]
13+
/// (if [`Some`]), or removing a [`CheckPoint`] (if [`None`]).
1114
pub type ChangeSet = BTreeMap<u32, Option<BlockHash>>;
1215

1316
/// A [`LocalChain`] checkpoint is used to find the agreement point between two chains and as a
1417
/// transaction anchor.
1518
///
1619
/// Each checkpoint contains the height and hash of a block ([`BlockId`]).
1720
///
18-
/// Internaly, checkpoints are nodes of a linked-list. This allows the caller to view the entire
19-
/// chain without holding a lock to [`LocalChain`].
21+
/// Internaly, checkpoints are nodes of a reference-counted linked-list. This allows the caller to
22+
/// cheaply clone a [`CheckPoint`] without copying the whole list and to view the entire chain
23+
/// without holding a lock on [`LocalChain`].
2024
#[derive(Debug, Clone)]
2125
pub struct CheckPoint(Arc<CPInner>);
2226

@@ -54,10 +58,7 @@ impl CheckPoint {
5458
///
5559
/// Returns an `Err(self)` if there is block which does not have a greater height than the
5660
/// previous one.
57-
pub fn extend_with_blocks(
58-
self,
59-
blocks: impl IntoIterator<Item = BlockId>,
60-
) -> Result<Self, Self> {
61+
pub fn extend(self, blocks: impl IntoIterator<Item = BlockId>) -> Result<Self, Self> {
6162
let mut curr = self.clone();
6263
for block in blocks {
6364
curr = curr.push(block).map_err(|_| self.clone())?;
@@ -120,12 +121,15 @@ impl IntoIterator for CheckPoint {
120121
/// A struct to update [`LocalChain`].
121122
///
122123
/// This is used as input for [`LocalChain::apply_update`]. It contains the update's chain `tip` and
123-
/// a `bool` which signals whether this update can introduce blocks below the original chain's tip
124-
/// without invalidating blocks residing on the original chain. Block-by-block syncing mechanisms
125-
/// would typically create updates that builds upon the previous tip. In this case, this paramater
126-
/// would be `false`. Script-pubkey based syncing mechanisms may not introduce transactions in a
127-
/// chronological order so some updates require introducing older blocks (to anchor older
128-
/// transactions). For script-pubkey based syncing, this parameter would typically be `true`.
124+
/// a flag `introduce_older_blocks` which signals whether this update intends to introduce missing
125+
/// blocks to the original chain.
126+
///
127+
/// Block-by-block syncing mechanisms would typically create updates that builds upon the previous
128+
/// tip. In this case, `introduce_older_blocks` would be `false`.
129+
///
130+
/// Script-pubkey based syncing mechanisms may not introduce transactions in a chronological order
131+
/// so some updates require introducing older blocks (to anchor older transactions). For
132+
/// script-pubkey based syncing, `introduce_older_blocks` would typically be `true`.
129133
#[derive(Debug, Clone)]
130134
pub struct Update {
131135
/// The update chain's new tip.
@@ -205,13 +209,13 @@ impl LocalChain {
205209

206210
/// Construct a [`LocalChain`] from a given `checkpoint` tip.
207211
pub fn from_tip(tip: CheckPoint) -> Self {
208-
let mut _self = Self {
212+
let mut chain = Self {
209213
tip: Some(tip),
210214
..Default::default()
211215
};
212-
_self.reindex(0);
213-
debug_assert!(_self._check_index_is_consistent_with_tip());
214-
_self
216+
chain.reindex(0);
217+
debug_assert!(chain._check_index_is_consistent_with_tip());
218+
chain
215219
}
216220

217221
/// Constructs a [`LocalChain`] from a [`BTreeMap`] of height to [`BlockHash`].
@@ -247,26 +251,23 @@ impl LocalChain {
247251

248252
/// Returns whether the [`LocalChain`] is empty (has no checkpoints).
249253
pub fn is_empty(&self) -> bool {
250-
self.tip.is_none()
254+
let res = self.tip.is_none();
255+
debug_assert_eq!(res, self.index.is_empty());
256+
res
251257
}
252258

253259
/// Applies the given `update` to the chain.
254260
///
255261
/// The method returns [`ChangeSet`] on success. This represents the applied changes to `self`.
256262
///
257-
/// To update, the `update_tip` must *connect* with `self`. If `self` and `update_tip` has a
258-
/// mutual checkpoint (same height and hash), it can connect if:
259-
/// * The mutual checkpoint is the tip of `self`.
260-
/// * An ancestor of `update_tip` has a height which is of the checkpoint one higher than the
261-
/// mutual checkpoint from `self`.
262-
///
263-
/// Additionally:
264-
/// * If `self` is empty, `update_tip` will always connect.
265-
/// * If `self` only has one checkpoint, `update_tip` must have an ancestor checkpoint with the
266-
/// same height as it.
263+
/// There must be no ambiguity about which of the existing chain's blocks are still valid and
264+
/// which are now invalid. That is, the new chain must implicitly connect to a definite block in
265+
/// the existing chain and invalidate the block after it (if it exists) by including a block at
266+
/// the same height but with a different hash to explicitly exclude it as a connection point.
267267
///
268-
/// To invalidate from a given checkpoint, `update_tip` must contain an ancestor checkpoint with
269-
/// the same height but different hash.
268+
/// Additionally, an empty chain can be updated with any chain, and a chain with a single block
269+
/// can have it's block invalidated by an update chain with a block at the same height but
270+
/// different hash.
270271
///
271272
/// # Errors
272273
///
@@ -325,7 +326,7 @@ impl LocalChain {
325326
}
326327
let new_tip = match base {
327328
Some(base) => Some(
328-
base.extend_with_blocks(extension.into_iter().map(BlockId::from))
329+
base.extend(extension.into_iter().map(BlockId::from))
329330
.expect("extension is strictly greater than base"),
330331
),
331332
None => LocalChain::from_blocks(extension).tip(),
@@ -379,15 +380,15 @@ impl LocalChain {
379380
self.index.iter().map(|(k, v)| (*k, Some(*v))).collect()
380381
}
381382

382-
/// Iterate over checkpoints in decending height order.
383+
/// Iterate over checkpoints in descending height order.
383384
pub fn iter_checkpoints(&self) -> CheckPointIter {
384385
CheckPointIter {
385386
current: self.tip.as_ref().map(|tip| tip.0.clone()),
386387
}
387388
}
388389

389390
/// Get a reference to the internal index mapping the height to block hash.
390-
pub fn heights(&self) -> &BTreeMap<u32, BlockHash> {
391+
pub fn blocks(&self) -> &BTreeMap<u32, BlockHash> {
391392
&self.index
392393
}
393394

crates/chain/src/tx_graph.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ impl<A: Anchor> TxGraph<A> {
627627
};
628628
let mut has_missing_height = false;
629629
for anchor_block in tx_anchors.iter().map(Anchor::anchor_block) {
630-
match chain.heights().get(&anchor_block.height) {
630+
match chain.blocks().get(&anchor_block.height) {
631631
None => {
632632
has_missing_height = true;
633633
continue;
@@ -651,7 +651,7 @@ impl<A: Anchor> TxGraph<A> {
651651
.filter_map(move |(a, _)| {
652652
let anchor_block = a.anchor_block();
653653
if Some(anchor_block.height) != last_height_emitted
654-
&& !chain.heights().contains_key(&anchor_block.height)
654+
&& !chain.blocks().contains_key(&anchor_block.height)
655655
{
656656
last_height_emitted = Some(anchor_block.height);
657657
Some(anchor_block.height)

crates/chain/tests/test_indexed_tx_graph.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ fn test_list_owned_txouts() {
212212
(
213213
*tx,
214214
local_chain
215-
.heights()
215+
.blocks()
216216
.get(&height)
217217
.cloned()
218218
.map(|hash| BlockId { height, hash })
@@ -232,7 +232,7 @@ fn test_list_owned_txouts() {
232232
|height: u32,
233233
graph: &IndexedTxGraph<ConfirmationHeightAnchor, KeychainTxOutIndex<String>>| {
234234
let chain_tip = local_chain
235-
.heights()
235+
.blocks()
236236
.get(&height)
237237
.map(|&hash| BlockId { height, hash })
238238
.unwrap_or_else(|| panic!("block must exist at {}", height));

example-crates/wallet_esplora/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
5656

5757
let (update_graph, last_active_indices) =
5858
client.update_tx_graph(keychain_spks, None, None, STOP_GAP, PARALLEL_REQUESTS)?;
59-
let get_heights = wallet.tx_graph().missing_heights(wallet.local_chain());
60-
let chain_update = client.update_local_chain(prev_tip, get_heights)?;
59+
let missing_heights = wallet.tx_graph().missing_heights(wallet.local_chain());
60+
let chain_update = client.update_local_chain(prev_tip, missing_heights)?;
6161
let update = LocalUpdate {
6262
last_active_indices,
6363
graph: update_graph,

example-crates/wallet_esplora_async/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
5757
let (update_graph, last_active_indices) = client
5858
.update_tx_graph(keychain_spks, None, None, STOP_GAP, PARALLEL_REQUESTS)
5959
.await?;
60-
let get_heights = wallet.tx_graph().missing_heights(wallet.local_chain());
61-
let chain_update = client.update_local_chain(prev_tip, get_heights).await?;
60+
let missing_heights = wallet.tx_graph().missing_heights(wallet.local_chain());
61+
let chain_update = client.update_local_chain(prev_tip, missing_heights).await?;
6262
let update = LocalUpdate {
6363
last_active_indices,
6464
graph: update_graph,

0 commit comments

Comments
 (0)