Skip to content

Commit 8bb24be

Browse files
author
Ludo Galabru
authored
fix: initial flow (#178)
* chore: update chainhook-sdk + cascade changes * fix: update archive url * feat: only create rocksdb if sqlite present * fix: use crossbeam channel instead of std * fix: improve error message * doc: update README * fix: build warnings * fix: block_archiving expiration * fix: archive url * fix: read content len from http header * chore: untar sqlite file * chore: bump versions
1 parent ac3d458 commit 8bb24be

File tree

17 files changed

+661
-784
lines changed

17 files changed

+661
-784
lines changed

Cargo.lock

+543-738
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ members = [
44
"components/ordhook-core",
55
"components/ordhook-sdk-js"
66
]
7-
87
default-members = ["components/ordhook-cli"]
8+
resolver = "2"

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,15 @@ will spin up a HTTP API for managing events destinations.
112112

113113
A comprehensive OpenAPI specification explaining how to interact with this HTTP REST API can be found [here](https://github.com/hirosystems/chainhook/blob/develop/docs/chainhook-openapi.json).
114114

115+
---
116+
### Troubleshooting: Performance and System Requirements
117+
118+
The Ordinals Theory protocol is resource-intensive, demanding significant CPU, memory, and disk capabilities. As we continue to refine and optimize, keep in mind the following system requirements and recommendations to ensure optimal performance:
119+
120+
CPU: The ordhook tool efficiently utilizes multiple cores when detected at runtime, parallelizing tasks to boost performance.
121+
122+
Memory: A minimum of 16GB RAM is recommended.
123+
124+
Disk: To enhance I/O performance, SSD or NVMe storage is suggested.
115125

126+
OS Requirements: Ensure your system allows for a minimum of 4096 open file descriptors. Configuration may vary based on your operating system. On certain systems, this can be adjusted using the `ulimit` command or the `launchctl limit` command.

components/ordhook-cli/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ordhook-cli"
3-
version = "1.0.1"
3+
version = "1.0.2"
44
edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -15,7 +15,7 @@ serde = "1"
1515
serde_json = "1"
1616
serde_derive = "1"
1717
reqwest = { version = "0.11", features = ["stream", "json"] }
18-
hiro-system-kit = "0.1.0"
18+
hiro-system-kit = "0.3.1"
1919
clap = { version = "3.2.23", features = ["derive"], optional = true }
2020
clap_generate = { version = "3.0.3", optional = true }
2121
toml = { version = "0.5.6", features = ["preserve_order"], optional = true }

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ max_caching_memory_size_mb = 32000
3737
# Disable the following section if the state
3838
# must be built locally
3939
[bootstrap]
40-
download_url = "https://archive.hiro.so/mainnet/chainhooks/hord.sqlite"
40+
download_url = "https://archive.hiro.so/mainnet/ordhook/mainnet-ordhook-sqlite-latest"
4141
4242
[logs]
4343
ordinals_internals = true

components/ordhook-core/Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ordhook"
3-
version = "0.4.0"
3+
version = "0.5.0"
44
edition = "2021"
55

66
[dependencies]
@@ -12,9 +12,9 @@ redis = "0.21.5"
1212
serde-redis = "0.12.0"
1313
hex = "0.4.3"
1414
rand = "0.8.5"
15-
chainhook-sdk = { version = "=0.9.0", default-features = false, features = ["zeromq", "log"] }
15+
chainhook-sdk = { version = "=0.9.5", default-features = false, features = ["zeromq", "log"] }
1616
# chainhook-sdk = { version = "=0.9.0", path = "../../../chainhook/components/chainhook-sdk", default-features = false, features = ["zeromq", "log"] }
17-
hiro-system-kit = "0.1.0"
17+
hiro-system-kit = "0.3.1"
1818
reqwest = { version = "0.11", features = ["stream", "json"] }
1919
tokio = { version = "=1.24", features = ["full"] }
2020
futures-util = "0.3.24"

components/ordhook-core/src/config/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use chainhook_sdk::types::{
77
use std::path::PathBuf;
88

99
const DEFAULT_MAINNET_ORDINALS_SQLITE_ARCHIVE: &str =
10-
"https://archive.hiro.so/mainnet/chainhooks/hord.sqlite";
10+
"https://archive.hiro.so/mainnet/ordhook/mainnet-ordhook-sqlite-latest";
1111

1212
pub const DEFAULT_INGESTION_PORT: u16 = 20455;
1313
pub const DEFAULT_CONTROL_PORT: u16 = 20456;
@@ -155,7 +155,7 @@ impl Config {
155155
}
156156

157157
pub fn expected_remote_ordinals_sqlite_url(&self) -> String {
158-
format!("{}.gz", self.expected_remote_ordinals_sqlite_base_url())
158+
format!("{}.tar.gz", self.expected_remote_ordinals_sqlite_base_url())
159159
}
160160

161161
pub fn devnet_default() -> Config {

components/ordhook-core/src/core/mod.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ use chainhook_sdk::{
1414

1515
use crate::{
1616
config::{Config, LogConfig},
17-
db::find_lazy_block_at_block_height,
17+
db::{find_lazy_block_at_block_height, open_readwrite_ordhook_db_conn_rocks_db},
1818
};
1919

2020
use crate::db::{
2121
find_last_block_inserted, find_latest_inscription_block_height, initialize_ordhook_db,
22-
open_readonly_ordhook_db_conn, open_readonly_ordhook_db_conn_rocks_db,
22+
open_readonly_ordhook_db_conn,
2323
};
2424

2525
use crate::db::LazyBlockTransaction;
@@ -94,6 +94,26 @@ pub fn compute_next_satpoint_data(
9494
SatPosition::Output((output_index, (offset_cross_inputs - offset_intra_outputs)))
9595
}
9696

97+
pub fn should_sync_rocks_db(
98+
config: &Config,
99+
ctx: &Context,
100+
) -> Result<Option<(u64, u64)>, String> {
101+
let blocks_db = open_readwrite_ordhook_db_conn_rocks_db(&config.expected_cache_path(), &ctx)?;
102+
let inscriptions_db_conn = open_readonly_ordhook_db_conn(&config.expected_cache_path(), &ctx)?;
103+
let last_compressed_block = find_last_block_inserted(&blocks_db) as u64;
104+
let last_indexed_block = match find_latest_inscription_block_height(&inscriptions_db_conn, ctx)? {
105+
Some(last_indexed_block) => last_indexed_block,
106+
None => 0
107+
};
108+
109+
let res = if last_compressed_block < last_indexed_block {
110+
Some((last_compressed_block, last_indexed_block))
111+
} else {
112+
None
113+
};
114+
Ok(res)
115+
}
116+
97117
pub fn should_sync_ordhook_db(
98118
config: &Config,
99119
ctx: &Context,
@@ -110,7 +130,7 @@ pub fn should_sync_ordhook_db(
110130
}
111131
};
112132

113-
let blocks_db = open_readonly_ordhook_db_conn_rocks_db(&config.expected_cache_path(), &ctx)?;
133+
let blocks_db = open_readwrite_ordhook_db_conn_rocks_db(&config.expected_cache_path(), &ctx)?;
114134
let mut start_block = find_last_block_inserted(&blocks_db) as u64;
115135

116136
if start_block == 0 {

components/ordhook-core/src/core/pipeline/processors/block_archiving.rs

+3-20
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
use std::{
2-
sync::mpsc::Sender,
32
thread::{sleep, JoinHandle},
43
time::Duration,
54
};
6-
5+
use crossbeam_channel::{Sender, TryRecvError};
76
use chainhook_sdk::{types::BitcoinBlockData, utils::Context};
8-
use crossbeam_channel::TryRecvError;
97
use rocksdb::DB;
108

119
use crate::{
1210
config::Config,
1311
core::pipeline::{PostProcessorCommand, PostProcessorController, PostProcessorEvent},
1412
db::{
15-
insert_entry_in_blocks, open_ordhook_db_conn_rocks_db_loop,
13+
insert_entry_in_blocks,
1614
open_readwrite_ordhook_db_conn_rocks_db, LazyBlock,
1715
},
1816
};
@@ -30,10 +28,9 @@ pub fn start_block_archiving_processor(
3028
let ctx = ctx.clone();
3129
let handle: JoinHandle<()> = hiro_system_kit::thread_named("Processor Runloop")
3230
.spawn(move || {
33-
let mut blocks_db_rw =
31+
let blocks_db_rw =
3432
open_readwrite_ordhook_db_conn_rocks_db(&config.expected_cache_path(), &ctx)
3533
.unwrap();
36-
let mut empty_cycles = 0;
3734
let mut processed_blocks = 0;
3835

3936
loop {
@@ -49,16 +46,7 @@ pub fn start_block_archiving_processor(
4946
}
5047
Err(e) => match e {
5148
TryRecvError::Empty => {
52-
empty_cycles += 1;
53-
if empty_cycles == 30 {
54-
warn!(ctx.expect_logger(), "Block processor reached expiration");
55-
let _ = events_tx.send(PostProcessorEvent::Expired);
56-
break;
57-
}
5849
sleep(Duration::from_secs(1));
59-
if empty_cycles > 120 {
60-
break;
61-
}
6250
continue;
6351
}
6452
_ => {
@@ -71,11 +59,6 @@ pub fn start_block_archiving_processor(
7159

7260
if processed_blocks % 10_000 == 0 {
7361
let _ = blocks_db_rw.flush_wal(true);
74-
blocks_db_rw = open_ordhook_db_conn_rocks_db_loop(
75-
true,
76-
&config.expected_cache_path(),
77-
&ctx,
78-
);
7962
}
8063
}
8164

components/ordhook-core/src/db/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ pub fn open_readonly_ordhook_db_conn_rocks_db(
228228
opts.set_disable_auto_compactions(true);
229229
opts.set_max_background_jobs(0);
230230
let db = DB::open_for_read_only(&opts, path, false)
231-
.map_err(|e| format!("unable to open blocks_db: {}", e.to_string()))?;
231+
.map_err(|e| format!("unable to open hord.rocksdb: {}", e.to_string()))?;
232232
Ok(db)
233233
}
234234

@@ -276,7 +276,7 @@ pub fn open_readwrite_ordhook_db_conn_rocks_db(
276276
let path = get_default_ordhook_db_file_path_rocks_db(&base_dir);
277277
let opts = rocks_db_default_options();
278278
let db = DB::open(&opts, path)
279-
.map_err(|e| format!("unable to open blocks_db: {}", e.to_string()))?;
279+
.map_err(|e| format!("unable to open hord.rocksdb: {}", e.to_string()))?;
280280
Ok(db)
281281
}
282282

components/ordhook-core/src/download/mod.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use flate2::read::GzDecoder;
66
use futures_util::StreamExt;
77
use progressing::mapping::Bar as MappingBar;
88
use progressing::Baring;
9+
use tar::Archive;
910
use std::fs;
1011
use std::io::{self, Cursor};
1112
use std::io::{Read, Write};
@@ -19,7 +20,7 @@ pub fn default_sqlite_sha_file_path(_network: &BitcoinNetwork) -> String {
1920
}
2021

2122
pub async fn download_sqlite_file(config: &Config, _ctx: &Context) -> Result<(), String> {
22-
let mut destination_path = config.expected_cache_path();
23+
let destination_path = config.expected_cache_path();
2324
std::fs::create_dir_all(&destination_path).unwrap_or_else(|e| {
2425
println!("{}", e.to_string());
2526
});
@@ -46,22 +47,21 @@ pub async fn download_sqlite_file(config: &Config, _ctx: &Context) -> Result<(),
4647

4748
// Download chunks
4849
let (tx, rx) = flume::bounded(0);
49-
destination_path.push(default_sqlite_file_path(&config.network.bitcoin_network));
5050

5151
let decoder_thread = std::thread::spawn(move || {
5252
let input = ChannelRead::new(rx);
5353
let mut decoder = GzDecoder::new(input);
5454
let mut content = Vec::new();
5555
let _ = decoder.read_to_end(&mut content);
56-
let mut file = fs::File::create(&destination_path).unwrap();
57-
if let Err(e) = file.write_all(&content[..]) {
56+
let mut archive = Archive::new(&content[..]);
57+
if let Err(e) = archive.unpack(&destination_path) {
5858
println!("unable to write file: {}", e.to_string());
5959
std::process::exit(1);
6060
}
6161
});
6262

6363
if res.status() == reqwest::StatusCode::OK {
64-
let limit = 5_400_000_000;
64+
let limit = res.content_length().unwrap_or(10_000_000_000) as i64;
6565
let mut progress_bar = MappingBar::with_range(0i64, limit);
6666
progress_bar.set_len(60);
6767
let mut stdout = std::io::stdout();

components/ordhook-core/src/scan/bitcoin.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -234,14 +234,14 @@ pub async fn process_block_with_predicates(
234234
predicates: &Vec<&BitcoinChainhookSpecification>,
235235
event_observer_config: &EventObserverConfig,
236236
ctx: &Context,
237-
) -> Result<u32, ()> {
237+
) -> Result<u32, String> {
238238
let chain_event =
239239
BitcoinChainEvent::ChainUpdatedWithBlocks(BitcoinChainUpdatedWithBlocksData {
240240
new_blocks: vec![block],
241241
confirmed_blocks: vec![],
242242
});
243243

244-
let (predicates_triggered, _predicates_evaluated) =
244+
let (predicates_triggered, _predicates_evaluated, _) =
245245
evaluate_bitcoin_chainhooks_on_chain_event(&chain_event, predicates, ctx);
246246

247247
execute_predicates_action(predicates_triggered, &event_observer_config, &ctx).await
@@ -251,7 +251,7 @@ pub async fn execute_predicates_action<'a>(
251251
hits: Vec<BitcoinTriggerChainhook<'a>>,
252252
config: &EventObserverConfig,
253253
ctx: &Context,
254-
) -> Result<u32, ()> {
254+
) -> Result<u32, String> {
255255
let mut actions_triggered = 0;
256256
let mut proofs = HashMap::new();
257257
for trigger in hits.into_iter() {

components/ordhook-core/src/service/http_api.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ fn handle_get_predicates(
9999

100100
let serialized_predicates = predicates
101101
.iter()
102-
.map(|(p, _)| p.into_serialized_json())
102+
.map(|(p, s)| serialized_predicate_with_status(p, s))
103103
.collect::<Vec<_>>();
104104

105105
Json(json!({
@@ -311,3 +311,27 @@ pub fn load_predicates_from_redis(
311311
.map_err(|e| format!("unable to connect to redis: {}", e.to_string()))?;
312312
get_entries_from_predicates_db(&mut predicate_db_conn, ctx)
313313
}
314+
315+
fn serialized_predicate_with_status(
316+
predicate: &ChainhookSpecification,
317+
status: &PredicateStatus,
318+
) -> JsonValue {
319+
match (predicate, status) {
320+
(ChainhookSpecification::Stacks(spec), status) => json!({
321+
"chain": "stacks",
322+
"uuid": spec.uuid,
323+
"network": spec.network,
324+
"predicate": spec.predicate,
325+
"status": status,
326+
"enabled": spec.enabled,
327+
}),
328+
(ChainhookSpecification::Bitcoin(spec), status) => json!({
329+
"chain": "bitcoin",
330+
"uuid": spec.uuid,
331+
"network": spec.network,
332+
"predicate": spec.predicate,
333+
"status": status,
334+
"enabled": spec.enabled,
335+
}),
336+
}
337+
}

components/ordhook-core/src/service/mod.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ mod runloops;
44

55
use crate::config::{Config, PredicatesApi};
66
use crate::core::pipeline::download_and_pipeline_blocks;
7+
use crate::core::pipeline::processors::block_archiving::start_block_archiving_processor;
78
use crate::core::pipeline::processors::inscription_indexing::process_block;
89
use crate::core::pipeline::processors::start_inscription_indexing_processor;
910
use crate::core::pipeline::processors::transfers_recomputing::start_transfers_recomputing_processor;
1011
use crate::core::protocol::inscription_parsing::{
1112
get_inscriptions_revealed_in_block, parse_inscriptions_in_standardized_block,
1213
};
1314
use crate::core::protocol::inscription_sequencing::SequenceCursor;
14-
use crate::core::{new_traversals_lazy_cache, should_sync_ordhook_db};
15+
use crate::core::{new_traversals_lazy_cache, should_sync_ordhook_db, should_sync_rocks_db};
1516
use crate::db::{
1617
delete_data_in_ordhook_db, insert_entry_in_blocks,
1718
update_inscriptions_with_block, update_locations_with_block,
@@ -465,6 +466,38 @@ impl Service {
465466
&self,
466467
block_post_processor: Option<crossbeam_channel::Sender<BitcoinBlockData>>,
467468
) -> Result<(), String> {
469+
// First, make sure that rocksdb and sqlite are aligned.
470+
// If rocksdb.chain_tip.height <= sqlite.chain_tip.height
471+
// Perform some block compression until that height.
472+
if let Some((start_block, end_block)) = should_sync_rocks_db(&self.config, &self.ctx)? {
473+
let blocks_post_processor = start_block_archiving_processor(
474+
&self.config,
475+
&self.ctx,
476+
false,
477+
block_post_processor.clone(),
478+
);
479+
480+
self.ctx.try_log(|logger| {
481+
info!(
482+
logger,
483+
"Compressing blocks (from #{start_block} to #{end_block})"
484+
)
485+
});
486+
487+
let ordhook_config = self.config.get_ordhook_config();
488+
let first_inscription_height = ordhook_config.first_inscription_height;
489+
let blocks = BlockHeights::BlockRange(start_block, end_block).get_sorted_entries();
490+
download_and_pipeline_blocks(
491+
&self.config,
492+
blocks.into(),
493+
first_inscription_height,
494+
Some(&blocks_post_processor),
495+
10_000,
496+
&self.ctx,
497+
)
498+
.await?;
499+
}
500+
468501
// Start predicate processor
469502
let mut last_block_processed = 0;
470503
while let Some((start_block, end_block, speed)) =

components/ordhook-core/src/service/predicates.rs

+1
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ pub fn create_and_consolidate_chainhook_config_with_predicates(
248248
blocks: None,
249249
start_block: None,
250250
end_block: None,
251+
expired_at: None,
251252
expire_after_occurrence: None,
252253
predicate: chainhook_sdk::chainhooks::types::BitcoinPredicateType::OrdinalsProtocol(
253254
chainhook_sdk::chainhooks::types::OrdinalOperations::InscriptionFeed,

components/ordhook-sdk-js/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ordhook-sdk-js"
3-
version = "0.4.0"
3+
version = "0.5.0"
44
edition = "2021"
55
exclude = ["index.node"]
66

0 commit comments

Comments
 (0)