Skip to content

Commit 98d05a4

Browse files
committed
test: add test for reloading signer config when reward set unavailable at start of prepare phase
1 parent 5715f67 commit 98d05a4

File tree

3 files changed

+163
-17
lines changed

3 files changed

+163
-17
lines changed

.github/workflows/bitcoin-tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ jobs:
9595
- tests::signer::v0::mock_sign_epoch_25
9696
- tests::signer::v0::signer_set_rollover
9797
- tests::signer::v0::miner_forking
98+
- tests::signer::v0::reloads_signer_set_in
9899
- tests::nakamoto_integrations::stack_stx_burn_op_integration_test
99100
- tests::nakamoto_integrations::check_block_heights
100101
- tests::nakamoto_integrations::clarity_burn_state

testnet/stacks-node/src/tests/nakamoto_integrations.rs

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,11 +1073,7 @@ fn signer_vote_if_needed(
10731073
}
10741074
}
10751075

1076-
///
1077-
/// * `stacker_sks` - must be a private key for sending a large `stack-stx` transaction in order
1078-
/// for pox-4 to activate
1079-
/// * `signer_pks` - must be the same size as `stacker_sks`
1080-
pub fn boot_to_epoch_3_reward_set_calculation_boundary(
1076+
pub fn setup_epoch_3_reward_set(
10811077
naka_conf: &Config,
10821078
blocks_processed: &Arc<AtomicU64>,
10831079
stacker_sks: &[StacksPrivateKey],
@@ -1099,9 +1095,6 @@ pub fn boot_to_epoch_3_reward_set_calculation_boundary(
10991095
);
11001096
let epoch_3_reward_cycle_boundary =
11011097
epoch_3_start_height.saturating_sub(epoch_3_start_height % reward_cycle_len);
1102-
let epoch_3_reward_set_calculation_boundary = epoch_3_reward_cycle_boundary
1103-
.saturating_sub(prepare_phase_len)
1104-
.wrapping_add(1);
11051098
let http_origin = format!("http://{}", &naka_conf.node.rpc_bind);
11061099
next_block_and_wait(btc_regtest_controller, &blocks_processed);
11071100
next_block_and_wait(btc_regtest_controller, &blocks_processed);
@@ -1115,13 +1108,13 @@ pub fn boot_to_epoch_3_reward_set_calculation_boundary(
11151108
.block_height_to_reward_cycle(block_height)
11161109
.unwrap();
11171110
let lock_period: u128 = num_stacking_cycles.unwrap_or(12_u64).into();
1118-
debug!("Test Cycle Info";
1119-
"prepare_phase_len" => {prepare_phase_len},
1120-
"reward_cycle_len" => {reward_cycle_len},
1121-
"block_height" => {block_height},
1122-
"reward_cycle" => {reward_cycle},
1123-
"epoch_3_reward_cycle_boundary" => {epoch_3_reward_cycle_boundary},
1124-
"epoch_3_start_height" => {epoch_3_start_height},
1111+
info!("Test Cycle Info";
1112+
"prepare_phase_len" => {prepare_phase_len},
1113+
"reward_cycle_len" => {reward_cycle_len},
1114+
"block_height" => {block_height},
1115+
"reward_cycle" => {reward_cycle},
1116+
"epoch_3_reward_cycle_boundary" => {epoch_3_reward_cycle_boundary},
1117+
"epoch_3_start_height" => {epoch_3_start_height},
11251118
);
11261119
for (stacker_sk, signer_sk) in stacker_sks.iter().zip(signer_sks.iter()) {
11271120
let pox_addr = PoxAddress::from_legacy(
@@ -1165,6 +1158,44 @@ pub fn boot_to_epoch_3_reward_set_calculation_boundary(
11651158
);
11661159
submit_tx(&http_origin, &stacking_tx);
11671160
}
1161+
}
1162+
1163+
///
1164+
/// * `stacker_sks` - must be a private key for sending a large `stack-stx` transaction in order
1165+
/// for pox-4 to activate
1166+
/// * `signer_pks` - must be the same size as `stacker_sks`
1167+
pub fn boot_to_epoch_3_reward_set_calculation_boundary(
1168+
naka_conf: &Config,
1169+
blocks_processed: &Arc<AtomicU64>,
1170+
stacker_sks: &[StacksPrivateKey],
1171+
signer_sks: &[StacksPrivateKey],
1172+
btc_regtest_controller: &mut BitcoinRegtestController,
1173+
num_stacking_cycles: Option<u64>,
1174+
) {
1175+
setup_epoch_3_reward_set(
1176+
naka_conf,
1177+
blocks_processed,
1178+
stacker_sks,
1179+
signer_sks,
1180+
btc_regtest_controller,
1181+
num_stacking_cycles,
1182+
);
1183+
1184+
let epochs = naka_conf.burnchain.epochs.clone().unwrap();
1185+
let epoch_3 = &epochs[StacksEpoch::find_epoch_by_id(&epochs, StacksEpochId::Epoch30).unwrap()];
1186+
let reward_cycle_len = naka_conf.get_burnchain().pox_constants.reward_cycle_length as u64;
1187+
let prepare_phase_len = naka_conf.get_burnchain().pox_constants.prepare_length as u64;
1188+
1189+
let epoch_3_start_height = epoch_3.start_height;
1190+
assert!(
1191+
epoch_3_start_height > 0,
1192+
"Epoch 3.0 start height must be greater than 0"
1193+
);
1194+
let epoch_3_reward_cycle_boundary =
1195+
epoch_3_start_height.saturating_sub(epoch_3_start_height % reward_cycle_len);
1196+
let epoch_3_reward_set_calculation_boundary = epoch_3_reward_cycle_boundary
1197+
.saturating_sub(prepare_phase_len)
1198+
.saturating_add(1);
11681199

11691200
run_until_burnchain_height(
11701201
btc_regtest_controller,

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

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ use crate::nakamoto_node::miner::TEST_BROADCAST_STALL;
6161
use crate::neon::Counters;
6262
use crate::run_loop::boot_nakamoto;
6363
use crate::tests::nakamoto_integrations::{
64-
boot_to_epoch_25, boot_to_epoch_3_reward_set, next_block_and, wait_for,
65-
POX_4_DEFAULT_STACKER_BALANCE, POX_4_DEFAULT_STACKER_STX_AMT,
64+
boot_to_epoch_25, boot_to_epoch_3_reward_set, boot_to_epoch_3_reward_set_calculation_boundary,
65+
next_block_and, setup_epoch_3_reward_set, wait_for, POX_4_DEFAULT_STACKER_BALANCE,
66+
POX_4_DEFAULT_STACKER_STX_AMT,
6667
};
6768
use crate::tests::neon_integrations::{
6869
get_account, get_chain_info, next_block_and_wait, run_until_burnchain_height, submit_tx,
@@ -744,6 +745,119 @@ struct TenureForkingResult {
744745
mined_d: MinedNakamotoBlockEvent,
745746
}
746747

748+
#[test]
749+
#[ignore]
750+
/// Test to make sure that the signers are capable of reloading their reward set
751+
/// if the stacks-node doesn't have it available at the first block of a prepare phase (e.g., if there was no block)
752+
fn reloads_signer_set_in() {
753+
tracing_subscriber::registry()
754+
.with(fmt::layer())
755+
.with(EnvFilter::from_default_env())
756+
.init();
757+
758+
let num_signers = 5;
759+
let sender_sk = Secp256k1PrivateKey::new();
760+
let sender_addr = tests::to_addr(&sender_sk);
761+
let send_amt = 100;
762+
let send_fee = 180;
763+
let mut signer_test: SignerTest<SpawnedSigner> = SignerTest::new_with_config_modifications(
764+
num_signers,
765+
vec![(sender_addr.clone(), send_amt + send_fee)],
766+
Some(Duration::from_secs(15)),
767+
|_config| {},
768+
|_| {},
769+
&[],
770+
);
771+
772+
setup_epoch_3_reward_set(
773+
&signer_test.running_nodes.conf,
774+
&signer_test.running_nodes.blocks_processed,
775+
&signer_test.signer_stacks_private_keys,
776+
&signer_test.signer_stacks_private_keys,
777+
&mut signer_test.running_nodes.btc_regtest_controller,
778+
Some(signer_test.num_stacking_cycles),
779+
);
780+
781+
let naka_conf = &signer_test.running_nodes.conf;
782+
let epochs = naka_conf.burnchain.epochs.clone().unwrap();
783+
let epoch_3 = &epochs[StacksEpoch::find_epoch_by_id(&epochs, StacksEpochId::Epoch30).unwrap()];
784+
let reward_cycle_len = naka_conf.get_burnchain().pox_constants.reward_cycle_length as u64;
785+
let prepare_phase_len = naka_conf.get_burnchain().pox_constants.prepare_length as u64;
786+
787+
let epoch_3_start_height = epoch_3.start_height;
788+
assert!(
789+
epoch_3_start_height > 0,
790+
"Epoch 3.0 start height must be greater than 0"
791+
);
792+
let epoch_3_reward_cycle_boundary =
793+
epoch_3_start_height.saturating_sub(epoch_3_start_height % reward_cycle_len);
794+
let before_epoch_3_reward_set_calculation =
795+
epoch_3_reward_cycle_boundary.saturating_sub(prepare_phase_len);
796+
run_until_burnchain_height(
797+
&mut signer_test.running_nodes.btc_regtest_controller,
798+
&signer_test.running_nodes.blocks_processed,
799+
before_epoch_3_reward_set_calculation,
800+
naka_conf,
801+
);
802+
803+
info!("Waiting for signer set calculation.");
804+
let mut reward_set_calculated = false;
805+
let short_timeout = Duration::from_secs(30);
806+
let now = std::time::Instant::now();
807+
// Make sure the signer set is calculated before continuing or signers may not
808+
// recognize that they are registered signers in the subsequent burn block event
809+
let reward_cycle = signer_test.get_current_reward_cycle() + 1;
810+
signer_test
811+
.running_nodes
812+
.btc_regtest_controller
813+
.build_next_block(1);
814+
while !reward_set_calculated {
815+
let reward_set = signer_test
816+
.stacks_client
817+
.get_reward_set_signers(reward_cycle)
818+
.expect("Failed to check if reward set is calculated");
819+
reward_set_calculated = reward_set.is_some();
820+
if reward_set_calculated {
821+
info!("Signer set: {:?}", reward_set.unwrap());
822+
}
823+
std::thread::sleep(Duration::from_secs(1));
824+
assert!(
825+
now.elapsed() < short_timeout,
826+
"Timed out waiting for reward set calculation"
827+
);
828+
}
829+
info!("Signer set calculated");
830+
831+
// Manually consume one more block to ensure signers refresh their state
832+
info!("Waiting for signers to initialize.");
833+
next_block_and_wait(
834+
&mut signer_test.running_nodes.btc_regtest_controller,
835+
&signer_test.running_nodes.blocks_processed,
836+
);
837+
signer_test.wait_for_registered(30);
838+
info!("Signers initialized");
839+
840+
signer_test.run_until_epoch_3_boundary();
841+
842+
let commits_submitted = signer_test.running_nodes.commits_submitted.clone();
843+
844+
info!("Waiting 1 burnchain block for miner VRF key confirmation");
845+
// Wait one block to confirm the VRF register, wait until a block commit is submitted
846+
next_block_and(
847+
&mut signer_test.running_nodes.btc_regtest_controller,
848+
60,
849+
|| {
850+
let commits_count = commits_submitted.load(Ordering::SeqCst);
851+
Ok(commits_count >= 1)
852+
},
853+
)
854+
.unwrap();
855+
info!("Ready to mine Nakamoto blocks!");
856+
857+
info!("------------------------- Reached Epoch 3.0 -------------------------");
858+
signer_test.shutdown();
859+
}
860+
747861
/// This test spins up a nakamoto-neon node.
748862
/// It starts in Epoch 2.0, mines with `neon_node` to Epoch 3.0, and then switches
749863
/// to Nakamoto operation (activating pox-4 by submitting a stack-stx tx). The BootLoop

0 commit comments

Comments
 (0)