Skip to content

Commit ee9a345

Browse files
author
Ludo Galabru
committed
feat: fetch full bitcoin block, including witness data
1 parent 611c79c commit ee9a345

File tree

2 files changed

+59
-37
lines changed
  • components/chainhook-event-observer/src/indexer

2 files changed

+59
-37
lines changed

components/chainhook-event-observer/src/indexer/bitcoin/mod.rs

+58-36
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,47 @@ mod blocks_pool;
33
use std::time::Duration;
44

55
use crate::chainhooks::types::{
6-
get_canonical_magic_bytes, get_canonical_pox_config, PoxConfig, StacksOpcodes,
6+
get_canonical_pox_config, get_ordinal_canonical_magic_bytes, get_stacks_canonical_magic_bytes,
7+
PoxConfig, StacksOpcodes,
78
};
89
use crate::indexer::IndexerConfig;
910
use crate::observer::BitcoinConfig;
1011
use crate::utils::Context;
11-
use bitcoincore_rpc::bitcoin::Block;
12+
use bitcoincore_rpc::bitcoin;
13+
use bitcoincore_rpc_json::{GetRawTransactionResult, GetRawTransactionResultVout};
1214
pub use blocks_pool::BitcoinBlockPool;
1315
use chainhook_types::bitcoin::{OutPoint, TxIn, TxOut};
1416
use chainhook_types::{
1517
BitcoinBlockData, BitcoinBlockMetadata, BitcoinTransactionData, BitcoinTransactionMetadata,
16-
BlockCommitmentData, BlockIdentifier, KeyRegistrationData, LockSTXData, PobBlockCommitmentData,
17-
PoxBlockCommitmentData, PoxReward, StacksBaseChainOperation, TransactionIdentifier,
18-
TransferSTXData,
18+
BlockCommitmentData, BlockIdentifier, KeyRegistrationData, LockSTXData,
19+
OrdinalInscriptionRevealData, OrdinalOperation, PobBlockCommitmentData, PoxBlockCommitmentData,
20+
PoxReward, StacksBaseChainOperation, TransactionIdentifier, TransferSTXData,
1921
};
2022
use clarity_repl::clarity::util::hash::{hex_bytes, to_hex};
2123
use hiro_system_kit::slog;
2224
use rocket::serde::json::Value as JsonValue;
2325

