mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-04-28 11:46:07 +08:00
Merge remote-tracking branch 'origin/next' into feat/stacker-bitvec
This commit is contained in:
@@ -12,7 +12,7 @@ COPY . .
|
||||
RUN apt-get update && apt-get install -y git libclang-dev
|
||||
|
||||
# Run all the build steps in ramdisk in an attempt to speed things up
|
||||
RUN target=${BUILD_DIR} cp -R /src/. ${BUILD_DIR}/ \
|
||||
RUN --mount=type=tmpfs,target=${BUILD_DIR} cp -R /src/. ${BUILD_DIR}/ \
|
||||
&& cd ${BUILD_DIR} \
|
||||
&& rustup target add ${TARGET} \
|
||||
&& rustup component add rustfmt \
|
||||
@@ -21,5 +21,5 @@ RUN target=${BUILD_DIR} cp -R /src/. ${BUILD_DIR}/ \
|
||||
&& cp -R ${BUILD_DIR}/target/${TARGET}/release/. /out
|
||||
|
||||
FROM --platform=${TARGETPLATFORM} debian:bookworm
|
||||
COPY --from=build /out/stacks-node /bin/
|
||||
COPY --from=build /out/stacks-node /out/stacks-signer /bin/
|
||||
CMD ["stacks-node", "mainnet"]
|
||||
|
||||
@@ -23,6 +23,7 @@ use std::sync::Arc;
|
||||
use blockstack_lib::chainstate::nakamoto::NakamotoBlock;
|
||||
use blockstack_lib::chainstate::stacks::boot::{MINERS_NAME, SIGNERS_NAME};
|
||||
use blockstack_lib::chainstate::stacks::events::StackerDBChunksEvent;
|
||||
use blockstack_lib::chainstate::stacks::{StacksTransaction, ThresholdSignature};
|
||||
use blockstack_lib::net::api::postblock_proposal::{
|
||||
BlockValidateReject, BlockValidateResponse, ValidateRejectCode,
|
||||
};
|
||||
@@ -32,9 +33,11 @@ use serde::{Deserialize, Serialize};
|
||||
use stacks_common::codec::{
|
||||
read_next, read_next_at_most, write_next, Error as CodecError, StacksMessageCodec,
|
||||
};
|
||||
use stacks_common::util::hash::Sha512Trunc256Sum;
|
||||
use tiny_http::{
|
||||
Method as HttpMethod, Request as HttpRequest, Response as HttpResponse, Server as HttpServer,
|
||||
};
|
||||
use wsts::common::Signature;
|
||||
use wsts::net::{Message, Packet};
|
||||
|
||||
use crate::http::{decode_http_body, decode_http_request};
|
||||
@@ -73,11 +76,26 @@ pub enum SignerMessage {
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum BlockResponse {
|
||||
/// The Nakamoto block was accepted and therefore signed
|
||||
Accepted(NakamotoBlock),
|
||||
Accepted((Sha512Trunc256Sum, ThresholdSignature)),
|
||||
/// The Nakamoto block was rejected and therefore not signed
|
||||
Rejected(BlockRejection),
|
||||
}
|
||||
|
||||
impl BlockResponse {
|
||||
/// Create a new accepted BlockResponse for the provided block signer signature hash and signature
|
||||
pub fn accepted(hash: Sha512Trunc256Sum, sig: Signature) -> Self {
|
||||
Self::Accepted((hash, ThresholdSignature(sig)))
|
||||
}
|
||||
|
||||
/// Create a new rejected BlockResponse for the provided block signer signature hash and signature
|
||||
pub fn rejected(hash: Sha512Trunc256Sum, sig: Signature) -> Self {
|
||||
Self::Rejected(BlockRejection::new(
|
||||
hash,
|
||||
RejectCode::SignedRejection(ThresholdSignature(sig)),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
/// A rejection response from a signer for a proposed block
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct BlockRejection {
|
||||
@@ -85,17 +103,17 @@ pub struct BlockRejection {
|
||||
pub reason: String,
|
||||
/// The reason code for the rejection
|
||||
pub reason_code: RejectCode,
|
||||
/// The block that was rejected
|
||||
pub block: NakamotoBlock,
|
||||
/// The signer signature hash of the block that was rejected
|
||||
pub signer_signature_hash: Sha512Trunc256Sum,
|
||||
}
|
||||
|
||||
impl BlockRejection {
|
||||
/// Create a new BlockRejection for the provided block and reason code
|
||||
pub fn new(block: NakamotoBlock, reason_code: RejectCode) -> Self {
|
||||
pub fn new(signer_signature_hash: Sha512Trunc256Sum, reason_code: RejectCode) -> Self {
|
||||
Self {
|
||||
reason: reason_code.to_string(),
|
||||
reason_code,
|
||||
block,
|
||||
signer_signature_hash,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,7 +123,7 @@ impl From<BlockValidateReject> for BlockRejection {
|
||||
Self {
|
||||
reason: reject.reason,
|
||||
reason_code: RejectCode::ValidationFailed(reject.reason_code),
|
||||
block: reject.block,
|
||||
signer_signature_hash: reject.signer_signature_hash,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,9 +135,7 @@ pub enum RejectCode {
|
||||
/// RPC endpoint Validation failed
|
||||
ValidationFailed(ValidateRejectCode),
|
||||
/// Signers signed a block rejection
|
||||
SignedRejection,
|
||||
/// Invalid signature hash
|
||||
InvalidSignatureHash,
|
||||
SignedRejection(ThresholdSignature),
|
||||
/// Insufficient signers agreed to sign the block
|
||||
InsufficientSigners(Vec<u32>),
|
||||
}
|
||||
@@ -128,10 +144,9 @@ impl std::fmt::Display for RejectCode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
RejectCode::ValidationFailed(code) => write!(f, "Validation failed: {:?}", code),
|
||||
RejectCode::SignedRejection => {
|
||||
write!(f, "A threshold number of signers rejected the block.")
|
||||
RejectCode::SignedRejection(sig) => {
|
||||
write!(f, "A threshold number of signers rejected the block with the following signature: {:?}.", sig)
|
||||
}
|
||||
RejectCode::InvalidSignatureHash => write!(f, "The signature hash was invalid."),
|
||||
RejectCode::InsufficientSigners(malicious_signers) => write!(
|
||||
f,
|
||||
"Insufficient signers agreed to sign the block. The following signers are malicious: {:?}",
|
||||
|
||||
@@ -340,10 +340,10 @@ impl Config {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Network;
|
||||
use super::{Config, RawConfigFile};
|
||||
use blockstack_lib::util_lib::boot::boot_code_id;
|
||||
|
||||
use super::{Config, Network, RawConfigFile};
|
||||
|
||||
fn create_raw_config(overrides: impl FnOnce(&mut RawConfigFile)) -> RawConfigFile {
|
||||
let mut config = RawConfigFile {
|
||||
node_host: "127.0.0.1:20443".to_string(),
|
||||
|
||||
@@ -19,7 +19,6 @@ use std::time::Duration;
|
||||
|
||||
use blockstack_lib::burnchains::Txid;
|
||||
use blockstack_lib::chainstate::nakamoto::NakamotoBlock;
|
||||
use blockstack_lib::chainstate::stacks::ThresholdSignature;
|
||||
use blockstack_lib::net::api::postblock_proposal::BlockValidateResponse;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use libsigner::{
|
||||
@@ -186,13 +185,10 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
is_taproot,
|
||||
merkle_root,
|
||||
} => {
|
||||
let Ok(hash) = block.header.signer_signature_hash() else {
|
||||
error!("Failed to sign block. Invalid signature hash.");
|
||||
return false;
|
||||
};
|
||||
let signer_signature_hash = block.header.signer_signature_hash();
|
||||
let block_info = self
|
||||
.blocks
|
||||
.entry(hash)
|
||||
.entry(signer_signature_hash)
|
||||
.or_insert_with(|| BlockInfo::new(block.clone()));
|
||||
if block_info.signing_round {
|
||||
debug!("Received a sign command for a block we are already signing over. Ignore it.");
|
||||
@@ -256,29 +252,29 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
res: Sender<Vec<OperationResult>>,
|
||||
) {
|
||||
let transactions = &self.transactions;
|
||||
let (block_info, hash) = match block_validate_response {
|
||||
let block_info = match block_validate_response {
|
||||
BlockValidateResponse::Ok(block_validate_ok) => {
|
||||
let Ok(hash) = block_validate_ok.block.header.signer_signature_hash() else {
|
||||
self.broadcast_signature_hash_rejection(block_validate_ok.block);
|
||||
let Some(block_info) = self
|
||||
.blocks
|
||||
.get_mut(&block_validate_ok.signer_signature_hash)
|
||||
else {
|
||||
// We have not seen this block before. Why are we getting a response for it?
|
||||
debug!("Received a block validate response for a block we have not seen before. Ignoring...");
|
||||
return;
|
||||
};
|
||||
let block_info = self
|
||||
.blocks
|
||||
.entry(hash)
|
||||
.or_insert(BlockInfo::new(block_validate_ok.block.clone()));
|
||||
block_info.valid = Some(true);
|
||||
(block_info, hash)
|
||||
block_info
|
||||
}
|
||||
BlockValidateResponse::Reject(block_validate_reject) => {
|
||||
// There is no point in triggering a sign round for this block if validation failed from the stacks node
|
||||
let Ok(hash) = block_validate_reject.block.header.signer_signature_hash() else {
|
||||
self.broadcast_signature_hash_rejection(block_validate_reject.block);
|
||||
let Some(block_info) = self
|
||||
.blocks
|
||||
.get_mut(&block_validate_reject.signer_signature_hash)
|
||||
else {
|
||||
// We have not seen this block before. Why are we getting a response for it?
|
||||
debug!("Received a block validate response for a block we have not seen before. Ignoring...");
|
||||
return;
|
||||
};
|
||||
let block_info = self
|
||||
.blocks
|
||||
.entry(hash)
|
||||
.or_insert(BlockInfo::new(block_validate_reject.block.clone()));
|
||||
block_info.valid = Some(false);
|
||||
// Submit a rejection response to the .signers contract for miners
|
||||
// to observe so they know to send another block and to prove signers are doing work);
|
||||
@@ -288,14 +284,14 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
) {
|
||||
warn!("Failed to send block rejection to stacker-db: {:?}", e);
|
||||
}
|
||||
(block_info, hash)
|
||||
block_info
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(mut request) = block_info.nonce_request.take() {
|
||||
debug!("Received a block validate response from the stacks node for a block we already received a nonce request for. Responding to the nonce request...");
|
||||
// We have an associated nonce request. Respond to it
|
||||
Self::determine_vote(block_info, &mut request, transactions, hash);
|
||||
Self::determine_vote(block_info, &mut request, transactions);
|
||||
// Send the nonce request through with our vote
|
||||
let packet = Packet {
|
||||
msg: Message::NonceRequest(request),
|
||||
@@ -345,12 +341,11 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
/// Handle proposed blocks submitted by the miners to stackerdb
|
||||
fn handle_proposed_blocks(&mut self, blocks: Vec<NakamotoBlock>) {
|
||||
for block in blocks {
|
||||
let Ok(hash) = block.header.signer_signature_hash() else {
|
||||
self.broadcast_signature_hash_rejection(block);
|
||||
continue;
|
||||
};
|
||||
// Store the block in our cache
|
||||
self.blocks.insert(hash, BlockInfo::new(block.clone()));
|
||||
self.blocks.insert(
|
||||
block.header.signer_signature_hash(),
|
||||
BlockInfo::new(block.clone()),
|
||||
);
|
||||
// Submit the block for validation
|
||||
self.stacks_client
|
||||
.submit_block_for_validation(block)
|
||||
@@ -447,19 +442,14 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
debug!("Received a nonce request for an unknown message stream. Reject it.");
|
||||
return false;
|
||||
};
|
||||
let Ok(hash) = block.header.signer_signature_hash() else {
|
||||
debug!(
|
||||
"Received a nonce request for a block with an invalid signature hash. Reject it"
|
||||
);
|
||||
return false;
|
||||
};
|
||||
let transactions = &self.transactions;
|
||||
let Some(block_info) = self.blocks.get_mut(&hash) else {
|
||||
let signer_signature_hash = block.header.signer_signature_hash();
|
||||
let Some(block_info) = self.blocks.get_mut(&signer_signature_hash) else {
|
||||
// We have not seen this block before. Cache it. Send a RPC to the stacks node to validate it.
|
||||
debug!("We have received a block sign request for a block we have not seen before. Cache the nonce request and submit the block for validation...");
|
||||
// Store the block in our cache
|
||||
self.blocks.insert(
|
||||
hash,
|
||||
signer_signature_hash,
|
||||
BlockInfo::new_with_request(block.clone(), request.clone()),
|
||||
);
|
||||
self.stacks_client
|
||||
@@ -475,7 +465,7 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
block_info.nonce_request = Some(request.clone());
|
||||
return false;
|
||||
}
|
||||
Self::determine_vote(block_info, request, transactions, hash);
|
||||
Self::determine_vote(block_info, request, transactions);
|
||||
true
|
||||
}
|
||||
|
||||
@@ -484,9 +474,8 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
block_info: &mut BlockInfo,
|
||||
nonce_request: &mut NonceRequest,
|
||||
transactions: &[Txid],
|
||||
hash: Sha512Trunc256Sum,
|
||||
) {
|
||||
let mut vote_bytes = hash.0.to_vec();
|
||||
let mut vote_bytes = block_info.block.header.signer_signature_hash().0.to_vec();
|
||||
// Validate the block contents
|
||||
if !block_info.valid.unwrap_or(false)
|
||||
|| !transactions
|
||||
@@ -574,35 +563,34 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
};
|
||||
let message = self.coordinator.get_message();
|
||||
// This jankiness is because a coordinator could have signed a rejection we need to find the underlying block hash
|
||||
let block_hash_bytes = if message.len() > 32 {
|
||||
let signer_signature_hash_bytes = if message.len() > 32 {
|
||||
&message[..32]
|
||||
} else {
|
||||
&message
|
||||
};
|
||||
let Some(block_hash) = Sha512Trunc256Sum::from_bytes(block_hash_bytes) else {
|
||||
let Some(signer_signature_hash) =
|
||||
Sha512Trunc256Sum::from_bytes(signer_signature_hash_bytes)
|
||||
else {
|
||||
debug!("Received a signature result for a signature over a non-block. Nothing to broadcast.");
|
||||
return;
|
||||
};
|
||||
let Some(block_info) = self.blocks.remove(&block_hash) else {
|
||||
debug!("Received a signature result for a block we have not seen before. Ignoring...");
|
||||
return;
|
||||
};
|
||||
|
||||
// TODO: proper garbage collection...This is currently our only cleanup of blocks
|
||||
self.blocks.remove(&signer_signature_hash);
|
||||
|
||||
// This signature is no longer valid. Do not broadcast it.
|
||||
if !signature.verify(aggregate_public_key, &message) {
|
||||
warn!("Received an invalid signature result across the block. Do not broadcast it.");
|
||||
// TODO: should we reinsert it and trigger a sign round across the block again?
|
||||
return;
|
||||
}
|
||||
// Update the block signature hash with what the signers produced.
|
||||
let mut block = block_info.block;
|
||||
block.header.signer_signature = ThresholdSignature(signature.clone());
|
||||
|
||||
let block_submission = if message == block_hash.0.to_vec() {
|
||||
let block_submission = if message == signer_signature_hash.0.to_vec() {
|
||||
// we agreed to sign the block hash. Return an approval message
|
||||
BlockResponse::Accepted(block).into()
|
||||
BlockResponse::accepted(signer_signature_hash, signature.clone()).into()
|
||||
} else {
|
||||
// We signed a rejection message. Return a rejection message
|
||||
BlockRejection::new(block, RejectCode::SignedRejection).into()
|
||||
BlockResponse::rejected(signer_signature_hash, signature.clone()).into()
|
||||
};
|
||||
|
||||
// Submit signature result to miners to observe
|
||||
@@ -627,16 +615,16 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
let block = read_next::<NakamotoBlock, _>(&mut &message[..]).ok().unwrap_or({
|
||||
// This is not a block so maybe its across its hash
|
||||
// This jankiness is because a coordinator could have signed a rejection we need to find the underlying block hash
|
||||
let block_hash_bytes = if message.len() > 32 {
|
||||
let signer_signature_hash_bytes = if message.len() > 32 {
|
||||
&message[..32]
|
||||
} else {
|
||||
&message
|
||||
};
|
||||
let Some(block_hash) = Sha512Trunc256Sum::from_bytes(block_hash_bytes) else {
|
||||
let Some(signer_signature_hash) = Sha512Trunc256Sum::from_bytes(signer_signature_hash_bytes) else {
|
||||
debug!("Received a signature result for a signature over a non-block. Nothing to broadcast.");
|
||||
return;
|
||||
};
|
||||
let Some(block_info) = self.blocks.remove(&block_hash) else {
|
||||
let Some(block_info) = self.blocks.remove(&signer_signature_hash) else {
|
||||
debug!("Received a signature result for a block we have not seen before. Ignoring...");
|
||||
return;
|
||||
};
|
||||
@@ -644,7 +632,7 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
});
|
||||
// We don't have enough signers to sign the block. Broadcast a rejection
|
||||
let block_rejection = BlockRejection::new(
|
||||
block,
|
||||
block.header.signer_signature_hash(),
|
||||
RejectCode::InsufficientSigners(malicious_signers.clone()),
|
||||
);
|
||||
// Submit signature result to miners to observe
|
||||
@@ -696,19 +684,6 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Broadcast a block rejection due to an invalid block signature hash
|
||||
fn broadcast_signature_hash_rejection(&mut self, block: NakamotoBlock) {
|
||||
debug!("Broadcasting a block rejection due to a block with an invalid signature hash...");
|
||||
let block_rejection = BlockRejection::new(block, RejectCode::InvalidSignatureHash);
|
||||
// Submit signature result to miners to observe
|
||||
if let Err(e) = self
|
||||
.stackerdb
|
||||
.send_message_with_retry(self.signing_round.signer_id, block_rejection.into())
|
||||
{
|
||||
warn!("Failed to send block submission to stacker-db: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Config> for RunLoop<FireCoordinator<v2::Aggregator>> {
|
||||
|
||||
@@ -403,7 +403,21 @@ impl StacksMessageCodec for NakamotoBlockHeader {
|
||||
impl NakamotoBlockHeader {
|
||||
/// Calculate the message digest for miners to sign.
|
||||
/// This includes all fields _except_ the signatures.
|
||||
pub fn miner_signature_hash(&self) -> Result<Sha512Trunc256Sum, CodecError> {
|
||||
pub fn miner_signature_hash(&self) -> Sha512Trunc256Sum {
|
||||
self.miner_signature_hash_inner()
|
||||
.expect("BUG: failed to calculate miner signature hash")
|
||||
}
|
||||
|
||||
/// Calculate the message digest for signers to sign.
|
||||
/// This includes all fields _except_ the signer signature.
|
||||
pub fn signer_signature_hash(&self) -> Sha512Trunc256Sum {
|
||||
self.signer_signature_hash_inner()
|
||||
.expect("BUG: failed to calculate signer signature hash")
|
||||
}
|
||||
|
||||
/// Inner calculation of the message digest for miners to sign.
|
||||
/// This includes all fields _except_ the signatures.
|
||||
fn miner_signature_hash_inner(&self) -> Result<Sha512Trunc256Sum, CodecError> {
|
||||
let mut hasher = Sha512_256::new();
|
||||
let fd = &mut hasher;
|
||||
write_next(fd, &self.version)?;
|
||||
@@ -416,9 +430,9 @@ impl NakamotoBlockHeader {
|
||||
Ok(Sha512Trunc256Sum::from_hasher(hasher))
|
||||
}
|
||||
|
||||
/// Calculate the message digest for stackers to sign.
|
||||
/// Inner calculation of the message digest for stackers to sign.
|
||||
/// This includes all fields _except_ the stacker signature.
|
||||
pub fn signer_signature_hash(&self) -> Result<Sha512Trunc256Sum, CodecError> {
|
||||
fn signer_signature_hash_inner(&self) -> Result<Sha512Trunc256Sum, CodecError> {
|
||||
let mut hasher = Sha512_256::new();
|
||||
let fd = &mut hasher;
|
||||
write_next(fd, &self.version)?;
|
||||
@@ -434,7 +448,7 @@ impl NakamotoBlockHeader {
|
||||
}
|
||||
|
||||
pub fn recover_miner_pk(&self) -> Option<StacksPublicKey> {
|
||||
let signed_hash = self.miner_signature_hash().ok()?;
|
||||
let signed_hash = self.miner_signature_hash();
|
||||
let recovered_pk =
|
||||
StacksPublicKey::recover_to_pubkey(signed_hash.bits(), &self.miner_signature).ok()?;
|
||||
|
||||
@@ -456,7 +470,7 @@ impl NakamotoBlockHeader {
|
||||
|
||||
/// Sign the block header by the miner
|
||||
pub fn sign_miner(&mut self, privk: &StacksPrivateKey) -> Result<(), ChainstateError> {
|
||||
let sighash = self.miner_signature_hash()?.0;
|
||||
let sighash = self.miner_signature_hash().0;
|
||||
let sig = privk
|
||||
.sign(&sighash)
|
||||
.map_err(|se| net_error::SigningError(se.to_string()))?;
|
||||
@@ -1727,7 +1741,7 @@ impl NakamotoChainState {
|
||||
if !db_handle.expects_signer_signature(
|
||||
&block.header.consensus_hash,
|
||||
schnorr_signature,
|
||||
&block.header.signer_signature_hash()?.0,
|
||||
&block.header.signer_signature_hash().0,
|
||||
aggregate_public_key,
|
||||
)? {
|
||||
let msg = format!("Received block, but the stacker signature does not match the active stacking cycle");
|
||||
|
||||
@@ -155,11 +155,7 @@ impl Default for TestSigners {
|
||||
impl TestSigners {
|
||||
pub fn sign_nakamoto_block(&mut self, block: &mut NakamotoBlock) {
|
||||
let mut rng = rand_core::OsRng;
|
||||
let msg = block
|
||||
.header
|
||||
.signer_signature_hash()
|
||||
.expect("Failed to determine the block header signature hash for signers.")
|
||||
.0;
|
||||
let msg = block.header.signer_signature_hash().0;
|
||||
let (nonces, sig_shares, key_ids) =
|
||||
wsts::v2::test_helpers::sign(msg.as_slice(), &mut self.signer_parties, &mut rng);
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ use stacks_common::types::chainstate::{
|
||||
use stacks_common::types::net::PeerHost;
|
||||
use stacks_common::types::StacksPublicKeyBuffer;
|
||||
use stacks_common::util::get_epoch_time_ms;
|
||||
use stacks_common::util::hash::{hex_bytes, to_hex, Hash160, Sha256Sum};
|
||||
use stacks_common::util::hash::{hex_bytes, to_hex, Hash160, Sha256Sum, Sha512Trunc256Sum};
|
||||
use stacks_common::util::retry::BoundReader;
|
||||
|
||||
use crate::burnchains::affirmation::AffirmationMap;
|
||||
@@ -90,8 +90,7 @@ fn hex_deser_block<'de, D: serde::Deserializer<'de>>(d: D) -> Result<NakamotoBlo
|
||||
/// that the stacks-node thinks should be rejected.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct BlockValidateReject {
|
||||
#[serde(serialize_with = "hex_ser_block", deserialize_with = "hex_deser_block")]
|
||||
pub block: NakamotoBlock,
|
||||
pub signer_signature_hash: Sha512Trunc256Sum,
|
||||
pub reason: String,
|
||||
pub reason_code: ValidateRejectCode,
|
||||
}
|
||||
@@ -119,8 +118,7 @@ where
|
||||
/// that the stacks-node thinks is acceptable.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct BlockValidateOk {
|
||||
#[serde(serialize_with = "hex_ser_block", deserialize_with = "hex_deser_block")]
|
||||
pub block: NakamotoBlock,
|
||||
pub signer_signature_hash: Sha512Trunc256Sum,
|
||||
pub cost: ExecutionCost,
|
||||
pub size: u64,
|
||||
}
|
||||
@@ -166,7 +164,7 @@ impl NakamotoBlockProposal {
|
||||
let result =
|
||||
self.validate(&sortdb, &mut chainstate)
|
||||
.map_err(|reason| BlockValidateReject {
|
||||
block: self.block.clone(),
|
||||
signer_signature_hash: self.block.header.signer_signature_hash(),
|
||||
reason_code: reason.reason_code,
|
||||
reason: reason.reason,
|
||||
});
|
||||
@@ -326,7 +324,11 @@ impl NakamotoBlockProposal {
|
||||
})
|
||||
);
|
||||
|
||||
Ok(BlockValidateOk { block, cost, size })
|
||||
Ok(BlockValidateOk {
|
||||
signer_signature_hash: block.header.signer_signature_hash(),
|
||||
cost,
|
||||
size,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -979,7 +979,7 @@ impl MockamotoNode {
|
||||
|
||||
let miner_signature = self
|
||||
.miner_key
|
||||
.sign(block.header.miner_signature_hash().unwrap().as_bytes())
|
||||
.sign(block.header.miner_signature_hash().as_bytes())
|
||||
.unwrap();
|
||||
|
||||
block.header.miner_signature = miner_signature;
|
||||
|
||||
@@ -66,11 +66,7 @@ impl SelfSigner {
|
||||
|
||||
pub fn sign_nakamoto_block(&mut self, block: &mut NakamotoBlock) {
|
||||
let mut rng = rand::rngs::OsRng::default();
|
||||
let msg = block
|
||||
.header
|
||||
.signer_signature_hash()
|
||||
.expect("Failed to determine the block header signature hash for signers.")
|
||||
.0;
|
||||
let msg = block.header.signer_signature_hash().0;
|
||||
let (nonces, sig_shares, key_ids) =
|
||||
wsts::v2::test_helpers::sign(msg.as_slice(), &mut self.signer_parties, &mut rng);
|
||||
|
||||
|
||||
@@ -562,13 +562,7 @@ impl BlockMinerThread {
|
||||
|
||||
let mining_key = self.keychain.get_nakamoto_sk();
|
||||
let miner_signature = mining_key
|
||||
.sign(
|
||||
block
|
||||
.header
|
||||
.miner_signature_hash()
|
||||
.map_err(|_| NakamotoNodeError::SigningError("Could not create sighash"))?
|
||||
.as_bytes(),
|
||||
)
|
||||
.sign(block.header.miner_signature_hash().as_bytes())
|
||||
.map_err(NakamotoNodeError::SigningError)?;
|
||||
block.header.miner_signature = miner_signature;
|
||||
|
||||
|
||||
@@ -384,12 +384,7 @@ fn stackerdb_dkg_sign() {
|
||||
block.header.tx_merkle_root = tx_merkle_root;
|
||||
|
||||
// The block is invalid so the signers should return a signature across its hash + b'n'
|
||||
let mut msg = block
|
||||
.header
|
||||
.signer_signature_hash()
|
||||
.expect("Failed to get signature hash")
|
||||
.0
|
||||
.to_vec();
|
||||
let mut msg = block.header.signer_signature_hash().0.to_vec();
|
||||
msg.push(b'n');
|
||||
|
||||
let signer_test = SignerTest::new(10, 400);
|
||||
@@ -642,16 +637,16 @@ fn stackerdb_block_proposal() {
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
}
|
||||
let validate_responses = test_observer::get_proposal_responses();
|
||||
let mut proposed_block = match validate_responses.first().expect("No block proposal") {
|
||||
BlockValidateResponse::Ok(block_validated) => block_validated.block.clone(),
|
||||
_ => panic!("Unexpected response"),
|
||||
};
|
||||
let signature_hash = proposed_block
|
||||
.header
|
||||
.signer_signature_hash()
|
||||
.expect("Unable to retrieve signature hash from proposed block");
|
||||
let proposed_signer_signature_hash =
|
||||
match validate_responses.first().expect("No block proposal") {
|
||||
BlockValidateResponse::Ok(block_validated) => block_validated.signer_signature_hash,
|
||||
_ => panic!("Unexpected response"),
|
||||
};
|
||||
assert!(
|
||||
signature.verify(&aggregate_public_key, signature_hash.0.as_slice()),
|
||||
signature.verify(
|
||||
&aggregate_public_key,
|
||||
proposed_signer_signature_hash.0.as_slice()
|
||||
),
|
||||
"Signature verification failed"
|
||||
);
|
||||
// Verify that the signers broadcasted a signed NakamotoBlock back to the .signers contract
|
||||
@@ -680,9 +675,13 @@ fn stackerdb_block_proposal() {
|
||||
}
|
||||
let chunk = chunk.unwrap();
|
||||
let signer_message = bincode::deserialize::<SignerMessage>(&chunk).unwrap();
|
||||
if let SignerMessage::BlockResponse(BlockResponse::Accepted(block)) = signer_message {
|
||||
proposed_block.header.signer_signature = ThresholdSignature(signature);
|
||||
assert_eq!(block, proposed_block);
|
||||
if let SignerMessage::BlockResponse(BlockResponse::Accepted((
|
||||
block_signer_signature_hash,
|
||||
block_signature,
|
||||
))) = signer_message
|
||||
{
|
||||
assert_eq!(block_signer_signature_hash, proposed_signer_signature_hash);
|
||||
assert_eq!(block_signature, ThresholdSignature(signature));
|
||||
} else {
|
||||
panic!("Received unexpected message");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user