From 99e7b1388ba5e54b6065878c878ff84261bcbd13 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Thu, 24 Oct 2024 09:54:13 +0200 Subject: [PATCH 01/11] feat: include recovered signer pubkeys in new block payload --- .../service/tests/helpers/mock_stacks_node.rs | 1 + .../fixtures/stacks/testnet/occurrence.json | 42 ++++++++++----- .../chainhook-sdk/src/indexer/stacks/mod.rs | 53 +++++++++++++++++++ .../indexer/tests/helpers/stacks_blocks.rs | 1 + components/chainhook-types-rs/src/rosetta.rs | 1 + 5 files changed, 84 insertions(+), 14 deletions(-) diff --git a/components/chainhook-cli/src/service/tests/helpers/mock_stacks_node.rs b/components/chainhook-cli/src/service/tests/helpers/mock_stacks_node.rs index 88385368..f4e064e5 100644 --- a/components/chainhook-cli/src/service/tests/helpers/mock_stacks_node.rs +++ b/components/chainhook-cli/src/service/tests/helpers/mock_stacks_node.rs @@ -264,6 +264,7 @@ pub fn create_stacks_new_block( tenure_height: Some(1122), signer_bitvec: Some("000800000001ff".to_owned()), signer_signature: Some(vec!["1234".to_owned(), "2345".to_owned()]), + signer_signature_hash: None, cycle_number: Some(1), reward_set: Some(RewardSet { pox_ustx_threshold: "50000".to_owned(), diff --git a/components/chainhook-sdk/src/chainhooks/tests/fixtures/stacks/testnet/occurrence.json b/components/chainhook-sdk/src/chainhooks/tests/fixtures/stacks/testnet/occurrence.json index d1f9474b..51ce27c9 100644 --- a/components/chainhook-sdk/src/chainhooks/tests/fixtures/stacks/testnet/occurrence.json +++ b/components/chainhook-sdk/src/chainhooks/tests/fixtures/stacks/testnet/occurrence.json @@ -20,7 +20,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -108,7 +109,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -195,7 +197,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -283,7 +286,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -370,7 +374,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -459,7 +464,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -547,7 +553,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -635,7 +642,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -724,7 +732,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -812,7 +821,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -900,7 +910,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -988,7 +999,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -1076,7 +1088,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", @@ -1174,7 +1187,8 @@ "cycle_number": null, "reward_set": null, "signer_bitvec": null, - "signer_signature": null + "signer_signature": null, + "signer_public_keys": null }, "parent_block_identifier": { "hash": "0x", diff --git a/components/chainhook-sdk/src/indexer/stacks/mod.rs b/components/chainhook-sdk/src/indexer/stacks/mod.rs index 21109f4e..8cf9e7ee 100644 --- a/components/chainhook-sdk/src/indexer/stacks/mod.rs +++ b/components/chainhook-sdk/src/indexer/stacks/mod.rs @@ -45,6 +45,9 @@ pub struct NewBlock { #[serde(skip_serializing_if = "Option::is_none")] pub signer_bitvec: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub signer_signature_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub signer_signature: Option>, @@ -472,6 +475,13 @@ pub fn standardize_stacks_block( }) }; + let signer_sig_hash = block + .signer_signature_hash + .as_ref() + .map(|hash| { + hex::decode(&hash[2..]).expect("unable to decode signer_signature hex") + }); + let block = StacksBlockData { block_identifier: BlockIdentifier { hash: block.index_block_hash.clone(), @@ -502,6 +512,19 @@ pub fn standardize_stacks_block( signer_bitvec: block.signer_bitvec.clone(), signer_signature: block.signer_signature.clone(), + signer_public_keys: match (signer_sig_hash, &block.signer_signature) { + (Some(signer_sig_hash), Some(signatures)) => { + Some(signatures.iter().map(|sig_hex| { + let sig_msg = clarity::util::secp256k1::MessageSignature::from_hex(sig_hex) + .expect("unable to parse signer signature message"); + let pubkey = get_signer_pubkey_from_message_hash(&signer_sig_hash, &sig_msg) + .expect("unable to recover signer sig pubkey"); + format!("0x{}", hex::encode(pubkey)) + }).collect()) + } + _ => None, + }, + cycle_number: block.cycle_number, reward_set: block.reward_set.as_ref().and_then(|r| { Some(StacksBlockMetadataRewardSet { @@ -848,6 +871,36 @@ fn get_nakamoto_index_block_hash( Ok(format!("0x{}", hex::encode(hash))) } +pub fn get_signer_pubkey_from_message_hash( + message_hash: &Vec, + signature: &clarity::util::secp256k1::MessageSignature, +) -> Result<[u8; 33], String> { + use miniscript::bitcoin::{ + key::Secp256k1, + secp256k1::{ + ecdsa::{RecoverableSignature, RecoveryId}, + Message, + }, + }; + + let (first, sig) = signature.0.split_at(1); + let rec_id = first[0]; + + let secp = Secp256k1::new(); + let recovery_id = + RecoveryId::from_i32(rec_id as i32).map_err(|e| format!("invalid recovery id: {e}"))?; + let signature = RecoverableSignature::from_compact(&sig, recovery_id) + .map_err(|e| format!("invalid signature: {e}"))?; + let message = + Message::from_digest_slice(&message_hash).map_err(|e| format!("invalid digest message: {e}"))?; + + let pubkey = secp + .recover_ecdsa(&message, &signature) + .map_err(|e| format!("unable to recover pubkey: {e}"))?; + + Ok(pubkey.serialize()) +} + #[cfg(feature = "stacks-signers")] pub fn get_signer_pubkey_from_stackerdb_chunk_slot( slot: &NewSignerModifiedSlot, diff --git a/components/chainhook-sdk/src/indexer/tests/helpers/stacks_blocks.rs b/components/chainhook-sdk/src/indexer/tests/helpers/stacks_blocks.rs index 71123b9f..fcbd1e79 100644 --- a/components/chainhook-sdk/src/indexer/tests/helpers/stacks_blocks.rs +++ b/components/chainhook-sdk/src/indexer/tests/helpers/stacks_blocks.rs @@ -76,6 +76,7 @@ pub fn generate_test_stacks_block( tenure_height: Some(1122), signer_bitvec: Some("1010101010101".to_owned()), signer_signature: Some(vec!["1234".to_owned(), "2345".to_owned()]), + signer_public_keys: Some(vec!["12".to_owned(), "23".to_owned()]), cycle_number: Some(1), reward_set: Some(StacksBlockMetadataRewardSet { pox_ustx_threshold: "50000".to_owned(), diff --git a/components/chainhook-types-rs/src/rosetta.rs b/components/chainhook-types-rs/src/rosetta.rs index ee9066b9..6af1972b 100644 --- a/components/chainhook-types-rs/src/rosetta.rs +++ b/components/chainhook-types-rs/src/rosetta.rs @@ -119,6 +119,7 @@ pub struct StacksBlockMetadata { pub block_time: Option, pub signer_bitvec: Option, pub signer_signature: Option>, + pub signer_public_keys: Option>, // Available starting in epoch3, only included in blocks where the pox cycle rewards are first calculated pub cycle_number: Option, From 15d47441bb61e71da88b1f58e5d6de5326a12260 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Thu, 24 Oct 2024 09:59:11 +0200 Subject: [PATCH 02/11] chore: ts schema update --- components/chainhook-types-js/src/index.ts | 1 + components/client/typescript/src/schemas/stacks/payload.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/components/chainhook-types-js/src/index.ts b/components/chainhook-types-js/src/index.ts index 8f6251d3..5c51c530 100644 --- a/components/chainhook-types-js/src/index.ts +++ b/components/chainhook-types-js/src/index.ts @@ -699,6 +699,7 @@ export interface StacksBlockMetadata { tenure_height?: number | null; signer_bitvec?: string | null; signer_signature?: string[] | null; + signer_public_keys?: string[] | null; cycle_number?: number | null; reward_set?: { pox_ustx_threshold: string; diff --git a/components/client/typescript/src/schemas/stacks/payload.ts b/components/client/typescript/src/schemas/stacks/payload.ts index e25974bf..b8768316 100644 --- a/components/client/typescript/src/schemas/stacks/payload.ts +++ b/components/client/typescript/src/schemas/stacks/payload.ts @@ -74,6 +74,7 @@ export const StacksEventMetadataSchema = Type.Object({ block_time: Nullable(Type.Integer()), signer_bitvec: Nullable(Type.String()), signer_signature: Nullable(Type.Array(Type.String())), + signer_public_keys: Nullable(Type.Array(Type.String())), // Available starting in epoch3, only included in blocks where the pox cycle rewards are first calculated cycle_number: Nullable(Type.Integer()), From dadd638dd559aa77d61cdd46826479c4808de168 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Thu, 24 Oct 2024 11:29:16 +0200 Subject: [PATCH 03/11] fix: update SignerMessage deserializing --- .vscode/chainhook.toml | 46 +++++++++++++++++++ .vscode/launch.json | 24 ++++++++++ Cargo.lock | 4 +- Cargo.toml | 2 +- .../chainhook-sdk/src/indexer/stacks/mod.rs | 6 +-- 5 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 .vscode/chainhook.toml diff --git a/.vscode/chainhook.toml b/.vscode/chainhook.toml new file mode 100644 index 00000000..a01390be --- /dev/null +++ b/.vscode/chainhook.toml @@ -0,0 +1,46 @@ +[storage] +working_dir = "cache" + +# The HTTP API allows you to register / deregister +# predicates dynamically. +# This is disabled by default. +# +[http_api] +http_port = 20456 +database_uri = "redis://localhost:6379/" + +[network] +mode = "testnet" +bitcoind_rpc_url = "http://localhost:18443" +bitcoind_rpc_username = "btc" +bitcoind_rpc_password = "btc" + +# Chainhook must be able to receive Bitcoin block events. +# These events can originate from either a Stacks node or a Bitcoin node's ZeroMQ interface. + +# By default, the service is set to receive Bitcoin block events from the Stacks node: +stacks_node_rpc_url = "http://localhost:20443" +stacks_events_ingestion_port = 20455 + +# However, events can also be received directly from a Bitcoin node. +# To achieve this, comment out the `stacks_node_rpc_url` line and uncomment the following line: +# bitcoind_zmq_url = "tcp://0.0.0.0:18543" + +[limits] +max_number_of_bitcoin_predicates = 100 +max_number_of_concurrent_bitcoin_scans = 100 +max_number_of_stacks_predicates = 10 +max_number_of_concurrent_stacks_scans = 10 +max_number_of_processing_threads = 16 +max_number_of_networking_threads = 16 +max_caching_memory_size_mb = 32000 + +# The TSV file is required for downloading historical data for your predicates. +# If this is not a requirement, you can comment out the `tsv_file_url` line. +# [[event_source]] +# tsv_file_url = "https://archive.hiro.so/regtest/stacks-blockchain-api/regtest-stacks-blockchain-api-latest" + +# Enables a server that provides metrics that can be scraped by Prometheus. +# This is disabled by default. +# [monitoring] +# prometheus_monitoring_port = 20457 diff --git a/.vscode/launch.json b/.vscode/launch.json index 448c74c7..9d0644e2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,30 @@ { "version": "0.2.0", "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'chainhook'", + "cargo": { + "args": [ + "build", + "--bin=chainhook", + "--package=chainhook" + ], + "filter": { + "name": "chainhook", + "kind": "bin" + } + }, + "args": [ + "service", + "start", + "--config-path=${workspaceFolder}/.vscode/chainhook.toml", + ], + "cwd": "${workspaceFolder}", + "preLaunchTask": "redis:start", + "postDebugTask": "redis:stop" + }, { "type": "lldb", "request": "launch", diff --git a/Cargo.lock b/Cargo.lock index 23d5c23e..989eeb26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3549,8 +3549,8 @@ dependencies = [ [[package]] name = "stacks-codec" -version = "2.9.0" -source = "git+https://github.com/hirosystems/clarinet.git?rev=b0683675115562d719ed4b5245f620e0990030a0#b0683675115562d719ed4b5245f620e0990030a0" +version = "2.10.0" +source = "git+https://github.com/hirosystems/clarinet.git?rev=fcebfb5a986ded32d5a450c34f8e5e5f2da97de4#fcebfb5a986ded32d5a450c34f8e5e5f2da97de4" dependencies = [ "clarity", "serde", diff --git a/Cargo.toml b/Cargo.toml index e7694ce1..97b5fc91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,4 @@ default-members = ["components/chainhook-cli", "components/chainhook-sdk"] resolver = "2" [patch.crates-io] -stacks-codec = { git = "https://github.com/hirosystems/clarinet.git", rev = "b0683675115562d719ed4b5245f620e0990030a0" } +stacks-codec = { git = "https://github.com/hirosystems/clarinet.git", rev = "fcebfb5a986ded32d5a450c34f8e5e5f2da97de4" } diff --git a/components/chainhook-sdk/src/indexer/stacks/mod.rs b/components/chainhook-sdk/src/indexer/stacks/mod.rs index 8cf9e7ee..41a6cb4b 100644 --- a/components/chainhook-sdk/src/indexer/stacks/mod.rs +++ b/components/chainhook-sdk/src/indexer/stacks/mod.rs @@ -713,10 +713,10 @@ pub fn standardize_stacks_stackerdb_chunks( }) } SignerMessage::BlockResponse(block_response) => match block_response { - BlockResponse::Accepted((block_hash, sig)) => StacksSignerMessage::BlockResponse( + BlockResponse::Accepted(block_accepted) => StacksSignerMessage::BlockResponse( BlockResponseData::Accepted(BlockAcceptedResponse { - signer_signature_hash: format!("0x{}", block_hash.to_hex()), - sig: format!("0x{}", sig.to_hex()), + signer_signature_hash: format!("0x{}", block_accepted.signer_signature_hash.to_hex()), + sig: format!("0x{}", block_accepted.signature.to_hex()), }), ), BlockResponse::Rejected(block_rejection) => StacksSignerMessage::BlockResponse( From f6450da7a379d542d67e6c6a08ca346fc03ae6ed Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Thu, 24 Oct 2024 11:41:08 +0200 Subject: [PATCH 04/11] feat: include metadata in predicate response --- components/chainhook-sdk/src/indexer/stacks/mod.rs | 6 ++++++ components/chainhook-types-rs/src/signers.rs | 7 +++++++ components/client/typescript/src/schemas/stacks/signers.ts | 6 ++++++ 3 files changed, 19 insertions(+) diff --git a/components/chainhook-sdk/src/indexer/stacks/mod.rs b/components/chainhook-sdk/src/indexer/stacks/mod.rs index 41a6cb4b..09c55dfc 100644 --- a/components/chainhook-sdk/src/indexer/stacks/mod.rs +++ b/components/chainhook-sdk/src/indexer/stacks/mod.rs @@ -717,6 +717,9 @@ pub fn standardize_stacks_stackerdb_chunks( BlockResponseData::Accepted(BlockAcceptedResponse { signer_signature_hash: format!("0x{}", block_accepted.signer_signature_hash.to_hex()), sig: format!("0x{}", block_accepted.signature.to_hex()), + metadata: SignerMessageMetadata { + server_version: block_accepted.metadata.server_version, + } }), ), BlockResponse::Rejected(block_rejection) => StacksSignerMessage::BlockResponse( @@ -768,6 +771,9 @@ pub fn standardize_stacks_stackerdb_chunks( ), chain_id: block_rejection.chain_id, signature: format!("0x{}", block_rejection.signature.to_hex()), + metadata: SignerMessageMetadata { + server_version: block_rejection.metadata.server_version, + }, }), ), }, diff --git a/components/chainhook-types-rs/src/signers.rs b/components/chainhook-types-rs/src/signers.rs index 131a32b6..03aba800 100644 --- a/components/chainhook-types-rs/src/signers.rs +++ b/components/chainhook-types-rs/src/signers.rs @@ -34,6 +34,12 @@ pub struct BlockProposalData { pub struct BlockAcceptedResponse { pub signer_signature_hash: String, pub sig: String, + pub metadata: SignerMessageMetadata, +} + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct SignerMessageMetadata { + pub server_version: String, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] @@ -65,6 +71,7 @@ pub struct BlockRejectedResponse { pub signer_signature_hash: String, pub chain_id: u32, pub signature: String, + pub metadata: SignerMessageMetadata, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] diff --git a/components/client/typescript/src/schemas/stacks/signers.ts b/components/client/typescript/src/schemas/stacks/signers.ts index caa0e2e3..6ac04e2f 100644 --- a/components/client/typescript/src/schemas/stacks/signers.ts +++ b/components/client/typescript/src/schemas/stacks/signers.ts @@ -41,6 +41,9 @@ export const StacksSignerMessageBlockResponseAcceptedSchema = Type.Object({ data: Type.Object({ signer_signature_hash: Type.String(), sig: Type.String(), + metadata: Type.Object({ + server_version: Type.String(), + }), }), }); export type StacksSignerMessageBlockResponseAccepted = Static< @@ -62,6 +65,9 @@ export const StacksSignerMessageBlockResponseRejectedSchema = Type.Object({ signer_signature_hash: Type.String(), chain_id: Type.Integer(), signature: Type.String(), + metadata: Type.Object({ + server_version: Type.String(), + }), }), }); export type StacksSignerMessageBlockResponseRejected = Static< From 30f5d66312c1f5f406318a5635ed5e67da3e9fef Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Thu, 24 Oct 2024 12:43:25 +0200 Subject: [PATCH 05/11] fix: BlockRejectReason serialization --- components/chainhook-sdk/src/indexer/stacks/mod.rs | 6 +++--- components/chainhook-types-rs/src/signers.rs | 5 ++++- .../client/typescript/src/schemas/stacks/signers.ts | 12 +++++++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/components/chainhook-sdk/src/indexer/stacks/mod.rs b/components/chainhook-sdk/src/indexer/stacks/mod.rs index 09c55dfc..7108c26b 100644 --- a/components/chainhook-sdk/src/indexer/stacks/mod.rs +++ b/components/chainhook-sdk/src/indexer/stacks/mod.rs @@ -727,8 +727,8 @@ pub fn standardize_stacks_stackerdb_chunks( reason: block_rejection.reason, reason_code: match block_rejection.reason_code { RejectCode::ValidationFailed(validate_reject_code) => { - BlockRejectReasonCode::ValidationFailed( - match validate_reject_code { + BlockRejectReasonCode::ValidationFailed { + validation_failed: match validate_reject_code { ValidateRejectCode::BadBlockHash => { BlockValidationFailedCode::BadBlockHash } @@ -751,7 +751,7 @@ pub fn standardize_stacks_stackerdb_chunks( BlockValidationFailedCode::NoSuchTenure } }, - ) + } } RejectCode::NoSortitionView => BlockRejectReasonCode::NoSortitionView, RejectCode::ConnectivityIssues => { diff --git a/components/chainhook-types-rs/src/signers.rs b/components/chainhook-types-rs/src/signers.rs index 03aba800..c539a52c 100644 --- a/components/chainhook-types-rs/src/signers.rs +++ b/components/chainhook-types-rs/src/signers.rs @@ -43,6 +43,7 @@ pub struct SignerMessageMetadata { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum BlockValidationFailedCode { BadBlockHash, BadTransaction, @@ -54,9 +55,11 @@ pub enum BlockValidationFailedCode { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[serde(untagged)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum BlockRejectReasonCode { - ValidationFailed(BlockValidationFailedCode), + #[serde(rename_all = "SCREAMING_SNAKE_CASE")] + ValidationFailed { validation_failed: BlockValidationFailedCode }, ConnectivityIssues, RejectedInPriorRound, NoSortitionView, diff --git a/components/client/typescript/src/schemas/stacks/signers.ts b/components/client/typescript/src/schemas/stacks/signers.ts index 6ac04e2f..b668f837 100644 --- a/components/client/typescript/src/schemas/stacks/signers.ts +++ b/components/client/typescript/src/schemas/stacks/signers.ts @@ -55,7 +55,17 @@ export const StacksSignerMessageBlockResponseRejectedSchema = Type.Object({ data: Type.Object({ reason: Type.String(), reason_code: Type.Union([ - Type.Literal('VALIDATION_FAILED'), + Type.Object({ + VALIDATION_FAILED: Type.Union([ + Type.Literal('BAD_BLOCK_HASH'), + Type.Literal('BAD_TRANSACTION'), + Type.Literal('INVALID_BLOCK'), + Type.Literal('CHAINSTATE_ERROR'), + Type.Literal('UNKNOWN_PARENT'), + Type.Literal('NON_CANONICAL_TENURE'), + Type.Literal('NO_SUCH_TENURE'), + ]), + }), Type.Literal('CONNECTIVITY_ISSUES'), Type.Literal('REJECTED_IN_PRIOR_ROUND'), Type.Literal('NO_SORTITION_VIEW'), From a40ff870c79dd74ca9fe231b157cf813930baa16 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Thu, 24 Oct 2024 13:48:11 +0200 Subject: [PATCH 06/11] fix: received_at -> received_at_ms typo --- components/chainhook-sdk/src/chainhooks/stacks/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/chainhook-sdk/src/chainhooks/stacks/mod.rs b/components/chainhook-sdk/src/chainhooks/stacks/mod.rs index 1eb2c7fb..6771dde7 100644 --- a/components/chainhook-sdk/src/chainhooks/stacks/mod.rs +++ b/components/chainhook-sdk/src/chainhooks/stacks/mod.rs @@ -1107,7 +1107,7 @@ fn serialize_stacks_non_consensus_event( }; json!({ "payload": payload, - "received_at": event.received_at_ms, + "received_at_ms": event.received_at_ms, "received_at_block": event.received_at_block, }) } From 53e1ced6f21dda2f03d31cefbbf608dbc699a8f3 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Thu, 24 Oct 2024 14:02:54 +0200 Subject: [PATCH 07/11] chore: error log rather than panic workaround for unexpected non_consensus_event predicate --- components/chainhook-sdk/src/chainhooks/stacks/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/chainhook-sdk/src/chainhooks/stacks/mod.rs b/components/chainhook-sdk/src/chainhooks/stacks/mod.rs index 6771dde7..58724cb8 100644 --- a/components/chainhook-sdk/src/chainhooks/stacks/mod.rs +++ b/components/chainhook-sdk/src/chainhooks/stacks/mod.rs @@ -847,7 +847,7 @@ pub fn evaluate_stacks_predicate_on_block<'a>( pub fn evaluate_stacks_predicate_on_non_consensus_events<'a>( events: &'a Vec, chainhook: &'a StacksChainhookInstance, - _ctx: &Context, + ctx: &Context, ) -> ( Vec<&'a StacksNonConsensusEventData>, BTreeMap<&'a str, &'a BlockIdentifier>, @@ -873,7 +873,11 @@ pub fn evaluate_stacks_predicate_on_non_consensus_events<'a>( | StacksPredicate::NftEvent(_) | StacksPredicate::StxEvent(_) | StacksPredicate::PrintEvent(_) - | StacksPredicate::Txid(_) => unreachable!(), + | StacksPredicate::Txid(_) => { + ctx.try_log(|logger| { + slog::error!(logger, "Invalid predicate for non-consensus events: {:?}", chainhook.predicate) + }); + }, }; } (occurrences, expired_predicates) From 0ad66455d6a1c4a813ef5dabb608d51aa7844b65 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Thu, 24 Oct 2024 14:46:52 +0200 Subject: [PATCH 08/11] fix: consistent signature field naming between BlockAccept and BlockReject payloads --- components/chainhook-sdk/src/indexer/stacks/mod.rs | 2 +- components/chainhook-sdk/src/indexer/stacks/tests.rs | 2 +- components/chainhook-types-rs/src/signers.rs | 2 +- components/client/typescript/src/schemas/stacks/signers.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/chainhook-sdk/src/indexer/stacks/mod.rs b/components/chainhook-sdk/src/indexer/stacks/mod.rs index 7108c26b..67fe2a40 100644 --- a/components/chainhook-sdk/src/indexer/stacks/mod.rs +++ b/components/chainhook-sdk/src/indexer/stacks/mod.rs @@ -716,7 +716,7 @@ pub fn standardize_stacks_stackerdb_chunks( BlockResponse::Accepted(block_accepted) => StacksSignerMessage::BlockResponse( BlockResponseData::Accepted(BlockAcceptedResponse { signer_signature_hash: format!("0x{}", block_accepted.signer_signature_hash.to_hex()), - sig: format!("0x{}", block_accepted.signature.to_hex()), + signature: format!("0x{}", block_accepted.signature.to_hex()), metadata: SignerMessageMetadata { server_version: block_accepted.metadata.server_version, } diff --git a/components/chainhook-sdk/src/indexer/stacks/tests.rs b/components/chainhook-sdk/src/indexer/stacks/tests.rs index e5ae1bf9..e7f1c6f2 100644 --- a/components/chainhook-sdk/src/indexer/stacks/tests.rs +++ b/components/chainhook-sdk/src/indexer/stacks/tests.rs @@ -427,7 +427,7 @@ fn stackerdb_chunks_covert_into_signer_messages() { match &message.message { StacksSignerMessage::BlockResponse(block_response_data) => match block_response_data { BlockResponseData::Accepted(block_accepted_response) => { - assert_eq!(block_accepted_response.sig, "0x005eb55250597b25acbf99d3dd3c2fa8189046e1b5d21309a44cbaf2b327c09b0159a01ed3f0094bfa9e5f72f5d894e12ce252081eab5396eb8bba137bddfc365b"); + assert_eq!(block_accepted_response.signature, "0x005eb55250597b25acbf99d3dd3c2fa8189046e1b5d21309a44cbaf2b327c09b0159a01ed3f0094bfa9e5f72f5d894e12ce252081eab5396eb8bba137bddfc365b"); assert_eq!( block_accepted_response.signer_signature_hash, "0x74aff146904763a787aa14c614d0dd1fc63b537bdb2fd351cdf881f6db75f986" diff --git a/components/chainhook-types-rs/src/signers.rs b/components/chainhook-types-rs/src/signers.rs index c539a52c..36662a3a 100644 --- a/components/chainhook-types-rs/src/signers.rs +++ b/components/chainhook-types-rs/src/signers.rs @@ -33,7 +33,7 @@ pub struct BlockProposalData { #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct BlockAcceptedResponse { pub signer_signature_hash: String, - pub sig: String, + pub signature: String, pub metadata: SignerMessageMetadata, } diff --git a/components/client/typescript/src/schemas/stacks/signers.ts b/components/client/typescript/src/schemas/stacks/signers.ts index b668f837..7b9ceeb8 100644 --- a/components/client/typescript/src/schemas/stacks/signers.ts +++ b/components/client/typescript/src/schemas/stacks/signers.ts @@ -40,7 +40,7 @@ export const StacksSignerMessageBlockResponseAcceptedSchema = Type.Object({ type: Type.Literal('Accepted'), data: Type.Object({ signer_signature_hash: Type.String(), - sig: Type.String(), + signature: Type.String(), metadata: Type.Object({ server_version: Type.String(), }), From 7584f491f8411094dacab1776b13aa1e023dfa56 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Thu, 24 Oct 2024 14:56:24 +0200 Subject: [PATCH 09/11] fix: BlockRejectReasonCode serialization tweak --- components/chainhook-types-rs/src/signers.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/chainhook-types-rs/src/signers.rs b/components/chainhook-types-rs/src/signers.rs index 36662a3a..c0754dd2 100644 --- a/components/chainhook-types-rs/src/signers.rs +++ b/components/chainhook-types-rs/src/signers.rs @@ -55,11 +55,13 @@ pub enum BlockValidationFailedCode { } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -#[serde(untagged)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum BlockRejectReasonCode { #[serde(rename_all = "SCREAMING_SNAKE_CASE")] - ValidationFailed { validation_failed: BlockValidationFailedCode }, + ValidationFailed { + #[serde(rename = "VALIDATION_FAILED")] + validation_failed: BlockValidationFailedCode, + }, ConnectivityIssues, RejectedInPriorRound, NoSortitionView, From 5269732ec84ab4eaf53a0bd0d8b879319c4d5d91 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Thu, 24 Oct 2024 19:21:05 +0200 Subject: [PATCH 10/11] chore: ignore invalid predicates for non-consensus events --- components/chainhook-sdk/src/chainhooks/stacks/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/chainhook-sdk/src/chainhooks/stacks/mod.rs b/components/chainhook-sdk/src/chainhooks/stacks/mod.rs index 58724cb8..a59344ea 100644 --- a/components/chainhook-sdk/src/chainhooks/stacks/mod.rs +++ b/components/chainhook-sdk/src/chainhooks/stacks/mod.rs @@ -847,7 +847,7 @@ pub fn evaluate_stacks_predicate_on_block<'a>( pub fn evaluate_stacks_predicate_on_non_consensus_events<'a>( events: &'a Vec, chainhook: &'a StacksChainhookInstance, - ctx: &Context, + _ctx: &Context, ) -> ( Vec<&'a StacksNonConsensusEventData>, BTreeMap<&'a str, &'a BlockIdentifier>, @@ -874,9 +874,8 @@ pub fn evaluate_stacks_predicate_on_non_consensus_events<'a>( | StacksPredicate::StxEvent(_) | StacksPredicate::PrintEvent(_) | StacksPredicate::Txid(_) => { - ctx.try_log(|logger| { - slog::error!(logger, "Invalid predicate for non-consensus events: {:?}", chainhook.predicate) - }); + // Ignore, possibly expected behavior? + // https://github.com/hirosystems/chainhook/pull/663#discussion_r1814995429 }, }; } From c3a8b7515d02afbd67db97215ab88fd80ef16ad4 Mon Sep 17 00:00:00 2001 From: Matthew Little Date: Thu, 24 Oct 2024 19:37:18 +0200 Subject: [PATCH 11/11] chore: propagate signer pubkey recovery errors in newblock processing --- components/chainhook-sdk/src/indexer/stacks/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/chainhook-sdk/src/indexer/stacks/mod.rs b/components/chainhook-sdk/src/indexer/stacks/mod.rs index 8cf9e7ee..8b1c2aa9 100644 --- a/components/chainhook-sdk/src/indexer/stacks/mod.rs +++ b/components/chainhook-sdk/src/indexer/stacks/mod.rs @@ -516,11 +516,12 @@ pub fn standardize_stacks_block( (Some(signer_sig_hash), Some(signatures)) => { Some(signatures.iter().map(|sig_hex| { let sig_msg = clarity::util::secp256k1::MessageSignature::from_hex(sig_hex) - .expect("unable to parse signer signature message"); + .map_err(|e| format!("unable to parse signer signature message: {}", e))?; let pubkey = get_signer_pubkey_from_message_hash(&signer_sig_hash, &sig_msg) - .expect("unable to recover signer sig pubkey"); - format!("0x{}", hex::encode(pubkey)) - }).collect()) + .map_err(|e| format!("unable to recover signer sig pubkey: {}", e))?; + Ok(format!("0x{}", hex::encode(pubkey))) + }) + .collect::, String>>()?) } _ => None, },