feat: handle transfer

This commit is contained in:
Ludo Galabru
2023-05-25 15:35:14 -04:00
parent af280b7929
commit fd5da52df4
4 changed files with 142 additions and 69 deletions

View File

@@ -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,
)?;

View File

@@ -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,
),
})
}

View File

@@ -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();

View File

@@ -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,