Skip to content

Commit 86e4e60

Browse files
committed
Add support for pre naka blocks
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent 1c7bf30 commit 86e4e60

9 files changed

+764
-350
lines changed

stackslib/src/chainstate/coordinator/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,16 @@ impl<
17321732
Ok(None)
17331733
}
17341734

1735+
/// A helper function for exposing the private process_new_pox_anchor_test function
1736+
#[cfg(test)]
1737+
pub fn process_new_pox_anchor_test(
1738+
&mut self,
1739+
block_id: BlockHeaderHash,
1740+
already_processed_burn_blocks: &mut HashSet<BurnchainHeaderHash>,
1741+
) -> Result<Option<BlockHeaderHash>, Error> {
1742+
self.process_new_pox_anchor(block_id, already_processed_burn_blocks)
1743+
}
1744+
17351745
/// Process a new PoX anchor block, possibly resulting in the PoX history being unwound and
17361746
/// replayed through a different sequence of consensus hashes. If the new anchor block causes
17371747
/// the node to reach a prepare-phase that elects a network-affirmed anchor block that we don't

stackslib/src/chainstate/nakamoto/coordinator/mod.rs

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -363,28 +363,27 @@ pub fn load_nakamoto_reward_set<U: RewardSetProvider>(
363363
provider: &U,
364364
) -> Result<Option<(RewardCycleInfo, StacksHeaderInfo)>, Error> {
365365
let cycle_start_height = burnchain.nakamoto_first_block_of_cycle(reward_cycle);
366-
367366
let epoch_at_height = SortitionDB::get_stacks_epoch(sort_db.conn(), cycle_start_height)?
368-
.unwrap_or_else(|| {
369-
panic!(
370-
"FATAL: no epoch defined for burn height {}",
371-
cycle_start_height
372-
)
373-
});
374-
375-
// Find the first Stacks block in this reward cycle's preceding prepare phase.
376-
// This block will have invoked `.signers.stackerdb-set-signer-slots()` with the reward set.
377-
// Note that we may not have processed it yet. But, if we do find it, then it's
378-
// unique (and since Nakamoto Stacks blocks are processed in order, the anchor block
379-
// cannot change later).
380-
let first_epoch30_reward_cycle = burnchain
381-
.block_height_to_reward_cycle(epoch_at_height.start_height)
382-
.expect("FATAL: no reward cycle for epoch 3.0 start height");
383-
384-
if !epoch_at_height
385-
.epoch_id
386-
.uses_nakamoto_reward_set(reward_cycle, first_epoch30_reward_cycle)
387-
{
367+
.unwrap_or_else(|| panic!("FATAL: no epoch defined for burn height {cycle_start_height}"));
368+
let is_pre_naka_epoch = if epoch_at_height.epoch_id < StacksEpochId::Epoch30 {
369+
true
370+
} else {
371+
let epoch_30 =
372+
SortitionDB::get_stacks_epoch_by_epoch_id(sort_db.conn(), &StacksEpochId::Epoch30)?
373+
.unwrap_or_else(|| panic!("FATAL: no Nakamoto epoch defined"));
374+
// Find the first Stacks block in this reward cycle's preceding prepare phase.
375+
// This block will have invoked `.signers.stackerdb-set-signer-slots()` with the reward set.
376+
// Note that we may not have processed it yet. But, if we do find it, then it's
377+
// unique (and since Nakamoto Stacks blocks are processed in order, the anchor block
378+
// cannot change later).
379+
let first_epoch30_reward_cycle = burnchain
380+
.block_height_to_reward_cycle(epoch_30.start_height)
381+
.expect("FATAL: no reward cycle for epoch 3.0 start height");
382+
!epoch_at_height
383+
.epoch_id
384+
.uses_nakamoto_reward_set(reward_cycle, first_epoch30_reward_cycle)
385+
};
386+
if is_pre_naka_epoch {
388387
// in epoch 2.5, and in the first reward cycle of epoch 3.0, the reward set can *only* be found in the sortition DB.
389388
// The nakamoto chain-processing rules aren't active yet, so we can't look for the reward
390389
// cycle info in the nakamoto chain state.

stackslib/src/chainstate/nakamoto/tests/node.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,75 @@ impl TestStacksNode {
10611061
Ok((block, size, cost))
10621062
}
10631063

1064+
/// Insert a staging pre-Nakamoto block and microblocks
1065+
/// then process them as the next ready block
1066+
/// NOTE: Will panic if called with unprocessed staging
1067+
/// blocks already in the queue.
1068+
pub fn process_pre_nakamoto_next_ready_block<'a>(
1069+
stacks_node: &mut TestStacksNode,
1070+
sortdb: &mut SortitionDB,
1071+
miner: &mut TestMiner,
1072+
tenure_id_consensus_hash: &ConsensusHash,
1073+
coord: &mut ChainsCoordinator<
1074+
'a,
1075+
TestEventObserver,
1076+
(),
1077+
OnChainRewardSetProvider<'a, TestEventObserver>,
1078+
(),
1079+
(),
1080+
BitcoinIndexer,
1081+
>,
1082+
block: &StacksBlock,
1083+
microblocks: &[StacksMicroblock],
1084+
) -> Result<Option<StacksEpochReceipt>, ChainstateError> {
1085+
// First append the block to the staging blocks
1086+
{
1087+
let ic = sortdb.index_conn();
1088+
let tip = SortitionDB::get_canonical_burn_chain_tip(&ic).unwrap();
1089+
stacks_node
1090+
.chainstate
1091+
.preprocess_stacks_epoch(&ic, &tip, block, microblocks)
1092+
.unwrap();
1093+
}
1094+
1095+
let canonical_sortition_tip = coord.canonical_sortition_tip.clone().expect(
1096+
"FAIL: processing a new Stacks block, but don't have a canonical sortition tip",
1097+
);
1098+
let mut sort_tx = sortdb.tx_begin_at_tip();
1099+
let res = stacks_node
1100+
.chainstate
1101+
.process_next_staging_block(&mut sort_tx, coord.dispatcher)
1102+
.map(|(epoch_receipt, _)| epoch_receipt)?;
1103+
sort_tx.commit()?;
1104+
if let Some(block_receipt) = res.as_ref() {
1105+
let in_sortition_set = coord
1106+
.sortition_db
1107+
.is_stacks_block_in_sortition_set(
1108+
&canonical_sortition_tip,
1109+
&block_receipt.header.anchored_header.block_hash(),
1110+
)
1111+
.unwrap();
1112+
if in_sortition_set {
1113+
let block_hash = block_receipt.header.anchored_header.block_hash();
1114+
// Was this block sufficiently confirmed by the prepare phase that it was a PoX
1115+
// anchor block? And if we're in epoch 2.1, does it match the heaviest-confirmed
1116+
// block-commit in the burnchain DB, and is it affirmed by the majority of the
1117+
// network?
1118+
if let Some(pox_anchor) = coord
1119+
.sortition_db
1120+
.is_stacks_block_pox_anchor(&block_hash, &canonical_sortition_tip)
1121+
.unwrap()
1122+
{
1123+
debug!("Discovered PoX anchor block {block_hash} off of canonical sortition tip {canonical_sortition_tip}");
1124+
coord
1125+
.process_new_pox_anchor_test(pox_anchor, &mut HashSet::new())
1126+
.unwrap();
1127+
}
1128+
}
1129+
}
1130+
Ok(res)
1131+
}
1132+
10641133
/// Insert a staging Nakamoto block as a pushed block and
10651134
/// then process it as the next ready block
10661135
/// NOTE: Will panic if called with unprocessed staging

0 commit comments

Comments
 (0)