Skip to content

Commit dbf0bd9

Browse files
committed
CRC: break choose_miner_directive into sep fns for sn with winner vs no winner
Signed-off-by: Jacinta Ferrant <jacinta@trustmachines.co>
1 parent 9eb307b commit dbf0bd9

File tree

1 file changed

+94
-76
lines changed

1 file changed

+94
-76
lines changed

testnet/stacks-node/src/nakamoto_node/relayer.rs

Lines changed: 94 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -504,13 +504,11 @@ impl RelayerThread {
504504
}
505505
}
506506

507-
/// Choose a miner directive based on the outcome of a sortition.
507+
/// Choose a miner directive for a sortition with a winner.
508508
///
509509
/// The decision process is a little tricky, because the right decision depends on:
510510
/// * whether or not we won the _given_ sortition (`sn`)
511511
/// * whether or not we won the sortition that started the ongoing Stacks tenure
512-
/// * whether or not we won the last sortition with a winner
513-
/// * whether or not the last sortition winner has produced a Stacks block
514512
/// * whether or not the ongoing Stacks tenure is at or descended from the last-winning
515513
/// sortition
516514
///
@@ -520,31 +518,30 @@ impl RelayerThread {
520518
/// tenure-change. Otherwise, if we won the tenure which started the ongoing Stacks tenure
521519
/// (i.e. we're the active miner), then we _may_ start mining after a timeout _if_ the winning
522520
/// miner (not us) fails to submit a `BlockFound` tenure-change block for `sn`.
523-
///
524-
/// Otherwise, if the given sortition `sn` has no winner, the find out who won the last sortition
525-
/// with a winner. If it was us, and if we haven't yet submitted a `BlockFound` tenure-change
526-
/// for it (which can happen if this given sortition is from a flash block), then start mining
527-
/// immediately with a "late" `BlockFound` tenure, _and_ prepare to start mining right afterwards
528-
/// with an `Extended` tenure-change so as to represent the given sortition `sn`'s burn view in
529-
/// the Stacks chain.
530-
///
531-
/// Otherwise, if this sortition has no winner, and we did not win the last-winning sortition,
532-
/// then check to see if we're the ongoing Stack's tenure's miner. If so, then we _may_ start
533-
/// mining after a timeout _if_ the winner of the last-good sortition (not us) fails to submit
534-
/// a `BlockFound` tenure-change block. This can happen if `sn` was a flash block, and the
535-
/// remote miner has yet to process it.
536-
///
537-
/// We won't always be able to mine -- for example, this could be an empty sortition, but the
538-
/// parent block could be an epoch 2 block. In this case, the right thing to do is to wait for
539-
/// the next block-commit.
540-
pub(crate) fn choose_miner_directive(
521+
fn choose_directive_sortition_with_winner(
541522
&mut self,
542523
sn: BlockSnapshot,
543-
won_sortition: bool,
524+
mining_pk: Hash160,
544525
committed_index_hash: StacksBlockId,
545526
) -> Option<MinerDirective> {
546-
// Reset the tenure extend time as we need to process this new sortition to deterine if we should extend
547-
self.tenure_extend_time = None;
527+
let won_sortition = sn.miner_pk_hash == Some(mining_pk);
528+
if won_sortition || self.config.get_node_config(false).mock_mining {
529+
// a sortition happenend, and we won
530+
info!("Won sortition; begin tenure.";
531+
"winning_sortition" => %sn.consensus_hash);
532+
return Some(MinerDirective::BeginTenure {
533+
parent_tenure_start: committed_index_hash,
534+
burnchain_tip: sn.clone(),
535+
election_block: sn,
536+
late: false,
537+
});
538+
}
539+
540+
// a sortition happened, but we didn't win. Check if we won the ongoing tenure.
541+
debug!(
542+
"Relayer: did not win sortition {}, so stopping tenure",
543+
&sn.sortition
544+
);
548545
let (canonical_stacks_tip_ch, _) =
549546
SortitionDB::get_canonical_stacks_chain_tip_hash(self.sortdb.conn())
550547
.expect("FATAL: failed to query sortition DB for stacks tip");
@@ -553,56 +550,68 @@ impl RelayerThread {
553550
.expect("FATAL: failed to query sortiiton DB for epoch")
554551
.expect("FATAL: no sortition for canonical stacks tip");
555552

556-
let mining_pkh_opt = self.get_mining_key_pkh();
557-
558553
let won_ongoing_tenure_sortition =
559-
mining_pkh_opt.is_some() && canonical_stacks_snapshot.miner_pk_hash == mining_pkh_opt;
560-
561-
if sn.sortition {
562-
// a sortition happened
563-
if won_sortition || self.config.get_node_config(false).mock_mining {
564-
// a sortition happenend, and we won
565-
info!("Relayer: Won sortition; begin tenure.";
566-
"winning_sortition" => %sn.consensus_hash);
567-
return Some(MinerDirective::BeginTenure {
568-
parent_tenure_start: committed_index_hash,
569-
burnchain_tip: sn.clone(),
570-
election_block: sn,
571-
late: false,
572-
});
573-
}
574-
575-
// a sortition happened, but we didn't win.
576-
debug!(
577-
"Relayer: did not win sortition {}, so stopping tenure",
578-
&sn.sortition
579-
);
580-
581-
if won_ongoing_tenure_sortition {
582-
// we won the current ongoing tenure, but not the most recent sortition. Should we attempt to extend immediately or wait for the incoming miner?
583-
if let Ok(result) = Self::find_highest_valid_sortition(
584-
&self.sortdb,
585-
&mut self.chainstate,
586-
&sn,
587-
&canonical_stacks_snapshot.consensus_hash,
588-
) {
589-
if result.is_some() {
590-
debug!("Relayer: Did not win current sortition but won the prior valid sortition. Will attempt to extend tenure after allowing the new miner some time to come online.";
591-
"tenure_extend_wait_timeout_ms" => self.config.miner.tenure_extend_wait_timeout.as_millis(),
592-
);
593-
self.tenure_extend_time = Some(TenureExtendTime::delayed(
594-
self.config.miner.tenure_extend_wait_timeout,
595-
));
596-
} else {
597-
info!("Relayer: no valid sortition since our last winning sortition. Will extend tenure.");
598-
self.tenure_extend_time = Some(TenureExtendTime::immediate());
599-
}
554+
canonical_stacks_snapshot.miner_pk_hash == Some(mining_pk);
555+
if won_ongoing_tenure_sortition {
556+
// we won the current ongoing tenure, but not the most recent sortition. Should we attempt to extend immediately or wait for the incoming miner?
557+
if let Ok(result) = Self::find_highest_valid_sortition(
558+
&self.sortdb,
559+
&mut self.chainstate,
560+
&sn,
561+
&canonical_stacks_snapshot.consensus_hash,
562+
) {
563+
if result.is_some() {
564+
debug!("Relayer: Did not win current sortition but won the prior valid sortition. Will attempt to extend tenure after allowing the new miner some time to come online.";
565+
"tenure_extend_wait_timeout_ms" => self.config.miner.tenure_extend_wait_timeout.as_millis(),
566+
);
567+
self.tenure_extend_time = Some(TenureExtendTime::delayed(
568+
self.config.miner.tenure_extend_wait_timeout,
569+
));
570+
} else {
571+
info!("Relayer: no valid sortition since our last winning sortition. Will extend tenure.");
572+
self.tenure_extend_time = Some(TenureExtendTime::immediate());
600573
}
601574
}
602-
return Some(MinerDirective::StopTenure);
603575
}
576+
return Some(MinerDirective::StopTenure);
577+
}
578+
579+
/// Choose a miner directive for a sortition with no winner.
580+
///
581+
/// The decision process is a little tricky, because the right decision depends on:
582+
/// * whether or not we won the sortition that started the ongoing Stacks tenure
583+
/// * whether or not we won the last sortition with a winner
584+
/// * whether or not the last sortition winner has produced a Stacks block
585+
/// * whether or not the ongoing Stacks tenure is at or descended from the last-winning
586+
/// sortition
587+
///
588+
/// Find out who won the last sortition with a winner. If it was us, and if we haven't yet
589+
/// submitted a `BlockFound` tenure-change for it (which can happen if this given sortition is
590+
/// from a flash block), then start mining immediately with a "late" `BlockFound` tenure, _and_
591+
/// prepare to start mining right afterwards with an `Extended` tenure-change so as to represent
592+
/// the given sortition `sn`'s burn view in the Stacks chain.
593+
///
594+
/// Otherwise, if did not win the last-winning sortition, then check to see if we're the ongoing
595+
/// Stack's tenure's miner. If so, then we _may_ start mining after a timeout _if_ the winner of
596+
/// the last-good sortition (not us) fails to submit a `BlockFound` tenure-change block.
597+
/// This can happen if `sn` was a flash block, and the remote miner has yet to process it.
598+
///
599+
/// We won't always be able to mine -- for example, this could be an empty sortition, but the
600+
/// parent block could be an epoch 2 block. In this case, the right thing to do is to wait for
601+
/// the next block-commit.
602+
fn choose_directive_sortition_without_winner(
603+
&mut self,
604+
sn: BlockSnapshot,
605+
mining_pk: Hash160,
606+
) -> Option<MinerDirective> {
607+
let (canonical_stacks_tip_ch, _) =
608+
SortitionDB::get_canonical_stacks_chain_tip_hash(self.sortdb.conn())
609+
.expect("FATAL: failed to query sortition DB for stacks tip");
610+
let canonical_stacks_snapshot =
611+
SortitionDB::get_block_snapshot_consensus(self.sortdb.conn(), &canonical_stacks_tip_ch)
612+
.expect("FATAL: failed to query sortiiton DB for epoch")
613+
.expect("FATAL: no sortition for canonical stacks tip");
604614

605-
// no sortition happened.
606615
// find out what epoch the Stacks tip is in.
607616
// If it's in epoch 2.x, then we must always begin a new tenure, but we can't do so
608617
// right now since this sortition has no winner.
@@ -632,9 +641,7 @@ impl RelayerThread {
632641
return None;
633642
};
634643

635-
let won_last_winning_snapshot =
636-
mining_pkh_opt.is_some() && last_winning_snapshot.miner_pk_hash == mining_pkh_opt;
637-
644+
let won_last_winning_snapshot = last_winning_snapshot.miner_pk_hash == Some(mining_pk);
638645
if won_last_winning_snapshot {
639646
debug!(
640647
"Relayer: we won the last winning sortition {}",
@@ -657,8 +664,8 @@ impl RelayerThread {
657664
late: true,
658665
});
659666
}
660-
let tip_is_last_winning_snapshot = mining_pkh_opt.is_some()
661-
&& canonical_stacks_snapshot.block_height == last_winning_snapshot.block_height
667+
let tip_is_last_winning_snapshot = canonical_stacks_snapshot.block_height
668+
== last_winning_snapshot.block_height
662669
&& canonical_stacks_snapshot.consensus_hash == last_winning_snapshot.consensus_hash;
663670

664671
if tip_is_last_winning_snapshot {
@@ -671,6 +678,8 @@ impl RelayerThread {
671678
}
672679
}
673680

681+
let won_ongoing_tenure_sortition =
682+
canonical_stacks_snapshot.miner_pk_hash == Some(mining_pk);
674683
if won_ongoing_tenure_sortition {
675684
info!("Relayer: No sortition, but we produced the canonical Stacks tip. Will extend tenure.");
676685
if !won_last_winning_snapshot {
@@ -818,8 +827,17 @@ impl RelayerThread {
818827
.raise_initiative("process_sortition".to_string());
819828
return Ok(None);
820829
}
821-
822-
let directive_opt = self.choose_miner_directive(sn, won_sortition, committed_index_hash);
830+
// Reset the tenure extend time
831+
self.tenure_extend_time = None;
832+
let Some(mining_pk) = self.get_mining_key_pkh() else {
833+
debug!("No mining key, will not mine");
834+
return Ok(None);
835+
};
836+
let directive_opt = if sn.sortition {
837+
self.choose_directive_sortition_with_winner(sn, mining_pk, committed_index_hash)
838+
} else {
839+
self.choose_directive_sortition_without_winner(sn, mining_pk)
840+
};
823841
debug!(
824842
"Relayer: Processed sortition {}: Miner directive is {:?}",
825843
&consensus_hash, &directive_opt

0 commit comments

Comments
 (0)