Skip to content

Commit f09306e

Browse files
committed
Fix reorg_attempts_activity_timeout_exceeded test
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent ba32406 commit f09306e

File tree

1 file changed

+79
-42
lines changed
  • testnet/stacks-node/src/tests/signer

1 file changed

+79
-42
lines changed

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

Lines changed: 79 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11546,9 +11546,39 @@ fn reorg_attempts_activity_timeout_exceeded() {
1154611546
block_proposal
1154711547
};
1154811548

11549+
let wait_for_block_rejections = |hash: Sha512Trunc256Sum| {
11550+
wait_for(30, || {
11551+
let stackerdb_events = test_observer::get_stackerdb_chunks();
11552+
let block_rejections = stackerdb_events
11553+
.into_iter()
11554+
.flat_map(|chunk| chunk.modified_slots)
11555+
.filter_map(|chunk| {
11556+
let message = SignerMessage::consensus_deserialize(&mut chunk.data.as_slice())
11557+
.expect("Failed to deserialize SignerMessage");
11558+
match message {
11559+
SignerMessage::BlockResponse(BlockResponse::Rejected(rejection)) => {
11560+
if rejection.signer_signature_hash == hash {
11561+
assert_eq!(
11562+
rejection.reason_code,
11563+
RejectCode::SortitionViewMismatch
11564+
);
11565+
Some(rejection)
11566+
} else {
11567+
None
11568+
}
11569+
}
11570+
_ => None,
11571+
}
11572+
})
11573+
.collect::<Vec<_>>();
11574+
Ok(block_rejections.len() >= num_signers * 3 / 10)
11575+
})
11576+
};
11577+
1154911578
info!("------------------------- Test Mine Block N -------------------------");
1155011579
let chain_before = get_chain_info(&signer_test.running_nodes.conf);
1155111580
// Stall validation so signers will be unable to process the tenure change block for Tenure B.
11581+
// And so the incoming miner proposes a block N' (the reorging block).
1155211582
TEST_VALIDATE_STALL.set(true);
1155311583
test_observer::clear();
1155411584
// submit a tx so that the miner will mine an extra block
@@ -11573,7 +11603,7 @@ fn reorg_attempts_activity_timeout_exceeded() {
1157311603
.running_nodes
1157411604
.commits_submitted
1157511605
.load(Ordering::SeqCst);
11576-
11606+
let chain_before = get_chain_info(&signer_test.running_nodes.conf);
1157711607
next_block_and(
1157811608
&mut signer_test.running_nodes.btc_regtest_controller,
1157911609
60,
@@ -11582,67 +11612,74 @@ fn reorg_attempts_activity_timeout_exceeded() {
1158211612
.running_nodes
1158311613
.commits_submitted
1158411614
.load(Ordering::SeqCst);
11585-
Ok(commits_count > commits_before)
11615+
let chain_info = get_chain_info(&signer_test.running_nodes.conf);
11616+
Ok(commits_count > commits_before
11617+
&& chain_info.burn_block_height > chain_before.burn_block_height)
1158611618
},
1158711619
)
1158811620
.unwrap();
1158911621

11590-
std::thread::sleep(reorg_attempts_activity_timeout.add(Duration::from_secs(1)));
11622+
info!("------------------------- Wait for block N' to arrive late -------------------------");
1159111623
test_observer::clear();
11592-
TEST_BROADCAST_STALL.set(false);
11593-
let block_proposal_n_prime =
11594-
wait_for_block_proposal().expect("Failed to get block proposal N'");
11595-
std::thread::sleep(block_proposal_timeout.add(Duration::from_secs(1)));
11596-
11597-
assert_ne!(block_proposal_n, block_proposal_n_prime);
11598-
let chain_before = get_chain_info(&signer_test.running_nodes.conf);
11624+
// Allow block N validation to finish.
1159911625
TEST_VALIDATE_STALL.set(false);
11600-
1160111626
wait_for(30, || {
1160211627
let chain_info = get_chain_info(&signer_test.running_nodes.conf);
1160311628
Ok(chain_info.stacks_tip_height > chain_before.stacks_tip_height)
1160411629
})
11605-
.expect("Timed out waiting for stacks tip to advance to block N");
11606-
11630+
.expect("Tiemd out waiting for stacks tip to advance to block N");
1160711631
let chain_after = get_chain_info(&signer_test.running_nodes.conf);
11632+
TEST_VALIDATE_STALL.set(true);
11633+
// Allow incoming mine to propose block N'
11634+
// Make sure to wait the reorg_attempts_activity_timeout AFTER the block is globally signed over
11635+
// as this is the point where signers start considering from.
11636+
std::thread::sleep(reorg_attempts_activity_timeout.add(Duration::from_secs(1)));
11637+
TEST_BROADCAST_STALL.set(false);
11638+
let block_proposal_n_prime =
11639+
wait_for_block_proposal().expect("Failed to get block proposal N'");
11640+
assert_eq!(
11641+
block_proposal_n_prime.block.header.chain_length,
11642+
chain_after.stacks_tip_height
11643+
);
11644+
// Make sure that no subsequent proposal arrives before the block_proposal_timeout is exceeded
11645+
TEST_BROADCAST_STALL.set(true);
11646+
TEST_VALIDATE_STALL.set(false);
11647+
// We only need to wait the difference between the two timeouts now since we already slept for a min of reorg_attempts_activity_timeout + 1
11648+
std::thread::sleep(block_proposal_timeout.saturating_sub(reorg_attempts_activity_timeout));
11649+
assert_ne!(block_proposal_n, block_proposal_n_prime);
1160811650
assert_eq!(
1160911651
chain_after.stacks_tip_height,
1161011652
block_proposal_n.block.header.chain_length
1161111653
);
11612-
1161311654
let chain_before = chain_after;
11655+
1161411656
info!("------------------------- Wait for Block N' Rejection -------------------------");
11657+
wait_for_block_rejections(block_proposal_n_prime.block.header.signer_signature_hash())
11658+
.expect("FAIL: Timed out waiting for block proposal rejections of N'");
11659+
11660+
info!("------------------------- Wait for Block N+1 Proposal -------------------------");
11661+
test_observer::clear();
11662+
TEST_BROADCAST_STALL.set(false);
1161511663
wait_for(30, || {
11616-
let stackerdb_events = test_observer::get_stackerdb_chunks();
11617-
let block_rejections = stackerdb_events
11618-
.into_iter()
11619-
.flat_map(|chunk| chunk.modified_slots)
11620-
.filter_map(|chunk| {
11621-
let message = SignerMessage::consensus_deserialize(&mut chunk.data.as_slice())
11622-
.expect("Failed to deserialize SignerMessage");
11623-
match message {
11624-
SignerMessage::BlockResponse(BlockResponse::Rejected(rejection)) => {
11625-
if rejection.signer_signature_hash
11626-
== block_proposal_n_prime.block.header.signer_signature_hash()
11627-
{
11628-
assert_eq!(rejection.reason_code, RejectCode::SortitionViewMismatch);
11629-
Some(rejection)
11630-
} else {
11631-
None
11632-
}
11633-
}
11634-
_ => None,
11635-
}
11636-
})
11637-
.collect::<Vec<_>>();
11638-
Ok(block_rejections.len() >= num_signers * 3 / 10)
11639-
})
11640-
.expect("FAIL: Timed out waiting for block proposal rejections of N'");
11664+
let block_proposal_n_1 =
11665+
wait_for_block_proposal().expect("Failed to get block proposal N+1");
11666+
Ok(block_proposal_n_1.block.header.chain_length
11667+
== block_proposal_n.block.header.chain_length + 1)
11668+
})
11669+
.expect("Timed out waiting for block N+1 to be proposed");
11670+
11671+
info!("------------------------- Wait for Block N+1 Rejection -------------------------");
11672+
// The miner will automatically reattempt to mine a block N+1 once it sees the stacks tip advance to block N.
11673+
// N+1 will still be rejected however as the signers will have already marked the miner as invalid since the reorg
11674+
// block N' arrived AFTER the reorg_attempts_activity_timeout and the subsequent block N+1 arrived AFTER the
11675+
// block_proposal_timeout.
11676+
let block_proposal_n_1 = wait_for_block_proposal().expect("Failed to get block proposal N+1'");
11677+
wait_for_block_rejections(block_proposal_n_1.block.header.signer_signature_hash())
11678+
.expect("FAIL: Timed out waiting for block proposal rejections of N+1'");
1164111679

1164211680
info!("------------------------- Ensure chain halts -------------------------");
11643-
// The signer should automatically attempt to mine a new block once the signers eventually tell it to abandon the previous block
11644-
// It will reject it though because the block proposal timeout is exceeded and its first block proposal arrived AFTER the reorg activity timeout
11645-
assert!(wait_for(30, || {
11681+
// Just in case, wait again and ensure that the chain is still halted (once marked invalid, the miner can do nothing to satisfy the signers)
11682+
assert!(wait_for(reorg_attempts_activity_timeout.as_secs(), || {
1164611683
let chain_info = get_chain_info(&signer_test.running_nodes.conf);
1164711684
assert_eq!(chain_info.stacks_tip_height, chain_before.stacks_tip_height);
1164811685
Ok(false)

0 commit comments

Comments
 (0)