@@ -10,29 +10,69 @@ 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).
19- block : BlockId ,
17+ struct CPInner < B > {
18+ /// Block height.
19+ height : u32 ,
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 < B > PartialEq for CheckPoint < B >
33+ where
34+ B : Copy + Clone + core:: cmp:: PartialEq ,
35+ {
2536 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 ( ) ) ;
2839 self_cps. eq ( other_cps)
2940 }
3041}
3142
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.
3445 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" )
3676 }
3777
3878 /// Construct a checkpoint from a list of [`BlockId`]s in ascending height order.
@@ -50,36 +90,75 @@ impl CheckPoint {
5090 block_ids : impl IntoIterator < Item = BlockId > ,
5191 ) -> Result < Self , Option < Self > > {
5292 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) ;
5495 for id in blocks {
5596 acc = acc. push ( id) . map_err ( Some ) ?;
5697 }
5798 Ok ( acc)
5899 }
59100
60- /// Construct a checkpoint from the given `header` and block `height` .
101+ /// Extends the checkpoint linked list by a iterator of block ids .
61102 ///
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.
64127 ///
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" ) ;
69136
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+ }
74149
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" ) ;
78156 } ;
79157
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" )
83162 }
84163
85164 /// Puts another checkpoint onto the linked list representing the blockchain.
@@ -89,48 +168,37 @@ impl CheckPoint {
89168 pub fn push ( self , block : BlockId ) -> Result < Self , Self > {
90169 if self . height ( ) < block. height {
91170 Ok ( Self ( Arc :: new ( CPInner {
92- block,
171+ height : block. height ,
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 + Clone ,
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 {
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
125193 }
126194
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 {
@@ -164,55 +232,19 @@ impl CheckPoint {
164232 } )
165233 }
166234
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-
203235 /// This method tests for `self` and `other` to have equal internal pointers.
204236 pub fn eq_ptr ( & self , other : & Self ) -> bool {
205237 Arc :: as_ptr ( & self . 0 ) == Arc :: as_ptr ( & other. 0 )
206238 }
207239}
208240
209241/// 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 > > > ,
212244}
213245
214- impl Iterator for CheckPointIter {
215- type Item = CheckPoint ;
246+ impl < B > Iterator for CheckPointIter < B > {
247+ type Item = CheckPoint < B > ;
216248
217249 fn next ( & mut self ) -> Option < Self :: Item > {
218250 let current = self . current . clone ( ) ?;
@@ -221,9 +253,9 @@ impl Iterator for CheckPointIter {
221253 }
222254}
223255
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 > ;
227259
228260 fn into_iter ( self ) -> Self :: IntoIter {
229261 CheckPointIter {
0 commit comments