Skip to content

Commit

Permalink
Merge pull request #584 from hirosystems/develop
Browse files Browse the repository at this point in the history
chore(release): publish v1.6.0
  • Loading branch information
MicaiahReid committed May 9, 2024
2 parents 065f9af + f0bdfc5 commit 4a45617
Show file tree
Hide file tree
Showing 19 changed files with 392 additions and 152 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion components/chainhook-cli/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "chainhook"
version = "1.5.1"
version = "1.6.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
4 changes: 2 additions & 2 deletions components/chainhook-cli/src/scan/stacks.rs
Expand Up @@ -317,7 +317,7 @@ pub async fn scan_stacks_chainstate_via_rocksdb_using_predicate(
Ok(action) => {
number_of_times_triggered += 1;
let res = match action {
StacksChainhookOccurrence::Http(request) => {
StacksChainhookOccurrence::Http(request, _) => {
send_request(request, 3, 1, &ctx).await
}
StacksChainhookOccurrence::File(path, bytes) => file_append(path, bytes, &ctx),
Expand Down Expand Up @@ -488,7 +488,7 @@ pub async fn scan_stacks_chainstate_via_csv_using_predicate(
Ok(action) => {
occurrences_found += 1;
let res = match action {
StacksChainhookOccurrence::Http(request) => {
StacksChainhookOccurrence::Http(request, _) => {
send_request(request, 10, 3, &ctx).await
}
StacksChainhookOccurrence::File(path, bytes) => file_append(path, bytes, &ctx),
Expand Down
68 changes: 55 additions & 13 deletions components/chainhook-cli/src/service/mod.rs
Expand Up @@ -16,9 +16,9 @@ use chainhook_sdk::chainhooks::types::{ChainhookConfig, ChainhookFullSpecificati
use chainhook_sdk::chainhooks::types::ChainhookSpecification;
use chainhook_sdk::observer::{
start_event_observer, HookExpirationData, ObserverCommand, ObserverEvent,
PredicateEvaluationReport,
PredicateEvaluationReport, PredicateInterruptedData, StacksObserverStartupContext,
};
use chainhook_sdk::types::{Chain, StacksChainEvent};
use chainhook_sdk::types::{Chain, StacksBlockData, StacksChainEvent};
use chainhook_sdk::utils::Context;
use redis::{Commands, Connection};

Expand Down Expand Up @@ -243,24 +243,38 @@ impl Service {
let ctx = self.ctx.clone();
let stacks_db =
open_readonly_stacks_db_conn_with_retry(&config.expected_cache_path(), 3, &ctx)?;
let unconfirmed_blocks = match get_all_unconfirmed_blocks(&stacks_db, &ctx) {
let confirmed_tip = get_last_block_height_inserted(&stacks_db, &ctx).unwrap_or(0);
let stacks_startup_context = match get_all_unconfirmed_blocks(&stacks_db, &ctx) {
Ok(blocks) => {
let confirmed_tip = get_last_block_height_inserted(&stacks_db, &ctx).unwrap_or(0);
// any unconfirmed blocks that are earlier than confirmed blocks are invalid
Some(
blocks
.iter()
.filter(|&b| b.block_identifier.index > confirmed_tip)
.cloned()
.collect(),
)

let unconfirmed_blocks = blocks
.iter()
.filter(|&b| b.block_identifier.index > confirmed_tip)
.cloned()
.collect::<Vec<StacksBlockData>>();

let highest_appended = match unconfirmed_blocks
.iter()
.max_by_key(|b| b.block_identifier.index)
{
Some(highest_block) => highest_block.block_identifier.index,
None => confirmed_tip,
};
StacksObserverStartupContext {
block_pool_seed: unconfirmed_blocks,
last_block_height_appended: highest_appended,
}
}
Err(e) => {
info!(
self.ctx.expect_logger(),
"Failed to get stacks blocks from db to seed block pool: {}", e
);
None
StacksObserverStartupContext {
block_pool_seed: vec![],
last_block_height_appended: confirmed_tip,
}
}
};

Expand All @@ -272,7 +286,7 @@ impl Service {
observer_command_rx,
Some(observer_event_tx_moved),
None,
unconfirmed_blocks,
Some(stacks_startup_context),
self.ctx.clone(),
);

Expand Down Expand Up @@ -618,6 +632,24 @@ impl Service {
}
}
}
ObserverEvent::PredicateInterrupted(PredicateInterruptedData {
predicate_key,
error,
}) => {
if let PredicatesApi::On(ref config) = self.config.http_api {
let Ok(mut predicates_db_conn) =
open_readwrite_predicates_db_conn_verbose(&config, &ctx)
else {
continue;
};
set_predicate_interrupted_status(
error,
&predicate_key,
&mut predicates_db_conn,
&ctx,
);
}
}
ObserverEvent::Terminate => {
info!(
self.ctx.expect_logger(),
Expand Down Expand Up @@ -743,6 +775,16 @@ fn update_status_from_report(
}
}

fn set_predicate_interrupted_status(
error: String,
predicate_key: &str,
predicates_db_conn: &mut Connection,
ctx: &Context,
) {
let status = PredicateStatus::Interrupted(error);
update_predicate_status(predicate_key, status, predicates_db_conn, ctx);
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum StreamingDataType {
Occurrence {
Expand Down
24 changes: 10 additions & 14 deletions components/chainhook-cli/src/service/runloops.rs
Expand Up @@ -15,9 +15,7 @@ use crate::{
bitcoin::scan_bitcoin_chainstate_via_rpc_using_predicate,
stacks::scan_stacks_chainstate_via_rocksdb_using_predicate,
},
service::{
open_readwrite_predicates_db_conn_or_panic, update_predicate_status, PredicateStatus,
},
service::{open_readwrite_predicates_db_conn_or_panic, set_predicate_interrupted_status},
storage::open_readonly_stacks_db_conn,
};

Expand Down Expand Up @@ -73,14 +71,13 @@ pub fn start_stacks_scan_runloop(

// Update predicate status in redis
if let PredicatesApi::On(ref api_config) = moved_config.http_api {
let status = PredicateStatus::Interrupted(format!(
"Unable to evaluate predicate on Stacks chainstate: {e}"
));
let error =
format!("Unable to evaluate predicate on Stacks chainstate: {e}");
let mut predicates_db_conn =
open_readwrite_predicates_db_conn_or_panic(api_config, &moved_ctx);
update_predicate_status(
set_predicate_interrupted_status(
error,
&predicate_spec.key(),
status,
&mut predicates_db_conn,
&moved_ctx,
);
Expand Down Expand Up @@ -147,17 +144,16 @@ pub fn start_bitcoin_scan_runloop(

// Update predicate status in redis
if let PredicatesApi::On(ref api_config) = moved_config.http_api {
let status = PredicateStatus::Interrupted(format!(
"Unable to evaluate predicate on Bitcoin chainstate: {e}"
));
let error =
format!("Unable to evaluate predicate on Bitcoin chainstate: {e}");
let mut predicates_db_conn =
open_readwrite_predicates_db_conn_or_panic(api_config, &moved_ctx);
update_predicate_status(
set_predicate_interrupted_status(
error,
&predicate_spec.key(),
status,
&mut predicates_db_conn,
&moved_ctx,
);
)
}
return;
}
Expand Down
81 changes: 52 additions & 29 deletions components/chainhook-sdk/src/chainhooks/bitcoin/mod.rs
Expand Up @@ -35,6 +35,7 @@ pub struct BitcoinTriggerChainhook<'a> {

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BitcoinTransactionPayload {
#[serde(flatten)]
pub block: BitcoinBlockData,
}

Expand Down Expand Up @@ -233,38 +234,60 @@ pub fn serialize_bitcoin_transactions_to_json<'a>(
.into_iter()
.map(|transaction| {
let mut metadata = serde_json::Map::new();
if predicate_spec.include_inputs {
metadata.insert(
"inputs".into(),
json!(transaction
.metadata
.inputs
.iter()
.map(|input| {
json!({

metadata.insert("fee".into(), json!(transaction.metadata.fee));
metadata.insert("index".into(), json!(transaction.metadata.index));

let inputs = if predicate_spec.include_inputs {
transaction
.metadata
.inputs
.iter()
.map(|input| {
let witness = if predicate_spec.include_witness {
input.witness.clone()
} else {
vec![]
};
json!({
"previous_output": {
"txin": input.previous_output.txid.hash.to_string(),
"vout": input.previous_output.vout,
"sequence": input.sequence,
})
"value": input.previous_output.value,
"block_height": input.previous_output.block_height,
},
"script_sig": input.script_sig,
"sequence": input.sequence,
"witness": witness
})
.collect::<Vec<_>>()),
);
}
if predicate_spec.include_outputs {
metadata.insert("outputs".into(), json!(transaction.metadata.outputs));
}
if !transaction.metadata.stacks_operations.is_empty() {
metadata.insert(
"stacks_operations".into(),
json!(transaction.metadata.stacks_operations),
);
}
if !transaction.metadata.ordinal_operations.is_empty() {
metadata.insert(
"ordinal_operations".into(),
json!(transaction.metadata.ordinal_operations),
);
}
})
.collect::<Vec<_>>()
} else {
vec![]
};
metadata.insert("inputs".into(), json!(inputs));

let outputs = if predicate_spec.include_outputs {
transaction.metadata.outputs.clone()
} else {
vec![]
};
metadata.insert("outputs".into(), json!(outputs));

let stacks_ops = if transaction.metadata.stacks_operations.is_empty() {
vec![]
} else {
transaction.metadata.stacks_operations.clone()
};
metadata.insert("stacks_operations".into(), json!(stacks_ops));

let ordinals_ops = if transaction.metadata.ordinal_operations.is_empty() {
vec![]
} else {
transaction.metadata.ordinal_operations.clone()
};
metadata.insert("ordinal_operations".into(), json!(ordinals_ops));

metadata.insert(
"proof".into(),
json!(proofs.get(&transaction.transaction_identifier)),
Expand Down
59 changes: 59 additions & 0 deletions components/chainhook-sdk/src/chainhooks/bitcoin/tests.rs
@@ -1,8 +1,12 @@
use super::super::types::MatchingRule;
use super::*;
use crate::indexer::tests::helpers::accounts;
use crate::indexer::tests::helpers::bitcoin_blocks::generate_test_bitcoin_block;
use crate::indexer::tests::helpers::transactions::generate_test_tx_bitcoin_p2pkh_transfer;
use crate::types::BitcoinTransactionMetadata;
use chainhook_types::bitcoin::TxOut;

use chainhook_types::BitcoinNetwork;
use test_case::test_case;

#[test_case(
Expand Down Expand Up @@ -134,3 +138,58 @@ fn script_pubkey_evaluation(output: OutputPredicate, script_pubkey: &str, matche

assert_eq!(matches, predicate.evaluate_transaction_predicate(&tx, &ctx));
}

#[test_case(
true, true, true, true;
"including all optional fields"
)]
#[test_case(
false, false, false, false;
"omitting all optional fields"
)]

fn it_serdes_occurrence_payload(
include_proof: bool,
include_inputs: bool,
include_outputs: bool,
include_witness: bool,
) {
let transaction = generate_test_tx_bitcoin_p2pkh_transfer(
0,
&accounts::wallet_1_btc_address(),
&accounts::wallet_3_btc_address(),
3,
);
let block = generate_test_bitcoin_block(0, 0, vec![transaction.clone()], None);
let chainhook = &BitcoinChainhookSpecification {
uuid: "uuid".into(),
owner_uuid: None,
name: "name".into(),
network: BitcoinNetwork::Mainnet,
version: 0,
blocks: None,
start_block: None,
end_block: None,
expire_after_occurrence: None,
predicate: BitcoinPredicateType::Block,
action: HookAction::Noop,
include_proof,
include_inputs,
include_outputs,
include_witness,
enabled: true,
expired_at: None,
};
let trigger = BitcoinTriggerChainhook {
chainhook,
apply: vec![(vec![&transaction], &block)],
rollback: vec![],
};
let payload = serde_json::to_vec(&serialize_bitcoin_payload_to_json(
&trigger,
&HashMap::new(),
))
.unwrap();

let _: BitcoinChainhookOccurrencePayload = serde_json::from_slice(&payload[..]).unwrap();
}

0 comments on commit 4a45617

Please sign in to comment.