mirror of
https://github.com/alexgo-io/bitcoin-indexer.git
synced 2026-01-12 08:34:17 +08:00
feat: update inscription transfer logic
This commit is contained in:
@@ -16,6 +16,8 @@ use crate::{
|
||||
utils::Context,
|
||||
};
|
||||
|
||||
use super::ord::height::Height;
|
||||
|
||||
fn get_default_ordinals_db_file_path(base_dir: &PathBuf) -> PathBuf {
|
||||
let mut destination_path = base_dir.clone();
|
||||
destination_path.push("bitcoin_block_traversal.sqlite");
|
||||
@@ -54,9 +56,9 @@ pub fn initialize_ordinal_state_storage(path: &PathBuf, ctx: &Context) -> Connec
|
||||
"CREATE TABLE IF NOT EXISTS inscriptions (
|
||||
inscription_id TEXT NOT NULL PRIMARY KEY,
|
||||
outpoint_to_watch TEXT NOT NULL,
|
||||
satoshi_id TEXT NOT NULL,
|
||||
ordinal_number INTEGER NOT NULL,
|
||||
inscription_number INTEGER NOT NULL,
|
||||
offset NOT NULL
|
||||
offset INTEGER NOT NULL
|
||||
)",
|
||||
[],
|
||||
) {
|
||||
@@ -69,7 +71,7 @@ pub fn initialize_ordinal_state_storage(path: &PathBuf, ctx: &Context) -> Connec
|
||||
ctx.try_log(|logger| slog::error!(logger, "{}", e.to_string()));
|
||||
}
|
||||
if let Err(e) = conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS index_inscriptions_on_satoshi_id ON inscriptions(satoshi_id);",
|
||||
"CREATE INDEX IF NOT EXISTS index_inscriptions_on_ordinal_number ON inscriptions(ordinal_number);",
|
||||
[],
|
||||
) {
|
||||
ctx.try_log(|logger| slog::error!(logger, "{}", e.to_string()));
|
||||
@@ -240,7 +242,7 @@ pub fn retrieve_compacted_block_from_index(
|
||||
) -> Option<CompactedBlock> {
|
||||
let args: &[&dyn ToSql] = &[&block_id.to_sql().unwrap()];
|
||||
let mut stmt = storage_conn
|
||||
.prepare("SELECT compacted_bytes FROM blocks WHERE id = ?1")
|
||||
.prepare("SELECT compacted_bytes FROM blocks WHERE id = ?")
|
||||
.unwrap();
|
||||
let result_iter = stmt
|
||||
.query_map(args, |row| {
|
||||
@@ -255,35 +257,14 @@ pub fn retrieve_compacted_block_from_index(
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn scan_existing_inscriptions_id(
|
||||
inscription_id: &str,
|
||||
storage_conn: &Connection,
|
||||
) -> Option<String> {
|
||||
let args: &[&dyn ToSql] = &[&inscription_id.to_sql().unwrap()];
|
||||
let mut stmt = storage_conn
|
||||
.prepare("SELECT inscription_id FROM inscriptions WHERE inscription_id = ?1")
|
||||
.unwrap();
|
||||
let result_iter = stmt
|
||||
.query_map(args, |row| {
|
||||
let inscription_id: String = row.get(0).unwrap();
|
||||
Ok(inscription_id)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
for result in result_iter {
|
||||
return Some(result.unwrap());
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn store_new_inscription(
|
||||
inscription_data: &OrdinalInscriptionRevealData,
|
||||
storage_conn: &Connection,
|
||||
ctx: &Context,
|
||||
) {
|
||||
if let Err(e) = storage_conn.execute(
|
||||
"INSERT INTO inscriptions (inscription_id, outpoint_to_watch, satoshi_id, inscription_number) VALUES (?1, ?2)",
|
||||
rusqlite::params![&inscription_data.inscription_id, &inscription_data.outpoint_post_inscription, &inscription_data.inscription_id, &inscription_data.inscription_id],
|
||||
"INSERT INTO inscriptions (inscription_id, outpoint_to_watch, ordinal_number, inscription_number, offset) VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
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],
|
||||
) {
|
||||
ctx.try_log(|logger| slog::error!(logger, "{}", e.to_string()));
|
||||
}
|
||||
@@ -297,7 +278,7 @@ pub fn update_transfered_inscription(
|
||||
ctx: &Context,
|
||||
) {
|
||||
if let Err(e) = storage_conn.execute(
|
||||
"UPDATE inscriptions SET outpoint_to_watch = ?1, offset = ?2 WHERE inscription_id = ?3",
|
||||
"UPDATE inscriptions SET outpoint_to_watch = ?, offset = ? WHERE inscription_id = ?",
|
||||
rusqlite::params![&outpoint_post_transfer, &offset, &inscription_id],
|
||||
) {
|
||||
ctx.try_log(|logger| slog::error!(logger, "{}", e.to_string()));
|
||||
@@ -314,61 +295,48 @@ pub fn find_last_inscription_number(
|
||||
"SELECT inscription_number FROM inscriptions ORDER BY inscription_number DESC LIMIT 1",
|
||||
)
|
||||
.unwrap();
|
||||
let result_iter = stmt
|
||||
.query_map(args, |row| {
|
||||
let inscription_number: u64 = row.get(0).unwrap();
|
||||
Ok(inscription_number)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
for result in result_iter {
|
||||
return Ok(result.unwrap());
|
||||
let mut rows = stmt.query(args).unwrap();
|
||||
while let Ok(Some(row)) = rows.next() {
|
||||
let inscription_number: u64 = row.get(0).unwrap();
|
||||
return Ok(inscription_number);
|
||||
}
|
||||
return Ok(0);
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn find_inscription_with_satoshi_id(
|
||||
satoshi_id: &str,
|
||||
pub fn find_inscription_with_ordinal_number(
|
||||
ordinal_number: &u64,
|
||||
storage_conn: &Connection,
|
||||
ctx: &Context,
|
||||
) -> Option<String> {
|
||||
let args: &[&dyn ToSql] = &[&satoshi_id.to_sql().unwrap()];
|
||||
let args: &[&dyn ToSql] = &[&ordinal_number.to_sql().unwrap()];
|
||||
let mut stmt = storage_conn
|
||||
.prepare("SELECT inscription_id FROM inscriptions WHERE satoshi_id = ?1")
|
||||
.prepare("SELECT inscription_id FROM inscriptions WHERE ordinal_number = ?")
|
||||
.unwrap();
|
||||
let result_iter = stmt
|
||||
.query_map(args, |row| {
|
||||
let inscription_id: String = row.get(0).unwrap();
|
||||
Ok(inscription_id)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
for result in result_iter {
|
||||
return Some(result.unwrap());
|
||||
let mut rows = stmt.query(args).unwrap();
|
||||
while let Ok(Some(row)) = rows.next() {
|
||||
let inscription_id: String = row.get(0).unwrap();
|
||||
return Some(inscription_id);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn find_inscriptions_at_wached_outpoint(
|
||||
txin: &str,
|
||||
outpoint: &str,
|
||||
storage_conn: &Connection,
|
||||
) -> Vec<(String, u64, String, u64)> {
|
||||
let args: &[&dyn ToSql] = &[&txin.to_sql().unwrap()];
|
||||
) -> Vec<(String, u64, u64, u64)> {
|
||||
let args: &[&dyn ToSql] = &[&outpoint.to_sql().unwrap()];
|
||||
let mut stmt = storage_conn
|
||||
.prepare("SELECT inscription_id, inscription_number, satoshi_id, offset FROM inscriptions WHERE outpoint_to_watch = ?1 ORDER BY offset ASC")
|
||||
.prepare("SELECT inscription_id, inscription_number, ordinal_number, offset FROM inscriptions WHERE outpoint_to_watch = ? ORDER BY offset ASC")
|
||||
.unwrap();
|
||||
let mut results = vec![];
|
||||
let result_iter = stmt
|
||||
.query_map(args, |row| {
|
||||
let inscription_id: String = row.get(0).unwrap();
|
||||
let inscription_number: u64 = row.get(1).unwrap();
|
||||
let satoshi_id: String = row.get(2).unwrap();
|
||||
let offset: u64 = row.get(1).unwrap();
|
||||
results.push((inscription_id, inscription_number, satoshi_id, offset));
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let mut rows = stmt.query(args).unwrap();
|
||||
while let Ok(Some(row)) = rows.next() {
|
||||
let inscription_id: String = row.get(0).unwrap();
|
||||
let inscription_number: u64 = row.get(1).unwrap();
|
||||
let ordinal_number: u64 = row.get(2).unwrap();
|
||||
let offset: u64 = row.get(3).unwrap();
|
||||
results.push((inscription_id, inscription_number, ordinal_number, offset));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -430,51 +398,61 @@ pub async fn build_bitcoin_traversal_local_storage(
|
||||
let bitcoin_config = bitcoin_config.clone();
|
||||
let moved_ctx = ctx.clone();
|
||||
let block_data_tx_moved = block_data_tx.clone();
|
||||
let handle_1 = hiro_system_kit::thread_named("Block data retrieval").spawn(move || {
|
||||
while let Ok(Some((block_height, block_hash))) = block_hash_rx.recv() {
|
||||
let moved_bitcoin_config = bitcoin_config.clone();
|
||||
let block_data_tx = block_data_tx_moved.clone();
|
||||
let moved_ctx = moved_ctx.clone();
|
||||
retrieve_block_data_pool.execute(move || {
|
||||
moved_ctx.try_log(|logger| slog::info!(logger, "Fetching block #{block_height}"));
|
||||
let future = retrieve_full_block_breakdown_with_retry(
|
||||
&moved_bitcoin_config,
|
||||
&block_hash,
|
||||
&moved_ctx,
|
||||
);
|
||||
let block_data = hiro_system_kit::nestable_block_on(future).unwrap();
|
||||
let _ = block_data_tx.send(Some(block_data));
|
||||
});
|
||||
let res = retrieve_block_data_pool.join();
|
||||
res
|
||||
}
|
||||
}).expect("unable to spawn thread");
|
||||
let handle_1 = hiro_system_kit::thread_named("Block data retrieval")
|
||||
.spawn(move || {
|
||||
while let Ok(Some((block_height, block_hash))) = block_hash_rx.recv() {
|
||||
let moved_bitcoin_config = bitcoin_config.clone();
|
||||
let block_data_tx = block_data_tx_moved.clone();
|
||||
let moved_ctx = moved_ctx.clone();
|
||||
retrieve_block_data_pool.execute(move || {
|
||||
moved_ctx
|
||||
.try_log(|logger| slog::info!(logger, "Fetching block #{block_height}"));
|
||||
let future = retrieve_full_block_breakdown_with_retry(
|
||||
&moved_bitcoin_config,
|
||||
&block_hash,
|
||||
&moved_ctx,
|
||||
);
|
||||
let block_data = hiro_system_kit::nestable_block_on(future).unwrap();
|
||||
let _ = block_data_tx.send(Some(block_data));
|
||||
});
|
||||
let res = retrieve_block_data_pool.join();
|
||||
res
|
||||
}
|
||||
})
|
||||
.expect("unable to spawn thread");
|
||||
|
||||
let handle_2 = hiro_system_kit::thread_named("Block data compression").spawn(move || {
|
||||
while let Ok(Some(block_data)) = block_data_rx.recv() {
|
||||
let block_compressed_tx_moved = block_compressed_tx.clone();
|
||||
compress_block_data_pool.execute(move || {
|
||||
let compressed_block = CompactedBlock::from_full_block(&block_data);
|
||||
let _ = block_compressed_tx_moved
|
||||
.send(Some((block_data.height as u32, compressed_block)));
|
||||
});
|
||||
let handle_2 = hiro_system_kit::thread_named("Block data compression")
|
||||
.spawn(move || {
|
||||
while let Ok(Some(block_data)) = block_data_rx.recv() {
|
||||
let block_compressed_tx_moved = block_compressed_tx.clone();
|
||||
compress_block_data_pool.execute(move || {
|
||||
let compressed_block = CompactedBlock::from_full_block(&block_data);
|
||||
let _ = block_compressed_tx_moved
|
||||
.send(Some((block_data.height as u32, compressed_block)));
|
||||
});
|
||||
|
||||
let res = compress_block_data_pool.join();
|
||||
// let _ = block_compressed_tx.send(None);
|
||||
res
|
||||
}
|
||||
}).expect("unable to spawn thread");
|
||||
let res = compress_block_data_pool.join();
|
||||
// let _ = block_compressed_tx.send(None);
|
||||
res
|
||||
}
|
||||
})
|
||||
.expect("unable to spawn thread");
|
||||
|
||||
let mut blocks_stored = 0;
|
||||
while let Ok(Some((block_height, compacted_block))) = block_compressed_rx.recv() {
|
||||
ctx.try_log(|logger| slog::info!(logger, "Storing block #{block_height}"));
|
||||
write_compacted_block_to_index(block_height, &compacted_block, &storage_conn, &ctx);
|
||||
blocks_stored+= 1;
|
||||
blocks_stored += 1;
|
||||
if blocks_stored == end_block - start_block {
|
||||
let _ = block_data_tx.send(None);
|
||||
let _ = block_hash_tx.send(None);
|
||||
ctx.try_log(|logger| slog::info!(logger, "Local ordinals storage successfully seeded with #{blocks_stored} blocks"));
|
||||
return Ok(())
|
||||
ctx.try_log(|logger| {
|
||||
slog::info!(
|
||||
logger,
|
||||
"Local ordinals storage successfully seeded with #{blocks_stored} blocks"
|
||||
)
|
||||
});
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,7 +466,7 @@ pub fn retrieve_satoshi_point_using_local_storage(
|
||||
block_identifier: &BlockIdentifier,
|
||||
transaction_identifier: &TransactionIdentifier,
|
||||
ctx: &Context,
|
||||
) -> Result<(u64, u64), String> {
|
||||
) -> Result<(u64, u64, u64), String> {
|
||||
let mut ordinal_offset = 0;
|
||||
let mut ordinal_block_number = block_identifier.index as u32;
|
||||
let txid = {
|
||||
@@ -505,20 +483,23 @@ pub fn retrieve_satoshi_point_using_local_storage(
|
||||
}
|
||||
};
|
||||
|
||||
let coinbase_txid = &res.0 .0 .0;
|
||||
let txid = tx_cursor.0;
|
||||
|
||||
ctx.try_log(|logger| {
|
||||
slog::debug!(
|
||||
slog::info!(
|
||||
logger,
|
||||
"{ordinal_block_number}:{:?}:{:?}",
|
||||
hex::encode(&res.0 .0 .0),
|
||||
hex::encode(txid)
|
||||
hex::encode(&coinbase_txid),
|
||||
hex::encode(&txid)
|
||||
)
|
||||
});
|
||||
|
||||
// to remove
|
||||
std::thread::sleep(std::time::Duration::from_millis(300));
|
||||
|
||||
// evaluate exit condition: did we reach a coinbase transaction?
|
||||
let coinbase_txid = &res.0 .0 .0;
|
||||
if coinbase_txid.eq(&tx_cursor.0) {
|
||||
// evaluate exit condition: did we reach the **final** coinbase transaction
|
||||
if coinbase_txid.eq(&txid) {
|
||||
let coinbase_value = &res.0 .0 .1;
|
||||
if ordinal_offset.lt(coinbase_value) {
|
||||
break;
|
||||
@@ -527,7 +508,7 @@ pub fn retrieve_satoshi_point_using_local_storage(
|
||||
// loop over the transaction fees to detect the right range
|
||||
let cut_off = ordinal_offset - coinbase_value;
|
||||
let mut accumulated_fees = 0;
|
||||
for (txid, inputs, outputs) in res.0 .1 {
|
||||
for (_, inputs, outputs) in res.0 .1 {
|
||||
let mut total_in = 0;
|
||||
for (_, _, _, input_value) in inputs.iter() {
|
||||
total_in += input_value;
|
||||
@@ -559,14 +540,14 @@ pub fn retrieve_satoshi_point_using_local_storage(
|
||||
}
|
||||
} else {
|
||||
// isolate the target transaction
|
||||
for (txid, inputs, outputs) in res.0 .1 {
|
||||
for (txid_n, inputs, outputs) in res.0 .1 {
|
||||
// we iterate over the transactions, looking for the transaction target
|
||||
if !txid.eq(&tx_cursor.0) {
|
||||
if !txid_n.eq(&txid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx.try_log(|logger| {
|
||||
slog::debug!(logger, "Evaluating {}: {:?}", hex::encode(&txid), outputs)
|
||||
slog::info!(logger, "Evaluating {}: {:?}", hex::encode(&txid_n), outputs)
|
||||
});
|
||||
|
||||
let mut sats_out = 0;
|
||||
@@ -575,21 +556,35 @@ pub fn retrieve_satoshi_point_using_local_storage(
|
||||
break;
|
||||
}
|
||||
ctx.try_log(|logger| {
|
||||
slog::debug!(logger, "Adding {} from output #{}", output_value, index)
|
||||
slog::info!(logger, "Adding {} from output #{}", output_value, index)
|
||||
});
|
||||
sats_out += output_value;
|
||||
}
|
||||
sats_out += ordinal_offset;
|
||||
ctx.try_log(|logger| {
|
||||
slog::info!(
|
||||
logger,
|
||||
"Adding offset {ordinal_offset} to sats_out {sats_out}"
|
||||
)
|
||||
});
|
||||
|
||||
let mut sats_in = 0;
|
||||
for (txin, block_height, vout, txin_value) in inputs.into_iter() {
|
||||
sats_in += txin_value;
|
||||
ctx.try_log(|logger| {
|
||||
slog::info!(
|
||||
logger,
|
||||
"Adding txin_value {txin_value} to sats_in {sats_in} (txin: {})",
|
||||
hex::encode(&txin)
|
||||
)
|
||||
});
|
||||
|
||||
if sats_in >= sats_out {
|
||||
ordinal_offset = sats_out - (sats_in - txin_value);
|
||||
ordinal_block_number = block_height;
|
||||
|
||||
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}",
|
||||
hex::encode(&txid),
|
||||
hex::encode(&txid_n),
|
||||
hex::encode(&txin)));
|
||||
tx_cursor = (txin, vout as usize);
|
||||
break;
|
||||
@@ -598,6 +593,9 @@ pub fn retrieve_satoshi_point_using_local_storage(
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((ordinal_block_number.into(), ordinal_offset))
|
||||
}
|
||||
|
||||
let height = Height(ordinal_block_number.into());
|
||||
let ordinal_number = height.starting_sat().0 + ordinal_offset;
|
||||
|
||||
Ok((ordinal_block_number.into(), ordinal_offset, ordinal_number))
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ use crate::chainhooks::types::{
|
||||
};
|
||||
use crate::indexer::bitcoin::{retrieve_full_block_breakdown_with_retry, NewBitcoinBlock};
|
||||
use crate::indexer::ordinals::db::{
|
||||
find_inscription_with_satoshi_id, find_inscriptions_at_wached_outpoint,
|
||||
find_inscription_with_ordinal_number, find_inscriptions_at_wached_outpoint,
|
||||
find_last_inscription_number, initialize_ordinal_state_storage, open_readonly_ordinals_db_conn,
|
||||
open_readwrite_ordinals_db_conn, retrieve_satoshi_point_using_local_storage,
|
||||
scan_existing_inscriptions_id, store_new_inscription, update_transfered_inscription,
|
||||
write_compacted_block_to_index, CompactedBlock,
|
||||
store_new_inscription, update_transfered_inscription, write_compacted_block_to_index,
|
||||
CompactedBlock,
|
||||
};
|
||||
use crate::indexer::ordinals::ord::height::Height;
|
||||
use crate::indexer::ordinals::ord::{
|
||||
@@ -520,18 +520,39 @@ pub async fn start_observer_commands_handler(
|
||||
match chain_event {
|
||||
BitcoinChainEvent::ChainUpdatedWithBlocks(ref mut new_blocks) => {
|
||||
// Look for inscription transfered
|
||||
let storage_conn =
|
||||
open_readonly_ordinals_db_conn(&config.get_cache_path_buf(), &ctx)
|
||||
.unwrap(); // TODO(lgalabru)
|
||||
|
||||
for new_block in new_blocks.new_blocks.iter_mut() {
|
||||
let mut coinbase_offset = 0;
|
||||
// Persist compacted block in table blocks
|
||||
{
|
||||
ctx.try_log(|logger| {
|
||||
slog::info!(
|
||||
logger,
|
||||
"Persisting in local storage Bitcoin block #{} for further traversals",
|
||||
new_block.block_identifier.index,
|
||||
)
|
||||
});
|
||||
|
||||
let compacted_block =
|
||||
CompactedBlock::from_standardized_block(&new_block);
|
||||
let storage_rw_conn = open_readwrite_ordinals_db_conn(
|
||||
&config.get_cache_path_buf(),
|
||||
&ctx,
|
||||
)
|
||||
.unwrap(); // TODO(lgalabru)
|
||||
write_compacted_block_to_index(
|
||||
new_block.block_identifier.index as u32,
|
||||
&compacted_block,
|
||||
&storage_rw_conn,
|
||||
&ctx,
|
||||
);
|
||||
}
|
||||
|
||||
let mut cumulated_fees = 0;
|
||||
let coinbase_txid = &new_block.transactions[0]
|
||||
.transaction_identifier
|
||||
.hash
|
||||
.clone();
|
||||
let coinbase_subsidy =
|
||||
Height(new_block.block_identifier.index).subsidy();
|
||||
let first_sat_post_subsidy =
|
||||
Height(new_block.block_identifier.index).starting_sat().0;
|
||||
|
||||
for new_tx in new_block.transactions.iter_mut().skip(1) {
|
||||
let mut ordinals_events_indexes_to_discard = VecDeque::new();
|
||||
@@ -542,34 +563,50 @@ pub async fn start_observer_commands_handler(
|
||||
if let OrdinalOperation::InscriptionRevealed(inscription) =
|
||||
ordinal_event
|
||||
{
|
||||
// Are we looking at a re-inscription?
|
||||
let res = retrieve_satoshi_point_using_local_storage(
|
||||
&storage_conn,
|
||||
&new_block.block_identifier,
|
||||
&new_tx.transaction_identifier,
|
||||
let storage_conn = open_readonly_ordinals_db_conn(
|
||||
&config.get_cache_path_buf(),
|
||||
&ctx,
|
||||
);
|
||||
let (block_height, offset) = match res {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
continue;
|
||||
)
|
||||
.unwrap(); // TODO(lgalabru)
|
||||
|
||||
let (ordinal_block_height, ordinal_offset, ordinal_number) = {
|
||||
// Are we looking at a re-inscription?
|
||||
let res = retrieve_satoshi_point_using_local_storage(
|
||||
&storage_conn,
|
||||
&new_block.block_identifier,
|
||||
&new_tx.transaction_identifier,
|
||||
&ctx,
|
||||
);
|
||||
|
||||
match res {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
ctx.try_log(|logger| {
|
||||
slog::error!(
|
||||
logger,
|
||||
"unable to retrieve satoshi point: {}",
|
||||
e.to_string()
|
||||
);
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
let satoshi_id = format!("{}:{}", block_height, offset);
|
||||
if let Some(entry) = find_inscription_with_satoshi_id(
|
||||
&satoshi_id,
|
||||
|
||||
if let Some(_entry) = find_inscription_with_ordinal_number(
|
||||
&ordinal_number,
|
||||
&storage_conn,
|
||||
&ctx,
|
||||
) {
|
||||
ctx.try_log(|logger| {
|
||||
slog::warn!(logger, "Transaction {} in block {} is overriding an existing inscription {}", new_tx.transaction_identifier.hash, new_block.block_identifier.index, satoshi_id);
|
||||
slog::warn!(logger, "Transaction {} in block {} is overriding an existing inscription {}", new_tx.transaction_identifier.hash, new_block.block_identifier.index, ordinal_number);
|
||||
});
|
||||
ordinals_events_indexes_to_discard
|
||||
.push_front(ordinal_event_index);
|
||||
} else {
|
||||
inscription.ordinal_block_height = block_height;
|
||||
inscription.ordinal_offset = offset;
|
||||
inscription.ordinal_number = 0;
|
||||
inscription.ordinal_offset = ordinal_offset;
|
||||
inscription.ordinal_block_height = ordinal_block_height;
|
||||
inscription.ordinal_number = ordinal_number;
|
||||
inscription.inscription_number =
|
||||
match find_last_inscription_number(
|
||||
&storage_conn,
|
||||
@@ -577,11 +614,14 @@ pub async fn start_observer_commands_handler(
|
||||
) {
|
||||
Ok(inscription_number) => inscription_number,
|
||||
Err(e) => {
|
||||
ctx.try_log(|logger| {
|
||||
slog::error!(logger, "unable to retrieve satoshi number: {}", e.to_string());
|
||||
});
|
||||
continue;
|
||||
}
|
||||
};
|
||||
ctx.try_log(|logger| {
|
||||
slog::info!(logger, "Transaction {} in block {} inclues a new inscription {}", new_tx.transaction_identifier.hash, new_block.block_identifier.index, satoshi_id);
|
||||
slog::info!(logger, "Transaction {} in block {} includes a new inscription {}", new_tx.transaction_identifier.hash, new_block.block_identifier.index, ordinal_number);
|
||||
});
|
||||
|
||||
{
|
||||
@@ -604,26 +644,57 @@ pub async fn start_observer_commands_handler(
|
||||
// Have inscriptions been transfered?
|
||||
let mut sats_in_offset = 0;
|
||||
let mut sats_out_offset = 0;
|
||||
let storage_conn = open_readonly_ordinals_db_conn(
|
||||
&config.get_cache_path_buf(),
|
||||
&ctx,
|
||||
)
|
||||
.unwrap(); // TODO(lgalabru)
|
||||
|
||||
for input in new_tx.metadata.inputs.iter() {
|
||||
// input.previous_output.txid
|
||||
let outpoint_pre_transfer = format!(
|
||||
"{}:{}",
|
||||
input.previous_output.txid, input.previous_output.vout
|
||||
&input.previous_output.txid[2..],
|
||||
input.previous_output.vout
|
||||
);
|
||||
|
||||
let mut post_transfer_output_index = 0;
|
||||
let mut post_transfer_offset = 0;
|
||||
|
||||
for (inscription_id, inscription_number, satoshi_id, offset) in
|
||||
find_inscriptions_at_wached_outpoint(
|
||||
&outpoint_pre_transfer,
|
||||
&ordinals_db_conn,
|
||||
let entries = find_inscriptions_at_wached_outpoint(
|
||||
&outpoint_pre_transfer,
|
||||
&storage_conn,
|
||||
);
|
||||
|
||||
ctx.try_log(|logger| {
|
||||
slog::info!(
|
||||
logger,
|
||||
"Checking if {} is part of our watch outpoints set: {}",
|
||||
outpoint_pre_transfer,
|
||||
entries.len(),
|
||||
)
|
||||
.into_iter()
|
||||
{
|
||||
// At this point we know that inscriptions are being moved.
|
||||
// Question is: are inscriptions moving to a new output, burnt or lost in fees and transfered to the miner?
|
||||
});
|
||||
|
||||
for (
|
||||
inscription_id,
|
||||
inscription_number,
|
||||
ordinal_number,
|
||||
offset,
|
||||
) in entries.into_iter()
|
||||
{
|
||||
let satpoint_pre_transfer =
|
||||
format!("{}:{}", outpoint_pre_transfer, offset);
|
||||
// At this point we know that inscriptions are being moved.
|
||||
ctx.try_log(|logger| {
|
||||
slog::info!(
|
||||
logger,
|
||||
"Detected transaction {} involving txin {} that includes watched ordinals",
|
||||
new_tx.transaction_identifier.hash,
|
||||
satpoint_pre_transfer,
|
||||
)
|
||||
});
|
||||
|
||||
// Question is: are inscriptions moving to a new output,
|
||||
// burnt or lost in fees and transfered to the miner?
|
||||
let post_transfer_output = loop {
|
||||
if sats_out_offset >= sats_in_offset + offset {
|
||||
break Some(post_transfer_output_index);
|
||||
@@ -647,7 +718,8 @@ pub async fn start_observer_commands_handler(
|
||||
Some(index) => {
|
||||
let outpoint = format!(
|
||||
"{}:{}",
|
||||
new_tx.transaction_identifier.hash, index
|
||||
&new_tx.transaction_identifier.hash[2..],
|
||||
index
|
||||
);
|
||||
let offset = 0;
|
||||
let script_pub_key_hex = new_tx.metadata.outputs
|
||||
@@ -678,17 +750,21 @@ pub async fn start_observer_commands_handler(
|
||||
}
|
||||
None => {
|
||||
// Get Coinbase TX
|
||||
let offset = coinbase_subsidy + coinbase_offset;
|
||||
let offset =
|
||||
first_sat_post_subsidy + cumulated_fees;
|
||||
let outpoint = coinbase_txid.clone();
|
||||
(outpoint, offset, None)
|
||||
}
|
||||
};
|
||||
|
||||
// Compute the offset / new txin:vout to watch
|
||||
let outpoint_post_transfer = format!(
|
||||
"{}:{}",
|
||||
input.previous_output.txid, input.previous_output.vout
|
||||
);
|
||||
ctx.try_log(|logger| {
|
||||
slog::info!(
|
||||
logger,
|
||||
"Updating watched outpoint {} to outpoint {}",
|
||||
outpoint_post_transfer,
|
||||
outpoint_pre_transfer,
|
||||
)
|
||||
});
|
||||
|
||||
// Update watched outpoint
|
||||
{
|
||||
@@ -706,13 +782,18 @@ pub async fn start_observer_commands_handler(
|
||||
);
|
||||
}
|
||||
|
||||
let satpoint_post_transfer = format!(
|
||||
"{}:{}",
|
||||
outpoint_post_transfer, offset_post_transfer
|
||||
);
|
||||
|
||||
let event_data = OrdinalInscriptionTransferData {
|
||||
inscription_id,
|
||||
inscription_number,
|
||||
satoshi_id,
|
||||
ordinal_number,
|
||||
updated_address,
|
||||
outpoint_pre_transfer: outpoint_pre_transfer.clone(),
|
||||
outpoint_post_transfer,
|
||||
satpoint_pre_transfer,
|
||||
satpoint_post_transfer,
|
||||
};
|
||||
|
||||
// Attach transfer event
|
||||
@@ -729,32 +810,7 @@ pub async fn start_observer_commands_handler(
|
||||
new_tx.metadata.ordinal_operations.remove(index);
|
||||
}
|
||||
|
||||
coinbase_offset += new_tx.metadata.fee;
|
||||
}
|
||||
|
||||
// Persist compacted block in table blocks
|
||||
{
|
||||
ctx.try_log(|logger| {
|
||||
slog::info!(
|
||||
logger,
|
||||
"Caching Bitcoin block #{} for further traversals",
|
||||
new_block.block_identifier.index
|
||||
)
|
||||
});
|
||||
|
||||
let compacted_block =
|
||||
CompactedBlock::from_standardized_block(&new_block);
|
||||
let storage_rw_conn = open_readwrite_ordinals_db_conn(
|
||||
&config.get_cache_path_buf(),
|
||||
&ctx,
|
||||
)
|
||||
.unwrap(); // TODO(lgalabru)
|
||||
write_compacted_block_to_index(
|
||||
new_block.block_identifier.index as u32,
|
||||
&compacted_block,
|
||||
&storage_rw_conn,
|
||||
&ctx,
|
||||
);
|
||||
cumulated_fees += new_tx.metadata.fee;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,10 +284,10 @@ pub enum OrdinalOperation {
|
||||
pub struct OrdinalInscriptionTransferData {
|
||||
pub inscription_number: u64,
|
||||
pub inscription_id: String,
|
||||
pub satoshi_id: String,
|
||||
pub ordinal_number: u64,
|
||||
pub updated_address: Option<String>,
|
||||
pub outpoint_pre_transfer: String,
|
||||
pub outpoint_post_transfer: String,
|
||||
pub satpoint_pre_transfer: String,
|
||||
pub satpoint_post_transfer: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
@@ -302,7 +302,7 @@ pub struct OrdinalInscriptionRevealData {
|
||||
pub ordinal_number: u64,
|
||||
pub ordinal_block_height: u64,
|
||||
pub ordinal_offset: u64,
|
||||
pub outpoint_post_inscription: String,
|
||||
pub satpoint_post_inscription: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
|
||||
Reference in New Issue
Block a user