Skip to content

Commit

Permalink
Merge pull request #6095 from ethereum-optimism/k0621/sec-90-fd-tests
Browse files Browse the repository at this point in the history
fault-detector: remove pre-bedrock support and update tests
  • Loading branch information
OptimismBot authored Jun 23, 2023
2 parents 505751c + cda9d84 commit e498563
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 396 deletions.
5 changes: 5 additions & 0 deletions .changeset/nervous-icons-retire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@eth-optimism/fault-detector': minor
---

Remove pre-bedrock support from fault detector.
13 changes: 3 additions & 10 deletions packages/fault-detector/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ yarn build
## Running the service

Copy `.env.example` into a new file named `.env`, then set the environment variables listed there. Additional env setting are listed on `--help`. If running the fault detector against
a custom op chain, the necessary contract addresses must also be set associated with the op-chain.

- Bedrock: `OptimismPortal`
- Legacy: `StateCommitmentChain`
a custom op chain, the `OptimismPortal` contract addresses must also be set associated with the op-chain.

Once your environment variables or flags have been set, run the service via:

Expand All @@ -40,13 +37,11 @@ yarn start
The `fault-detector` detects differences between the transaction results generated by your local Optimism node and the transaction results actually published to Ethereum.
Currently, transaction results take the form of [the root of the Optimism state trie](https://medium.com/@eiki1212/ethereum-state-trie-architecture-explained-a30237009d4e).

- Post bedrock upgrade, the state root of the block is published to the [`L2OutputOracle`](https://github.com/ethereum-optimism/optimism/blob/39b7262cc3ffd78cd314341b8512b2683c1d9af7/packages/contracts-bedrock/contracts/L1/L2OutputOracle.sol) contract on Ethereum.
The state root of the block is published to the [`L2OutputOracle`](https://github.com/ethereum-optimism/optimism/blob/39b7262cc3ffd78cd314341b8512b2683c1d9af7/packages/contracts-bedrock/contracts/L1/L2OutputOracle.sol) contract on Ethereum.
- ***Note***: The service accepts the `OptimismPortal` as a flag instead of the `L2OutputOracle` for backwards compatibility with early versions of these contracts. The `L2OutputOracle`
is inferred from the portal contract.
- For pre-bedrock chains, the state root of the block is published to the [`StateCommitmentChain`](https://github.com/ethereum-optimism/optimism/blob/39b7262cc3ffd78cd314341b8512b2683c1d9af7/packages/contracts/contracts/L1/rollup/StateCommitmentChain.sol) contract on Ethereum.

We can therefore detect differences by, for each block, checking the state root of the given block as reported by an Optimism node and the state root as published to Ethereum.
In order for the fault detector to differentiate between bedrock and legacy chains, please make sure to specify `--bedrock`.

We export a series of Prometheus metrics that you can use to trigger alerting when issues are detected.
Check the list of available metrics via `yarn start --help`:
Expand All @@ -62,9 +57,7 @@ Options:
--l2rpcprovider Provider for interacting with L2 (env: FAULT_DETECTOR__L2_RPC_PROVIDER)
--startbatchindex Batch index to start checking from. Setting it to -1 will cause the fault detector to find the first state batch index that has not yet passed the fault proof window (env: FAULT_DETECTOR__START_BATCH_INDEX, default value: -1)
--loopintervalms Loop interval in milliseconds (env: FAULT_DETECTOR__LOOP_INTERVAL_MS)
--bedrock Whether or not the service is running against a Bedrock chain (env: FAULT_DETECTOR__BEDROCK, default value: false)
--optimismportaladdress [Custom Bedrock Chains] Deployed OptimismPortal contract address. Used to retrieve necessary info for ouput verification (env: FAULT_DETECTOR__OPTIMISM_PORTAL_ADDRESS, default 0x0)
--statecommitmentchainaddress [Custom Legacy Chains] Deployed StateCommitmentChain contract address. Used to fetch necessary info for output verification. (env: FAULT_DETECTOR__STATE_COMMITMENT_CHAIN_ADDRESS, default 0x0)
--optimismportaladdress [Custom OP Chains] Deployed OptimismPortal contract address. Used to retrieve necessary info for ouput verification (env: FAULT_DETECTOR__OPTIMISM_PORTAL_ADDRESS, default 0x0)

--port Port for the app server (env: FAULT_DETECTOR__PORT)
--hostname Hostname for the app server (env: FAULT_DETECTOR__HOSTNAME)
Expand Down
2 changes: 1 addition & 1 deletion packages/fault-detector/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
},
"dependencies": {
"@eth-optimism/common-ts": "^0.8.2",
"@eth-optimism/contracts": "^0.6.0",
"@eth-optimism/contracts-bedrock": "^0.14.0",
"@eth-optimism/core-utils": "^0.12.1",
"@eth-optimism/sdk": "^3.0.0",
"@ethersproject/abstract-provider": "^5.7.0"
Expand Down
41 changes: 16 additions & 25 deletions packages/fault-detector/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import { Contract, BigNumber } from 'ethers'
import { Contract } from 'ethers'
import { Logger } from '@eth-optimism/common-ts'

export interface OutputOracle<TSubmissionEventArgs> {
contract: Contract
filter: any
getTotalElements: () => Promise<BigNumber>
getEventIndex: (args: TSubmissionEventArgs) => BigNumber
}

/**
* Partial event interface, meant to reduce the size of the event cache to avoid
* running out of memory.
Expand Down Expand Up @@ -54,12 +47,12 @@ const getCache = (
* @param contract Contract to update cache for.
* @param filter Event filter to use.
*/
export const updateOracleCache = async <TSubmissionEventArgs>(
oracle: OutputOracle<TSubmissionEventArgs>,
export const updateOracleCache = async (
oracle: Contract,
logger?: Logger
): Promise<void> => {
const cache = getCache(oracle.contract.address)
const endBlock = await oracle.contract.provider.getBlockNumber()
const cache = getCache(oracle.address)
const endBlock = await oracle.provider.getBlockNumber()
logger?.info('visiting uncached oracle events for range', {
node: 'l1',
cachedUntilBlock: cache.highestBlock,
Expand All @@ -77,17 +70,15 @@ export const updateOracleCache = async <TSubmissionEventArgs>(
blockRangeSize: step,
})

const events = await oracle.contract.queryFilter(
oracle.filter,
const events = await oracle.queryFilter(
oracle.filters.OutputProposed(),
currentBlock,
currentBlock + step
)

// Throw the events into the cache.
for (const event of events) {
cache.eventCache[
oracle.getEventIndex(event.args as TSubmissionEventArgs).toNumber()
] = {
cache.eventCache[event.args.l2OutputIndex.toNumber()] = {
blockNumber: event.blockNumber,
transactionHash: event.transactionHash,
args: event.args,
Expand Down Expand Up @@ -135,12 +126,12 @@ export const updateOracleCache = async <TSubmissionEventArgs>(
* @param index State batch index to search for.
* @returns Event corresponding to the batch.
*/
export const findEventForStateBatch = async <TSubmissionEventArgs>(
oracle: OutputOracle<TSubmissionEventArgs>,
export const findEventForStateBatch = async (
oracle: Contract,
index: number,
logger?: Logger
): Promise<PartialEvent> => {
const cache = getCache(oracle.contract.address)
const cache = getCache(oracle.address)

// Try to find the event in cache first.
if (cache.eventCache[index]) {
Expand All @@ -166,21 +157,21 @@ export const findEventForStateBatch = async <TSubmissionEventArgs>(
* @param oracle Output oracle contract.
* @returns Starting state root batch index.
*/
export const findFirstUnfinalizedStateBatchIndex = async <TSubmissionEventArgs>(
oracle: OutputOracle<TSubmissionEventArgs>,
export const findFirstUnfinalizedStateBatchIndex = async (
oracle: Contract,
fpw: number,
logger?: Logger
): Promise<number> => {
const latestBlock = await oracle.contract.provider.getBlock('latest')
const totalBatches = (await oracle.getTotalElements()).toNumber()
const latestBlock = await oracle.provider.getBlock('latest')
const totalBatches = (await oracle.nextOutputIndex()).toNumber()

// Perform a binary search to find the next batch that will pass the challenge period.
let lo = 0
let hi = totalBatches
while (lo !== hi) {
const mid = Math.floor((lo + hi) / 2)
const event = await findEventForStateBatch(oracle, mid, logger)
const block = await oracle.contract.provider.getBlock(event.blockNumber)
const block = await oracle.provider.getBlock(event.blockNumber)

if (block.timestamp + fpw < latestBlock.timestamp) {
lo = mid + 1
Expand Down
Loading

0 comments on commit e498563

Please sign in to comment.