Skip to content

Commit df36617

Browse files
author
Ludo Galabru
committed
feat: plug inscription processing in ibd
1 parent 9fab5a3 commit df36617

File tree

7 files changed

+135
-35
lines changed

7 files changed

+135
-35
lines changed

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

+5-3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use crate::scan::stacks::scan_stacks_chain_with_predicate;
77

88
use chainhook_event_observer::chainhooks::types::ChainhookFullSpecification;
99
use chainhook_event_observer::hord::db::{
10-
build_bitcoin_traversal_local_storage, find_inscriptions_at_wached_outpoint,
11-
initialize_hord_db, open_readonly_hord_db_conn, retrieve_satoshi_point_using_local_storage,
10+
fetch_and_cache_blocks_in_hord_db, find_inscriptions_at_wached_outpoint, initialize_hord_db,
11+
open_readonly_hord_db_conn, retrieve_satoshi_point_using_local_storage,
1212
};
1313
use chainhook_event_observer::observer::BitcoinConfig;
1414
use chainhook_event_observer::utils::Context;
@@ -381,17 +381,19 @@ async fn handle_command(opts: Opts, ctx: Context) -> Result<(), String> {
381381
username: config.network.bitcoin_node_rpc_username.clone(),
382382
password: config.network.bitcoin_node_rpc_password.clone(),
383383
rpc_url: config.network.bitcoin_node_rpc_url.clone(),
384+
network: config.network.bitcoin_network.clone(),
384385
};
385386

386387
let hord_db_conn = initialize_hord_db(&config.expected_cache_path(), &ctx);
387388

388-
let _ = build_bitcoin_traversal_local_storage(
389+
let _ = fetch_and_cache_blocks_in_hord_db(
389390
&bitcoin_config,
390391
&hord_db_conn,
391392
cmd.start_block,
392393
cmd.end_block,
393394
&ctx,
394395
cmd.network_threads,
396+
None,
395397
)
396398
.await;
397399
}

