mirror of
https://github.com/alexgo-io/bitcoin-indexer.git
synced 2026-04-30 04:35:04 +08:00
feat: add command to check stacks db integrity
This commit is contained in:
@@ -4,6 +4,9 @@ use crate::config::{Config, PredicatesApi};
|
|||||||
use crate::scan::bitcoin::scan_bitcoin_chainstate_via_rpc_using_predicate;
|
use crate::scan::bitcoin::scan_bitcoin_chainstate_via_rpc_using_predicate;
|
||||||
use crate::scan::stacks::scan_stacks_chainstate_via_csv_using_predicate;
|
use crate::scan::stacks::scan_stacks_chainstate_via_csv_using_predicate;
|
||||||
use crate::service::Service;
|
use crate::service::Service;
|
||||||
|
use crate::storage::{
|
||||||
|
get_last_block_height_inserted, is_stacks_block_present, open_readonly_stacks_db_conn,
|
||||||
|
};
|
||||||
|
|
||||||
use chainhook_sdk::bitcoincore_rpc::{Auth, Client, RpcApi};
|
use chainhook_sdk::bitcoincore_rpc::{Auth, Client, RpcApi};
|
||||||
use chainhook_sdk::chainhooks::types::{
|
use chainhook_sdk::chainhooks::types::{
|
||||||
@@ -59,9 +62,12 @@ enum Command {
|
|||||||
/// Run a service streaming blocks and evaluating registered predicates
|
/// Run a service streaming blocks and evaluating registered predicates
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
Service(ServiceCommand),
|
Service(ServiceCommand),
|
||||||
/// Explore the Ordinal Theory
|
/// Ordinals related subcommands
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
Hord(HordCommand),
|
Hord(HordCommand),
|
||||||
|
/// Stacks related subcommands
|
||||||
|
#[clap(subcommand)]
|
||||||
|
Stacks(StacksCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand, PartialEq, Clone, Debug)]
|
#[derive(Subcommand, PartialEq, Clone, Debug)]
|
||||||
@@ -192,14 +198,14 @@ struct StartCommand {
|
|||||||
enum HordCommand {
|
enum HordCommand {
|
||||||
/// Db maintenance related commands
|
/// Db maintenance related commands
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
Db(DbCommand),
|
Db(HordDbCommand),
|
||||||
/// Db maintenance related commands
|
/// Db maintenance related commands
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
Scan(ScanCommand),
|
Scan(ScanCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand, PartialEq, Clone, Debug)]
|
#[derive(Subcommand, PartialEq, Clone, Debug)]
|
||||||
enum DbCommand {
|
enum HordDbCommand {
|
||||||
/// Rewrite hord db
|
/// Rewrite hord db
|
||||||
#[clap(name = "rewrite", bin_name = "rewrite")]
|
#[clap(name = "rewrite", bin_name = "rewrite")]
|
||||||
Rewrite(UpdateHordDbCommand),
|
Rewrite(UpdateHordDbCommand),
|
||||||
@@ -211,7 +217,7 @@ enum DbCommand {
|
|||||||
Drop(DropHordDbCommand),
|
Drop(DropHordDbCommand),
|
||||||
/// Check integrity
|
/// Check integrity
|
||||||
#[clap(name = "check", bin_name = "check")]
|
#[clap(name = "check", bin_name = "check")]
|
||||||
Check(CheckHordDbCommand),
|
Check(CheckDbCommand),
|
||||||
/// Patch DB
|
/// Patch DB
|
||||||
#[clap(name = "patch", bin_name = "patch")]
|
#[clap(name = "patch", bin_name = "patch")]
|
||||||
Patch(PatchHordDbCommand),
|
Patch(PatchHordDbCommand),
|
||||||
@@ -220,6 +226,20 @@ enum DbCommand {
|
|||||||
Migrate(MigrateHordDbCommand),
|
Migrate(MigrateHordDbCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand, PartialEq, Clone, Debug)]
|
||||||
|
enum StacksCommand {
|
||||||
|
/// Db maintenance related commands
|
||||||
|
#[clap(subcommand)]
|
||||||
|
Db(StacksDbCommand),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand, PartialEq, Clone, Debug)]
|
||||||
|
enum StacksDbCommand {
|
||||||
|
/// Check integrity
|
||||||
|
#[clap(name = "check", bin_name = "check")]
|
||||||
|
Check(CheckDbCommand),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Subcommand, PartialEq, Clone, Debug)]
|
#[derive(Subcommand, PartialEq, Clone, Debug)]
|
||||||
enum ScanCommand {
|
enum ScanCommand {
|
||||||
/// Compute ordinal number of the 1st satoshi of the 1st input of a given transaction
|
/// Compute ordinal number of the 1st satoshi of the 1st input of a given transaction
|
||||||
@@ -348,7 +368,7 @@ struct MigrateHordDbCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser, PartialEq, Clone, Debug)]
|
#[derive(Parser, PartialEq, Clone, Debug)]
|
||||||
struct CheckHordDbCommand {
|
struct CheckDbCommand {
|
||||||
/// Load config file path
|
/// Load config file path
|
||||||
#[clap(long = "config-path")]
|
#[clap(long = "config-path")]
|
||||||
pub config_path: Option<String>,
|
pub config_path: Option<String>,
|
||||||
@@ -752,7 +772,7 @@ async fn handle_command(opts: Opts, ctx: Context) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Command::Hord(HordCommand::Db(subcmd)) => match subcmd {
|
Command::Hord(HordCommand::Db(subcmd)) => match subcmd {
|
||||||
DbCommand::Sync(cmd) => {
|
HordDbCommand::Sync(cmd) => {
|
||||||
let config = Config::default(false, false, false, &cmd.config_path)?;
|
let config = Config::default(false, false, false, &cmd.config_path)?;
|
||||||
if let Some((start_block, end_block)) = should_sync_hord_db(&config, &ctx)? {
|
if let Some((start_block, end_block)) = should_sync_hord_db(&config, &ctx)? {
|
||||||
if start_block == 0 {
|
if start_block == 0 {
|
||||||
@@ -778,7 +798,7 @@ async fn handle_command(opts: Opts, ctx: Context) -> Result<(), String> {
|
|||||||
info!(ctx.expect_logger(), "Database hord up to date");
|
info!(ctx.expect_logger(), "Database hord up to date");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DbCommand::Rewrite(cmd) => {
|
HordDbCommand::Rewrite(cmd) => {
|
||||||
let config = Config::default(false, false, false, &cmd.config_path)?;
|
let config = Config::default(false, false, false, &cmd.config_path)?;
|
||||||
// Delete data, if any
|
// Delete data, if any
|
||||||
{
|
{
|
||||||
@@ -805,7 +825,7 @@ async fn handle_command(opts: Opts, ctx: Context) -> Result<(), String> {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
DbCommand::Check(cmd) => {
|
HordDbCommand::Check(cmd) => {
|
||||||
let config = Config::default(false, false, false, &cmd.config_path)?;
|
let config = Config::default(false, false, false, &cmd.config_path)?;
|
||||||
// Delete data, if any
|
// Delete data, if any
|
||||||
{
|
{
|
||||||
@@ -813,7 +833,7 @@ async fn handle_command(opts: Opts, ctx: Context) -> Result<(), String> {
|
|||||||
open_readwrite_hord_db_conn_rocks_db(&config.expected_cache_path(), &ctx)?;
|
open_readwrite_hord_db_conn_rocks_db(&config.expected_cache_path(), &ctx)?;
|
||||||
|
|
||||||
let mut missing_blocks = vec![];
|
let mut missing_blocks = vec![];
|
||||||
for i in 1..=780000 {
|
for i in 1..=790000 {
|
||||||
if find_lazy_block_at_block_height(i, 3, &blocks_db_rw).is_none() {
|
if find_lazy_block_at_block_height(i, 3, &blocks_db_rw).is_none() {
|
||||||
println!("Missing block {i}");
|
println!("Missing block {i}");
|
||||||
missing_blocks.push(i);
|
missing_blocks.push(i);
|
||||||
@@ -822,7 +842,7 @@ async fn handle_command(opts: Opts, ctx: Context) -> Result<(), String> {
|
|||||||
println!("{:?}", missing_blocks);
|
println!("{:?}", missing_blocks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DbCommand::Drop(cmd) => {
|
HordDbCommand::Drop(cmd) => {
|
||||||
let config = Config::default(false, false, false, &cmd.config_path)?;
|
let config = Config::default(false, false, false, &cmd.config_path)?;
|
||||||
let blocks_db =
|
let blocks_db =
|
||||||
open_readwrite_hord_db_conn_rocks_db(&config.expected_cache_path(), &ctx)?;
|
open_readwrite_hord_db_conn_rocks_db(&config.expected_cache_path(), &ctx)?;
|
||||||
@@ -842,13 +862,42 @@ async fn handle_command(opts: Opts, ctx: Context) -> Result<(), String> {
|
|||||||
cmd.end_block - cmd.start_block + 1
|
cmd.end_block - cmd.start_block + 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
DbCommand::Patch(_cmd) => {
|
HordDbCommand::Patch(_cmd) => {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
DbCommand::Migrate(_cmd) => {
|
HordDbCommand::Migrate(_cmd) => {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Command::Stacks(StacksCommand::Db(StacksDbCommand::Check(cmd))) => {
|
||||||
|
let config = Config::default(false, false, false, &cmd.config_path)?;
|
||||||
|
// Delete data, if any
|
||||||
|
{
|
||||||
|
let stacks_db = open_readonly_stacks_db_conn(&config.expected_cache_path(), &ctx)?;
|
||||||
|
let mut missing_blocks = vec![];
|
||||||
|
if let Some(tip) = get_last_block_height_inserted(&stacks_db, &ctx) {
|
||||||
|
for index in 1..=tip {
|
||||||
|
let block_identifier = BlockIdentifier {
|
||||||
|
index: i,
|
||||||
|
hash: "".into(),
|
||||||
|
};
|
||||||
|
if !is_stacks_block_present(&block_identifier, 3, &stacks_db) {
|
||||||
|
missing_blocks.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if missing_blocks.is_empty() {
|
||||||
|
info!(ctx.expect_logger(), "Stacks db successfully checked");
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
ctx.expect_logger(),
|
||||||
|
"Stacks db includes {} missing entries: {:?}",
|
||||||
|
missing_blocks.len(),
|
||||||
|
missing_blocks
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user