Skip to content

Commit 756e5a5

Browse files
committed
Do not pause block broadcast until certain all signers have processed the last block pushed message
Signed-off-by: Jacinta Ferrant <jacinta.ferrant@gmail.com>
1 parent 1c9c412 commit 756e5a5

File tree

5 files changed

+57
-2
lines changed

5 files changed

+57
-2
lines changed

stacks-signer/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ use chainstate::SortitionsView;
5353
use config::GlobalConfig;
5454
use libsigner::{SignerEvent, SignerEventReceiver, SignerEventTrait, VERSION_STRING};
5555
use runloop::SignerResult;
56+
use signerdb::BlockInfo;
5657
use stacks_common::{info, warn};
5758
use v0::signer_state::LocalStateMachine;
5859

@@ -81,6 +82,8 @@ pub trait Signer<T: SignerEventTrait>: Debug + Display {
8182
fn get_local_state_machine(&self) -> &LocalStateMachine;
8283
/// Get the number of pending block proposals
8384
fn get_pending_proposals_count(&self) -> u64;
85+
/// Get canonical block according to this signer's db
86+
fn get_canonical_tip(&self) -> Option<BlockInfo>;
8487
}
8588

8689
/// A wrapper around the running signer type for the signer

stacks-signer/src/runloop.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use stacks_common::{debug, error, info, warn};
2525
use crate::chainstate::SortitionsView;
2626
use crate::client::{retry_with_exponential_backoff, ClientError, StacksClient};
2727
use crate::config::{GlobalConfig, SignerConfig, SignerConfigMode};
28+
use crate::signerdb::BlockInfo;
2829
use crate::v0::signer_state::LocalStateMachine;
2930
#[cfg(any(test, feature = "testing"))]
3031
use crate::v0::tests::TEST_SKIP_SIGNER_CLEANUP;
@@ -59,6 +60,9 @@ pub struct StateInfo {
5960
pub signer_state_machines: Vec<(u64, Option<LocalStateMachine>)>,
6061
/// The number of pending block proposals for this signer
6162
pub pending_proposals_count: u64,
63+
/// The canonical tip block info according to the running signers
64+
/// as a pair of (reward-cycle, block-info)
65+
pub signer_canonical_tips: Vec<(u64, Option<BlockInfo>)>,
6266
}
6367

6468
/// The signer result that can be sent across threads
@@ -544,6 +548,16 @@ impl<Signer: SignerTrait<T>, T: StacksMessageCodec + Clone + Send + Debug>
544548
}
545549
})
546550
.unwrap_or(0),
551+
signer_canonical_tips: self
552+
.stacks_signers
553+
.iter()
554+
.map(|(reward_cycle, signer)| {
555+
let ConfiguredSigner::RegisteredSigner(ref signer) = signer else {
556+
return (*reward_cycle, None);
557+
};
558+
(*reward_cycle, signer.get_canonical_tip())
559+
})
560+
.collect(),
547561
};
548562
info!("Signer status check requested: {state_info:?}");
549563

stacks-signer/src/signerdb.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ impl FromRow<BurnBlockInfo> for BurnBlockInfo {
9898
}
9999
}
100100

101-
#[derive(Serialize, Deserialize, Debug, PartialEq, Default)]
101+
#[derive(Serialize, Deserialize, Debug, PartialEq, Default, Clone)]
102102
/// Store extra version-specific info in `BlockInfo`
103103
pub enum ExtraBlockInfo {
104104
#[default]
@@ -167,7 +167,7 @@ impl TryFrom<&str> for BlockState {
167167
}
168168

169169
/// Additional Info about a proposed block
170-
#[derive(Serialize, Deserialize, Debug, PartialEq)]
170+
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
171171
pub struct BlockInfo {
172172
/// The block we are considering
173173
pub block: NakamotoBlock,

stacks-signer/src/v0/signer.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,14 @@ impl SignerTrait<SignerMessage> for Signer {
336336
.map(|results| u64::try_from(results.len()).unwrap())
337337
.unwrap_or(0)
338338
}
339+
340+
fn get_canonical_tip(&self) -> Option<BlockInfo> {
341+
self.signer_db
342+
.get_canonical_tip()
343+
.inspect_err(|e| error!("{self}: Failed to check for canonical tip: {e:?}"))
344+
.ok()
345+
.flatten()
346+
}
339347
}
340348

341349
impl Signer {

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7344,6 +7344,36 @@ fn miner_recovers_when_broadcast_block_delay_across_tenures_occurs() {
73447344
// Clear the stackerdb chunks
73457345
info!("Forcing miner to ignore block responses for block N+1");
73467346
TEST_IGNORE_SIGNERS.set(true);
7347+
7348+
info!("------------------------- Wait for All Signers to Update their Canonical Tip to Block N -------------------------");
7349+
let current_rc = signer_test.get_current_reward_cycle();
7350+
let expected_tip = block_n.header.signer_signature_hash();
7351+
wait_for(30, || {
7352+
let states = signer_test.get_all_states();
7353+
let canonical_tips = states
7354+
.iter()
7355+
.filter(|state| {
7356+
state
7357+
.signer_canonical_tips
7358+
.iter()
7359+
.find_map(|(rc, block_info_opt)| {
7360+
if current_rc % 2 == *rc {
7361+
block_info_opt.as_ref()
7362+
} else {
7363+
None
7364+
}
7365+
})
7366+
.map(|block_info| {
7367+
block_info.block.header.signer_signature_hash() == expected_tip
7368+
})
7369+
.unwrap_or(false)
7370+
})
7371+
.count();
7372+
7373+
Ok(canonical_tips == num_signers)
7374+
})
7375+
.expect("Timed out waiting for all signers to update their global state to Block N");
7376+
73477377
info!("Delaying signer block N+1 broadcasting to the miner");
73487378
TEST_PAUSE_BLOCK_BROADCAST.set(true);
73497379
test_observer::clear();

0 commit comments

Comments
 (0)