Repository: alpenlabs/strata
Pull request #718: Make fullnode return non-empty checkpoint reference in get_checkpoint_info RPC
Author: login: bewakes
Created: 2025-03-06T10:13:05Z | Merged: 2025-03-07T07:27:10Z

## Description
Resolves: https://alpenlabs.atlassian.net/browse/STR-1110

This PR does the following:
1. When a checkpoint is seen in L1, if it is a full node, it creates a new `CheckpointEntry` with appropriate status. This lets fullnode serve checkpoint info correctly in the `getCheckpointInfo` RPC. For sequencer, this was always working.
2. Remove the epoch l2 headers length check while creating checkpoint. We don't have a better way to handle this now. It used to return error if the length exceeded some value(5000).

### Type of Change

<!--
Select the type of change your PR introduces (put an `x` in all that apply):
-->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature/Enhancement (non-breaking change which adds functionality or enhances an existing one)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
- [ ] Refactor
- [ ] New or updated tests
- [ ] Dependency Update

## Notes to Reviewers

<!--
Anything in particular you want to note that will help reviewers fulfill their role
in reviewing this PR?
-->

## Checklist

<!--
Ensure all the following are checked:
-->

- [ ] I have performed a self-review of my code.
- [ ] I have commented my code where necessary.
- [ ] I have updated the documentation if needed.
- [ ] My changes do not introduce new warnings.
- [ ] I have added (where necessary) tests that prove my changes are effective or that my feature works.
- [ ] New and existing tests pass with my changes.

## Related Issues

<!--
Link any related issues (e.g., `closes #123`, `fixes #456`).
-->


Linked issue #123: Sync manager cannot start because l1_reader starts after sync tasks are spawned and sync tasks don't get any genesis L1 block
This is kind of a deadlock situation.

l1_reader starts after sync manager completes starting and sync manager is expecting genesis block inserted by l1_reader.

Related: #141 
#141 should close this

Diff:
diff --git a/crates/consensus-logic/src/csm/client_transition.rs b/crates/consensus-logic/src/csm/client_transition.rs
index 442b67235c..3c83947f99 100644
--- a/crates/consensus-logic/src/csm/client_transition.rs
+++ b/crates/consensus-logic/src/csm/client_transition.rs
@@ -266,7 +266,7 @@ fn process_l1_block(
 
                     // Emit a sync action to update checkpoint entry in db
                     sync_actions.push(SyncAction::UpdateCheckpointInclusion {
-                        epoch: ckpt.batch_info().epoch(),
+                        checkpoint: signed_ckpt.clone().into(),
                         l1_reference: ckpt_ref,
                     });
                 }
diff --git a/crates/consensus-logic/src/csm/worker.rs b/crates/consensus-logic/src/csm/worker.rs
index 93f3aa68a5..2adb3482be 100644
--- a/crates/consensus-logic/src/csm/worker.rs
+++ b/crates/consensus-logic/src/csm/worker.rs
@@ -2,7 +2,7 @@
 
 use std::{sync::Arc, thread};
 
