Skip to content

Commit deaa739

Browse files
author
Ludo Galabru
committed
feat: improve onboarding
1 parent fa802fa commit deaa739

File tree

6 files changed

+107
-150
lines changed

6 files changed

+107
-150
lines changed

components/hord-cli/src/cli/mod.rs

+25-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::db::{
1313
find_all_transfers_in_block, find_inscription_with_id, find_last_block_inserted,
1414
find_latest_inscription_block_height, find_lazy_block_at_block_height,
1515
open_readonly_hord_db_conn, open_readonly_hord_db_conn_rocks_db, open_readwrite_hord_db_conn,
16-
open_readwrite_hord_db_conn_rocks_db, initialize_hord_db,
16+
open_readwrite_hord_db_conn_rocks_db, initialize_hord_db, get_default_hord_db_file_path,
1717
};
1818
use chainhook_sdk::bitcoincore_rpc::{Auth, Client, RpcApi};
1919
use chainhook_sdk::chainhooks::types::HttpHook;
@@ -261,6 +261,9 @@ struct StartCommand {
261261

262262
#[derive(Subcommand, PartialEq, Clone, Debug)]
263263
enum HordDbCommand {
264+
/// Initialize a new hord db
265+
#[clap(name = "new", bin_name = "new")]
266+
New(SyncHordDbCommand),
264267
/// Catch-up hord db
265268
#[clap(name = "sync", bin_name = "sync")]
266269
Sync(SyncHordDbCommand),
@@ -476,21 +479,25 @@ async fn handle_command(opts: Opts, ctx: &Context) -> Result<(), String> {
476479
.await?;
477480
} else {
478481
let _ = download_ordinals_dataset_if_required(&config, ctx).await;
482+
let mut total_inscriptions = 0;
483+
let mut total_transfers = 0;
479484

480485
let inscriptions_db_conn =
481-
open_readonly_hord_db_conn(&config.expected_cache_path(), &ctx)?;
486+
initialize_hord_db(&config.expected_cache_path(), &ctx);
482487
while let Some(block_height) = block_range.pop_front() {
483-
let mut total_transfers = 0;
484488
let inscriptions =
485489
find_all_inscriptions_in_block(&block_height, &inscriptions_db_conn, &ctx);
486490
let mut locations =
487491
find_all_transfers_in_block(&block_height, &inscriptions_db_conn, &ctx);
492+
493+
let mut total_transfers_in_block = 0;
494+
488495
for (_, inscription) in inscriptions.iter() {
489496
println!("Inscription {} revealed at block #{} (inscription_number {}, ordinal_number {})", inscription.get_inscription_id(), block_height, inscription.inscription_number, inscription.ordinal_number);
490497
if let Some(transfers) = locations.remove(&inscription.get_inscription_id())
491498
{
492499
for t in transfers.iter().skip(1) {
493-
total_transfers += 1;
500+
total_transfers_in_block += 1;
494501
println!(
495502
"\t→ Transferred in transaction {}",
496503
t.transaction_identifier_location.hash
@@ -501,21 +508,28 @@ async fn handle_command(opts: Opts, ctx: &Context) -> Result<(), String> {
501508
for (inscription_id, transfers) in locations.iter() {
502509
println!("Inscription {}", inscription_id);
503510
for t in transfers.iter() {
504-
total_transfers += 1;
511+
total_transfers_in_block += 1;
505512
println!(
506513
"\t→ Transferred in transaction {}",
507514
t.transaction_identifier_location.hash
508515
);
509516
}
510517
}
511-
if total_transfers > 0 && inscriptions.len() > 0 {
518+
if total_transfers_in_block > 0 && inscriptions.len() > 0 {
512519
println!(
513-
"Inscriptions revealed: {}, inscriptions transferred: {total_transfers}",
520+
"Inscriptions revealed: {}, inscriptions transferred: {total_transfers_in_block}",
514521
inscriptions.len()
515522
);
516523
println!("-----");
517524
}
525+
526+
total_inscriptions += inscriptions.len();
527+
total_transfers += total_transfers_in_block;
518528
}
529+
if total_transfers == 0 && total_inscriptions == 0 {
530+
let db_file_path = get_default_hord_db_file_path(&config.expected_cache_path());
531+
warn!(ctx.expect_logger(), "No data available. Check the validity of the range being scanned and the validity of your local database {}", db_file_path.display());
532+
}
519533
}
520534
}
521535
Command::Scan(ScanCommand::Inscription(cmd)) => {
@@ -620,6 +634,10 @@ async fn handle_command(opts: Opts, ctx: &Context) -> Result<(), String> {
620634
println!("Created file Hord.toml");
621635
}
622636
},
637+
Command::Db(HordDbCommand::New(cmd)) => {
638+
let config = Config::default(false, false, false, &cmd.config_path)?;
639+
initialize_hord_db(&config.expected_cache_path(), &ctx);
640+
},
623641
Command::Db(HordDbCommand::Sync(_cmd)) => unimplemented!(),
624642
Command::Db(HordDbCommand::Repair(subcmd)) => match subcmd {
625643
RepairCommand::Blocks(cmd) => {

components/hord-cli/src/config/file.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
pub struct ConfigFile {
33
pub storage: StorageConfigFile,
44
pub http_api: Option<PredicatesApiConfigFile>,
5-
pub event_source: Option<Vec<EventSourceConfigFile>>,
65
pub limits: LimitsConfigFile,
76
pub network: NetworkConfigFile,
87
pub logs: Option<LogConfigFile>,
8+
pub bootstrap: Option<BootstrapConfigFile>,
99
}
1010

1111
#[derive(Deserialize, Debug, Clone)]
@@ -28,13 +28,8 @@ pub struct PredicatesApiConfigFile {
2828
}
2929

3030
#[derive(Deserialize, Debug, Clone)]
31-
pub struct EventSourceConfigFile {
32-
pub source_type: Option<String>,
33-
pub stacks_node_url: Option<String>,
34-
pub chainhook_node_url: Option<String>,
35-
pub polling_delay: Option<u32>,
36-
pub tsv_file_path: Option<String>,
37-
pub tsv_file_url: Option<String>,
31+
pub struct BootstrapConfigFile {
32+
pub download_url: Option<String>,
3833
}
3934

4035
#[derive(Deserialize, Debug, Clone)]

components/hord-cli/src/config/generator.rs

+5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ max_number_of_processing_threads = 16
3434
bitcoin_concurrent_http_requests_max = 16
3535
max_caching_memory_size_mb = 32000
3636
37+
# Disable the following section if the state
38+
# must be built locally
39+
[bootstrap]
40+
download_url = "https://archive.hiro.so/mainnet/chainhooks/hord.sqlite"
41+
3742
[logs]
3843
ordinals_internals = true
3944
chainhook_internals = true

components/hord-cli/src/config/mod.rs

+22-74
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ pub const BITCOIN_MAX_PREDICATE_REGISTRATION: usize = 50;
2727
pub struct Config {
2828
pub storage: StorageConfig,
2929
pub http_api: PredicatesApi,
30-
pub event_sources: Vec<EventSourceConfig>,
3130
pub limits: LimitsConfig,
3231
pub network: IndexerConfig,
32+
pub bootstrap: BootstrapConfig,
3333
pub logs: LogConfig,
3434
}
3535

@@ -58,9 +58,9 @@ pub struct PredicatesApiConfig {
5858
}
5959

6060
#[derive(Clone, Debug)]
61-
pub enum EventSourceConfig {
62-
OrdinalsSqlitePath(PathConfig),
63-
OrdinalsSqliteUrl(UrlConfig),
61+
pub enum BootstrapConfig {
62+
Build,
63+
Download(String),
6464
}
6565

6666
#[derive(Clone, Debug)]
@@ -152,21 +152,13 @@ impl Config {
152152
_ => return Err("network.mode not supported".to_string()),
153153
};
154154

155-
let mut event_sources = vec![];
156-
for source in config_file.event_source.unwrap_or(vec![]).iter_mut() {
157-
if let Some(dst) = source.tsv_file_path.take() {
158-
let mut file_path = PathBuf::new();
159-
file_path.push(dst);
160-
event_sources.push(EventSourceConfig::OrdinalsSqlitePath(PathConfig {
161-
file_path,
162-
}));
163-
continue;
155+
let bootstrap = match config_file.bootstrap {
156+
Some(bootstrap) => match bootstrap.download_url {
157+
Some(ref url) => BootstrapConfig::Download(url.to_string()),
158+
None => BootstrapConfig::Build
164159
}
165-
if let Some(file_url) = source.tsv_file_url.take() {
166-
event_sources.push(EventSourceConfig::OrdinalsSqliteUrl(UrlConfig { file_url }));
167-
continue;
168-
}
169-
}
160+
None => BootstrapConfig::Build
161+
};
170162

171163
let config = Config {
172164
storage: StorageConfig {
@@ -185,7 +177,7 @@ impl Config {
185177
}),
186178
},
187179
},
188-
event_sources,
180+
bootstrap,
189181
limits: LimitsConfig {
190182
max_number_of_stacks_predicates: config_file
191183
.limits
@@ -248,28 +240,11 @@ impl Config {
248240
Ok(config)
249241
}
250242

251-
pub fn is_initial_ingestion_required(&self) -> bool {
252-
for source in self.event_sources.iter() {
253-
match source {
254-
EventSourceConfig::OrdinalsSqlitePath(_)
255-
| EventSourceConfig::OrdinalsSqliteUrl(_) => return true,
256-
}
243+
pub fn should_bootstrap_through_download(&self) -> bool {
244+
match &self.bootstrap {
245+
BootstrapConfig::Build => false,
246+
BootstrapConfig::Download(_) => true
257247
}
258-
return false;
259-
}
260-
261-
pub fn add_ordinals_sqlite_remote_source_url(&mut self, file_url: &str) {
262-
self.event_sources
263-
.push(EventSourceConfig::OrdinalsSqliteUrl(UrlConfig {
264-
file_url: file_url.to_string(),
265-
}));
266-
}
267-
268-
pub fn add_local_ordinals_sqlite_source(&mut self, file_path: &PathBuf) {
269-
self.event_sources
270-
.push(EventSourceConfig::OrdinalsSqlitePath(PathConfig {
271-
file_path: file_path.clone(),
272-
}));
273248
}
274249

275250
pub fn expected_api_database_uri(&self) -> &str {
@@ -289,13 +264,11 @@ impl Config {
289264
destination_path
290265
}
291266

292-
fn expected_remote_ordinals_sqlite_base_url(&self) -> &String {
293-
for source in self.event_sources.iter() {
294-
if let EventSourceConfig::OrdinalsSqliteUrl(config) = source {
295-
return &config.file_url;
296-
}
267+
fn expected_remote_ordinals_sqlite_base_url(&self) -> &str {
268+
match &self.bootstrap {
269+
BootstrapConfig::Build => unreachable!(),
270+
BootstrapConfig::Download(url) => &url
297271
}
298-
panic!("expected remote-tsv source")
299272
}
300273

301274
pub fn expected_remote_ordinals_sqlite_sha256(&self) -> String {
@@ -306,29 +279,6 @@ impl Config {
306279
format!("{}.gz", self.expected_remote_ordinals_sqlite_base_url())
307280
}
308281

309-
pub fn rely_on_remote_ordinals_sqlite(&self) -> bool {
310-
for source in self.event_sources.iter() {
311-
if let EventSourceConfig::OrdinalsSqliteUrl(_config) = source {
312-
return true;
313-
}
314-
}
315-
false
316-
}
317-
318-
pub fn should_download_remote_ordinals_sqlite(&self) -> bool {
319-
let mut rely_on_remote_tsv = false;
320-
let mut remote_tsv_present_locally = false;
321-
for source in self.event_sources.iter() {
322-
if let EventSourceConfig::OrdinalsSqliteUrl(_config) = source {
323-
rely_on_remote_tsv = true;
324-
}
325-
if let EventSourceConfig::OrdinalsSqlitePath(_config) = source {
326-
remote_tsv_present_locally = true;
327-
}
328-
}
329-
rely_on_remote_tsv == true && remote_tsv_present_locally == false
330-
}
331-
332282
pub fn default(
333283
devnet: bool,
334284
testnet: bool,
@@ -351,7 +301,7 @@ impl Config {
351301
working_dir: default_cache_path(),
352302
},
353303
http_api: PredicatesApi::Off,
354-
event_sources: vec![],
304+
bootstrap: BootstrapConfig::Build,
355305
limits: LimitsConfig {
356306
max_number_of_bitcoin_predicates: BITCOIN_MAX_PREDICATE_REGISTRATION,
357307
max_number_of_concurrent_bitcoin_scans: BITCOIN_SCAN_THREAD_POOL_SIZE,
@@ -384,7 +334,7 @@ impl Config {
384334
working_dir: default_cache_path(),
385335
},
386336
http_api: PredicatesApi::Off,
387-
event_sources: vec![],
337+
bootstrap: BootstrapConfig::Build,
388338
limits: LimitsConfig {
389339
max_number_of_bitcoin_predicates: BITCOIN_MAX_PREDICATE_REGISTRATION,
390340
max_number_of_concurrent_bitcoin_scans: BITCOIN_SCAN_THREAD_POOL_SIZE,
@@ -417,9 +367,7 @@ impl Config {
417367
working_dir: default_cache_path(),
418368
},
419369
http_api: PredicatesApi::Off,
420-
event_sources: vec![EventSourceConfig::OrdinalsSqliteUrl(UrlConfig {
421-
file_url: DEFAULT_MAINNET_ORDINALS_SQLITE_ARCHIVE.into(),
422-
})],
370+
bootstrap: BootstrapConfig::Download(DEFAULT_MAINNET_ORDINALS_SQLITE_ARCHIVE.to_string()),
423371
limits: LimitsConfig {
424372
max_number_of_bitcoin_predicates: BITCOIN_MAX_PREDICATE_REGISTRATION,
425373
max_number_of_concurrent_bitcoin_scans: BITCOIN_SCAN_THREAD_POOL_SIZE,

components/hord-cli/src/db/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::{
2323
core::protocol::inscription_parsing::get_inscriptions_revealed_in_block, ord::sat::Sat,
2424
};
2525

26-
fn get_default_hord_db_file_path(base_dir: &PathBuf) -> PathBuf {
26+
pub fn get_default_hord_db_file_path(base_dir: &PathBuf) -> PathBuf {
2727
let mut destination_path = base_dir.clone();
2828
destination_path.push("hord.sqlite");
2929
destination_path
@@ -124,7 +124,7 @@ pub fn initialize_hord_db(path: &PathBuf, ctx: &Context) -> Connection {
124124
conn
125125
}
126126

127-
fn create_or_open_readwrite_db(cache_path: &PathBuf, ctx: &Context) -> Connection {
127+
pub fn create_or_open_readwrite_db(cache_path: &PathBuf, ctx: &Context) -> Connection {
128128
let path = get_default_hord_db_file_path(&cache_path);
129129
let open_flags = match std::fs::metadata(&path) {
130130
Err(e) => {

0 commit comments

Comments
 (0)