From a6164ea05a77a1932418c02a002a7c3bf352caaf Mon Sep 17 00:00:00 2001 From: Ludo Galabru Date: Tue, 26 Dec 2023 11:47:15 -0500 Subject: [PATCH] feat: broadcast ObserverEvent::BitcoinPredicateTriggered on successful requests --- .../src/chainhooks/bitcoin/mod.rs | 95 ++++++++++--------- components/chainhook-sdk/src/observer/mod.rs | 12 ++- 2 files changed, 60 insertions(+), 47 deletions(-) diff --git a/components/chainhook-sdk/src/chainhooks/bitcoin/mod.rs b/components/chainhook-sdk/src/chainhooks/bitcoin/mod.rs index 4fe7c93d8..83a23da3d 100644 --- a/components/chainhook-sdk/src/chainhooks/bitcoin/mod.rs +++ b/components/chainhook-sdk/src/chainhooks/bitcoin/mod.rs @@ -49,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::>(); + BitcoinTransactionPayload { block } + }) + .collect::>(), + rollback: trigger + .rollback + .into_iter() + .map(|(transactions, block)| { + let mut block = block.clone(); + block.transactions = transactions + .into_iter() + .map(|t| t.clone()) + .collect::>(); + BitcoinTransactionPayload { block } + }) + .collect::>(), + chainhook: BitcoinChainhookPayload { + uuid: trigger.chainhook.uuid.clone(), + }, + } + } +} + pub enum BitcoinChainhookOccurrence { - Http(RequestBuilder), + Http(RequestBuilder, BitcoinChainhookOccurrencePayload), File(String, Vec), Data(BitcoinChainhookOccurrencePayload), } @@ -156,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, @@ -170,7 +206,7 @@ pub fn serialize_bitcoin_payload_to_json<'a>( "metadata": block.metadata, }) }).collect::>(), - "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, @@ -252,18 +288,19 @@ 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(), @@ -271,35 +308,7 @@ pub fn handle_bitcoin_hook_action<'a>( )) } 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::>(); - BitcoinTransactionPayload { block } - }) - .collect::>(), - rollback: trigger - .rollback - .into_iter() - .map(|(transactions, block)| { - let mut block = block.clone(); - block.transactions = transactions - .into_iter() - .map(|t| t.clone()) - .collect::>(); - BitcoinTransactionPayload { block } - }) - .collect::>(), - chainhook: BitcoinChainhookPayload { - uuid: trigger.chainhook.uuid.clone(), - }, - }, + BitcoinChainhookOccurrencePayload::from_trigger(trigger), )), } } diff --git a/components/chainhook-sdk/src/observer/mod.rs b/components/chainhook-sdk/src/observer/mod.rs index de3f6be46..170b47c2b 100644 --- a/components/chainhook-sdk/src/observer/mod.rs +++ b/components/chainhook-sdk/src/observer/mod.rs @@ -1121,8 +1121,8 @@ pub async fn start_observer_commands_handler( slog::error!(logger, "unable to handle action {}", e) }); } - Ok(BitcoinChainhookOccurrence::Http(request)) => { - requests.push(request); + Ok(BitcoinChainhookOccurrence::Http(request, data)) => { + requests.push((request, data)); } Ok(BitcoinChainhookOccurrence::File(_path, _bytes)) => { ctx.try_log(|logger| { @@ -1168,8 +1168,12 @@ pub async fn start_observer_commands_handler( } } - for request in requests.into_iter() { - let _ = send_request(request, 3, 1, &ctx).await; + for (request, data) in requests.into_iter() { + if send_request(request, 3, 1, &ctx).await.is_ok() { + if let Some(ref tx) = observer_events_tx { + let _ = tx.send(ObserverEvent::BitcoinPredicateTriggered(data)); + } + } } if let Some(ref tx) = observer_events_tx {