Skip to content

Commit 3260a2c

Browse files
committed
Add signing_in_0th_tenure_of_reward_cycle test
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent 0b4f3b2 commit 3260a2c

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

.github/workflows/bitcoin-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ jobs:
114114
- tests::signer::v0::partial_tenure_fork
115115
- tests::signer::v0::mine_2_nakamoto_reward_cycles
116116
- tests::signer::v0::signer_set_rollover
117+
- tests::signer::v0::signing_in_0th_tenure_of_reward_cycle
117118
- tests::nakamoto_integrations::stack_stx_burn_op_integration_test
118119
- tests::nakamoto_integrations::check_block_heights
119120
- tests::nakamoto_integrations::clarity_burn_state

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

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use stacks::chainstate::stacks::db::{StacksBlockHeaderTypes, StacksChainState, S
3535
use stacks::codec::StacksMessageCodec;
3636
use stacks::core::{StacksEpochId, CHAIN_ID_TESTNET};
3737
use stacks::libstackerdb::StackerDBChunkData;
38+
use stacks::net::api::getsigner::GetSignerResponse;
3839
use stacks::net::api::postblock_proposal::{ValidateRejectCode, TEST_VALIDATE_STALL};
3940
use stacks::net::relay::fault_injection::set_ignore_block;
4041
use stacks::types::chainstate::{StacksAddress, StacksBlockId, StacksPrivateKey, StacksPublicKey};
@@ -4813,3 +4814,115 @@ fn miner_recovers_when_broadcast_block_delay_across_tenures_occurs() {
48134814
assert_eq!(info_after.stacks_tip.to_string(), block_n_2.block_hash);
48144815
assert_ne!(block_n_2, block_n);
48154816
}
4817+
4818+
#[test]
4819+
#[ignore]
4820+
/// Test that signers can successfully sign a block proposal in the 0th tenure of a reward cycle
4821+
/// This ensures there is no race condition in the /v2/pox endpoint which could prevent it from updating
4822+
/// on time, possibly triggering an "off by one" like behaviour in the 0th tenure.
4823+
///
4824+
fn signing_in_0th_tenure_of_reward_cycle() {
4825+
if env::var("BITCOIND_TEST") != Ok("1".into()) {
4826+
return;
4827+
}
4828+
4829+
tracing_subscriber::registry()
4830+
.with(fmt::layer())
4831+
.with(EnvFilter::from_default_env())
4832+
.init();
4833+
4834+
info!("------------------------- Test Setup -------------------------");
4835+
let num_signers = 5;
4836+
let sender_sk = Secp256k1PrivateKey::new();
4837+
let sender_addr = tests::to_addr(&sender_sk);
4838+
let send_amt = 100;
4839+
let send_fee = 180;
4840+
let recipient = PrincipalData::from(StacksAddress::burn_address(false));
4841+
let mut signer_test: SignerTest<SpawnedSigner> = SignerTest::new(
4842+
num_signers,
4843+
vec![(sender_addr.clone(), send_amt + send_fee)],
4844+
);
4845+
let signer_public_keys = signer_test
4846+
.signer_stacks_private_keys
4847+
.iter()
4848+
.map(StacksPublicKey::from_private)
4849+
.collect::<Vec<_>>();
4850+
let long_timeout = Duration::from_secs(200);
4851+
signer_test.boot_to_epoch_3();
4852+
let curr_reward_cycle = signer_test.get_current_reward_cycle();
4853+
let next_reward_cycle = curr_reward_cycle + 1;
4854+
// Mine until the boundary of the first full Nakamoto reward cycles (epoch 3 starts in the middle of one)
4855+
let next_reward_cycle_height_boundary = signer_test
4856+
.running_nodes
4857+
.btc_regtest_controller
4858+
.get_burnchain()
4859+
.reward_cycle_to_block_height(next_reward_cycle)
4860+
.saturating_sub(1);
4861+
4862+
info!("------------------------- Advancing to {next_reward_cycle} Boundary at Block {next_reward_cycle_height_boundary} -------------------------");
4863+
signer_test.run_until_burnchain_height_nakamoto(
4864+
long_timeout,
4865+
next_reward_cycle_height_boundary,
4866+
num_signers,
4867+
);
4868+
4869+
let http_origin = format!("http://{}", &signer_test.running_nodes.conf.node.rpc_bind);
4870+
let get_v3_signer = |pubkey: &Secp256k1PublicKey, reward_cycle: u64| {
4871+
let url = &format!(
4872+
"{http_origin}/v3/signer/{pk}/{reward_cycle}",
4873+
pk = pubkey.to_hex()
4874+
);
4875+
info!("Send request: GET {url}");
4876+
reqwest::blocking::get(url)
4877+
.unwrap_or_else(|e| panic!("GET request failed: {e}"))
4878+
.json::<GetSignerResponse>()
4879+
.unwrap()
4880+
.blocks_signed
4881+
};
4882+
4883+
assert_eq!(signer_test.get_current_reward_cycle(), curr_reward_cycle);
4884+
4885+
for signer in &signer_public_keys {
4886+
let blocks_signed = get_v3_signer(&signer, next_reward_cycle);
4887+
assert_eq!(blocks_signed, 0);
4888+
}
4889+
4890+
info!("------------------------- Enter Reward Cycle {next_reward_cycle} -------------------------");
4891+
next_block_and(
4892+
&mut signer_test.running_nodes.btc_regtest_controller,
4893+
60,
4894+
|| Ok(true),
4895+
)
4896+
.unwrap();
4897+
4898+
for signer in &signer_public_keys {
4899+
let blocks_signed = get_v3_signer(&signer, next_reward_cycle);
4900+
assert_eq!(blocks_signed, 0);
4901+
}
4902+
4903+
let blocks_before = signer_test
4904+
.running_nodes
4905+
.nakamoto_blocks_mined
4906+
.load(Ordering::SeqCst);
4907+
4908+
// submit a tx so that the miner will mine a stacks block in the 0th block of the new reward cycle
4909+
let sender_nonce = 0;
4910+
let transfer_tx =
4911+
make_stacks_transfer(&sender_sk, sender_nonce, send_fee, &recipient, send_amt);
4912+
let _tx = submit_tx(&http_origin, &transfer_tx);
4913+
4914+
wait_for(30, || {
4915+
Ok(signer_test
4916+
.running_nodes
4917+
.nakamoto_blocks_mined
4918+
.load(Ordering::SeqCst)
4919+
> blocks_before)
4920+
})
4921+
.unwrap();
4922+
4923+
for signer in &signer_public_keys {
4924+
let blocks_signed = get_v3_signer(&signer, next_reward_cycle);
4925+
assert_eq!(blocks_signed, 1);
4926+
}
4927+
assert_eq!(signer_test.get_current_reward_cycle(), next_reward_cycle);
4928+
}

0 commit comments

Comments
 (0)