Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions stackslib/src/chainstate/coordinator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1732,6 +1732,16 @@ impl<
Ok(None)
}

/// A helper function for exposing the private process_new_pox_anchor_test function
#[cfg(test)]
pub fn process_new_pox_anchor_test(
&mut self,
block_id: BlockHeaderHash,
already_processed_burn_blocks: &mut HashSet<BurnchainHeaderHash>,
) -> Result<Option<BlockHeaderHash>, Error> {
self.process_new_pox_anchor(block_id, already_processed_burn_blocks)
}

/// Process a new PoX anchor block, possibly resulting in the PoX history being unwound and
/// replayed through a different sequence of consensus hashes. If the new anchor block causes
/// the node to reach a prepare-phase that elects a network-affirmed anchor block that we don't
Expand Down
12 changes: 5 additions & 7 deletions stackslib/src/chainstate/nakamoto/coordinator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,21 +364,19 @@ pub fn load_nakamoto_reward_set<U: RewardSetProvider>(
) -> Result<Option<(RewardCycleInfo, StacksHeaderInfo)>, Error> {
let cycle_start_height = burnchain.nakamoto_first_block_of_cycle(reward_cycle);

let epoch_30 =
SortitionDB::get_stacks_epoch_by_epoch_id(sort_db.conn(), &StacksEpochId::Epoch30)?
.unwrap_or_else(|| panic!("FATAL: no Nakamoto epoch defined"));
let epoch_at_height = SortitionDB::get_stacks_epoch(sort_db.conn(), cycle_start_height)?
.unwrap_or_else(|| {
panic!(
"FATAL: no epoch defined for burn height {}",
cycle_start_height
)
});
.unwrap_or_else(|| panic!("FATAL: no epoch defined for burn height {cycle_start_height}"));

// Find the first Stacks block in this reward cycle's preceding prepare phase.
// This block will have invoked `.signers.stackerdb-set-signer-slots()` with the reward set.
// Note that we may not have processed it yet. But, if we do find it, then it's
// unique (and since Nakamoto Stacks blocks are processed in order, the anchor block
// cannot change later).
let first_epoch30_reward_cycle = burnchain
.block_height_to_reward_cycle(epoch_at_height.start_height)
.block_height_to_reward_cycle(epoch_30.start_height)
.expect("FATAL: no reward cycle for epoch 3.0 start height");

if !epoch_at_height
Expand Down
69 changes: 69 additions & 0 deletions stackslib/src/chainstate/nakamoto/tests/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,75 @@ impl TestStacksNode {
Ok((block, size, cost))
}

/// Insert a staging pre-Nakamoto block and microblocks
/// then process them as the next ready block
/// NOTE: Will panic if called with unprocessed staging
/// blocks already in the queue.
pub fn process_pre_nakamoto_next_ready_block<'a>(
stacks_node: &mut TestStacksNode,
sortdb: &mut SortitionDB,
miner: &mut TestMiner,
tenure_id_consensus_hash: &ConsensusHash,
coord: &mut ChainsCoordinator<
'a,
TestEventObserver,
(),
OnChainRewardSetProvider<'a, TestEventObserver>,
(),
(),
BitcoinIndexer,
>,
block: &StacksBlock,
microblocks: &[StacksMicroblock],
) -> Result<Option<StacksEpochReceipt>, ChainstateError> {
// First append the block to the staging blocks
{
let ic = sortdb.index_conn();
let tip = SortitionDB::get_canonical_burn_chain_tip(&ic).unwrap();
stacks_node
.chainstate
.preprocess_stacks_epoch(&ic, &tip, block, microblocks)
.unwrap();
}

let canonical_sortition_tip = coord.canonical_sortition_tip.clone().expect(
"FAIL: processing a new Stacks block, but don't have a canonical sortition tip",
);
let mut sort_tx = sortdb.tx_begin_at_tip();
let res = stacks_node
.chainstate
.process_next_staging_block(&mut sort_tx, coord.dispatcher)
.map(|(epoch_receipt, _)| epoch_receipt)?;
sort_tx.commit()?;
if let Some(block_receipt) = res.as_ref() {
let in_sortition_set = coord
.sortition_db
.is_stacks_block_in_sortition_set(
&canonical_sortition_tip,
&block_receipt.header.anchored_header.block_hash(),
)
.unwrap();
if in_sortition_set {
let block_hash = block_receipt.header.anchored_header.block_hash();
// Was this block sufficiently confirmed by the prepare phase that it was a PoX
// anchor block? And if we're in epoch 2.1, does it match the heaviest-confirmed
// block-commit in the burnchain DB, and is it affirmed by the majority of the
// network?
if let Some(pox_anchor) = coord
.sortition_db
.is_stacks_block_pox_anchor(&block_hash, &canonical_sortition_tip)
.unwrap()
{
debug!("Discovered PoX anchor block {block_hash} off of canonical sortition tip {canonical_sortition_tip}");
coord
.process_new_pox_anchor_test(pox_anchor, &mut HashSet::new())
.unwrap();
}
}
}
Ok(res)
}

/// Insert a staging Nakamoto block as a pushed block and
/// then process it as the next ready block
/// NOTE: Will panic if called with unprocessed staging
Expand Down
Loading