mirror of
https://github.com/alexgo-io/bitcoin-indexer.git
synced 2026-01-12 22:43:06 +08:00
feat: extract additional data
This commit is contained in:
42
Cargo.lock
generated
42
Cargo.lock
generated
@@ -477,9 +477,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chainhook-sdk"
|
||||
version = "0.12.1"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54209dae9bcea839b2b3fea2546eb52f84b0a4224049ed7f09ed116e2942a5ae"
|
||||
checksum = "d960301b0bd0ed096d37ee17c0d4a67a773eb374089a9b912078bfd3ee218676"
|
||||
dependencies = [
|
||||
"base58 0.2.0",
|
||||
"base64 0.21.5",
|
||||
@@ -512,9 +512,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "chainhook-types"
|
||||
version = "1.3.1"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ebcb0d5e7c79a5b44a8ae0d31654605bf2756303c0cb91f73adfcd4e3bc52fc"
|
||||
checksum = "66859c3478ca302202b5cc96fe19df6f5d67d48fd909a6bf86941477de465643"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"schemars 0.8.16",
|
||||
@@ -538,6 +538,33 @@ dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ciborium"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"ciborium-ll",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-io"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-ll"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"half",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.6.1"
|
||||
@@ -1367,6 +1394,12 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
@@ -2268,6 +2301,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"atty",
|
||||
"chainhook-sdk",
|
||||
"ciborium",
|
||||
"crossbeam-channel",
|
||||
"dashmap",
|
||||
"flate2",
|
||||
|
||||
@@ -10,7 +10,7 @@ serde_json = "1"
|
||||
serde_derive = "1"
|
||||
hex = "0.4.3"
|
||||
rand = "0.8.5"
|
||||
chainhook-sdk = { version = "=0.12.1", features = ["zeromq"] }
|
||||
chainhook-sdk = { version = "=0.12.2", features = ["zeromq"] }
|
||||
# chainhook-sdk = { version = "=0.12.1", path = "../../../chainhook/components/chainhook-sdk", features = ["zeromq"] }
|
||||
hiro-system-kit = "0.3.1"
|
||||
reqwest = { version = "0.11", default-features = false, features = [
|
||||
@@ -43,6 +43,7 @@ rocksdb = { version = "0.21.0", default-features = false, features = [
|
||||
pprof = { version = "0.13.0", features = ["flamegraph"], optional = true }
|
||||
hyper = { version = "=0.14.27" }
|
||||
lazy_static = { version = "1.4.0" }
|
||||
ciborium = "0.2.1"
|
||||
|
||||
# [profile.release]
|
||||
# debug = true
|
||||
|
||||
@@ -7,6 +7,7 @@ use chainhook_sdk::types::{
|
||||
OrdinalOperation,
|
||||
};
|
||||
use chainhook_sdk::utils::Context;
|
||||
use serde_json::json;
|
||||
use std::collections::BTreeMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -59,6 +60,17 @@ pub fn parse_inscriptions_from_witness(
|
||||
let mut content_bytes = "0x".to_string();
|
||||
content_bytes.push_str(&hex::encode(&inscription_content_bytes));
|
||||
|
||||
let parent = envelope.payload.parent().and_then(|i| Some(i.to_string()));
|
||||
let delegate = envelope
|
||||
.payload
|
||||
.delegate()
|
||||
.and_then(|i| Some(i.to_string()));
|
||||
let metaprotocol = envelope
|
||||
.payload
|
||||
.metaprotocol()
|
||||
.and_then(|p| Some(p.to_string()));
|
||||
let metadata = envelope.payload.metadata().and_then(|m| Some(json!(m)));
|
||||
|
||||
let reveal_data = OrdinalInscriptionRevealData {
|
||||
content_type: envelope
|
||||
.payload
|
||||
@@ -75,6 +87,10 @@ pub fn parse_inscriptions_from_witness(
|
||||
inscription_fee: 0,
|
||||
inscription_number: OrdinalInscriptionNumber::zero(),
|
||||
inscriber_address: None,
|
||||
parent,
|
||||
delegate,
|
||||
metaprotocol,
|
||||
metadata,
|
||||
ordinal_number: 0,
|
||||
ordinal_block_height: 0,
|
||||
ordinal_offset: 0,
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{
|
||||
};
|
||||
|
||||
use chainhook_sdk::{
|
||||
bitcoincore_rpc_json::bitcoin::{Address, Network, ScriptBuf},
|
||||
bitcoincore_rpc_json::bitcoin::Network,
|
||||
types::{
|
||||
BitcoinBlockData, BitcoinNetwork, BitcoinTransactionData, BlockIdentifier,
|
||||
OrdinalInscriptionCurseType, OrdinalInscriptionNumber,
|
||||
@@ -930,7 +930,6 @@ pub fn consolidate_block_with_pre_computed_ordinals_data(
|
||||
let _ = augment_transaction_with_ordinals_transfers_data(
|
||||
tx,
|
||||
tx_index,
|
||||
&block.block_identifier,
|
||||
&network,
|
||||
&coinbase_txid,
|
||||
coinbase_subsidy,
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use chainhook_sdk::{
|
||||
bitcoincore_rpc_json::bitcoin::{Address, Network, ScriptBuf},
|
||||
types::{
|
||||
BitcoinBlockData, BitcoinNetwork, BitcoinTransactionData, BlockIdentifier,
|
||||
OrdinalInscriptionTransferData, OrdinalInscriptionTransferDestination, OrdinalOperation,
|
||||
TransactionIdentifier,
|
||||
BitcoinBlockData, BitcoinNetwork, BitcoinTransactionData, OrdinalInscriptionTransferData,
|
||||
OrdinalInscriptionTransferDestination, OrdinalOperation, TransactionIdentifier,
|
||||
},
|
||||
utils::Context,
|
||||
};
|
||||
@@ -40,7 +39,6 @@ pub fn augment_block_with_ordinals_transfer_data(
|
||||
let transfers = augment_transaction_with_ordinals_transfers_data(
|
||||
tx,
|
||||
tx_index,
|
||||
&block.block_identifier,
|
||||
&network,
|
||||
&coinbase_txid,
|
||||
coinbase_subsidy,
|
||||
@@ -150,7 +148,6 @@ pub fn compute_satpoint_post_transfer(
|
||||
pub fn augment_transaction_with_ordinals_transfers_data(
|
||||
tx: &mut BitcoinTransactionData,
|
||||
tx_index: usize,
|
||||
block_identifier: &BlockIdentifier,
|
||||
network: &Network,
|
||||
coinbase_txid: &TransactionIdentifier,
|
||||
coinbase_subsidy: u64,
|
||||
|
||||
@@ -39,7 +39,13 @@ pub fn compute_satoshi_number(
|
||||
{
|
||||
Some(entry) => {
|
||||
let tx = entry.value();
|
||||
((tx.inputs[inscription_input_index].txin.clone(), tx.inputs[inscription_input_index].vout.into()), tx.inputs[inscription_input_index].block_height)
|
||||
(
|
||||
(
|
||||
tx.inputs[inscription_input_index].txin.clone(),
|
||||
tx.inputs[inscription_input_index].vout.into(),
|
||||
),
|
||||
tx.inputs[inscription_input_index].block_height,
|
||||
)
|
||||
}
|
||||
None => loop {
|
||||
match find_pinned_block_bytes_at_block_height(ordinal_block_number, 3, &blocks_db, &ctx)
|
||||
@@ -51,7 +57,13 @@ pub fn compute_satoshi_number(
|
||||
let cursor = BlockBytesCursor::new(&block_bytes.as_ref());
|
||||
match cursor.find_and_serialize_transaction_with_txid(&txid) {
|
||||
Some(tx) => {
|
||||
break ((tx.inputs[inscription_input_index].txin.clone(), tx.inputs[inscription_input_index].vout.into()), tx.inputs[inscription_input_index].block_height);
|
||||
break (
|
||||
(
|
||||
tx.inputs[inscription_input_index].txin.clone(),
|
||||
tx.inputs[inscription_input_index].vout.into(),
|
||||
),
|
||||
tx.inputs[inscription_input_index].block_height,
|
||||
);
|
||||
}
|
||||
None => return Err(format!("txid not in block #{ordinal_block_number}")),
|
||||
}
|
||||
@@ -199,7 +211,8 @@ pub fn compute_satoshi_number(
|
||||
}
|
||||
} else {
|
||||
// isolate the target transaction
|
||||
let tx_bytes_cursor = match block_cursor.find_and_serialize_transaction_with_txid(&txid) {
|
||||
let tx_bytes_cursor = match block_cursor.find_and_serialize_transaction_with_txid(&txid)
|
||||
{
|
||||
Some(entry) => entry,
|
||||
None => {
|
||||
ctx.try_log(|logger| {
|
||||
@@ -229,7 +242,8 @@ pub fn compute_satoshi_number(
|
||||
|
||||
if sats_out < sats_in {
|
||||
back_track.push((ordinal_block_number, tx_cursor.0.clone(), tx_cursor.1));
|
||||
traversals_cache.insert((ordinal_block_number, tx_cursor.0), tx_bytes_cursor.clone());
|
||||
traversals_cache
|
||||
.insert((ordinal_block_number, tx_cursor.0), tx_bytes_cursor.clone());
|
||||
ordinal_offset = sats_out - (sats_in - input.txin_value);
|
||||
ordinal_block_number = input.block_height;
|
||||
tx_cursor = (input.txin.clone(), input.vout as usize);
|
||||
|
||||
@@ -25,6 +25,7 @@ pub const PARENT_TAG: [u8; 1] = [3];
|
||||
pub const METADATA_TAG: [u8; 1] = [5];
|
||||
pub const METAPROTOCOL_TAG: [u8; 1] = [7];
|
||||
pub const CONTENT_ENCODING_TAG: [u8; 1] = [9];
|
||||
pub const DELEGATE_TAG: [u8; 1] = [11];
|
||||
|
||||
type Result<T> = std::result::Result<T, script::Error>;
|
||||
pub type RawEnvelope = Envelope<Vec<Vec<u8>>>;
|
||||
@@ -91,6 +92,7 @@ impl From<RawEnvelope> for ParsedEnvelope {
|
||||
|
||||
let content_encoding = remove_field(&mut fields, &CONTENT_ENCODING_TAG);
|
||||
let content_type = remove_field(&mut fields, &CONTENT_TYPE_TAG);
|
||||
let delegate = remove_field(&mut fields, &DELEGATE_TAG);
|
||||
let metadata = remove_and_concatenate_field(&mut fields, &METADATA_TAG);
|
||||
let metaprotocol = remove_field(&mut fields, &METAPROTOCOL_TAG);
|
||||
let parent = remove_field(&mut fields, &PARENT_TAG);
|
||||
@@ -109,13 +111,14 @@ impl From<RawEnvelope> for ParsedEnvelope {
|
||||
.cloned()
|
||||
.collect()
|
||||
}),
|
||||
metaprotocol,
|
||||
parent,
|
||||
delegate,
|
||||
content_encoding,
|
||||
content_type,
|
||||
duplicate_field,
|
||||
incomplete_field,
|
||||
metadata,
|
||||
metaprotocol,
|
||||
parent,
|
||||
pointer,
|
||||
unrecognized_even_field,
|
||||
},
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::io::Cursor;
|
||||
|
||||
use chainhook_sdk::bitcoin::{hashes::Hash, Txid};
|
||||
|
||||
use super::{inscription_id::InscriptionId, media::Media};
|
||||
@@ -26,6 +28,7 @@ pub struct Inscription {
|
||||
pub parent: Option<Vec<u8>>,
|
||||
pub pointer: Option<Vec<u8>>,
|
||||
pub unrecognized_even_field: bool,
|
||||
pub delegate: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl Inscription {
|
||||
@@ -159,6 +162,49 @@ impl Inscription {
|
||||
str::from_utf8(self.metaprotocol.as_ref()?).ok()
|
||||
}
|
||||
|
||||
fn inscription_id_field(field: &Option<Vec<u8>>) -> Option<InscriptionId> {
|
||||
let value = field.as_ref()?;
|
||||
|
||||
if value.len() < Txid::LEN {
|
||||
return None;
|
||||
}
|
||||
|
||||
if value.len() > Txid::LEN + 4 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (txid, index) = value.split_at(Txid::LEN);
|
||||
|
||||
if let Some(last) = index.last() {
|
||||
// Accept fixed length encoding with 4 bytes (with potential trailing zeroes)
|
||||
// or variable length (no trailing zeroes)
|
||||
if index.len() != 4 && *last == 0 {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let txid = Txid::from_slice(txid).unwrap();
|
||||
|
||||
let index = [
|
||||
index.first().copied().unwrap_or(0),
|
||||
index.get(1).copied().unwrap_or(0),
|
||||
index.get(2).copied().unwrap_or(0),
|
||||
index.get(3).copied().unwrap_or(0),
|
||||
];
|
||||
|
||||
let index = u32::from_le_bytes(index);
|
||||
|
||||
Some(InscriptionId { txid, index })
|
||||
}
|
||||
|
||||
pub(crate) fn delegate(&self) -> Option<InscriptionId> {
|
||||
Self::inscription_id_field(&self.delegate)
|
||||
}
|
||||
|
||||
pub(crate) fn metadata(&self) -> Option<ciborium::Value> {
|
||||
ciborium::from_reader(Cursor::new(self.metadata.as_ref()?)).ok()
|
||||
}
|
||||
|
||||
pub(crate) fn parent(&self) -> Option<InscriptionId> {
|
||||
use chainhook_sdk::bitcoin::hash_types::Txid as TXID_LEN;
|
||||
let value = self.parent.as_ref()?;
|
||||
|
||||
Reference in New Issue
Block a user