Skip to content

Commit c900752

Browse files
authored
Merge pull request #5544 from stacks-network/fix/5502
Fix/5502
2 parents ca77e95 + 7d4499e commit c900752

File tree

7 files changed

+87
-556
lines changed

7 files changed

+87
-556
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
1212

1313
### Changed
1414

15+
- Nodes will assume that all PoX anchor blocks exist by default, and stall initial block download indefinitely to await their arrival (#5502)
16+
1517
## [3.1.0.0.1]
1618

1719
### Added

stackslib/src/chainstate/coordinator/mod.rs

+28-2
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ pub trait BlockEventDispatcher {
198198
}
199199

200200
pub struct ChainsCoordinatorConfig {
201+
/// true: assume all anchor blocks are present, and block chain sync until they arrive
202+
/// false: process sortitions in reward cycles without anchor blocks
203+
pub assume_present_anchor_blocks: bool,
201204
/// true: use affirmation maps before 2.1
202205
/// false: only use affirmation maps in 2.1 or later
203206
pub always_use_affirmation_maps: bool,
@@ -209,8 +212,17 @@ pub struct ChainsCoordinatorConfig {
209212
impl ChainsCoordinatorConfig {
210213
pub fn new() -> ChainsCoordinatorConfig {
211214
ChainsCoordinatorConfig {
212-
always_use_affirmation_maps: false,
215+
always_use_affirmation_maps: true,
213216
require_affirmed_anchor_blocks: true,
217+
assume_present_anchor_blocks: true,
218+
}
219+
}
220+
221+
pub fn test_new() -> ChainsCoordinatorConfig {
222+
ChainsCoordinatorConfig {
223+
always_use_affirmation_maps: false,
224+
require_affirmed_anchor_blocks: false,
225+
assume_present_anchor_blocks: false,
214226
}
215227
}
216228
}
@@ -700,7 +712,7 @@ impl<'a, T: BlockEventDispatcher, U: RewardSetProvider, B: BurnchainHeaderReader
700712
notifier: (),
701713
atlas_config,
702714
atlas_db: Some(atlas_db),
703-
config: ChainsCoordinatorConfig::new(),
715+
config: ChainsCoordinatorConfig::test_new(),
704716
burnchain_indexer,
705717
refresh_stacker_db: Arc::new(AtomicBool::new(false)),
706718
in_nakamoto_epoch: false,
@@ -2336,6 +2348,20 @@ impl<
23362348
panic!("BUG: no epoch defined at height {}", header.block_height)
23372349
});
23382350

2351+
if self.config.assume_present_anchor_blocks {
2352+
// anchor blocks are always assumed to be present in the chain history,
2353+
// so report its absence if we don't have it.
2354+
if let PoxAnchorBlockStatus::SelectedAndUnknown(missing_anchor_block, _) =
2355+
&rc_info.anchor_status
2356+
{
2357+
info!(
2358+
"Currently missing PoX anchor block {}, which is assumed to be present",
2359+
&missing_anchor_block
2360+
);
2361+
return Ok(Some(missing_anchor_block.clone()));
2362+
}
2363+
}
2364+
23392365
if cur_epoch.epoch_id >= StacksEpochId::Epoch21 || self.config.always_use_affirmation_maps {
23402366
// potentially have an anchor block, but only process the next reward cycle (and
23412367
// subsequent reward cycles) with it if the prepare-phase block-commits affirm its

stackslib/src/config/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1656,6 +1656,7 @@ pub struct NodeConfig {
16561656
pub use_test_genesis_chainstate: Option<bool>,
16571657
pub always_use_affirmation_maps: bool,
16581658
pub require_affirmed_anchor_blocks: bool,
1659+
pub assume_present_anchor_blocks: bool,
16591660
/// Fault injection for failing to push blocks
16601661
pub fault_injection_block_push_fail_probability: Option<u8>,
16611662
// fault injection for hiding blocks.
@@ -1939,6 +1940,7 @@ impl Default for NodeConfig {
19391940
use_test_genesis_chainstate: None,
19401941
always_use_affirmation_maps: true,
19411942
require_affirmed_anchor_blocks: true,
1943+
assume_present_anchor_blocks: true,
19421944
fault_injection_block_push_fail_probability: None,
19431945
fault_injection_hide_blocks: false,
19441946
chain_liveness_poll_time_secs: 300,
@@ -2428,6 +2430,7 @@ pub struct NodeConfigFile {
24282430
pub use_test_genesis_chainstate: Option<bool>,
24292431
pub always_use_affirmation_maps: Option<bool>,
24302432
pub require_affirmed_anchor_blocks: Option<bool>,
2433+
pub assume_present_anchor_blocks: Option<bool>,
24312434
/// At most, how often should the chain-liveness thread
24322435
/// wake up the chains-coordinator. Defaults to 300s (5 min).
24332436
pub chain_liveness_poll_time_secs: Option<u64>,
@@ -2509,6 +2512,10 @@ impl NodeConfigFile {
25092512
// miners should always try to mine, even if they don't have the anchored
25102513
// blocks in the canonical affirmation map. Followers, however, can stall.
25112514
require_affirmed_anchor_blocks: self.require_affirmed_anchor_blocks.unwrap_or(!miner),
2515+
// as of epoch 3.0, all prepare phases have anchor blocks.
2516+
// at the start of epoch 3.0, the chain stalls without anchor blocks.
2517+
// only set this to false if you're doing some very extreme testing.
2518+
assume_present_anchor_blocks: true,
25122519
// chainstate fault_injection activation for hide_blocks.
25132520
// you can't set this in the config file.
25142521
fault_injection_hide_blocks: false,

testnet/stacks-node/src/run_loop/nakamoto.rs

+1
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ impl RunLoop {
319319
let mut fee_estimator = moved_config.make_fee_estimator();
320320

321321
let coord_config = ChainsCoordinatorConfig {
322+
assume_present_anchor_blocks: moved_config.node.assume_present_anchor_blocks,
322323
always_use_affirmation_maps: moved_config.node.always_use_affirmation_maps,
323324
require_affirmed_anchor_blocks: moved_config
324325
.node

testnet/stacks-node/src/run_loop/neon.rs

+5-44
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ impl RunLoop {
615615
let mut fee_estimator = moved_config.make_fee_estimator();
616616

617617
let coord_config = ChainsCoordinatorConfig {
618+
assume_present_anchor_blocks: moved_config.node.assume_present_anchor_blocks,
618619
always_use_affirmation_maps: moved_config.node.always_use_affirmation_maps,
619620
require_affirmed_anchor_blocks: moved_config
620621
.node
@@ -1146,19 +1147,8 @@ impl RunLoop {
11461147

11471148
let mut sortition_db_height = rc_aligned_height;
11481149
let mut burnchain_height = sortition_db_height;
1149-
let mut num_sortitions_in_last_cycle = 1;
11501150

11511151
// prepare to fetch the first reward cycle!
1152-
let mut target_burnchain_block_height = cmp::min(
1153-
burnchain_config.reward_cycle_to_block_height(
1154-
burnchain_config
1155-
.block_height_to_reward_cycle(burnchain_height)
1156-
.expect("BUG: block height is not in a reward cycle")
1157-
+ 1,
1158-
),
1159-
burnchain.get_headers_height() - 1,
1160-
);
1161-
11621152
debug!("Runloop: Begin main runloop starting a burnchain block {sortition_db_height}");
11631153

11641154
let mut last_tenure_sortition_height = 0;
@@ -1186,17 +1176,13 @@ impl RunLoop {
11861176

11871177
let remote_chain_height = burnchain.get_headers_height() - 1;
11881178

1189-
// wait for the p2p state-machine to do at least one pass
1190-
debug!("Runloop: Wait until Stacks block downloads reach a quiescent state before processing more burnchain blocks"; "remote_chain_height" => remote_chain_height, "local_chain_height" => burnchain_height);
1191-
1192-
// wait until it's okay to process the next reward cycle's sortitions
1193-
let ibd = match self.get_pox_watchdog().pox_sync_wait(
1179+
// wait until it's okay to process the next reward cycle's sortitions.
1180+
let (ibd, target_burnchain_block_height) = match self.get_pox_watchdog().pox_sync_wait(
11941181
&burnchain_config,
11951182
&burnchain_tip,
11961183
remote_chain_height,
1197-
num_sortitions_in_last_cycle,
11981184
) {
1199-
Ok(ibd) => ibd,
1185+
Ok(x) => x,
12001186
Err(e) => {
12011187
debug!("Runloop: PoX sync wait routine aborted: {e:?}");
12021188
continue;
@@ -1210,9 +1196,6 @@ impl RunLoop {
12101196
0.0
12111197
};
12121198

1213-
// will recalculate this in the following loop
1214-
num_sortitions_in_last_cycle = 0;
1215-
12161199
// Download each burnchain block and process their sortitions. This, in turn, will
12171200
// cause the node's p2p and relayer threads to go fetch and download Stacks blocks and
12181201
// process them. This loop runs for one reward cycle, so that the next pass of the
@@ -1260,8 +1243,6 @@ impl RunLoop {
12601243
"Runloop: New burnchain block height {next_sortition_height} > {sortition_db_height}"
12611244
);
12621245

1263-
let mut sort_count = 0;
1264-
12651246
debug!("Runloop: block mining until we process all sortitions");
12661247
signal_mining_blocked(globals.get_miner_status());
12671248

@@ -1279,9 +1260,6 @@ impl RunLoop {
12791260
"Failed to find block in fork processed by burnchain indexer",
12801261
)
12811262
};
1282-
if block.sortition {
1283-
sort_count += 1;
1284-
}
12851263

12861264
let sortition_id = &block.sortition_id;
12871265

@@ -1328,9 +1306,8 @@ impl RunLoop {
13281306
debug!("Runloop: enable miner after processing sortitions");
13291307
signal_mining_ready(globals.get_miner_status());
13301308

1331-
num_sortitions_in_last_cycle = sort_count;
13321309
debug!(
1333-
"Runloop: Synchronized sortitions up to block height {next_sortition_height} from {sortition_db_height} (chain tip height is {burnchain_height}); {num_sortitions_in_last_cycle} sortitions"
1310+
"Runloop: Synchronized sortitions up to block height {next_sortition_height} from {sortition_db_height} (chain tip height is {burnchain_height})"
13341311
);
13351312

13361313
sortition_db_height = next_sortition_height;
@@ -1349,22 +1326,6 @@ impl RunLoop {
13491326
}
13501327
}
13511328

1352-
// advance one reward cycle at a time.
1353-
// If we're still downloading, then this is simply target_burnchain_block_height + reward_cycle_len.
1354-
// Otherwise, this is burnchain_tip + reward_cycle_len
1355-
let next_target_burnchain_block_height = cmp::min(
1356-
burnchain_config.reward_cycle_to_block_height(
1357-
burnchain_config
1358-
.block_height_to_reward_cycle(target_burnchain_block_height)
1359-
.expect("FATAL: burnchain height before system start")
1360-
+ 1,
1361-
),
1362-
remote_chain_height,
1363-
);
1364-
1365-
debug!("Runloop: Advance target burnchain block height from {target_burnchain_block_height} to {next_target_burnchain_block_height} (sortition height {sortition_db_height})");
1366-
target_burnchain_block_height = next_target_burnchain_block_height;
1367-
13681329
if sortition_db_height >= burnchain_height && !ibd {
13691330
let canonical_stacks_tip_height =
13701331
SortitionDB::get_canonical_burn_chain_tip(burnchain.sortdb_ref().conn())

0 commit comments

Comments
 (0)