Skip to content

Interop Filter Overview #24

@lucasmt

Description

@lucasmt

The Interop Filter is a service, independent from the Supernode, for cross-unsafe validation of blocks and transactions.

In the following, we give a short description of its architecture, describe its basic modes of operation and highlight differences from Supernode. Our investigation is based on commit https://github.com/ethereum-optimism/optimism/tree/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696.

Our findings are presented in #60.

Informational findings are described in #31 and #36.

Descriptions for the functions of the LockstepCrossValidator and LogsDBChainIngester modules, produced during the audit, can be found in the appendices in #30 and #35, respectively.

Architecture

flowchart LR
    subgraph be[Backend]
        subgraph ci1[ChainIngester]
            ldb1[(LogsDB)]
        end
        subgraph ci2[ChainIngester]
            ldb2[(LogsDB)]
        end
        subgraph ci3[ChainIngester]
            ldb3[(LogsDB)]
        end

        cv[CrossValidator]
        ci1-.-cv
        ci2-.-cv
        ci3-.-cv
    end

    be-.-qfe[QueryFrontend]
    be-.-afe[AdminFrontend]
Loading

The Interop Filter includes the following components:

  • A ChainIngester for each L2 chain, responsible for continuously reading blocks from the respective chain and storing them in a LogsDB. This runs asynchronously from the cross-validation loop, and tries to process as many blocks as are available. The ChainIngester is also responsible for detecting reorgs in its chain and raising the appropriate error.
  • A CrossValidator, responsible for cross-validating the data stored across the LogsDBs of each chain. Cross-validation proceeds one timestamp at a time, similarly to the Supernode, and tracks the latest cross-validated timestamp. It can also be queried to validate an executing message present in a transaction's access list, checking that this message is recorded in the corresponding chain's LogsDB and that it has been cross-validated.
  • Two frontends: a public QueryFrontend used for querying the CrossValidator to confirm the cross-validity of an access-list entry, and an authenticated AdminFrontend exposing methods to enable and disable the failsafe mode. When failsafe mode is enabled, cross-validity queries to the Interop Filter are blocked.

Modes of Operation

Failsafe Mode

In failsafe mode, the Backend rejects all CheckAccessList queries.

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/backend.go#L132-L139

Failsafe mode is active if it has been manually enabled, or if any major component (the CrossValidator or any ChainIngester) is in the error state.

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/backend.go#L93-L97

It can be manually triggered via AdminFrontend.

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/frontend.go#L43-L47

Error State Handling

CrossValidator

CrossValidator sets its error state in its validation loop if it fails to validate a given timestamp.

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/lockstep_cross_validator.go#L308-L313

Once in the error state, the cross-validation loop stalls and waits.

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/lockstep_cross_validator.go#L252-L266

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/lockstep_cross_validator.go#L268-L273

For a detailed and more formal description of CrossValidator error handling, see #30.

ChainIngester

A ChainIngester sets its error state in its ingestion loop if it detects a reorg,

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/logsdb_chain_ingester.go#L551-L552

if it fails to ingest a block due to parent hash mismatch,

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/logsdb_chain_ingester.go#L609-L615

or if it fails to add a new block and its logs to the LogsDB

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/logsdb_chain_ingester.go#L620-L635

In all cases, block ingestion stalls while the error state is set.

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/logsdb_chain_ingester.go#L410-L413

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/logsdb_chain_ingester.go#L583-L585

An error in any ingester also causes the CrossValidator's validation loop to stall.

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/lockstep_cross_validator.go#L275-L283

For a detailed description of CrossValidator error handling, see #36.

Failure Recovery

Neither CrossValidator nor ChainIngester implement a way to clear their error states programmatically. (While ChainIngester does expose a ClearError method, it is only called in tests.) Restoring the service to a functioning state therefore requires manual intervention: stopping the service, restoring the database to a known-good state by either rewinding or flushing it, and then restarting the service.

We note that AdminFrontend does define a Rewind endpoint, but at the commit under investigation it is not yet implemented.

https://github.com/ethereum-optimism/optimism/blob/be00aaa2cc3c8bea80e916d17c30a2b5d8d87696/op-interop-filter/filter/frontend.go#L49-L54

Normal Mode

When the service is not in failsafe mode, i.e. the manual failsafe is disabled, and neither CrossValidator nor any ChainIngester is in the error state, normal operation proceeds:

  • CheckAccessList queries are served.
  • The CrossValidator continues advancing the cross-validated timestamp.
  • Each ChainIngester continues ingesting blocks into its LogsDB.

Both validation and ingestion are monotonic in the following sense:

  • The cross-validated timestamp never decreases. On a validation error, the error state is set and further progress is blocked.
  • The ingested chain is never rewound. On a detected reorg or ingestion error, the error state is set and further ingestion is blocked.

The ingester monotonicity guarantee is significant for correctness: once block N of a given L2 has been ingested, it permanently refers to the same block for the lifetime of the service, ruling out a class of race conditions between the ingestion and validation processes.

Differences to Supernode

Although the Interop Filter performs a similar cross-validation to the Supernode, there are a few notable distinctions:

  • Unlike the Supernode, which fetches blocks from the L2 chains as needed during the cross-validation loop, the Interop Filter fetches L2 blocks asynchronously. While the CrossValidator component runs the cross-validation loop, each ChainIngester concurrently runs its own loop to retrieve L2 blocks and record them in its LogsDB, from where they are read by the CrossValidator.
  • The L2 blocks processed by the Interop Filter are unsafe blocks transmitted via the gossip protocol, rather than safe blocks derived from L1.
  • Cross-validation considers only executing messages that refer to an initiating message in the past, not messages at the same timestamp. As a consequence, no cycle check is required.
  • Unlike the Supernode, which maintains a full VerifiedDB, the Interop Filter keeps track of only the latest cross-validated timestamp.
  • The Interop Filter does not implement any rewind procedure. In the case of a reorg or a block failing cross-validation, the Interop Filter enters an error state, and recovery must be performed manually by deleting the data and restarting.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions