Skip to content

Conversation

@linoscope
Copy link
Collaborator

Problem

Currently, Shasta derivation performs validation at the proposal level. During derivation, raw proposal data is transformed into L2 blocks, and both the proposal and resulting blocks undergo validation—a process that may modify or filter them out.

This per-proposal validation creates an issue for preconfirmations, which operate on individual blocks rather than complete proposals. The validation logic used during proposal submission cannot be directly applied at preconfirmation time. This mismatch enables the following scenario:

  1. At preconf time: The preconfer broadcasts blocks to the P2P network
  2. At proposal time: The preconfer submits a proposal to L1 that derives into different blocks

A malicious or careless preconfer can exploit this to cause reorgs by making step 2 produce blocks that differ from step 1.

Note that we cannot slash for this behavior. Preconfirmations commit to rawTxList + metadata rather than block hashes, i.e., the inputs needed to derive blocks, not the blocks themselves. From a slashing perspective, the preconfer technically delivered what they promised; the issue is that derivation produced different outputs at different times.

Solution

To avoid such reorgs, the property we want is the following: The validation of preconf blocks must be strictly stricter than the validation in the derivation. This gives us the property where “if block is accepted at proposal time, it is accepted at preconf time”.

Implementation

  • Gas limit: Uses the same logic as derivation. Validates that gas limit is within 0.999990x to 1.000010x of the effective parent gas limit (parent gas - 250K).

  • Timestamp: Validates timestamp is within bounds: lower_bound = max(parent_timestamp + 1, now() - MAX_TIMESTAMP_DRIFT), upper_bound = min(submissionWindowEnd, now() + MAX_TIMESTAMP_DRIFT). Ensures timestamps are monotonic and don't drift too far from current time or exceed the submission window.

  • Anchor block number: Validates anchor block number is within acceptable drift from the last seen L1 head, ensuring it's not too far in the past or future. For the first block of a proposal, additionally requires that the anchor block number increments by at least one from the parent.

  • Sufficient bond: Verifies that the proposer has sufficient bond funds by calling hasSufficientBond(proposer) before accepting the preconfirmation.

Verifies that the gas limit is within acceptable bounds based on parent gas limit.
"""
parent_gas = parentState.gasLimit
effective_parent = parent_gas - 250000 # 250K
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where did this come from?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this 250K should be a parameter as well?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the exact same logic in derivation, will more properly comment.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the function to be more descriptive and use the constants defined in derivation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants