diff --git a/Cargo.lock b/Cargo.lock index f3a3f6a0..65c7ee5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1286,7 +1286,7 @@ checksum = "3bf679796c0322556351f287a51b49e48f7c4986e727b5dd78c972d30e2e16cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.90", ] [[package]] diff --git a/components/ordhook-cli/src/cli/mod.rs b/components/ordhook-cli/src/cli/mod.rs index a6fb2927..c557a234 100644 --- a/components/ordhook-cli/src/cli/mod.rs +++ b/components/ordhook-cli/src/cli/mod.rs @@ -19,7 +19,7 @@ use ordhook::db::blocks::{ open_blocks_db_with_retry, open_readonly_blocks_db, }; use ordhook::db::cursor::BlockBytesCursor; -use ordhook::db::migrate_dbs; +use ordhook::db::{migrate_dbs, reset_dbs}; use ordhook::service::Service; use ordhook::try_info; use std::collections::HashSet; @@ -43,9 +43,29 @@ enum Command { /// Stream Bitcoin blocks and index ordinals inscriptions and transfers #[clap(subcommand)] Service(ServiceCommand), - /// Perform maintenance operations on local databases + /// Perform maintenance operations on local index #[clap(subcommand)] - Db(OrdhookDbCommand), + Index(IndexCommand), + /// Database operations + #[clap(subcommand)] + Database(DatabaseCommand), +} + +#[derive(Subcommand, PartialEq, Clone, Debug)] +enum DatabaseCommand { + /// Migrates database + #[clap(name = "migrate", bin_name = "migrate")] + Migrate(DatabaseMigrateCommand), + /// Resets database to an empty state + #[clap(name = "reset", bin_name = "reset")] + Reset(DatabaseMigrateCommand), +} + +#[derive(Parser, PartialEq, Clone, Debug)] +struct DatabaseMigrateCommand { + /// Load config file path + #[clap(long = "config-path")] + pub config_path: Option, } #[derive(Subcommand, PartialEq, Clone, Debug)] @@ -184,7 +204,7 @@ struct StartCommand { } #[derive(Subcommand, PartialEq, Clone, Debug)] -enum OrdhookDbCommand { +enum IndexCommand { /// Initialize a new ordhook db #[clap(name = "new", bin_name = "new")] New(SyncOrdhookDbCommand), @@ -324,18 +344,18 @@ async fn handle_command(opts: Opts, ctx: &Context) -> Result<(), String> { println!("Created file Ordhook.toml"); } }, - Command::Db(OrdhookDbCommand::New(cmd)) => { + Command::Index(IndexCommand::New(cmd)) => { let config = ConfigFile::default(false, false, false, &cmd.config_path, &None)?; migrate_dbs(&config, ctx).await?; open_blocks_db_with_retry(true, &config, ctx); } - Command::Db(OrdhookDbCommand::Sync(cmd)) => { + Command::Index(IndexCommand::Sync(cmd)) => { let config = ConfigFile::default(false, false, false, &cmd.config_path, &None)?; migrate_dbs(&config, ctx).await?; let service = Service::new(&config, ctx); service.catch_up_to_bitcoin_chain_tip().await?; } - Command::Db(OrdhookDbCommand::Repair(subcmd)) => match subcmd { + Command::Index(IndexCommand::Repair(subcmd)) => match subcmd { RepairCommand::Blocks(cmd) => { let mut config = ConfigFile::default(false, false, false, &cmd.config_path, &None)?; if let Some(network_threads) = cmd.network_threads { @@ -369,7 +389,7 @@ async fn handle_command(opts: Opts, ctx: &Context) -> Result<(), String> { } } }, - Command::Db(OrdhookDbCommand::Check(cmd)) => { + Command::Index(IndexCommand::Check(cmd)) => { let config = ConfigFile::default(false, false, false, &cmd.config_path, &None)?; { let blocks_db = open_readonly_blocks_db(&config, ctx)?; @@ -379,7 +399,7 @@ async fn handle_command(opts: Opts, ctx: &Context) -> Result<(), String> { println!("{:?}", missing_blocks); } } - Command::Db(OrdhookDbCommand::Drop(cmd)) => { + Command::Index(IndexCommand::Drop(cmd)) => { let config = ConfigFile::default(false, false, false, &cmd.config_path, &None)?; let service = Service::new(&config, ctx); @@ -401,6 +421,22 @@ async fn handle_command(opts: Opts, ctx: &Context) -> Result<(), String> { service.rollback(&block_heights).await?; println!("{} blocks dropped", cmd.blocks); } + Command::Database(DatabaseCommand::Migrate(cmd)) => { + let config = ConfigFile::default(false, false, false, &cmd.config_path, &None)?; + migrate_dbs(&config, ctx).await?; + } + Command::Database(DatabaseCommand::Reset(cmd)) => { + let config = ConfigFile::default(false, false, false, &cmd.config_path, &None)?; + println!( + "WARNING: This operation will delete ALL index data and cannot be undone. Confirm? [Y/n]" + ); + let mut buffer = String::new(); + std::io::stdin().read_line(&mut buffer).unwrap(); + if buffer.to_lowercase().starts_with('n') { + return Err("Aborted".to_string()); + } + reset_dbs(&config, ctx).await?; + } } Ok(()) } diff --git a/components/ordhook-core/src/core/meta_protocols/brc20/brc20_pg.rs b/components/ordhook-core/src/core/meta_protocols/brc20/brc20_pg.rs index 713e5cab..3c0eaf1b 100644 --- a/components/ordhook-core/src/core/meta_protocols/brc20/brc20_pg.rs +++ b/components/ordhook-core/src/core/meta_protocols/brc20/brc20_pg.rs @@ -562,7 +562,7 @@ mod test { VerifiedBrc20BalanceData, VerifiedBrc20TokenDeployData, VerifiedBrc20TransferData, }, }, - db::{pg_test_clear_db, pg_test_connection, pg_test_connection_pool}, + db::{pg_reset_db, pg_test_connection, pg_test_connection_pool}, }; async fn get_counts_by_operation(client: &T) -> (i32, i32, i32, i32) { @@ -1000,7 +1000,7 @@ mod test { ); } } - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; Ok(()) } } diff --git a/components/ordhook-core/src/core/meta_protocols/brc20/cache.rs b/components/ordhook-core/src/core/meta_protocols/brc20/cache.rs index f7bc9f8c..b39949a4 100644 --- a/components/ordhook-core/src/core/meta_protocols/brc20/cache.rs +++ b/components/ordhook-core/src/core/meta_protocols/brc20/cache.rs @@ -487,7 +487,7 @@ mod test { VerifiedBrc20TokenDeployData, }, }, - db::{pg_test_clear_db, pg_test_connection, pg_test_connection_pool}, + db::{pg_reset_db, pg_test_connection, pg_test_connection_pool}, }; use super::Brc20MemoryCache; @@ -641,7 +641,7 @@ mod test { ))) ); } - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; Ok(()) } @@ -743,7 +743,7 @@ mod test { ) .await?) }; - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; result } } diff --git a/components/ordhook-core/src/core/meta_protocols/brc20/verifier.rs b/components/ordhook-core/src/core/meta_protocols/brc20/verifier.rs index 607f3bf5..404ca3ad 100644 --- a/components/ordhook-core/src/core/meta_protocols/brc20/verifier.rs +++ b/components/ordhook-core/src/core/meta_protocols/brc20/verifier.rs @@ -279,7 +279,7 @@ mod test { VerifiedBrc20BalanceData, VerifiedBrc20Operation, VerifiedBrc20TokenDeployData, }, }, - db::{pg_test_clear_db, pg_test_connection, pg_test_connection_pool}, + db::{pg_reset_db, pg_test_connection, pg_test_connection_pool}, }; use super::{verify_brc20_operation, verify_brc20_transfer, VerifiedBrc20TransferData}; @@ -421,7 +421,7 @@ mod test { ) .await }; - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; result } @@ -534,7 +534,7 @@ mod test { ) .await }; - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; result } @@ -621,7 +621,7 @@ mod test { ) .await }; - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; result } @@ -698,7 +698,7 @@ mod test { ) .await }; - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; result } @@ -778,7 +778,7 @@ mod test { ) .await }; - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; result } @@ -941,7 +941,7 @@ mod test { ) .await }; - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; result } @@ -1067,7 +1067,7 @@ mod test { ).await?; verify_brc20_transfer(&transfer, &mut cache, &client, &ctx).await }; - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; result } @@ -1175,7 +1175,7 @@ mod test { .await?; verify_brc20_transfer(&transfer, &mut cache, &client, &ctx).await }; - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; result } } diff --git a/components/ordhook-core/src/core/protocol/sequence_cursor.rs b/components/ordhook-core/src/core/protocol/sequence_cursor.rs index 4d92ab09..24d7b8fc 100644 --- a/components/ordhook-core/src/core/protocol/sequence_cursor.rs +++ b/components/ordhook-core/src/core/protocol/sequence_cursor.rs @@ -151,7 +151,7 @@ mod test { core::test_builders::{TestBlockBuilder, TestTransactionBuilder}, db::{ ordinals_pg::{self, insert_block}, - pg_test_clear_db, pg_test_connection, pg_test_connection_pool, + pg_reset_db, pg_test_connection, pg_test_connection_pool, }, }; @@ -200,7 +200,7 @@ mod test { (next.classic, next.jubilee) }; - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; Ok(result) } } diff --git a/components/ordhook-core/src/db/mod.rs b/components/ordhook-core/src/db/mod.rs index c61cbc58..def8ce4e 100644 --- a/components/ordhook-core/src/db/mod.rs +++ b/components/ordhook-core/src/db/mod.rs @@ -7,7 +7,7 @@ use chainhook_postgres::pg_connect_with_retry; use chainhook_sdk::utils::Context; -use crate::{config::Config, core::meta_protocols::brc20::brc20_pg, try_info}; +use crate::{config::Config, core::meta_protocols::brc20::brc20_pg, try_info, try_warn}; pub async fn migrate_dbs(config: &Config, ctx: &Context) -> Result<(), String> { { @@ -23,32 +23,24 @@ pub async fn migrate_dbs(config: &Config, ctx: &Context) -> Result<(), String> { Ok(()) } -#[cfg(test)] -pub fn pg_test_config() -> chainhook_postgres::PgConnectionConfig { - chainhook_postgres::PgConnectionConfig { - dbname: "postgres".to_string(), - host: "localhost".to_string(), - port: 5432, - user: "postgres".to_string(), - password: Some("postgres".to_string()), - search_path: None, - pool_max_size: None, +pub async fn reset_dbs(config: &Config, ctx: &Context) -> Result<(), String> { + { + try_warn!(ctx, "Resetting ordinals DB"); + let mut pg_client = pg_connect_with_retry(&config.ordinals_db).await; + pg_reset_db(&mut pg_client).await?; } + if let (Some(brc20_db), true) = (&config.brc20_db, config.meta_protocols.brc20) { + try_warn!(ctx, "Resetting brc20 DB"); + let mut pg_client = pg_connect_with_retry(&brc20_db).await; + pg_reset_db(&mut pg_client).await?; + } + Ok(()) } -#[cfg(test)] -pub fn pg_test_connection_pool() -> chainhook_postgres::deadpool_postgres::Pool { - chainhook_postgres::pg_pool(&pg_test_config()).unwrap() -} - -#[cfg(test)] -pub async fn pg_test_connection() -> chainhook_postgres::tokio_postgres::Client { - chainhook_postgres::pg_connect(&pg_test_config()).await.unwrap() -} - -#[cfg(test)] -pub async fn pg_test_clear_db(pg_client: &mut chainhook_postgres::tokio_postgres::Client) { - match pg_client +pub async fn pg_reset_db( + pg_client: &mut chainhook_postgres::tokio_postgres::Client, +) -> Result<(), String> { + pg_client .batch_execute( " DO $$ DECLARE @@ -66,16 +58,34 @@ pub async fn pg_test_clear_db(pg_client: &mut chainhook_postgres::tokio_postgres END LOOP; END $$;", ) - .await { - Ok(rows) => rows, - Err(e) => { - println!( - "error rolling back test migrations: {}", - e.to_string() - ); - std::process::exit(1); - } - }; + .await + .map_err(|e| format!("unable to reset db: {e}"))?; + Ok(()) +} + +#[cfg(test)] +pub fn pg_test_config() -> chainhook_postgres::PgConnectionConfig { + chainhook_postgres::PgConnectionConfig { + dbname: "postgres".to_string(), + host: "localhost".to_string(), + port: 5432, + user: "postgres".to_string(), + password: Some("postgres".to_string()), + search_path: None, + pool_max_size: None, + } +} + +#[cfg(test)] +pub fn pg_test_connection_pool() -> chainhook_postgres::deadpool_postgres::Pool { + chainhook_postgres::pg_pool(&pg_test_config()).unwrap() +} + +#[cfg(test)] +pub async fn pg_test_connection() -> chainhook_postgres::tokio_postgres::Client { + chainhook_postgres::pg_connect(&pg_test_config()) + .await + .unwrap() } /// Drops DB files in a test environment. diff --git a/components/ordhook-core/src/db/ordinals_pg.rs b/components/ordhook-core/src/db/ordinals_pg.rs index 2750a370..525edd52 100644 --- a/components/ordhook-core/src/db/ordinals_pg.rs +++ b/components/ordhook-core/src/db/ordinals_pg.rs @@ -990,7 +990,7 @@ mod test { self, get_chain_tip_block_height, get_inscriptions_at_block, insert_block, rollback_block, }, - pg_test_clear_db, pg_test_connection, pg_test_connection_pool, + pg_reset_db, pg_test_connection, pg_test_connection_pool, }, }; @@ -1401,7 +1401,7 @@ mod test { assert_eq!(Some(799999), get_chain_tip_block_height(&client).await?); } } - pg_test_clear_db(&mut pg_client).await; + pg_reset_db(&mut pg_client).await; Ok(()) } }