Skip to content

Commit 540fcd4

Browse files
committed
chore: convert BlockAccepted to a struct
1 parent 3d1f829 commit 540fcd4

File tree

5 files changed

+142
-62
lines changed

5 files changed

+142
-62
lines changed

libsigner/src/v0/messages.rs

Lines changed: 91 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ impl From<&BlockResponse> for BlockResponseTypePrefix {
603603
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
604604
pub enum BlockResponse {
605605
/// The Nakamoto block was accepted and therefore signed
606-
Accepted((Sha512Trunc256Sum, MessageSignature)),
606+
Accepted(BlockAccepted),
607607
/// The Nakamoto block was rejected and therefore not signed
608608
Rejected(BlockRejection),
609609
}
@@ -616,7 +616,7 @@ impl std::fmt::Display for BlockResponse {
616616
write!(
617617
f,
618618
"BlockAccepted: signer_sighash = {}, signature = {}",
619-
a.0, a.1
619+
a.signer_signature_hash, a.signature
620620
)
621621
}
622622
BlockResponse::Rejected(r) => {
@@ -633,7 +633,10 @@ impl std::fmt::Display for BlockResponse {
633633
impl BlockResponse {
634634
/// Create a new accepted BlockResponse for the provided block signer signature hash and signature
635635
pub fn accepted(hash: Sha512Trunc256Sum, sig: MessageSignature) -> Self {
636-
Self::Accepted((hash, sig))
636+
Self::Accepted(BlockAccepted {
637+
signer_signature_hash: hash,
638+
signature: sig,
639+
})
637640
}
638641

639642
/// 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 {
651654
fn consensus_serialize<W: Write>(&self, fd: &mut W) -> Result<(), CodecError> {
652655
write_next(fd, &(BlockResponseTypePrefix::from(self) as u8))?;
653656
match self {
654-
BlockResponse::Accepted((hash, sig)) => {
655-
write_next(fd, hash)?;
656-
write_next(fd, sig)?;
657+
BlockResponse::Accepted(accepted) => {
658+
write_next(fd, accepted)?;
657659
}
658660
BlockResponse::Rejected(rejection) => {
659661
write_next(fd, rejection)?;
@@ -667,9 +669,8 @@ impl StacksMessageCodec for BlockResponse {
667669
let type_prefix = BlockResponseTypePrefix::try_from(type_prefix_byte)?;
668670
let response = match type_prefix {
669671
BlockResponseTypePrefix::Accepted => {
670-
let hash = read_next::<Sha512Trunc256Sum, _>(fd)?;
671-
let sig = read_next::<MessageSignature, _>(fd)?;
672-
BlockResponse::Accepted((hash, sig))
672+
let accepted = read_next::<BlockAccepted, _>(fd)?;
673+
BlockResponse::Accepted(accepted)
673674
}
674675
BlockResponseTypePrefix::Rejected => {
675676
let rejection = read_next::<BlockRejection, _>(fd)?;
@@ -680,6 +681,32 @@ impl StacksMessageCodec for BlockResponse {
680681
}
681682
}
682683

684+
/// A rejection response from a signer for a proposed block
685+
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
686+
pub struct BlockAccepted {
687+
/// The signer signature hash of the block that was accepted
688+
pub signer_signature_hash: Sha512Trunc256Sum,
689+
/// The signer's signature across the acceptance
690+
pub signature: MessageSignature,
691+
}
692+
693+
impl StacksMessageCodec for BlockAccepted {
694+
fn consensus_serialize<W: Write>(&self, fd: &mut W) -> Result<(), CodecError> {
695+
write_next(fd, &self.signer_signature_hash)?;
696+
write_next(fd, &self.signature)?;
697+
Ok(())
698+
}
699+
700+
fn consensus_deserialize<R: Read>(fd: &mut R) -> Result<Self, CodecError> {
701+
let signer_signature_hash = read_next::<Sha512Trunc256Sum, _>(fd)?;
702+
let signature = read_next::<MessageSignature, _>(fd)?;
703+
Ok(Self {
704+
signer_signature_hash,
705+
signature,
706+
})
707+
}
708+
}
709+
683710
/// A rejection response from a signer for a proposed block
684711
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
685712
pub struct BlockRejection {
@@ -894,7 +921,7 @@ mod test {
894921
use clarity::consts::CHAIN_ID_MAINNET;
895922
use clarity::types::chainstate::{ConsensusHash, StacksBlockId, TrieHash};
896923
use clarity::types::PrivateKey;
897-
use clarity::util::hash::MerkleTree;
924+
use clarity::util::hash::{hex_bytes, MerkleTree};
898925
use clarity::util::secp256k1::MessageSignature;
899926
use rand::rngs::mock;
900927
use rand::{thread_rng, Rng, RngCore};
@@ -958,8 +985,11 @@ mod test {
958985

959986
#[test]
960987
fn serde_block_response() {
961-
let response =
962-
BlockResponse::Accepted((Sha512Trunc256Sum([0u8; 32]), MessageSignature::empty()));
988+
let accepted = BlockAccepted {
989+
signer_signature_hash: Sha512Trunc256Sum([0u8; 32]),
990+
signature: MessageSignature::empty(),
991+
};
992+
let response = BlockResponse::Accepted(accepted);
963993
let serialized_response = response.serialize_to_vec();
964994
let deserialized_response = read_next::<BlockResponse, _>(&mut &serialized_response[..])
965995
.expect("Failed to deserialize BlockResponse");
@@ -979,10 +1009,11 @@ mod test {
9791009

9801010
#[test]
9811011
fn serde_signer_message() {
982-
let signer_message = SignerMessage::BlockResponse(BlockResponse::Accepted((
983-
Sha512Trunc256Sum([2u8; 32]),
984-
MessageSignature::empty(),
985-
)));
1012+
let accepted = BlockAccepted {
1013+
signer_signature_hash: Sha512Trunc256Sum([2u8; 32]),
1014+
signature: MessageSignature::empty(),
1015+
};
1016+
let signer_message = SignerMessage::BlockResponse(BlockResponse::Accepted(accepted));
9861017
let serialized_signer_message = signer_message.serialize_to_vec();
9871018
let deserialized_signer_message =
9881019
read_next::<SignerMessage, _>(&mut &serialized_signer_message[..])
@@ -1122,4 +1153,48 @@ mod test {
11221153
.expect("Failed to deserialize MockSignData");
11231154
assert_eq!(mock_block, deserialized_data);
11241155
}
1156+
1157+
#[test]
1158+
fn test_backwards_compatibility() {
1159+
let block_rejected_hex = "010100000050426c6f636b206973206e6f7420612074656e7572652d737461727420626c6f636b2c20616e642068617320616e20756e7265636f676e697a65642074656e75726520636f6e73656e7375732068617368000691f95f84b7045f7dce7757052caa986ef042cb58f7df5031a3b5b5d0e3dda63e80000000006fb349212e1a1af1a3c712878d5159b5ec14636adb6f70be00a6da4ad4f88a9934d8a9abb229620dd8e0f225d63401e36c64817fb29e6c05591dcbe95c512df3";
1160+
let block_rejected_bytes = hex_bytes(&block_rejected_hex).unwrap();
1161+
let block_accepted_hex = "010011717149677c2ac97d15ae5954f7a716f10100b9cb81a2bf27551b2f2e54ef19001c694f8134c5c90f2f2bcd330e9f423204884f001b5df0050f36a2c4ff79dd93522bb2ae395ea87de4964886447507c18374b7a46ee2e371e9bf332f0706a3e8";
1162+
let block_accepted_bytes = hex_bytes(&block_accepted_hex).unwrap();
1163+
let block_rejected = read_next::<SignerMessage, _>(&mut &block_rejected_bytes[..])
1164+
.expect("Failed to deserialize BlockRejection");
1165+
let block_accepted = read_next::<SignerMessage, _>(&mut &block_accepted_bytes[..])
1166+
.expect("Failed to deserialize BlockRejection");
1167+
1168+
assert_eq!(
1169+
block_rejected,
1170+
SignerMessage::BlockResponse(BlockResponse::Rejected(BlockRejection {
1171+
reason_code: RejectCode::ValidationFailed(ValidateRejectCode::NoSuchTenure),
1172+
reason: "Block is not a tenure-start block, and has an unrecognized tenure consensus hash".to_string(),
1173+
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]),
1174+
chain_id: CHAIN_ID_TESTNET,
1175+
signature: MessageSignature([
1176+
0, 111, 179, 73, 33, 46, 26, 26, 241, 163, 199, 18, 135, 141, 81, 89, 181, 236,
1177+
20, 99, 106, 219, 111, 112, 190, 0, 166, 218, 74, 212, 248, 138, 153, 52, 216,
1178+
169, 171, 178, 41, 98, 13, 216, 224, 242, 37, 214, 52, 1, 227, 108, 100, 129,
1179+
127, 178, 158, 108, 5, 89, 29, 203, 233, 92, 81, 45, 243,
1180+
]),
1181+
}))
1182+
);
1183+
1184+
assert_eq!(
1185+
block_accepted,
1186+
SignerMessage::BlockResponse(BlockResponse::Accepted(BlockAccepted {
1187+
signer_signature_hash: Sha512Trunc256Sum([
1188+
17, 113, 113, 73, 103, 124, 42, 201, 125, 21, 174, 89, 84, 247, 167, 22, 241,
1189+
1, 0, 185, 203, 129, 162, 191, 39, 85, 27, 47, 46, 84, 239, 25
1190+
]),
1191+
signature: MessageSignature([
1192+
0, 28, 105, 79, 129, 52, 197, 201, 15, 47, 43, 205, 51, 14, 159, 66, 50, 4,
1193+
136, 79, 0, 27, 93, 240, 5, 15, 54, 162, 196, 255, 121, 221, 147, 82, 43, 178,
1194+
174, 57, 94, 168, 125, 228, 150, 72, 134, 68, 117, 7, 193, 131, 116, 183, 164,
1195+
110, 226, 227, 113, 233, 191, 51, 47, 7, 6, 163, 232
1196+
]),
1197+
}))
1198+
);
1199+
}
11251200
}

stacks-signer/src/v0/signer.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,13 @@ use clarity::types::{PrivateKey, StacksEpochId};
2525
use clarity::util::hash::MerkleHashFunc;
2626
use clarity::util::secp256k1::Secp256k1PublicKey;
2727
use libsigner::v0::messages::{
28-
BlockRejection, BlockResponse, MessageSlotID, MockProposal, MockSignature, RejectCode,
29-
SignerMessage,
28+
BlockAccepted, BlockRejection, BlockResponse, MessageSlotID, MockProposal, MockSignature,
29+
RejectCode, SignerMessage,
3030
};
3131
use libsigner::{BlockProposal, SignerEvent};
3232
use slog::{slog_debug, slog_error, slog_info, slog_warn};
3333
use stacks_common::types::chainstate::StacksAddress;
3434
use stacks_common::util::get_epoch_time_secs;
35-
use stacks_common::util::hash::Sha512Trunc256Sum;
3635
use stacks_common::util::secp256k1::MessageSignature;
3736
use stacks_common::{debug, error, info, warn};
3837

@@ -494,8 +493,8 @@ impl Signer {
494493
block_response: &BlockResponse,
495494
) {
496495
match block_response {
497-
BlockResponse::Accepted((block_hash, signature)) => {
498-
self.handle_block_signature(stacks_client, block_hash, signature);
496+
BlockResponse::Accepted(accepted) => {
497+
self.handle_block_signature(stacks_client, accepted);
499498
}
500499
BlockResponse::Rejected(block_rejection) => {
501500
self.handle_block_rejection(block_rejection);
@@ -547,13 +546,13 @@ impl Signer {
547546
self.signer_db
548547
.insert_block(&block_info)
549548
.unwrap_or_else(|_| panic!("{self}: Failed to insert block in DB"));
549+
let accepted = BlockAccepted {
550+
signer_signature_hash: block_info.signer_signature_hash(),
551+
signature,
552+
};
550553
// have to save the signature _after_ the block info
551-
self.handle_block_signature(
552-
stacks_client,
553-
&block_info.signer_signature_hash(),
554-
&signature,
555-
);
556-
Some(BlockResponse::accepted(signer_signature_hash, signature))
554+
self.handle_block_signature(stacks_client, &accepted);
555+
Some(BlockResponse::Accepted(accepted))
557556
}
558557

559558
/// Handle the block validate reject response. Returns our block response if we have one
@@ -739,12 +738,11 @@ impl Signer {
739738
}
740739

741740
/// Handle an observed signature from another signer
742-
fn handle_block_signature(
743-
&mut self,
744-
stacks_client: &StacksClient,
745-
block_hash: &Sha512Trunc256Sum,
746-
signature: &MessageSignature,
747-
) {
741+
fn handle_block_signature(&mut self, stacks_client: &StacksClient, accepted: &BlockAccepted) {
742+
let BlockAccepted {
743+
signer_signature_hash: block_hash,
744+
signature,
745+
} = accepted;
748746
debug!("{self}: Received a block-accept signature: ({block_hash}, {signature})");
749747

750748
// Have we already processed this block?

testnet/stacks-node/src/nakamoto_node/sign_coordinator.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ use std::sync::Arc;
2020
use std::time::Duration;
2121

2222
use hashbrown::{HashMap, HashSet};
23-
use libsigner::v0::messages::{BlockResponse, MinerSlotID, SignerMessage as SignerMessageV0};
23+
use libsigner::v0::messages::{
24+
BlockAccepted, BlockResponse, MinerSlotID, SignerMessage as SignerMessageV0,
25+
};
2426
use libsigner::{BlockProposal, SignerEntries, SignerEvent, SignerSession, StackerDBSession};
2527
use stacks::burnchains::Burnchain;
2628
use stacks::chainstate::burn::db::sortdb::SortitionDB;
@@ -450,10 +452,11 @@ impl SignCoordinator {
450452
}
451453

452454
match message {
453-
SignerMessageV0::BlockResponse(BlockResponse::Accepted((
454-
response_hash,
455-
signature,
456-
))) => {
455+
SignerMessageV0::BlockResponse(BlockResponse::Accepted(accepted)) => {
456+
let BlockAccepted {
457+
signer_signature_hash: response_hash,
458+
signature,
459+
} = accepted;
457460
let block_sighash = block.header.signer_signature_hash();
458461
if block_sighash != response_hash {
459462
warn!(

testnet/stacks-node/src/tests/signer/mod.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use std::time::{Duration, Instant};
3636

3737
use clarity::boot_util::boot_code_id;
3838
use clarity::vm::types::PrincipalData;
39-
use libsigner::v0::messages::{BlockResponse, SignerMessage};
39+
use libsigner::v0::messages::{BlockAccepted, BlockResponse, SignerMessage};
4040
use libsigner::{SignerEntries, SignerEventTrait};
4141
use stacks::chainstate::coordinator::comm::CoordinatorChannels;
4242
use stacks::chainstate::nakamoto::signer_set::NakamotoSigners;
@@ -578,10 +578,11 @@ impl<S: Signer<T> + Send + 'static, T: SignerEventTrait + 'static> SignerTest<Sp
578578
let message = SignerMessage::consensus_deserialize(&mut chunk.data.as_slice())
579579
.expect("Failed to deserialize SignerMessage");
580580
match message {
581-
SignerMessage::BlockResponse(BlockResponse::Accepted((
582-
hash,
583-
signature,
584-
))) => {
581+
SignerMessage::BlockResponse(BlockResponse::Accepted(accepted)) => {
582+
let BlockAccepted {
583+
signer_signature_hash: hash,
584+
signature,
585+
} = accepted;
585586
if hash == *signer_signature_hash
586587
&& expected_signers.iter().any(|pk| {
587588
pk.verify(hash.bits(), &signature)

testnet/stacks-node/src/tests/signer/v0.rs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3411,7 +3411,7 @@ fn duplicate_signers() {
34113411
})
34123412
.filter_map(|message| match message {
34133413
SignerMessage::BlockResponse(BlockResponse::Accepted(m)) => {
3414-
info!("Message(accepted): {message:?}");
3414+
info!("Message(accepted): {:?}", &m);
34153415
Some(m)
34163416
}
34173417
_ => {
@@ -3425,20 +3425,23 @@ fn duplicate_signers() {
34253425
info!("------------------------- Assert there are {unique_signers} unique signatures and recovered pubkeys -------------------------");
34263426

34273427
// Pick a message hash
3428-
let (selected_sighash, _) = signer_accepted_responses
3428+
let accepted = signer_accepted_responses
34293429
.iter()
3430-
.min_by_key(|(sighash, _)| *sighash)
3431-
.copied()
3430+
.min_by_key(|accepted| accepted.signer_signature_hash)
34323431
.expect("No `BlockResponse::Accepted` messages recieved");
3432+
let selected_sighash = accepted.signer_signature_hash;
34333433

34343434
// Filter only resonses for selected block and collect unique pubkeys and signatures
34353435
let (pubkeys, signatures): (HashSet<_>, HashSet<_>) = signer_accepted_responses
34363436
.into_iter()
3437-
.filter(|(hash, _)| *hash == selected_sighash)
3438-
.map(|(msg, sig)| {
3439-
let pubkey = Secp256k1PublicKey::recover_to_pubkey(msg.bits(), &sig)
3440-
.expect("Failed to recover pubkey");
3441-
(pubkey, sig)
3437+
.filter(|accepted| accepted.signer_signature_hash == selected_sighash)
3438+
.map(|accepted| {
3439+
let pubkey = Secp256k1PublicKey::recover_to_pubkey(
3440+
accepted.signer_signature_hash.bits(),
3441+
&accepted.signature,
3442+
)
3443+
.expect("Failed to recover pubkey");
3444+
(pubkey, accepted.signature)
34423445
})
34433446
.unzip();
34443447

@@ -4652,10 +4655,11 @@ fn reorg_locally_accepted_blocks_across_tenures_succeeds() {
46524655
let message = SignerMessage::consensus_deserialize(&mut chunk.data.as_slice())
46534656
.expect("Failed to deserialize SignerMessage");
46544657
match message {
4655-
SignerMessage::BlockResponse(BlockResponse::Accepted((hash, signature))) => {
4656-
ignoring_signers
4657-
.iter()
4658-
.find(|key| key.verify(hash.bits(), &signature).is_ok())
4658+
SignerMessage::BlockResponse(BlockResponse::Accepted(accepted)) => {
4659+
ignoring_signers.iter().find(|key| {
4660+
key.verify(accepted.signer_signature_hash.bits(), &accepted.signature)
4661+
.is_ok()
4662+
})
46594663
}
46604664
_ => None,
46614665
}
@@ -4896,12 +4900,11 @@ fn miner_recovers_when_broadcast_block_delay_across_tenures_occurs() {
48964900
let message = SignerMessage::consensus_deserialize(&mut chunk.data.as_slice())
48974901
.expect("Failed to deserialize SignerMessage");
48984902
match message {
4899-
SignerMessage::BlockResponse(BlockResponse::Accepted((
4900-
hash,
4901-
signature,
4902-
))) => {
4903-
if block.header.signer_signature_hash() == hash {
4904-
Some(signature)
4903+
SignerMessage::BlockResponse(BlockResponse::Accepted(accepted)) => {
4904+
if block.header.signer_signature_hash()
4905+
== accepted.signer_signature_hash
4906+
{
4907+
Some(accepted.signature)
49054908
} else {
49064909
None
49074910
}

0 commit comments

Comments
 (0)