mirror of
https://github.com/alexgo-io/bitcoin-indexer.git
synced 2026-01-12 22:43:06 +08:00
feat: handle transfer
This commit is contained in:
@@ -15,9 +15,8 @@ use chainhook_event_observer::chainhooks::types::{
|
||||
use chainhook_event_observer::hord::db::{
|
||||
delete_data_in_hord_db, fetch_and_cache_blocks_in_hord_db, find_last_block_inserted,
|
||||
find_lazy_block_at_block_height, find_watched_satpoint_for_inscription, initialize_hord_db,
|
||||
insert_entry_in_blocks, open_readonly_hord_db_conn, open_readonly_hord_db_conn_rocks_db,
|
||||
open_readwrite_hord_db_conn, open_readwrite_hord_db_conn_rocks_db,
|
||||
retrieve_satoshi_point_using_lazy_storage, LazyBlock,
|
||||
open_readonly_hord_db_conn, open_readonly_hord_db_conn_rocks_db, open_readwrite_hord_db_conn,
|
||||
open_readwrite_hord_db_conn_rocks_db, retrieve_satoshi_point_using_lazy_storage,
|
||||
};
|
||||
use chainhook_event_observer::hord::{
|
||||
new_traversals_lazy_cache, retrieve_inscribed_satoshi_points_from_block,
|
||||
@@ -643,6 +642,7 @@ async fn handle_command(opts: Opts, ctx: Context) -> Result<(), String> {
|
||||
&block_identifier,
|
||||
&transaction_identifier,
|
||||
0,
|
||||
0,
|
||||
Arc::new(traversals_cache),
|
||||
&ctx,
|
||||
)?;
|
||||
|
||||
@@ -425,7 +425,7 @@ pub fn find_inscription_with_id(
|
||||
) -> Option<TraversalResult> {
|
||||
let args: &[&dyn ToSql] = &[&inscription_id.to_sql().unwrap()];
|
||||
let mut stmt = inscriptions_db_conn
|
||||
.prepare("SELECT inscription_number, ordinal_number, block_hash FROM inscriptions WHERE inscription_id = ?")
|
||||
.prepare("SELECT inscription_number, ordinal_number, block_hash, offset, outpoint_to_watch FROM inscriptions WHERE inscription_id = ?")
|
||||
.unwrap();
|
||||
let mut rows = stmt.query(args).unwrap();
|
||||
while let Ok(Some(row)) = rows.next() {
|
||||
@@ -433,9 +433,13 @@ pub fn find_inscription_with_id(
|
||||
if block_hash.eq(&inscription_block_hash) {
|
||||
let inscription_number: i64 = row.get(0).unwrap();
|
||||
let ordinal_number: u64 = row.get(1).unwrap();
|
||||
let inscription_offset: u64 = row.get(3).unwrap();
|
||||
let outpoint_to_watch: String = row.get(4).unwrap();
|
||||
let traversal = TraversalResult {
|
||||
inscription_number,
|
||||
ordinal_number,
|
||||
inscription_offset,
|
||||
outpoint_to_watch,
|
||||
transfers: 0,
|
||||
};
|
||||
return Some(traversal);
|
||||
@@ -449,7 +453,7 @@ pub fn find_all_inscriptions(
|
||||
) -> BTreeMap<u64, Vec<(TransactionIdentifier, TraversalResult)>> {
|
||||
let args: &[&dyn ToSql] = &[];
|
||||
let mut stmt = inscriptions_db_conn
|
||||
.prepare("SELECT inscription_number, ordinal_number, block_height, inscription_id FROM inscriptions ORDER BY inscription_number ASC")
|
||||
.prepare("SELECT inscription_number, ordinal_number, block_height, inscription_id, offset, outpoint_to_watch FROM inscriptions ORDER BY inscription_number ASC")
|
||||
.unwrap();
|
||||
let mut results: BTreeMap<u64, Vec<(TransactionIdentifier, TraversalResult)>> = BTreeMap::new();
|
||||
let mut rows = stmt.query(args).unwrap();
|
||||
@@ -463,10 +467,14 @@ pub fn find_all_inscriptions(
|
||||
hash: format!("0x{}", &inscription_id[0..inscription_id.len() - 2]),
|
||||
}
|
||||
};
|
||||
let inscription_offset: u64 = row.get(4).unwrap();
|
||||
let outpoint_to_watch: String = row.get(5).unwrap();
|
||||
let traversal = TraversalResult {
|
||||
inscription_number,
|
||||
ordinal_number,
|
||||
transfers: 0,
|
||||
inscription_offset,
|
||||
outpoint_to_watch,
|
||||
};
|
||||
results
|
||||
.entry(block_height)
|
||||
@@ -817,6 +825,8 @@ pub async fn fetch_and_cache_blocks_in_hord_db(
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TraversalResult {
|
||||
pub inscription_number: i64,
|
||||
pub inscription_offset: u64,
|
||||
pub outpoint_to_watch: String,
|
||||
pub ordinal_number: u64,
|
||||
pub transfers: u32,
|
||||
}
|
||||
@@ -880,6 +890,7 @@ pub fn retrieve_satoshi_point_using_lazy_storage(
|
||||
blocks_db: &DB,
|
||||
block_identifier: &BlockIdentifier,
|
||||
transaction_identifier: &TransactionIdentifier,
|
||||
input_index: usize,
|
||||
inscription_number: i64,
|
||||
traversals_cache: Arc<
|
||||
DashMap<(u32, [u8; 8]), LazyBlockTransaction, BuildHasherDefault<FxHasher>>,
|
||||
@@ -894,16 +905,13 @@ pub fn retrieve_satoshi_point_using_lazy_storage(
|
||||
block_identifier.index
|
||||
)
|
||||
});
|
||||
|
||||
let mut inscription_localized = false;
|
||||
let mut inscription_offset = 0;
|
||||
let mut inscription_output_index: usize = 0;
|
||||
let mut ordinal_offset = 0;
|
||||
let mut ordinal_block_number = block_identifier.index as u32;
|
||||
let txid = {
|
||||
let bytes = hex::decode(&transaction_identifier.hash[2..]).unwrap();
|
||||
[
|
||||
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
|
||||
]
|
||||
};
|
||||
let mut tx_cursor = (txid, 0);
|
||||
let txid = transaction_identifier.get_8_hash_bytes();
|
||||
let mut tx_cursor = (txid, input_index);
|
||||
let mut hops: u32 = 0;
|
||||
loop {
|
||||
hops += 1;
|
||||
@@ -916,6 +924,31 @@ pub fn retrieve_satoshi_point_using_lazy_storage(
|
||||
|
||||
if let Some(cached_tx) = traversals_cache.get(&(ordinal_block_number, tx_cursor.0)) {
|
||||
let tx = cached_tx.value();
|
||||
|
||||
if !inscription_localized {
|
||||
inscription_localized = true;
|
||||
let mut sats_ranges = vec![];
|
||||
let mut bound = 0;
|
||||
for output_value in tx.outputs.iter() {
|
||||
sats_ranges.push((bound, bound + output_value));
|
||||
bound += output_value;
|
||||
}
|
||||
let mut input_offset = 0;
|
||||
for (i, input) in tx.inputs.iter().enumerate() {
|
||||
if i == input_index {
|
||||
break;
|
||||
}
|
||||
input_offset += input.txin_value;
|
||||
}
|
||||
|
||||
for (i, (min, max)) in sats_ranges.into_iter().enumerate() {
|
||||
if input_offset >= min && input_offset < max {
|
||||
inscription_output_index = i;
|
||||
inscription_offset = input_offset - min;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut next_found_in_cache = false;
|
||||
let mut sats_out = 0;
|
||||
for (index, output_value) in tx.outputs.iter().enumerate() {
|
||||
@@ -955,6 +988,11 @@ pub fn retrieve_satoshi_point_using_lazy_storage(
|
||||
inscription_number: 0,
|
||||
ordinal_number: 0,
|
||||
transfers: 0,
|
||||
inscription_offset,
|
||||
outpoint_to_watch: format_outpoint_to_watch(
|
||||
&transaction_identifier,
|
||||
inscription_output_index,
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1022,6 +1060,30 @@ pub fn retrieve_satoshi_point_using_lazy_storage(
|
||||
None => unreachable!(),
|
||||
};
|
||||
|
||||
if !inscription_localized {
|
||||
inscription_localized = true;
|
||||
let mut sats_ranges = vec![];
|
||||
let mut bound = 0;
|
||||
for output_value in lazy_tx.outputs.iter() {
|
||||
sats_ranges.push((bound, bound + output_value));
|
||||
bound += output_value;
|
||||
}
|
||||
let mut input_offset = 0;
|
||||
for (i, input) in lazy_tx.inputs.iter().enumerate() {
|
||||
if i == input_index {
|
||||
break;
|
||||
}
|
||||
input_offset += input.txin_value;
|
||||
}
|
||||
|
||||
for (i, (min, max)) in sats_ranges.into_iter().enumerate() {
|
||||
if input_offset >= min && input_offset < max {
|
||||
inscription_output_index = i;
|
||||
inscription_offset = input_offset - min;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut sats_out = 0;
|
||||
for (index, output_value) in lazy_tx.outputs.iter().enumerate() {
|
||||
if index == tx_cursor.1 {
|
||||
@@ -1056,6 +1118,11 @@ pub fn retrieve_satoshi_point_using_lazy_storage(
|
||||
inscription_number: 0,
|
||||
ordinal_number: 0,
|
||||
transfers: 0,
|
||||
inscription_offset,
|
||||
outpoint_to_watch: format_outpoint_to_watch(
|
||||
&transaction_identifier,
|
||||
inscription_output_index,
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1068,6 +1135,11 @@ pub fn retrieve_satoshi_point_using_lazy_storage(
|
||||
inscription_number,
|
||||
ordinal_number,
|
||||
transfers: hops,
|
||||
inscription_offset,
|
||||
outpoint_to_watch: format_outpoint_to_watch(
|
||||
&transaction_identifier,
|
||||
inscription_output_index,
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ use std::sync::mpsc::channel;
|
||||
use std::sync::Arc;
|
||||
use threadpool::ThreadPool;
|
||||
|
||||
use crate::hord::db::format_outpoint_to_watch;
|
||||
use crate::indexer::bitcoin::BitcoinTransactionFullBreakdown;
|
||||
use crate::{
|
||||
hord::{
|
||||
@@ -87,48 +88,27 @@ pub fn parse_ordinal_operations(
|
||||
None
|
||||
};
|
||||
|
||||
let payload = OrdinalInscriptionRevealData {
|
||||
content_type: inscription.content_type().unwrap_or("unknown").to_string(),
|
||||
content_bytes: format!("0x{}", hex::encode(&inscription_content_bytes)),
|
||||
content_length: inscription_content_bytes.len(),
|
||||
inscription_id: inscription_id.to_string(),
|
||||
inscriber_address,
|
||||
inscription_output_value,
|
||||
inscription_fee: 0,
|
||||
inscription_input_index: input_index,
|
||||
inscription_number: 0,
|
||||
ordinal_number: 0,
|
||||
ordinal_block_height: 0,
|
||||
ordinal_offset: 0,
|
||||
transfers_pre_inscription: 0,
|
||||
satpoint_post_inscription: format!("{}:0:0", tx.txid.clone()),
|
||||
};
|
||||
|
||||
if input_index == 0 {
|
||||
operations.push(OrdinalOperation::InscriptionRevealed(
|
||||
OrdinalInscriptionRevealData {
|
||||
content_type: inscription
|
||||
.content_type()
|
||||
.unwrap_or("unknown")
|
||||
.to_string(),
|
||||
content_bytes: format!("0x{}", hex::encode(&inscription_content_bytes)),
|
||||
content_length: inscription_content_bytes.len(),
|
||||
inscription_id: inscription_id.to_string(),
|
||||
inscriber_address,
|
||||
inscription_output_value,
|
||||
inscription_fee: 0,
|
||||
inscription_number: 0,
|
||||
ordinal_number: 0,
|
||||
ordinal_block_height: 0,
|
||||
ordinal_offset: 0,
|
||||
transfers_pre_inscription: 0,
|
||||
satpoint_post_inscription: format!("{}:0:0", tx.txid.clone()),
|
||||
},
|
||||
))
|
||||
operations.push(OrdinalOperation::InscriptionRevealed(payload));
|
||||
} else {
|
||||
operations.push(OrdinalOperation::CursedInscriptionRevealed(
|
||||
OrdinalInscriptionRevealData {
|
||||
content_type: inscription
|
||||
.content_type()
|
||||
.unwrap_or("unknown")
|
||||
.to_string(),
|
||||
content_bytes: format!("0x{}", hex::encode(&inscription_content_bytes)),
|
||||
content_length: inscription_content_bytes.len(),
|
||||
inscription_id: inscription_id.to_string(),
|
||||
inscriber_address,
|
||||
inscription_output_value,
|
||||
inscription_fee: 0,
|
||||
inscription_number: 0,
|
||||
ordinal_number: 0,
|
||||
ordinal_block_height: 0,
|
||||
ordinal_offset: 0,
|
||||
transfers_pre_inscription: 0,
|
||||
satpoint_post_inscription: format!("{}:0:0", tx.txid.clone()),
|
||||
},
|
||||
))
|
||||
operations.push(OrdinalOperation::CursedInscriptionRevealed(payload));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,23 +201,38 @@ pub fn retrieve_inscribed_satoshi_points_from_block(
|
||||
for tx in block.transactions.iter().skip(1) {
|
||||
// Have a new inscription been revealed, if so, are looking at a re-inscription
|
||||
for ordinal_event in tx.metadata.ordinal_operations.iter() {
|
||||
if let OrdinalOperation::InscriptionRevealed(inscription_data) = ordinal_event {
|
||||
if let Some(inscriptions_db_conn) = inscriptions_db_conn {
|
||||
if let Some(traversal) = find_inscription_with_id(
|
||||
&inscription_data.inscription_id,
|
||||
&block.block_identifier.hash,
|
||||
inscriptions_db_conn,
|
||||
ctx,
|
||||
) {
|
||||
traversals.insert(tx.transaction_identifier.clone(), traversal);
|
||||
} else {
|
||||
// Enqueue for traversals
|
||||
transactions_ids.push(tx.transaction_identifier.clone());
|
||||
}
|
||||
let (inscription_data, _is_cursed) = match ordinal_event {
|
||||
OrdinalOperation::InscriptionRevealed(inscription_data) => {
|
||||
(inscription_data, false)
|
||||
}
|
||||
OrdinalOperation::CursedInscriptionRevealed(inscription_data) => {
|
||||
(inscription_data, false)
|
||||
}
|
||||
OrdinalOperation::InscriptionTransferred(_) => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if let Some(inscriptions_db_conn) = inscriptions_db_conn {
|
||||
if let Some(traversal) = find_inscription_with_id(
|
||||
&inscription_data.inscription_id,
|
||||
&block.block_identifier.hash,
|
||||
inscriptions_db_conn,
|
||||
ctx,
|
||||
) {
|
||||
traversals.insert(tx.transaction_identifier.clone(), traversal);
|
||||
} else {
|
||||
// Enqueue for traversals
|
||||
transactions_ids.push(tx.transaction_identifier.clone());
|
||||
transactions_ids.push((
|
||||
tx.transaction_identifier.clone(),
|
||||
inscription_data.inscription_input_index,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// Enqueue for traversals
|
||||
transactions_ids.push((
|
||||
tx.transaction_identifier.clone(),
|
||||
inscription_data.inscription_input_index,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -249,7 +244,7 @@ pub fn retrieve_inscribed_satoshi_points_from_block(
|
||||
|
||||
let mut rng = thread_rng();
|
||||
transactions_ids.shuffle(&mut rng);
|
||||
for transaction_id in transactions_ids.into_iter() {
|
||||
for (transaction_id, input_index) in transactions_ids.into_iter() {
|
||||
let moved_traversal_tx = traversal_tx.clone();
|
||||
let moved_ctx = ctx.clone();
|
||||
let block_identifier = block.block_identifier.clone();
|
||||
@@ -262,6 +257,7 @@ pub fn retrieve_inscribed_satoshi_points_from_block(
|
||||
&blocks_db,
|
||||
&block_identifier,
|
||||
&transaction_id,
|
||||
input_index,
|
||||
0,
|
||||
local_cache,
|
||||
&moved_ctx,
|
||||
@@ -466,6 +462,10 @@ pub fn update_storage_and_augment_bitcoin_block_with_inscription_reveal_data(
|
||||
inscription.inscription_number = traversal.inscription_number;
|
||||
inscription.transfers_pre_inscription = traversal.transfers;
|
||||
inscription.inscription_fee = new_tx.metadata.fee;
|
||||
inscription.satpoint_post_inscription = format!(
|
||||
"{}:{}",
|
||||
traversal.outpoint_to_watch, traversal.inscription_offset
|
||||
);
|
||||
|
||||
match storage {
|
||||
Storage::Sqlite(rw_hord_db_conn) => {
|
||||
@@ -644,7 +644,7 @@ pub fn update_storage_and_augment_bitcoin_block_with_inscription_transfer_data(
|
||||
) = match post_transfer_output {
|
||||
Some(index) => {
|
||||
let outpoint =
|
||||
format!("{}:{}", &new_tx.transaction_identifier.hash[2..], index);
|
||||
format_outpoint_to_watch(&new_tx.transaction_identifier, index);
|
||||
let offset = (sats_in_offset + watched_satpoint.offset) - sats_out_offset;
|
||||
let script_pub_key_hex =
|
||||
new_tx.metadata.outputs[index].get_script_pubkey_hex();
|
||||
|
||||
@@ -327,6 +327,7 @@ pub struct OrdinalInscriptionRevealData {
|
||||
pub inscription_fee: u64,
|
||||
pub inscription_output_value: u64,
|
||||
pub inscription_id: String,
|
||||
pub inscription_input_index: usize,
|
||||
pub inscriber_address: Option<String>,
|
||||
pub ordinal_number: u64,
|
||||
pub ordinal_block_height: u64,
|
||||
|
||||
Reference in New Issue
Block a user