Skip to content

Commit 0e9cf5d

Browse files
authored
Merge pull request #4549 from stacks-network/feat/signers-subscribe-to-burn-blocks
Feat/signers subscribe to burn blocks
2 parents 3a94eb3 + 48bbbd5 commit 0e9cf5d

File tree

8 files changed

+339
-177
lines changed

8 files changed

+339
-177
lines changed

libsigner/src/events.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use blockstack_lib::util_lib::boot::boot_code_id;
3131
use clarity::vm::types::serialization::SerializationError;
3232
use clarity::vm::types::QualifiedContractIdentifier;
3333
use serde::{Deserialize, Serialize};
34+
use serde_json::Value;
3435
use stacks_common::codec::{
3536
read_next, read_next_at_most, read_next_exact, write_next, Error as CodecError,
3637
StacksMessageCodec,
@@ -73,6 +74,8 @@ pub enum SignerEvent {
7374
BlockValidationResponse(BlockValidateResponse),
7475
/// Status endpoint request
7576
StatusCheck,
77+
/// A new burn block event was received with the given burnchain block height
78+
NewBurnBlock(u64),
7679
}
7780

7881
impl StacksMessageCodec for BlockProposalSigners {
@@ -281,6 +284,8 @@ impl EventReceiver for SignerEventReceiver {
281284
process_stackerdb_event(event_receiver.local_addr, request, is_mainnet)
282285
} else if request.url() == "/proposal_response" {
283286
process_proposal_response(request)
287+
} else if request.url() == "/new_burn_block" {
288+
process_new_burn_block_event(request)
284289
} else {
285290
let url = request.url().to_string();
286291

@@ -438,6 +443,38 @@ fn process_proposal_response(mut request: HttpRequest) -> Result<SignerEvent, Ev
438443
Ok(SignerEvent::BlockValidationResponse(event))
439444
}
440445

446+
/// Process a new burn block event from the node
447+
fn process_new_burn_block_event(mut request: HttpRequest) -> Result<SignerEvent, EventError> {
448+
debug!("Got burn_block event");
449+
let mut body = String::new();
450+
if let Err(e) = request.as_reader().read_to_string(&mut body) {
451+
error!("Failed to read body: {:?}", &e);
452+
453+
if let Err(e) = request.respond(HttpResponse::empty(200u16)) {
454+
error!("Failed to respond to request: {:?}", &e);
455+
}
456+
return Err(EventError::MalformedRequest(format!(
457+
"Failed to read body: {:?}",
458+
&e
459+
)));
460+
}
461+
#[derive(Debug, Deserialize)]
462+
struct TempBurnBlockEvent {
463+
burn_block_hash: String,
464+
burn_block_height: u64,
465+
reward_recipients: Vec<serde_json::Value>,
466+
reward_slot_holders: Vec<String>,
467+
burn_amount: u64,
468+
}
469+
let temp: TempBurnBlockEvent = serde_json::from_slice(body.as_bytes())
470+
.map_err(|e| EventError::Deserialize(format!("Could not decode body to JSON: {:?}", &e)))?;
471+
let event = SignerEvent::NewBurnBlock(temp.burn_block_height);
472+
if let Err(e) = request.respond(HttpResponse::empty(200u16)) {
473+
error!("Failed to respond to request: {:?}", &e);
474+
}
475+
Ok(event)
476+
}
477+
441478
fn get_signers_db_signer_set_message_id(name: &str) -> Option<(u32, u32)> {
442479
// Splitting the string by '-'
443480
let parts: Vec<&str> = name.split('-').collect();

stacks-signer/src/client/mod.rs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ use std::time::Duration;
2323

2424
use clarity::vm::errors::Error as ClarityError;
2525
use clarity::vm::types::serialization::SerializationError;
26-
use libsigner::RPCError;
2726
use libstackerdb::Error as StackerDBError;
2827
use slog::slog_debug;
2928
pub use stackerdb::*;
@@ -48,9 +47,6 @@ pub enum ClientError {
4847
/// Failed to sign stacker-db chunk
4948
#[error("Failed to sign stacker-db chunk: {0}")]
5049
FailToSign(#[from] StackerDBError),
51-
/// Failed to write to stacker-db due to RPC error
52-
#[error("Failed to write to stacker-db instance: {0}")]
53-
PutChunkFailed(#[from] RPCError),
5450
/// Stacker-db instance rejected the chunk
5551
#[error("Stacker-db rejected the chunk. Reason: {0}")]
5652
PutChunkRejected(String),
@@ -72,33 +68,18 @@ pub enum ClientError {
7268
/// Failed to parse a Clarity value
7369
#[error("Received a malformed clarity value: {0}")]
7470
MalformedClarityValue(String),
75-
/// Invalid Clarity Name
76-
#[error("Invalid Clarity Name: {0}")]
77-
InvalidClarityName(String),
7871
/// Backoff retry timeout
7972
#[error("Backoff retry timeout occurred. Stacks node may be down.")]
8073
RetryTimeout,
8174
/// Not connected
8275
#[error("Not connected")]
8376
NotConnected,
84-
/// Invalid signing key
85-
#[error("Signing key not represented in the list of signers")]
86-
InvalidSigningKey,
8777
/// Clarity interpreter error
8878
#[error("Clarity interpreter error: {0}")]
8979
ClarityError(#[from] ClarityError),
90-
/// Our stacks address does not belong to a registered signer
91-
#[error("Our stacks address does not belong to a registered signer")]
92-
NotRegistered,
93-
/// Reward set not yet calculated for the given reward cycle
94-
#[error("Reward set not yet calculated for reward cycle: {0}")]
95-
RewardSetNotYetCalculated(u64),
9680
/// Malformed reward set
9781
#[error("Malformed contract data: {0}")]
9882
MalformedContractData(String),
99-
/// No reward set exists for the given reward cycle
100-
#[error("No reward set exists for reward cycle {0}")]
101-
NoRewardSet(u64),
10283
/// Stacks node does not support a feature we need
10384
#[error("Stacks node does not support a required feature: {0}")]
10485
UnsupportedStacksFeature(String),

stacks-signer/src/client/stackerdb.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ impl StackerDB {
169169
warn!("Failed to send message to stackerdb due to wrong version number. Attempted {}. Expected {}. Retrying...", slot_version, slot_metadata.slot_version);
170170
slot_version = slot_metadata.slot_version;
171171
} else {
172-
warn!("Failed to send message to stackerdb due to wrong version number. Attempted {}. Expected unkown version number. Incrementing and retrying...", slot_version);
172+
warn!("Failed to send message to stackerdb due to wrong version number. Attempted {}. Expected unknown version number. Incrementing and retrying...", slot_version);
173173
}
174174
if let Some(versions) = self.slot_versions.get_mut(&msg_id) {
175175
// NOTE: per the above, this is always executed

stacks-signer/src/client/stacks_client.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use wsts::curve::point::{Compressed, Point};
4646

4747
use crate::client::{retry_with_exponential_backoff, ClientError};
4848
use crate::config::GlobalConfig;
49+
use crate::runloop::RewardCycleInfo;
4950

5051
/// The Stacks signer client used to communicate with the stacks node
5152
#[derive(Clone, Debug)]
@@ -363,16 +364,23 @@ impl StacksClient {
363364
Ok(peer_info.burn_block_height)
364365
}
365366

366-
/// Get the current reward cycle from the stacks node
367-
pub fn get_current_reward_cycle(&self) -> Result<u64, ClientError> {
367+
/// Get the current reward cycle info from the stacks node
368+
pub fn get_current_reward_cycle_info(&self) -> Result<RewardCycleInfo, ClientError> {
368369
let pox_data = self.get_pox_data()?;
369370
let blocks_mined = pox_data
370371
.current_burnchain_block_height
371372
.saturating_sub(pox_data.first_burnchain_block_height);
372-
let reward_cycle_length = pox_data
373+
let reward_phase_block_length = pox_data
373374
.reward_phase_block_length
374375
.saturating_add(pox_data.prepare_phase_block_length);
375-
Ok(blocks_mined / reward_cycle_length)
376+
let reward_cycle = blocks_mined / reward_phase_block_length;
377+
Ok(RewardCycleInfo {
378+
reward_cycle,
379+
reward_phase_block_length,
380+
prepare_phase_block_length: pox_data.prepare_phase_block_length,
381+
first_burnchain_block_height: pox_data.first_burnchain_block_height,
382+
last_burnchain_block_height: pox_data.current_burnchain_block_height,
383+
})
376384
}
377385

378386
/// Helper function to retrieve the account info from the stacks node for a specific address
@@ -735,23 +743,23 @@ mod tests {
735743
fn valid_reward_cycle_should_succeed() {
736744
let mock = MockServerClient::new();
737745
let (pox_data_response, pox_data) = build_get_pox_data_response(None, None, None, None);
738-
let h = spawn(move || mock.client.get_current_reward_cycle());
746+
let h = spawn(move || mock.client.get_current_reward_cycle_info());
739747
write_response(mock.server, pox_data_response.as_bytes());
740-
let current_cycle_id = h.join().unwrap().unwrap();
748+
let current_cycle_info = h.join().unwrap().unwrap();
741749
let blocks_mined = pox_data
742750
.current_burnchain_block_height
743751
.saturating_sub(pox_data.first_burnchain_block_height);
744752
let reward_cycle_length = pox_data
745753
.reward_phase_block_length
746754
.saturating_add(pox_data.prepare_phase_block_length);
747755
let id = blocks_mined / reward_cycle_length;
748-
assert_eq!(current_cycle_id, id);
756+
assert_eq!(current_cycle_info.reward_cycle, id);
749757
}
750758

751759
#[test]
752760
fn invalid_reward_cycle_should_fail() {
753761
let mock = MockServerClient::new();
754-
let h = spawn(move || mock.client.get_current_reward_cycle());
762+
let h = spawn(move || mock.client.get_current_reward_cycle_info());
755763
write_response(
756764
mock.server,
757765
b"HTTP/1.1 200 Ok\n\n{\"current_cycle\":{\"id\":\"fake id\", \"is_pox_active\":false}}",

0 commit comments

Comments
 (0)