Skip to content

Commit

Permalink
Merge pull request #468 from hirosystems/feat/jubilee
Browse files Browse the repository at this point in the history
chore: support for Jubilee
  • Loading branch information
Ludo Galabru authored Jan 11, 2024
2 parents 823f430 + 60d2276 commit abcf809
Show file tree
Hide file tree
Showing 16 changed files with 459 additions and 391 deletions.
592 changes: 293 additions & 299 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion components/chainhook-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ redis = "0.21.5"
serde-redis = "0.12.0"
hex = "0.4.3"
rand = "0.8.5"
chainhook-sdk = { version = "0.11.0", default-features = false, features = [
chainhook-sdk = { version = "0.12.1", default-features = false, features = [
"zeromq",
], path = "../chainhook-sdk" }
hiro-system-kit = "0.3.1"
Expand Down
2 changes: 1 addition & 1 deletion components/chainhook-cli/src/scan/bitcoin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ pub async fn execute_predicates_action<'a>(
Ok(action) => {
actions_triggered += 1;
match action {
BitcoinChainhookOccurrence::Http(request) => {
BitcoinChainhookOccurrence::Http(request, _) => {
send_request(request, 10, 3, &ctx).await?
}
BitcoinChainhookOccurrence::File(path, bytes) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use chainhook_sdk::bitcoin::Network;
use chainhook_sdk::bitcoincore_rpc_json::GetRawTransactionResultVoutScriptPubKey;
use chainhook_sdk::indexer::bitcoin::BitcoinBlockFullBreakdown;
use chainhook_sdk::indexer::bitcoin::BitcoinTransactionFullBreakdown;
Expand Down Expand Up @@ -36,7 +37,7 @@ struct Rpc {

fn branch_and_height_to_hash(branch: Option<char>, height: u64) -> BlockHash {
let hash = Hash::from_str(&branch_and_height_to_hash_str(branch, height)).unwrap();
BlockHash::from_hash(hash)
BlockHash::from_raw_hash(hash)
}

#[derive(Clone, Serialize, Deserialize, Debug)]
Expand Down Expand Up @@ -139,7 +140,8 @@ fn handle_rpc(
hex: vec![],
req_sigs: None,
type_: None,
addresses: None,
addresses: vec![],
address: None,
},
}],
};
Expand All @@ -164,7 +166,8 @@ fn handle_rpc(
hex: vec![],
req_sigs: None,
type_: None,
addresses: None,
addresses: vec![],
address: None,
},
}],
};
Expand Down Expand Up @@ -192,7 +195,7 @@ fn handle_rpc(

let hash = branch_and_height_to_hash(Some(*branch), *chain_tip);
let blockchain_info = GetBlockchainInfoResult {
chain: "regtest".into(),
chain: Network::Regtest,
blocks: chain_tip.to_owned(),
headers: 0,
best_block_hash: hash,
Expand Down
16 changes: 7 additions & 9 deletions components/chainhook-sdk/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "chainhook-sdk"
version = "0.11.0"
version = "0.12.1"
description = "Stateless Transaction Indexing Engine for Stacks and Bitcoin"
license = "GPL-3.0"
edition = "2021"
Expand All @@ -13,16 +13,14 @@ serde_json = { version = "1", features = ["arbitrary_precision"] }
serde-hex = "0.1.0"
serde_derive = "1"
stacks-rpc-client = "2"
clarinet-utils = "1.0.0"
hiro-system-kit = { version = "0.3.1", optional = true }
# stacks-rpc-client = { version = "1", path = "../../../clarinet/components/stacks-rpc-client" }
# clarinet-utils = { version = "1", path = "../../../clarinet/components/clarinet-utils" }
# hiro-system-kit = { version = "0.1.0", path = "../../../clarinet/components/hiro-system-kit" }
chainhook-types = { version = "1.2.0", path = "../chainhook-types-rs" }
chainhook-types = { version = "1.3.0", path = "../chainhook-types-rs" }
rocket = { version = "=0.5.0-rc.3", features = ["json"] }
bitcoincore-rpc = "0.16.0"
bitcoincore-rpc-json = "0.16.0"
base64 = "0.13.0"
bitcoincore-rpc = "0.18.0"
bitcoincore-rpc-json = "0.18.0"
base64 = "0.21.5"
reqwest = { version = "0.11", default-features = false, features = [
"blocking",
"json",
Expand All @@ -33,7 +31,7 @@ base58 = "0.2.0"
schemars = { version = "0.8.10", git = "https://github.com/hirosystems/schemars.git", branch = "feat-chainhook-fixes" }
crossbeam-channel = "0.5.6"
futures = "0.3.21"
hyper = { version = "0.14.24", features = ["http1", "client"] }
hyper = { version = "=0.14.27", features = ["http1", "client"] }
hex = "0.4.3"
threadpool = "1.8.1"
rand = "0.8.5"
Expand All @@ -42,7 +40,7 @@ dashmap = "5.4.0"
fxhash = "0.2.1"
lazy_static = "1.4.0"
regex = "1.9.3"
miniscript = "10.0.0"
miniscript = "11.0.0"

[dev-dependencies]
test-case = "3.1.0"
Expand Down
120 changes: 65 additions & 55 deletions components/chainhook-sdk/src/chainhooks/bitcoin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ use super::types::{
};
use crate::utils::Context;

use bitcoincore_rpc::bitcoin::util::address::Payload;
use bitcoincore_rpc::bitcoin::Address;
use bitcoincore_rpc_json::bitcoin::{address::Payload, Address};
use chainhook_types::{
BitcoinBlockData, BitcoinChainEvent, BitcoinTransactionData, BlockIdentifier, OrdinalOperation,
StacksBaseChainOperation, TransactionIdentifier,
Expand All @@ -18,8 +17,10 @@ use miniscript::Descriptor;

use reqwest::{Client, Method};
use serde_json::Value as JsonValue;
use std::collections::{BTreeMap, HashMap};
use std::str::FromStr;
use std::{
collections::{BTreeMap, HashMap},
str::FromStr,
};

use reqwest::RequestBuilder;

Expand Down Expand Up @@ -48,8 +49,44 @@ pub struct BitcoinChainhookOccurrencePayload {
pub chainhook: BitcoinChainhookPayload,
}

impl BitcoinChainhookOccurrencePayload {
pub fn from_trigger<'a>(
trigger: BitcoinTriggerChainhook<'a>,
) -> BitcoinChainhookOccurrencePayload {
BitcoinChainhookOccurrencePayload {
apply: trigger
.apply
.into_iter()
.map(|(transactions, block)| {
let mut block = block.clone();
block.transactions = transactions
.into_iter()
.map(|t| t.clone())
.collect::<Vec<_>>();
BitcoinTransactionPayload { block }
})
.collect::<Vec<_>>(),
rollback: trigger
.rollback
.into_iter()
.map(|(transactions, block)| {
let mut block = block.clone();
block.transactions = transactions
.into_iter()
.map(|t| t.clone())
.collect::<Vec<_>>();
BitcoinTransactionPayload { block }
})
.collect::<Vec<_>>(),
chainhook: BitcoinChainhookPayload {
uuid: trigger.chainhook.uuid.clone(),
},
}
}
}

pub enum BitcoinChainhookOccurrence {
Http(RequestBuilder),
Http(RequestBuilder, BitcoinChainhookOccurrencePayload),
File(String, Vec<u8>),
Data(BitcoinChainhookOccurrencePayload),
}
Expand Down Expand Up @@ -155,12 +192,12 @@ pub fn evaluate_bitcoin_chainhooks_on_chain_event<'a>(
}

pub fn serialize_bitcoin_payload_to_json<'a>(
trigger: BitcoinTriggerChainhook<'a>,
trigger: &BitcoinTriggerChainhook<'a>,
proofs: &HashMap<&'a TransactionIdentifier, String>,
) -> JsonValue {
let predicate_spec = &trigger.chainhook;
let predicate_spec = trigger.chainhook;
json!({
"apply": trigger.apply.into_iter().map(|(transactions, block)| {
"apply": trigger.apply.iter().map(|(transactions, block)| {
json!({
"block_identifier": block.block_identifier,
"parent_block_identifier": block.parent_block_identifier,
Expand All @@ -169,7 +206,7 @@ pub fn serialize_bitcoin_payload_to_json<'a>(
"metadata": block.metadata,
})
}).collect::<Vec<_>>(),
"rollback": trigger.rollback.into_iter().map(|(transactions, block)| {
"rollback": trigger.rollback.iter().map(|(transactions, block)| {
json!({
"block_identifier": block.block_identifier,
"parent_block_identifier": block.parent_block_identifier,
Expand Down Expand Up @@ -251,54 +288,27 @@ pub fn handle_bitcoin_hook_action<'a>(
.map_err(|e| format!("unable to build http client: {}", e.to_string()))?;
let host = format!("{}", http.url);
let method = Method::POST;
let body = serde_json::to_vec(&serialize_bitcoin_payload_to_json(trigger, proofs))
let body = serde_json::to_vec(&serialize_bitcoin_payload_to_json(&trigger, proofs))
.map_err(|e| format!("unable to serialize payload {}", e.to_string()))?;
Ok(BitcoinChainhookOccurrence::Http(
client
.request(method, &host)
.header("Content-Type", "application/json")
.header("Authorization", http.authorization_header.clone())
.body(body),
))
let request = client
.request(method, &host)
.header("Content-Type", "application/json")
.header("Authorization", http.authorization_header.clone())
.body(body);

let data = BitcoinChainhookOccurrencePayload::from_trigger(trigger);
Ok(BitcoinChainhookOccurrence::Http(request, data))
}
HookAction::FileAppend(disk) => {
let bytes = serde_json::to_vec(&serialize_bitcoin_payload_to_json(trigger, proofs))
let bytes = serde_json::to_vec(&serialize_bitcoin_payload_to_json(&trigger, proofs))
.map_err(|e| format!("unable to serialize payload {}", e.to_string()))?;
Ok(BitcoinChainhookOccurrence::File(
disk.path.to_string(),
bytes,
))
}
HookAction::Noop => Ok(BitcoinChainhookOccurrence::Data(
BitcoinChainhookOccurrencePayload {
apply: trigger
.apply
.into_iter()
.map(|(transactions, block)| {
let mut block = block.clone();
block.transactions = transactions
.into_iter()
.map(|t| t.clone())
.collect::<Vec<_>>();
BitcoinTransactionPayload { block }
})
.collect::<Vec<_>>(),
rollback: trigger
.rollback
.into_iter()
.map(|(transactions, block)| {
let mut block = block.clone();
block.transactions = transactions
.into_iter()
.map(|t| t.clone())
.collect::<Vec<_>>();
BitcoinTransactionPayload { block }
})
.collect::<Vec<_>>(),
chainhook: BitcoinChainhookPayload {
uuid: trigger.chainhook.uuid.clone(),
},
},
BitcoinChainhookOccurrencePayload::from_trigger(trigger),
)),
}
}
Expand Down Expand Up @@ -387,7 +397,7 @@ impl BitcoinPredicateType {
encoded_address,
))) => {
let address = match Address::from_str(encoded_address) {
Ok(address) => address,
Ok(address) => address.assume_checked(),
Err(_) => return false,
};
let address_bytes = hex::encode(address.script_pubkey().as_bytes());
Expand All @@ -405,13 +415,13 @@ impl BitcoinPredicateType {
encoded_address,
))) => {
let address = match Address::from_str(encoded_address) {
Ok(address) => match address.payload {
Payload::WitnessProgram {
version: _,
program: _,
} => address,
_ => return false,
},
Ok(address) => {
let checked_address = address.assume_checked();
match checked_address.payload() {
Payload::WitnessProgram(_) => checked_address,
_ => return false,
}
}
Err(_) => return false,
};
let address_bytes = hex::encode(address.script_pubkey().as_bytes());
Expand Down
5 changes: 4 additions & 1 deletion components/chainhook-sdk/src/chainhooks/bitcoin/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ fn test_opreturn_evaluation(script_pubkey: &str, rule: MatchingRule, matches: bo
)]
fn test_descriptor_evaluation(addr: &str, expr: &str) {
// turn the address into a script_pubkey with a 0x prefix, as expected by the evaluator.
let script_pubkey = Address::from_str(addr).unwrap().script_pubkey();
let script_pubkey = Address::from_str(addr)
.unwrap()
.assume_checked()
.script_pubkey();
let matching_script_pubkey = format!("0x{}", hex::encode(script_pubkey));

let rule = DescriptorMatchingRule {
Expand Down
2 changes: 1 addition & 1 deletion components/chainhook-sdk/src/chainhooks/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ pub fn get_stacks_canonical_magic_bytes(network: &BitcoinNetwork) -> [u8; 2] {
BitcoinNetwork::Mainnet => *b"X2",
BitcoinNetwork::Testnet => *b"T2",
BitcoinNetwork::Regtest => *b"id",
BitcoinNetwork::Signet => unreachable!()
BitcoinNetwork::Signet => unreachable!(),
}
}

Expand Down
4 changes: 2 additions & 2 deletions components/chainhook-sdk/src/indexer/bitcoin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@ impl BitcoinTransactionInputFullBreakdown {
#[serde(rename_all = "camelCase")]
pub struct BitcoinTransactionInputPrevoutFullBreakdown {
pub height: u64,
#[serde(with = "bitcoin::util::amount::serde::as_btc")]
#[serde(with = "bitcoin::amount::serde::as_btc")]
pub value: Amount,
}

#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BitcoinTransactionOutputFullBreakdown {
#[serde(with = "bitcoin::util::amount::serde::as_btc")]
#[serde(with = "bitcoin::amount::serde::as_btc")]
pub value: Amount,
pub n: u32,
pub script_pub_key: GetRawTransactionResultVoutScriptPubKey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,32 @@ pub fn generate_test_tx_bitcoin_p2pkh_transfer(
let pubkey_hash = recipient
.from_base58()
.expect("Unable to get bytes from btc address");
let slice = [
pubkey_hash[1],
pubkey_hash[2],
pubkey_hash[3],
pubkey_hash[4],
pubkey_hash[5],
pubkey_hash[6],
pubkey_hash[7],
pubkey_hash[8],
pubkey_hash[9],
pubkey_hash[10],
pubkey_hash[11],
pubkey_hash[12],
pubkey_hash[13],
pubkey_hash[14],
pubkey_hash[15],
pubkey_hash[16],
pubkey_hash[17],
pubkey_hash[18],
pubkey_hash[19],
pubkey_hash[20],
];
let script = BitcoinScriptBuilder::new()
.push_opcode(opcodes::all::OP_DUP)
.push_opcode(opcodes::all::OP_HASH160)
.push_slice(&pubkey_hash[1..21])
.push_slice(&slice)
.push_opcode(opcodes::all::OP_EQUALVERIFY)
.push_opcode(opcodes::all::OP_CHECKSIG)
.into_script();
Expand Down
1 change: 1 addition & 0 deletions components/chainhook-sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub extern crate dashmap;
pub extern crate fxhash;
pub extern crate stacks_rpc_client;

pub use bitcoincore_rpc::bitcoin;
pub use chainhook_types as types;

pub mod chainhooks;
Expand Down
Loading

0 comments on commit abcf809

Please sign in to comment.