Skip to content

Commit 5ef0407

Browse files
committed
Implement process_pushed_next_ready_block to enable calling process_next_nakamoto_block
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent a7f4240 commit 5ef0407

7 files changed

+291
-318
lines changed

stackslib/src/chainstate/nakamoto/mod.rs

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,28 +2478,23 @@ impl NakamotoChainState {
24782478
reward_set: &RewardSet,
24792479
obtain_method: NakamotoBlockObtainMethod,
24802480
) -> Result<bool, ChainstateError> {
2481-
test_debug!("Consider Nakamoto block {}", &block.block_id());
2481+
let block_id = block.block_id();
2482+
test_debug!("Consider Nakamoto block {block_id}");
24822483
// do nothing if we already have this block
2483-
if Self::get_block_header(headers_conn, &block.header.block_id())?.is_some() {
2484-
debug!("Already have block {}", &block.header.block_id());
2484+
if Self::get_block_header(headers_conn, &block_id)?.is_some() {
2485+
debug!("Already have block {block_id}");
24852486
return Ok(false);
24862487
}
24872488

24882489
// if this is the first tenure block, then make sure it's well-formed
24892490
block.is_wellformed_tenure_start_block().map_err(|_| {
2490-
warn!(
2491-
"Block {} is not a well-formed first tenure block",
2492-
&block.block_id()
2493-
);
2491+
warn!("Block {block_id} is not a well-formed first tenure block");
24942492
ChainstateError::InvalidStacksBlock("Not a well-formed first-tenure block".into())
24952493
})?;
24962494

24972495
// if this is a tenure-extend block, then make sure it's well-formed
24982496
block.is_wellformed_tenure_extend_block().map_err(|_| {
2499-
warn!(
2500-
"Block {} is not a well-formed tenure-extend block",
2501-
&block.block_id()
2502-
);
2497+
warn!("Block {block_id} is not a well-formed tenure-extend block");
25032498
ChainstateError::InvalidStacksBlock("Not a well-formed tenure-extend block".into())
25042499
})?;
25052500

@@ -2510,51 +2505,50 @@ impl NakamotoChainState {
25102505
if block.is_shadow_block() {
25112506
// this block is already present in the staging DB, so just perform some prefunctory
25122507
// validation (since they're constructed a priori to be valid)
2513-
if let Err(e) = Self::validate_shadow_nakamoto_block_burnchain(
2508+
Self::validate_shadow_nakamoto_block_burnchain(
25142509
staging_db_tx.conn(),
25152510
db_handle,
25162511
expected_burn_opt,
25172512
block,
25182513
config.mainnet,
25192514
config.chain_id,
2520-
) {
2515+
)
2516+
.unwrap_or_else(|e| {
25212517
error!("Unacceptable shadow Nakamoto block";
2522-
"stacks_block_id" => %block.block_id(),
2523-
"error" => ?e
2518+
"stacks_block_id" => %block_id,
2519+
"error" => ?e
25242520
);
25252521
panic!("Unacceptable shadow Nakamoto block");
2526-
}
2527-
2522+
});
25282523
return Ok(false);
25292524
}
25302525

25312526
// this block must be consistent with its miner's leader-key and block-commit, and must
25322527
// contain only transactions that are valid in this epoch.
2533-
if let Err(e) = Self::validate_normal_nakamoto_block_burnchain(
2528+
Self::validate_normal_nakamoto_block_burnchain(
25342529
staging_db_tx.conn(),
25352530
db_handle,
25362531
expected_burn_opt,
25372532
block,
25382533
config.mainnet,
25392534
config.chain_id,
2540-
) {
2535+
)
2536+
.inspect_err(|e| {
25412537
warn!("Unacceptable Nakamoto block; will not store";
2542-
"stacks_block_id" => %block.block_id(),
2543-
"error" => ?e
2538+
"stacks_block_id" => %block_id,
2539+
"error" => ?e
25442540
);
2545-
return Ok(false);
2546-
};
2541+
})?;
25472542

2548-
let signing_weight = match block.header.verify_signer_signatures(reward_set) {
2549-
Ok(x) => x,
2550-
Err(e) => {
2543+
let signing_weight = block
2544+
.header
2545+
.verify_signer_signatures(reward_set)
2546+
.inspect_err(|e| {
25512547
warn!("Received block, but the signer signatures are invalid";
2552-
"block_id" => %block.block_id(),
2553-
"error" => ?e,
2548+
"block_id" => %block_id,
2549+
"error" => ?e,
25542550
);
2555-
return Err(e);
2556-
}
2557-
};
2551+
})?;
25582552

25592553
// if we pass all the tests, then along the way, we will have verified (in
25602554
// Self::validate_nakamoto_block_burnchain) that the consensus hash of this block is on the
@@ -2569,9 +2563,9 @@ impl NakamotoChainState {
25692563
obtain_method,
25702564
)?;
25712565
if ret {
2572-
test_debug!("Stored Nakamoto block {}", &block.block_id());
2566+
test_debug!("Stored Nakamoto block {block_id}");
25732567
} else {
2574-
test_debug!("Did NOT store Nakamoto block {}", &block.block_id());
2568+
test_debug!("Did NOT store Nakamoto block {block_id}");
25752569
}
25762570
Ok(ret)
25772571
}

stackslib/src/chainstate/nakamoto/tests/node.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,105 @@ impl TestStacksNode {
10601060
let cost = builder.tenure_finish(tenure_tx).unwrap();
10611061
Ok((block, size, cost))
10621062
}
1063+
1064+
/// Insert a staging Nakamoto block as a pushed block and
1065+
/// then process it as the next ready block
1066+
/// NOTE: Will panic if called with unprocessed staging
1067+
/// blocks already in the queue.
1068+
pub fn process_pushed_next_ready_block<'a>(
1069+
stacks_node: &mut TestStacksNode,
1070+
sortdb: &mut SortitionDB,
1071+
miner: &mut TestMiner,
1072+
tenure_id_consensus_hash: &ConsensusHash,
1073+
coord: &mut ChainsCoordinator<
1074+
'a,
1075+
TestEventObserver,
1076+
(),
1077+
OnChainRewardSetProvider<'a, TestEventObserver>,
1078+
(),
1079+
(),
1080+
BitcoinIndexer,
1081+
>,
1082+
nakamoto_block: NakamotoBlock,
1083+
) -> Result<Option<StacksEpochReceipt>, ChainstateError> {
1084+
// Before processeding, make sure the caller did not accidentally construct a test with unprocessed blocks already in the queue
1085+
let nakamoto_blocks_db = stacks_node.chainstate.nakamoto_blocks_db();
1086+
assert!(nakamoto_blocks_db
1087+
.next_ready_nakamoto_block(stacks_node.chainstate.db())
1088+
.unwrap().is_none(), "process_pushed_next_ready_block can only be called if the staging blocks queue is empty");
1089+
1090+
let tenure_sn =
1091+
SortitionDB::get_block_snapshot_consensus(sortdb.conn(), tenure_id_consensus_hash)?
1092+
.ok_or_else(|| ChainstateError::NoSuchBlockError)?;
1093+
1094+
let cycle = sortdb
1095+
.pox_constants
1096+
.block_height_to_reward_cycle(sortdb.first_block_height, tenure_sn.block_height)
1097+
.unwrap();
1098+
1099+
// Get the reward set
1100+
let sort_tip_sn = SortitionDB::get_canonical_burn_chain_tip(sortdb.conn())?;
1101+
let reward_set = load_nakamoto_reward_set(
1102+
miner
1103+
.burnchain
1104+
.block_height_to_reward_cycle(sort_tip_sn.block_height)
1105+
.expect("FATAL: no reward cycle for sortition"),
1106+
&sort_tip_sn.sortition_id,
1107+
&miner.burnchain,
1108+
&mut stacks_node.chainstate,
1109+
&nakamoto_block.header.parent_block_id,
1110+
sortdb,
1111+
&OnChainRewardSetProvider::new(),
1112+
)
1113+
.expect("Failed to load reward set")
1114+
.expect("Expected a reward set")
1115+
.0
1116+
.known_selected_anchor_block_owned()
1117+
.expect("Unknown reward set");
1118+
1119+
let block_id = nakamoto_block.block_id();
1120+
1121+
debug!(
1122+
"Process Nakamoto block {block_id} ({:?}",
1123+
&nakamoto_block.header
1124+
);
1125+
1126+
let sort_tip = SortitionDB::get_canonical_sortition_tip(sortdb.conn())?;
1127+
let mut sort_handle = sortdb.index_handle(&sort_tip);
1128+
1129+
// Force the block to be added to the nakamoto_staging_blocks table
1130+
let config = stacks_node.chainstate.config();
1131+
let (headers_conn, staging_db_tx) =
1132+
stacks_node.chainstate.headers_conn_and_staging_tx_begin()?;
1133+
let accepted = NakamotoChainState::accept_block(
1134+
&config,
1135+
&nakamoto_block,
1136+
&mut sort_handle,
1137+
&staging_db_tx,
1138+
headers_conn,
1139+
&reward_set,
1140+
NakamotoBlockObtainMethod::Pushed,
1141+
)?;
1142+
staging_db_tx.commit()?;
1143+
debug!("Accepted Nakamoto block {}", &nakamoto_block.block_id());
1144+
// Actually attempt to process the accepted block added to nakamoto_staging_blocks
1145+
// Will attempt to execute the transactions via a call to append_block
1146+
let res = NakamotoChainState::process_next_nakamoto_block(
1147+
&mut coord.chain_state_db,
1148+
&mut coord.sortition_db,
1149+
&coord.canonical_sortition_tip.clone().expect(
1150+
"FAIL: processing a new Stacks block, but don't have a canonical sortition tip",
1151+
),
1152+
coord.dispatcher,
1153+
coord.config.txindex,
1154+
)?;
1155+
if res.is_some() {
1156+
// If we successfully processed the block, make sure we append the block to our current tenure
1157+
// so subsequent blocks do not attempt to reorg it.
1158+
stacks_node.add_nakamoto_extended_blocks(vec![nakamoto_block]);
1159+
}
1160+
Ok(res)
1161+
}
10631162
}
10641163

10651164
/// Get the Nakamoto parent linkage data for building atop the last-produced tenure or

0 commit comments

Comments
 (0)