26+
#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
27+
#[serde(rename_all = "camelCase")]
28+
pub struct Block {
29+
pub hash: bitcoin::BlockHash,
30+
pub confirmations: i32,
31+
pub size: usize,
32+
pub strippedsize: Option<usize>,
33+
pub weight: usize,
34+
pub height: usize,
35+
pub version: i32,
36+
pub merkleroot: bitcoin::TxMerkleNode,
37+
pub tx: Vec<GetRawTransactionResult>,
38+
pub time: usize,
39+
pub mediantime: Option<usize>,
40+
pub nonce: u32,
41+
pub bits: String,
42+
pub difficulty: f64,
43+
pub n_tx: usize,
44+
pub previousblockhash: bitcoin::BlockHash,
45+
}
46+
2447
#[derive(Deserialize)]
2548
pub struct NewBitcoinBlock {
2649
pub burn_block_hash: String,
@@ -51,13 +74,13 @@ pub async fn retrieve_full_block(
5174
"jsonrpc": "1.0",
5275
"id": "chainhook-cli",
5376
"method": "getblock",
54-
"params": [block_hash, 0]
77+
"params": [block_hash, 2]
5578
});
5679
let http_client = HttpClient::builder()
5780
.timeout(Duration::from_secs(20))
5881
.build()
5982
.expect("Unable to build http client");
60-
let response_hex = http_client
83+
let block = http_client
6184
.post(&bitcoin_config.rpc_url)
6285
.basic_auth(&bitcoin_config.username, Some(&bitcoin_config.password))
6386
.header("Content-Type", "application/json")
@@ -69,15 +92,9 @@ pub async fn retrieve_full_block(
6992
.json::<bitcoincore_rpc::jsonrpc::Response>()
7093
.await
7194
.map_err(|e| format!("unable to parse response ({})", e))?
72-
.result::<String>()
95+
.result::<Block>()
7396
.map_err(|e| format!("unable to parse response ({})", e))?;
7497

75-
let bytes = hex_bytes(&response_hex)
76-
.map_err(|e| format!("unable to retrieve bytes from response ({})", e))?;
77-
78-
let block = bitcoincore_rpc::bitcoin::consensus::encode::deserialize(&bytes)
79-
.map_err(|e| format!("unable to deserialize bitcoin block ({})", e))?;
80-
8198
let block_height = partial_block.burn_block_height;
8299
Ok((block_height, block))
83100
}
@@ -96,16 +113,26 @@ pub fn standardize_bitcoin_block(
96113
for mut tx in block.txdata.into_iter() {
97114
let txid = tx.txid().to_string();
98115
let mut inputs = vec![];
99-
for input in tx.input.drain(..) {
116+
for input in tx.vin.drain(..) {
117+
if input.is_coinbase() {
118+
continue;
119+
}
100120
inputs.push(TxIn {
101121
previous_output: OutPoint {
102-
txid: input.previous_output.txid.to_string(),
103-
vout: input.previous_output.vout,
122+
txid: input
123+
.txid
124+
.expect("not provided for coinbase txs")
125+
.to_string(),
126+
vout: input.vout.expect("not provided for coinbase txs"),
104127
},
105-
script_sig: to_hex(input.script_sig.as_bytes()),
106-
sequence: input.sequence.0,
128+
script_sig: format!(
129+
"0x{}",
130+
to_hex(&input.script_sig.expect("not provided for coinbase txs").hex)
131+
),
132+
sequence: input.sequence,
107133
witness: input
108-
.witness
134+
.txinwitness
135+
.unwrap_or(vec![])
109136
.to_vec()
110137
.iter()
111138
.map(|w| format!("0x{}", to_hex(w)))
@@ -125,11 +152,10 @@ pub fn standardize_bitcoin_block(
125152
) {
126153
stacks_operations.push(op);
127154
}
128-
129-
for output in tx.output.drain(..) {
155+
for output in tx.vout.drain(..) {
130156
outputs.push(TxOut {
131-
value: output.value,
132-
script_pubkey: to_hex(output.script_pubkey.as_bytes()),
157+
value: output.value.to_sat(),
158+
script_pubkey: format!("0x{}", to_hex(&output.script_pub_key.hex)),
133159
});
134160
}
135161

@@ -150,21 +176,21 @@ pub fn standardize_bitcoin_block(
150176

151177
Ok(BitcoinBlockData {
152178
block_identifier: BlockIdentifier {
153-
hash: format!("0x{}", block.header.block_hash().to_string()),
179+
hash: format!("0x{}", block.hash),
154180
index: block_height,
155181
},
156182
parent_block_identifier: BlockIdentifier {
157-
hash: format!("0x{}", block.header.prev_blockhash.to_string()),
183+
hash: format!("0x{}", block.previousblockhash),
158184
index: block_height - 1,
159185
},
160-
timestamp: block.header.time,
186+
timestamp: block.time as u32,
161187
metadata: BitcoinBlockMetadata {},
162188
transactions,
163189
})
164190
}
165191

166192
fn try_parse_stacks_operation(
167-
outputs: &Vec<bitcoincore_rpc::bitcoin::TxOut>,
193+
outputs: &Vec<GetRawTransactionResultVout>,
168194
pox_config: &PoxConfig,
169195
expected_magic_bytes: &[u8; 2],
170196
block_height: u64,
@@ -174,12 +200,8 @@ fn try_parse_stacks_operation(
174200
return None;
175201
}
176202

177-
if !outputs[0].script_pubkey.is_op_return() {
178-
return None;
179-
}
180-
181203
// Safely parsing the first 2 bytes (following OP_RETURN + PUSH_DATA)
182-
let op_return_output = outputs[0].script_pubkey.as_bytes();
204+
let op_return_output = &outputs[0].script_pub_key.hex;
183205
if op_return_output.len() < 7 {
184206
return None;
185207
}
@@ -229,8 +251,8 @@ fn try_parse_stacks_operation(
229251
let mut rewards = vec![];
230252
for output in outputs[1..pox_config.rewarded_addresses_per_block].into_iter() {
231253
rewards.push(PoxReward {
232-
recipient: output.script_pubkey.to_string(),
233-
amount: output.value,
254+
recipient: format!("0x{}", to_hex(&output.script_pub_key.hex)),
255+
amount: output.value.to_sat(),
234256
});
235257
}
236258
StacksBaseChainOperation::PoxBlockCommitment(PoxBlockCommitmentData {
@@ -246,7 +268,7 @@ fn try_parse_stacks_operation(
246268
StacksBaseChainOperation::PobBlockCommitment(PobBlockCommitmentData {
247269
signers: vec![], // todo(lgalabru)
248270
stacks_block_hash: res.stacks_block_hash.clone(),
249-
amount,
271+
amount: amount.to_sat(),
250272
})
251273
}
252274
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pub mod bitcoin;
22
pub mod stacks;
33

44
use crate::utils::{AbstractBlock, Context};
5-
use bitcoincore_rpc::bitcoin::Block;
5+
use bitcoin::Block;
66
use chainhook_types::{
77
BitcoinChainEvent, BitcoinNetwork, BlockIdentifier, StacksChainEvent, StacksNetwork,
88
};

0 commit comments

Comments
 (0)