You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
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.
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.
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
LockstepCrossValidatorandLogsDBChainIngestermodules, 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]The Interop Filter includes the following components:
ChainIngesterfor each L2 chain, responsible for continuously reading blocks from the respective chain and storing them in aLogsDB. This runs asynchronously from the cross-validation loop, and tries to process as many blocks as are available. TheChainIngesteris also responsible for detecting reorgs in its chain and raising the appropriate error.CrossValidator, responsible for cross-validating the data stored across theLogsDBs 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'sLogsDBand that it has been cross-validated.QueryFrontendused for querying theCrossValidatorto confirm the cross-validity of an access-list entry, and an authenticatedAdminFrontendexposing 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
Backendrejects allCheckAccessListqueries.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
CrossValidatoror anyChainIngester) 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
CrossValidatorCrossValidatorsets 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
CrossValidatorerror handling, see #30.ChainIngesterA
ChainIngestersets 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
LogsDBhttps://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
CrossValidatorerror handling, see #36.Failure Recovery
Neither
CrossValidatornorChainIngesterimplement a way to clear their error states programmatically. (WhileChainIngesterdoes expose aClearErrormethod, 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
AdminFrontenddoes define aRewindendpoint, 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
CrossValidatornor anyChainIngesteris in the error state, normal operation proceeds:CheckAccessListqueries are served.CrossValidatorcontinues advancing the cross-validated timestamp.ChainIngestercontinues ingesting blocks into itsLogsDB.Both validation and ingestion are monotonic in the following sense:
The ingester monotonicity guarantee is significant for correctness: once block
Nof 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:
CrossValidatorcomponent runs the cross-validation loop, eachChainIngesterconcurrently runs its own loop to retrieve L2 blocks and record them in itsLogsDB, from where they are read by theCrossValidator.VerifiedDB, the Interop Filter keeps track of only the latest cross-validated timestamp.