Skip to content

Commit 57848b3

Browse files
committed
Fix block state transitions and update some comments
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent 1855264 commit 57848b3

File tree

3 files changed

+78
-43
lines changed

3 files changed

+78
-43
lines changed

stacks-signer/src/signerdb.rs

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -230,17 +230,9 @@ impl BlockInfo {
230230
}
231231
match state {
232232
BlockState::Unprocessed => false,
233-
BlockState::LocallyAccepted => {
234-
matches!(
235-
prev_state,
236-
BlockState::Unprocessed | BlockState::LocallyAccepted
237-
)
238-
}
239-
BlockState::LocallyRejected => {
240-
matches!(
241-
prev_state,
242-
BlockState::Unprocessed | BlockState::LocallyRejected
243-
)
233+
BlockState::LocallyAccepted | BlockState::LocallyRejected => {
234+
!matches!(prev_state, BlockState::GloballyRejected)
235+
&& !matches!(prev_state, BlockState::GloballyAccepted)
244236
}
245237
BlockState::GloballyAccepted => !matches!(prev_state, BlockState::GloballyRejected),
246238
BlockState::GloballyRejected => !matches!(prev_state, BlockState::GloballyAccepted),
@@ -1245,7 +1237,14 @@ mod tests {
12451237
assert_eq!(block.state, BlockState::LocallyAccepted);
12461238
assert!(!block.check_state(BlockState::Unprocessed));
12471239
assert!(block.check_state(BlockState::LocallyAccepted));
1248-
assert!(!block.check_state(BlockState::LocallyRejected));
1240+
assert!(block.check_state(BlockState::LocallyRejected));
1241+
assert!(block.check_state(BlockState::GloballyAccepted));
1242+
assert!(block.check_state(BlockState::GloballyRejected));
1243+
1244+
block.move_to(BlockState::LocallyRejected).unwrap();
1245+
assert!(!block.check_state(BlockState::Unprocessed));
1246+
assert!(block.check_state(BlockState::LocallyAccepted));
1247+
assert!(block.check_state(BlockState::LocallyRejected));
12491248
assert!(block.check_state(BlockState::GloballyAccepted));
12501249
assert!(block.check_state(BlockState::GloballyRejected));
12511250

@@ -1257,15 +1256,8 @@ mod tests {
12571256
assert!(block.check_state(BlockState::GloballyAccepted));
12581257
assert!(!block.check_state(BlockState::GloballyRejected));
12591258

1260-
// Must manually override as will not be able to move from GloballyAccepted to LocallyAccepted
1261-
block.state = BlockState::LocallyRejected;
1262-
assert!(!block.check_state(BlockState::Unprocessed));
1263-
assert!(!block.check_state(BlockState::LocallyAccepted));
1264-
assert!(block.check_state(BlockState::LocallyRejected));
1265-
assert!(block.check_state(BlockState::GloballyAccepted));
1266-
assert!(block.check_state(BlockState::GloballyRejected));
1267-
1268-
block.move_to(BlockState::GloballyRejected).unwrap();
1259+
// Must manually override as will not be able to move from GloballyAccepted to GloballyRejected
1260+
block.state = BlockState::GloballyRejected;
12691261
assert!(!block.check_state(BlockState::Unprocessed));
12701262
assert!(!block.check_state(BlockState::LocallyAccepted));
12711263
assert!(!block.check_state(BlockState::LocallyRejected));

stacks-signer/src/v0/signer.rs

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ pub static TEST_PAUSE_BLOCK_BROADCAST: std::sync::Mutex<Option<bool>> = std::syn
6464
/// Skip broadcasting the block to the network
6565
pub static TEST_SKIP_BLOCK_BROADCAST: std::sync::Mutex<Option<bool>> = std::sync::Mutex::new(None);
6666

67+
#[cfg(any(test, feature = "testing"))]
68+
/// Skip any block responses from other signers
69+
pub static TEST_IGNORE_BLOCK_RESPONSES: std::sync::Mutex<Option<bool>> =
70+
std::sync::Mutex::new(None);
71+
6772
/// The stacks signer registered for the reward cycle
6873
#[derive(Debug)]
6974
pub struct Signer {
@@ -476,10 +481,7 @@ impl Signer {
476481
self.test_reject_block_proposal(block_proposal, &mut block_info, block_response);
477482

478483
if let Some(block_response) = block_response {
479-
// We know proposal is invalid. Send rejection message, do not do further validation
480-
if let Err(e) = block_info.mark_locally_rejected() {
481-
warn!("{self}: Failed to mark block as locally rejected: {e:?}",);
482-
};
484+
// We know proposal is invalid. Send rejection message, do not do further validation and do not store it.
483485
debug!("{self}: Broadcasting a block response to stacks node: {block_response:?}");
484486
let res = self
485487
.stackerdb
@@ -535,6 +537,10 @@ impl Signer {
535537
stacks_client: &StacksClient,
536538
block_response: &BlockResponse,
537539
) {
540+
#[cfg(any(test, feature = "testing"))]
541+
if self.test_ignore_block_responses(block_response) {
542+
return;
543+
}
538544
match block_response {
539545
BlockResponse::Accepted(accepted) => {
540546
self.handle_block_signature(stacks_client, accepted);
@@ -870,7 +876,7 @@ impl Signer {
870876
// Not enough rejection signatures to make a decision
871877
return;
872878
}
873-
debug!("{self}: {total_reject_weight}/{total_weight} signers voteed to reject the block {block_hash}");
879+
debug!("{self}: {total_reject_weight}/{total_weight} signers voted to reject the block {block_hash}");
874880
if let Err(e) = block_info.mark_globally_rejected() {
875881
warn!("{self}: Failed to mark block as globally rejected: {e:?}",);
876882
}
@@ -999,7 +1005,7 @@ impl Signer {
9991005
return;
10001006
};
10011007
// move block to LOCALLY accepted state.
1002-
// We only mark this GLOBALLY accepted if we manage to broadcast it...
1008+
// It is only considered globally accepted IFF we receive a new block event confirming it OR see the chain tip of the node advance to it.
10031009
if let Err(e) = block_info.mark_locally_accepted(true) {
10041010
// Do not abort as we should still try to store the block signature threshold
10051011
warn!("{self}: Failed to mark block as locally accepted: {e:?}");
@@ -1012,22 +1018,8 @@ impl Signer {
10121018
panic!("{self} Failed to write block to signerdb: {e}");
10131019
});
10141020
#[cfg(any(test, feature = "testing"))]
1015-
{
1016-
if *TEST_PAUSE_BLOCK_BROADCAST.lock().unwrap() == Some(true) {
1017-
// Do an extra check just so we don't log EVERY time.
1018-
warn!("Block broadcast is stalled due to testing directive.";
1019-
"block_id" => %block_info.block.block_id(),
1020-
"height" => block_info.block.header.chain_length,
1021-
);
1022-
while *TEST_PAUSE_BLOCK_BROADCAST.lock().unwrap() == Some(true) {
1023-
std::thread::sleep(std::time::Duration::from_millis(10));
1024-
}
1025-
info!("Block validation is no longer stalled due to testing directive.";
1026-
"block_id" => %block_info.block.block_id(),
1027-
"height" => block_info.block.header.chain_length,
1028-
);
1029-
}
1030-
}
1021+
self.test_pause_block_broadcast(&block_info);
1022+
10311023
self.broadcast_signed_block(stacks_client, block_info.block, &addrs_to_sigs);
10321024
if self
10331025
.submitted_block_proposal
@@ -1137,6 +1129,36 @@ impl Signer {
11371129
}
11381130
}
11391131

1132+
#[cfg(any(test, feature = "testing"))]
1133+
fn test_ignore_block_responses(&self, block_response: &BlockResponse) -> bool {
1134+
if *TEST_IGNORE_BLOCK_RESPONSES.lock().unwrap() == Some(true) {
1135+
warn!(
1136+
"{self}: Ignoring block response due to testing directive";
1137+
"block_response" => %block_response
1138+
);
1139+
return true;
1140+
}
1141+
false
1142+
}
1143+
1144+
#[cfg(any(test, feature = "testing"))]
1145+
fn test_pause_block_broadcast(&self, block_info: &BlockInfo) {
1146+
if *TEST_PAUSE_BLOCK_BROADCAST.lock().unwrap() == Some(true) {
1147+
// Do an extra check just so we don't log EVERY time.
1148+
warn!("{self}: Block broadcast is stalled due to testing directive.";
1149+
"block_id" => %block_info.block.block_id(),
1150+
"height" => block_info.block.header.chain_length,
1151+
);
1152+
while *TEST_PAUSE_BLOCK_BROADCAST.lock().unwrap() == Some(true) {
1153+
std::thread::sleep(std::time::Duration::from_millis(10));
1154+
}
1155+
info!("{self}: Block validation is no longer stalled due to testing directive.";
1156+
"block_id" => %block_info.block.block_id(),
1157+
"height" => block_info.block.header.chain_length,
1158+
);
1159+
}
1160+
}
1161+
11401162
/// Send a mock signature to stackerdb to prove we are still alive
11411163
fn mock_sign(&mut self, mock_proposal: MockProposal) {
11421164
info!("{self}: Mock signing mock proposal: {mock_proposal:?}");

testnet/stacks-node/src/event_dispatcher.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ use url::Url;
7070

7171
use super::config::{EventKeyType, EventObserverConfig};
7272

73+
#[cfg(test)]
74+
pub static TEST_SKIP_BLOCK_ANNOUNCEMENT: std::sync::Mutex<Option<bool>> =
75+
std::sync::Mutex::new(None);
76+
7377
#[derive(Debug, Clone)]
7478
struct EventObserver {
7579
/// Path to the database where pending payloads are stored. If `None`, then
@@ -1299,6 +1303,11 @@ impl EventDispatcher {
12991303

13001304
let mature_rewards = serde_json::Value::Array(mature_rewards_vec);
13011305

1306+
#[cfg(any(test, feature = "testing"))]
1307+
if test_skip_block_announcement(&block) {
1308+
return;
1309+
}
1310+
13021311
for (observer_id, filtered_events_ids) in dispatch_matrix.iter().enumerate() {
13031312
let filtered_events: Vec<_> = filtered_events_ids
13041313
.iter()
@@ -1695,6 +1704,18 @@ impl EventDispatcher {
16951704
}
16961705
}
16971706

1707+
#[cfg(any(test, feature = "testing"))]
1708+
fn test_skip_block_announcement(block: &StacksBlockEventData) -> bool {
1709+
if *TEST_SKIP_BLOCK_ANNOUNCEMENT.lock().unwrap() == Some(true) {
1710+
warn!(
1711+
"Skipping new block announcement due to testing directive";
1712+
"block_hash" => %block.block_hash
1713+
);
1714+
return true;
1715+
}
1716+
false
1717+
}
1718+
16981719
#[cfg(test)]
16991720
mod test {
17001721
use std::net::TcpListener;

0 commit comments

Comments
 (0)