Skip to content

Commit 25cd9d9

Browse files
committed
Update test to be more streamlined and ensure no extra commits make it in
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent e459b8c commit 25cd9d9

File tree

1 file changed

+98
-66
lines changed
  • testnet/stacks-node/src/tests/signer

1 file changed

+98
-66
lines changed

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

Lines changed: 98 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -5023,7 +5023,9 @@ fn miner_recovers_when_broadcast_block_delay_across_tenures_occurs() {
50235023
/// Miner 1 wins the first Nakamoto tenure A. Miner 1 mines a regular stacks block N.
50245024
/// Miner 2 wins the second Nakamoto tenure B and proposes block N+1, but it is rejected by the signers.
50255025
/// An empty burn block is mined
5026-
/// Miner 2 wins the third Nakamoto tenure C. Miner 2 proposes a block N+1' which all signers accept.
5026+
/// TODO: which behaviour do we want to enforce? Should we allow both? If so, we should force both explicitly
5027+
/// Miner 1 should issue a tenure extend and propose block N+1' which is accepted by the signers OR
5028+
/// Miner 2 should issue a new TenureChangePayload followed by a TenureExtend.
50275029
/// Asserts:
50285030
/// - The stacks tip advances to N+1'
50295031
#[test]
@@ -5034,11 +5036,13 @@ fn continue_after_fast_block_no_sortition() {
50345036
}
50355037

50365038
let num_signers = 5;
5039+
let recipient = PrincipalData::from(StacksAddress::burn_address(false));
50375040
let sender_sk = Secp256k1PrivateKey::new();
50385041
let sender_addr = tests::to_addr(&sender_sk);
50395042
let send_amt = 100;
50405043
let send_fee = 180;
5041-
let num_txs = 5;
5044+
let num_txs = 1;
5045+
let sender_nonce = 0;
50425046

50435047
let btc_miner_1_seed = vec![1, 1, 1, 1];
50445048
let btc_miner_2_seed = vec![2, 2, 2, 2];
@@ -5129,6 +5133,7 @@ fn continue_after_fast_block_no_sortition() {
51295133
conf.burnchain.chain_id,
51305134
conf.burnchain.peer_version,
51315135
);
5136+
let http_origin = format!("http://{}", &signer_test.running_nodes.conf.node.rpc_bind);
51325137

51335138
let mut run_loop_2 = boot_nakamoto::BootRunLoop::new(conf_node_2.clone()).unwrap();
51345139
let run_loop_stopper_2 = run_loop_2.get_termination_switch();
@@ -5145,6 +5150,7 @@ fn continue_after_fast_block_no_sortition() {
51455150

51465151
info!("------------------------- Pause Miner 2's Block Commits -------------------------");
51475152

5153+
// Make sure Miner 2 cannot win a sortition at first.
51485154
rl2_skip_commit_op.set(true);
51495155
let run_loop_2_thread = thread::Builder::new()
51505156
.name("run_loop_2".into())
@@ -5185,16 +5191,23 @@ fn continue_after_fast_block_no_sortition() {
51855191

51865192
info!("------------------------- Miner 1 Mines a Normal Tenure A -------------------------");
51875193
let blocks_processed_before_1 = blocks_mined1.load(Ordering::SeqCst);
5188-
let commits_before_1 = rl1_commits.load(Ordering::SeqCst);
5194+
info!("------------------------- Pause Miner 1's Block Commit -------------------------");
5195+
// Make sure miner 1 doesn't submit a block commit for the next tenure BEFORE mining the bitcoin block
5196+
signer_test
5197+
.running_nodes
5198+
.nakamoto_test_skip_commit_op
5199+
.set(true);
51895200

5190-
next_block_and(
5191-
&mut signer_test.running_nodes.btc_regtest_controller,
5192-
60,
5193-
|| Ok(rl1_commits.load(Ordering::SeqCst) > commits_before_1),
5194-
)
5195-
.unwrap();
5201+
signer_test
5202+
.running_nodes
5203+
.btc_regtest_controller
5204+
.build_next_block(1);
51965205
btc_blocks_mined += 1;
51975206

5207+
// assure we have a sortition
5208+
let tip = SortitionDB::get_canonical_burn_chain_tip(sortdb.conn()).unwrap();
5209+
assert!(tip.sortition);
5210+
51985211
// wait for the new block to be processed
51995212
wait_for(60, || {
52005213
Ok(blocks_mined1.load(Ordering::SeqCst) > blocks_processed_before_1)
@@ -5212,28 +5225,35 @@ fn continue_after_fast_block_no_sortition() {
52125225
.expect("Failed to get peer info")
52135226
.stacks_tip_height;
52145227

5228+
info!("------------------------- Make Signers Reject All Subsequent Proposals -------------------------");
52155229
// Make all signers ignore block proposals
52165230
let ignoring_signers = all_signers.to_vec();
52175231
TEST_REJECT_ALL_BLOCK_PROPOSAL
52185232
.lock()
52195233
.unwrap()
52205234
.replace(ignoring_signers.clone());
52215235

5222-
// Make sure miner 1 doesn't submit a block commit for the next tenure
5223-
signer_test
5224-
.running_nodes
5225-
.nakamoto_test_skip_commit_op
5226-
.set(true);
5227-
5236+
info!("------------------------- Unpause Miner 2's Block Commits -------------------------");
52285237
let rejections_before = signer_test
52295238
.running_nodes
52305239
.nakamoto_blocks_rejected
52315240
.load(Ordering::SeqCst);
52325241

5242+
let rl2_commits_before = rl2_commits.load(Ordering::SeqCst);
52335243
// Unpause miner 2's block commits
52345244
rl2_skip_commit_op.set(false);
52355245

5236-
// Mine a new burn block
5246+
info!("------------------------- Wait for Miner 2's Block Commit Submission -------------------------");
5247+
// Ensure the miner 2 submits a block commit before mining the bitcoin block
5248+
wait_for(30, || {
5249+
Ok(rl2_commits.load(Ordering::SeqCst) > rl2_commits_before)
5250+
})
5251+
.unwrap();
5252+
5253+
// Make miner 2 also fail to submit any FURTHER block commits
5254+
info!("------------------------- Pause Miner 2's Block Commits -------------------------");
5255+
rl2_skip_commit_op.set(true);
5256+
52375257
let burn_height_before = get_burn_height();
52385258
info!("------------------------- Miner 2 Mines an Empty Tenure B -------------------------";
52395259
"burn_height_before" => burn_height_before,
@@ -5253,20 +5273,29 @@ fn continue_after_fast_block_no_sortition() {
52535273
assert!(tip.sortition);
52545274

52555275
info!("----- Waiting for block rejections -----");
5256-
let min_rejections = (num_signers as u64) * 4 / 10;
5276+
let min_rejections = num_signers * 4 / 10;
52575277
// Wait until we have some block rejections
52585278
wait_for(30, || {
5259-
let rejections = signer_test
5260-
.running_nodes
5261-
.nakamoto_blocks_rejected
5262-
.load(Ordering::SeqCst);
5263-
let rejections_diff = rejections - rejections_before;
5264-
Ok(rejections_diff >= min_rejections)
5279+
std::thread::sleep(Duration::from_secs(1));
5280+
let chunks = test_observer::get_stackerdb_chunks();
5281+
let rejections: Vec<_> = chunks
5282+
.into_iter()
5283+
.flat_map(|chunk| chunk.modified_slots)
5284+
.filter(|chunk| {
5285+
let Ok(message) = SignerMessage::consensus_deserialize(&mut chunk.data.as_slice())
5286+
else {
5287+
return false;
5288+
};
5289+
matches!(
5290+
message,
5291+
SignerMessage::BlockResponse(BlockResponse::Rejected(_))
5292+
)
5293+
})
5294+
.collect();
5295+
Ok(rejections.len() >= min_rejections)
52655296
})
52665297
.expect("Timed out waiting for block rejections");
52675298

5268-
// Make miner 2 also fail to submit commits
5269-
rl2_skip_commit_op.set(true);
52705299
// Miner another block and ensure there is _no_ sortition
52715300
info!("------------------------- Mine Burn Block with No Sortition -------------------------");
52725301
let blocks_processed_before_1 = blocks_mined1.load(Ordering::SeqCst);
@@ -5294,6 +5323,10 @@ fn continue_after_fast_block_no_sortition() {
52945323
blocks_processed_before_2
52955324
);
52965325

5326+
// assure we have NO sortition
5327+
let tip = SortitionDB::get_canonical_burn_chain_tip(sortdb.conn()).unwrap();
5328+
assert!(!tip.sortition);
5329+
52975330
// Verify that no Stacks blocks have been mined (signers are ignoring) and no commits have been submitted by either miner
52985331
let stacks_height = signer_test
52995332
.stacks_client
@@ -5303,56 +5336,32 @@ fn continue_after_fast_block_no_sortition() {
53035336
assert_eq!(stacks_height, stacks_height_before);
53045337
let stacks_height_before = stacks_height;
53055338

5306-
info!(
5307-
"------------------------- Miner 2 Attempts to Mine a Tenure C -------------------------"
5308-
);
5309-
53105339
let blocks_processed_before_2 = blocks_mined2.load(Ordering::SeqCst);
5311-
let burn_height_before = get_burn_height();
5312-
let commits_before_2 = rl2_commits.load(Ordering::SeqCst);
5313-
53145340
info!("----- Enabling signers to approve proposals -----";
53155341
"stacks_height" => stacks_height_before,
53165342
);
5343+
5344+
let nmb_old_blocks = test_observer::get_blocks().len();
53175345
// Allow signers to respond to proposals again
53185346
TEST_REJECT_ALL_BLOCK_PROPOSAL
53195347
.lock()
53205348
.unwrap()
53215349
.replace(Vec::new());
53225350

5323-
// Unpause miner 2's block commits
5324-
rl2_skip_commit_op.set(false);
5325-
5326-
// TODO: can combine the following three wait_for and also the next_block_and once fixed
5327-
next_block_and(
5328-
&mut signer_test.running_nodes.btc_regtest_controller,
5329-
60,
5330-
|| Ok(rl2_commits.load(Ordering::SeqCst) > commits_before_2),
5331-
)
5332-
.unwrap();
5333-
btc_blocks_mined += 1;
5334-
5335-
wait_for(30, || Ok(get_burn_height() > burn_height_before)).unwrap();
5336-
5337-
// TODO DELETE THIS
5338-
let blocks = test_observer::get_blocks();
5339-
// Debug the last 4 blocks
5340-
let blocks = blocks.iter().rev().take(4).rev().collect::<Vec<_>>();
5341-
for block in blocks {
5342-
println!("\n\n");
5343-
info!("Block: {}", serde_json::to_string_pretty(&block).unwrap());
5344-
let transactions = block.get("transactions").unwrap().as_array().unwrap();
5345-
for tx in transactions.iter().rev() {
5346-
let raw_tx = tx.get("raw_tx").unwrap().as_str().unwrap();
5347-
if raw_tx != "0x00" {
5348-
let tx_bytes = hex_bytes(&raw_tx[2..]).unwrap();
5349-
let parsed =
5350-
StacksTransaction::consensus_deserialize(&mut tx_bytes.as_slice()).unwrap();
5351-
info!("Tx: {}", serde_json::to_string_pretty(&parsed).unwrap());
5352-
}
5353-
}
5354-
}
5351+
// submit a tx so that the miner will mine an extra block just in case due to timing constraints, the first block with the tenure extend was
5352+
// rejected already by the signers
5353+
let transfer_tx = make_stacks_transfer(
5354+
&sender_sk,
5355+
sender_nonce,
5356+
send_fee,
5357+
signer_test.running_nodes.conf.burnchain.chain_id,
5358+
&recipient,
5359+
send_amt,
5360+
);
5361+
submit_tx(&http_origin, &transfer_tx);
53555362

5363+
// TODO: combine these wait fors once fixed code
5364+
// wait for the new block to be processed
53565365
wait_for(30, || {
53575366
Ok(blocks_mined2.load(Ordering::SeqCst) > blocks_processed_before_2)
53585367
})
@@ -5368,14 +5377,37 @@ fn continue_after_fast_block_no_sortition() {
53685377
})
53695378
.expect("Expected a new Stacks block to be mined");
53705379

5380+
wait_for(
5381+
30,
5382+
|| Ok(test_observer::get_blocks().len() > nmb_old_blocks),
5383+
)
5384+
.expect("Timed out waiting for test observer to see new block");
5385+
5386+
let blocks = test_observer::get_blocks();
5387+
let tenure_extend_block = if nmb_old_blocks + 1 == test_observer::get_blocks().len() {
5388+
blocks.last().unwrap()
5389+
} else {
5390+
&blocks[blocks.len() - 2]
5391+
};
5392+
let transactions = tenure_extend_block["transactions"].as_array().unwrap();
5393+
let tx = transactions.first().expect("No transactions in block");
5394+
let raw_tx = tx["raw_tx"].as_str().unwrap();
5395+
let tx_bytes = hex_bytes(&raw_tx[2..]).unwrap();
5396+
let parsed = StacksTransaction::consensus_deserialize(&mut &tx_bytes[..]).unwrap();
5397+
match &parsed.payload {
5398+
TransactionPayload::TenureChange(payload)
5399+
if payload.cause == TenureChangeCause::Extended => {}
5400+
_ => panic!("Expected tenure extend transaction, got {parsed:?}"),
5401+
};
5402+
53715403
let peer_info = signer_test
53725404
.stacks_client
53735405
.get_peer_info()
53745406
.expect("Failed to get peer info");
53755407

53765408
assert_eq!(get_burn_height(), starting_burn_height + btc_blocks_mined);
5377-
// We only successfully mine 2 stacks block in this test
5378-
assert_eq!(peer_info.stacks_tip_height, starting_peer_height + 2);
5409+
// We successfully mine at least 2 stacks block in this test
5410+
assert!(peer_info.stacks_tip_height >= starting_peer_height + 2);
53795411
rl2_coord_channels
53805412
.lock()
53815413
.expect("Mutex poisoned")

0 commit comments

Comments
 (0)