@@ -8,15 +8,19 @@ use alloc::sync::Arc;
8
8
use bitcoin:: BlockHash ;
9
9
10
10
/// 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`]).
11
14
pub type ChangeSet = BTreeMap < u32 , Option < BlockHash > > ;
12
15
13
16
/// A [`LocalChain`] checkpoint is used to find the agreement point between two chains and as a
14
17
/// transaction anchor.
15
18
///
16
19
/// Each checkpoint contains the height and hash of a block ([`BlockId`]).
17
20
///
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`].
20
24
#[ derive( Debug , Clone ) ]
21
25
pub struct CheckPoint ( Arc < CPInner > ) ;
22
26
@@ -54,10 +58,7 @@ impl CheckPoint {
54
58
///
55
59
/// Returns an `Err(self)` if there is block which does not have a greater height than the
56
60
/// 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 > {
61
62
let mut curr = self . clone ( ) ;
62
63
for block in blocks {
63
64
curr = curr. push ( block) . map_err ( |_| self . clone ( ) ) ?;
@@ -120,12 +121,15 @@ impl IntoIterator for CheckPoint {
120
121
/// A struct to update [`LocalChain`].
121
122
///
122
123
/// 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`.
129
133
#[ derive( Debug , Clone ) ]
130
134
pub struct Update {
131
135
/// The update chain's new tip.
@@ -205,13 +209,13 @@ impl LocalChain {
205
209
206
210
/// Construct a [`LocalChain`] from a given `checkpoint` tip.
207
211
pub fn from_tip ( tip : CheckPoint ) -> Self {
208
- let mut _self = Self {
212
+ let mut chain = Self {
209
213
tip : Some ( tip) ,
210
214
..Default :: default ( )
211
215
} ;
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
215
219
}
216
220
217
221
/// Constructs a [`LocalChain`] from a [`BTreeMap`] of height to [`BlockHash`].
@@ -247,26 +251,23 @@ impl LocalChain {
247
251
248
252
/// Returns whether the [`LocalChain`] is empty (has no checkpoints).
249
253
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
251
257
}
252
258
253
259
/// Applies the given `update` to the chain.
254
260
///
255
261
/// The method returns [`ChangeSet`] on success. This represents the applied changes to `self`.
256
262
///
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.
267
267
///
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.
270
271
///
271
272
/// # Errors
272
273
///
@@ -325,7 +326,7 @@ impl LocalChain {
325
326
}
326
327
let new_tip = match base {
327
328
Some ( base) => Some (
328
- base. extend_with_blocks ( extension. into_iter ( ) . map ( BlockId :: from) )
329
+ base. extend ( extension. into_iter ( ) . map ( BlockId :: from) )
329
330
. expect ( "extension is strictly greater than base" ) ,
330
331
) ,
331
332
None => LocalChain :: from_blocks ( extension) . tip ( ) ,
@@ -379,15 +380,15 @@ impl LocalChain {
379
380
self . index . iter ( ) . map ( |( k, v) | ( * k, Some ( * v) ) ) . collect ( )
380
381
}
381
382
382
- /// Iterate over checkpoints in decending height order.
383
+ /// Iterate over checkpoints in descending height order.
383
384
pub fn iter_checkpoints ( & self ) -> CheckPointIter {
384
385
CheckPointIter {
385
386
current : self . tip . as_ref ( ) . map ( |tip| tip. 0 . clone ( ) ) ,
386
387
}
387
388
}
388
389
389
390
/// 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 > {
391
392
& self . index
392
393
}
393
394
0 commit comments