@@ -4,15 +4,41 @@ use std::collections::HashMap;
44use std:: ops:: Range ;
55use std:: path:: PathBuf ;
66
7+ use crate :: error:: StorageResult ;
8+ use crate :: storage:: segments:: SegmentCache ;
9+ use crate :: storage:: PersistentStorage ;
10+ use crate :: types:: HashedBlockHeader ;
711use async_trait:: async_trait;
812use dashcore:: block:: Header as BlockHeader ;
13+ use dashcore:: prelude:: CoreBlockHeight ;
914use dashcore:: BlockHash ;
1015use tokio:: sync:: RwLock ;
1116
12- use crate :: error:: StorageResult ;
13- use crate :: storage:: segments:: SegmentCache ;
14- use crate :: storage:: PersistentStorage ;
15- use crate :: types:: HashedBlockHeader ;
17+ #[ derive( Debug , PartialEq ) ]
18+ pub struct BlockHeaderTip {
19+ height : CoreBlockHeight ,
20+ header : BlockHeader ,
21+ hash : BlockHash ,
22+ }
23+
24+ impl BlockHeaderTip {
25+ pub fn new ( height : CoreBlockHeight , hashed_block_header : HashedBlockHeader ) -> Self {
26+ Self {
27+ height,
28+ header : * hashed_block_header. header ( ) ,
29+ hash : * hashed_block_header. hash ( ) ,
30+ }
31+ }
32+ pub fn height ( & self ) -> CoreBlockHeight {
33+ self . height
34+ }
35+ pub fn header ( & self ) -> & BlockHeader {
36+ & self . header
37+ }
38+ pub fn hash ( & self ) -> & BlockHash {
39+ & self . hash
40+ }
41+ }
1642
1743#[ async_trait]
1844pub trait BlockHeaderStorage {
@@ -48,6 +74,8 @@ pub trait BlockHeaderStorage {
4874
4975 async fn get_tip_height ( & self ) -> Option < u32 > ;
5076
77+ async fn get_tip ( & self ) -> Option < BlockHeaderTip > ;
78+
5179 async fn get_start_height ( & self ) -> Option < u32 > ;
5280
5381 async fn get_stored_headers_len ( & self ) -> u32 ;
@@ -146,6 +174,14 @@ impl BlockHeaderStorage for PersistentBlockHeaderStorage {
146174 self . block_headers . read ( ) . await . tip_height ( )
147175 }
148176
177+ async fn get_tip ( & self ) -> Option < BlockHeaderTip > {
178+ let mut block_headers = self . block_headers . write ( ) . await ;
179+ let tip_height = block_headers. tip_height ( ) ?;
180+ let hashed_header =
181+ block_headers. get_items ( tip_height..tip_height + 1 ) . await . ok ( ) ?. into_iter ( ) . next ( ) ?;
182+ Some ( BlockHeaderTip :: new ( tip_height, hashed_header) )
183+ }
184+
149185 async fn get_start_height ( & self ) -> Option < u32 > {
150186 self . block_headers . read ( ) . await . start_height ( )
151187 }
@@ -175,3 +211,30 @@ impl BlockHeaderStorage for PersistentBlockHeaderStorage {
175211 Ok ( self . header_hash_index . get ( hash) . copied ( ) )
176212 }
177213}
214+
215+ #[ cfg( test) ]
216+ mod tests {
217+ use super :: * ;
218+ use tempfile:: TempDir ;
219+
220+ #[ tokio:: test]
221+ async fn test_get_tip ( ) {
222+ let headers = BlockHeader :: dummy_batch ( 0 ..5 ) ;
223+ let tmp_dir = TempDir :: new ( ) . unwrap ( ) ;
224+ let mut storage = PersistentBlockHeaderStorage :: open ( tmp_dir. path ( ) ) . await . unwrap ( ) ;
225+ // Tip should be none before storing headers
226+ assert ! ( storage. get_tip( ) . await . is_none( ) ) ;
227+ // Add one header and validate tip
228+ storage. store_headers ( & headers[ 0 ..1 ] ) . await . unwrap ( ) ;
229+ let tip = storage. get_tip ( ) . await . unwrap ( ) ;
230+ let expected_tip = BlockHeaderTip :: new ( 0 , HashedBlockHeader :: from ( headers[ 0 ] ) ) ;
231+ assert_eq ! ( tip, expected_tip) ;
232+ assert_eq ! ( storage. get_tip_height( ) . await , Some ( 0 ) ) ;
233+ // Add multiple headers and validate tip
234+ storage. store_headers ( & headers[ 1 ..] ) . await . unwrap ( ) ;
235+ let tip = storage. get_tip ( ) . await . unwrap ( ) ;
236+ let expected_tip = BlockHeaderTip :: new ( 4 , HashedBlockHeader :: from ( headers[ 4 ] ) ) ;
237+ assert_eq ! ( tip, expected_tip) ;
238+ assert_eq ! ( storage. get_tip_height( ) . await , Some ( 4 ) ) ;
239+ }
240+ }
0 commit comments