Skip to content

Commit 4cc0758

Browse files
committed
fix: better descendency check
1 parent 795b4a7 commit 4cc0758

File tree

3 files changed

+62
-36
lines changed

3 files changed

+62
-36
lines changed

stacks-signer/src/v0/signer_state.rs

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -997,40 +997,20 @@ impl LocalStateMachine {
997997
replay_state: &ReplayState,
998998
) -> Result<Option<ReplayState>, SignerChainstateError> {
999999
if expected_burn_block.burn_block_height > prior_state_machine.burn_block_height {
1000-
// prevent too large of a loop
1001-
if expected_burn_block
1002-
.burn_block_height
1003-
.saturating_sub(prior_state_machine.burn_block_height)
1004-
> 10
1005-
{
1006-
return Ok(None);
1007-
}
1008-
// are we building on top of this prior tip?
1009-
let mut parent_burn_block_info =
1010-
db.get_burn_block_by_ch(&expected_burn_block.consensus_hash)?;
1011-
1012-
while parent_burn_block_info.block_height > prior_state_machine.burn_block_height {
1013-
let Ok(parent_info) =
1014-
db.get_burn_block_by_hash(&parent_burn_block_info.parent_burn_block_hash)
1015-
else {
1016-
warn!(
1017-
"Failed to get parent burn block info for {}",
1018-
parent_burn_block_info.parent_burn_block_hash
1019-
);
1020-
return Ok(None);
1021-
};
1022-
parent_burn_block_info = parent_info;
1023-
}
1024-
if parent_burn_block_info.consensus_hash == prior_state_machine.burn_block {
1025-
// no bitcoin fork, because we're building on the parent
1026-
return Ok(None);
1027-
} else {
1000+
if Self::new_burn_block_fork_descendency_check(
1001+
db,
1002+
expected_burn_block,
1003+
prior_state_machine.burn_block_height,
1004+
prior_state_machine.burn_block,
1005+
)? {
10281006
info!("Detected bitcoin fork - prior tip is not parent of new tip.";
10291007
"new_tip.burn_block_height" => expected_burn_block.burn_block_height,
10301008
"new_tip.consensus_hash" => %expected_burn_block.consensus_hash,
10311009
"prior_tip.burn_block_height" => prior_state_machine.burn_block_height,
10321010
"prior_tip.consensus_hash" => %prior_state_machine.burn_block,
10331011
);
1012+
} else {
1013+
return Ok(None);
10341014
}
10351015
}
10361016
if expected_burn_block.consensus_hash == prior_state_machine.burn_block {
@@ -1273,4 +1253,53 @@ impl LocalStateMachine {
12731253

12741254
Ok(new_burn_block.burn_block_height > failsafe_height)
12751255
}
1256+
1257+
/// Check if the new burn block is a fork, by checking if the new burn block
1258+
/// is a descendant of the prior burn block
1259+
fn new_burn_block_fork_descendency_check(
1260+
db: &SignerDb,
1261+
new_burn_block: &NewBurnBlock,
1262+
prior_burn_block_height: u64,
1263+
prior_burn_block_ch: ConsensusHash,
1264+
) -> Result<bool, SignerChainstateError> {
1265+
let max_height_delta = 10;
1266+
let height_delta = match new_burn_block
1267+
.burn_block_height
1268+
.checked_sub(prior_burn_block_height)
1269+
{
1270+
None | Some(0) => return Ok(false), // same height or older
1271+
Some(d) if d > max_height_delta => return Ok(false), // too far apart
1272+
Some(d) => d,
1273+
};
1274+
1275+
let Ok(mut parent_burn_block_info) =
1276+
db.get_burn_block_by_ch(&new_burn_block.consensus_hash)
1277+
else {
1278+
warn!(
1279+
"Failed to get parent burn block info for {}",
1280+
new_burn_block.consensus_hash
1281+
);
1282+
return Ok(false);
1283+
};
1284+
1285+
for _ in 0..height_delta {
1286+
if parent_burn_block_info.block_height == prior_burn_block_height {
1287+
return Ok(parent_burn_block_info.consensus_hash != prior_burn_block_ch);
1288+
}
1289+
1290+
parent_burn_block_info =
1291+
match db.get_burn_block_by_hash(&parent_burn_block_info.parent_burn_block_hash) {
1292+
Ok(bi) => bi,
1293+
Err(e) => {
1294+
warn!(
1295+
"Failed to get parent burn block info for {}. Error: {e}",
1296+
parent_burn_block_info.parent_burn_block_hash
1297+
);
1298+
return Ok(false);
1299+
}
1300+
};
1301+
}
1302+
1303+
Ok(false)
1304+
}
12761305
}

testnet/stacks-node/src/tests/signer/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,11 @@ impl<S: Signer<T> + Send + 'static, T: SignerEventTrait + 'static> SignerTest<Sp
325325
let metadata_path = snapshot_path.join("metadata.json");
326326
if !metadata_path.clone().exists() {
327327
warn!("Snapshot metadata file does not exist, not restoring snapshot");
328-
return SetupSnapshotResult::NoSnapshot;
328+
std::fs::remove_dir_all(snapshot_path.clone()).unwrap();
329+
return SetupSnapshotResult::WithSnapshot(SnapshotSetupInfo {
330+
snapshot_path: snapshot_path.clone(),
331+
snapshot_exists: false,
332+
});
329333
}
330334
let Ok(metadata) = serde_json::from_reader::<_, SnapshotMetadata>(
331335
File::open(metadata_path.clone()).unwrap(),

testnet/stacks-node/src/tests/signer/v0.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3982,13 +3982,6 @@ fn tx_replay_simple() {
39823982
let _http_origin = format!("http://{}", &conf.node.rpc_bind);
39833983
let btc_controller = &signer_test.running_nodes.btc_regtest_controller;
39843984

3985-
let miner_pk = btc_controller
3986-
.get_mining_pubkey()
3987-
.as_deref()
3988-
.map(Secp256k1PublicKey::from_hex)
3989-
.unwrap()
3990-
.unwrap();
3991-
39923985
if signer_test.bootstrap_snapshot() {
39933986
signer_test.shutdown_and_snapshot();
39943987
return;

0 commit comments

Comments
 (0)