11use core:: ops:: RangeBounds ;
22
33use alloc:: sync:: Arc ;
4- use bitcoin:: BlockHash ;
4+ use bitcoin:: { block :: Header , consensus :: Encodable , hashes :: Hash , BlockHash } ;
55
66use crate :: BlockId ;
77
@@ -10,29 +10,83 @@ use crate::BlockId;
1010/// Checkpoints are cheaply cloneable and are useful to find the agreement point between two sparse
1111/// block chains.
1212#[ derive( Debug , Clone ) ]
13- pub struct CheckPoint ( Arc < CPInner > ) ;
13+ pub struct CheckPoint < B = BlockHash > ( Arc < CPInner < B > > ) ;
1414
1515/// The internal contents of [`CheckPoint`].
1616#[ derive( Debug , Clone ) ]
17- struct CPInner {
18- /// Block id (hash and height) .
17+ struct CPInner < B > {
18+ /// Block data .
1919 block : BlockId ,
20+ /// Data.
21+ data : B ,
2022 /// Previous checkpoint (if any).
21- prev : Option < Arc < CPInner > > ,
23+ prev : Option < Arc < CPInner < B > > > ,
2224}
2325
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 ToBlockHash for BlockHash {
33+ fn to_blockhash ( & self ) -> BlockHash {
34+ * self
35+ }
36+ }
37+
38+ impl ToBlockHash for Header {
39+ fn to_blockhash ( & self ) -> BlockHash {
40+ let mut bytes = vec ! [ ] ;
41+ self . consensus_encode ( & mut bytes) . unwrap_or_default ( ) ;
42+ BlockHash :: hash ( & bytes)
43+ }
44+ }
45+
46+ impl < B > PartialEq for CheckPoint < B >
47+ where
48+ B : Copy + core:: cmp:: PartialEq ,
49+ {
2550 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 ( ) ) ;
51+ let self_cps = self . iter ( ) . map ( |cp| * cp. inner ( ) ) ;
52+ let other_cps = other. iter ( ) . map ( |cp| * cp. inner ( ) ) ;
2853 self_cps. eq ( other_cps)
2954 }
3055}
3156
32- impl CheckPoint {
33- /// Construct a new base block at the front of a linked list.
57+ impl CheckPoint < BlockHash > {
58+ /// Construct a new [`CheckPoint`] at the front of a linked list.
3459 pub fn new ( block : BlockId ) -> Self {
35- Self ( Arc :: new ( CPInner { block, prev : None } ) )
60+ Self ( Arc :: new ( CPInner {
61+ block,
62+ data : block. hash ,
63+ prev : None ,
64+ } ) )
65+ }
66+
67+ /// Construct a checkpoint from the given `header` and block `height`.
68+ ///
69+ /// If `header` is of the genesis block, the checkpoint won't have a [`prev`] node. Otherwise,
70+ /// we return a checkpoint linked with the previous block.
71+ ///
72+ /// [`prev`]: CheckPoint::prev
73+ pub fn from_header ( header : & bitcoin:: block:: Header , height : u32 ) -> Self {
74+ let hash = header. block_hash ( ) ;
75+ let this_block_id = BlockId { height, hash } ;
76+
77+ let prev_height = match height. checked_sub ( 1 ) {
78+ Some ( h) => h,
79+ None => return Self :: new ( this_block_id) ,
80+ } ;
81+
82+ let prev_block_id = BlockId {
83+ height : prev_height,
84+ hash : header. prev_blockhash ,
85+ } ;
86+
87+ CheckPoint :: new ( prev_block_id)
88+ . push ( this_block_id)
89+ . expect ( "must construct checkpoint" )
3690 }
3791
3892 /// Construct a checkpoint from a list of [`BlockId`]s in ascending height order.
@@ -50,36 +104,61 @@ impl CheckPoint {
50104 block_ids : impl IntoIterator < Item = BlockId > ,
51105 ) -> Result < Self , Option < Self > > {
52106 let mut blocks = block_ids. into_iter ( ) ;
53- let mut acc = CheckPoint :: new ( blocks. next ( ) . ok_or ( None ) ?) ;
107+ let block = blocks. next ( ) . ok_or ( None ) ?;
108+ let mut acc = CheckPoint :: new ( block) ;
54109 for id in blocks {
55110 acc = acc. push ( id) . map_err ( Some ) ?;
56111 }
57112 Ok ( acc)
58113 }
59114
60- /// Construct a checkpoint from the given `header` and block `height` .
115+ /// Extends the checkpoint linked list by a iterator of block ids .
61116 ///
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.
117+ /// Returns an `Err(self)` if there is block which does not have a greater height than the
118+ /// previous one.
119+ pub fn extend ( self , blockdata : impl IntoIterator < Item = BlockId > ) -> Result < Self , Self > {
120+ let mut curr = self . clone ( ) ;
121+ for block in blockdata {
122+ curr = curr. push ( block) . map_err ( |_| self . clone ( ) ) ?;
123+ }
124+ Ok ( curr)
125+ }
126+
127+ /// Inserts `block_id` at its height within the chain.
64128 ///
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 } ;
129+ /// The effect of `insert` depends on whether a height already exists. If it doesn't the
130+ /// `block_id` we inserted and all pre-existing blocks higher than it will be re-inserted after
131+ /// it. If the height already existed and has a conflicting block hash then it will be purged
132+ /// along with all block followin it. The returned chain will have a tip of the `block_id`
133+ /// passed in. Of course, if the `block_id` was already present then this just returns `self`.
134+ #[ must_use]
135+ pub fn insert ( self , block_id : BlockId ) -> Self {
136+ assert_ne ! ( block_id. height, 0 , "cannot insert the genesis block" ) ;
69137
70- let prev_height = match height. checked_sub ( 1 ) {
71- Some ( h) => h,
72- None => return Self :: new ( this_block_id) ,
73- } ;
138+ let mut cp = self . clone ( ) ;
139+ let mut tail = vec ! [ ] ;
140+ let base = loop {
141+ if cp. height ( ) == block_id. height {
142+ if cp. hash ( ) == block_id. hash {
143+ return self ;
144+ }
145+ // if we have a conflict we just return the inserted block because the tail is by
146+ // implication invalid.
147+ tail = vec ! [ ] ;
148+ break cp. prev ( ) . expect ( "can't be called on genesis block" ) ;
149+ }
74150
75- let prev_block_id = BlockId {
76- height : prev_height,
77- hash : header. prev_blockhash ,
151+ if cp. height ( ) < block_id. height {
152+ break cp;
153+ }
154+
155+ tail. push ( cp. block_id ( ) ) ;
156+ cp = cp. prev ( ) . expect ( "will break before genesis block" ) ;
78157 } ;
79158
80- CheckPoint :: new ( prev_block_id )
81- . push ( this_block_id )
82- . expect ( "must construct checkpoint " )
159+ let new_cp = core :: iter :: once ( block_id ) . chain ( tail . into_iter ( ) . rev ( ) ) ;
160+
161+ base . extend ( new_cp ) . expect ( "tail is in order " )
83162 }
84163
85164 /// Puts another checkpoint onto the linked list representing the blockchain.
@@ -90,47 +169,36 @@ impl CheckPoint {
90169 if self . height ( ) < block. height {
91170 Ok ( Self ( Arc :: new ( CPInner {
92171 block,
172+ data : block. hash ,
93173 prev : Some ( self . 0 ) ,
94174 } ) ) )
95175 } else {
96176 Err ( self )
97177 }
98178 }
179+ }
99180
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 ,
184+ {
185+ /// Get reference to the inner type.
186+ pub fn inner ( & self ) -> & B {
187+ & self . 0 . data
115188 }
116189
117190 /// Get the height of the checkpoint.
118191 pub fn height ( & self ) -> u32 {
119192 self . 0 . block . height
120193 }
121194
122- /// Get the block hash of the checkpoint.
123- pub fn hash ( & self ) -> BlockHash {
124- self . 0 . block . hash
125- }
126-
127195 /// Get the previous checkpoint in the chain
128- pub fn prev ( & self ) -> Option < CheckPoint > {
196+ pub fn prev ( & self ) -> Option < CheckPoint < B > > {
129197 self . 0 . prev . clone ( ) . map ( CheckPoint )
130198 }
131199
132200 /// Iterate from this checkpoint in descending height.
133- pub fn iter ( & self ) -> CheckPointIter {
201+ pub fn iter ( & self ) -> CheckPointIter < B > {
134202 self . clone ( ) . into_iter ( )
135203 }
136204
@@ -145,7 +213,7 @@ impl CheckPoint {
145213 ///
146214 /// Note that we always iterate checkpoints in reverse height order (iteration starts at tip
147215 /// 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 > >
149217 where
150218 R : RangeBounds < u32 > ,
151219 {
@@ -163,6 +231,48 @@ impl CheckPoint {
163231 core:: ops:: Bound :: Unbounded => true ,
164232 } )
165233 }
234+ }
235+
236+ impl < B > CheckPoint < B >
237+ where
238+ B : Copy + core:: fmt:: Debug + ToBlockHash ,
239+ {
240+ /// Get the [`BlockId`] of the checkpoint.
241+ pub fn block_id ( & self ) -> BlockId {
242+ BlockId {
243+ height : self . height ( ) ,
244+ hash : self . hash ( ) ,
245+ }
246+ }
247+
248+ /// Construct a new [`CheckPoint`] at the front of a linked list.
249+ pub fn from_data ( height : u32 , data : B ) -> Self {
250+ Self ( Arc :: new ( CPInner {
251+ block : BlockId {
252+ height,
253+ hash : data. to_blockhash ( ) ,
254+ } ,
255+ data,
256+ prev : None ,
257+ } ) )
258+ }
259+
260+ /// Get the block hash of the checkpoint.
261+ pub fn hash ( & self ) -> BlockHash {
262+ self . 0 . data . to_blockhash ( )
263+ }
264+
265+ /// Extends the checkpoint linked list by a iterator of block ids.
266+ ///
267+ /// Returns an `Err(self)` if there is block which does not have a greater height than the
268+ /// previous one.
269+ pub fn extend_data ( self , blockdata : impl IntoIterator < Item = ( u32 , B ) > ) -> Result < Self , Self > {
270+ let mut curr = self . clone ( ) ;
271+ for ( height, data) in blockdata {
272+ curr = curr. push_data ( height, data) . map_err ( |_| self . clone ( ) ) ?;
273+ }
274+ Ok ( curr)
275+ }
166276
167277 /// Inserts `block_id` at its height within the chain.
168278 ///
@@ -172,14 +282,14 @@ impl CheckPoint {
172282 /// along with all block followin it. The returned chain will have a tip of the `block_id`
173283 /// passed in. Of course, if the `block_id` was already present then this just returns `self`.
174284 #[ must_use]
175- pub fn insert ( self , block_id : BlockId ) -> Self {
176- assert_ne ! ( block_id . height, 0 , "cannot insert the genesis block" ) ;
285+ pub fn insert_data ( self , height : u32 , data : B ) -> Self {
286+ assert_ne ! ( height, 0 , "cannot insert the genesis block" ) ;
177287
178288 let mut cp = self . clone ( ) ;
179289 let mut tail = vec ! [ ] ;
180290 let base = loop {
181- if cp. height ( ) == block_id . height {
182- if cp. hash ( ) == block_id . hash {
291+ if cp. height ( ) == height {
292+ if cp. hash ( ) == data . to_blockhash ( ) {
183293 return self ;
184294 }
185295 // if we have a conflict we just return the inserted block because the tail is by
@@ -188,16 +298,36 @@ impl CheckPoint {
188298 break cp. prev ( ) . expect ( "can't be called on genesis block" ) ;
189299 }
190300
191- if cp. height ( ) < block_id . height {
301+ if cp. height ( ) < height {
192302 break cp;
193303 }
194304
195- tail. push ( cp . block_id ( ) ) ;
305+ tail. push ( ( height , data ) ) ;
196306 cp = cp. prev ( ) . expect ( "will break before genesis block" ) ;
197307 } ;
198308
199- base. extend ( core:: iter:: once ( block_id) . chain ( tail. into_iter ( ) . rev ( ) ) )
200- . expect ( "tail is in order" )
309+ let new_cp = core:: iter:: once ( ( height, data) ) . chain ( tail. into_iter ( ) . rev ( ) ) ;
310+
311+ base. extend_data ( new_cp) . expect ( "tail is in order" )
312+ }
313+
314+ /// Puts another checkpoint onto the linked list representing the blockchain.
315+ ///
316+ /// Returns an `Err(self)` if the block you are pushing on is not at a greater height that the one you
317+ /// are pushing on to.
318+ pub fn push_data ( self , height : u32 , data : B ) -> Result < Self , Self > {
319+ if self . height ( ) < height {
320+ Ok ( Self ( Arc :: new ( CPInner {
321+ block : BlockId {
322+ height,
323+ hash : data. to_blockhash ( ) ,
324+ } ,
325+ data,
326+ prev : Some ( self . 0 ) ,
327+ } ) ) )
328+ } else {
329+ Err ( self )
330+ }
201331 }
202332
203333 /// This method tests for `self` and `other` to have equal internal pointers.
@@ -207,12 +337,12 @@ impl CheckPoint {
207337}
208338
209339/// Iterates over checkpoints backwards.
210- pub struct CheckPointIter {
211- current : Option < Arc < CPInner > > ,
340+ pub struct CheckPointIter < B = BlockHash > {
341+ current : Option < Arc < CPInner < B > > > ,
212342}
213343
214- impl Iterator for CheckPointIter {
215- type Item = CheckPoint ;
344+ impl < B > Iterator for CheckPointIter < B > {
345+ type Item = CheckPoint < B > ;
216346
217347 fn next ( & mut self ) -> Option < Self :: Item > {
218348 let current = self . current . clone ( ) ?;
@@ -221,9 +351,9 @@ impl Iterator for CheckPointIter {
221351 }
222352}
223353
224- impl IntoIterator for CheckPoint {
225- type Item = CheckPoint ;
226- type IntoIter = CheckPointIter ;
354+ impl < B > IntoIterator for CheckPoint < B > {
355+ type Item = CheckPoint < B > ;
356+ type IntoIter = CheckPointIter < B > ;
227357
228358 fn into_iter ( self ) -> Self :: IntoIter {
229359 CheckPointIter {
0 commit comments