Skip to content

Commit f31752f

Browse files
committed
fix: tenure downloader reward set error #6234
1 parent 3f1966d commit f31752f

File tree

4 files changed

+352
-46
lines changed

4 files changed

+352
-46
lines changed

stackslib/src/net/download/nakamoto/download_state_machine.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ use crate::chainstate::stacks::db::StacksChainState;
2828
use crate::net::chat::ConversationP2P;
2929
use crate::net::connection::ConnectionOptions;
3030
use crate::net::download::nakamoto::{
31-
downloader_block_height_to_reward_cycle, AvailableTenures, NakamotoTenureDownloader,
32-
NakamotoTenureDownloaderSet, NakamotoUnconfirmedTenureDownloader, TenureStartEnd, WantedTenure,
31+
AvailableTenures, NakamotoTenureDownloader, NakamotoTenureDownloaderSet,
32+
NakamotoUnconfirmedTenureDownloader, TenureStartEnd, WantedTenure,
3333
};
3434
use crate::net::inv::nakamoto::NakamotoTenureInv;
3535
use crate::net::neighbors::rpc::NeighborRPC;
@@ -122,6 +122,21 @@ impl NakamotoDownloadStateMachine {
122122
}
123123
}
124124

125+
/// Return the reward cycle which could be confirmed by a nakamoto block commit
126+
/// in burn block height `burn_height`.
127+
///
128+
/// Nakamoto block commits point at the parent of the tenure that
129+
/// starts at `burn_height`. Therefore, a commit at height N
130+
/// could confirm a tenure in the reward cycle active at height
131+
/// `N-1`.
132+
fn get_confirmable_reward_cycle(
133+
pox_constants: &PoxConstants,
134+
first_burn_height: u64,
135+
burn_height: u64,
136+
) -> Option<u64> {
137+
pox_constants.block_height_to_reward_cycle(first_burn_height, burn_height.saturating_sub(1))
138+
}
139+
125140
/// Get a range of wanted tenures between two burnchain blocks.
126141
/// Each wanted tenure's .processed flag will be set to false.
127142
///
@@ -220,7 +235,13 @@ impl NakamotoDownloadStateMachine {
220235
sortdb: &SortitionDB,
221236
loaded_so_far: &[WantedTenure],
222237
) -> Result<Vec<WantedTenure>, NetError> {
223-
let tip_rc = downloader_block_height_to_reward_cycle(
238+
// we want tenures that are *confirmable* from the current sortition tip.
239+
// any miner commitment chosen in the sortition tip confirms a tenure with a lower
240+
// block height, so only consider the reward cycle at height - 1.
241+
// *Note: its possible that a the second or later sortition of a RC also confirms a tenure
242+
// in the previous RC, but for the purposes of the wanted tenures calculations, we only
243+
// are loading up wanted tenures in the current RC.
244+
let tip_rc = Self::get_confirmable_reward_cycle(
224245
&sortdb.pox_constants,
225246
sortdb.first_block_height,
226247
tip.block_height,
@@ -234,21 +255,17 @@ impl NakamotoDownloadStateMachine {
234255
} else if let Some(last_tip) = last_tip.as_ref() {
235256
last_tip.block_height.saturating_add(1)
236257
} else {
237-
// careful -- need .saturating_sub(1) since this calculation puts the reward cycle start at
238-
// block height 1 mod reward cycle len, but we really want 0 mod reward cycle len
239258
sortdb
240259
.pox_constants
241-
.reward_cycle_to_block_height(sortdb.first_block_height, tip_rc)
242-
.saturating_sub(1)
260+
.nakamoto_first_block_of_cycle(sortdb.first_block_height, tip_rc)
243261
};
244262

245263
// be extra careful with last_block_height -- we not only account for the above, but also
246264
// we need to account for the fact that `load_wanted_tenures` does not load the sortition
247265
// of the last block height (but we want this!)
248266
let last_block_height = sortdb
249267
.pox_constants
250-
.reward_cycle_to_block_height(sortdb.first_block_height, tip_rc.saturating_add(1))
251-
.saturating_sub(1)
268+
.nakamoto_first_block_of_cycle(sortdb.first_block_height, tip_rc.saturating_add(1))
252269
.min(tip.block_height.saturating_add(1));
253270

254271
debug!(
@@ -395,7 +412,7 @@ impl NakamotoDownloadStateMachine {
395412
.expect("FATAL: usize cannot support reward cycle length")
396413
{
397414
// this is the first-ever pass, so load up the last full reward cycle
398-
let prev_sort_rc = downloader_block_height_to_reward_cycle(
415+
let prev_sort_rc = Self::get_confirmable_reward_cycle(
399416
&sortdb.pox_constants,
400417
sortdb.first_block_height,
401418
sort_tip.block_height,
@@ -419,7 +436,7 @@ impl NakamotoDownloadStateMachine {
419436
}
420437
if self.wanted_tenures.is_empty() {
421438
// this is the first-ever pass, so load up the current reward cycle
422-
let sort_rc = downloader_block_height_to_reward_cycle(
439+
let sort_rc = Self::get_confirmable_reward_cycle(
423440
&sortdb.pox_constants,
424441
sortdb.first_block_height,
425442
sort_tip.block_height,
@@ -472,7 +489,7 @@ impl NakamotoDownloadStateMachine {
472489
self.initialize_wanted_tenures(sort_tip, sortdb)?;
473490
let last_sort_height_opt = self.last_sort_tip.as_ref().map(|sn| sn.block_height);
474491
let last_sort_height = last_sort_height_opt.unwrap_or(sort_tip.block_height);
475-
let sort_rc = downloader_block_height_to_reward_cycle(
492+
let sort_rc = Self::get_confirmable_reward_cycle(
476493
&sortdb.pox_constants,
477494
sortdb.first_block_height,
478495
last_sort_height,

stackslib/src/net/download/nakamoto/mod.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ use std::collections::HashMap;
114114
use stacks_common::types::chainstate::ConsensusHash;
115115
use stacks_common::types::StacksEpochId;
116116

117-
use crate::burnchains::PoxConstants;
118117
use crate::chainstate::burn::db::sortdb::SortitionDB;
119118
use crate::chainstate::nakamoto::NakamotoBlock;
120119
use crate::chainstate::stacks::db::StacksChainState;
@@ -139,14 +138,6 @@ pub use crate::net::download::nakamoto::tenure_downloader_unconfirmed::{
139138
NakamotoUnconfirmedDownloadState, NakamotoUnconfirmedTenureDownloader,
140139
};
141140

142-
pub fn downloader_block_height_to_reward_cycle(
143-
pox_constants: &PoxConstants,
144-
first_block_height: u64,
145-
block_height: u64,
146-
) -> Option<u64> {
147-
pox_constants.block_height_to_reward_cycle(first_block_height, block_height.saturating_sub(1))
148-
}
149-
150141
impl PeerNetwork {
151142
/// Set up the Nakamoto block downloader
152143
pub fn init_nakamoto_block_downloader(&mut self) {

stackslib/src/net/download/nakamoto/tenure_downloader_unconfirmed.rs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ use crate::chainstate::nakamoto::{NakamotoBlock, NakamotoChainState};
2626
use crate::chainstate::stacks::boot::RewardSet;
2727
use crate::chainstate::stacks::db::StacksChainState;
2828
use crate::net::api::gettenureinfo::RPCGetTenureInfo;
29-
use crate::net::download::nakamoto::{
30-
downloader_block_height_to_reward_cycle, NakamotoTenureDownloader,
31-
};
29+
use crate::net::download::nakamoto::NakamotoTenureDownloader;
3230
use crate::net::httpcore::{StacksHttpRequest, StacksHttpResponse};
3331
use crate::net::neighbors::rpc::NeighborRPC;
3432
use crate::net::p2p::{CurrentRewardSet, DropReason, DropSource, PeerNetwork};
@@ -162,8 +160,11 @@ impl NakamotoUnconfirmedTenureDownloader {
162160
return Err(NetError::InvalidState);
163161
}
164162

165-
debug!("Got tenure info {:?}", remote_tenure_tip);
166-
debug!("Local sortition tip is {}", &local_sort_tip.consensus_hash);
163+
debug!(
164+
"Got tenure info";
165+
"remote_tenure_tip" => ?remote_tenure_tip,
166+
"local_sortition_tip" => %local_sort_tip.consensus_hash
167+
);
167168

168169
// authenticate consensus hashes against canonical chain history
169170
let local_tenure_sn = SortitionDB::get_block_snapshot_consensus(
@@ -286,19 +287,24 @@ impl NakamotoUnconfirmedTenureDownloader {
286287
return Ok(());
287288
}
288289

290+
debug!(
291+
"TenureDownloaderUnconfirmed not finished";
292+
"tenure_burn_ht" => local_tenure_sn.block_height,
293+
"parent_tenure_burn_ht" => parent_local_tenure_sn.block_height
294+
);
295+
289296
// we're not finished
290-
let tenure_rc = downloader_block_height_to_reward_cycle(
291-
&sortdb.pox_constants,
292-
sortdb.first_block_height,
293-
local_tenure_sn.block_height,
294-
)
295-
.expect("FATAL: sortition from before system start");
296-
let parent_tenure_rc = downloader_block_height_to_reward_cycle(
297-
&sortdb.pox_constants,
298-
sortdb.first_block_height,
299-
parent_local_tenure_sn.block_height,
300-
)
301-
.expect("FATAL: sortition from before system start");
297+
let tenure_rc = sortdb
298+
.pox_constants
299+
.block_height_to_reward_cycle(sortdb.first_block_height, local_tenure_sn.block_height)
300+
.expect("FATAL: sortition from before system start");
301+
let parent_tenure_rc = sortdb
302+
.pox_constants
303+
.block_height_to_reward_cycle(
304+
sortdb.first_block_height,
305+
parent_local_tenure_sn.block_height,
306+
)
307+
.expect("FATAL: sortition from before system start");
302308

303309
// get reward set info for the unconfirmed tenure and highest-complete tenure sortitions
304310
let Some(Some(confirmed_reward_set)) = current_reward_sets
@@ -697,10 +703,12 @@ impl NakamotoUnconfirmedTenureDownloader {
697703
return Err(NetError::InvalidState);
698704
};
699705

700-
debug!(
701-
"Create downloader for highest complete tenure {} known by {}",
702-
&tenure_tip.parent_consensus_hash, &self.naddr,
706+
info!(
707+
"Create highest confirmed downloader from unconfirmed";
708+
"confirmed_tenure" => %tenure_tip.parent_consensus_hash,
709+
"neighbor" => %self.naddr,
703710
);
711+
704712
let ntd = NakamotoTenureDownloader::new(
705713
tenure_tip.parent_consensus_hash.clone(),
706714
tenure_tip.consensus_hash.clone(),

0 commit comments

Comments
 (0)