@@ -5,236 +5,10 @@ use core::ops::RangeBounds;
5
5
6
6
use crate :: collections:: BTreeMap ;
7
7
use crate :: { BlockId , ChainOracle , Merge } ;
8
- use alloc :: sync :: Arc ;
8
+ pub use bdk_core :: { CheckPoint , CheckPointIter } ;
9
9
use bitcoin:: block:: Header ;
10
10
use bitcoin:: BlockHash ;
11
11
12
- /// A [`LocalChain`] checkpoint is used to find the agreement point between two chains and as a
13
- /// transaction anchor.
14
- ///
15
- /// Each checkpoint contains the height and hash of a block ([`BlockId`]).
16
- ///
17
- /// Internally, checkpoints are nodes of a reference-counted linked-list. This allows the caller to
18
- /// cheaply clone a [`CheckPoint`] without copying the whole list and to view the entire chain
19
- /// without holding a lock on [`LocalChain`].
20
- #[ derive( Debug , Clone ) ]
21
- pub struct CheckPoint ( Arc < CPInner > ) ;
22
-
23
- /// The internal contents of [`CheckPoint`].
24
- #[ derive( Debug , Clone ) ]
25
- struct CPInner {
26
- /// Block id (hash and height).
27
- block : BlockId ,
28
- /// Previous checkpoint (if any).
29
- prev : Option < Arc < CPInner > > ,
30
- }
31
-
32
- impl PartialEq for CheckPoint {
33
- fn eq ( & self , other : & Self ) -> bool {
34
- let self_cps = self . iter ( ) . map ( |cp| cp. block_id ( ) ) ;
35
- let other_cps = other. iter ( ) . map ( |cp| cp. block_id ( ) ) ;
36
- self_cps. eq ( other_cps)
37
- }
38
- }
39
-
40
- impl CheckPoint {
41
- /// Construct a new base block at the front of a linked list.
42
- pub fn new ( block : BlockId ) -> Self {
43
- Self ( Arc :: new ( CPInner { block, prev : None } ) )
44
- }
45
-
46
- /// Construct a checkpoint from a list of [`BlockId`]s in ascending height order.
47
- ///
48
- /// # Errors
49
- ///
50
- /// This method will error if any of the follow occurs:
51
- ///
52
- /// - The `blocks` iterator is empty, in which case, the error will be `None`.
53
- /// - The `blocks` iterator is not in ascending height order.
54
- /// - The `blocks` iterator contains multiple [`BlockId`]s of the same height.
55
- ///
56
- /// The error type is the last successful checkpoint constructed (if any).
57
- pub fn from_block_ids (
58
- block_ids : impl IntoIterator < Item = BlockId > ,
59
- ) -> Result < Self , Option < Self > > {
60
- let mut blocks = block_ids. into_iter ( ) ;
61
- let mut acc = CheckPoint :: new ( blocks. next ( ) . ok_or ( None ) ?) ;
62
- for id in blocks {
63
- acc = acc. push ( id) . map_err ( Some ) ?;
64
- }
65
- Ok ( acc)
66
- }
67
-
68
- /// Construct a checkpoint from the given `header` and block `height`.
69
- ///
70
- /// If `header` is of the genesis block, the checkpoint won't have a [`prev`] node. Otherwise,
71
- /// we return a checkpoint linked with the previous block.
72
- ///
73
- /// [`prev`]: CheckPoint::prev
74
- pub fn from_header ( header : & bitcoin:: block:: Header , height : u32 ) -> Self {
75
- let hash = header. block_hash ( ) ;
76
- let this_block_id = BlockId { height, hash } ;
77
-
78
- let prev_height = match height. checked_sub ( 1 ) {
79
- Some ( h) => h,
80
- None => return Self :: new ( this_block_id) ,
81
- } ;
82
-
83
- let prev_block_id = BlockId {
84
- height : prev_height,
85
- hash : header. prev_blockhash ,
86
- } ;
87
-
88
- CheckPoint :: new ( prev_block_id)
89
- . push ( this_block_id)
90
- . expect ( "must construct checkpoint" )
91
- }
92
-
93
- /// Puts another checkpoint onto the linked list representing the blockchain.
94
- ///
95
- /// Returns an `Err(self)` if the block you are pushing on is not at a greater height that the one you
96
- /// are pushing on to.
97
- pub fn push ( self , block : BlockId ) -> Result < Self , Self > {
98
- if self . height ( ) < block. height {
99
- Ok ( Self ( Arc :: new ( CPInner {
100
- block,
101
- prev : Some ( self . 0 ) ,
102
- } ) ) )
103
- } else {
104
- Err ( self )
105
- }
106
- }
107
-
108
- /// Extends the checkpoint linked list by a iterator of block ids.
109
- ///
110
- /// Returns an `Err(self)` if there is block which does not have a greater height than the
111
- /// previous one.
112
- pub fn extend ( self , blocks : impl IntoIterator < Item = BlockId > ) -> Result < Self , Self > {
113
- let mut curr = self . clone ( ) ;
114
- for block in blocks {
115
- curr = curr. push ( block) . map_err ( |_| self . clone ( ) ) ?;
116
- }
117
- Ok ( curr)
118
- }
119
-
120
- /// Get the [`BlockId`] of the checkpoint.
121
- pub fn block_id ( & self ) -> BlockId {
122
- self . 0 . block
123
- }
124
-
125
- /// Get the height of the checkpoint.
126
- pub fn height ( & self ) -> u32 {
127
- self . 0 . block . height
128
- }
129
-
130
- /// Get the block hash of the checkpoint.
131
- pub fn hash ( & self ) -> BlockHash {
132
- self . 0 . block . hash
133
- }
134
-
135
- /// Get the previous checkpoint in the chain
136
- pub fn prev ( & self ) -> Option < CheckPoint > {
137
- self . 0 . prev . clone ( ) . map ( CheckPoint )
138
- }
139
-
140
- /// Iterate from this checkpoint in descending height.
141
- pub fn iter ( & self ) -> CheckPointIter {
142
- self . clone ( ) . into_iter ( )
143
- }
144
-
145
- /// Get checkpoint at `height`.
146
- ///
147
- /// Returns `None` if checkpoint at `height` does not exist`.
148
- pub fn get ( & self , height : u32 ) -> Option < Self > {
149
- self . range ( height..=height) . next ( )
150
- }
151
-
152
- /// Iterate checkpoints over a height range.
153
- ///
154
- /// Note that we always iterate checkpoints in reverse height order (iteration starts at tip
155
- /// height).
156
- pub fn range < R > ( & self , range : R ) -> impl Iterator < Item = CheckPoint >
157
- where
158
- R : RangeBounds < u32 > ,
159
- {
160
- let start_bound = range. start_bound ( ) . cloned ( ) ;
161
- let end_bound = range. end_bound ( ) . cloned ( ) ;
162
- self . iter ( )
163
- . skip_while ( move |cp| match end_bound {
164
- core:: ops:: Bound :: Included ( inc_bound) => cp. height ( ) > inc_bound,
165
- core:: ops:: Bound :: Excluded ( exc_bound) => cp. height ( ) >= exc_bound,
166
- core:: ops:: Bound :: Unbounded => false ,
167
- } )
168
- . take_while ( move |cp| match start_bound {
169
- core:: ops:: Bound :: Included ( inc_bound) => cp. height ( ) >= inc_bound,
170
- core:: ops:: Bound :: Excluded ( exc_bound) => cp. height ( ) > exc_bound,
171
- core:: ops:: Bound :: Unbounded => true ,
172
- } )
173
- }
174
-
175
- /// Inserts `block_id` at its height within the chain.
176
- ///
177
- /// The effect of `insert` depends on whether a height already exists. If it doesn't the
178
- /// `block_id` we inserted and all pre-existing blocks higher than it will be re-inserted after
179
- /// it. If the height already existed and has a conflicting block hash then it will be purged
180
- /// along with all block followin it. The returned chain will have a tip of the `block_id`
181
- /// passed in. Of course, if the `block_id` was already present then this just returns `self`.
182
- #[ must_use]
183
- pub fn insert ( self , block_id : BlockId ) -> Self {
184
- assert_ne ! ( block_id. height, 0 , "cannot insert the genesis block" ) ;
185
-
186
- let mut cp = self . clone ( ) ;
187
- let mut tail = vec ! [ ] ;
188
- let base = loop {
189
- if cp. height ( ) == block_id. height {
190
- if cp. hash ( ) == block_id. hash {
191
- return self ;
192
- }
193
- // if we have a conflict we just return the inserted block because the tail is by
194
- // implication invalid.
195
- tail = vec ! [ ] ;
196
- break cp. prev ( ) . expect ( "can't be called on genesis block" ) ;
197
- }
198
-
199
- if cp. height ( ) < block_id. height {
200
- break cp;
201
- }
202
-
203
- tail. push ( cp. block_id ( ) ) ;
204
- cp = cp. prev ( ) . expect ( "will break before genesis block" ) ;
205
- } ;
206
-
207
- base. extend ( core:: iter:: once ( block_id) . chain ( tail. into_iter ( ) . rev ( ) ) )
208
- . expect ( "tail is in order" )
209
- }
210
- }
211
-
212
- /// Iterates over checkpoints backwards.
213
- pub struct CheckPointIter {
214
- current : Option < Arc < CPInner > > ,
215
- }
216
-
217
- impl Iterator for CheckPointIter {
218
- type Item = CheckPoint ;
219
-
220
- fn next ( & mut self ) -> Option < Self :: Item > {
221
- let current = self . current . clone ( ) ?;
222
- self . current . clone_from ( & current. prev ) ;
223
- Some ( CheckPoint ( current) )
224
- }
225
- }
226
-
227
- impl IntoIterator for CheckPoint {
228
- type Item = CheckPoint ;
229
- type IntoIter = CheckPointIter ;
230
-
231
- fn into_iter ( self ) -> Self :: IntoIter {
232
- CheckPointIter {
233
- current : Some ( self . 0 ) ,
234
- }
235
- }
236
- }
237
-
238
12
/// Apply `changeset` to the checkpoint.
239
13
fn apply_changeset_to_checkpoint (
240
14
mut init_cp : CheckPoint ,
@@ -582,9 +356,7 @@ impl LocalChain {
582
356
583
357
/// Iterate over checkpoints in descending height order.
584
358
pub fn iter_checkpoints ( & self ) -> CheckPointIter {
585
- CheckPointIter {
586
- current : Some ( self . tip . 0 . clone ( ) ) ,
587
- }
359
+ self . tip . iter ( )
588
360
}
589
361
590
362
fn _check_changeset_is_applied ( & self , changeset : & ChangeSet ) -> bool {
@@ -847,7 +619,7 @@ fn merge_chains(
847
619
prev_orig_was_invalidated = false ;
848
620
// OPTIMIZATION 2 -- if we have the same underlying pointer at this point, we
849
621
// can guarantee that no older blocks are introduced.
850
- if Arc :: as_ptr ( & o . 0 ) == Arc :: as_ptr ( & u . 0 ) {
622
+ if o . eq_ptr ( u ) {
851
623
if is_update_height_superset_of_original {
852
624
return Ok ( ( update_tip, changeset) ) ;
853
625
} else {
0 commit comments