Verifier
Table of Contents
Derivation Pipeline
The derivation pipeline enforces invariants on safe blocks that include executing messages.
- The executing message MUST have a corresponding initiating message
- The initiating message that corresponds to an executing message MUST come from a chain in its dependency set
- A block MUST be considered invalid if it is built with any invalid executing messages
Blocks that contain transactions that relay cross domain messages to the destination chain where the initiating transaction does not exist MUST be considered invalid and MUST not be allowed by the derivation pipeline to be considered safe.
There is no concept of replay protection at the lowest level of abstractions within the protocol because there is no replay protection mechanism that fits well for all applications. Users MAY submit an arbitrary number of executing messages per initiating message. Applications MUST build their own replay protection mechanisms if they are interacting with the lowest level abstractions.
Blocks that contain invalid executing messages are considered invalid by the protocol. The derivation
pipeline will never promote them from being unsafe
. A block that contains invalid executing messages
MUST be replaced by a deposits only block at the same block number.
Depositing an Executing Message
Deposit transactions (force inclusion transactions) give censorship resistance to layer two networks. The derivation pipeline must gracefully handle the case in which a user uses a deposit transaction to relay a cross chain message. To not couple preconfirmation security to consensus, deposit transactions that execute cross chain messages MUST have an initiating message that is considered safe by the remote chain's derivation pipeline. This relaxes a strict synchrony assumption on the sequencer that it MUST have all unsafe blocks of destination chains as fast as possible to ensure that it is building correct blocks.
If a deposit transaction references an initiating transaction that is not yet safe or does not exist, it MUST be dropped by the derivation pipeline.
This inclusion property prevents a class of attacks where the user can trick the derivation pipeline into reorganizing the sequencer.
Safety
Safety is an abstraction that is useful for reasoning about security. It should be thought about
as a spectrum from unsafe
to finalized
. Users can choose to operate on information based on its
level of safety depending on their risk profile and personal preferences.
The following labels are used to describe both inputs and outputs:
unsafe
cross-unsafe
safe
finalized
Inputs correspond to the inputs to the state transition function while outputs correspond to the side effects of the state transition function.
Anything before safe
technically uses a "preconfirmation" based security model which is not part
of consensus. While useful to have definitions of the default meanings of these terms, they are
technically policy and may be changed in the future.
The unsafe
label has the lowest latency while the finalized
label has the highest latency.
A set of invariants must be held true before an input or an output can be promoted to the next
label, starting at unsafe
.
The initiating messages for all dependent executing messages MUST be resolved as safe before an L2 block can transition from being unsafe to safe. Users MAY optimistically accept unsafe blocks without any verification of the executing messages. They SHOULD optimistically verify the initiating messages exist in destination unsafe blocks to more quickly reorganize out invalid blocks.
unsafe
Inputs
- MUST be signed by the p2p sequencer key
- MAY be reorganized
- MUST be promoted to a higher level of safety or reorganized out to ensure liveness
unsafe
inputs are currently gossiped around the p2p network. To prevent denial of service, they MUST
be signed by the sequencer. This signature represents the sequencer's claim that it
built a block that conforms to the protocol. unsafe
blocks exist to give low latency access to the
latest information. To keep the latency as low as possible, cross chain messages are assumed valid
at this stage. This means that the remote unsafe inputs are trusted solely because they were
included in a block by the sequencer.
An alternative approach to unsafe
inputs would be to include an SGX proof that the sequencer ran
particular software when building the block.
cross-unsafe
Inputs
- MUST have valid cross chain messages
cross-unsafe
represents the unsafe
blocks that had their cross chain messages fully verified.
The network can be represented as a graph where each block across all chains are represented as
a node and then a directed edge between two blocks represents the source block of the initiating
message and the block that included the executing message.
An input can be promoted from unsafe
to cross-unsafe
when the full dependency graph is resolved
such that all cross chain messages are verified to be valid and at least one message in the dependency
graph is still unsafe
.
Note that the cross-unsafe
is not meant to be exposed to the end user via the RPC label. It is
meant for internal usage. All cross-unsafe
inputs are still considered unsafe
by the execution
layer RPC.
safe
Inputs
- MUST be available
- MAY be reorganized
- Safe block MUST be invalidated if a reorg occurs
safe
represents the state in which the cross-unsafe
dependency graph has been fully resolved
in a way where all of the data has been published to the data availability layer.
finalized
Inputs
- MUST NOT be reorganized based on Ethereum economic security
finalized
represents full Proof of Stake economic security on top of the data. This means that
if the data is reorganized, then validators will be slashed.
Honest Verifier
The honest verifier follows a naive verification algorithm. That is similar to the block building code that the sequencer follows. The main difference is that the validity of included executing messages is verified instead of verifying possible executing messages before inclusion.
Security Considerations
Forced Inclusion of Cross Chain Messages
The design is particular to not introduce any sort of "forced inclusion" between L2s. This design space introduces risky synchrony assumptions and forces the introduction of a message queue to prevent denial of service attacks where all chains in the network decide to send cross chain messages to the same chain at the same time.
"Forced inclusion" transactions are good for censorship resistance. In the worst case of censoring sequencers, it will take at most 2 sequencing windows for the cross chain message to be processed. The initiating transaction can be sent via a deposit which MUST be included in the source chain or the sequencer will be reorganized at the end of the sequencing window that includes the deposit transaction. If the executing transaction is censored, it will take another sequencing window of time to force the inclusion of the executing message per the spec.
What if Safety isn't Enough?
It is possible that small latency differences may impact the allowance of deposited executing messages if the rule is that the initiating message is safe. A more strict invariant may be introduced:
identifier.timestamp + sequencer_window <= block.timestamp
This says that a sequencer window must elapse before the initiating message can be referenced in an executing message.
Reliance on History
When fully executing historical blocks, a dependency on historical receipts from remote chains is present. EIP-4444 will eventually provide a solution for making historical receipts available without needing to require increasingly large execution client databases.
It is also possible to introduce a form of expiry on historical receipts by enforcing that the timestamp
is recent enough in the CrossL2Inbox
.