Commit 25dd1cee authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into felipe/prevent-ban-out-of-sync

parents d7033e69 13825864
---
'@eth-optimism/contracts-periphery': patch
---
Add faucet contract
......@@ -62,7 +62,7 @@ require (
github.com/deckarep/golang-set/v2 v2.1.0 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
github.com/deepmap/oapi-codegen v1.8.2 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/elastic/gosigar v0.14.2 // indirect
......
......@@ -124,8 +124,8 @@ github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQ
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v20.10.24+incompatible h1:Ugvxm7a8+Gz6vqQYQQ2W7GYq5EUPaAiuPgIfVyI3dYE=
github.com/docker/docker v20.10.24+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
......
......@@ -202,6 +202,10 @@ func main() {
dryRun := ctx.Bool("dry-run")
noCheck := ctx.Bool("no-check")
if noCheck {
panic("must run with check on")
}
// Perform the migration
res, err := genesis.MigrateDB(ldb, config, block, &migrationData, !dryRun, noCheck)
if err != nil {
......
......@@ -57,7 +57,9 @@ func (w *LegacyWithdrawal) Encode() ([]byte, error) {
return out, nil
}
// Decode will decode a serialized LegacyWithdrawal
// Decode will decode a serialized LegacyWithdrawal. There is a known inconsistency
// where the decoded `msg.sender` is not authenticated. A round trip of encoding and
// decoding with a spoofed withdrawal will result in a different message being recovered.
func (w *LegacyWithdrawal) Decode(data []byte) error {
if len(data) < len(predeploys.L2CrossDomainMessengerAddr)+4 {
return fmt.Errorf("withdrawal data too short: %d", len(data))
......@@ -68,6 +70,8 @@ func (w *LegacyWithdrawal) Decode(data []byte) error {
return fmt.Errorf("invalid selector: 0x%x", data[0:4])
}
// This should be the L2CrossDomainMessenger address but is not guaranteed
// to be.
msgSender := data[len(data)-len(predeploys.L2CrossDomainMessengerAddr):]
raw := data[4 : len(data)-len(predeploys.L2CrossDomainMessengerAddr)]
......
......@@ -37,7 +37,6 @@ func newRPCServer(ctx context.Context, rpcCfg *RPCConfig, rollupCfg *rollup.Conf
apis: []rpc.API{{
Namespace: "optimism",
Service: api,
Public: true,
Authenticated: false,
}},
appVersion: appVersion,
......@@ -51,7 +50,6 @@ func (s *rpcServer) EnableAdminAPI(api *adminAPI) {
Namespace: "admin",
Version: "",
Service: api,
Public: true, // TODO: this field is deprecated. Do we even need this anymore?
Authenticated: false,
})
}
......@@ -61,7 +59,6 @@ func (s *rpcServer) EnableP2P(backend *p2p.APIBackend) {
Namespace: p2p.NamespaceRPC,
Version: "",
Service: backend,
Public: true,
Authenticated: false,
})
}
......
package l2
import (
"fmt"
"math/big"
"testing"
......@@ -54,7 +55,7 @@ func TestGet(t *testing.T) {
db := NewOracleBackedDB(oracle)
key := make([]byte, common.HashLength)
copy(rawdb.CodePrefix, key)
println(key[0])
fmt.Println(key[0])
expected := []byte{1, 2, 3}
oracle.Data[common.BytesToHash(key)] = expected
val, err := db.Get(key)
......
......@@ -109,7 +109,7 @@ func Run(l1RpcUrl string, l2RpcUrl string, l2OracleAddr common.Address) error {
defer func() {
err := os.RemoveAll(temp)
if err != nil {
println("Failed to remove temp dir:" + err.Error())
fmt.Println("Failed to remove temp dir:" + err.Error())
}
}()
fmt.Printf("Using temp dir: %s\n", temp)
......
{
"finalSystemOwner": "0x62790eFcB3a5f3A5D398F95B47930A9Addd83807",
"portalGuardian": "0x62790eFcB3a5f3A5D398F95B47930A9Addd83807",
"controller": "0x2d30335B0b807bBa1682C487BaAFD2Ad6da5D675",
"l1StartingBlockTag": "0x4104895a540d87127ff11eef0d51d8f63ce00a6fc211db751a45a4b3a61a9c83",
"l1ChainID": 5,
"l2ChainID": 420,
"l2BlockTime": 2,
"maxSequencerDrift": 1200,
"sequencerWindowSize": 3600,
"channelTimeout": 120,
"p2pSequencerAddress": "0xCBABF46d40982B4530c0EAc9889f6e44e17f0383",
"batchInboxAddress": "0xff00000000000000000000000000000000000420",
"batchSenderAddress": "0x3a2baA0160275024A50C1be1FC677375E7DB4Bd7",
"l2OutputOracleSubmissionInterval": 20,
"l2OutputOracleStartingTimestamp": 1670625264,
"l2OutputOracleStartingBlockNumber": 3324764,
"l2OutputOracleProposer": "0x88BCa4Af3d950625752867f826E073E337076581",
"l2OutputOracleChallenger": "0x88BCa4Af3d950625752867f826E073E337076581",
"finalizationPeriodSeconds": 2,
"proxyAdminOwner": "0x62790eFcB3a5f3A5D398F95B47930A9Addd83807",
"governanceTokenName": "Optimism",
"governanceTokenSymbol": "OP",
"governanceTokenOwner": "0x038a8825A3C3B0c08d52Cc76E5E361953Cf6Dc76",
"l2GenesisBlockGasLimit": "0x1c9c380",
"l2GenesisBlockCoinbase": "0x4200000000000000000000000000000000000011",
"l2GenesisBlockBaseFeePerGas": "0x3b9aca00",
"gasPriceOracleOverhead": 2100,
"gasPriceOracleScalar": 1000000,
"eip1559Denominator": 50,
"eip1559Elasticity": 10
}
import { DeployConfig } from '../src/deploy-config'
import config from './final-migration-rehearsal.json'
export default config satisfies DeployConfig
......@@ -93,12 +93,6 @@ const config: HardhatUserConfig = {
accounts: [process.env.PRIVATE_KEY_DEPLOYER || ethers.constants.HashZero],
live: true,
},
'final-migration-rehearsal': {
chainId: 5,
url: process.env.L1_RPC || '',
accounts: [process.env.PRIVATE_KEY_DEPLOYER || ethers.constants.HashZero],
live: true,
},
'internal-devnet': {
chainId: 5,
url: process.env.L1_RPC || '',
......@@ -149,10 +143,6 @@ const config: HardhatUserConfig = {
'../contracts/deployments/goerli',
'../contracts-periphery/deployments/goerli',
],
'final-migration-rehearsal': [
'../contracts/deployments/goerli',
'../contracts-periphery/deployments/goerli',
],
},
},
solidity: {
......
......@@ -16,8 +16,13 @@ yarn build
## Running the service
Copy `.env.example` into a new file named `.env`, then set the environment variables listed there.
Once your environment variables have been set, run the service via:
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`
Once your environment variables or flags have been set, run the service via:
```
yarn start
......@@ -34,8 +39,14 @@ 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).
For every Optimism block, 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.
- For bedrock chains, 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 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`:
......@@ -52,6 +63,9 @@ Options:
--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)
--port Port for the app server (env: FAULT_DETECTOR__PORT)
--hostname Hostname for the app server (env: FAULT_DETECTOR__HOSTNAME)
-h, --help display help for command
......
......@@ -7,7 +7,13 @@ import {
waitForProvider,
} from '@eth-optimism/common-ts'
import { getChainId, sleep, toRpcHexString } from '@eth-optimism/core-utils'
import { CrossChainMessenger } from '@eth-optimism/sdk'
import {
CONTRACT_ADDRESSES,
CrossChainMessenger,
getOEContract,
L2ChainID,
OEL1ContractsLike,
} from '@eth-optimism/sdk'
import { Provider } from '@ethersproject/abstract-provider'
import { ethers, Transaction } from 'ethers'
import dateformat from 'dateformat'
......@@ -26,6 +32,8 @@ type Options = {
l2RpcProvider: Provider
startBatchIndex: number
bedrock: boolean
optimismPortalAddress?: string
stateCommitmentChainAddress?: string
}
type Metrics = {
......@@ -73,6 +81,18 @@ export class FaultDetector extends BaseServiceV2<Options, Metrics, State> {
desc: 'Whether or not the service is running against a Bedrock chain',
public: true,
},
optimismPortalAddress: {
validator: validators.str,
default: ethers.constants.AddressZero,
desc: '[Custom Bedrock Chains] Deployed OptimismPortal contract address. Used to retrieve necessary info for ouput verification ',
public: true,
},
stateCommitmentChainAddress: {
validator: validators.str,
default: ethers.constants.AddressZero,
desc: '[Custom Legacy Chains] Deployed StateCommitmentChain contract address. Used to fetch necessary info for output verification.',
public: true,
},
},
metricsSpec: {
highestBatchIndex: {
......@@ -93,6 +113,83 @@ export class FaultDetector extends BaseServiceV2<Options, Metrics, State> {
})
}
/**
* Provides the required set of addresses used by the fault detector. For recognized op-chains, this
* will fallback to the pre-defined set of addresses from options, otherwise aborting if unset.
*
* Required Contracts
* - Bedrock: OptimismPortal (used to also fetch L2OutputOracle address variable). This is the preferred address
* since in early versions of bedrock, OptimismPortal holds the FINALIZATION_WINDOW variable instead of L2OutputOracle.
* The retrieved L2OutputOracle address from OptimismPortal is used to query for output roots.
* - Legacy: StateCommitmentChain to query for output roots.
*
* @param l2ChainId op chain id
* @returns OEL1ContractsLike set of L1 contracts with only the required addresses set
*/
async getOEL1Contracts(l2ChainId: number): Promise<OEL1ContractsLike> {
// CrossChainMessenger requires all address to be defined. Default to `AddressZero` to ignore unused contracts
let contracts: OEL1ContractsLike = {
AddressManager: ethers.constants.AddressZero,
L1CrossDomainMessenger: ethers.constants.AddressZero,
L1StandardBridge: ethers.constants.AddressZero,
StateCommitmentChain: ethers.constants.AddressZero,
CanonicalTransactionChain: ethers.constants.AddressZero,
BondManager: ethers.constants.AddressZero,
OptimismPortal: ethers.constants.AddressZero,
L2OutputOracle: ethers.constants.AddressZero,
}
const chainType = this.options.bedrock ? 'bedrock' : 'legacy'
this.logger.info(`Setting contracts for OP chain type: ${chainType}`)
const knownChainId = L2ChainID[l2ChainId] !== undefined
if (knownChainId) {
this.logger.info(`Recognized L2 chain id ${L2ChainID[l2ChainId]}`)
// fallback to the predefined defaults for this chain id
contracts = CONTRACT_ADDRESSES[l2ChainId].l1
}
this.logger.info('checking contract address options...')
if (this.options.bedrock) {
const address = this.options.optimismPortalAddress
if (!knownChainId && address === ethers.constants.AddressZero) {
this.logger.error('OptimismPortal contract unspecified')
throw new Error(
'--optimismportalcontractaddress needs to set for custom bedrock op chains'
)
}
if (address !== ethers.constants.AddressZero) {
this.logger.info('set OptimismPortal contract override')
contracts.OptimismPortal = address
this.logger.info('fetching L2OutputOracle contract from OptimismPortal')
const opts = { address, signerOrProvider: this.options.l1RpcProvider }
const portalContract = getOEContract('OptimismPortal', l2ChainId, opts)
contracts.L2OutputOracle = await portalContract.L2_ORACLE()
}
// ... for a known chain ids without an override, the L2OutputOracle will already
// be set via the hardcoded default
} else {
const address = this.options.stateCommitmentChainAddress
if (!knownChainId && address === ethers.constants.AddressZero) {
this.logger.error('StateCommitmentChain contract unspecified')
throw new Error(
'--statecommitmentchainaddress needs to set for custom legacy op chains'
)
}
if (address !== ethers.constants.AddressZero) {
this.logger.info('set StateCommitmentChain contract override')
contracts.StateCommitmentChain = address
}
}
return contracts
}
async init(): Promise<void> {
// Connect to L1.
await waitForProvider(this.options.l1RpcProvider, {
......@@ -106,12 +203,15 @@ export class FaultDetector extends BaseServiceV2<Options, Metrics, State> {
name: 'L2',
})
const l1ChainId = await getChainId(this.options.l1RpcProvider)
const l2ChainId = await getChainId(this.options.l2RpcProvider)
this.state.messenger = new CrossChainMessenger({
l1SignerOrProvider: this.options.l1RpcProvider,
l2SignerOrProvider: this.options.l2RpcProvider,
l1ChainId: await getChainId(this.options.l1RpcProvider),
l2ChainId: await getChainId(this.options.l2RpcProvider),
l1ChainId,
l2ChainId,
bedrock: this.options.bedrock,
contracts: { l1: await this.getOEL1Contracts(l2ChainId) },
})
// Not diverged by default.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment