From 540fcd4481d365952ae3904b8d5aa78b76536992 Mon Sep 17 00:00:00 2001 From: Hank Stoever Date: Fri, 18 Oct 2024 16:13:33 -0700 Subject: [PATCH 1/4] chore: convert BlockAccepted to a struct --- libsigner/src/v0/messages.rs | 107 +++++++++++++++--- stacks-signer/src/v0/signer.rs | 32 +++--- .../src/nakamoto_node/sign_coordinator.rs | 13 ++- testnet/stacks-node/src/tests/signer/mod.rs | 11 +- testnet/stacks-node/src/tests/signer/v0.rs | 41 +++---- 5 files changed, 142 insertions(+), 62 deletions(-) diff --git a/libsigner/src/v0/messages.rs b/libsigner/src/v0/messages.rs index 47d317992d..102da15a1d 100644 --- a/libsigner/src/v0/messages.rs +++ b/libsigner/src/v0/messages.rs @@ -603,7 +603,7 @@ impl From<&BlockResponse> for BlockResponseTypePrefix { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum BlockResponse { /// The Nakamoto block was accepted and therefore signed - Accepted((Sha512Trunc256Sum, MessageSignature)), + Accepted(BlockAccepted), /// The Nakamoto block was rejected and therefore not signed Rejected(BlockRejection), } @@ -616,7 +616,7 @@ impl std::fmt::Display for BlockResponse { write!( f, "BlockAccepted: signer_sighash = {}, signature = {}", - a.0, a.1 + a.signer_signature_hash, a.signature ) } BlockResponse::Rejected(r) => { @@ -633,7 +633,10 @@ impl std::fmt::Display for BlockResponse { impl BlockResponse { /// Create a new accepted BlockResponse for the provided block signer signature hash and signature pub fn accepted(hash: Sha512Trunc256Sum, sig: MessageSignature) -> Self { - Self::Accepted((hash, sig)) + Self::Accepted(BlockAccepted { + signer_signature_hash: hash, + signature: sig, + }) } /// Create a new rejected BlockResponse for the provided block signer signature hash and rejection code and sign it with the provided private key @@ -651,9 +654,8 @@ impl StacksMessageCodec for BlockResponse { fn consensus_serialize(&self, fd: &mut W) -> Result<(), CodecError> { write_next(fd, &(BlockResponseTypePrefix::from(self) as u8))?; match self { - BlockResponse::Accepted((hash, sig)) => { - write_next(fd, hash)?; - write_next(fd, sig)?; + BlockResponse::Accepted(accepted) => { + write_next(fd, accepted)?; } BlockResponse::Rejected(rejection) => { write_next(fd, rejection)?; @@ -667,9 +669,8 @@ impl StacksMessageCodec for BlockResponse { let type_prefix = BlockResponseTypePrefix::try_from(type_prefix_byte)?; let response = match type_prefix { BlockResponseTypePrefix::Accepted => { - let hash = read_next::(fd)?; - let sig = read_next::(fd)?; - BlockResponse::Accepted((hash, sig)) + let accepted = read_next::(fd)?; + BlockResponse::Accepted(accepted) } BlockResponseTypePrefix::Rejected => { let rejection = read_next::(fd)?; @@ -680,6 +681,32 @@ impl StacksMessageCodec for BlockResponse { } } +/// A rejection response from a signer for a proposed block +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct BlockAccepted { + /// The signer signature hash of the block that was accepted + pub signer_signature_hash: Sha512Trunc256Sum, + /// The signer's signature across the acceptance + pub signature: MessageSignature, +} + +impl StacksMessageCodec for BlockAccepted { + fn consensus_serialize(&self, fd: &mut W) -> Result<(), CodecError> { + write_next(fd, &self.signer_signature_hash)?; + write_next(fd, &self.signature)?; + Ok(()) + } + + fn consensus_deserialize(fd: &mut R) -> Result { + let signer_signature_hash = read_next::(fd)?; + let signature = read_next::(fd)?; + Ok(Self { + signer_signature_hash, + signature, + }) + } +} + /// A rejection response from a signer for a proposed block #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct BlockRejection { @@ -894,7 +921,7 @@ mod test { use clarity::consts::CHAIN_ID_MAINNET; use clarity::types::chainstate::{ConsensusHash, StacksBlockId, TrieHash}; use clarity::types::PrivateKey; - use clarity::util::hash::MerkleTree; + use clarity::util::hash::{hex_bytes, MerkleTree}; use clarity::util::secp256k1::MessageSignature; use rand::rngs::mock; use rand::{thread_rng, Rng, RngCore}; @@ -958,8 +985,11 @@ mod test { #[test] fn serde_block_response() { - let response = - BlockResponse::Accepted((Sha512Trunc256Sum([0u8; 32]), MessageSignature::empty())); + let accepted = BlockAccepted { + signer_signature_hash: Sha512Trunc256Sum([0u8; 32]), + signature: MessageSignature::empty(), + }; + let response = BlockResponse::Accepted(accepted); let serialized_response = response.serialize_to_vec(); let deserialized_response = read_next::(&mut &serialized_response[..]) .expect("Failed to deserialize BlockResponse"); @@ -979,10 +1009,11 @@ mod test { #[test] fn serde_signer_message() { - let signer_message = SignerMessage::BlockResponse(BlockResponse::Accepted(( - Sha512Trunc256Sum([2u8; 32]), - MessageSignature::empty(), - ))); + let accepted = BlockAccepted { + signer_signature_hash: Sha512Trunc256Sum([2u8; 32]), + signature: MessageSignature::empty(), + }; + let signer_message = SignerMessage::BlockResponse(BlockResponse::Accepted(accepted)); let serialized_signer_message = signer_message.serialize_to_vec(); let deserialized_signer_message = read_next::(&mut &serialized_signer_message[..]) @@ -1122,4 +1153,48 @@ mod test { .expect("Failed to deserialize MockSignData"); assert_eq!(mock_block, deserialized_data); } + + #[test] + fn test_backwards_compatibility() { + let block_rejected_hex = "010100000050426c6f636b206973206e6f7420612074656e7572652d737461727420626c6f636b2c20616e642068617320616e20756e7265636f676e697a65642074656e75726520636f6e73656e7375732068617368000691f95f84b7045f7dce7757052caa986ef042cb58f7df5031a3b5b5d0e3dda63e80000000006fb349212e1a1af1a3c712878d5159b5ec14636adb6f70be00a6da4ad4f88a9934d8a9abb229620dd8e0f225d63401e36c64817fb29e6c05591dcbe95c512df3"; + let block_rejected_bytes = hex_bytes(&block_rejected_hex).unwrap(); + let block_accepted_hex = "010011717149677c2ac97d15ae5954f7a716f10100b9cb81a2bf27551b2f2e54ef19001c694f8134c5c90f2f2bcd330e9f423204884f001b5df0050f36a2c4ff79dd93522bb2ae395ea87de4964886447507c18374b7a46ee2e371e9bf332f0706a3e8"; + let block_accepted_bytes = hex_bytes(&block_accepted_hex).unwrap(); + let block_rejected = read_next::(&mut &block_rejected_bytes[..]) + .expect("Failed to deserialize BlockRejection"); + let block_accepted = read_next::(&mut &block_accepted_bytes[..]) + .expect("Failed to deserialize BlockRejection"); + + assert_eq!( + block_rejected, + SignerMessage::BlockResponse(BlockResponse::Rejected(BlockRejection { + reason_code: RejectCode::ValidationFailed(ValidateRejectCode::NoSuchTenure), + reason: "Block is not a tenure-start block, and has an unrecognized tenure consensus hash".to_string(), + signer_signature_hash: Sha512Trunc256Sum([145, 249, 95, 132, 183, 4, 95, 125, 206, 119, 87, 5, 44, 170, 152, 110, 240, 66, 203, 88, 247, 223, 80, 49, 163, 181, 181, 208, 227, 221, 166, 62]), + chain_id: CHAIN_ID_TESTNET, + signature: MessageSignature([ + 0, 111, 179, 73, 33, 46, 26, 26, 241, 163, 199, 18, 135, 141, 81, 89, 181, 236, + 20, 99, 106, 219, 111, 112, 190, 0, 166, 218, 74, 212, 248, 138, 153, 52, 216, + 169, 171, 178, 41, 98, 13, 216, 224, 242, 37, 214, 52, 1, 227, 108, 100, 129, + 127, 178, 158, 108, 5, 89, 29, 203, 233, 92, 81, 45, 243, + ]), + })) + ); + + assert_eq!( + block_accepted, + SignerMessage::BlockResponse(BlockResponse::Accepted(BlockAccepted { + signer_signature_hash: Sha512Trunc256Sum([ + 17, 113, 113, 73, 103, 124, 42, 201, 125, 21, 174, 89, 84, 247, 167, 22, 241, + 1, 0, 185, 203, 129, 162, 191, 39, 85, 27, 47, 46, 84, 239, 25 + ]), + signature: MessageSignature([ + 0, 28, 105, 79, 129, 52, 197, 201, 15, 47, 43, 205, 51, 14, 159, 66, 50, 4, + 136, 79, 0, 27, 93, 240, 5, 15, 54, 162, 196, 255, 121, 221, 147, 82, 43, 178, + 174, 57, 94, 168, 125, 228, 150, 72, 134, 68, 117, 7, 193, 131, 116, 183, 164, + 110, 226, 227, 113, 233, 191, 51, 47, 7, 6, 163, 232 + ]), + })) + ); + } } diff --git a/stacks-signer/src/v0/signer.rs b/stacks-signer/src/v0/signer.rs index 5d068fad0f..fe626cb11f 100644 --- a/stacks-signer/src/v0/signer.rs +++ b/stacks-signer/src/v0/signer.rs @@ -25,14 +25,13 @@ use clarity::types::{PrivateKey, StacksEpochId}; use clarity::util::hash::MerkleHashFunc; use clarity::util::secp256k1::Secp256k1PublicKey; use libsigner::v0::messages::{ - BlockRejection, BlockResponse, MessageSlotID, MockProposal, MockSignature, RejectCode, - SignerMessage, + BlockAccepted, BlockRejection, BlockResponse, MessageSlotID, MockProposal, MockSignature, + RejectCode, SignerMessage, }; use libsigner::{BlockProposal, SignerEvent}; use slog::{slog_debug, slog_error, slog_info, slog_warn}; use stacks_common::types::chainstate::StacksAddress; use stacks_common::util::get_epoch_time_secs; -use stacks_common::util::hash::Sha512Trunc256Sum; use stacks_common::util::secp256k1::MessageSignature; use stacks_common::{debug, error, info, warn}; @@ -494,8 +493,8 @@ impl Signer { block_response: &BlockResponse, ) { match block_response { - BlockResponse::Accepted((block_hash, signature)) => { - self.handle_block_signature(stacks_client, block_hash, signature); + BlockResponse::Accepted(accepted) => { + self.handle_block_signature(stacks_client, accepted); } BlockResponse::Rejected(block_rejection) => { self.handle_block_rejection(block_rejection); @@ -547,13 +546,13 @@ impl Signer { self.signer_db .insert_block(&block_info) .unwrap_or_else(|_| panic!("{self}: Failed to insert block in DB")); + let accepted = BlockAccepted { + signer_signature_hash: block_info.signer_signature_hash(), + signature, + }; // have to save the signature _after_ the block info - self.handle_block_signature( - stacks_client, - &block_info.signer_signature_hash(), - &signature, - ); - Some(BlockResponse::accepted(signer_signature_hash, signature)) + self.handle_block_signature(stacks_client, &accepted); + Some(BlockResponse::Accepted(accepted)) } /// Handle the block validate reject response. Returns our block response if we have one @@ -739,12 +738,11 @@ impl Signer { } /// Handle an observed signature from another signer - fn handle_block_signature( - &mut self, - stacks_client: &StacksClient, - block_hash: &Sha512Trunc256Sum, - signature: &MessageSignature, - ) { + fn handle_block_signature(&mut self, stacks_client: &StacksClient, accepted: &BlockAccepted) { + let BlockAccepted { + signer_signature_hash: block_hash, + signature, + } = accepted; debug!("{self}: Received a block-accept signature: ({block_hash}, {signature})"); // Have we already processed this block? diff --git a/testnet/stacks-node/src/nakamoto_node/sign_coordinator.rs b/testnet/stacks-node/src/nakamoto_node/sign_coordinator.rs index 2694d1d9ca..1954f6eb12 100644 --- a/testnet/stacks-node/src/nakamoto_node/sign_coordinator.rs +++ b/testnet/stacks-node/src/nakamoto_node/sign_coordinator.rs @@ -20,7 +20,9 @@ use std::sync::Arc; use std::time::Duration; use hashbrown::{HashMap, HashSet}; -use libsigner::v0::messages::{BlockResponse, MinerSlotID, SignerMessage as SignerMessageV0}; +use libsigner::v0::messages::{ + BlockAccepted, BlockResponse, MinerSlotID, SignerMessage as SignerMessageV0, +}; use libsigner::{BlockProposal, SignerEntries, SignerEvent, SignerSession, StackerDBSession}; use stacks::burnchains::Burnchain; use stacks::chainstate::burn::db::sortdb::SortitionDB; @@ -450,10 +452,11 @@ impl SignCoordinator { } match message { - SignerMessageV0::BlockResponse(BlockResponse::Accepted(( - response_hash, - signature, - ))) => { + SignerMessageV0::BlockResponse(BlockResponse::Accepted(accepted)) => { + let BlockAccepted { + signer_signature_hash: response_hash, + signature, + } = accepted; let block_sighash = block.header.signer_signature_hash(); if block_sighash != response_hash { warn!( diff --git a/testnet/stacks-node/src/tests/signer/mod.rs b/testnet/stacks-node/src/tests/signer/mod.rs index 2e67234285..5fb318e234 100644 --- a/testnet/stacks-node/src/tests/signer/mod.rs +++ b/testnet/stacks-node/src/tests/signer/mod.rs @@ -36,7 +36,7 @@ use std::time::{Duration, Instant}; use clarity::boot_util::boot_code_id; use clarity::vm::types::PrincipalData; -use libsigner::v0::messages::{BlockResponse, SignerMessage}; +use libsigner::v0::messages::{BlockAccepted, BlockResponse, SignerMessage}; use libsigner::{SignerEntries, SignerEventTrait}; use stacks::chainstate::coordinator::comm::CoordinatorChannels; use stacks::chainstate::nakamoto::signer_set::NakamotoSigners; @@ -578,10 +578,11 @@ impl + Send + 'static, T: SignerEventTrait + 'static> SignerTest { + SignerMessage::BlockResponse(BlockResponse::Accepted(accepted)) => { + let BlockAccepted { + signer_signature_hash: hash, + signature, + } = accepted; if hash == *signer_signature_hash && expected_signers.iter().any(|pk| { pk.verify(hash.bits(), &signature) diff --git a/testnet/stacks-node/src/tests/signer/v0.rs b/testnet/stacks-node/src/tests/signer/v0.rs index 753883bead..6fc4c7078a 100644 --- a/testnet/stacks-node/src/tests/signer/v0.rs +++ b/testnet/stacks-node/src/tests/signer/v0.rs @@ -3411,7 +3411,7 @@ fn duplicate_signers() { }) .filter_map(|message| match message { SignerMessage::BlockResponse(BlockResponse::Accepted(m)) => { - info!("Message(accepted): {message:?}"); + info!("Message(accepted): {:?}", &m); Some(m) } _ => { @@ -3425,20 +3425,23 @@ fn duplicate_signers() { info!("------------------------- Assert there are {unique_signers} unique signatures and recovered pubkeys -------------------------"); // Pick a message hash - let (selected_sighash, _) = signer_accepted_responses + let accepted = signer_accepted_responses .iter() - .min_by_key(|(sighash, _)| *sighash) - .copied() + .min_by_key(|accepted| accepted.signer_signature_hash) .expect("No `BlockResponse::Accepted` messages recieved"); + let selected_sighash = accepted.signer_signature_hash; // Filter only resonses for selected block and collect unique pubkeys and signatures let (pubkeys, signatures): (HashSet<_>, HashSet<_>) = signer_accepted_responses .into_iter() - .filter(|(hash, _)| *hash == selected_sighash) - .map(|(msg, sig)| { - let pubkey = Secp256k1PublicKey::recover_to_pubkey(msg.bits(), &sig) - .expect("Failed to recover pubkey"); - (pubkey, sig) + .filter(|accepted| accepted.signer_signature_hash == selected_sighash) + .map(|accepted| { + let pubkey = Secp256k1PublicKey::recover_to_pubkey( + accepted.signer_signature_hash.bits(), + &accepted.signature, + ) + .expect("Failed to recover pubkey"); + (pubkey, accepted.signature) }) .unzip(); @@ -4652,10 +4655,11 @@ fn reorg_locally_accepted_blocks_across_tenures_succeeds() { let message = SignerMessage::consensus_deserialize(&mut chunk.data.as_slice()) .expect("Failed to deserialize SignerMessage"); match message { - SignerMessage::BlockResponse(BlockResponse::Accepted((hash, signature))) => { - ignoring_signers - .iter() - .find(|key| key.verify(hash.bits(), &signature).is_ok()) + SignerMessage::BlockResponse(BlockResponse::Accepted(accepted)) => { + ignoring_signers.iter().find(|key| { + key.verify(accepted.signer_signature_hash.bits(), &accepted.signature) + .is_ok() + }) } _ => None, } @@ -4896,12 +4900,11 @@ fn miner_recovers_when_broadcast_block_delay_across_tenures_occurs() { let message = SignerMessage::consensus_deserialize(&mut chunk.data.as_slice()) .expect("Failed to deserialize SignerMessage"); match message { - SignerMessage::BlockResponse(BlockResponse::Accepted(( - hash, - signature, - ))) => { - if block.header.signer_signature_hash() == hash { - Some(signature) + SignerMessage::BlockResponse(BlockResponse::Accepted(accepted)) => { + if block.header.signer_signature_hash() + == accepted.signer_signature_hash + { + Some(accepted.signature) } else { None } From 5f4c42fc5a28bb8f19a2a212f6587d2f1c64b9bb Mon Sep 17 00:00:00 2001 From: Hank Stoever Date: Fri, 18 Oct 2024 16:54:27 -0700 Subject: [PATCH 2/4] feat: add signer message metadata to block responses --- libsigner/src/libsigner.rs | 10 ++ libsigner/src/v0/messages.rs | 148 +++++++++++++++++- stacks-signer/src/cli.rs | 3 +- stacks-signer/src/client/stackerdb.rs | 5 +- stacks-signer/src/lib.rs | 12 +- stacks-signer/src/main.rs | 3 +- stacks-signer/src/monitoring/server.rs | 2 +- stacks-signer/src/v0/signer.rs | 11 +- .../src/nakamoto_node/sign_coordinator.rs | 7 +- testnet/stacks-node/src/tests/signer/mod.rs | 17 +- testnet/stacks-node/src/tests/signer/v0.rs | 4 +- 11 files changed, 183 insertions(+), 39 deletions(-) diff --git a/libsigner/src/libsigner.rs b/libsigner/src/libsigner.rs index 878d428bfc..b1b760af6d 100644 --- a/libsigner/src/libsigner.rs +++ b/libsigner/src/libsigner.rs @@ -49,8 +49,10 @@ use std::cmp::Eq; use std::fmt::Debug; use std::hash::Hash; +use blockstack_lib::version_string; use clarity::codec::StacksMessageCodec; use clarity::vm::types::QualifiedContractIdentifier; +use lazy_static::lazy_static; pub use crate::error::{EventError, RPCError}; pub use crate::events::{ @@ -74,3 +76,11 @@ pub trait SignerMessage: StacksMessageCodec { /// The contract identifier for the message slot in stacker db fn msg_id(&self) -> Option; } + +lazy_static! { + /// The version string for the signer + pub static ref VERSION_STRING: String = { + let pkg_version = option_env!("STACKS_NODE_VERSION").unwrap_or(env!("CARGO_PKG_VERSION")); + version_string("stacks-signer", pkg_version) + }; +} diff --git a/libsigner/src/v0/messages.rs b/libsigner/src/v0/messages.rs index 102da15a1d..264a4cc107 100644 --- a/libsigner/src/v0/messages.rs +++ b/libsigner/src/v0/messages.rs @@ -70,7 +70,7 @@ use crate::http::{decode_http_body, decode_http_request}; use crate::stacks_common::types::PublicKey; use crate::{ BlockProposal, EventError, MessageSlotID as MessageSlotIDTrait, - SignerMessage as SignerMessageTrait, + SignerMessage as SignerMessageTrait, VERSION_STRING, }; define_u8_enum!( @@ -615,15 +615,15 @@ impl std::fmt::Display for BlockResponse { BlockResponse::Accepted(a) => { write!( f, - "BlockAccepted: signer_sighash = {}, signature = {}", - a.signer_signature_hash, a.signature + "BlockAccepted: signer_sighash = {}, signature = {}, version = {}", + a.signer_signature_hash, a.signature, a.metadata.server_version ) } BlockResponse::Rejected(r) => { write!( f, - "BlockRejected: signer_sighash = {}, code = {}, reason = {}, signature = {}", - r.reason_code, r.reason, r.signer_signature_hash, r.signature + "BlockRejected: signer_sighash = {}, code = {}, reason = {}, signature = {}, version = {}", + r.reason_code, r.reason, r.signer_signature_hash, r.signature, r.metadata.server_version ) } } @@ -636,6 +636,7 @@ impl BlockResponse { Self::Accepted(BlockAccepted { signer_signature_hash: hash, signature: sig, + metadata: SignerMessageMetadata::default(), }) } @@ -681,6 +682,57 @@ impl StacksMessageCodec for BlockResponse { } } +/// Metadata for signer messages +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct SignerMessageMetadata { + /// The signer's server version + pub server_version: String, +} + +/// To ensure backwards compatibility, when deserializing, +/// if no bytes are found, return empty metadata +impl StacksMessageCodec for SignerMessageMetadata { + fn consensus_serialize(&self, fd: &mut W) -> Result<(), CodecError> { + write_next(fd, &self.server_version.as_bytes().to_vec())?; + Ok(()) + } + + fn consensus_deserialize(fd: &mut R) -> Result { + match read_next::, _>(fd) { + Ok(server_version) => { + let server_version = String::from_utf8(server_version).map_err(|e| { + CodecError::DeserializeError(format!( + "Failed to decode server version: {:?}", + &e + )) + })?; + Ok(Self { server_version }) + } + Err(_) => { + // For backwards compatibility, return empty metadata + Ok(Self::empty()) + } + } + } +} + +impl Default for SignerMessageMetadata { + fn default() -> Self { + Self { + server_version: VERSION_STRING.to_string(), + } + } +} + +impl SignerMessageMetadata { + /// Empty metadata + pub fn empty() -> Self { + Self { + server_version: String::new(), + } + } +} + /// A rejection response from a signer for a proposed block #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct BlockAccepted { @@ -688,25 +740,41 @@ pub struct BlockAccepted { pub signer_signature_hash: Sha512Trunc256Sum, /// The signer's signature across the acceptance pub signature: MessageSignature, + /// Signer message metadata + pub metadata: SignerMessageMetadata, } impl StacksMessageCodec for BlockAccepted { fn consensus_serialize(&self, fd: &mut W) -> Result<(), CodecError> { write_next(fd, &self.signer_signature_hash)?; write_next(fd, &self.signature)?; + write_next(fd, &self.metadata)?; Ok(()) } fn consensus_deserialize(fd: &mut R) -> Result { let signer_signature_hash = read_next::(fd)?; let signature = read_next::(fd)?; + let metadata = read_next::(fd)?; Ok(Self { signer_signature_hash, signature, + metadata, }) } } +impl BlockAccepted { + /// Create a new BlockAccepted for the provided block signer signature hash and signature + pub fn new(signer_signature_hash: Sha512Trunc256Sum, signature: MessageSignature) -> Self { + Self { + signer_signature_hash, + signature, + metadata: SignerMessageMetadata::default(), + } + } +} + /// A rejection response from a signer for a proposed block #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct BlockRejection { @@ -720,6 +788,8 @@ pub struct BlockRejection { pub signature: MessageSignature, /// The chain id pub chain_id: u32, + /// Signer message metadata + pub metadata: SignerMessageMetadata, } impl BlockRejection { @@ -741,6 +811,7 @@ impl BlockRejection { signer_signature_hash, signature: MessageSignature::empty(), chain_id, + metadata: SignerMessageMetadata::default(), }; rejection .sign(private_key) @@ -765,6 +836,7 @@ impl BlockRejection { signer_signature_hash: reject.signer_signature_hash, chain_id, signature: MessageSignature::empty(), + metadata: SignerMessageMetadata::default(), }; rejection .sign(private_key) @@ -814,6 +886,7 @@ impl StacksMessageCodec for BlockRejection { write_next(fd, &self.signer_signature_hash)?; write_next(fd, &self.chain_id)?; write_next(fd, &self.signature)?; + write_next(fd, &self.metadata)?; Ok(()) } @@ -826,12 +899,14 @@ impl StacksMessageCodec for BlockRejection { let signer_signature_hash = read_next::(fd)?; let chain_id = read_next::(fd)?; let signature = read_next::(fd)?; + let metadata = read_next::(fd)?; Ok(Self { reason, reason_code, signer_signature_hash, chain_id, signature, + metadata, }) } } @@ -988,6 +1063,7 @@ mod test { let accepted = BlockAccepted { signer_signature_hash: Sha512Trunc256Sum([0u8; 32]), signature: MessageSignature::empty(), + metadata: SignerMessageMetadata::default(), }; let response = BlockResponse::Accepted(accepted); let serialized_response = response.serialize_to_vec(); @@ -1012,6 +1088,7 @@ mod test { let accepted = BlockAccepted { signer_signature_hash: Sha512Trunc256Sum([2u8; 32]), signature: MessageSignature::empty(), + metadata: SignerMessageMetadata::default(), }; let signer_message = SignerMessage::BlockResponse(BlockResponse::Accepted(accepted)); let serialized_signer_message = signer_message.serialize_to_vec(); @@ -1178,6 +1255,55 @@ mod test { 169, 171, 178, 41, 98, 13, 216, 224, 242, 37, 214, 52, 1, 227, 108, 100, 129, 127, 178, 158, 108, 5, 89, 29, 203, 233, 92, 81, 45, 243, ]), + metadata: SignerMessageMetadata::empty(), + })) + ); + + assert_eq!( + block_accepted, + SignerMessage::BlockResponse(BlockResponse::Accepted(BlockAccepted { + signer_signature_hash: Sha512Trunc256Sum([ + 17, 113, 113, 73, 103, 124, 42, 201, 125, 21, 174, 89, 84, 247, 167, 22, 241, + 1, 0, 185, 203, 129, 162, 191, 39, 85, 27, 47, 46, 84, 239, 25 + ]), + metadata: SignerMessageMetadata::empty(), + signature: MessageSignature([ + 0, 28, 105, 79, 129, 52, 197, 201, 15, 47, 43, 205, 51, 14, 159, 66, 50, 4, + 136, 79, 0, 27, 93, 240, 5, 15, 54, 162, 196, 255, 121, 221, 147, 82, 43, 178, + 174, 57, 94, 168, 125, 228, 150, 72, 134, 68, 117, 7, 193, 131, 116, 183, 164, + 110, 226, 227, 113, 233, 191, 51, 47, 7, 6, 163, 232 + ]), + })) + ); + } + + #[test] + fn test_block_response_metadata() { + let block_rejected_hex = "010100000050426c6f636b206973206e6f7420612074656e7572652d737461727420626c6f636b2c20616e642068617320616e20756e7265636f676e697a65642074656e75726520636f6e73656e7375732068617368000691f95f84b7045f7dce7757052caa986ef042cb58f7df5031a3b5b5d0e3dda63e80000000006fb349212e1a1af1a3c712878d5159b5ec14636adb6f70be00a6da4ad4f88a9934d8a9abb229620dd8e0f225d63401e36c64817fb29e6c05591dcbe95c512df30000000b48656c6c6f20776f726c64"; + let block_rejected_bytes = hex_bytes(&block_rejected_hex).unwrap(); + let block_accepted_hex = "010011717149677c2ac97d15ae5954f7a716f10100b9cb81a2bf27551b2f2e54ef19001c694f8134c5c90f2f2bcd330e9f423204884f001b5df0050f36a2c4ff79dd93522bb2ae395ea87de4964886447507c18374b7a46ee2e371e9bf332f0706a3e80000000b48656c6c6f20776f726c64"; + let block_accepted_bytes = hex_bytes(&block_accepted_hex).unwrap(); + let block_rejected = read_next::(&mut &block_rejected_bytes[..]) + .expect("Failed to deserialize BlockRejection"); + let block_accepted = read_next::(&mut &block_accepted_bytes[..]) + .expect("Failed to deserialize BlockRejection"); + + assert_eq!( + block_rejected, + SignerMessage::BlockResponse(BlockResponse::Rejected(BlockRejection { + reason_code: RejectCode::ValidationFailed(ValidateRejectCode::NoSuchTenure), + reason: "Block is not a tenure-start block, and has an unrecognized tenure consensus hash".to_string(), + signer_signature_hash: Sha512Trunc256Sum([145, 249, 95, 132, 183, 4, 95, 125, 206, 119, 87, 5, 44, 170, 152, 110, 240, 66, 203, 88, 247, 223, 80, 49, 163, 181, 181, 208, 227, 221, 166, 62]), + chain_id: CHAIN_ID_TESTNET, + signature: MessageSignature([ + 0, 111, 179, 73, 33, 46, 26, 26, 241, 163, 199, 18, 135, 141, 81, 89, 181, 236, + 20, 99, 106, 219, 111, 112, 190, 0, 166, 218, 74, 212, 248, 138, 153, 52, 216, + 169, 171, 178, 41, 98, 13, 216, 224, 242, 37, 214, 52, 1, 227, 108, 100, 129, + 127, 178, 158, 108, 5, 89, 29, 203, 233, 92, 81, 45, 243, + ]), + metadata: SignerMessageMetadata { + server_version: "Hello world".to_string(), + }, })) ); @@ -1188,6 +1314,9 @@ mod test { 17, 113, 113, 73, 103, 124, 42, 201, 125, 21, 174, 89, 84, 247, 167, 22, 241, 1, 0, 185, 203, 129, 162, 191, 39, 85, 27, 47, 46, 84, 239, 25 ]), + metadata: SignerMessageMetadata { + server_version: "Hello world".to_string(), + }, signature: MessageSignature([ 0, 28, 105, 79, 129, 52, 197, 201, 15, 47, 43, 205, 51, 14, 159, 66, 50, 4, 136, 79, 0, 27, 93, 240, 5, 15, 54, 162, 196, 255, 121, 221, 147, 82, 43, 178, @@ -1197,4 +1326,13 @@ mod test { })) ); } + + #[test] + fn test_empty_metadata() { + let serialized_metadata = [0u8; 0]; + let deserialized_metadata = + read_next::(&mut &serialized_metadata[..]) + .expect("Failed to deserialize SignerMessageMetadata"); + assert_eq!(deserialized_metadata, SignerMessageMetadata::empty()); + } } diff --git a/stacks-signer/src/cli.rs b/stacks-signer/src/cli.rs index 97829b6977..4e9067498d 100644 --- a/stacks-signer/src/cli.rs +++ b/stacks-signer/src/cli.rs @@ -29,6 +29,7 @@ use clarity::util::hash::Sha256Sum; use clarity::util::secp256k1::MessageSignature; use clarity::vm::types::{QualifiedContractIdentifier, TupleData}; use clarity::vm::Value; +use libsigner::VERSION_STRING; use serde::{Deserialize, Serialize}; use stacks_common::address::{ b58, AddressHashMode, C32_ADDRESS_VERSION_MAINNET_MULTISIG, @@ -38,8 +39,6 @@ use stacks_common::address::{ use stacks_common::define_u8_enum; use stacks_common::types::chainstate::StacksPrivateKey; -use crate::VERSION_STRING; - extern crate alloc; #[derive(Parser, Debug)] diff --git a/stacks-signer/src/client/stackerdb.rs b/stacks-signer/src/client/stackerdb.rs index 0fc43350db..117dd4814f 100644 --- a/stacks-signer/src/client/stackerdb.rs +++ b/stacks-signer/src/client/stackerdb.rs @@ -235,7 +235,9 @@ mod tests { use blockstack_lib::chainstate::nakamoto::{NakamotoBlock, NakamotoBlockHeader}; use clarity::util::hash::{MerkleTree, Sha512Trunc256Sum}; use clarity::util::secp256k1::MessageSignature; - use libsigner::v0::messages::{BlockRejection, BlockResponse, RejectCode, SignerMessage}; + use libsigner::v0::messages::{ + BlockRejection, BlockResponse, RejectCode, SignerMessage, SignerMessageMetadata, + }; use rand::{thread_rng, RngCore}; use super::*; @@ -283,6 +285,7 @@ mod tests { signer_signature_hash: block.header.signer_signature_hash(), chain_id: thread_rng().next_u32(), signature: MessageSignature::empty(), + metadata: SignerMessageMetadata::empty(), }; let signer_message = SignerMessage::BlockResponse(BlockResponse::Rejected(block_reject)); let ack = StackerDBChunkAckData { diff --git a/stacks-signer/src/lib.rs b/stacks-signer/src/lib.rs index 3555435eaa..246015bfb7 100644 --- a/stacks-signer/src/lib.rs +++ b/stacks-signer/src/lib.rs @@ -48,11 +48,9 @@ mod tests; use std::fmt::{Debug, Display}; use std::sync::mpsc::{channel, Receiver, Sender}; -use blockstack_lib::version_string; use chainstate::SortitionsView; use config::GlobalConfig; -use lazy_static::lazy_static; -use libsigner::{SignerEvent, SignerEventReceiver, SignerEventTrait}; +use libsigner::{SignerEvent, SignerEventReceiver, SignerEventTrait, VERSION_STRING}; use runloop::SignerResult; use slog::{slog_info, slog_warn}; use stacks_common::{info, warn}; @@ -61,14 +59,6 @@ use crate::client::StacksClient; use crate::config::SignerConfig; use crate::runloop::RunLoop; -lazy_static! { - /// The version string for the signer - pub static ref VERSION_STRING: String = { - let pkg_version = option_env!("STACKS_NODE_VERSION").unwrap_or(env!("CARGO_PKG_VERSION")); - version_string("stacks-signer", pkg_version) - }; -} - /// A trait which provides a common `Signer` interface for `v0` and `v1` pub trait Signer: Debug + Display { /// Create a new `Signer` instance diff --git a/stacks-signer/src/main.rs b/stacks-signer/src/main.rs index 56f322b185..a23918f6f8 100644 --- a/stacks-signer/src/main.rs +++ b/stacks-signer/src/main.rs @@ -32,7 +32,7 @@ use blockstack_lib::util_lib::signed_structured_data::pox4::make_pox_4_signer_ke use clap::Parser; use clarity::types::chainstate::StacksPublicKey; use clarity::util::sleep_ms; -use libsigner::SignerSession; +use libsigner::{SignerSession, VERSION_STRING}; use libstackerdb::StackerDBChunkData; use slog::{slog_debug, slog_error}; use stacks_common::util::hash::to_hex; @@ -47,7 +47,6 @@ use stacks_signer::config::GlobalConfig; use stacks_signer::monitor_signers::SignerMonitor; use stacks_signer::utils::stackerdb_session; use stacks_signer::v0::SpawnedSigner; -use stacks_signer::VERSION_STRING; use tracing_subscriber::prelude::*; use tracing_subscriber::{fmt, EnvFilter}; diff --git a/stacks-signer/src/monitoring/server.rs b/stacks-signer/src/monitoring/server.rs index f5e3cceef1..15267c44ee 100644 --- a/stacks-signer/src/monitoring/server.rs +++ b/stacks-signer/src/monitoring/server.rs @@ -19,6 +19,7 @@ use std::time::Instant; use clarity::util::hash::to_hex; use clarity::util::secp256k1::Secp256k1PublicKey; +use libsigner::VERSION_STRING; use slog::{slog_debug, slog_error, slog_info, slog_warn}; use stacks_common::{debug, error, info, warn}; use tiny_http::{Response as HttpResponse, Server as HttpServer}; @@ -28,7 +29,6 @@ use crate::client::{ClientError, StacksClient}; use crate::config::{GlobalConfig, Network}; use crate::monitoring::prometheus::gather_metrics_string; use crate::monitoring::{update_signer_nonce, update_stacks_tip_height}; -use crate::VERSION_STRING; #[derive(thiserror::Error, Debug)] /// Monitoring server errors diff --git a/stacks-signer/src/v0/signer.rs b/stacks-signer/src/v0/signer.rs index fe626cb11f..2cb10a9817 100644 --- a/stacks-signer/src/v0/signer.rs +++ b/stacks-signer/src/v0/signer.rs @@ -546,10 +546,7 @@ impl Signer { self.signer_db .insert_block(&block_info) .unwrap_or_else(|_| panic!("{self}: Failed to insert block in DB")); - let accepted = BlockAccepted { - signer_signature_hash: block_info.signer_signature_hash(), - signature, - }; + let accepted = BlockAccepted::new(block_info.signer_signature_hash(), signature); // have to save the signature _after_ the block info self.handle_block_signature(stacks_client, &accepted); Some(BlockResponse::Accepted(accepted)) @@ -742,8 +739,12 @@ impl Signer { let BlockAccepted { signer_signature_hash: block_hash, signature, + metadata, } = accepted; - debug!("{self}: Received a block-accept signature: ({block_hash}, {signature})"); + debug!( + "{self}: Received a block-accept signature: ({block_hash}, {signature}, {})", + metadata.server_version + ); // Have we already processed this block? match self diff --git a/testnet/stacks-node/src/nakamoto_node/sign_coordinator.rs b/testnet/stacks-node/src/nakamoto_node/sign_coordinator.rs index 1954f6eb12..697dddeb03 100644 --- a/testnet/stacks-node/src/nakamoto_node/sign_coordinator.rs +++ b/testnet/stacks-node/src/nakamoto_node/sign_coordinator.rs @@ -456,6 +456,7 @@ impl SignCoordinator { let BlockAccepted { signer_signature_hash: response_hash, signature, + metadata, } = accepted; let block_sighash = block.header.signer_signature_hash(); if block_sighash != response_hash { @@ -466,7 +467,8 @@ impl SignCoordinator { "response_hash" => %response_hash, "slot_id" => slot_id, "reward_cycle_id" => reward_cycle_id, - "response_hash" => %response_hash + "response_hash" => %response_hash, + "server_version" => %metadata.server_version ); continue; } @@ -514,7 +516,8 @@ impl SignCoordinator { "signer_weight" => signer_entry.weight, "total_weight_signed" => total_weight_signed, "stacks_block_hash" => %block.header.block_hash(), - "stacks_block_id" => %block.header.block_id() + "stacks_block_id" => %block.header.block_id(), + "server_version" => metadata.server_version, ); gathered_signatures.insert(slot_id, signature); responded_signers.insert(signer_pubkey); diff --git a/testnet/stacks-node/src/tests/signer/mod.rs b/testnet/stacks-node/src/tests/signer/mod.rs index 5fb318e234..42b894398d 100644 --- a/testnet/stacks-node/src/tests/signer/mod.rs +++ b/testnet/stacks-node/src/tests/signer/mod.rs @@ -36,7 +36,7 @@ use std::time::{Duration, Instant}; use clarity::boot_util::boot_code_id; use clarity::vm::types::PrincipalData; -use libsigner::v0::messages::{BlockAccepted, BlockResponse, SignerMessage}; +use libsigner::v0::messages::{BlockResponse, SignerMessage}; use libsigner::{SignerEntries, SignerEventTrait}; use stacks::chainstate::coordinator::comm::CoordinatorChannels; use stacks::chainstate::nakamoto::signer_set::NakamotoSigners; @@ -579,17 +579,16 @@ impl + Send + 'static, T: SignerEventTrait + 'static> SignerTest { - let BlockAccepted { - signer_signature_hash: hash, - signature, - } = accepted; - if hash == *signer_signature_hash + if accepted.signer_signature_hash == *signer_signature_hash && expected_signers.iter().any(|pk| { - pk.verify(hash.bits(), &signature) - .expect("Failed to verify signature") + pk.verify( + accepted.signer_signature_hash.bits(), + &accepted.signature, + ) + .expect("Failed to verify signature") }) { - Some(signature) + Some(accepted.signature) } else { None } diff --git a/testnet/stacks-node/src/tests/signer/v0.rs b/testnet/stacks-node/src/tests/signer/v0.rs index 6fc4c7078a..e02d5b62ca 100644 --- a/testnet/stacks-node/src/tests/signer/v0.rs +++ b/testnet/stacks-node/src/tests/signer/v0.rs @@ -25,7 +25,7 @@ use clarity::vm::StacksEpoch; use libsigner::v0::messages::{ BlockRejection, BlockResponse, MessageSlotID, MinerSlotID, RejectCode, SignerMessage, }; -use libsigner::{BlockProposal, SignerSession, StackerDBSession}; +use libsigner::{BlockProposal, SignerSession, StackerDBSession, VERSION_STRING}; use stacks::address::AddressHashMode; use stacks::burnchains::Txid; use stacks::chainstate::burn::db::sortdb::SortitionDB; @@ -2567,10 +2567,12 @@ fn empty_sortition() { }; if let SignerMessage::BlockResponse(BlockResponse::Rejected(BlockRejection { reason_code, + metadata, .. })) = latest_msg { assert!(matches!(reason_code, RejectCode::SortitionViewMismatch)); + assert_eq!(metadata.server_version, VERSION_STRING.to_string()); found_rejections.push(*slot_id); } else { info!("Latest message from slot #{slot_id} isn't a block rejection, will wait to see if the signer updates to a rejection"); From a1208c89e1e8101944af7f1d39f5dd92f302662a Mon Sep 17 00:00:00 2001 From: Hank Stoever Date: Fri, 18 Oct 2024 16:56:27 -0700 Subject: [PATCH 3/4] feat: add metadata to mock signatures --- libsigner/src/v0/messages.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libsigner/src/v0/messages.rs b/libsigner/src/v0/messages.rs index 264a4cc107..2436421fa8 100644 --- a/libsigner/src/v0/messages.rs +++ b/libsigner/src/v0/messages.rs @@ -439,6 +439,8 @@ pub struct MockSignature { signature: MessageSignature, /// The mock block proposal that was signed across pub mock_proposal: MockProposal, + /// The signature metadata + pub metadata: SignerMessageMetadata, } impl MockSignature { @@ -447,6 +449,7 @@ impl MockSignature { let mut sig = Self { signature: MessageSignature::empty(), mock_proposal, + metadata: SignerMessageMetadata::default(), }; sig.sign(stacks_private_key) .expect("Failed to sign MockSignature"); @@ -476,15 +479,18 @@ impl StacksMessageCodec for MockSignature { fn consensus_serialize(&self, fd: &mut W) -> Result<(), CodecError> { write_next(fd, &self.signature)?; self.mock_proposal.consensus_serialize(fd)?; + self.metadata.consensus_serialize(fd)?; Ok(()) } fn consensus_deserialize(fd: &mut R) -> Result { let signature = read_next::(fd)?; let mock_proposal = MockProposal::consensus_deserialize(fd)?; + let metadata = SignerMessageMetadata::consensus_deserialize(fd)?; Ok(Self { signature, mock_proposal, + metadata, }) } } @@ -1206,6 +1212,7 @@ mod test { let mut mock_signature = MockSignature { signature: MessageSignature::empty(), mock_proposal: random_mock_proposal(), + metadata: SignerMessageMetadata::default(), }; mock_signature .sign(&StacksPrivateKey::new()) From 9f9ad40c8ae57cae5a9dab9e7fd5bf8528ac51e2 Mon Sep 17 00:00:00 2001 From: Hank Stoever Date: Sun, 20 Oct 2024 12:12:50 -0700 Subject: [PATCH 4/4] fix: use hex instead of u8 bytes in fixture --- libsigner/src/v0/messages.rs | 48 +++++++++++------------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/libsigner/src/v0/messages.rs b/libsigner/src/v0/messages.rs index 2436421fa8..618aa20937 100644 --- a/libsigner/src/v0/messages.rs +++ b/libsigner/src/v0/messages.rs @@ -1254,14 +1254,9 @@ mod test { SignerMessage::BlockResponse(BlockResponse::Rejected(BlockRejection { reason_code: RejectCode::ValidationFailed(ValidateRejectCode::NoSuchTenure), reason: "Block is not a tenure-start block, and has an unrecognized tenure consensus hash".to_string(), - signer_signature_hash: Sha512Trunc256Sum([145, 249, 95, 132, 183, 4, 95, 125, 206, 119, 87, 5, 44, 170, 152, 110, 240, 66, 203, 88, 247, 223, 80, 49, 163, 181, 181, 208, 227, 221, 166, 62]), + signer_signature_hash: Sha512Trunc256Sum::from_hex("91f95f84b7045f7dce7757052caa986ef042cb58f7df5031a3b5b5d0e3dda63e").unwrap(), chain_id: CHAIN_ID_TESTNET, - signature: MessageSignature([ - 0, 111, 179, 73, 33, 46, 26, 26, 241, 163, 199, 18, 135, 141, 81, 89, 181, 236, - 20, 99, 106, 219, 111, 112, 190, 0, 166, 218, 74, 212, 248, 138, 153, 52, 216, - 169, 171, 178, 41, 98, 13, 216, 224, 242, 37, 214, 52, 1, 227, 108, 100, 129, - 127, 178, 158, 108, 5, 89, 29, 203, 233, 92, 81, 45, 243, - ]), + signature: MessageSignature::from_hex("006fb349212e1a1af1a3c712878d5159b5ec14636adb6f70be00a6da4ad4f88a9934d8a9abb229620dd8e0f225d63401e36c64817fb29e6c05591dcbe95c512df3").unwrap(), metadata: SignerMessageMetadata::empty(), })) ); @@ -1269,17 +1264,12 @@ mod test { assert_eq!( block_accepted, SignerMessage::BlockResponse(BlockResponse::Accepted(BlockAccepted { - signer_signature_hash: Sha512Trunc256Sum([ - 17, 113, 113, 73, 103, 124, 42, 201, 125, 21, 174, 89, 84, 247, 167, 22, 241, - 1, 0, 185, 203, 129, 162, 191, 39, 85, 27, 47, 46, 84, 239, 25 - ]), + signer_signature_hash: Sha512Trunc256Sum::from_hex( + "11717149677c2ac97d15ae5954f7a716f10100b9cb81a2bf27551b2f2e54ef19" + ) + .unwrap(), metadata: SignerMessageMetadata::empty(), - signature: MessageSignature([ - 0, 28, 105, 79, 129, 52, 197, 201, 15, 47, 43, 205, 51, 14, 159, 66, 50, 4, - 136, 79, 0, 27, 93, 240, 5, 15, 54, 162, 196, 255, 121, 221, 147, 82, 43, 178, - 174, 57, 94, 168, 125, 228, 150, 72, 134, 68, 117, 7, 193, 131, 116, 183, 164, - 110, 226, 227, 113, 233, 191, 51, 47, 7, 6, 163, 232 - ]), + signature: MessageSignature::from_hex("001c694f8134c5c90f2f2bcd330e9f423204884f001b5df0050f36a2c4ff79dd93522bb2ae395ea87de4964886447507c18374b7a46ee2e371e9bf332f0706a3e8").unwrap(), })) ); } @@ -1300,14 +1290,9 @@ mod test { SignerMessage::BlockResponse(BlockResponse::Rejected(BlockRejection { reason_code: RejectCode::ValidationFailed(ValidateRejectCode::NoSuchTenure), reason: "Block is not a tenure-start block, and has an unrecognized tenure consensus hash".to_string(), - signer_signature_hash: Sha512Trunc256Sum([145, 249, 95, 132, 183, 4, 95, 125, 206, 119, 87, 5, 44, 170, 152, 110, 240, 66, 203, 88, 247, 223, 80, 49, 163, 181, 181, 208, 227, 221, 166, 62]), + signer_signature_hash: Sha512Trunc256Sum::from_hex("91f95f84b7045f7dce7757052caa986ef042cb58f7df5031a3b5b5d0e3dda63e").unwrap(), chain_id: CHAIN_ID_TESTNET, - signature: MessageSignature([ - 0, 111, 179, 73, 33, 46, 26, 26, 241, 163, 199, 18, 135, 141, 81, 89, 181, 236, - 20, 99, 106, 219, 111, 112, 190, 0, 166, 218, 74, 212, 248, 138, 153, 52, 216, - 169, 171, 178, 41, 98, 13, 216, 224, 242, 37, 214, 52, 1, 227, 108, 100, 129, - 127, 178, 158, 108, 5, 89, 29, 203, 233, 92, 81, 45, 243, - ]), + signature: MessageSignature::from_hex("006fb349212e1a1af1a3c712878d5159b5ec14636adb6f70be00a6da4ad4f88a9934d8a9abb229620dd8e0f225d63401e36c64817fb29e6c05591dcbe95c512df3").unwrap(), metadata: SignerMessageMetadata { server_version: "Hello world".to_string(), }, @@ -1317,19 +1302,14 @@ mod test { assert_eq!( block_accepted, SignerMessage::BlockResponse(BlockResponse::Accepted(BlockAccepted { - signer_signature_hash: Sha512Trunc256Sum([ - 17, 113, 113, 73, 103, 124, 42, 201, 125, 21, 174, 89, 84, 247, 167, 22, 241, - 1, 0, 185, 203, 129, 162, 191, 39, 85, 27, 47, 46, 84, 239, 25 - ]), + signer_signature_hash: Sha512Trunc256Sum::from_hex( + "11717149677c2ac97d15ae5954f7a716f10100b9cb81a2bf27551b2f2e54ef19" + ) + .unwrap(), metadata: SignerMessageMetadata { server_version: "Hello world".to_string(), }, - signature: MessageSignature([ - 0, 28, 105, 79, 129, 52, 197, 201, 15, 47, 43, 205, 51, 14, 159, 66, 50, 4, - 136, 79, 0, 27, 93, 240, 5, 15, 54, 162, 196, 255, 121, 221, 147, 82, 43, 178, - 174, 57, 94, 168, 125, 228, 150, 72, 134, 68, 117, 7, 193, 131, 116, 183, 164, - 110, 226, 227, 113, 233, 191, 51, 47, 7, 6, 163, 232 - ]), + signature: MessageSignature::from_hex("001c694f8134c5c90f2f2bcd330e9f423204884f001b5df0050f36a2c4ff79dd93522bb2ae395ea87de4964886447507c18374b7a46ee2e371e9bf332f0706a3e8").unwrap(), })) ); }