components/chainhook-cli/src/node/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -465,8 +465,8 @@ impl Node {
465465
.map_err(|e| format!("unable to parse response ({})", e))?;
466466

467467
let block = indexer::bitcoin::standardize_bitcoin_block(
468-
&event_observer_config,
469468
raw_block,
469+
&event_observer_config.bitcoin_network,
470470
&self.ctx,
471471
)?;
472472

components/chainhook-cli/src/scan/bitcoin.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ use chainhook_event_observer::chainhooks::types::{
99
BitcoinChainhookFullSpecification, BitcoinPredicateType, Protocols,
1010
};
1111
use chainhook_event_observer::hord::db::{
12-
build_bitcoin_traversal_local_storage, find_all_inscriptions,
13-
find_compacted_block_at_block_height, find_latest_compacted_block_known,
14-
open_readonly_hord_db_conn, open_readwrite_hord_db_conn,
12+
fetch_and_cache_blocks_in_hord_db, find_all_inscriptions, find_compacted_block_at_block_height,
13+
find_latest_compacted_block_known, open_readonly_hord_db_conn, open_readwrite_hord_db_conn,
1514
};
1615
use chainhook_event_observer::indexer;
1716
use chainhook_event_observer::indexer::bitcoin::{
@@ -115,13 +114,14 @@ pub async fn scan_bitcoin_chain_with_predicate(
115114
"Database hord.sqlite appears to be outdated regarding the window of blocks provided. Syncing {} missing blocks",
116115
(end_block - start_block)
117116
);
118-
build_bitcoin_traversal_local_storage(
117+
fetch_and_cache_blocks_in_hord_db(
119118
&config.get_event_observer_config().get_bitcoin_config(),
120119
&rw_hord_db_conn,
121120
start_block,
122121
end_block,
123122
&ctx,
124123
8,
124+
None,
125125
)
126126
.await?;
127127
}
@@ -163,8 +163,8 @@ pub async fn scan_bitcoin_chain_with_predicate(
163163
let block_breakdown =
164164
retrieve_full_block_breakdown_with_retry(&block_hash, &bitcoin_config, ctx).await?;
165165
let block = indexer::bitcoin::standardize_bitcoin_block(
166-
&event_observer_config,
167166
block_breakdown,
167+
&event_observer_config.bitcoin_network,
168168
ctx,
169169
)?;
170170

components/chainhook-event-observer/src/hord/db/mod.rs

+99-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use std::path::PathBuf;
1+
use std::{
2+
collections::HashMap,
3+
path::PathBuf,
4+
sync::mpsc::{channel, Sender},
5+
};
26

37
use chainhook_types::{
48
BitcoinBlockData, BlockIdentifier, OrdinalInscriptionRevealData, TransactionIdentifier,
@@ -11,13 +15,13 @@ use threadpool::ThreadPool;
1115
use crate::{
1216
indexer::bitcoin::{
1317
retrieve_block_hash_with_retry, retrieve_full_block_breakdown_with_retry,
14-
BitcoinBlockFullBreakdown,
18+
standardize_bitcoin_block, BitcoinBlockFullBreakdown,
1519
},
1620
observer::BitcoinConfig,
1721
utils::Context,
1822
};
1923

20-
use super::ord::height::Height;
24+
use super::{ord::height::Height, update_hord_db_and_augment_bitcoin_block};
2125

2226
fn get_default_hord_db_file_path(base_dir: &PathBuf) -> PathBuf {
2327
let mut destination_path = base_dir.clone();
@@ -414,13 +418,98 @@ pub fn remove_entry_from_inscriptions(
414418
}
415419
}
416420

417-
pub async fn build_bitcoin_traversal_local_storage(
421+
pub async fn update_hord_db(
422+
bitcoin_config: &BitcoinConfig,
423+
hord_db_path: &PathBuf,
424+
hord_db_conn: &Connection,
425+
start_block: u64,
426+
end_block: u64,
427+
_ctx: &Context,
428+
network_thread: usize,
429+
) -> Result<(), String> {
430+
let (block_tx, block_rx) = channel::<BitcoinBlockFullBreakdown>();
431+
let first_inscription_block_height = 767430;
432+
let ctx = _ctx.clone();
433+
let network = bitcoin_config.network.clone();
434+
let hord_db_path = hord_db_path.clone();
435+
let handle = hiro_system_kit::thread_named("Inscriptions indexing")
436+
.spawn(move || {
437+
let mut cursor = first_inscription_block_height;
438+
let mut inbox = HashMap::new();
439+
440+
while let Ok(raw_block) = block_rx.recv() {
441+
// Early return, only considering blocks after 1st inscription
442+
if raw_block.height < first_inscription_block_height {
443+
continue;
444+
}
445+
let block_height = raw_block.height;
446+
inbox.insert(raw_block.height, raw_block);
447+
448+
// In the context of ordinals, we're constrained to process blocks sequentially
449+
// Blocks are processed by a threadpool and could be coming out of order.
450+
// Inbox block for later if the current block is not the one we should be
451+
// processing.
452+
if block_height != cursor {
453+
continue;
454+
}
455+
456+
// Is the action of processing a block allows us
457+
// to process more blocks present in the inbox?
458+
while let Some(next_block) = inbox.remove(&cursor) {
459+
let mut new_block = match standardize_bitcoin_block(next_block, &network, &ctx)
460+
{
461+
Ok(block) => block,
462+
Err(e) => {
463+
ctx.try_log(|logger| {
464+
slog::error!(logger, "Unable to standardize bitcoin block: {e}",)
465+
});
466+
return;
467+
}
468+
};
469+
470+
if let Err(e) = update_hord_db_and_augment_bitcoin_block(
471+
&mut new_block,
472+
&hord_db_path,
473+
&ctx,
474+
) {
475+
ctx.try_log(|logger| {
476+
slog::error!(
477+
logger,
478+
"Unable to augment bitcoin block with hord_db: {e}",
479+
)
480+
});
481+
return;
482+
}
483+
cursor += 1;
484+
}
485+
}
486+
})
487+
.expect("unable to detach thread");
488+
489+
fetch_and_cache_blocks_in_hord_db(
490+
bitcoin_config,
491+
hord_db_conn,
492+
start_block,
493+
end_block,
494+
&_ctx,
495+
network_thread,
496+
Some(block_tx),
497+
)
498+
.await?;
499+
500+
let _ = handle.join();
501+
502+
Ok(())
503+
}
504+
505+
pub async fn fetch_and_cache_blocks_in_hord_db(
418506
bitcoin_config: &BitcoinConfig,
419507
hord_db_conn: &Connection,
420508
start_block: u64,
421509
end_block: u64,
422510
ctx: &Context,
423511
network_thread: usize,
512+
block_tx: Option<Sender<BitcoinBlockFullBreakdown>>,
424513
) -> Result<(), String> {
425514
let retrieve_block_hash_pool = ThreadPool::new(network_thread);
426515
let (block_hash_tx, block_hash_rx) = crossbeam_channel::unbounded();
@@ -471,10 +560,14 @@ pub async fn build_bitcoin_traversal_local_storage(
471560
.spawn(move || {
472561
while let Ok(Some(block_data)) = block_data_rx.recv() {
473562
let block_compressed_tx_moved = block_compressed_tx.clone();
563+
let block_tx = block_tx.clone();
474564
compress_block_data_pool.execute(move || {
475565
let compressed_block = CompactedBlock::from_full_block(&block_data);
476-
let _ = block_compressed_tx_moved
477-
.send(Some((block_data.height as u32, compressed_block)));
566+
let block_index = block_data.height as u32;
567+
if let Some(block_tx) = block_tx {
568+
let _ = block_tx.send(block_data);
569+
}
570+
let _ = block_compressed_tx_moved.send(Some((block_index, compressed_block)));
478571
});
479572

480573
let res = compress_block_data_pool.join();

components/chainhook-event-observer/src/hord/mod.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use bitcoincore_rpc::bitcoin::{Address, Network, Script};
77
use chainhook_types::{BitcoinBlockData, OrdinalInscriptionTransferData, OrdinalOperation};
88
use hiro_system_kit::slog;
99
use std::collections::VecDeque;
10+
use std::path::PathBuf;
1011

1112
use crate::{
1213
hord::{
@@ -64,7 +65,7 @@ pub fn revert_hord_db_with_augmented_bitcoin_block(
6465

6566
pub fn update_hord_db_and_augment_bitcoin_block(
6667
new_block: &mut BitcoinBlockData,
67-
config: &EventObserverConfig,
68+
hord_db_path: &PathBuf,
6869
ctx: &Context,
6970
) -> Result<(), String> {
7071
{
@@ -77,7 +78,7 @@ pub fn update_hord_db_and_augment_bitcoin_block(
7778
});
7879

7980
let compacted_block = CompactedBlock::from_standardized_block(&new_block);
80-
let rw_hord_db_conn = open_readwrite_hord_db_conn(&config.get_cache_path_buf(), &ctx)?;
81+
let rw_hord_db_conn = open_readwrite_hord_db_conn(&hord_db_path, &ctx)?;
8182
insert_entry_in_blocks(
8283
new_block.block_identifier.index as u32,
8384
&compacted_block,
@@ -100,8 +101,7 @@ pub fn update_hord_db_and_augment_bitcoin_block(
100101
new_tx.metadata.ordinal_operations.iter_mut().enumerate()
101102
{
102103
if let OrdinalOperation::InscriptionRevealed(inscription) = ordinal_event {
103-
let hord_db_conn =
104-
open_readonly_hord_db_conn(&config.get_cache_path_buf(), &ctx).unwrap(); // TODO(lgalabru)
104+
let hord_db_conn = open_readonly_hord_db_conn(&hord_db_path, &ctx).unwrap(); // TODO(lgalabru)
105105

106106
let (ordinal_block_height, ordinal_offset, ordinal_number) = {
107107
// Are we looking at a re-inscription?
@@ -170,8 +170,7 @@ pub fn update_hord_db_and_augment_bitcoin_block(
170170

171171
{
172172
let rw_hord_db_conn =
173-
open_readwrite_hord_db_conn(&config.get_cache_path_buf(), &ctx)
174-
.unwrap(); // TODO(lgalabru)
173+
open_readwrite_hord_db_conn(&hord_db_path, &ctx).unwrap(); // TODO(lgalabru)
175174
store_new_inscription(
176175
&inscription,
177176
&new_block.block_identifier,
@@ -186,7 +185,7 @@ pub fn update_hord_db_and_augment_bitcoin_block(
186185
// Have inscriptions been transfered?
187186
let mut sats_in_offset = 0;
188187
let mut sats_out_offset = 0;
189-
let hord_db_conn = open_readonly_hord_db_conn(&config.get_cache_path_buf(), &ctx).unwrap(); // TODO(lgalabru)
188+
let hord_db_conn = open_readonly_hord_db_conn(&hord_db_path, &ctx)?;
190189

191190
for input in new_tx.metadata.inputs.iter() {
192191
// input.previous_output.txid
@@ -291,8 +290,7 @@ pub fn update_hord_db_and_augment_bitcoin_block(
291290

292291
// Update watched outpoint
293292
{
294-
let rw_hord_db_conn =
295-
open_readwrite_hord_db_conn(&config.get_cache_path_buf(), &ctx).unwrap(); // TODO(lgalabru)
293+
let rw_hord_db_conn = open_readwrite_hord_db_conn(&hord_db_path, &ctx)?;
296294
update_transfered_inscription(
297295
&inscription_id,
298296
&outpoint_post_transfer,

components/chainhook-event-observer/src/indexer/bitcoin/mod.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::chainhooks::types::{
66
get_canonical_pox_config, get_stacks_canonical_magic_bytes, PoxConfig, StacksOpcodes,
77
};
88

9-
use crate::observer::{BitcoinConfig, EventObserverConfig};
9+
use crate::observer::BitcoinConfig;
1010
use crate::utils::Context;
1111
use bitcoincore_rpc::bitcoin::hashes::hex::FromHex;
1212
use bitcoincore_rpc::bitcoin::hashes::Hash;
@@ -17,10 +17,10 @@ use bitcoincore_rpc_json::{
1717
pub use blocks_pool::BitcoinBlockPool;
1818
use chainhook_types::bitcoin::{OutPoint, TxIn, TxOut};
1919
use chainhook_types::{
20-
BitcoinBlockData, BitcoinBlockMetadata, BitcoinTransactionData, BitcoinTransactionMetadata,
21-
BlockCommitmentData, BlockHeader, BlockIdentifier, KeyRegistrationData, LockSTXData,
22-
OrdinalInscriptionRevealData, OrdinalOperation, PoxReward, StacksBaseChainOperation,
23-
StacksBlockCommitmentData, TransactionIdentifier, TransferSTXData,
20+
BitcoinBlockData, BitcoinBlockMetadata, BitcoinNetwork, BitcoinTransactionData,
21+
BitcoinTransactionMetadata, BlockCommitmentData, BlockHeader, BlockIdentifier,
22+
KeyRegistrationData, LockSTXData, OrdinalInscriptionRevealData, OrdinalOperation, PoxReward,
23+
StacksBaseChainOperation, StacksBlockCommitmentData, TransactionIdentifier, TransferSTXData,
2424
};
2525
use hiro_system_kit::slog;
2626

@@ -261,14 +261,14 @@ pub async fn retrieve_block_hash(
261261
}
262262

263263
pub fn standardize_bitcoin_block(
264-
config: &EventObserverConfig,
265264
block: BitcoinBlockFullBreakdown,
265+
network: &BitcoinNetwork,
266266
ctx: &Context,
267267
) -> Result<BitcoinBlockData, String> {
268268
let mut transactions = vec![];
269269
let block_height = block.height as u64;
270-
let expected_magic_bytes = get_stacks_canonical_magic_bytes(&config.bitcoin_network);
271-
let pox_config = get_canonical_pox_config(&config.bitcoin_network);
270+
let expected_magic_bytes = get_stacks_canonical_magic_bytes(&network);
271+
let pox_config = get_canonical_pox_config(&network);
272272

273273
ctx.try_log(|logger| slog::debug!(logger, "Standardizing Bitcoin block {}", block.hash,));
274274

components/chainhook-event-observer/src/observer/mod.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ impl EventObserverConfig {
152152
username: self.bitcoin_node_username.clone(),
153153
password: self.bitcoin_node_password.clone(),
154154
rpc_url: self.bitcoin_node_rpc_url.clone(),
155+
network: self.bitcoin_network.clone(),
155156
};
156157
bitcoin_config
157158
}
@@ -224,6 +225,7 @@ pub struct BitcoinConfig {
224225
pub username: String,
225226
pub password: String,
226227
pub rpc_url: String,
228+
pub network: BitcoinNetwork,
227229
}
228230

229231
#[derive(Debug, Clone)]
@@ -507,7 +509,8 @@ pub async fn start_observer_commands_handler(
507509
break;
508510
}
509511
ObserverCommand::ProcessBitcoinBlock(block_data) => {
510-
let new_block = standardize_bitcoin_block(&config, block_data, &ctx)?;
512+
let new_block =
513+
standardize_bitcoin_block(block_data, &config.bitcoin_network, &ctx)?;
511514
bitcoin_block_store.insert(new_block.block_identifier.clone(), new_block);
512515
}
513516
ObserverCommand::CacheBitcoinBlock(block) => {
@@ -528,7 +531,9 @@ pub async fn start_observer_commands_handler(
528531
match bitcoin_block_store.get_mut(&header.block_identifier) {
529532
Some(block) => {
530533
if let Err(e) = update_hord_db_and_augment_bitcoin_block(
531-
block, &config, &ctx,
534+
block,
535+
&config.get_cache_path_buf(),
536+
&ctx,
532537
) {
533538
ctx.try_log(|logger| {
534539
slog::error!(
@@ -612,7 +617,9 @@ pub async fn start_observer_commands_handler(
612617
match bitcoin_block_store.get_mut(&header.block_identifier) {
613618
Some(block) => {
614619
if let Err(e) = update_hord_db_and_augment_bitcoin_block(
615-
block, &config, &ctx,
620+
block,
621+
&config.get_cache_path_buf(),
622+
&ctx,
616623
) {
617624
ctx.try_log(|logger| {
618625
slog::error!(

0 commit comments

Comments
 (0)