Skip to content

Commit

Permalink
fix: validate and wait for bitcoind block height responses (#340)
Browse files Browse the repository at this point in the history
* fix: validate and wait for bitcoind block height responses

* chore: comments
  • Loading branch information
rafaelcr authored Jul 22, 2024
1 parent 54296f6 commit b28b92e
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 90 deletions.
27 changes: 2 additions & 25 deletions components/ordhook-cli/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::config::file::ConfigFile;
use crate::config::generator::generate_config;
use clap::{Parser, Subcommand};
use hiro_system_kit;
use ordhook::chainhook_sdk::bitcoincore_rpc::{Auth, Client, RpcApi};
use ordhook::chainhook_sdk::chainhooks::types::{
BitcoinChainhookSpecification, HttpHook, InscriptionFeedData, OrdinalsMetaProtocol,
};
Expand Down Expand Up @@ -35,6 +34,7 @@ use ordhook::download::download_ordinals_dataset_if_required;
use ordhook::scan::bitcoin::scan_bitcoin_chainstate_via_rpc_using_predicate;
use ordhook::service::observers::initialize_observers_db;
use ordhook::service::{start_observer_forwarding, Service};
use ordhook::utils::bitcoind::bitcoind_get_block_height;
use ordhook::{hex, initialize_db};
use reqwest::Client as HttpClient;
use std::collections::HashSet;
Expand Down Expand Up @@ -553,7 +553,7 @@ async fn handle_command(opts: Opts, ctx: &Context) -> Result<(), String> {
ctx.expect_logger(),
"Checking {}...", config.network.bitcoind_rpc_url
);
let tip = check_bitcoind_connection(&config).await?;
let tip = bitcoind_get_block_height(&config, ctx);
if let Some(highest_desired) = block_range.pop_back() {
if tip < highest_desired {
error!(ctx.expect_logger(), "Unable to scan desired block range: underlying bitcoind synchronized until block #{} ", tip);
Expand Down Expand Up @@ -1035,29 +1035,6 @@ pub fn build_predicate_from_cli(
Ok(predicate)
}

pub async fn check_bitcoind_connection(config: &Config) -> Result<u64, String> {
let auth = Auth::UserPass(
config.network.bitcoind_rpc_username.clone(),
config.network.bitcoind_rpc_password.clone(),
);

let bitcoin_rpc = match Client::new(&config.network.bitcoind_rpc_url, auth) {
Ok(con) => con,
Err(message) => {
return Err(format!("unable to connect to bitcoind: {}", message));
}
};

let end_block = match bitcoin_rpc.get_blockchain_info() {
Ok(result) => result.blocks,
Err(e) => {
return Err(format!("unable to connect to bitcoind: {}", e));
}
};

Ok(end_block)
}

fn parse_blocks_heights_spec(
blocks_interval: &Option<String>,
blocks: &Option<String>,
Expand Down
30 changes: 3 additions & 27 deletions components/ordhook-core/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,11 @@ use std::hash::BuildHasherDefault;
use std::ops::Div;
use std::path::PathBuf;

use chainhook_sdk::{
bitcoincore_rpc::{Auth, Client, RpcApi},
utils::Context,
};
use chainhook_sdk::utils::Context;

use crate::{
config::{Config, LogConfig, MetaProtocolsConfig, ResourcesConfig},
db::{find_pinned_block_bytes_at_block_height, open_ordhook_db_conn_rocks_db_loop},
db::{find_pinned_block_bytes_at_block_height, open_ordhook_db_conn_rocks_db_loop}, utils::bitcoind::bitcoind_get_block_height,
};

use crate::db::{
Expand Down Expand Up @@ -144,18 +141,6 @@ pub fn should_sync_ordhook_db(
config: &Config,
ctx: &Context,
) -> Result<Option<(u64, u64, usize)>, String> {
let auth = Auth::UserPass(
config.network.bitcoind_rpc_username.clone(),
config.network.bitcoind_rpc_password.clone(),
);

let bitcoin_rpc = match Client::new(&config.network.bitcoind_rpc_url, auth) {
Ok(con) => con,
Err(message) => {
return Err(format!("Bitcoin RPC error: {}", message.to_string()));
}
};

let blocks_db = open_ordhook_db_conn_rocks_db_loop(
true,
&config.expected_cache_path(),
Expand Down Expand Up @@ -186,17 +171,8 @@ pub fn should_sync_ordhook_db(
}
};

let end_block = match bitcoin_rpc.get_blockchain_info() {
Ok(result) => result.blocks,
Err(e) => {
return Err(format!(
"unable to retrieve Bitcoin chain tip ({})",
e.to_string()
));
}
};

// TODO: Gracefully handle Regtest, Testnet and Signet
let end_block = bitcoind_get_block_height(config, ctx);
let (mut end_block, speed) = if start_block < 200_000 {
(end_block.min(200_000), 10_000)
} else if start_block < 550_000 {
Expand Down
3 changes: 1 addition & 2 deletions components/ordhook-core/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ use chainhook_sdk::{
};

use crate::{
config::Config,
core::{
meta_protocols::brc20::db::{delete_activity_in_block_range, open_readwrite_brc20_db_conn},
meta_protocols::brc20::db::delete_activity_in_block_range,
protocol::inscription_parsing::{
get_inscriptions_revealed_in_block, get_inscriptions_transferred_in_block,
},
Expand Down
46 changes: 10 additions & 36 deletions components/ordhook-core/src/scan/bitcoin.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::config::Config;
use crate::core::meta_protocols::brc20::brc20_activation_height;
use crate::core::meta_protocols::brc20::db::open_readonly_brc20_db_conn;
use crate::core::protocol::inscription_parsing::{
get_inscriptions_revealed_in_block, get_inscriptions_transferred_in_block,
Expand All @@ -11,8 +10,7 @@ use crate::download::download_ordinals_dataset_if_required;
use crate::service::observers::{
open_readwrite_observers_db_conn_or_panic, update_observer_progress,
};
use chainhook_sdk::bitcoincore_rpc::RpcApi;
use chainhook_sdk::bitcoincore_rpc::{Auth, Client};
use crate::utils::bitcoind::bitcoind_get_block_height;
use chainhook_sdk::chainhooks::bitcoin::{
evaluate_bitcoin_chainhooks_on_chain_event, handle_bitcoin_hook_action,
BitcoinChainhookOccurrence, BitcoinTriggerChainhook,
Expand All @@ -37,18 +35,6 @@ pub async fn scan_bitcoin_chainstate_via_rpc_using_predicate(
ctx: &Context,
) -> Result<(), String> {
let _ = download_ordinals_dataset_if_required(config, ctx).await;

let auth = Auth::UserPass(
config.network.bitcoind_rpc_username.clone(),
config.network.bitcoind_rpc_password.clone(),
);

let bitcoin_rpc = match Client::new(&config.network.bitcoind_rpc_url, auth) {
Ok(con) => con,
Err(message) => {
return Err(format!("Bitcoin RPC error: {}", message.to_string()));
}
};
let mut floating_end_block = false;

let block_heights_to_scan_res = if let Some(ref blocks) = predicate_spec.blocks {
Expand All @@ -65,15 +51,7 @@ pub async fn scan_bitcoin_chainstate_via_rpc_using_predicate(
};
let (end_block, update_end_block) = match predicate_spec.end_block {
Some(end_block) => (end_block, false),
None => match bitcoin_rpc.get_blockchain_info() {
Ok(result) => (result.blocks, true),
Err(e) => {
return Err(format!(
"unable to retrieve Bitcoin chain tip ({})",
e.to_string()
));
}
},
None => (bitcoind_get_block_height(config, ctx), true),
};
floating_end_block = update_end_block;
BlockHeights::BlockRange(start_block, end_block).get_sorted_entries()
Expand Down Expand Up @@ -195,20 +173,16 @@ pub async fn scan_bitcoin_chainstate_via_rpc_using_predicate(
)
}
if block_heights_to_scan.is_empty() && floating_end_block {
let new_tip = match bitcoin_rpc.get_blockchain_info() {
Ok(result) => match predicate_spec.end_block {
Some(end_block) => {
if end_block > result.blocks {
result.blocks
} else {
end_block
}
let bitcoind_chain_tip = bitcoind_get_block_height(config, ctx);
let new_tip = match predicate_spec.end_block {
Some(end_block) => {
if end_block > bitcoind_chain_tip {
bitcoind_chain_tip
} else {
end_block
}
None => result.blocks,
},
Err(_e) => {
continue;
}
None => bitcoind_chain_tip,
};

for entry in (current_block_height + 1)..new_tip {
Expand Down
41 changes: 41 additions & 0 deletions components/ordhook-core/src/utils/bitcoind.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use chainhook_sdk::{bitcoincore_rpc::{Auth, Client, RpcApi}, utils::Context};

use crate::{config::Config, try_error};

fn bitcoind_get_client(config: &Config, ctx: &Context) -> Client {
loop {
let auth = Auth::UserPass(
config.network.bitcoind_rpc_username.clone(),
config.network.bitcoind_rpc_password.clone(),
);
match Client::new(&config.network.bitcoind_rpc_url, auth) {
Ok(con) => {
return con;
}
Err(e) => {
try_error!(ctx, "bitcoind unable to get client: {}", e.to_string());
std::thread::sleep(std::time::Duration::from_secs(1));
}
}
}
}

/// Retrieves the block height from bitcoind.
pub fn bitcoind_get_block_height(config: &Config, ctx: &Context) -> u64 {
let bitcoin_rpc = bitcoind_get_client(config, ctx);
loop {
match bitcoin_rpc.get_blockchain_info() {
Ok(result) => {
return result.blocks;
}
Err(e) => {
try_error!(
ctx,
"bitcoind unable to get block height: {}",
e.to_string()
);
std::thread::sleep(std::time::Duration::from_secs(1));
}
};
}
}
39 changes: 39 additions & 0 deletions components/ordhook-core/src/utils/logger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#[macro_export]
macro_rules! try_info {
($a:expr, $tag:expr, $($args:tt)*) => {
$a.try_log(|l| info!(l, $tag, $($args)*));
};
($a:expr, $tag:expr) => {
$a.try_log(|l| info!(l, $tag));
};
}

#[macro_export]
macro_rules! try_debug {
($a:expr, $tag:expr, $($args:tt)*) => {
$a.try_log(|l| debug!(l, $tag, $($args)*));
};
($a:expr, $tag:expr) => {
$a.try_log(|l| debug!(l, $tag));
};
}

#[macro_export]
macro_rules! try_warn {
($a:expr, $tag:expr, $($args:tt)*) => {
$a.try_log(|l| warn!(l, $tag, $($args)*));
};
($a:expr, $tag:expr) => {
$a.try_log(|l| warn!(l, $tag));
};
}

#[macro_export]
macro_rules! try_error {
($a:expr, $tag:expr, $($args:tt)*) => {
$a.try_log(|l| error!(l, $tag, $($args)*));
};
($a:expr, $tag:expr) => {
$a.try_log(|l| error!(l, $tag));
};
}
3 changes: 3 additions & 0 deletions components/ordhook-core/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pub mod bitcoind;
pub mod logger;

use std::{
fs,
io::{Read, Write},
Expand Down

0 comments on commit b28b92e

Please sign in to comment.