Skip to content

Commit f5c8b03

Browse files
committed
feat: setup test to repro #5400
1 parent 559b1d6 commit f5c8b03

File tree

1 file changed

+195
-0
lines changed
  • testnet/stacks-node/src/tests/signer

1 file changed

+195
-0
lines changed

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

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5074,6 +5074,201 @@ fn miner_recovers_when_broadcast_block_delay_across_tenures_occurs() {
50745074
assert_ne!(block_n_2, block_n);
50755075
}
50765076

5077+
/// Test a scenario where:
5078+
/// We have one miner. During block A, there is a sortition and a TenureChange.
5079+
/// Block B is mined, but it does not contain a TenureChange (ie because a
5080+
/// new burn block was mined too quickly).
5081+
/// Then block C occurs, which does not have a sortition.
5082+
#[test]
5083+
#[ignore]
5084+
fn continue_after_fast_block_no_sortition() {
5085+
if env::var("BITCOIND_TEST") != Ok("1".into()) {
5086+
return;
5087+
}
5088+
5089+
tracing_subscriber::registry()
5090+
.with(fmt::layer())
5091+
.with(EnvFilter::from_default_env())
5092+
.init();
5093+
5094+
info!("------------------------- Test Setup -------------------------");
5095+
let num_signers = 5;
5096+
let sender_sk = Secp256k1PrivateKey::new();
5097+
let sender_addr = tests::to_addr(&sender_sk);
5098+
let _recipient = PrincipalData::from(StacksAddress::burn_address(false));
5099+
let send_amt = 100;
5100+
let send_fee = 180;
5101+
let mut signer_test: SignerTest<SpawnedSigner> = SignerTest::new(
5102+
num_signers,
5103+
vec![(sender_addr.clone(), (send_amt + send_fee) * 5)],
5104+
);
5105+
let timeout = Duration::from_secs(200);
5106+
let _coord_channel = signer_test.running_nodes.coord_channel.clone();
5107+
let _http_origin = format!("http://{}", &signer_test.running_nodes.conf.node.rpc_bind);
5108+
5109+
signer_test.boot_to_epoch_3();
5110+
5111+
let burnchain = signer_test.running_nodes.conf.get_burnchain();
5112+
let sortdb = burnchain.open_sortition_db(true).unwrap();
5113+
5114+
let get_burn_height = || {
5115+
SortitionDB::get_canonical_burn_chain_tip(&sortdb.conn())
5116+
.unwrap()
5117+
.block_height
5118+
};
5119+
5120+
let all_signers = signer_test
5121+
.signer_stacks_private_keys
5122+
.iter()
5123+
.map(StacksPublicKey::from_private)
5124+
.collect::<Vec<_>>();
5125+
5126+
let commits_before = signer_test
5127+
.running_nodes
5128+
.commits_submitted
5129+
.load(Ordering::SeqCst);
5130+
5131+
info!("------------------------- Mine Normal Tenure -------------------------");
5132+
signer_test.mine_and_verify_confirmed_naka_block(timeout, num_signers);
5133+
5134+
let stacks_height_before = signer_test
5135+
.stacks_client
5136+
.get_peer_info()
5137+
.expect("Failed to get peer info")
5138+
.stacks_tip_height;
5139+
5140+
// Wait for a new block commit
5141+
wait_for(20, || {
5142+
let commits = signer_test
5143+
.running_nodes
5144+
.commits_submitted
5145+
.load(Ordering::SeqCst);
5146+
// 2 because we mined one block in the normal tenure
5147+
Ok(commits - commits_before >= 2)
5148+
})
5149+
.expect("Timed out waiting for a new block commit");
5150+
5151+
// Make all signers ignore block proposals
5152+
let ignoring_signers: Vec<_> = all_signers.iter().cloned().collect();
5153+
TEST_REJECT_ALL_BLOCK_PROPOSAL
5154+
.lock()
5155+
.unwrap()
5156+
.replace(ignoring_signers.clone());
5157+
5158+
// Don't make future block commits
5159+
signer_test
5160+
.running_nodes
5161+
.nakamoto_test_skip_commit_op
5162+
.set(true);
5163+
5164+
let burn_height_before = get_burn_height();
5165+
5166+
let rejections_before = signer_test
5167+
.running_nodes
5168+
.nakamoto_blocks_rejected
5169+
.load(Ordering::SeqCst);
5170+
5171+
// Mine a new burn block
5172+
info!("------------------------- Starting Tenure B -------------------------";
5173+
"burn_height_before" => burn_height_before,
5174+
"rejections_before" => rejections_before,
5175+
);
5176+
5177+
next_block_and(
5178+
&mut signer_test.running_nodes.btc_regtest_controller,
5179+
60,
5180+
|| Ok(get_burn_height() > burn_height_before),
5181+
)
5182+
.unwrap();
5183+
5184+
// assure we have a sortition
5185+
let tip = SortitionDB::get_canonical_burn_chain_tip(&sortdb.conn()).unwrap();
5186+
assert!(tip.sortition);
5187+
5188+
let burn_height_before = signer_test
5189+
.stacks_client
5190+
.get_peer_info()
5191+
.expect("Failed to get peer info")
5192+
.burn_block_height;
5193+
5194+
info!("----- Waiting for block rejections -----");
5195+
let min_rejections = (num_signers as u64) * 4 / 10;
5196+
// Wait until we have some block rejections
5197+
wait_for(30, || {
5198+
let rejections = signer_test
5199+
.running_nodes
5200+
.nakamoto_blocks_rejected
5201+
.load(Ordering::SeqCst);
5202+
let rejections_diff = rejections - rejections_before;
5203+
Ok(rejections_diff >= min_rejections)
5204+
})
5205+
.expect("Timed out waiting for block rejections");
5206+
5207+
// Miner another block and ensure there is _no_ sortition
5208+
info!("------------------------- Mine another block -------------------------");
5209+
next_block_and(
5210+
&mut signer_test.running_nodes.btc_regtest_controller,
5211+
60,
5212+
|| {
5213+
let burn_height = signer_test
5214+
.stacks_client
5215+
.get_peer_info()
5216+
.expect("Failed to get peer info")
5217+
.burn_block_height;
5218+
Ok(burn_height > burn_height_before)
5219+
},
5220+
)
5221+
.unwrap();
5222+
5223+
// Verify that no Stacks blocks have been mined (signers are ignoring)
5224+
let stacks_height = signer_test
5225+
.stacks_client
5226+
.get_peer_info()
5227+
.expect("Failed to get peer info")
5228+
.stacks_tip_height;
5229+
assert_eq!(stacks_height, stacks_height_before);
5230+
5231+
let stacks_height_before = stacks_height;
5232+
5233+
info!("----- Enabling signers to approve proposals -----";
5234+
"stacks_height" => stacks_height_before,
5235+
);
5236+
5237+
// Allow signers to respond to proposals again
5238+
TEST_REJECT_ALL_BLOCK_PROPOSAL
5239+
.lock()
5240+
.unwrap()
5241+
.replace(Vec::new());
5242+
5243+
wait_for(30, || {
5244+
let stacks_height = signer_test
5245+
.stacks_client
5246+
.get_peer_info()
5247+
.expect("Failed to get peer info")
5248+
.stacks_tip_height;
5249+
Ok(stacks_height > stacks_height_before)
5250+
})
5251+
.expect("Expected a new Stacks block to be mined");
5252+
5253+
let blocks = test_observer::get_blocks();
5254+
// Debug the last 4 blocks
5255+
let blocks = blocks.iter().rev().take(4).rev().collect::<Vec<_>>();
5256+
for block in blocks {
5257+
println!("\n\n");
5258+
info!("Block: {}", serde_json::to_string_pretty(&block).unwrap());
5259+
let transactions = block.get("transactions").unwrap().as_array().unwrap();
5260+
for tx in transactions.iter().rev() {
5261+
let raw_tx = tx.get("raw_tx").unwrap().as_str().unwrap();
5262+
if raw_tx != "0x00" {
5263+
let tx_bytes = hex_bytes(&raw_tx[2..]).unwrap();
5264+
let parsed =
5265+
StacksTransaction::consensus_deserialize(&mut tx_bytes.as_slice()).unwrap();
5266+
info!("Tx: {}", serde_json::to_string_pretty(&parsed).unwrap());
5267+
}
5268+
}
5269+
}
5270+
}
5271+
50775272
#[test]
50785273
#[ignore]
50795274
/// Test that we can mine a tenure extend and then continue mining afterwards.

0 commit comments

Comments
 (0)