Skip to content

Commit 9d0d106

Browse files
author
Ludo Galabru
committed
feat: update inscription transfer logic
1 parent 2ac3022 commit 9d0d106

File tree

3 files changed

+246
-192
lines changed

3 files changed

+246
-192
lines changed

components/chainhook-event-observer/src/indexer/ordinals/db/mod.rs

+115-117
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use crate::{
1616
utils::Context,
1717
};
1818

19+
use super::ord::height::Height;
20+
1921
fn get_default_ordinals_db_file_path(base_dir: &PathBuf) -> PathBuf {
2022
let mut destination_path = base_dir.clone();
2123
destination_path.push("bitcoin_block_traversal.sqlite");
@@ -54,9 +56,9 @@ pub fn initialize_ordinal_state_storage(path: &PathBuf, ctx: &Context) -> Connec
5456
"CREATE TABLE IF NOT EXISTS inscriptions (
5557
inscription_id TEXT NOT NULL PRIMARY KEY,
5658
outpoint_to_watch TEXT NOT NULL,
57-
satoshi_id TEXT NOT NULL,
59+
ordinal_number INTEGER NOT NULL,
5860
inscription_number INTEGER NOT NULL,
59-
offset NOT NULL
61+
offset INTEGER NOT NULL
6062
)",
6163
[],
6264
) {
@@ -69,7 +71,7 @@ pub fn initialize_ordinal_state_storage(path: &PathBuf, ctx: &Context) -> Connec
6971
ctx.try_log(|logger| slog::error!(logger, "{}", e.to_string()));
7072
}
7173
if let Err(e) = conn.execute(
72-
"CREATE INDEX IF NOT EXISTS index_inscriptions_on_satoshi_id ON inscriptions(satoshi_id);",
74+
"CREATE INDEX IF NOT EXISTS index_inscriptions_on_ordinal_number ON inscriptions(ordinal_number);",
7375
[],
7476
) {
7577
ctx.try_log(|logger| slog::error!(logger, "{}", e.to_string()));
@@ -240,7 +242,7 @@ pub fn retrieve_compacted_block_from_index(
240242
) -> Option<CompactedBlock> {
241243
let args: &[&dyn ToSql] = &[&block_id.to_sql().unwrap()];
242244
let mut stmt = storage_conn
243-
.prepare("SELECT compacted_bytes FROM blocks WHERE id = ?1")
245+
.prepare("SELECT compacted_bytes FROM blocks WHERE id = ?")
244246
.unwrap();
245247
let result_iter = stmt
246248
.query_map(args, |row| {
@@ -255,35 +257,14 @@ pub fn retrieve_compacted_block_from_index(
255257
return None;
256258
}
257259

258-
pub fn scan_existing_inscriptions_id(
259-
inscription_id: &str,
260-
storage_conn: &Connection,
261-
) -> Option<String> {
262-
let args: &[&dyn ToSql] = &[&inscription_id.to_sql().unwrap()];
263-
let mut stmt = storage_conn
264-
.prepare("SELECT inscription_id FROM inscriptions WHERE inscription_id = ?1")
265-
.unwrap();
266-
let result_iter = stmt
267-
.query_map(args, |row| {
268-
let inscription_id: String = row.get(0).unwrap();
269-
Ok(inscription_id)
270-
})
271-
.unwrap();
272-
273-
for result in result_iter {
274-
return Some(result.unwrap());
275-
}
276-
return None;
277-
}
278-
279260
pub fn store_new_inscription(
280261
inscription_data: &OrdinalInscriptionRevealData,
281262
storage_conn: &Connection,
282263
ctx: &Context,
283264
) {
284265
if let Err(e) = storage_conn.execute(
285-
"INSERT INTO inscriptions (inscription_id, outpoint_to_watch, satoshi_id, inscription_number) VALUES (?1, ?2)",
286-
rusqlite::params![&inscription_data.inscription_id, &inscription_data.outpoint_post_inscription, &inscription_data.inscription_id, &inscription_data.inscription_id],
266+
"INSERT INTO inscriptions (inscription_id, outpoint_to_watch, ordinal_number, inscription_number, offset) VALUES (?1, ?2, ?3, ?4, ?5)",
267+
rusqlite::params![&inscription_data.inscription_id, &inscription_data.satpoint_post_inscription[0..inscription_data.satpoint_post_inscription.len()-2], &inscription_data.ordinal_number, &inscription_data.inscription_number, 0],
287268
) {
288269
ctx.try_log(|logger| slog::error!(logger, "{}", e.to_string()));
289270
}
@@ -297,7 +278,7 @@ pub fn update_transfered_inscription(
297278
ctx: &Context,
298279
) {
299280
if let Err(e) = storage_conn.execute(
300-
"UPDATE inscriptions SET outpoint_to_watch = ?1, offset = ?2 WHERE inscription_id = ?3",
281+
"UPDATE inscriptions SET outpoint_to_watch = ?, offset = ? WHERE inscription_id = ?",
301282
rusqlite::params![&outpoint_post_transfer, &offset, &inscription_id],
302283
) {
303284
ctx.try_log(|logger| slog::error!(logger, "{}", e.to_string()));
@@ -314,61 +295,48 @@ pub fn find_last_inscription_number(
314295
"SELECT inscription_number FROM inscriptions ORDER BY inscription_number DESC LIMIT 1",
315296
)
316297
.unwrap();
317-
let result_iter = stmt
318-
.query_map(args, |row| {
319-
let inscription_number: u64 = row.get(0).unwrap();
320-
Ok(inscription_number)
321-
})
322-
.unwrap();
323-
324-
for result in result_iter {
325-
return Ok(result.unwrap());
298+
let mut rows = stmt.query(args).unwrap();
299+
while let Ok(Some(row)) = rows.next() {
300+
let inscription_number: u64 = row.get(0).unwrap();
301+
return Ok(inscription_number);
326302
}
327-
return Ok(0);
303+
Ok(0)
328304
}
329305

330-
pub fn find_inscription_with_satoshi_id(
331-
satoshi_id: &str,
306+
pub fn find_inscription_with_ordinal_number(
307+
ordinal_number: &u64,
332308
storage_conn: &Connection,
333309
ctx: &Context,
334310
) -> Option<String> {
335-
let args: &[&dyn ToSql] = &[&satoshi_id.to_sql().unwrap()];
311+
let args: &[&dyn ToSql] = &[&ordinal_number.to_sql().unwrap()];
336312
let mut stmt = storage_conn
337-
.prepare("SELECT inscription_id FROM inscriptions WHERE satoshi_id = ?1")
313+
.prepare("SELECT inscription_id FROM inscriptions WHERE ordinal_number = ?")
338314
.unwrap();
339-
let result_iter = stmt
340-
.query_map(args, |row| {
341-
let inscription_id: String = row.get(0).unwrap();
342-
Ok(inscription_id)
343-
})
344-
.unwrap();
345-
346-
for result in result_iter {
347-
return Some(result.unwrap());
315+
let mut rows = stmt.query(args).unwrap();
316+
while let Ok(Some(row)) = rows.next() {
317+
let inscription_id: String = row.get(0).unwrap();
318+
return Some(inscription_id);
348319
}
349320
return None;
350321
}
351322

352323
pub fn find_inscriptions_at_wached_outpoint(
353-
txin: &str,
324+
outpoint: &str,
354325
storage_conn: &Connection,
355-
) -> Vec<(String, u64, String, u64)> {
356-
let args: &[&dyn ToSql] = &[&txin.to_sql().unwrap()];
326+
) -> Vec<(String, u64, u64, u64)> {
327+
let args: &[&dyn ToSql] = &[&outpoint.to_sql().unwrap()];
357328
let mut stmt = storage_conn
358-
.prepare("SELECT inscription_id, inscription_number, satoshi_id, offset FROM inscriptions WHERE outpoint_to_watch = ?1 ORDER BY offset ASC")
329+
.prepare("SELECT inscription_id, inscription_number, ordinal_number, offset FROM inscriptions WHERE outpoint_to_watch = ? ORDER BY offset ASC")
359330
.unwrap();
360331
let mut results = vec![];
361-
let result_iter = stmt
362-
.query_map(args, |row| {
363-
let inscription_id: String = row.get(0).unwrap();
364-
let inscription_number: u64 = row.get(1).unwrap();
365-
let satoshi_id: String = row.get(2).unwrap();
366-
let offset: u64 = row.get(1).unwrap();
367-
results.push((inscription_id, inscription_number, satoshi_id, offset));
368-
Ok(())
369-
})
370-
.unwrap();
371-
332+
let mut rows = stmt.query(args).unwrap();
333+
while let Ok(Some(row)) = rows.next() {
334+
let inscription_id: String = row.get(0).unwrap();
335+
let inscription_number: u64 = row.get(1).unwrap();
336+
let ordinal_number: u64 = row.get(2).unwrap();
337+
let offset: u64 = row.get(3).unwrap();
338+
results.push((inscription_id, inscription_number, ordinal_number, offset));
339+
}
372340
return results;
373341
}
374342

@@ -430,51 +398,61 @@ pub async fn build_bitcoin_traversal_local_storage(
430398
let bitcoin_config = bitcoin_config.clone();
431399
let moved_ctx = ctx.clone();
432400
let block_data_tx_moved = block_data_tx.clone();
433-
let handle_1 = hiro_system_kit::thread_named("Block data retrieval").spawn(move || {
434-
while let Ok(Some((block_height, block_hash))) = block_hash_rx.recv() {
435-
let moved_bitcoin_config = bitcoin_config.clone();
436-
let block_data_tx = block_data_tx_moved.clone();
437-
let moved_ctx = moved_ctx.clone();
438-
retrieve_block_data_pool.execute(move || {
439-
moved_ctx.try_log(|logger| slog::info!(logger, "Fetching block #{block_height}"));
440-
let future = retrieve_full_block_breakdown_with_retry(
441-
&moved_bitcoin_config,
442-
&block_hash,
443-
&moved_ctx,
444-
);
445-
let block_data = hiro_system_kit::nestable_block_on(future).unwrap();
446-
let _ = block_data_tx.send(Some(block_data));
447-
});
448-
let res = retrieve_block_data_pool.join();
449-
res
450-
}
451-
}).expect("unable to spawn thread");
452-
453-
let handle_2 = hiro_system_kit::thread_named("Block data compression").spawn(move || {
454-
while let Ok(Some(block_data)) = block_data_rx.recv() {
455-
let block_compressed_tx_moved = block_compressed_tx.clone();
456-
compress_block_data_pool.execute(move || {
457-
let compressed_block = CompactedBlock::from_full_block(&block_data);
458-
let _ = block_compressed_tx_moved
459-
.send(Some((block_data.height as u32, compressed_block)));
460-
});
401+
let handle_1 = hiro_system_kit::thread_named("Block data retrieval")
402+
.spawn(move || {
403+
while let Ok(Some((block_height, block_hash))) = block_hash_rx.recv() {
404+
let moved_bitcoin_config = bitcoin_config.clone();
405+
let block_data_tx = block_data_tx_moved.clone();
406+
let moved_ctx = moved_ctx.clone();
407+
retrieve_block_data_pool.execute(move || {
408+
moved_ctx
409+
.try_log(|logger| slog::info!(logger, "Fetching block #{block_height}"));
410+
let future = retrieve_full_block_breakdown_with_retry(
411+
&moved_bitcoin_config,
412+
&block_hash,
413+
&moved_ctx,
414+
);
415+
let block_data = hiro_system_kit::nestable_block_on(future).unwrap();
416+
let _ = block_data_tx.send(Some(block_data));
417+
});
418+
let res = retrieve_block_data_pool.join();
419+
res
420+
}
421+
})
422+
.expect("unable to spawn thread");
423+
424+
let handle_2 = hiro_system_kit::thread_named("Block data compression")
425+
.spawn(move || {
426+
while let Ok(Some(block_data)) = block_data_rx.recv() {
427+
let block_compressed_tx_moved = block_compressed_tx.clone();
428+
compress_block_data_pool.execute(move || {
429+
let compressed_block = CompactedBlock::from_full_block(&block_data);
430+
let _ = block_compressed_tx_moved
431+
.send(Some((block_data.height as u32, compressed_block)));
432+
});
461433

462-
let res = compress_block_data_pool.join();
463-
// let _ = block_compressed_tx.send(None);
464-
res
465-
}
466-
}).expect("unable to spawn thread");
434+
let res = compress_block_data_pool.join();
435+
// let _ = block_compressed_tx.send(None);
436+
res
437+
}
438+
})
439+
.expect("unable to spawn thread");
467440

468441
let mut blocks_stored = 0;
469442
while let Ok(Some((block_height, compacted_block))) = block_compressed_rx.recv() {
470443
ctx.try_log(|logger| slog::info!(logger, "Storing block #{block_height}"));
471444
write_compacted_block_to_index(block_height, &compacted_block, &storage_conn, &ctx);
472-
blocks_stored+= 1;
445+
blocks_stored += 1;
473446
if blocks_stored == end_block - start_block {
474447
let _ = block_data_tx.send(None);
475448
let _ = block_hash_tx.send(None);
476-
ctx.try_log(|logger| slog::info!(logger, "Local ordinals storage successfully seeded with #{blocks_stored} blocks"));
477-
return Ok(())
449+
ctx.try_log(|logger| {
450+
slog::info!(
451+
logger,
452+
"Local ordinals storage successfully seeded with #{blocks_stored} blocks"
453+
)
454+
});
455+
return Ok(());
478456
}
479457
}
480458

@@ -488,7 +466,7 @@ pub fn retrieve_satoshi_point_using_local_storage(
488466
block_identifier: &BlockIdentifier,
489467
transaction_identifier: &TransactionIdentifier,
490468
ctx: &Context,
491-
) -> Result<(u64, u64), String> {
469+
) -> Result<(u64, u64, u64), String> {
492470
let mut ordinal_offset = 0;
493471
let mut ordinal_block_number = block_identifier.index as u32;
494472
let txid = {
@@ -505,20 +483,23 @@ pub fn retrieve_satoshi_point_using_local_storage(
505483
}
506484
};
507485

486+
let coinbase_txid = &res.0 .0 .0;
487+
let txid = tx_cursor.0;
488+
508489
ctx.try_log(|logger| {
509-
slog::debug!(
490+
slog::info!(
510491
logger,
511492
"{ordinal_block_number}:{:?}:{:?}",
512-
hex::encode(&res.0 .0 .0),
513-
hex::encode(txid)
493+
hex::encode(&coinbase_txid),
494+
hex::encode(&txid)
514495
)
515496
});
516497

498+
// to remove
517499
std::thread::sleep(std::time::Duration::from_millis(300));
518500

519-
// evaluate exit condition: did we reach a coinbase transaction?
520-
let coinbase_txid = &res.0 .0 .0;
521-
if coinbase_txid.eq(&tx_cursor.0) {
501+
// evaluate exit condition: did we reach the **final** coinbase transaction
502+
if coinbase_txid.eq(&txid) {
522503
let coinbase_value = &res.0 .0 .1;
523504
if ordinal_offset.lt(coinbase_value) {
524505
break;
@@ -527,7 +508,7 @@ pub fn retrieve_satoshi_point_using_local_storage(
527508
// loop over the transaction fees to detect the right range
528509
let cut_off = ordinal_offset - coinbase_value;
529510
let mut accumulated_fees = 0;
530-
for (txid, inputs, outputs) in res.0 .1 {
511+
for (_, inputs, outputs) in res.0 .1 {
531512
let mut total_in = 0;
532513
for (_, _, _, input_value) in inputs.iter() {
533514
total_in += input_value;
@@ -559,14 +540,14 @@ pub fn retrieve_satoshi_point_using_local_storage(
559540
}
560541
} else {
561542
// isolate the target transaction
562-
for (txid, inputs, outputs) in res.0 .1 {
543+
for (txid_n, inputs, outputs) in res.0 .1 {
563544
// we iterate over the transactions, looking for the transaction target
564-
if !txid.eq(&tx_cursor.0) {
545+
if !txid_n.eq(&txid) {
565546
continue;
566547
}
567548

568549
ctx.try_log(|logger| {
569-
slog::debug!(logger, "Evaluating {}: {:?}", hex::encode(&txid), outputs)
550+
slog::info!(logger, "Evaluating {}: {:?}", hex::encode(&txid_n), outputs)
570551
});
571552

572553
let mut sats_out = 0;
@@ -575,21 +556,35 @@ pub fn retrieve_satoshi_point_using_local_storage(
575556
break;
576557
}
577558
ctx.try_log(|logger| {
578-
slog::debug!(logger, "Adding {} from output #{}", output_value, index)
559+
slog::info!(logger, "Adding {} from output #{}", output_value, index)
579560
});
580561
sats_out += output_value;
581562
}
582563
sats_out += ordinal_offset;
564+
ctx.try_log(|logger| {
565+
slog::info!(
566+
logger,
567+
"Adding offset {ordinal_offset} to sats_out {sats_out}"
568+
)
569+
});
583570

584571
let mut sats_in = 0;
585572
for (txin, block_height, vout, txin_value) in inputs.into_iter() {
586573
sats_in += txin_value;
574+
ctx.try_log(|logger| {
575+
slog::info!(
576+
logger,
577+
"Adding txin_value {txin_value} to sats_in {sats_in} (txin: {})",
578+
hex::encode(&txin)
579+
)
580+
});
581+
587582
if sats_in >= sats_out {
588583
ordinal_offset = sats_out - (sats_in - txin_value);
589584
ordinal_block_number = block_height;
590585

591586
ctx.try_log(|logger| slog::debug!(logger, "Block {ordinal_block_number} / Tx {} / [in:{sats_in}, out:{sats_out}]: {block_height} -> {ordinal_block_number}:{ordinal_offset} -> {}:{vout}",
592-
hex::encode(&txid),
587+
hex::encode(&txid_n),
593588
hex::encode(&txin)));
594589
tx_cursor = (txin, vout as usize);
595590
break;
@@ -598,6 +593,9 @@ pub fn retrieve_satoshi_point_using_local_storage(
598593
}
599594
}
600595
}
601-
Ok((ordinal_block_number.into(), ordinal_offset))
602-
}
603596

597+
let height = Height(ordinal_block_number.into());
598+
let ordinal_number = height.starting_sat().0 + ordinal_offset;
599+
600+
Ok((ordinal_block_number.into(), ordinal_offset, ordinal_number))
601+
}

0 commit comments

Comments
 (0)