@@ -6,7 +6,8 @@ use crate::scan::bitcoin::scan_bitcoin_chainstate_via_rpc_using_predicate;
6
6
use crate :: scan:: stacks:: scan_stacks_chainstate_via_csv_using_predicate;
7
7
use crate :: service:: Service ;
8
8
use crate :: storage:: {
9
- get_last_block_height_inserted, is_stacks_block_present, open_readonly_stacks_db_conn,
9
+ get_last_block_height_inserted, get_stacks_block_at_block_height, is_stacks_block_present,
10
+ open_readonly_stacks_db_conn,
10
11
} ;
11
12
12
13
use chainhook_sdk:: bitcoincore_rpc:: { Auth , Client , RpcApi } ;
@@ -242,6 +243,9 @@ enum StacksDbCommand {
242
243
/// Update database using latest Stacks archive file
243
244
#[ clap( name = "update" , bin_name = "update" ) ]
244
245
Update ( UpdateDbCommand ) ,
246
+ /// Retrieve a block from the Stacks db
247
+ #[ clap( name = "get" , bin_name = "get" ) ]
248
+ GetBlock ( GetBlockDbCommand ) ,
245
249
}
246
250
247
251
#[ derive( Subcommand , PartialEq , Clone , Debug ) ]
@@ -385,6 +389,16 @@ struct UpdateDbCommand {
385
389
pub config_path : Option < String > ,
386
390
}
387
391
392
+ #[ derive( Parser , PartialEq , Clone , Debug ) ]
393
+ struct GetBlockDbCommand {
394
+ /// Block index to retrieve
395
+ #[ clap( long = "block-height" ) ]
396
+ pub block_height : u64 ,
397
+ /// Load config file path
398
+ #[ clap( long = "config-path" ) ]
399
+ pub config_path : Option < String > ,
400
+ }
401
+
388
402
#[ derive( Parser , PartialEq , Clone , Debug ) ]
389
403
struct InitHordDbCommand {
390
404
/// Load config file path
@@ -880,46 +894,68 @@ async fn handle_command(opts: Opts, ctx: Context) -> Result<(), String> {
880
894
unimplemented ! ( )
881
895
}
882
896
} ,
883
- Command :: Stacks ( StacksCommand :: Db ( StacksDbCommand :: Update ( cmd) ) ) => {
884
- let mut config = Config :: default ( false , false , false , & cmd. config_path ) ?;
885
- download_stacks_dataset_if_required ( & mut config, & ctx) . await ;
886
- }
887
- Command :: Stacks ( StacksCommand :: Db ( StacksDbCommand :: Check ( cmd) ) ) => {
888
- let config = Config :: default ( false , false , false , & cmd. config_path ) ?;
889
- // Delete data, if any
890
- {
891
- let stacks_db = open_readonly_stacks_db_conn ( & config. expected_cache_path ( ) , & ctx) ?;
892
- let mut missing_blocks = vec ! [ ] ;
893
- let mut min = 0 ;
894
- let mut max = 0 ;
895
- if let Some ( tip) = get_last_block_height_inserted ( & stacks_db, & ctx) {
896
- min = 1 ;
897
- max = tip;
898
- for index in 1 ..=tip {
899
- let block_identifier = BlockIdentifier {
900
- index,
901
- hash : "" . into ( ) ,
902
- } ;
903
- if !is_stacks_block_present ( & block_identifier, 3 , & stacks_db) {
904
- missing_blocks. push ( index) ;
905
- }
897
+ Command :: Stacks ( subcmd) => match subcmd {
898
+ StacksCommand :: Db ( StacksDbCommand :: GetBlock ( cmd) ) => {
899
+ let mut config = Config :: default ( false , false , false , & cmd. config_path ) ?;
900
+ let stacks_db = open_readonly_stacks_db_conn ( & config. expected_cache_path ( ) , & ctx)
901
+ . expect ( "unable to read stacks_db" ) ;
902
+ match get_stacks_block_at_block_height ( cmd. block_height , true , 10 , & stacks_db) {
903
+ Ok ( Some ( block) ) => {
904
+ info ! ( ctx. expect_logger( ) , "{}" , json!( block) ) ;
905
+ }
906
+ Ok ( None ) => {
907
+ warn ! (
908
+ ctx. expect_logger( ) ,
909
+ "Block {} not present in database" , cmd. block_height
910
+ ) ;
911
+ }
912
+ Err ( e) => {
913
+ error ! ( ctx. expect_logger( ) , "{e}" , ) ;
906
914
}
907
915
}
908
- if missing_blocks. is_empty ( ) {
909
- info ! (
910
- ctx. expect_logger( ) ,
911
- "Stacks db successfully checked ({min}, {max})"
912
- ) ;
913
- } else {
914
- warn ! (
915
- ctx. expect_logger( ) ,
916
- "Stacks db includes {} missing entries ({min}, {max}): {:?}" ,
917
- missing_blocks. len( ) ,
918
- missing_blocks
919
- ) ;
916
+ }
917
+ StacksCommand :: Db ( StacksDbCommand :: Update ( cmd) ) => {
918
+ let mut config = Config :: default ( false , false , false , & cmd. config_path ) ?;
919
+ download_stacks_dataset_if_required ( & mut config, & ctx) . await ;
920
+ }
921
+ StacksCommand :: Db ( StacksDbCommand :: Check ( cmd) ) => {
922
+ let config = Config :: default ( false , false , false , & cmd. config_path ) ?;
923
+ // Delete data, if any
924
+ {
925
+ let stacks_db =
926
+ open_readonly_stacks_db_conn ( & config. expected_cache_path ( ) , & ctx) ?;
927
+ let mut missing_blocks = vec ! [ ] ;
928
+ let mut min = 0 ;
929
+ let mut max = 0 ;
930
+ if let Some ( tip) = get_last_block_height_inserted ( & stacks_db, & ctx) {
931
+ min = 1 ;
932
+ max = tip;
933
+ for index in 1 ..=tip {
934
+ let block_identifier = BlockIdentifier {
935
+ index,
936
+ hash : "" . into ( ) ,
937
+ } ;
938
+ if !is_stacks_block_present ( & block_identifier, 3 , & stacks_db) {
939
+ missing_blocks. push ( index) ;
940
+ }
941
+ }
942
+ }
943
+ if missing_blocks. is_empty ( ) {
944
+ info ! (
945
+ ctx. expect_logger( ) ,
946
+ "Stacks db successfully checked ({min}, {max})"
947
+ ) ;
948
+ } else {
949
+ warn ! (
950
+ ctx. expect_logger( ) ,
951
+ "Stacks db includes {} missing entries ({min}, {max}): {:?}" ,
952
+ missing_blocks. len( ) ,
953
+ missing_blocks
954
+ ) ;
955
+ }
920
956
}
921
957
}
922
- }
958
+ } ,
923
959
}
924
960
Ok ( ( ) )
925
961
}
0 commit comments