@@ -341,6 +341,14 @@ impl BlockTree {
341341 self . headers . get ( hash) . map ( |node| node. header )
342342 }
343343
344+ // Returns the height of `hash` only when it sits on the canonical chain of most work.
345+ // Returns `None` for unknown hashes and for hashes on stale/reorganized branches.
346+ pub ( crate ) fn height_of_hash_canonical_only ( & self , hash : BlockHash ) -> Option < Height > {
347+ let height = self . headers . get ( & hash) . map ( |node| node. height ) ?;
348+ let canonical = self . block_hash_at_height ( height) ?;
349+ ( canonical == hash) . then_some ( height)
350+ }
351+
344352 pub ( crate ) fn height_of_hash ( & self , hash : BlockHash ) -> Option < Height > {
345353 self . headers . get ( & hash) . map ( |node| node. height )
346354 }
@@ -614,6 +622,20 @@ mod tests {
614622 assert_eq ! ( chain. header_at_height( 10 ) , Some ( new_block_10) ) ;
615623 assert_eq ! ( chain. header_at_height( 9 ) , Some ( base[ 1 ] . 0 ) ) ;
616624 assert_eq ! ( chain. header_at_height( 8 ) , Some ( base[ 0 ] . 0 ) ) ;
625+ // height_of_hash returns the height for hashes on the canonical chain
626+ assert_eq ! ( chain. height_of_hash( new_block_10. block_hash( ) ) , Some ( 10 ) ) ;
627+ assert_eq ! ( chain. height_of_hash( block_11. block_hash( ) ) , Some ( 11 ) ) ;
628+ // ...and None for hashes that were reorganized away, even though the header
629+ // is still stored in the graph.
630+ assert_eq ! (
631+ chain. height_of_hash_canonical_only( old_block_10. block_hash( ) ) ,
632+ None
633+ ) ;
634+ // Unknown hashes also return None.
635+ let unknown =
636+ BlockHash :: from_str ( "0000000000000000000000000000000000000000000000000000000000000000" )
637+ . unwrap ( ) ;
638+ assert_eq ! ( chain. height_of_hash( unknown) , None ) ;
617639 }
618640
619641 #[ test]
0 commit comments