Skip to content

Commit 15f497b

Browse files
authored
Merge pull request #5996 from obycode/test/burn-block-height
test: add integration test checking `burn-block-height` behavior
2 parents 29566bd + 4cdb8dc commit 15f497b

File tree

1 file changed

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

1 file changed

+214
-0
lines changed

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

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13549,3 +13549,217 @@ fn verify_mempool_caches() {
1354913549

1355013550
signer_test.shutdown();
1355113551
}
13552+
13553+
#[test]
13554+
#[ignore]
13555+
/// This test checks the behavior of `burn-block-height` within a normal
13556+
/// Nakamoto block and within a tenure-extend block.
13557+
fn burn_block_height_behavior() {
13558+
if env::var("BITCOIND_TEST") != Ok("1".into()) {
13559+
return;
13560+
}
13561+
13562+
tracing_subscriber::registry()
13563+
.with(fmt::layer())
13564+
.with(EnvFilter::from_default_env())
13565+
.init();
13566+
13567+
info!("------------------------- Test Setup -------------------------");
13568+
let num_signers = 5;
13569+
let sender_sk = Secp256k1PrivateKey::random();
13570+
let sender_addr = tests::to_addr(&sender_sk);
13571+
let send_amt = 100;
13572+
let send_fee = 180;
13573+
let deployer_sk = Secp256k1PrivateKey::random();
13574+
let deployer_addr = tests::to_addr(&deployer_sk);
13575+
let tx_fee = 10000;
13576+
let deploy_fee = 200000;
13577+
let block_proposal_timeout = Duration::from_secs(20);
13578+
let mut signer_test: SignerTest<SpawnedSigner> = SignerTest::new_with_config_modifications(
13579+
num_signers,
13580+
vec![
13581+
(sender_addr, send_amt + send_fee),
13582+
(deployer_addr, deploy_fee + tx_fee * 3),
13583+
],
13584+
|config| {
13585+
// make the duration long enough that the miner will be marked as malicious
13586+
config.block_proposal_timeout = block_proposal_timeout;
13587+
},
13588+
|_| {},
13589+
None,
13590+
None,
13591+
);
13592+
let http_origin = format!("http://{}", &signer_test.running_nodes.conf.node.rpc_bind);
13593+
13594+
signer_test.boot_to_epoch_3();
13595+
13596+
let Counters {
13597+
naka_skip_commit_op: skip_commit_op,
13598+
..
13599+
} = signer_test.running_nodes.counters.clone();
13600+
13601+
info!("------------------------- Test Mine Regular Tenure A -------------------------");
13602+
13603+
let contract_src = "(define-public (foo) (ok burn-block-height))";
13604+
13605+
// First, lets deploy the contract
13606+
let mut deployer_nonce = 0;
13607+
let contract_tx = make_contract_publish(
13608+
&deployer_sk,
13609+
deployer_nonce,
13610+
deploy_fee,
13611+
signer_test.running_nodes.conf.burnchain.chain_id,
13612+
"foo",
13613+
&contract_src,
13614+
);
13615+
submit_tx(&http_origin, &contract_tx);
13616+
deployer_nonce += 1;
13617+
13618+
// Wait for this transaction to be mined in a block
13619+
info!("----- Submitted deploy txs, waiting for block -----");
13620+
wait_for(60, || {
13621+
Ok(get_account(&http_origin, &deployer_addr).nonce == deployer_nonce)
13622+
})
13623+
.unwrap();
13624+
13625+
// Stall block commits, so the next block will have no sortition
13626+
skip_commit_op.set(true);
13627+
13628+
// Mine a regular tenure
13629+
let info_before = signer_test.get_peer_info();
13630+
next_block_and(
13631+
&mut signer_test.running_nodes.btc_regtest_controller,
13632+
60,
13633+
|| {
13634+
let chain_info = get_chain_info(&signer_test.running_nodes.conf);
13635+
Ok(chain_info.stacks_tip_height > info_before.stacks_tip_height)
13636+
},
13637+
)
13638+
.expect("Timed out waiting for block");
13639+
13640+
let info = get_chain_info(&signer_test.running_nodes.conf);
13641+
let stacks_height_before = info.stacks_tip_height;
13642+
let burn_height_before = info.burn_block_height;
13643+
13644+
info!("------------------------- submit contract call 1 -------------------------");
13645+
let call_tx = make_contract_call(
13646+
&deployer_sk,
13647+
deployer_nonce,
13648+
tx_fee,
13649+
signer_test.running_nodes.conf.burnchain.chain_id,
13650+
&deployer_addr,
13651+
"foo",
13652+
"foo",
13653+
&[],
13654+
);
13655+
let txid = submit_tx(&http_origin, &call_tx);
13656+
deployer_nonce += 1;
13657+
13658+
info!("------------------------- wait for the call tx to be mined -------------------------");
13659+
// Wait for the call tx to be mined in a new Nakamoto block
13660+
wait_for(60, || {
13661+
test_observer::get_mined_nakamoto_blocks()
13662+
.last()
13663+
.and_then(|block| {
13664+
block.tx_events.iter().find_map(|tx| match tx {
13665+
TransactionEvent::Success(tx) if tx.txid.to_string() == txid => {
13666+
let result = tx
13667+
.result
13668+
.clone()
13669+
.expect_result_ok()
13670+
.ok()?
13671+
.expect_u128()
13672+
.ok()?;
13673+
Some(result)
13674+
}
13675+
_ => None,
13676+
})
13677+
})
13678+
.map_or(Ok(false), |result_height| {
13679+
assert_eq!(result_height, burn_height_before as u128);
13680+
Ok(true)
13681+
})
13682+
})
13683+
.expect("Timed out waiting for call tx to be mined");
13684+
13685+
info!("------------------------- Wait for the block to be processed -------------------------");
13686+
// Wait for the block to be processed
13687+
wait_for(60, || {
13688+
let info = get_chain_info(&signer_test.running_nodes.conf);
13689+
Ok(info.stacks_tip_height > stacks_height_before)
13690+
})
13691+
.expect("Timed out waiting for block to be processed");
13692+
13693+
// Stall mining, so that the next call will get included in the tenure extend block
13694+
TEST_MINE_STALL.set(true);
13695+
13696+
// Wait to ensure the miner reaches the stalled state
13697+
// This is necessary because it's possible that the miner will mine the
13698+
// following transaction before reaching the stall state, causing the test
13699+
// to be flaky.
13700+
sleep_ms(5000);
13701+
13702+
info!("------------------------- submit contract call 2 -------------------------");
13703+
let call_tx = make_contract_call(
13704+
&deployer_sk,
13705+
deployer_nonce,
13706+
tx_fee,
13707+
signer_test.running_nodes.conf.burnchain.chain_id,
13708+
&deployer_addr,
13709+
"foo",
13710+
"foo",
13711+
&[],
13712+
);
13713+
let txid = submit_tx(&http_origin, &call_tx);
13714+
13715+
info!(
13716+
"------------------------- mine bitcoin block with no sortition -------------------------"
13717+
);
13718+
let info = get_chain_info(&signer_test.running_nodes.conf);
13719+
let stacks_height_before = info.stacks_tip_height;
13720+
let burn_height_before = info.burn_block_height;
13721+
13722+
signer_test
13723+
.running_nodes
13724+
.btc_regtest_controller
13725+
.build_next_block(1);
13726+
13727+
wait_for(60, || {
13728+
let info = get_chain_info(&signer_test.running_nodes.conf);
13729+
Ok(info.burn_block_height == burn_height_before + 1)
13730+
})
13731+
.expect("Failed to advance chain tip");
13732+
13733+
info!("------------------------- wait for tenure change block -------------------------");
13734+
13735+
// Resume mining and wait for the next block to be mined
13736+
TEST_MINE_STALL.set(false);
13737+
wait_for_tenure_change_tx(60, TenureChangeCause::Extended, stacks_height_before + 1)
13738+
.expect("Timed out waiting for tenure extend");
13739+
13740+
let blocks = test_observer::get_mined_nakamoto_blocks();
13741+
let last_block = blocks.last().unwrap();
13742+
let txs = &last_block.tx_events;
13743+
assert_eq!(txs.len(), 2, "Expected 2 txs in the tenure extend block");
13744+
let _tenure_extend_tx = txs.first().unwrap();
13745+
let call_tx = txs.last().unwrap();
13746+
match call_tx {
13747+
TransactionEvent::Success(tx) => {
13748+
if tx.txid.to_string() == txid {
13749+
let result_height = tx
13750+
.result
13751+
.clone()
13752+
.expect_result_ok()
13753+
.unwrap()
13754+
.expect_u128()
13755+
.unwrap();
13756+
assert_eq!(result_height, burn_height_before as u128 + 1);
13757+
}
13758+
}
13759+
_ => {}
13760+
}
13761+
13762+
info!("------------------------- shutdown -------------------------");
13763+
13764+
signer_test.shutdown();
13765+
}

0 commit comments

Comments
 (0)