Skip to content

Commit ea05fae

Browse files
Merge pull request #6879 from aaronb-stacks/fix/miner-sortdb-memo
Fix: miner should not need SortitionDB memoized tip
2 parents 7c95397 + ee4d6f3 commit ea05fae

File tree

2 files changed

+312
-80
lines changed

2 files changed

+312
-80
lines changed

stacks-node/src/nakamoto_node/miner.rs

Lines changed: 73 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,100 +1249,93 @@ impl BlockMinerThread {
12491249
tx_signer.get_tx().unwrap()
12501250
}
12511251

1252-
// TODO: add tests from mutation testing results #4869
12531252
#[cfg_attr(test, mutants::skip)]
1254-
/// Load up the parent block info for mining.
1253+
/// Load up the parent block header for mining the next block.
12551254
/// If we can't find the parent in the DB but we expect one, return Err(ParentNotFound).
1256-
fn load_block_parent_info(
1255+
///
1256+
/// The nakamoto miner must always build off of a chain tip that is either:
1257+
/// 1. The highest block in our own tenure
1258+
/// 2. The highest block in our tenure's parent tenure (i.e., `self.parent_tenure_id`)
1259+
///
1260+
/// `self.parent_tenure_id` is the tenure start block which was
1261+
/// committed to by our tenure's associated block commit.
1262+
fn load_block_parent_header(
12571263
&self,
12581264
burn_db: &mut SortitionDB,
12591265
chain_state: &mut StacksChainState,
1260-
) -> Result<ParentStacksBlockInfo, NakamotoNodeError> {
1261-
// load up stacks chain tip
1262-
let (stacks_tip_ch, stacks_tip_bh) =
1263-
SortitionDB::get_canonical_stacks_chain_tip_hash(burn_db.conn()).map_err(|e| {
1264-
error!("Failed to load canonical Stacks tip: {e:?}");
1265-
NakamotoNodeError::ParentNotFound
1266-
})?;
1267-
1268-
let stacks_tip_block_id = StacksBlockId::new(&stacks_tip_ch, &stacks_tip_bh);
1269-
let tenure_tip_opt = self
1266+
) -> Result<StacksHeaderInfo, NakamotoNodeError> {
1267+
let my_tenure_tip = self
12701268
.find_highest_known_block_in_my_tenure(&burn_db, &chain_state)
12711269
.map_err(|e| {
12721270
error!(
1273-
"Could not query header info for tenure tip {} off of {stacks_tip_block_id}: {e:?}",
1274-
&self.burn_election_block.consensus_hash
1275-
);
1271+
"Could not find highest header info for miner's tenure {}: {e:?}",
1272+
&self.burn_election_block.consensus_hash
1273+
);
12761274
NakamotoNodeError::ParentNotFound
12771275
})?;
1278-
1279-
// The nakamoto miner must always build off of a chain tip that is the highest of:
1280-
// 1. The highest block in the miner's current tenure
1281-
// 2. The highest block in the current tenure's parent tenure
1282-
//
1283-
// Where the current tenure's parent tenure is the tenure start block committed to in the current tenure's associated block commit.
1284-
let stacks_tip_header = if let Some(tenure_tip) = tenure_tip_opt {
1276+
if let Some(my_tenure_tip) = my_tenure_tip {
12851277
debug!(
12861278
"Stacks block parent ID is last block in tenure ID {}",
1287-
&tenure_tip.consensus_hash
1288-
);
1289-
tenure_tip
1290-
} else {
1291-
// This tenure is empty on the canonical fork, so mine the first tenure block.
1292-
debug!(
1293-
"Stacks block parent ID is last block in parent tenure tipped by {}",
1294-
&self.parent_tenure_id
1279+
&my_tenure_tip.consensus_hash
12951280
);
1281+
return Ok(my_tenure_tip);
1282+
}
12961283

1297-
// find the last block in the parent tenure, since this is the tip we'll build atop
1298-
let parent_tenure_header =
1299-
NakamotoChainState::get_block_header(chain_state.db(), &self.parent_tenure_id)
1300-
.map_err(|e| {
1301-
error!(
1302-
"Could not query header for parent tenure ID {}: {e:?}",
1303-
&self.parent_tenure_id
1304-
);
1305-
NakamotoNodeError::ParentNotFound
1306-
})?
1307-
.ok_or_else(|| {
1308-
error!("No header for parent tenure ID {}", &self.parent_tenure_id);
1309-
NakamotoNodeError::ParentNotFound
1310-
})?;
1311-
1312-
let header_opt = NakamotoChainState::get_highest_block_header_in_tenure(
1313-
&mut chain_state.index_conn(),
1314-
&stacks_tip_block_id,
1315-
&parent_tenure_header.consensus_hash,
1316-
)
1317-
.map_err(|e| {
1318-
error!("Could not query parent tenure finish block: {e:?}");
1319-
NakamotoNodeError::ParentNotFound
1320-
})?;
1321-
if let Some(header) = header_opt {
1322-
header
1323-
} else {
1324-
// this is an epoch2 block
1325-
debug!(
1326-
"Stacks block parent ID may be an epoch2x block: {}",
1327-
&self.parent_tenure_id
1328-
);
1329-
NakamotoChainState::get_block_header(chain_state.db(), &self.parent_tenure_id)
1330-
.map_err(|e| {
1331-
error!(
1332-
"Could not query header info for epoch2x tenure block ID {}: {e:?}",
1333-
&self.parent_tenure_id
1334-
);
1335-
NakamotoNodeError::ParentNotFound
1336-
})?
1337-
.ok_or_else(|| {
1338-
error!(
1339-
"No header info for epoch2x tenure block ID {}",
1340-
&self.parent_tenure_id
1341-
);
1342-
NakamotoNodeError::ParentNotFound
1343-
})?
1344-
}
1345-
};
1284+
// My tenure is empty on the canonical fork, so our parent should be the highest block in
1285+
// self.parent_tenure_id
1286+
debug!(
1287+
"Stacks block parent ID is last block in parent tenure tipped by {}",
1288+
&self.parent_tenure_id
1289+
);
1290+
1291+
// find the last block in the parent tenure, since this is the tip we'll build atop
1292+
let parent_tenure_header =
1293+
NakamotoChainState::get_block_header(chain_state.db(), &self.parent_tenure_id)
1294+
.map_err(|e| {
1295+
error!(
1296+
"Could not query header for parent tenure ID {}: {e:?}",
1297+
&self.parent_tenure_id
1298+
);
1299+
NakamotoNodeError::ParentNotFound
1300+
})?
1301+
.ok_or_else(|| {
1302+
error!("No header for parent tenure ID {}", &self.parent_tenure_id);
1303+
NakamotoNodeError::ParentNotFound
1304+
})?;
1305+
1306+
let header_opt = NakamotoChainState::find_highest_known_block_header_in_tenure(
1307+
&chain_state,
1308+
burn_db,
1309+
&parent_tenure_header.consensus_hash,
1310+
)
1311+
.map_err(|e| {
1312+
error!("Could not query parent tenure finish block: {e:?}");
1313+
NakamotoNodeError::ParentNotFound
1314+
})?;
1315+
1316+
if let Some(parent_tenure_tip) = header_opt {
1317+
return Ok(parent_tenure_tip);
1318+
}
1319+
1320+
// this is an epoch2 block
1321+
debug!(
1322+
"Stacks block parent ID is an epoch2x block: {}",
1323+
&self.parent_tenure_id
1324+
);
1325+
1326+
Ok(parent_tenure_header)
1327+
}
1328+
1329+
// TODO: add tests from mutation testing results #4869
1330+
#[cfg_attr(test, mutants::skip)]
1331+
/// Load up the parent block info for mining.
1332+
/// If we can't find the parent in the DB but we expect one, return Err(ParentNotFound).
1333+
fn load_block_parent_info(
1334+
&self,
1335+
burn_db: &mut SortitionDB,
1336+
chain_state: &mut StacksChainState,
1337+
) -> Result<ParentStacksBlockInfo, NakamotoNodeError> {
1338+
let stacks_tip_header = self.load_block_parent_header(burn_db, chain_state)?;
13461339

13471340
debug!(
13481341
"Miner: stacks tip parent header is {} {stacks_tip_header:?}",

0 commit comments

Comments
 (0)