@@ -10,29 +10,69 @@ use crate::BlockId;
10
10
/// Checkpoints are cheaply cloneable and are useful to find the agreement point between two sparse
11
11
/// block chains.
12
12
#[ derive( Debug , Clone ) ]
13
- pub struct CheckPoint ( Arc < CPInner > ) ;
13
+ pub struct CheckPoint < B = BlockHash > ( Arc < CPInner < B > > ) ;
14
14
15
15
/// The internal contents of [`CheckPoint`].
16
16
#[ derive( Debug , Clone ) ]
17
- struct CPInner {
18
- /// Block id (hash and height).
19
- block : BlockId ,
17
+ struct CPInner < B > {
18
+ /// Block height.
19
+ height : u32 ,
20
+ /// Data.
21
+ data : B ,
20
22
/// Previous checkpoint (if any).
21
- prev : Option < Arc < CPInner > > ,
23
+ prev : Option < Arc < CPInner < B > > > ,
22
24
}
23
25
24
- impl PartialEq for CheckPoint {
26
+ /// TODO: ToBlockHash doc
27
+ pub trait ToBlockHash {
28
+ /// TODO: to_blockhash doc
29
+ fn to_blockhash ( & self ) -> BlockHash ;
30
+ }
31
+
32
+ impl < B > PartialEq for CheckPoint < B >
33
+ where
34
+ B : Copy + Clone + core:: cmp:: PartialEq ,
35
+ {
25
36
fn eq ( & self , other : & Self ) -> bool {
26
- let self_cps = self . iter ( ) . map ( |cp| cp. block_id ( ) ) ;
27
- let other_cps = other. iter ( ) . map ( |cp| cp. block_id ( ) ) ;
37
+ let self_cps = self . iter ( ) . map ( |cp| * cp. inner ( ) ) ;
38
+ let other_cps = other. iter ( ) . map ( |cp| * cp. inner ( ) ) ;
28
39
self_cps. eq ( other_cps)
29
40
}
30
41
}
31
42
32
- impl CheckPoint {
33
- /// Construct a new base block at the front of a linked list.
43
+ impl CheckPoint < BlockHash > {
44
+ /// Construct a new [`CheckPoint`] at the front of a linked list.
34
45
pub fn new ( block : BlockId ) -> Self {
35
- Self ( Arc :: new ( CPInner { block, prev : None } ) )
46
+ Self ( Arc :: new ( CPInner {
47
+ height : block. height ,
48
+ data : block. hash ,
49
+ prev : None ,
50
+ } ) )
51
+ }
52
+
53
+ /// Construct a checkpoint from the given `header` and block `height`.
54
+ ///
55
+ /// If `header` is of the genesis block, the checkpoint won't have a [`prev`] node. Otherwise,
56
+ /// we return a checkpoint linked with the previous block.
57
+ ///
58
+ /// [`prev`]: CheckPoint::prev
59
+ pub fn from_header ( header : & bitcoin:: block:: Header , height : u32 ) -> Self {
60
+ let hash = header. block_hash ( ) ;
61
+ let this_block_id = BlockId { height, hash } ;
62
+
63
+ let prev_height = match height. checked_sub ( 1 ) {
64
+ Some ( h) => h,
65
+ None => return Self :: new ( this_block_id) ,
66
+ } ;
67
+
68
+ let prev_block_id = BlockId {
69
+ height : prev_height,
70
+ hash : header. prev_blockhash ,
71
+ } ;
72
+
73
+ CheckPoint :: new ( prev_block_id)
74
+ . push ( this_block_id)
75
+ . expect ( "must construct checkpoint" )
36
76
}
37
77
38
78
/// Construct a checkpoint from a list of [`BlockId`]s in ascending height order.
@@ -50,36 +90,75 @@ impl CheckPoint {
50
90
block_ids : impl IntoIterator < Item = BlockId > ,
51
91
) -> Result < Self , Option < Self > > {
52
92
let mut blocks = block_ids. into_iter ( ) ;
53
- let mut acc = CheckPoint :: new ( blocks. next ( ) . ok_or ( None ) ?) ;
93
+ let block = blocks. next ( ) . ok_or ( None ) ?;
94
+ let mut acc = CheckPoint :: new ( block) ;
54
95
for id in blocks {
55
96
acc = acc. push ( id) . map_err ( Some ) ?;
56
97
}
57
98
Ok ( acc)
58
99
}
59
100
60
- /// Construct a checkpoint from the given `header` and block `height` .
101
+ /// Extends the checkpoint linked list by a iterator of block ids .
61
102
///
62
- /// If `header` is of the genesis block, the checkpoint won't have a [`prev`] node. Otherwise,
63
- /// we return a checkpoint linked with the previous block.
103
+ /// Returns an `Err(self)` if there is block which does not have a greater height than the
104
+ /// previous one.
105
+ pub fn extend ( self , blockdata : impl IntoIterator < Item = BlockId > ) -> Result < Self , Self > {
106
+ let mut curr = self . clone ( ) ;
107
+ for block in blockdata {
108
+ curr = curr. push ( block) . map_err ( |_| self . clone ( ) ) ?;
109
+ }
110
+ Ok ( curr)
111
+ }
112
+
113
+ /// Get the block hash of the checkpoint.
114
+ pub fn hash ( & self ) -> BlockHash {
115
+ self . 0 . data
116
+ }
117
+
118
+ /// Get the [`BlockId`] of the checkpoint.
119
+ pub fn block_id ( & self ) -> BlockId {
120
+ BlockId {
121
+ height : self . height ( ) ,
122
+ hash : self . hash ( ) ,
123
+ }
124
+ }
125
+
126
+ /// Inserts `block_id` at its height within the chain.
64
127
///
65
- /// [`prev`]: CheckPoint::prev
66
- pub fn from_header ( header : & bitcoin:: block:: Header , height : u32 ) -> Self {
67
- let hash = header. block_hash ( ) ;
68
- let this_block_id = BlockId { height, hash } ;
128
+ /// The effect of `insert` depends on whether a height already exists. If it doesn't the
129
+ /// `block_id` we inserted and all pre-existing blocks higher than it will be re-inserted after
130
+ /// it. If the height already existed and has a conflicting block hash then it will be purged
131
+ /// along with all block followin it. The returned chain will have a tip of the `block_id`
132
+ /// passed in. Of course, if the `block_id` was already present then this just returns `self`.
133
+ #[ must_use]
134
+ pub fn insert ( self , block_id : BlockId ) -> Self {
135
+ assert_ne ! ( block_id. height, 0 , "cannot insert the genesis block" ) ;
69
136
70
- let prev_height = match height. checked_sub ( 1 ) {
71
- Some ( h) => h,
72
- None => return Self :: new ( this_block_id) ,
73
- } ;
137
+ let mut cp = self . clone ( ) ;
138
+ let mut tail = vec ! [ ] ;
139
+ let base = loop {
140
+ if cp. height ( ) == block_id. height {
141
+ if cp. hash ( ) == block_id. hash {
142
+ return self ;
143
+ }
144
+ // if we have a conflict we just return the inserted block because the tail is by
145
+ // implication invalid.
146
+ tail = vec ! [ ] ;
147
+ break cp. prev ( ) . expect ( "can't be called on genesis block" ) ;
148
+ }
74
149
75
- let prev_block_id = BlockId {
76
- height : prev_height,
77
- hash : header. prev_blockhash ,
150
+ if cp. height ( ) < block_id. height {
151
+ break cp;
152
+ }
153
+
154
+ tail. push ( cp. block_id ( ) ) ;
155
+ cp = cp. prev ( ) . expect ( "will break before genesis block" ) ;
78
156
} ;
79
157
80
- CheckPoint :: new ( prev_block_id)
81
- . push ( this_block_id)
82
- . expect ( "must construct checkpoint" )
158
+ let new_cp = core:: iter:: once ( block_id) . chain ( tail. into_iter ( ) . rev ( ) ) ;
159
+ //.map(|block| (block.height, block.hash));
160
+
161
+ base. extend ( new_cp) . expect ( "tail is in order" )
83
162
}
84
163
85
164
/// Puts another checkpoint onto the linked list representing the blockchain.
@@ -89,48 +168,37 @@ impl CheckPoint {
89
168
pub fn push ( self , block : BlockId ) -> Result < Self , Self > {
90
169
if self . height ( ) < block. height {
91
170
Ok ( Self ( Arc :: new ( CPInner {
92
- block,
171
+ height : block. height ,
172
+ data : block. hash ,
93
173
prev : Some ( self . 0 ) ,
94
174
} ) ) )
95
175
} else {
96
176
Err ( self )
97
177
}
98
178
}
179
+ }
99
180
100
- /// Extends the checkpoint linked list by a iterator of block ids.
101
- ///
102
- /// Returns an `Err(self)` if there is block which does not have a greater height than the
103
- /// previous one.
104
- pub fn extend ( self , blocks : impl IntoIterator < Item = BlockId > ) -> Result < Self , Self > {
105
- let mut curr = self . clone ( ) ;
106
- for block in blocks {
107
- curr = curr. push ( block) . map_err ( |_| self . clone ( ) ) ?;
108
- }
109
- Ok ( curr)
110
- }
111
-
112
- /// Get the [`BlockId`] of the checkpoint.
113
- pub fn block_id ( & self ) -> BlockId {
114
- self . 0 . block
181
+ impl < B > CheckPoint < B >
182
+ where
183
+ B : Copy + Clone ,
184
+ {
185
+ /// Get reference to the inner type.
186
+ pub fn inner ( & self ) -> & B {
187
+ & self . 0 . data
115
188
}
116
189
117
190
/// Get the height of the checkpoint.
118
191
pub fn height ( & self ) -> u32 {
119
- self . 0 . block . height
120
- }
121
-
122
- /// Get the block hash of the checkpoint.
123
- pub fn hash ( & self ) -> BlockHash {
124
- self . 0 . block . hash
192
+ self . 0 . height
125
193
}
126
194
127
195
/// Get the previous checkpoint in the chain
128
- pub fn prev ( & self ) -> Option < CheckPoint > {
196
+ pub fn prev ( & self ) -> Option < CheckPoint < B > > {
129
197
self . 0 . prev . clone ( ) . map ( CheckPoint )
130
198
}
131
199
132
200
/// Iterate from this checkpoint in descending height.
133
- pub fn iter ( & self ) -> CheckPointIter {
201
+ pub fn iter ( & self ) -> CheckPointIter < B > {
134
202
self . clone ( ) . into_iter ( )
135
203
}
136
204
@@ -145,7 +213,7 @@ impl CheckPoint {
145
213
///
146
214
/// Note that we always iterate checkpoints in reverse height order (iteration starts at tip
147
215
/// height).
148
- pub fn range < R > ( & self , range : R ) -> impl Iterator < Item = CheckPoint >
216
+ pub fn range < R > ( & self , range : R ) -> impl Iterator < Item = CheckPoint < B > >
149
217
where
150
218
R : RangeBounds < u32 > ,
151
219
{
@@ -164,55 +232,19 @@ impl CheckPoint {
164
232
} )
165
233
}
166
234
167
- /// Inserts `block_id` at its height within the chain.
168
- ///
169
- /// The effect of `insert` depends on whether a height already exists. If it doesn't the
170
- /// `block_id` we inserted and all pre-existing blocks higher than it will be re-inserted after
171
- /// it. If the height already existed and has a conflicting block hash then it will be purged
172
- /// along with all block followin it. The returned chain will have a tip of the `block_id`
173
- /// passed in. Of course, if the `block_id` was already present then this just returns `self`.
174
- #[ must_use]
175
- pub fn insert ( self , block_id : BlockId ) -> Self {
176
- assert_ne ! ( block_id. height, 0 , "cannot insert the genesis block" ) ;
177
-
178
- let mut cp = self . clone ( ) ;
179
- let mut tail = vec ! [ ] ;
180
- let base = loop {
181
- if cp. height ( ) == block_id. height {
182
- if cp. hash ( ) == block_id. hash {
183
- return self ;
184
- }
185
- // if we have a conflict we just return the inserted block because the tail is by
186
- // implication invalid.
187
- tail = vec ! [ ] ;
188
- break cp. prev ( ) . expect ( "can't be called on genesis block" ) ;
189
- }
190
-
191
- if cp. height ( ) < block_id. height {
192
- break cp;
193
- }
194
-
195
- tail. push ( cp. block_id ( ) ) ;
196
- cp = cp. prev ( ) . expect ( "will break before genesis block" ) ;
197
- } ;
198
-
199
- base. extend ( core:: iter:: once ( block_id) . chain ( tail. into_iter ( ) . rev ( ) ) )
200
- . expect ( "tail is in order" )
201
- }
202
-
203
235
/// This method tests for `self` and `other` to have equal internal pointers.
204
236
pub fn eq_ptr ( & self , other : & Self ) -> bool {
205
237
Arc :: as_ptr ( & self . 0 ) == Arc :: as_ptr ( & other. 0 )
206
238
}
207
239
}
208
240
209
241
/// Iterates over checkpoints backwards.
210
- pub struct CheckPointIter {
211
- current : Option < Arc < CPInner > > ,
242
+ pub struct CheckPointIter < B = BlockHash > {
243
+ current : Option < Arc < CPInner < B > > > ,
212
244
}
213
245
214
- impl Iterator for CheckPointIter {
215
- type Item = CheckPoint ;
246
+ impl < B > Iterator for CheckPointIter < B > {
247
+ type Item = CheckPoint < B > ;
216
248
217
249
fn next ( & mut self ) -> Option < Self :: Item > {
218
250
let current = self . current . clone ( ) ?;
@@ -221,9 +253,9 @@ impl Iterator for CheckPointIter {
221
253
}
222
254
}
223
255
224
- impl IntoIterator for CheckPoint {
225
- type Item = CheckPoint ;
226
- type IntoIter = CheckPointIter ;
256
+ impl < B > IntoIterator for CheckPoint < B > {
257
+ type Item = CheckPoint < B > ;
258
+ type IntoIter = CheckPointIter < B > ;
227
259
228
260
fn into_iter ( self ) -> Self :: IntoIter {
229
261
CheckPointIter {
0 commit comments