@@ -6,8 +6,8 @@ use core::ops::RangeBounds;
66
77use crate :: collections:: BTreeMap ;
88use crate :: { BlockId , ChainOracle , Merge } ;
9- use bdk_core:: ToBlockHash ;
109pub use bdk_core:: { CheckPoint , CheckPointIter } ;
10+ use bdk_core:: { CheckPointEntry , ToBlockHash } ;
1111use bitcoin:: block:: Header ;
1212use bitcoin:: BlockHash ;
1313
2525 // point of agreement
2626 let mut base: Option < CheckPoint < D > > = None ;
2727
28- for cp in init_cp. iter ( ) {
28+ for cp in init_cp. iter ( ) . filter_map ( |item| item . checkpoint ( ) ) {
2929 if cp. height ( ) >= start_height {
3030 extension. insert ( cp. height ( ) , cp. data ( ) ) ;
3131 } else {
@@ -63,30 +63,42 @@ pub struct LocalChain<D = BlockHash> {
6363 tip : CheckPoint < D > ,
6464}
6565
66- impl < D > PartialEq for LocalChain < D > {
66+ impl < D : ToBlockHash > PartialEq for LocalChain < D > {
6767 fn eq ( & self , other : & Self ) -> bool {
6868 self . tip == other. tip
6969 }
7070}
7171
72- impl < D > ChainOracle for LocalChain < D > {
72+ impl < D : ToBlockHash > ChainOracle for LocalChain < D > {
7373 type Error = Infallible ;
7474
7575 fn is_block_in_chain (
7676 & self ,
7777 block : BlockId ,
7878 chain_tip : BlockId ,
7979 ) -> Result < Option < bool > , Self :: Error > {
80- let chain_tip_cp = match self . tip . get ( chain_tip. height ) {
81- // we can only determine whether `block` is in chain of `chain_tip` if `chain_tip` can
82- // be identified in chain
83- Some ( cp) if cp. hash ( ) == chain_tip. hash => cp,
84- _ => return Ok ( None ) ,
85- } ;
86- match chain_tip_cp. get ( block. height ) {
87- Some ( cp) => Ok ( Some ( cp. hash ( ) == block. hash ) ) ,
88- None => Ok ( None ) ,
89- }
80+ Ok ( || -> Option < bool > {
81+ let mut cp_iter = self . tip . iter ( ) ;
82+ let mut cp_item = cp_iter. next ( ) ?;
83+ loop {
84+ if cp_item. height ( ) < chain_tip. height {
85+ return None ;
86+ }
87+ if cp_item. block_id ( ) == chain_tip {
88+ break ;
89+ }
90+ cp_item = cp_iter. next ( ) ?;
91+ }
92+ loop {
93+ if cp_item. height ( ) < block. height {
94+ return None ;
95+ }
96+ if cp_item. height ( ) == block. height {
97+ return Some ( cp_item. hash ( ) == block. hash ) ;
98+ }
99+ cp_item = cp_iter. next ( ) ?;
100+ }
101+ } ( ) )
90102 }
91103
92104 fn get_chain_tip ( & self ) -> Result < BlockId , Self :: Error > {
@@ -195,7 +207,9 @@ impl<D> LocalChain<D> {
195207 pub fn tip ( & self ) -> CheckPoint < D > {
196208 self . tip . clone ( )
197209 }
210+ }
198211
212+ impl < D : ToBlockHash > LocalChain < D > {
199213 /// Get the genesis hash.
200214 pub fn genesis_hash ( & self ) -> BlockHash {
201215 self . tip . get ( 0 ) . expect ( "genesis must exist" ) . block_id ( ) . hash
@@ -211,8 +225,8 @@ impl<D> LocalChain<D> {
211225 /// This is a shorthand for calling [`CheckPoint::get`] on the [`tip`].
212226 ///
213227 /// [`tip`]: LocalChain::tip
214- pub fn get ( & self , height : u32 ) -> Option < CheckPoint < D > > {
215- self . tip . get ( height)
228+ pub fn get ( & self , height : u32 ) -> Option < CheckPointEntry < D > > {
229+ self . tip . entry ( height)
216230 }
217231
218232 /// Iterate checkpoints over a height range.
@@ -223,7 +237,7 @@ impl<D> LocalChain<D> {
223237 /// This is a shorthand for calling [`CheckPoint::range`] on the [`tip`].
224238 ///
225239 /// [`tip`]: LocalChain::tip
226- pub fn range < R > ( & self , range : R ) -> impl Iterator < Item = CheckPoint < D > >
240+ pub fn range < R > ( & self , range : R ) -> impl Iterator < Item = CheckPointEntry < D > >
227241 where
228242 R : RangeBounds < u32 > ,
229243 {
@@ -325,6 +339,7 @@ where
325339 blocks : self
326340 . tip
327341 . iter ( )
342+ . filter_map ( |entry| entry. checkpoint ( ) )
328343 . map ( |cp| ( cp. height ( ) , Some ( cp. data ( ) ) ) )
329344 . collect ( ) ,
330345 }
@@ -383,14 +398,20 @@ where
383398 ) -> Result < ChangeSet < D > , MissingGenesisError > {
384399 let mut remove_from = Option :: < CheckPoint < D > > :: None ;
385400 let mut changeset = ChangeSet :: default ( ) ;
386- for cp in self . tip ( ) . iter ( ) {
387- let cp_id = cp . block_id ( ) ;
401+ for cp_entry in self . tip ( ) . iter ( ) {
402+ let cp_id = cp_entry . block_id ( ) ;
388403 if cp_id. height < block_id. height {
389404 break ;
390405 }
391406 changeset. blocks . insert ( cp_id. height , None ) ;
392407 if cp_id == block_id {
393- remove_from = Some ( cp) ;
408+ // TODO: This is wrong. What am I doing?
409+ remove_from = match cp_entry. floor_checkpoint ( ) {
410+ Some ( floor_cp) if floor_cp. height ( ) < cp_entry. height ( ) => Some ( floor_cp) ,
411+ Some ( floor_cp) => floor_cp. prev ( ) ,
412+ None => None ,
413+ } ;
414+ break ;
394415 }
395416 }
396417 self . tip = match remove_from. map ( |cp| cp. prev ( ) ) {
@@ -604,8 +625,8 @@ where
604625 let mut curr_orig = None ;
605626 let mut curr_update = None ;
606627
607- let mut prev_orig: Option < CheckPoint < D > > = None ;
608- let mut prev_update: Option < CheckPoint < D > > = None ;
628+ let mut prev_orig: Option < CheckPointEntry < D > > = None ;
629+ let mut prev_update: Option < CheckPointEntry < D > > = None ;
609630
610631 let mut point_of_agreement_found = false ;
611632
@@ -634,7 +655,9 @@ where
634655 match ( curr_orig. as_ref ( ) , curr_update. as_ref ( ) ) {
635656 // Update block that doesn't exist in the original chain
636657 ( o, Some ( u) ) if Some ( u. height ( ) ) > o. map ( |o| o. height ( ) ) => {
637- changeset. blocks . insert ( u. height ( ) , Some ( u. data ( ) ) ) ;
658+ if let Some ( data) = u. data ( ) {
659+ changeset. blocks . insert ( u. height ( ) , Some ( data) ) ;
660+ }
638661 prev_update = curr_update. take ( ) ;
639662 }
640663 // Original block that isn't in the update
@@ -671,7 +694,12 @@ where
671694 prev_orig_was_invalidated = false ;
672695 // OPTIMIZATION 2 -- if we have the same underlying pointer at this point, we
673696 // can guarantee that no older blocks are introduced.
674- if o. eq_ptr ( u) {
697+ // TODO: Is this correct?
698+ let is_eq_ptr = match ( o. floor_checkpoint ( ) , u. floor_checkpoint ( ) ) {
699+ ( Some ( o_cp) , Some ( u_cp) ) => o_cp. eq_ptr ( & u_cp) ,
700+ _ => false ,
701+ } ;
702+ if is_eq_ptr {
675703 if is_update_height_superset_of_original {
676704 return Ok ( ( update_tip, changeset) ) ;
677705 } else {
@@ -685,7 +713,9 @@ where
685713 } else {
686714 // We have an invalidation height so we set the height to the updated hash and
687715 // also purge all the original chain block hashes above this block.
688- changeset. blocks . insert ( u. height ( ) , Some ( u. data ( ) ) ) ;
716+ if let Some ( u_data) = u. data ( ) {
717+ changeset. blocks . insert ( u. height ( ) , Some ( u_data) ) ;
718+ }
689719 for invalidated_height in potentially_invalidated_heights. drain ( ..) {
690720 changeset. blocks . insert ( invalidated_height, None ) ;
691721 }
0 commit comments