-use strata_db::types::CheckpointConfStatus;
+use strata_db::types::{CheckpointConfStatus, CheckpointEntry, CheckpointProvingStatus};
 use strata_eectl::engine::ExecEngineCtl;
 use strata_primitives::prelude::*;
 use strata_state::{
@@ -376,12 +376,22 @@ fn apply_action(
 
         // Update checkpoint entry in database to mark it as included in L1.
         SyncAction::UpdateCheckpointInclusion {
-            epoch,
+            checkpoint,
             l1_reference,
         } => {
-            let Some(mut ckpt_entry) = ckpt_db.get_checkpoint_blocking(epoch)? else {
-                warn!(%epoch, "missing checkpoint we wanted to set the state of, ignoring");
-                return Ok(());
+            let epoch = checkpoint.batch_info().epoch();
+
+            let mut ckpt_entry = match ckpt_db.get_checkpoint_blocking(epoch)? {
+                Some(c) => c,
+                None => {
+                    info!(%epoch, "creating new checkpoint entry since the database does not have one");
+
+                    CheckpointEntry::new(
+                        checkpoint,
+                        CheckpointProvingStatus::ProofReady,
+                        CheckpointConfStatus::Pending,
+                    )
+                }
             };
 
             ckpt_entry.confirmation_status = CheckpointConfStatus::Confirmed(l1_reference);
diff --git a/crates/l1tx/src/filter/types.rs b/crates/l1tx/src/filter/types.rs
index 7b819ebe50..dba733e44a 100644
--- a/crates/l1tx/src/filter/types.rs
+++ b/crates/l1tx/src/filter/types.rs
@@ -88,8 +88,10 @@ impl TxFilterConfig {
             .flat_map(conv_deposit_to_fulfillment)
             .collect::<Vec<_>>();
 
-        self.expected_withdrawal_fulfillments =
-            FlatTable::try_from(exp_fulfillments).expect("types: duplicate deposit indexes?");
+        self.expected_withdrawal_fulfillments = FlatTable::try_from_unsorted(exp_fulfillments)
+            .expect(
+                "types: duplicate/unsorted deposit indexes? (expected_withdrawal_fulfillments)?",
+            );
 
         // Watch all utxos we have in our deposit table.
         let exp_outpoints = chainstate
@@ -101,8 +103,8 @@ impl TxFilterConfig {
             })
             .collect::<Vec<_>>();
 
-        self.expected_outpoints =
-            FlatTable::try_from(exp_outpoints).expect("types: duplicate deposit indexes?");
+        self.expected_outpoints = FlatTable::try_from_unsorted(exp_outpoints)
+            .expect("types: duplicate/unsorted deposit indexes? (expected_outpoints)");
     }
 }
 
diff --git a/crates/sequencer/src/checkpoint/worker.rs b/crates/sequencer/src/checkpoint/worker.rs
index b8216667b2..2fd6a141fa 100644
--- a/crates/sequencer/src/checkpoint/worker.rs
+++ b/crates/sequencer/src/checkpoint/worker.rs
@@ -1,7 +1,5 @@
 //! worker to monitor chainstate and create checkpoint entries.
 
-#![allow(unused)] // TODO clean this up once we're sure we don't need these fns
-
 use std::sync::Arc;
 
 use strata_db::{types::CheckpointEntry, DbError};
@@ -19,9 +17,7 @@ use strata_state::{
     header::*,
 };
 use strata_status::*;
-use strata_storage::{
-    ChainstateManager, CheckpointDbManager, L1BlockManager, L2BlockManager, NodeStorage,
-};
+use strata_storage::{CheckpointDbManager, L1BlockManager, L2BlockManager, NodeStorage};
 use strata_tasks::ShutdownGuard;
 use tokio::runtime::Handle;
 use tracing::*;
@@ -229,22 +225,10 @@ fn create_checkpoint_prep_data_from_summary(
     let l1man = storage.l1();
     let l2man = storage.l2();
     let chsman = storage.chainstate();
-    let rollup_params_hash = params.compute_hash();
 
     let epoch = summary.epoch();
     let is_genesis_epoch = epoch == 0;
 
-    let prev_checkpoint = if !is_genesis_epoch {
-        let prev_epoch = epoch - 1;
-        let prev = storage.checkpoint().get_checkpoint_blocking(prev_epoch)?;
-        if prev.is_none() {
-            warn!(%epoch, %prev_epoch, "missing expected checkpoint for previous epoch, continuing with none, this might produce an invalid checkpoint proof");
-        }
-        prev
-    } else {
-        None
-    };
-
     // There's some special handling we have to do if we're the genesis epoch.
     let prev_summary = if !is_genesis_epoch {
         let ec = summary.get_prev_epoch_commitment().unwrap();
@@ -308,8 +292,6 @@ fn fetch_epoch_l2_headers(
     summary: &EpochSummary,
     l2man: &L2BlockManager,
 ) -> anyhow::Result<Vec<L2BlockHeader>> {
-    let limit = 5000; // TODO make a const
-
     let mut headers = Vec::new();
 
     let terminal = fetch_l2_block(summary.terminal().blkid(), l2man)?;
@@ -320,9 +302,11 @@ fn fetch_epoch_l2_headers(
     //
     // The break conditions are a little weird so we use a bare `loop`.
     loop {
-        if headers.len() >= limit {
-            return Err(Error::MalformedEpoch(summary.get_epoch_commitment()).into());
-        }
+        // let limit = 5000; // TODO make a const
+        // TODO: we need some way to limit L2 blocks in an epoch, we can't just error like this
+        // if headers.len() >= limit {
+        //     return Err(Error::MalformedEpoch(summary.get_epoch_commitment()).into());
+        // }
 
         let cur = headers.last().unwrap();
         let cur_parent = cur.parent();
@@ -356,31 +340,8 @@ fn fetch_l2_block(blkid: &L2BlockId, l2man: &L2BlockManager) -> anyhow::Result<L
         .ok_or(Error::MissingL2Block(*blkid))?)
 }
 
-fn fetch_chainstate(slot: u64, chsman: &ChainstateManager) -> anyhow::Result<Chainstate> {
-    Ok(chsman
-        .get_toplevel_chainstate_blocking(slot)?
-        .ok_or(Error::MissingIdxChainstate(slot))?)
-}
-
 fn fetch_l1_block_manifest(height: u64, l1man: &L1BlockManager) -> anyhow::Result<L1BlockManifest> {
     Ok(l1man
         .get_block_manifest_at_height(height)?
         .ok_or(DbError::MissingL1Block(height))?)
 }
-
-/// Fetches and L1 block manifest, checking that the manifest that we found
-/// reported as specific epoch index.
-// TODO maybe convert this fn to use epoch commitments?
-fn fetch_block_manifest_at_epoch(
-    height: u64,
-    epoch: u64,
-    l1man: &L1BlockManager,
-) -> anyhow::Result<L1BlockManifest> {
-    let mf = fetch_l1_block_manifest(height, l1man)?;
-
-    if mf.epoch() != epoch {
-        return Err(Error::L1ManifestEpochMismatch(*mf.blkid(), mf.epoch(), epoch).into());
-    }
-
-    Ok(mf)
-}
diff --git a/crates/state/src/operation.rs b/crates/state/src/operation.rs
index 40baad142a..8aa80648c2 100644
--- a/crates/state/src/operation.rs
+++ b/crates/state/src/operation.rs
@@ -4,7 +4,7 @@
 use arbitrary::Arbitrary;
 use borsh::{BorshDeserialize, BorshSerialize};
 use serde::{Deserialize, Serialize};
-use strata_primitives::epoch::EpochCommitment;
+use strata_primitives::{batch::Checkpoint, epoch::EpochCommitment};
 
 use crate::{
     client_state::{CheckpointL1Ref, ClientState},
@@ -49,6 +49,7 @@ impl ClientUpdateOutput {
 
 /// Actions the client state machine directs the node to take to update its own
 /// database bookkeeping.
+#[allow(clippy::large_enum_variant)]
 #[derive(
     Clone, Debug, Eq, PartialEq, Arbitrary, BorshDeserialize, BorshSerialize, Deserialize, Serialize,
 )]
@@ -65,7 +66,7 @@ pub enum SyncAction {
 
     /// Checkpoint is included in L1 at given L1 reference.
     UpdateCheckpointInclusion {
-        epoch: u64,
+        checkpoint: Checkpoint,
         l1_reference: CheckpointL1Ref,
     },
 }
diff --git a/functional-tests/envs/testenv.py b/functional-tests/envs/testenv.py
index 1a9cb23fd9..98ec1aaf77 100644
--- a/functional-tests/envs/testenv.py
+++ b/functional-tests/envs/testenv.py
@@ -282,7 +282,7 @@ def init(self, ctx: flexitest.EnvContext) -> flexitest.LiveEnv:
 
         # set up network params
         initdir = ctx.make_service_dir("_init")
-        settings = self.rollup_settings or RollupParamsSettings.new_default()
+        settings = self.rollup_settings or RollupParamsSettings.new_default().fast_batch()
         params_gen_data = generate_simple_params(initdir, settings, self.n_operators)
         params = params_gen_data["params"]
         # Instantiaze the generated rollup config so it's convenient to work with.
diff --git a/functional-tests/tests/sync/sync_from_rpc.py b/functional-tests/tests/sync/sync_from_rpc.py
index 355463ddda..6faafb3e9e 100644
--- a/functional-tests/tests/sync/sync_from_rpc.py
+++ b/functional-tests/tests/sync/sync_from_rpc.py
@@ -4,6 +4,7 @@
 import flexitest
 
 from envs import testenv
+from utils.utils import wait_until_epoch_confirmed
 
 FOLLOW_DIST = 1
 
@@ -62,3 +63,13 @@ def main(self, ctx: flexitest.RunContext):
             \tseq {block_from_sequencer},\n\tfn {block_from_fullnode}"
         )
         assert seq_el_hash == fn_el_hash, "EL blocks don't match"
+
+        # Check fullnode sees same checkpoint reference as sequencer
+        epoch = 1
+        wait_until_epoch_confirmed(seqrpc, epoch)
+
+        fn_checkpt_info = fnrpc.strata_getCheckpointInfo(epoch)
+        sq_checkpt_info = seqrpc.strata_getCheckpointInfo(epoch)
+
+        assert fn_checkpt_info["l1_reference"] == sq_checkpt_info["l1_reference"]
+        assert fn_checkpt_info["confirmation_status"] == sq_checkpt_info["confirmation_status"]
diff --git a/functional-tests/tests/sync/sync_fullnode_l2_lag.py b/functional-tests/tests/sync/sync_fullnode_l2_lag.py
index d8e72ad9fa..52b1af59f6 100644
--- a/functional-tests/tests/sync/sync_fullnode_l2_lag.py
+++ b/functional-tests/tests/sync/sync_fullnode_l2_lag.py
@@ -17,6 +17,8 @@ def __init__(self, ctx: flexitest.InitContext):
         ctx.set_env(env)
 
     def main(self, ctx: flexitest.RunContext):
+        # TODO: re-enable this after full node sync is fixed
+        return True
         seq = ctx.get_service("seq_node")
         seqrpc = seq.create_rpc()
         fullnode = ctx.get_service("follower_1_node")
diff --git a/provers/sp1/guest-cl-stf/Cargo.toml b/provers/sp1/guest-cl-stf/Cargo.toml
index 4a1f976e64..bef7f7d03a 100644
--- a/provers/sp1/guest-cl-stf/Cargo.toml
+++ b/provers/sp1/guest-cl-stf/Cargo.toml
@@ -12,9 +12,9 @@ zkaleido-sp1-adapter = { git = "https://github.com/alpenlabs/zkaleido", tag = "v
 ] }
 
 [patch.crates-io]
+k256 = { git = "https://github.com/sp1-patches/elliptic-curves", tag = "patch-k256-13.4-sp1-4.1.0" }
 secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", branch = "patch-secp256k1-v0.29.1" }
 sha2-v0-10-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.10.8" }
-k256 = { git = "https://github.com/sp1-patches/elliptic-curves", tag = "patch-k256-13.4-sp1-4.1.0" }
 
 [features]
 mock = ["zkaleido-sp1-adapter/mock"]
diff --git a/provers/sp1/guest-evm-ee-stf/Cargo.toml b/provers/sp1/guest-evm-ee-stf/Cargo.toml
index 5a23446dc5..bc056be90a 100644
--- a/provers/sp1/guest-evm-ee-stf/Cargo.toml
+++ b/provers/sp1/guest-evm-ee-stf/Cargo.toml
@@ -12,12 +12,12 @@ zkaleido-sp1-adapter = { git = "https://github.com/alpenlabs/zkaleido", tag = "v
 ] }
 
 [patch.crates-io]
+k256 = { git = "https://github.com/sp1-patches/elliptic-curves", tag = "patch-k256-13.4-sp1-4.1.0" }
 revm = { git = "https://github.com/sp1-patches/revm-new", branch = "john/update-for-v1" }
 revm-primitives = { git = "https://github.com/sp1-patches/revm-new", branch = "john/update-for-v1" }
 secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", branch = "patch-secp256k1-v0.29.1" }
 sha2-v0-10-8 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha2", branch = "patch-sha2-v0.10.8" }
 tiny-keccak = { git = "https://github.com/sp1-patches/tiny-keccak", branch = "patch-v2.0.2" }
-k256 = { git = "https://github.com/sp1-patches/elliptic-curves", tag = "patch-k256-13.4-sp1-4.1.0" }
 
 
 [features]


Reviews:
user: login: sapinb
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T10:24:02Z
user: login: sapinb
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T10:26:03Z
user: login: sapinb
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T14:59:04Z
user: login: sapinb
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T15:50:08Z
user: login: delbonis
body: This is a good improvement to handle that oversight and ensure more correct behavior.

But I still kindaaa feel like the checkpoint entry types could be split out more because this table still feels like it's serving multiple roles.  I guess as a rough comparison, we don't have a specially-tagged version of a block entry that we store on disk while we're constructing it before it's broadcast.  I don't think this is actionable here yet but it's something to keep in mind.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T21:20:03Z
user: login: bewakes
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T05:41:44Z
user: login: bewakes
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T05:44:24Z
user: login: bewakes
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T05:45:24Z
user: login: sapinb
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T07:27:00Z

Review comments:
diff_hunk: @@ -320,9 +320,10 @@ fn fetch_epoch_l2_headers(
     //
     // The break conditions are a little weird so we use a bare `loop`.
     loop {
-        if headers.len() >= limit {
-            return Err(Error::MalformedEpoch(summary.get_epoch_commitment()).into());
-        }
+        // TODO: we need some way to limit L2 blocks in an epoch, we can't just error like this
+        // if headers.len() >= limit {
path: crates/sequencer/src/checkpoint/worker.rs
user: login: sapinb
body: can we also remove the unused limit variable ?
`#[allow(unused)]` 😞 
created_at: 2025-03-06T10:24:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,3 +63,14 @@ def main(self, ctx: flexitest.RunContext):
             \tseq {block_from_sequencer},\n\tfn {block_from_fullnode}"
         )
         assert seq_el_hash == fn_el_hash, "EL blocks don't match"
+
+        # Check fullnode sees same checkpoint reference as sequencer
+        wait_until(
+            lambda: seqrpc.strata_getCheckpointInfo(0)["confirmation_status"] != "pending",
+            error_with="Did not see checkpoint in l1",
+        )
+        fn_checkpt_info = fnrpc.strata_getCheckpointInfo(0)
+        sq_checkpt_info = seqrpc.strata_getCheckpointInfo(0)
path: functional-tests/tests/sync/sync_from_rpc.py
user: login: sapinb
body: can we wait and check till checkpoint 1 or 2 is synced correctly? Just to cover more ground with this test.
created_at: 2025-03-06T10:26:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,3 +63,16 @@ def main(self, ctx: flexitest.RunContext):
             \tseq {block_from_sequencer},\n\tfn {block_from_fullnode}"
         )
         assert seq_el_hash == fn_el_hash, "EL blocks don't match"
+
+        # Check fullnode sees same checkpoint reference as sequencer
+        epoch = 1
+        wait_until(
+            lambda: seqrpc.strata_getCheckpointInfo(epoch)["confirmation_status"] != "pending",
+            error_with="Did not see checkpoint in l1",
+            timeout=15,
+        )
path: functional-tests/tests/sync/sync_from_rpc.py
user: login: delbonis
body: Should have a dedicated utils fn for this.  This is rather ad-hoc.  See the others I added recently.
created_at: 2025-03-06T21:11:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -376,12 +376,22 @@ fn apply_action(
 
         // Update checkpoint entry in database to mark it as included in L1.
         SyncAction::UpdateCheckpointInclusion {
-            epoch,
+            checkpoint,
             l1_reference,
         } => {
-            let Some(mut ckpt_entry) = ckpt_db.get_checkpoint_blocking(epoch)? else {
-                warn!(%epoch, "missing checkpoint we wanted to set the state of, ignoring");
-                return Ok(());
+            let epoch = checkpoint.batch_info().epoch();
+
+            let mut ckpt_entry = match ckpt_db.get_checkpoint_blocking(epoch)? {
+                Some(c) => c,
+                None => {
+                    warn!(%epoch, "missing checkpoint we wanted to set the state of, creating new entry");
path: crates/consensus-logic/src/csm/worker.rs
user: login: delbonis
body: I don't really think this is a warning to be honest.

Also, what should we do in the case of reorgs?  This won't be an issue here but maybe we should create a ticket if there isn't a simple and obviously correct way to deal with it.
created_at: 2025-03-06T21:13:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -376,12 +376,22 @@ fn apply_action(
 
         // Update checkpoint entry in database to mark it as included in L1.
         SyncAction::UpdateCheckpointInclusion {
-            epoch,
+            checkpoint,
             l1_reference,
         } => {
-            let Some(mut ckpt_entry) = ckpt_db.get_checkpoint_blocking(epoch)? else {
-                warn!(%epoch, "missing checkpoint we wanted to set the state of, ignoring");
-                return Ok(());
+            let epoch = checkpoint.batch_info().epoch();
+
+            let mut ckpt_entry = match ckpt_db.get_checkpoint_blocking(epoch)? {
+                Some(c) => c,
+                None => {
+                    warn!(%epoch, "missing checkpoint we wanted to set the state of, creating new entry");
+
+                    CheckpointEntry::new(
+                        checkpoint,
+                        CheckpointProvingStatus::ProofReady,
+                        CheckpointConfStatus::Pending,
+                    )
+                }
             };
 
             ckpt_entry.confirmation_status = CheckpointConfStatus::Confirmed(l1_reference);
path: crates/consensus-logic/src/csm/worker.rs
user: login: delbonis
body: When we're constructing a new one, can't we preemptively set it as `Confirmed` here?  I suppose it doesn't really matter.
created_at: 2025-03-06T21:14:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,3 +63,16 @@ def main(self, ctx: flexitest.RunContext):
             \tseq {block_from_sequencer},\n\tfn {block_from_fullnode}"
         )
         assert seq_el_hash == fn_el_hash, "EL blocks don't match"
+
+        # Check fullnode sees same checkpoint reference as sequencer
+        epoch = 1
+        wait_until(
+            lambda: seqrpc.strata_getCheckpointInfo(epoch)["confirmation_status"] != "pending",
+            error_with="Did not see checkpoint in l1",
+            timeout=15,
+        )
path: functional-tests/tests/sync/sync_from_rpc.py
user: login: bewakes
body: Yes, used the one there's already there.
created_at: 2025-03-07T05:41:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -376,12 +376,22 @@ fn apply_action(
 
         // Update checkpoint entry in database to mark it as included in L1.
         SyncAction::UpdateCheckpointInclusion {
-            epoch,
+            checkpoint,
             l1_reference,
         } => {
-            let Some(mut ckpt_entry) = ckpt_db.get_checkpoint_blocking(epoch)? else {
-                warn!(%epoch, "missing checkpoint we wanted to set the state of, ignoring");
-                return Ok(());
+            let epoch = checkpoint.batch_info().epoch();
+
+            let mut ckpt_entry = match ckpt_db.get_checkpoint_blocking(epoch)? {
+                Some(c) => c,
+                None => {
+                    warn!(%epoch, "missing checkpoint we wanted to set the state of, creating new entry");
path: crates/consensus-logic/src/csm/worker.rs
user: login: bewakes
body: Yes, this isn't a warning anymore. Corrected.

In case of reorgs, we should probably clear the corresponding database checkpoint entries(and possibly other entries which might be related). Just reverting L1 manifests and corresponding tx entries won't be enough.
created_at: 2025-03-07T05:44:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -376,12 +376,22 @@ fn apply_action(
 
         // Update checkpoint entry in database to mark it as included in L1.
         SyncAction::UpdateCheckpointInclusion {
-            epoch,
+            checkpoint,
             l1_reference,
         } => {
-            let Some(mut ckpt_entry) = ckpt_db.get_checkpoint_blocking(epoch)? else {
-                warn!(%epoch, "missing checkpoint we wanted to set the state of, ignoring");
-                return Ok(());
+            let epoch = checkpoint.batch_info().epoch();
+
+            let mut ckpt_entry = match ckpt_db.get_checkpoint_blocking(epoch)? {
+                Some(c) => c,
+                None => {
+                    warn!(%epoch, "missing checkpoint we wanted to set the state of, creating new entry");
+
+                    CheckpointEntry::new(
+                        checkpoint,
+                        CheckpointProvingStatus::ProofReady,
+                        CheckpointConfStatus::Pending,
+                    )
+                }
             };
 
             ckpt_entry.confirmation_status = CheckpointConfStatus::Confirmed(l1_reference);
path: crates/consensus-logic/src/csm/worker.rs
user: login: bewakes
body: Yeah, it doesn't matter. I just didn't want to re-set the same status twice.
created_at: 2025-03-07T05:45:24Z
author_association: CONTRIBUTOR

PR comments:
user: login: codecov[bot]
created_at: 2025-03-06T10:19:26Z
body: ## [Codecov](https://app.codecov.io/gh/alpenlabs/strata/pull/718?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) Report
Attention: Patch coverage is `0%` with `17 lines` in your changes missing coverage. Please review.
> Project coverage is 54.77%. Comparing base [(`5f647be`)](https://app.codecov.io/gh/alpenlabs/strata/commit/5f647bea009e28d78311e7f67bdb725ea68fd4d3?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) to head [(`85bb2ce`)](https://app.codecov.io/gh/alpenlabs/strata/commit/85bb2ced34ed39de6dc39e32ac8754558cd06773?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs).
> Report is 1 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/alpenlabs/strata/pull/718?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) | Patch % | Lines |
|---|---|---|
| [crates/consensus-logic/src/csm/worker.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/718?src=pr&el=tree&filepath=crates%2Fconsensus-logic%2Fsrc%2Fcsm%2Fworker.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-Y3JhdGVzL2NvbnNlbnN1cy1sb2dpYy9zcmMvY3NtL3dvcmtlci5ycw==) | 0.00% | [10 Missing :warning: ](https://app.codecov.io/gh/alpenlabs/strata/pull/718?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) |
| [crates/l1tx/src/filter/types.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/718?src=pr&el=tree&filepath=crates%2Fl1tx%2Fsrc%2Ffilter%2Ftypes.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-Y3JhdGVzL2wxdHgvc3JjL2ZpbHRlci90eXBlcy5ycw==) | 0.00% | [6 Missing :warning: ](https://app.codecov.io/gh/alpenlabs/strata/pull/718?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) |
| [...rates/consensus-logic/src/csm/client\_transition.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/718?src=pr&el=tree&filepath=crates%2Fconsensus-logic%2Fsrc%2Fcsm%2Fclient_transition.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-Y3JhdGVzL2NvbnNlbnN1cy1sb2dpYy9zcmMvY3NtL2NsaWVudF90cmFuc2l0aW9uLnJz) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/alpenlabs/strata/pull/718?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) |

```diff
@@            Coverage Diff             @@
##             main     #718      +/-   ##
==========================================
+ Coverage   54.73%   54.77%   +0.04%     
==========================================
  Files         317      317              
  Lines       35414    35391      -23     
==========================================
+ Hits        19385    19387       +2     
+ Misses      16029    16004      -25     
```

| [Files with missing lines](https://app.codecov.io/gh/alpenlabs/strata/pull/718?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs) | Coverage Δ | |
|---|---|---|
| [crates/sequencer/src/checkpoint/worker.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/718?src=pr&el=tree&filepath=crates%2Fsequencer%2Fsrc%2Fcheckpoint%2Fworker.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-Y3JhdGVzL3NlcXVlbmNlci9zcmMvY2hlY2twb2ludC93b3JrZXIucnM=) | `0.00% <ø> (ø)` | |
| [crates/state/src/operation.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/718?src=pr&el=tree&filepath=crates%2Fstate%2Fsrc%2Foperation.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-Y3JhdGVzL3N0YXRlL3NyYy9vcGVyYXRpb24ucnM=) | `45.00% <ø> (ø)` | |
| [...rates/consensus-logic/src/csm/client\_transition.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/718?src=pr&el=tree&filepath=crates%2Fconsensus-logic%2Fsrc%2Fcsm%2Fclient_transition.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-Y3JhdGVzL2NvbnNlbnN1cy1sb2dpYy9zcmMvY3NtL2NsaWVudF90cmFuc2l0aW9uLnJz) | `70.32% <0.00%> (ø)` | |
| [crates/l1tx/src/filter/types.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/718?src=pr&el=tree&filepath=crates%2Fl1tx%2Fsrc%2Ffilter%2Ftypes.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-Y3JhdGVzL2wxdHgvc3JjL2ZpbHRlci90eXBlcy5ycw==) | `60.91% <0.00%> (-1.44%)` | :arrow_down: |
| [crates/consensus-logic/src/csm/worker.rs](https://app.codecov.io/gh/alpenlabs/strata/pull/718?src=pr&el=tree&filepath=crates%2Fconsensus-logic%2Fsrc%2Fcsm%2Fworker.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs#diff-Y3JhdGVzL2NvbnNlbnN1cy1sb2dpYy9zcmMvY3NtL3dvcmtlci5ycw==) | `0.00% <0.00%> (ø)` | |

... and [3 files with indirect coverage changes](https://app.codecov.io/gh/alpenlabs/strata/pull/718/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=alpenlabs)

<details><summary>🚀 New features to boost your workflow: </summary>

- ❄ [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-06T10:41:26Z
body: **Commit**: f2343e3b

**SP1 Performance Test Results**
 
| program           | cycles      | success  |
|-------------------|-------------|----------|
| BTC_BLOCKSPACE    |      59,844 | ✅       |
| EL_BLOCK          |     118,411 | ✅       |
| CL_BLOCK          |      73,123 | ✅       |
| CHECKPOINT        |       2,616 | ✅       |


author_association: CONTRIBUTOR
user: login: sapinb
created_at: 2025-03-06T15:48:45Z
body: can we disable this failing fn test `sync_fullnode_l2_lag` ? I'll enable it when its fixed in #715 
author_association: CONTRIBUTOR