Skip to content

Commit 42fd891

Browse files
authored
Merge pull request #5072 from stacks-network/feat/pox-4-tests-nakamoto
Update pox_4_tests to run in 2.5 and 3.0
2 parents f3e264b + 1668fae commit 42fd891

File tree

28 files changed

+1139
-539
lines changed

28 files changed

+1139
-539
lines changed

stacks-common/src/types/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ pub enum StacksEpochId {
8282
Epoch30 = 0x03000,
8383
}
8484

85+
#[derive(Debug)]
8586
pub enum MempoolCollectionBehavior {
8687
ByStacksHeight,
8788
ByReceiveTime,

stackslib/src/burnchains/burnchain.rs

Lines changed: 31 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -549,47 +549,43 @@ impl Burnchain {
549549
.expect("Overflowed u64 in calculating expected sunset_burn")
550550
}
551551

552+
/// Is this the first block to receive rewards in its cycle?
553+
/// This is the mod 1 block. Note: in nakamoto, the signer set for cycle N signs
554+
/// the mod 0 block.
552555
pub fn is_reward_cycle_start(&self, burn_height: u64) -> bool {
553556
self.pox_constants
554557
.is_reward_cycle_start(self.first_block_height, burn_height)
555558
}
556559

560+
/// Is this the first block to be signed by the signer set in cycle N?
561+
/// This is the mod 0 block.
562+
pub fn is_naka_signing_cycle_start(&self, burn_height: u64) -> bool {
563+
self.pox_constants
564+
.is_naka_signing_cycle_start(self.first_block_height, burn_height)
565+
}
566+
567+
/// return the first burn block which receives reward in `reward_cycle`.
568+
/// this is the modulo 1 block
557569
pub fn reward_cycle_to_block_height(&self, reward_cycle: u64) -> u64 {
558570
self.pox_constants
559571
.reward_cycle_to_block_height(self.first_block_height, reward_cycle)
560572
}
561573

562-
/// Compute the reward cycle ID of the PoX reward set which is active as of this burn_height.
563-
/// The reward set is calculated at reward cycle index 1, so if this block height is at or after
564-
/// reward cycle index 1, then this behaves like `block_height_to_reward_cycle()`. However,
565-
/// if it's reward cycle index is 0, then it belongs to the previous reward cycle.
566-
pub fn pox_reward_cycle(&self, block_height: u64) -> Option<u64> {
567-
let cycle = self.block_height_to_reward_cycle(block_height)?;
568-
let effective_height = block_height.checked_sub(self.first_block_height)?;
569-
if effective_height % u64::from(self.pox_constants.reward_cycle_length) == 0 {
570-
Some(cycle.saturating_sub(1))
571-
} else {
572-
Some(cycle)
573-
}
574+
/// the first burn block that must be *signed* by the signer set of `reward_cycle`.
575+
/// this is the modulo 0 block
576+
pub fn nakamoto_first_block_of_cycle(&self, reward_cycle: u64) -> u64 {
577+
self.pox_constants
578+
.nakamoto_first_block_of_cycle(self.first_block_height, reward_cycle)
574579
}
575580

581+
/// What is the reward cycle for this block height?
582+
/// This considers the modulo 0 block to be in reward cycle `n`, even though
583+
/// rewards for cycle `n` do not begin until modulo 1.
576584
pub fn block_height_to_reward_cycle(&self, block_height: u64) -> Option<u64> {
577585
self.pox_constants
578586
.block_height_to_reward_cycle(self.first_block_height, block_height)
579587
}
580588

581-
pub fn static_block_height_to_reward_cycle(
582-
block_height: u64,
583-
first_block_height: u64,
584-
reward_cycle_length: u64,
585-
) -> Option<u64> {
586-
PoxConstants::static_block_height_to_reward_cycle(
587-
block_height,
588-
first_block_height,
589-
reward_cycle_length,
590-
)
591-
}
592-
593589
/// Is this block either the first block in a reward cycle or
594590
/// right before the reward phase starts? This is the mod 0 or mod 1
595591
/// block. Reward cycle start events (like auto-unlocks) process *after*
@@ -607,27 +603,19 @@ impl Burnchain {
607603
(effective_height % reward_cycle_length) <= 1
608604
}
609605

610-
pub fn static_is_in_prepare_phase(
611-
first_block_height: u64,
612-
reward_cycle_length: u64,
613-
prepare_length: u64,
614-
block_height: u64,
615-
) -> bool {
616-
PoxConstants::static_is_in_prepare_phase(
617-
first_block_height,
618-
reward_cycle_length,
619-
prepare_length,
620-
block_height,
621-
)
606+
/// Does this block include reward slots?
607+
/// This is either in the last prepare_phase_length blocks of the cycle
608+
/// or the modulo 0 block
609+
pub fn is_in_prepare_phase(&self, block_height: u64) -> bool {
610+
self.pox_constants
611+
.is_in_prepare_phase(self.first_block_height, block_height)
622612
}
623613

624-
pub fn is_in_prepare_phase(&self, block_height: u64) -> bool {
625-
Self::static_is_in_prepare_phase(
626-
self.first_block_height,
627-
self.pox_constants.reward_cycle_length as u64,
628-
self.pox_constants.prepare_length.into(),
629-
block_height,
630-
)
614+
/// The prepare phase is the last prepare_phase_length blocks of the cycle
615+
/// This cannot include the 0 block for nakamoto
616+
pub fn is_in_naka_prepare_phase(&self, block_height: u64) -> bool {
617+
self.pox_constants
618+
.is_in_naka_prepare_phase(self.first_block_height, block_height)
631619
}
632620

633621
pub fn regtest(working_dir: &str) -> Burnchain {

stackslib/src/burnchains/mod.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ impl PoxConstants {
517517
}
518518
}
519519

520-
/// What's the first block in the prepare phase
520+
/// The first block of the prepare phase during `reward_cycle`. This is the prepare phase _for the next cycle_.
521521
pub fn prepare_phase_start(&self, first_block_height: u64, reward_cycle: u64) -> u64 {
522522
let reward_cycle_start =
523523
self.reward_cycle_to_block_height(first_block_height, reward_cycle);
@@ -526,18 +526,37 @@ impl PoxConstants {
526526
prepare_phase_start
527527
}
528528

529+
/// Is this the first block to receive rewards in its cycle?
530+
/// This is the mod 1 block. Note: in nakamoto, the signer set for cycle N signs
531+
/// the mod 0 block.
529532
pub fn is_reward_cycle_start(&self, first_block_height: u64, burn_height: u64) -> bool {
530533
let effective_height = burn_height - first_block_height;
531534
// first block of the new reward cycle
532535
(effective_height % u64::from(self.reward_cycle_length)) == 1
533536
}
534537

538+
/// Is this the first block to be signed by the signer set in cycle N?
539+
/// This is the mod 0 block.
540+
pub fn is_naka_signing_cycle_start(&self, first_block_height: u64, burn_height: u64) -> bool {
541+
let effective_height = burn_height - first_block_height;
542+
// first block of the new reward cycle
543+
(effective_height % u64::from(self.reward_cycle_length)) == 0
544+
}
545+
546+
/// return the first burn block which receives reward in `reward_cycle`.
547+
/// this is the modulo 1 block
535548
pub fn reward_cycle_to_block_height(&self, first_block_height: u64, reward_cycle: u64) -> u64 {
536549
// NOTE: the `+ 1` is because the height of the first block of a reward cycle is mod 1, not
537550
// mod 0.
538551
first_block_height + reward_cycle * u64::from(self.reward_cycle_length) + 1
539552
}
540553

554+
/// the first burn block that must be *signed* by the signer set of `reward_cycle`.
555+
/// this is the modulo 0 block
556+
pub fn nakamoto_first_block_of_cycle(&self, first_block_height: u64, reward_cycle: u64) -> u64 {
557+
first_block_height + reward_cycle * u64::from(self.reward_cycle_length)
558+
}
559+
541560
pub fn reward_cycle_index(&self, first_block_height: u64, burn_height: u64) -> Option<u64> {
542561
let effective_height = burn_height.checked_sub(first_block_height)?;
543562
Some(effective_height % u64::from(self.reward_cycle_length))
@@ -609,6 +628,35 @@ impl PoxConstants {
609628
}
610629
}
611630

631+
/// The prepare phase is the last prepare_phase_length blocks of the cycle
632+
/// This cannot include the 0 block for nakamoto
633+
pub fn is_in_naka_prepare_phase(&self, first_block_height: u64, block_height: u64) -> bool {
634+
Self::static_is_in_naka_prepare_phase(
635+
first_block_height,
636+
u64::from(self.reward_cycle_length),
637+
u64::from(self.prepare_length),
638+
block_height,
639+
)
640+
}
641+
642+
/// The prepare phase is the last prepare_phase_length blocks of the cycle
643+
/// This cannot include the 0 block for nakamoto
644+
pub fn static_is_in_naka_prepare_phase(
645+
first_block_height: u64,
646+
reward_cycle_length: u64,
647+
prepare_length: u64,
648+
block_height: u64,
649+
) -> bool {
650+
if block_height <= first_block_height {
651+
// not a reward cycle start if we're the first block after genesis.
652+
false
653+
} else {
654+
let effective_height = block_height - first_block_height;
655+
let reward_index = effective_height % reward_cycle_length;
656+
reward_index > u64::from(reward_cycle_length - prepare_length)
657+
}
658+
}
659+
612660
/// Returns the active reward cycle at the given burn block height
613661
/// * `first_block_ht` - the first burn block height that the Stacks network monitored
614662
/// * `reward_cycle_len` - the length of each reward cycle in the network.

stackslib/src/chainstate/burn/db/sortdb.rs

Lines changed: 9 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -3584,42 +3584,6 @@ impl SortitionDB {
35843584
Ok(())
35853585
}
35863586

3587-
/// Get the prepare phase end sortition ID of a reward cycle. This is the last prepare
3588-
/// phase sortition for the prepare phase that began this reward cycle (i.e. the returned
3589-
/// sortition will be in the preceding reward cycle)
3590-
/// Wrapper around SortitionDBConn::get_prepare_phase_end_sortition_id_for_reward_ccyle()
3591-
pub fn get_prepare_phase_end_sortition_id_for_reward_cycle(
3592-
&self,
3593-
tip: &SortitionId,
3594-
reward_cycle_id: u64,
3595-
) -> Result<SortitionId, db_error> {
3596-
self.index_conn()
3597-
.get_prepare_phase_end_sortition_id_for_reward_cycle(
3598-
&self.pox_constants,
3599-
self.first_block_height,
3600-
tip,
3601-
reward_cycle_id,
3602-
)
3603-
}
3604-
3605-
/// Get the prepare phase start sortition ID of a reward cycle. This is the first prepare
3606-
/// phase sortition for the prepare phase that began this reward cycle (i.e. the returned
3607-
/// sortition will be in the preceding reward cycle)
3608-
/// Wrapper around SortitionDBConn::get_prepare_phase_start_sortition_id_for_reward_cycle().
3609-
pub fn get_prepare_phase_start_sortition_id_for_reward_cycle(
3610-
&self,
3611-
tip: &SortitionId,
3612-
reward_cycle_id: u64,
3613-
) -> Result<SortitionId, db_error> {
3614-
self.index_conn()
3615-
.get_prepare_phase_start_sortition_id_for_reward_cycle(
3616-
&self.pox_constants,
3617-
self.first_block_height,
3618-
tip,
3619-
reward_cycle_id,
3620-
)
3621-
}
3622-
36233587
/// Figure out the reward cycle for `tip` and lookup the preprocessed
36243588
/// reward set (if it exists) for the active reward cycle during `tip`.
36253589
/// Returns the reward cycle info on success.
@@ -3934,33 +3898,6 @@ impl<'a> SortitionDBConn<'a> {
39343898
.and_then(|(reward_cycle_info, _anchor_sortition_id)| Ok(reward_cycle_info))
39353899
}
39363900

3937-
/// Get the prepare phase end sortition ID of a reward cycle. This is the last prepare
3938-
/// phase sortition for the prepare phase that began this reward cycle (i.e. the returned
3939-
/// sortition will be in the preceding reward cycle)
3940-
pub fn get_prepare_phase_end_sortition_id_for_reward_cycle(
3941-
&self,
3942-
pox_constants: &PoxConstants,
3943-
first_block_height: u64,
3944-
tip: &SortitionId,
3945-
reward_cycle_id: u64,
3946-
) -> Result<SortitionId, db_error> {
3947-
let prepare_phase_end = pox_constants
3948-
.reward_cycle_to_block_height(first_block_height, reward_cycle_id)
3949-
.saturating_sub(1);
3950-
3951-
let last_sortition =
3952-
get_ancestor_sort_id(self, prepare_phase_end, tip)?.ok_or_else(|| {
3953-
error!(
3954-
"Could not find prepare phase end ancestor while fetching reward set";
3955-
"tip_sortition_id" => %tip,
3956-
"reward_cycle_id" => reward_cycle_id,
3957-
"prepare_phase_end_height" => prepare_phase_end
3958-
);
3959-
db_error::NotFoundError
3960-
})?;
3961-
Ok(last_sortition)
3962-
}
3963-
39643901
/// Get the prepare phase start sortition ID of a reward cycle. This is the first prepare
39653902
/// phase sortition for the prepare phase that began this reward cycle (i.e. the returned
39663903
/// sortition will be in the preceding reward cycle)
@@ -3971,9 +3908,11 @@ impl<'a> SortitionDBConn<'a> {
39713908
tip: &SortitionId,
39723909
reward_cycle_id: u64,
39733910
) -> Result<SortitionId, db_error> {
3974-
let prepare_phase_start = pox_constants
3975-
.reward_cycle_to_block_height(first_block_height, reward_cycle_id)
3976-
.saturating_sub(pox_constants.prepare_length.into());
3911+
let reward_cycle_of_prepare_phase = reward_cycle_id
3912+
.checked_sub(1)
3913+
.ok_or_else(|| db_error::Other("No prepare phase exists for cycle 0".into()))?;
3914+
let prepare_phase_start =
3915+
pox_constants.prepare_phase_start(first_block_height, reward_cycle_of_prepare_phase);
39773916

39783917
let first_sortition =
39793918
get_ancestor_sort_id(self, prepare_phase_start, tip)?.ok_or_else(|| {
@@ -5945,10 +5884,10 @@ impl<'a> SortitionHandleTx<'a> {
59455884

59465885
/// Get the expected number of PoX payouts per output
59475886
fn get_num_pox_payouts(&self, burn_block_height: u64) -> usize {
5948-
let op_num_outputs = if Burnchain::static_is_in_prepare_phase(
5887+
let op_num_outputs = if PoxConstants::static_is_in_prepare_phase(
59495888
self.context.first_block_height,
5950-
self.context.pox_constants.reward_cycle_length as u64,
5951-
self.context.pox_constants.prepare_length.into(),
5889+
u64::from(self.context.pox_constants.reward_cycle_length),
5890+
u64::from(self.context.pox_constants.prepare_length),
59525891
burn_block_height,
59535892
) {
59545893
1
@@ -6173,7 +6112,7 @@ impl<'a> SortitionHandleTx<'a> {
61736112
}
61746113
// if there are qualifying auto-unlocks, record them
61756114
if !reward_set.start_cycle_state.is_empty() {
6176-
let cycle_number = Burnchain::static_block_height_to_reward_cycle(
6115+
let cycle_number = PoxConstants::static_block_height_to_reward_cycle(
61776116
snapshot.block_height,
61786117
self.context.first_block_height,
61796118
self.context.pox_constants.reward_cycle_length.into(),

stackslib/src/chainstate/coordinator/mod.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,8 @@ pub trait RewardSetProvider {
297297

298298
fn get_reward_set_nakamoto(
299299
&self,
300-
cycle_start_burn_height: u64,
301300
chainstate: &mut StacksChainState,
302-
burnchain: &Burnchain,
301+
cycle: u64,
303302
sortdb: &SortitionDB,
304303
block_id: &StacksBlockId,
305304
) -> Result<RewardSet, Error>;
@@ -372,20 +371,12 @@ impl<'a, T: BlockEventDispatcher> RewardSetProvider for OnChainRewardSetProvider
372371

373372
fn get_reward_set_nakamoto(
374373
&self,
375-
cycle_start_burn_height: u64,
376374
chainstate: &mut StacksChainState,
377-
burnchain: &Burnchain,
375+
reward_cycle: u64,
378376
sortdb: &SortitionDB,
379377
block_id: &StacksBlockId,
380378
) -> Result<RewardSet, Error> {
381-
self.read_reward_set_nakamoto(
382-
cycle_start_burn_height,
383-
chainstate,
384-
burnchain,
385-
sortdb,
386-
block_id,
387-
false,
388-
)
379+
self.read_reward_set_nakamoto(chainstate, reward_cycle, sortdb, block_id, false)
389380
}
390381
}
391382

stackslib/src/chainstate/coordinator/tests.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,9 +520,8 @@ impl RewardSetProvider for StubbedRewardSetProvider {
520520

521521
fn get_reward_set_nakamoto(
522522
&self,
523-
cycle_start_burn_height: u64,
524523
chainstate: &mut StacksChainState,
525-
burnchain: &Burnchain,
524+
cycle: u64,
526525
sortdb: &SortitionDB,
527526
block_id: &StacksBlockId,
528527
) -> Result<RewardSet, CoordError> {

0 commit comments

Comments
 (0)