Skip to content

Commit 9f1474c

Browse files
committed
fix(fault-proof): align catch-up head selection with upstream PR succinctlabs#927
Upstream replaced succinctlabs#926 with succinctlabs#927, adding two increments on top of the same core selection logic: - Emit a tracing::debug! when the canonical head is chosen from a catch-up chain outside the anchor subtree, so operators can tell the proposer is recovering on a non-descendant lineage. - Cover the multi-chain case in a new unit test (multiple_catchup_chains_select_highest_tip): after repeated stall/recovery cycles, several genesis-rooted catch-up chains can sit in the cache, and the head must be the highest tip pooled across all of them, not the tip of the chain whose root sits highest.
1 parent 1945d71 commit 9f1474c

1 file changed

Lines changed: 30 additions & 0 deletions

File tree

fault-proof/src/proposer.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,16 @@ impl ProposerState {
273273
.cloned()
274274
});
275275

276+
// Log when the head comes from a catch-up chain so operators can tell the proposer is
277+
// recovering along a chain outside the anchor subtree.
278+
if let Some(head) = override_head.as_ref() {
279+
tracing::debug!(
280+
head_index = %head.index,
281+
head_l2_block = %head.l2_block,
282+
"Canonical head selected from a catch-up chain outside the anchor subtree"
283+
);
284+
}
285+
276286
override_head.or(anchor_head)
277287
}
278288
}
@@ -2777,6 +2787,26 @@ mod tests {
27772787
);
27782788
assert_eq!(s.select_canonical_head().unwrap().index, U256::from(7));
27792789
}
2790+
2791+
#[test]
2792+
fn multiple_catchup_chains_select_highest_tip() {
2793+
// Repeated stall/recovery cycles can leave several genesis-rooted catch-up chains in
2794+
// the cache at once. The head must be the highest-block tip across all qualifying
2795+
// chains pooled together (chain B's tip 9), even though chain B's root (block 250)
2796+
// sits below chain A's tip (block 300).
2797+
let anchor = game_with(5, 4, 100);
2798+
let s = state(
2799+
vec![
2800+
anchor.clone(),
2801+
game_with(6, u32::MAX, 200),
2802+
game_with(7, 6, 300),
2803+
game_with(8, u32::MAX, 250),
2804+
game_with(9, 8, 400),
2805+
],
2806+
Some(anchor),
2807+
);
2808+
assert_eq!(s.select_canonical_head().unwrap().index, U256::from(9));
2809+
}
27802810
}
27812811

27822812
async fn mock_prove(

0 commit comments

Comments
 (0)