Conversation
einar-oplabs
left a comment
There was a problem hiding this comment.
Good and thorough description of your design 👍 .
|
Thanks for taking care of the design doc @pcw109550!
|
Thanks for raising this. I agree that at the network level there is a form of bidirectional interaction in sequencer deployments, especially when a Light CL sequencer follows a normal (non-light) verifier. At a high level, the interaction looks like this: the Light CL sequencer produces and gossips unsafe blocks, which the verifier may consume as candidates, while the verifier publishes safe / finalized / currentL1 that the Light CL sequencer follows. This creates a network-level feedback relationship between the two nodes. flowchart LR
subgraph SEQ ["Sequencer (Light CL)"]
direction TB
SeqUnsafe["Unsafe blocks"]
SeqSafe["Safe / Finalized view"]
end
subgraph VER ["Verifier (Normal CL)"]
direction TB
VerUnsafe["Unsafe blocks"]
VerSafe["Safe / Finalized view<br/>(L1-anchored)"]
end
%% Proposal path
SeqUnsafe -->|gossip proposal| VerUnsafe
%% Confirmation path
VerSafe -->|optimism_syncStatus| SeqSafe
However, despite this bidirectional network reality, the authority hierarchy remains strictly one-directional, and this is the key reason it does not introduce race conditions or circular control dependencies. We can reason about this more precisely as follows:
Concretely, using explicit dependencies (A -> B means B depends on A):
flowchart LR
%% =========================================================
%% Panel 1: Normal Sequencer <> Normal Verifier
%% =========================================================
subgraph P1 ["Normal Sequencer"]
direction LR
N_L1["L1 (Canonical)"]
subgraph N_SEQ["Sequencer (Normal CL)"]
N_SeqSafe["Seq-Safe"] -->|consolidate| N_SeqUnsafe["Seq-Unsafe"]
end
subgraph N_VER["Verifier (Normal CL)"]
N_VerSafe["Ver-Safe"] -->|consolidate| N_VerUnsafe["Ver-Unsafe"]
end
%% Normal CL anchors
N_L1 -->|derive| N_VerSafe
N_L1 -->|derive| N_SeqSafe
%% Requested link: Seq-Unsafe still needs L1 origin
N_L1 -->|origin| N_SeqUnsafe
%% Network flow
N_SeqUnsafe -->|gossip| N_VerUnsafe
end
%% =========================================================
%% Panel 2: Light CL Sequencer <> Normal Verifier
%% =========================================================
subgraph P2 ["Light CL Sequencer"]
direction LR
L_L1["L1 (Canonical)"]
subgraph L_SEQ["Sequencer (Light CL)"]
L_SeqSafe["Seq-Safe"] -->|consolidate| L_SeqUnsafe["Seq-Unsafe"]
end
subgraph L_VER["Verifier (Normal CL)"]
L_VerSafe["Ver-Safe"] -->|consolidate| L_VerUnsafe["Ver-Unsafe"]
end
%% Verifier anchors
L_L1 -->|derive| L_VerSafe
%% Light CL differences
L_VerSafe -.->|**follow**| L_SeqSafe
L_L1 -->|origin| L_SeqUnsafe
%% Network flow
L_SeqUnsafe -->|gossip| L_VerUnsafe
end
%% Styling
style P1 fill:#f9f9f9,stroke:#333,stroke-dasharray: 5 5
style P2 fill:#f0f7ff,stroke:#005fb8,stroke-width:2px
The important point is that the only cross-node authoritative dependency is Ver-Safe -> Seq-Safe. The reverse direction (Seq-Unsafe -> Ver-Unsafe) is strictly non-authoritative and exists purely as a proposal mechanism. The verifier's safe chain remains derived from and anchored to canonical L1, not dependent on the sequencer's safe view. As a result, although there is a bidirectional network interaction, there is no circular authority and no race condition in the correctness sense. Timing skew between locally advancing unsafe state and externally advancing safe state is expected in a distributed setting, and the follow algorithm is explicitly designed to reconcile these updates safely (consolidation, reorg, block-not-found cases, etc.). In short, this is a proposal / confirmation loop, not a circular control dependency, and authority continues to flow in a single direction: L1 -> Ver-Safe -> Seq-Safe. |
Good point. The doc currently focuses on the follower behavior, but it should state the contract/assumptions for |
|
My brain dump about the similarity between the
So the key difference is who owns finalization:
This matches the review point that the external derivation actor should own finalization and Light CL should not care about it:
So if we decide to view the
Let's hypothetically introduce a Normal CL flow:
Light CL flow:
So, I think the "FollowActor ~= DerivationActor" framing is plausible, but it only becomes clean if we also standardize where finalization lives. Otherwise we end up with two different finalization ownership models depending on mode. I am open to adapting the trait pattern / interface shape here, especially if there is a minimal way to provide the necessary L1 -> L2 linkage for followed safe blocks without reintroducing derivation coupling. |
I agree this line of thinking is consistent with the direction we’re already discussing (moving finalization out of The main distinction is that switching the existing in-process I do think this is a natural followup direction once the ownership model is clear, and I am open to moving toward an RPC-based boundary in a subsequent step. |
|
@op-will, @theochap and I had a synchronous design review and reached consensus: [Short term for landing the light CL]
[Long term goal]
Will update the design doc with respect to above bullet point. |
|
|
||
| - Tracking system configuration updates | ||
| - Tracking L1 origin for sequencer operation | ||
| While it is technically possible for a Light CL to follow another Light CL, operators must avoid cycles in the light CL dependency graph. |
There was a problem hiding this comment.
Why would a light CL follow another one? Aren't we going to run one lightCL per sequencer?
It would make more sense to me that two separate light CLs follow one normal validator node (like inside a conductor set)
There was a problem hiding this comment.
Regarding that, we could simply remove this undefined behavior by adding an RPC endpoint to kona nodes that specify whether a node is a "normal" or a "light" CL
There was a problem hiding this comment.
I think this is already specified as an assumption and doesn't need to be clarified.
A critical assumption of a Light CL is that it delegates derivation to a node that has accurate and up-to-date derivation information. This is just another way of stating that assumption and can be removed.
There was a problem hiding this comment.
Making a Light CL follow another Light CL is defined behavior that enables a "Fan-out" scaling pattern.
For example, we can expose a light CL endpoint to a public, which the general public will run their own light CL using the endpoint.
The design is agnostic: if a node provides a valid DerivationState, it is a valid source. Prohibiting this would limit this kind of scalability and deployment flexibility.
theochap
left a comment
There was a problem hiding this comment.
Looks good to me. Thanks for taking the time to update the document
op-will
left a comment
There was a problem hiding this comment.
Looks good!
I left a number of comments around verbiage and clarity that you may or may not choose to adopt, but the design looks great!
| #### Cycles and Authority Graph Constraints | ||
|
|
||
| While it is technically possible for a Light CL to follow another Light CL, operators must avoid cycles in the light CL dependency graph. | ||
|
|
||
| Circular dependencies in `{safeL2, finalizedL2, currentL1}` authority can lead to undefined behavior and circular trust assumptions. | ||
|
|
||
| Operational guidance: | ||
| - The light CL dependency graph must be acyclic | ||
| - At least one node in the graph must terminate in a deriving rollup node that directly consumes L1 data |
There was a problem hiding this comment.
Does this section need to exist?
If we change our semantics from follow to delegate derivation to, this concern becomes obvious: a CL should not delegate derivation to another CL that is also delegating derivation since it would be delegating a responsibility that is potentially unfulfilled.
Even if an operator chooses to do this, we already state the assumption that the delegate serves accurate derivation state.
There was a problem hiding this comment.
I believe this section should remain because it defines the Terminal Authority required for safe chain progression.
While "delegation" implies trust, it doesn't explicitly guarantee termination.
Summary
This PR adds a public design document describing Light CL as implemented in kona-node.
Light CL is an OP Stack consensus client mode that disables local derivation and instead follows externally derived consensus data (
safe,finalized,currentL1) via theoptimism_syncStatusRPC, while continuing to execute the local EL and maintain unsafe chain progression.A reviewed internal Light CL design doc already exists and was used to implement the feature in op-node (Go), which has since been merged (PR1, PR2). After that work, I independently implemented Light CL(PR) for kona-node (Rust), resulting in a non-trivial architectural change (~1000 LOC).
This PR documents that kona-node implementation.
Motivation
The kona-node Light CL implementation introduces a new operational mode with clear architectural consequences:
safe/finalized/currentL1moves to an external CLWhile the code is functional(acceptance tests passing / deployed to devnet), the behavior may difficult to reason about without a written design, especially for maintainers who did not author the change. Relying on code alone would make invariants, trust assumptions, and failure modes implicit and easy to misunderstand.
This design doc exists to:
Scope
The goal is to record and explain an architectural mode that has already shipped in op-node, in a way that is reviewable, maintainable, and consistent with the rest of the kona-node design.