mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-01-12 22:43:42 +08:00
Move filtering of messages out ot stacks-signer into libsigner
Signed-off-by: Jacinta Ferrant <jacinta@trustmachines.co>
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1971,6 +1971,7 @@ dependencies = [
|
||||
name = "libsigner"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"clarity",
|
||||
"libc",
|
||||
"libstackerdb",
|
||||
|
||||
@@ -16,6 +16,7 @@ name = "libsigner"
|
||||
path = "./src/libsigner.rs"
|
||||
|
||||
[dependencies]
|
||||
bincode = "1.3.3"
|
||||
clarity = { path = "../clarity" }
|
||||
libc = "0.2"
|
||||
libstackerdb = { path = "../libstackerdb" }
|
||||
|
||||
@@ -21,9 +21,11 @@ use std::sync::mpsc::Sender;
|
||||
use std::sync::Arc;
|
||||
|
||||
use blockstack_lib::chainstate::nakamoto::NakamotoBlock;
|
||||
use blockstack_lib::chainstate::stacks::boot::MINERS_NAME;
|
||||
use blockstack_lib::chainstate::stacks::boot::{MINERS_NAME, SIGNERS_NAME};
|
||||
use blockstack_lib::chainstate::stacks::events::StackerDBChunksEvent;
|
||||
use blockstack_lib::net::api::postblock_proposal::BlockValidateResponse;
|
||||
use blockstack_lib::net::api::postblock_proposal::{
|
||||
BlockValidateReject, BlockValidateResponse, ValidateRejectCode,
|
||||
};
|
||||
use blockstack_lib::util_lib::boot::boot_code_id;
|
||||
use clarity::vm::types::QualifiedContractIdentifier;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -38,13 +40,155 @@ use wsts::net::{Message, Packet};
|
||||
use crate::http::{decode_http_body, decode_http_request};
|
||||
use crate::EventError;
|
||||
|
||||
/// Temporary placeholder for the number of slots allocated to a stacker-db writer. This will be retrieved from the stacker-db instance in the future
|
||||
/// See: https://github.com/stacks-network/stacks-blockchain/issues/3921
|
||||
/// Is equal to the number of message types
|
||||
pub const SIGNER_SLOTS_PER_USER: u32 = 11;
|
||||
|
||||
// The slot IDS for each message type
|
||||
const DKG_BEGIN_SLOT_ID: u32 = 0;
|
||||
const DKG_PRIVATE_BEGIN_SLOT_ID: u32 = 1;
|
||||
const DKG_END_BEGIN_SLOT_ID: u32 = 2;
|
||||
const DKG_END_SLOT_ID: u32 = 3;
|
||||
const DKG_PUBLIC_SHARES_SLOT_ID: u32 = 4;
|
||||
const DKG_PRIVATE_SHARES_SLOT_ID: u32 = 5;
|
||||
const NONCE_REQUEST_SLOT_ID: u32 = 6;
|
||||
const NONCE_RESPONSE_SLOT_ID: u32 = 7;
|
||||
const SIGNATURE_SHARE_REQUEST_SLOT_ID: u32 = 8;
|
||||
const SIGNATURE_SHARE_RESPONSE_SLOT_ID: u32 = 9;
|
||||
/// The slot ID for the block response for miners to observe
|
||||
pub const BLOCK_SLOT_ID: u32 = 10;
|
||||
|
||||
/// The messages being sent through the stacker db contracts
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum SignerMessage {
|
||||
/// The signed/validated Nakamoto block for miners to observe
|
||||
BlockResponse(BlockResponse),
|
||||
/// DKG and Signing round data for other signers to observe
|
||||
Packet(Packet),
|
||||
}
|
||||
|
||||
/// The response that a signer sends back to observing miners
|
||||
/// either accepting or rejecting a Nakamoto block with the corresponding reason
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum BlockResponse {
|
||||
/// The Nakamoto block was accepted and therefore signed
|
||||
Accepted(NakamotoBlock),
|
||||
/// The Nakamoto block was rejected and therefore not signed
|
||||
Rejected(BlockRejection),
|
||||
}
|
||||
|
||||
/// A rejection response from a signer for a proposed block
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct BlockRejection {
|
||||
/// The reason for the rejection
|
||||
pub reason: String,
|
||||
/// The reason code for the rejection
|
||||
pub reason_code: RejectCode,
|
||||
/// The block that was rejected
|
||||
pub block: NakamotoBlock,
|
||||
}
|
||||
|
||||
impl BlockRejection {
|
||||
/// Create a new BlockRejection for the provided block and reason code
|
||||
pub fn new(block: NakamotoBlock, reason_code: RejectCode) -> Self {
|
||||
Self {
|
||||
reason: reason_code.to_string(),
|
||||
reason_code,
|
||||
block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockValidateReject> for BlockRejection {
|
||||
fn from(reject: BlockValidateReject) -> Self {
|
||||
Self {
|
||||
reason: reject.reason,
|
||||
reason_code: RejectCode::ValidationFailed(reject.reason_code),
|
||||
block: reject.block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This enum is used to supply a `reason_code` for block rejections
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[repr(u8)]
|
||||
pub enum RejectCode {
|
||||
/// RPC endpoint Validation failed
|
||||
ValidationFailed(ValidateRejectCode),
|
||||
/// Signers signed a block rejection
|
||||
SignedRejection,
|
||||
/// Invalid signature hash
|
||||
InvalidSignatureHash,
|
||||
}
|
||||
|
||||
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::InvalidSignatureHash => write!(f, "The signature hash was invalid."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Packet> for SignerMessage {
|
||||
fn from(packet: Packet) -> Self {
|
||||
Self::Packet(packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockResponse> for SignerMessage {
|
||||
fn from(block_response: BlockResponse) -> Self {
|
||||
Self::BlockResponse(block_response)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockRejection> for SignerMessage {
|
||||
fn from(block_rejection: BlockRejection) -> Self {
|
||||
Self::BlockResponse(BlockResponse::Rejected(block_rejection))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockValidateReject> for SignerMessage {
|
||||
fn from(rejection: BlockValidateReject) -> Self {
|
||||
Self::BlockResponse(BlockResponse::Rejected(rejection.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl SignerMessage {
|
||||
/// Helper function to determine the slot ID for the provided stacker-db writer id
|
||||
pub fn slot_id(&self, id: u32) -> u32 {
|
||||
let slot_id = match self {
|
||||
Self::Packet(packet) => match packet.msg {
|
||||
Message::DkgBegin(_) => DKG_BEGIN_SLOT_ID,
|
||||
Message::DkgPrivateBegin(_) => DKG_PRIVATE_BEGIN_SLOT_ID,
|
||||
Message::DkgEndBegin(_) => DKG_END_BEGIN_SLOT_ID,
|
||||
Message::DkgEnd(_) => DKG_END_SLOT_ID,
|
||||
Message::DkgPublicShares(_) => DKG_PUBLIC_SHARES_SLOT_ID,
|
||||
Message::DkgPrivateShares(_) => DKG_PRIVATE_SHARES_SLOT_ID,
|
||||
Message::NonceRequest(_) => NONCE_REQUEST_SLOT_ID,
|
||||
Message::NonceResponse(_) => NONCE_RESPONSE_SLOT_ID,
|
||||
Message::SignatureShareRequest(_) => SIGNATURE_SHARE_REQUEST_SLOT_ID,
|
||||
Message::SignatureShareResponse(_) => SIGNATURE_SHARE_RESPONSE_SLOT_ID,
|
||||
},
|
||||
Self::BlockResponse(_) => BLOCK_SLOT_ID,
|
||||
};
|
||||
SIGNER_SLOTS_PER_USER * id + slot_id
|
||||
}
|
||||
}
|
||||
|
||||
/// Event enum for newly-arrived signer subscribed events
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum SignerEvent {
|
||||
/// A new stackerDB chunk was received
|
||||
StackerDB(StackerDBChunksEvent),
|
||||
/// A new block proposal was received
|
||||
BlockProposal(BlockValidateResponse),
|
||||
/// The miner proposed blocks for signers to observe and sign
|
||||
ProposedBlocks(Vec<NakamotoBlock>),
|
||||
/// The signer messages for other signers and miners to observe
|
||||
SignerMessages(Vec<SignerMessage>),
|
||||
/// A new block proposal validation response from the node
|
||||
BlockValidationResponse(BlockValidateResponse),
|
||||
}
|
||||
|
||||
/// Trait to implement a stop-signaler for the event receiver thread.
|
||||
@@ -55,7 +199,7 @@ pub trait EventStopSignaler {
|
||||
fn send(&mut self);
|
||||
}
|
||||
|
||||
/// Trait to implement to handle StackerDB and BlockProposal events sent by the Stacks node
|
||||
/// Trait to implement to handle signer specific events sent by the Stacks node
|
||||
pub trait EventReceiver {
|
||||
/// The implementation of ST will ensure that a call to ST::send() will cause
|
||||
/// the call to `is_stopped()` below to return true.
|
||||
@@ -120,25 +264,31 @@ pub struct SignerEventReceiver {
|
||||
out_channels: Vec<Sender<SignerEvent>>,
|
||||
/// inter-thread stop variable -- if set to true, then the `main_loop` will exit
|
||||
stop_signal: Arc<AtomicBool>,
|
||||
/// Whether the receiver is running on mainnet
|
||||
is_mainnet: bool,
|
||||
}
|
||||
|
||||
impl SignerEventReceiver {
|
||||
/// Make a new Signer event receiver, and return both the receiver and the read end of a
|
||||
/// channel into which node-received data can be obtained.
|
||||
pub fn new(contract_ids: Vec<QualifiedContractIdentifier>) -> SignerEventReceiver {
|
||||
pub fn new(
|
||||
contract_ids: Vec<QualifiedContractIdentifier>,
|
||||
is_mainnet: bool,
|
||||
) -> SignerEventReceiver {
|
||||
SignerEventReceiver {
|
||||
stackerdb_contract_ids: contract_ids,
|
||||
http_server: None,
|
||||
local_addr: None,
|
||||
out_channels: vec![],
|
||||
stop_signal: Arc::new(AtomicBool::new(false)),
|
||||
is_mainnet,
|
||||
}
|
||||
}
|
||||
|
||||
/// Do something with the socket
|
||||
pub fn with_server<F, R>(&mut self, todo: F) -> Result<R, EventError>
|
||||
where
|
||||
F: FnOnce(&SignerEventReceiver, &mut HttpServer, &[QualifiedContractIdentifier]) -> R,
|
||||
F: FnOnce(&SignerEventReceiver, &mut HttpServer, bool) -> R,
|
||||
{
|
||||
let mut server = if let Some(s) = self.http_server.take() {
|
||||
s
|
||||
@@ -146,7 +296,7 @@ impl SignerEventReceiver {
|
||||
return Err(EventError::NotBound);
|
||||
};
|
||||
|
||||
let res = todo(self, &mut server, &self.stackerdb_contract_ids);
|
||||
let res = todo(self, &mut server, self.is_mainnet);
|
||||
|
||||
self.http_server = Some(server);
|
||||
Ok(res)
|
||||
@@ -203,14 +353,12 @@ impl EventReceiver for SignerEventReceiver {
|
||||
/// Errors are recoverable -- the caller should call this method again even if it returns an
|
||||
/// error.
|
||||
fn next_event(&mut self) -> Result<SignerEvent, EventError> {
|
||||
self.with_server(|event_receiver, http_server, contract_ids| {
|
||||
let mut request = http_server.recv()?;
|
||||
|
||||
self.with_server(|event_receiver, http_server, is_mainnet| {
|
||||
// were we asked to terminate?
|
||||
if event_receiver.is_stopped() {
|
||||
return Err(EventError::Terminated);
|
||||
}
|
||||
|
||||
let request = http_server.recv()?;
|
||||
if request.method() != &HttpMethod::Post {
|
||||
return Err(EventError::MalformedRequest(format!(
|
||||
"Unrecognized method '{}'",
|
||||
@@ -218,71 +366,9 @@ impl EventReceiver for SignerEventReceiver {
|
||||
)));
|
||||
}
|
||||
if request.url() == "/stackerdb_chunks" {
|
||||
debug!("Got stackerdb_chunks event");
|
||||
let mut body = String::new();
|
||||
if let Err(e) = request
|
||||
.as_reader()
|
||||
.read_to_string(&mut body) {
|
||||
error!("Failed to read body: {:?}", &e);
|
||||
|
||||
request
|
||||
.respond(HttpResponse::empty(200u16))
|
||||
.expect("response failed");
|
||||
return Err(EventError::MalformedRequest(format!(
|
||||
"Failed to read body: {:?}",
|
||||
&e
|
||||
)));
|
||||
}
|
||||
|
||||
let event: StackerDBChunksEvent =
|
||||
serde_json::from_slice(body.as_bytes()).map_err(|e| {
|
||||
EventError::Deserialize(format!("Could not decode body to JSON: {:?}", &e))
|
||||
})?;
|
||||
|
||||
if !contract_ids.contains(&event.contract_id) {
|
||||
info!(
|
||||
"[{:?}] next_event got event from an unexpected contract id {}, return OK so other side doesn't keep sending this",
|
||||
event_receiver.local_addr,
|
||||
event.contract_id
|
||||
);
|
||||
request
|
||||
.respond(HttpResponse::empty(200u16))
|
||||
.expect("response failed");
|
||||
return Err(EventError::UnrecognizedStackerDBContract(event.contract_id));
|
||||
}
|
||||
|
||||
request
|
||||
.respond(HttpResponse::empty(200u16))
|
||||
.expect("response failed");
|
||||
|
||||
Ok(SignerEvent::StackerDB(event))
|
||||
process_stackerdb_event(event_receiver.local_addr, request, is_mainnet)
|
||||
} else if request.url() == "/proposal_response" {
|
||||
debug!("Got proposal_response event");
|
||||
let mut body = String::new();
|
||||
if let Err(e) = request
|
||||
.as_reader()
|
||||
.read_to_string(&mut body) {
|
||||
error!("Failed to read body: {:?}", &e);
|
||||
|
||||
request
|
||||
.respond(HttpResponse::empty(200u16))
|
||||
.expect("response failed");
|
||||
return Err(EventError::MalformedRequest(format!(
|
||||
"Failed to read body: {:?}",
|
||||
&e
|
||||
)));
|
||||
}
|
||||
|
||||
let event: BlockValidateResponse =
|
||||
serde_json::from_slice(body.as_bytes()).map_err(|e| {
|
||||
EventError::Deserialize(format!("Could not decode body to JSON: {:?}", &e))
|
||||
})?;
|
||||
|
||||
request
|
||||
.respond(HttpResponse::empty(200u16))
|
||||
.expect("response failed");
|
||||
|
||||
Ok(SignerEvent::BlockProposal(event))
|
||||
process_proposal_response(request)
|
||||
} else {
|
||||
let url = request.url().to_string();
|
||||
|
||||
@@ -349,3 +435,86 @@ impl EventReceiver for SignerEventReceiver {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Process a stackerdb event from the node
|
||||
fn process_stackerdb_event(
|
||||
local_addr: Option<SocketAddr>,
|
||||
mut request: HttpRequest,
|
||||
is_mainnet: bool,
|
||||
) -> Result<SignerEvent, EventError> {
|
||||
debug!("Got stackerdb_chunks event");
|
||||
let mut body = String::new();
|
||||
if let Err(e) = request.as_reader().read_to_string(&mut body) {
|
||||
error!("Failed to read body: {:?}", &e);
|
||||
|
||||
request
|
||||
.respond(HttpResponse::empty(200u16))
|
||||
.expect("response failed");
|
||||
return Err(EventError::MalformedRequest(format!(
|
||||
"Failed to read body: {:?}",
|
||||
&e
|
||||
)));
|
||||
}
|
||||
|
||||
let event: StackerDBChunksEvent = serde_json::from_slice(body.as_bytes())
|
||||
.map_err(|e| EventError::Deserialize(format!("Could not decode body to JSON: {:?}", &e)))?;
|
||||
|
||||
let signer_event = if event.contract_id == boot_code_id(MINERS_NAME, is_mainnet) {
|
||||
let blocks: Vec<NakamotoBlock> = event
|
||||
.modified_slots
|
||||
.iter()
|
||||
.filter_map(|chunk| read_next::<NakamotoBlock, _>(&mut &chunk.data[..]).ok())
|
||||
.collect();
|
||||
SignerEvent::ProposedBlocks(blocks)
|
||||
} else if event.contract_id.name.to_string() == SIGNERS_NAME {
|
||||
// TODO: fix this to be against boot_code_id(SIGNERS_NAME, is_mainnet) when .signers is deployed
|
||||
let signer_messages: Vec<SignerMessage> = event
|
||||
.modified_slots
|
||||
.iter()
|
||||
.filter_map(|chunk| bincode::deserialize::<SignerMessage>(&chunk.data).ok())
|
||||
.collect();
|
||||
SignerEvent::SignerMessages(signer_messages)
|
||||
} else {
|
||||
info!(
|
||||
"[{:?}] next_event got event from an unexpected contract id {}, return OK so other side doesn't keep sending this",
|
||||
local_addr,
|
||||
event.contract_id
|
||||
);
|
||||
request
|
||||
.respond(HttpResponse::empty(200u16))
|
||||
.expect("response failed");
|
||||
return Err(EventError::UnrecognizedStackerDBContract(event.contract_id));
|
||||
};
|
||||
|
||||
request
|
||||
.respond(HttpResponse::empty(200u16))
|
||||
.expect("response failed");
|
||||
|
||||
Ok(signer_event)
|
||||
}
|
||||
|
||||
/// Process a proposal response from the node
|
||||
fn process_proposal_response(mut request: HttpRequest) -> Result<SignerEvent, EventError> {
|
||||
debug!("Got proposal_response event");
|
||||
let mut body = String::new();
|
||||
if let Err(e) = request.as_reader().read_to_string(&mut body) {
|
||||
error!("Failed to read body: {:?}", &e);
|
||||
|
||||
request
|
||||
.respond(HttpResponse::empty(200u16))
|
||||
.expect("response failed");
|
||||
return Err(EventError::MalformedRequest(format!(
|
||||
"Failed to read body: {:?}",
|
||||
&e
|
||||
)));
|
||||
}
|
||||
|
||||
let event: BlockValidateResponse = serde_json::from_slice(body.as_bytes())
|
||||
.map_err(|e| EventError::Deserialize(format!("Could not decode body to JSON: {:?}", &e)))?;
|
||||
|
||||
request
|
||||
.respond(HttpResponse::empty(200u16))
|
||||
.expect("response failed");
|
||||
|
||||
Ok(SignerEvent::BlockValidationResponse(event))
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ mod session;
|
||||
|
||||
pub use crate::error::{EventError, RPCError};
|
||||
pub use crate::events::{
|
||||
EventReceiver, EventStopSignaler, SignerEvent, SignerEventReceiver, SignerStopSignaler,
|
||||
BlockRejection, BlockResponse, EventReceiver, EventStopSignaler, RejectCode, SignerEvent,
|
||||
SignerEventReceiver, SignerMessage, SignerStopSignaler, BLOCK_SLOT_ID, SIGNER_SLOTS_PER_USER,
|
||||
};
|
||||
pub use crate::runloop::{RunningSigner, Signer, SignerRunLoop};
|
||||
pub use crate::session::{SignerSession, StackerDBSession};
|
||||
|
||||
@@ -22,13 +22,16 @@ use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
use std::time::Duration;
|
||||
use std::{mem, thread};
|
||||
|
||||
use blockstack_lib::chainstate::stacks::boot::SIGNERS_NAME;
|
||||
use blockstack_lib::chainstate::stacks::events::StackerDBChunksEvent;
|
||||
use blockstack_lib::util_lib::boot::boot_code_id;
|
||||
use clarity::vm::types::QualifiedContractIdentifier;
|
||||
use libstackerdb::StackerDBChunkData;
|
||||
use stacks_common::util::secp256k1::Secp256k1PrivateKey;
|
||||
use stacks_common::util::sleep_ms;
|
||||
use wsts::net::{DkgBegin, Packet};
|
||||
|
||||
use crate::events::SignerEvent;
|
||||
use crate::events::{SignerEvent, SignerMessage};
|
||||
use crate::{Signer, SignerEventReceiver, SignerRunLoop};
|
||||
|
||||
/// Simple runloop implementation. It receives `max_events` events and returns `events` from the
|
||||
@@ -87,28 +90,27 @@ impl SignerRunLoop<Vec<SignerEvent>, Command> for SimpleRunLoop {
|
||||
/// and the signer runloop.
|
||||
#[test]
|
||||
fn test_simple_signer() {
|
||||
let ev = SignerEventReceiver::new(vec![QualifiedContractIdentifier::parse(
|
||||
"ST2DS4MSWSGJ3W9FBC6BVT0Y92S345HY8N3T6AV7R.hello-world",
|
||||
)
|
||||
.unwrap()]);
|
||||
let contract_id =
|
||||
QualifiedContractIdentifier::parse("ST2DS4MSWSGJ3W9FBC6BVT0Y92S345HY8N3T6AV7R.signers")
|
||||
.unwrap(); // TODO: change to boot_code_id(SIGNERS_NAME, false) when .signers is deployed
|
||||
let ev = SignerEventReceiver::new(vec![contract_id.clone()], false);
|
||||
let (_cmd_send, cmd_recv) = channel();
|
||||
let (res_send, _res_recv) = channel();
|
||||
let mut signer = Signer::new(SimpleRunLoop::new(5), ev, cmd_recv, res_send);
|
||||
let endpoint: SocketAddr = "127.0.0.1:30000".parse().unwrap();
|
||||
|
||||
let mut chunks = vec![];
|
||||
for i in 0..5 {
|
||||
let privk = Secp256k1PrivateKey::new();
|
||||
let mut chunk = StackerDBChunkData::new(i as u32, 1, "hello world".as_bytes().to_vec());
|
||||
let msg = wsts::net::Message::DkgBegin(DkgBegin { dkg_id: 0 });
|
||||
let message = SignerMessage::Packet(Packet { msg, sig: vec![] });
|
||||
let message_bytes = bincode::serialize(&message).unwrap();
|
||||
let mut chunk = StackerDBChunkData::new(i as u32, 1, message_bytes);
|
||||
chunk.sign(&privk).unwrap();
|
||||
|
||||
let chunk_event = SignerEvent::StackerDB(StackerDBChunksEvent {
|
||||
contract_id: QualifiedContractIdentifier::parse(
|
||||
"ST2DS4MSWSGJ3W9FBC6BVT0Y92S345HY8N3T6AV7R.hello-world",
|
||||
)
|
||||
.unwrap(),
|
||||
let chunk_event = StackerDBChunksEvent {
|
||||
contract_id: contract_id.clone(),
|
||||
modified_slots: vec![chunk],
|
||||
});
|
||||
};
|
||||
chunks.push(chunk_event);
|
||||
}
|
||||
|
||||
@@ -126,42 +128,38 @@ fn test_simple_signer() {
|
||||
}
|
||||
};
|
||||
|
||||
match &thread_chunks[num_sent] {
|
||||
SignerEvent::StackerDB(ev) => {
|
||||
let body = serde_json::to_string(ev).unwrap();
|
||||
let req = format!("POST /stackerdb_chunks HTTP/1.0\r\nConnection: close\r\nContent-Length: {}\r\n\r\n{}", &body.len(), body);
|
||||
debug!("Send:\n{}", &req);
|
||||
let ev = &thread_chunks[num_sent];
|
||||
let body = serde_json::to_string(ev).unwrap();
|
||||
let req = format!("POST /stackerdb_chunks HTTP/1.0\r\nConnection: close\r\nContent-Length: {}\r\n\r\n{}", &body.len(), body);
|
||||
debug!("Send:\n{}", &req);
|
||||
|
||||
sock.write_all(req.as_bytes()).unwrap();
|
||||
sock.flush().unwrap();
|
||||
sock.write_all(req.as_bytes()).unwrap();
|
||||
sock.flush().unwrap();
|
||||
|
||||
num_sent += 1;
|
||||
}
|
||||
_ => panic!("Unexpected event type"),
|
||||
}
|
||||
num_sent += 1;
|
||||
}
|
||||
});
|
||||
|
||||
let running_signer = signer.spawn(endpoint).unwrap();
|
||||
sleep_ms(5000);
|
||||
let mut accepted_events = running_signer.stop().unwrap();
|
||||
let accepted_events = running_signer.stop().unwrap();
|
||||
|
||||
chunks.sort_by(|ev1, ev2| match (ev1, ev2) {
|
||||
(SignerEvent::StackerDB(ev1), SignerEvent::StackerDB(ev2)) => ev1.modified_slots[0]
|
||||
chunks.sort_by(|ev1, ev2| {
|
||||
ev1.modified_slots[0]
|
||||
.slot_id
|
||||
.partial_cmp(&ev2.modified_slots[0].slot_id)
|
||||
.unwrap(),
|
||||
_ => panic!("Unexpected event type"),
|
||||
});
|
||||
accepted_events.sort_by(|ev1, ev2| match (ev1, ev2) {
|
||||
(SignerEvent::StackerDB(ev1), SignerEvent::StackerDB(ev2)) => ev1.modified_slots[0]
|
||||
.slot_id
|
||||
.partial_cmp(&ev2.modified_slots[0].slot_id)
|
||||
.unwrap(),
|
||||
_ => panic!("Unexpected event type"),
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
// runloop got the event that the mocked stacks node sent
|
||||
assert_eq!(accepted_events, chunks);
|
||||
let sent_events: Vec<SignerEvent> = chunks
|
||||
.iter()
|
||||
.map(|chunk| {
|
||||
let msg = chunk.modified_slots[0].data.clone();
|
||||
let signer_message: SignerMessage = bincode::deserialize(&msg).unwrap();
|
||||
SignerEvent::SignerMessages(vec![signer_message])
|
||||
})
|
||||
.collect();
|
||||
|
||||
assert_eq!(sent_events, accepted_events);
|
||||
mock_stacks_node.join().unwrap();
|
||||
}
|
||||
|
||||
@@ -13,161 +13,18 @@
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
use blockstack_lib::chainstate::nakamoto::NakamotoBlock;
|
||||
use blockstack_lib::net::api::postblock_proposal::{BlockValidateReject, ValidateRejectCode};
|
||||
use clarity::vm::types::QualifiedContractIdentifier;
|
||||
use hashbrown::HashMap;
|
||||
use libsigner::{SignerSession, StackerDBSession};
|
||||
use libsigner::{SignerMessage, SignerSession, StackerDBSession};
|
||||
use libstackerdb::{StackerDBChunkAckData, StackerDBChunkData};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use slog::{slog_debug, slog_warn};
|
||||
use stacks_common::types::chainstate::StacksPrivateKey;
|
||||
use stacks_common::{debug, warn};
|
||||
use wsts::net::{Message, Packet};
|
||||
|
||||
use super::ClientError;
|
||||
use crate::client::retry_with_exponential_backoff;
|
||||
use crate::config::Config;
|
||||
|
||||
/// Temporary placeholder for the number of slots allocated to a stacker-db writer. This will be retrieved from the stacker-db instance in the future
|
||||
/// See: https://github.com/stacks-network/stacks-blockchain/issues/3921
|
||||
/// Is equal to the number of message types
|
||||
pub const SIGNER_SLOTS_PER_USER: u32 = 11;
|
||||
|
||||
// The slot IDS for each message type
|
||||
const DKG_BEGIN_SLOT_ID: u32 = 0;
|
||||
const DKG_PRIVATE_BEGIN_SLOT_ID: u32 = 1;
|
||||
const DKG_END_BEGIN_SLOT_ID: u32 = 2;
|
||||
const DKG_END_SLOT_ID: u32 = 3;
|
||||
const DKG_PUBLIC_SHARES_SLOT_ID: u32 = 4;
|
||||
const DKG_PRIVATE_SHARES_SLOT_ID: u32 = 5;
|
||||
const NONCE_REQUEST_SLOT_ID: u32 = 6;
|
||||
const NONCE_RESPONSE_SLOT_ID: u32 = 7;
|
||||
const SIGNATURE_SHARE_REQUEST_SLOT_ID: u32 = 8;
|
||||
const SIGNATURE_SHARE_RESPONSE_SLOT_ID: u32 = 9;
|
||||
const BLOCK_SLOT_ID: u32 = 10;
|
||||
|
||||
/// The messages being sent through the stacker db contracts
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum SignerMessage {
|
||||
/// The signed/validated Nakamoto block for miners to observe
|
||||
BlockResponse(BlockResponse),
|
||||
/// DKG and Signing round data for other signers to observe
|
||||
Packet(Packet),
|
||||
}
|
||||
|
||||
/// The response that a signer sends back to observing miners
|
||||
/// either accepting or rejecting a Nakamoto block with the corresponding reason
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum BlockResponse {
|
||||
/// The Nakamoto block was accepted and therefore signed
|
||||
Accepted(NakamotoBlock),
|
||||
/// The Nakamoto block was rejected and therefore not signed
|
||||
Rejected(BlockRejection),
|
||||
}
|
||||
|
||||
/// A rejection response from a signer for a proposed block
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct BlockRejection {
|
||||
/// The reason for the rejection
|
||||
pub reason: String,
|
||||
/// The reason code for the rejection
|
||||
pub reason_code: RejectCode,
|
||||
/// The block that was rejected
|
||||
pub block: NakamotoBlock,
|
||||
}
|
||||
|
||||
impl BlockRejection {
|
||||
/// Create a new BlockRejection for the provided block and reason code
|
||||
pub fn new(block: NakamotoBlock, reason_code: RejectCode) -> Self {
|
||||
Self {
|
||||
reason: reason_code.to_string(),
|
||||
reason_code,
|
||||
block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockValidateReject> for BlockRejection {
|
||||
fn from(reject: BlockValidateReject) -> Self {
|
||||
Self {
|
||||
reason: reject.reason,
|
||||
reason_code: RejectCode::ValidationFailed(reject.reason_code),
|
||||
block: reject.block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This enum is used to supply a `reason_code` for block rejections
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[repr(u8)]
|
||||
pub enum RejectCode {
|
||||
/// RPC endpoint Validation failed
|
||||
ValidationFailed(ValidateRejectCode),
|
||||
/// Signers signed a block rejection
|
||||
SignedRejection,
|
||||
/// Invalid signature hash
|
||||
InvalidSignatureHash,
|
||||
}
|
||||
|
||||
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::InvalidSignatureHash => write!(f, "The signature hash was invalid."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Packet> for SignerMessage {
|
||||
fn from(packet: Packet) -> Self {
|
||||
Self::Packet(packet)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockResponse> for SignerMessage {
|
||||
fn from(block_response: BlockResponse) -> Self {
|
||||
Self::BlockResponse(block_response)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockRejection> for SignerMessage {
|
||||
fn from(block_rejection: BlockRejection) -> Self {
|
||||
Self::BlockResponse(BlockResponse::Rejected(block_rejection))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BlockValidateReject> for SignerMessage {
|
||||
fn from(rejection: BlockValidateReject) -> Self {
|
||||
Self::BlockResponse(BlockResponse::Rejected(rejection.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl SignerMessage {
|
||||
/// Helper function to determine the slot ID for the provided stacker-db writer id
|
||||
pub fn slot_id(&self, id: u32) -> u32 {
|
||||
let slot_id = match self {
|
||||
Self::Packet(packet) => match packet.msg {
|
||||
Message::DkgBegin(_) => DKG_BEGIN_SLOT_ID,
|
||||
Message::DkgPrivateBegin(_) => DKG_PRIVATE_BEGIN_SLOT_ID,
|
||||
Message::DkgEndBegin(_) => DKG_END_BEGIN_SLOT_ID,
|
||||
Message::DkgEnd(_) => DKG_END_SLOT_ID,
|
||||
Message::DkgPublicShares(_) => DKG_PUBLIC_SHARES_SLOT_ID,
|
||||
Message::DkgPrivateShares(_) => DKG_PRIVATE_SHARES_SLOT_ID,
|
||||
Message::NonceRequest(_) => NONCE_REQUEST_SLOT_ID,
|
||||
Message::NonceResponse(_) => NONCE_RESPONSE_SLOT_ID,
|
||||
Message::SignatureShareRequest(_) => SIGNATURE_SHARE_REQUEST_SLOT_ID,
|
||||
Message::SignatureShareResponse(_) => SIGNATURE_SHARE_RESPONSE_SLOT_ID,
|
||||
},
|
||||
Self::BlockResponse(_) => BLOCK_SLOT_ID,
|
||||
};
|
||||
SIGNER_SLOTS_PER_USER * id + slot_id
|
||||
}
|
||||
}
|
||||
|
||||
/// The StackerDB client for communicating with the .signers contract
|
||||
pub struct StackerDB {
|
||||
/// The stacker-db session for the signer StackerDB
|
||||
|
||||
@@ -91,6 +91,14 @@ impl Network {
|
||||
Self::Testnet | Self::Mocknet => TransactionVersion::Testnet,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the network is Mainnet or not
|
||||
pub fn is_mainnet(&self) -> bool {
|
||||
match self {
|
||||
Self::Mainnet => true,
|
||||
Self::Testnet | Self::Mocknet => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The parsed configuration for the signer
|
||||
|
||||
@@ -36,7 +36,10 @@ use std::time::Duration;
|
||||
use blockstack_lib::chainstate::nakamoto::NakamotoBlock;
|
||||
use clap::Parser;
|
||||
use clarity::vm::types::QualifiedContractIdentifier;
|
||||
use libsigner::{RunningSigner, Signer, SignerEventReceiver, SignerSession, StackerDBSession};
|
||||
use libsigner::{
|
||||
RunningSigner, Signer, SignerEventReceiver, SignerSession, StackerDBSession,
|
||||
SIGNER_SLOTS_PER_USER,
|
||||
};
|
||||
use libstackerdb::StackerDBChunkData;
|
||||
use slog::{slog_debug, slog_error};
|
||||
use stacks_common::address::{
|
||||
@@ -49,7 +52,6 @@ use stacks_signer::cli::{
|
||||
Cli, Command, GenerateFilesArgs, GetChunkArgs, GetLatestChunkArgs, PutChunkArgs, RunDkgArgs,
|
||||
SignArgs, StackerDBArgs,
|
||||
};
|
||||
use stacks_signer::client::SIGNER_SLOTS_PER_USER;
|
||||
use stacks_signer::config::{Config, Network};
|
||||
use stacks_signer::runloop::{RunLoop, RunLoopCommand};
|
||||
use stacks_signer::utils::{build_signer_config_tomls, build_stackerdb_contract};
|
||||
@@ -90,7 +92,10 @@ fn spawn_running_signer(path: &PathBuf) -> SpawnedSigner {
|
||||
let config = Config::try_from(path).unwrap();
|
||||
let (cmd_send, cmd_recv) = channel();
|
||||
let (res_send, res_recv) = channel();
|
||||
let ev = SignerEventReceiver::new(vec![config.stackerdb_contract_id.clone()]);
|
||||
let ev = SignerEventReceiver::new(
|
||||
vec![config.stackerdb_contract_id.clone()],
|
||||
config.network.is_mainnet(),
|
||||
);
|
||||
let runloop: RunLoop<FireCoordinator<v2::Aggregator>> = RunLoop::from(&config);
|
||||
let mut signer: Signer<
|
||||
RunLoopCommand,
|
||||
|
||||
@@ -19,14 +19,12 @@ use std::time::Duration;
|
||||
|
||||
use blockstack_lib::burnchains::Txid;
|
||||
use blockstack_lib::chainstate::nakamoto::NakamotoBlock;
|
||||
use blockstack_lib::chainstate::stacks::boot::MINERS_NAME;
|
||||
use blockstack_lib::chainstate::stacks::events::StackerDBChunksEvent;
|
||||
use blockstack_lib::chainstate::stacks::ThresholdSignature;
|
||||
use blockstack_lib::net::api::postblock_proposal::BlockValidateResponse;
|
||||
use blockstack_lib::util_lib::boot::boot_code_id;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use libsigner::{SignerEvent, SignerRunLoop};
|
||||
use libstackerdb::StackerDBChunkData;
|
||||
use libsigner::{
|
||||
BlockRejection, BlockResponse, RejectCode, SignerEvent, SignerMessage, SignerRunLoop,
|
||||
};
|
||||
use slog::{slog_debug, slog_error, slog_info, slog_warn};
|
||||
use stacks_common::codec::{read_next, StacksMessageCodec};
|
||||
use stacks_common::util::hash::{Sha256Sum, Sha512Trunc256Sum};
|
||||
@@ -41,10 +39,7 @@ use wsts::state_machine::signer::Signer;
|
||||
use wsts::state_machine::{OperationResult, PublicKeys};
|
||||
use wsts::v2;
|
||||
|
||||
use crate::client::{
|
||||
retry_with_exponential_backoff, BlockRejection, BlockResponse, ClientError, RejectCode,
|
||||
SignerMessage, StackerDB, StacksClient,
|
||||
};
|
||||
use crate::client::{retry_with_exponential_backoff, ClientError, StackerDB, StacksClient};
|
||||
use crate::config::{Config, Network};
|
||||
|
||||
/// Which operation to perform
|
||||
@@ -328,40 +323,31 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle the stackerdb chunk event as a signer message
|
||||
fn handle_stackerdb_chunk_event_signers(
|
||||
/// Handle signer messages submitted to signers stackerdb
|
||||
fn handle_signer_messages(
|
||||
&mut self,
|
||||
stackerdb_chunk_event: StackerDBChunksEvent,
|
||||
res: Sender<Vec<OperationResult>>,
|
||||
messages: Vec<SignerMessage>,
|
||||
) {
|
||||
let (_coordinator_id, coordinator_public_key) =
|
||||
calculate_coordinator(&self.signing_round.public_keys, &self.stacks_client);
|
||||
|
||||
let inbound_packets: Vec<Packet> = stackerdb_chunk_event
|
||||
.modified_slots
|
||||
.iter()
|
||||
.filter_map(|chunk| self.verify_chunk(chunk, &coordinator_public_key))
|
||||
let packets: Vec<Packet> = messages
|
||||
.into_iter()
|
||||
.filter_map(|msg| match msg {
|
||||
SignerMessage::BlockResponse(_) => None,
|
||||
SignerMessage::Packet(packet) => {
|
||||
self.verify_packet(packet, &coordinator_public_key)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
self.handle_packets(res, &inbound_packets);
|
||||
self.handle_packets(res, &packets);
|
||||
}
|
||||
|
||||
/// Handle the stackerdb chunk event as a miner message
|
||||
fn handle_stackerdb_chunk_event_miners(&mut self, stackerdb_chunk_event: StackerDBChunksEvent) {
|
||||
for chunk in &stackerdb_chunk_event.modified_slots {
|
||||
let Some(block) = read_next::<NakamotoBlock, _>(&mut &chunk.data[..]).ok() else {
|
||||
warn!("Received an unrecognized message type from .miners stacker-db slot id {}: {:?}", chunk.slot_id, chunk.data);
|
||||
continue;
|
||||
};
|
||||
/// 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.signature_hash() else {
|
||||
warn!("Received a block proposal with an invalid signature hash. Broadcasting a block rejection...");
|
||||
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);
|
||||
}
|
||||
self.broadcast_signature_hash_rejection(block);
|
||||
continue;
|
||||
};
|
||||
// Store the block in our cache
|
||||
@@ -517,17 +503,12 @@ impl<C: Coordinator> RunLoop<C> {
|
||||
/// and SignatureShareRequests with a different message than what the coordinator originally sent.
|
||||
/// This is done to prevent a malicious coordinator from sending a different message than what was
|
||||
/// agreed upon and to support the case where the signer wishes to reject a block by voting no
|
||||
fn verify_chunk(
|
||||
fn verify_packet(
|
||||
&mut self,
|
||||
chunk: &StackerDBChunkData,
|
||||
mut packet: Packet,
|
||||
coordinator_public_key: &PublicKey,
|
||||
) -> Option<Packet> {
|
||||
// We only care about verified wsts packets. Ignore anything else
|
||||
let signer_message = bincode::deserialize::<SignerMessage>(&chunk.data).ok()?;
|
||||
let mut packet = match signer_message {
|
||||
SignerMessage::Packet(packet) => packet,
|
||||
_ => return None, // This is a message for miners to observe. Ignore it.
|
||||
};
|
||||
// We only care about verified wsts packets. Ignore anything else.
|
||||
if packet.verify(&self.signing_round.public_keys, coordinator_public_key) {
|
||||
match &mut packet.msg {
|
||||
Message::SignatureShareRequest(request) => {
|
||||
@@ -764,26 +745,17 @@ impl<C: Coordinator> SignerRunLoop<Vec<OperationResult>, RunLoopCommand> for Run
|
||||
// Process any arrived events
|
||||
debug!("Processing event: {:?}", event);
|
||||
match event {
|
||||
Some(SignerEvent::BlockProposal(block_validate_response)) => {
|
||||
Some(SignerEvent::BlockValidationResponse(block_validate_response)) => {
|
||||
debug!("Received a block proposal result from the stacks node...");
|
||||
self.handle_block_validate_response(block_validate_response, res)
|
||||
}
|
||||
Some(SignerEvent::StackerDB(stackerdb_chunk_event)) => {
|
||||
if stackerdb_chunk_event.contract_id == *self.stackerdb.signers_contract_id() {
|
||||
debug!("Received a StackerDB event for the .signers contract...");
|
||||
self.handle_stackerdb_chunk_event_signers(stackerdb_chunk_event, res);
|
||||
} else if stackerdb_chunk_event.contract_id
|
||||
== boot_code_id(MINERS_NAME, self.mainnet)
|
||||
{
|
||||
debug!("Received a StackerDB event for the .miners contract...");
|
||||
self.handle_stackerdb_chunk_event_miners(stackerdb_chunk_event);
|
||||
} else {
|
||||
// Ignore non miner or signer messages
|
||||
debug!(
|
||||
"Received a StackerDB event for an unrecognized contract id: {:?}. Ignoring...",
|
||||
stackerdb_chunk_event.contract_id
|
||||
);
|
||||
}
|
||||
Some(SignerEvent::SignerMessages(messages)) => {
|
||||
debug!("Received messages from the other signers...");
|
||||
self.handle_signer_messages(res, messages);
|
||||
}
|
||||
Some(SignerEvent::ProposedBlocks(blocks)) => {
|
||||
debug!("Received block proposals from the miners...");
|
||||
self.handle_proposed_blocks(blocks);
|
||||
}
|
||||
None => {
|
||||
// No event. Do nothing.
|
||||
|
||||
@@ -88,6 +88,7 @@ pub const BOOT_TEST_POX_4_AGG_KEY_CONTRACT: &'static str = "pox-4-agg-test-boote
|
||||
pub const BOOT_TEST_POX_4_AGG_KEY_FNAME: &'static str = "aggregate-key";
|
||||
|
||||
pub const MINERS_NAME: &'static str = "miners";
|
||||
pub const SIGNERS_NAME: &'static str = "signers";
|
||||
|
||||
pub mod docs;
|
||||
|
||||
|
||||
@@ -6,20 +6,21 @@ use std::time::{Duration, Instant};
|
||||
use std::{env, thread};
|
||||
|
||||
use clarity::vm::types::QualifiedContractIdentifier;
|
||||
use libsigner::{RunningSigner, Signer, SignerEventReceiver};
|
||||
use libsigner::{
|
||||
BlockResponse, RunningSigner, Signer, SignerEventReceiver, SignerMessage, BLOCK_SLOT_ID,
|
||||
SIGNER_SLOTS_PER_USER,
|
||||
};
|
||||
use stacks::chainstate::coordinator::comm::CoordinatorChannels;
|
||||
use stacks::chainstate::nakamoto::{NakamotoBlock, NakamotoBlockHeader};
|
||||
use stacks::chainstate::stacks::boot::MINERS_NAME;
|
||||
use stacks::chainstate::stacks::{StacksPrivateKey, ThresholdSignature};
|
||||
use stacks::net::api::postblock_proposal::BlockValidateResponse;
|
||||
use stacks::util_lib::boot::boot_code_id;
|
||||
use stacks_common::types::chainstate::{
|
||||
ConsensusHash, StacksAddress, StacksBlockId, StacksPublicKey, TrieHash,
|
||||
};
|
||||
use stacks_common::util::hash::{MerkleTree, Sha512Trunc256Sum};
|
||||
use stacks_common::util::secp256k1::MessageSignature;
|
||||
use stacks_signer::client::{BlockResponse, SignerMessage, StacksClient, SIGNER_SLOTS_PER_USER};
|
||||
use stacks_signer::config::{Config as SignerConfig, Network};
|
||||
use stacks_signer::client::StacksClient;
|
||||
use stacks_signer::config::Config as SignerConfig;
|
||||
use stacks_signer::runloop::{calculate_coordinator, RunLoopCommand};
|
||||
use stacks_signer::utils::{build_signer_config_tomls, build_stackerdb_contract};
|
||||
use tracing_subscriber::prelude::*;
|
||||
@@ -63,7 +64,7 @@ struct SignerTest {
|
||||
// The channel for sending commands to the coordinator
|
||||
pub coordinator_cmd_sender: Sender<RunLoopCommand>,
|
||||
// The channels for sending commands to the signers
|
||||
pub signer_cmd_senders: HashMap<u32, Sender<RunLoopCommand>>,
|
||||
pub _signer_cmd_senders: HashMap<u32, Sender<RunLoopCommand>>,
|
||||
// The channels for receiving results from both the coordinator and the signers
|
||||
pub result_receivers: Vec<Receiver<Vec<OperationResult>>>,
|
||||
// The running coordinator and its threads
|
||||
@@ -152,7 +153,7 @@ impl SignerTest {
|
||||
Self {
|
||||
running_nodes: node,
|
||||
result_receivers,
|
||||
signer_cmd_senders,
|
||||
_signer_cmd_senders: signer_cmd_senders,
|
||||
coordinator_cmd_sender,
|
||||
running_coordinator,
|
||||
running_signers,
|
||||
@@ -186,10 +187,8 @@ fn spawn_signer(
|
||||
sender: Sender<Vec<OperationResult>>,
|
||||
) -> RunningSigner<SignerEventReceiver, Vec<OperationResult>> {
|
||||
let config = stacks_signer::config::Config::load_from_str(data).unwrap();
|
||||
let ev = SignerEventReceiver::new(vec![
|
||||
boot_code_id(MINERS_NAME, config.network == Network::Mainnet),
|
||||
config.stackerdb_contract_id.clone(),
|
||||
]);
|
||||
let is_mainnet = config.network.is_mainnet();
|
||||
let ev = SignerEventReceiver::new(vec![config.stackerdb_contract_id.clone()], is_mainnet);
|
||||
let runloop: stacks_signer::runloop::RunLoop<FireCoordinator<v2::Aggregator>> =
|
||||
stacks_signer::runloop::RunLoop::from(&config);
|
||||
let mut signer: Signer<
|
||||
@@ -666,7 +665,7 @@ fn stackerdb_block_proposal() {
|
||||
for event in nakamoto_blocks {
|
||||
// The tenth slot is the miners block slot
|
||||
for slot in event.modified_slots {
|
||||
if slot.slot_id == 10 {
|
||||
if slot.slot_id == BLOCK_SLOT_ID {
|
||||
chunk = Some(slot.data);
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user