Commit 069f9c22 authored by Mark Tyneway's avatar Mark Tyneway Committed by Andreas Bigger

op-e2e: major refactor

Refactor op-e2e to use the same deploy script that is used in
production. There is only 1 way to deploy contracts now and
it goes through foundry. This removes the need to maintain
multiple sets of contracts deployments/devnets. It does
add a new tooling dep to the monorepo which is `geth`.
A top level `make` command is provided as well as some
docs in the `op-e2e` package on its usage.

The `devnetL1.json` deployconfig is the source of truth
for deploy configs in `op-e2e` now. In the long term,
we should delineate which config values are safe to alter
in memory and which are not. Some things are still coupled
together in weird ways, but I tried to add assertions where
I could to ensure that future people will get better error
messages.

To install geth, run the command:

`` `
make install-geth
```

To create the genesis state, run the command:

```
make devnet-allocs
```

This will run the forge deploy script against an instance of
`geth --dev` and then call `debug_dumpBlock` which will dump
the state into a format that we can inject at runtime into
the genesis of both `op-e2e` as well as the L1 of the docker
compose setup.

I tried to use `anvil` instead of `geth` but it does not
support this endpoint. It supports a different endpoint
that uses a compressed binary serialization of state,
it is easier to work with the JSON.
parent 3e60c7e1
This diff is collapsed.
......@@ -68,6 +68,7 @@ You'll need the following:
* [Docker Compose](https://docs.docker.com/compose/install/)
* [Go](https://go.dev/dl/)
* [Foundry](https://getfoundry.sh)
* [go-ethereum](https://github.com/ethereum/go-ethereum)
### Setup
......@@ -80,7 +81,7 @@ cd optimism
### Install the Correct Version of NodeJS
Install node v16.16.0 with [nvm](https://github.com/nvm-sh/nvm)
Install the correct node version with [nvm](https://github.com/nvm-sh/nvm)
```bash
nvm use
......@@ -112,10 +113,11 @@ Use the above commands to recompile the packages.
### Building the rest of the system
If you want to run an Optimism node OR **if you want to run the integration tests**, you'll need to build the rest of the system.
Note that these environment variables significantly speed up build time.
```bash
cd ops
export COMPOSE_DOCKER_CLI_BUILD=1 # these environment variables significantly speed up build time
cd ops-bedrock
export COMPOSE_DOCKER_CLI_BUILD=1
export DOCKER_BUILDKIT=1
docker-compose build
```
......@@ -124,7 +126,7 @@ Source code changes can have an impact on more than one container.
**If you're unsure about which containers to rebuild, just rebuild them all**:
```bash
cd ops
cd ops-bedrock
docker-compose down
docker-compose build
docker-compose up
......
......@@ -77,8 +77,9 @@ devnet-up:
PYTHONPATH=./bedrock-devnet python3 ./bedrock-devnet/main.py --monorepo-dir=.
.PHONY: devnet-up
# alias for devnet-up
devnet-up-deploy:
PYTHONPATH=./bedrock-devnet python3 ./bedrock-devnet/main.py --monorepo-dir=. --deploy
PYTHONPATH=./bedrock-devnet python3 ./bedrock-devnet/main.py --monorepo-dir=.
.PHONY: devnet-up-deploy
devnet-down:
......@@ -93,6 +94,9 @@ devnet-clean:
docker volume ls --filter name=ops-bedrock --format='{{.Name}}' | xargs -r docker volume rm
.PHONY: devnet-clean
devnet-allocs:
PYTHONPATH=./bedrock-devnet python3 ./bedrock-devnet/main.py --monorepo-dir=. --allocs
devnet-logs:
@(cd ./ops-bedrock && docker-compose logs -f)
.PHONY: devnet-logs
......@@ -133,3 +137,6 @@ bedrock-markdown-links:
docker run --init -it -v `pwd`:/input lycheeverse/lychee --verbose --no-progress --exclude-loopback \
--exclude twitter.com --exclude explorer.optimism.io --exclude linux-mips.org \
--exclude-mail /input/README.md "/input/specs/**/*.md"
install-geth:
go install github.com/ethereum/go-ethereum/cmd/geth@v1.12.0
This diff is collapsed.
import time
DEV_ACCOUNTS = [
'3c44cdddb6a900fa2b585dd299e03d12fa4293bc',
'70997970c51812dc3a010c7d01b50e0d17dc79c8',
'f39fd6e51aad88f6f4ce6ab8827279cfffb92266'
]
GENESIS_TMPL = {
'config': {
'chainId': 900,
"homesteadBlock": 0,
"eip150Block": 0,
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"muirGlacierBlock": 0,
"berlinBlock": 0,
"londonBlock": 0,
"arrowGlacierBlock": 0,
"grayGlacierBlock": 0,
"shanghaiBlock": None,
"cancunBlock": None,
'clique': {
'period': 3,
'epoch': 30000
}
},
'nonce': '0x0',
'timestamp': '{:#x}'.format(int(time.time())),
'extraData': '0x0000000000000000000000000000000000000000000000000000000000000000ca062b0fd91172d89bcd4bb084ac4e21972cc4670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'gasLimit': '0xE4E1C0',
'difficulty': '0x1',
'mixHash': '0x0000000000000000000000000000000000000000000000000000000000000000',
'coinbase': '0x0000000000000000000000000000000000000000',
'alloc': {
'{:x}'.format(i).ljust(40, '0'): {
'balance': '0x1'
} for i in range(0, 255)
},
'number': '0x0',
'gasUsed': '0x0',
'parentHash': '0x0000000000000000000000000000000000000000000000000000000000000000',
'baseFeePergas': '0x3B9ACA00'
}
GENESIS_TMPL['alloc'].update({
d: {
'balance': '0x200000000000000000000000000000000000000000000000000000000000000'
} for d in DEV_ACCOUNTS
})
......@@ -5,6 +5,7 @@ import (
"github.com/BurntSushi/toml"
"github.com/ethereum-optimism/optimism/indexer/processor"
"github.com/ethereum/go-ethereum/log"
)
......@@ -21,7 +22,8 @@ type Config struct {
// ChainConfig configures of the chain being indexed
type ChainConfig struct {
// Configure known chains with the l2 chain id
Preset int
Preset int
L1Contracts processor.L1Contracts
}
// RPCsConfig configures the RPC urls
......
......@@ -7,7 +7,6 @@ import (
"time"
"github.com/ethereum-optimism/optimism/indexer/node"
"github.com/ethereum-optimism/optimism/indexer/processor"
"github.com/ethereum-optimism/optimism/op-service/client/utils"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
......@@ -15,6 +14,7 @@ import (
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
......@@ -25,7 +25,7 @@ func TestE2EBlockHeaders(t *testing.T) {
l1Client := testSuite.OpSys.Clients["l1"]
l2Client := testSuite.OpSys.Clients["sequencer"]
l2OutputOracle, err := bindings.NewL2OutputOracleCaller(predeploys.DevL2OutputOracleAddr, l1Client)
l2OutputOracle, err := bindings.NewL2OutputOracleCaller(testSuite.OpCfg.L1Deployments.L2OutputOracleProxy, l1Client)
require.NoError(t, err)
// a minute for total setup to finish
......@@ -111,7 +111,10 @@ func TestE2EBlockHeaders(t *testing.T) {
testCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
devContracts := processor.DevL1Contracts().ToSlice()
devContracts := make([]common.Address, 0)
testSuite.OpCfg.L1Deployments.ForEach(func(name string, address common.Address) {
devContracts = append(devContracts, address)
})
logFilter := ethereum.FilterQuery{FromBlock: big.NewInt(0), ToBlock: big.NewInt(int64(l1Height)), Addresses: devContracts}
logs, err := l1Client.FilterLogs(testCtx, logFilter) // []types.Log
require.NoError(t, err)
......
......@@ -28,7 +28,7 @@ func TestE2EBridge(t *testing.T) {
l1Client := testSuite.OpSys.Clients["l1"]
l2Client := testSuite.OpSys.Clients["sequencer"]
l1StandardBridge, err := bindings.NewL1StandardBridge(predeploys.DevL1StandardBridgeAddr, l1Client)
l1StandardBridge, err := bindings.NewL1StandardBridge(testSuite.OpCfg.L1Deployments.L1StandardBridgeProxy, l1Client)
require.NoError(t, err)
l2StandardBridge, err := bindings.NewL2StandardBridge(predeploys.L2StandardBridgeAddr, l2Client)
......
......@@ -13,6 +13,7 @@ import (
"github.com/ethereum-optimism/optimism/indexer"
"github.com/ethereum-optimism/optimism/indexer/config"
"github.com/ethereum-optimism/optimism/indexer/database"
"github.com/ethereum-optimism/optimism/indexer/processor"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-node/testlog"
......@@ -44,10 +45,17 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite {
// Rollup System Configuration and Start
opCfg := op_e2e.DefaultSystemConfig(t)
opCfg.DeployConfig.FinalizationPeriodSeconds = 2
opSys, err := opCfg.Start()
require.NoError(t, err)
l1Contracts := processor.L1Contracts{
OptimismPortal: opCfg.L1Deployments.OptimismPortalProxy,
L2OutputOracle: opCfg.L1Deployments.L2OutputOracleProxy,
L1CrossDomainMessenger: opCfg.L1Deployments.L1CrossDomainMessengerProxy,
L1StandardBridge: opCfg.L1Deployments.L1StandardBridgeProxy,
L1ERC721Bridge: opCfg.L1Deployments.L1ERC721BridgeProxy,
}
// Indexer Configuration and Start
indexerCfg := config.Config{
DB: config.DBConfig{
......@@ -61,6 +69,9 @@ func createE2ETestSuite(t *testing.T) E2ETestSuite {
L2RPC: opSys.Nodes["sequencer"].HTTPEndpoint(),
},
Logger: logger,
Chain: config.ChainConfig{
L1Contracts: l1Contracts,
},
}
db, err := database.NewDB(fmt.Sprintf("postgres://%s@localhost:5432/%s?sslmode=disable", dbUser, dbName))
......
......@@ -38,8 +38,7 @@ func NewIndexer(cfg config.Config) (*Indexer, error) {
return nil, err
}
// L1 Processor (hardhat devnet contracts). Make this configurable
l1Contracts := processor.DevL1Contracts()
l1Contracts := cfg.Chain.L1Contracts
l1EthClient, err := node.DialEthClient(cfg.RPCs.L1RPC)
if err != nil {
return nil, err
......
......@@ -46,7 +46,7 @@ func TestBedrockIndexer(t *testing.T) {
// wait a couple of blocks
require.NoError(t, utils.WaitBlock(e2eutils.TimeoutCtx(t, 30*time.Second), l2Client, 10))
l1SB, err := bindings.NewL1StandardBridge(predeploys.DevL1StandardBridgeAddr, l1Client)
l1SB, err := bindings.NewL1StandardBridge(cfg.L1Deployments.L1StandardBridgeProxy, l1Client)
require.NoError(t, err)
l2SB, err := bindings.NewL2StandardBridge(predeploys.L2StandardBridgeAddr, l2Client)
require.NoError(t, err)
......@@ -208,7 +208,7 @@ func TestBedrockIndexer(t *testing.T) {
require.Nil(t, wd.BedrockFinalizedTxHash)
// Finalize withdrawal
err = withdrawals.WaitForFinalizationPeriod(e2eutils.TimeoutCtx(t, 30*time.Second), l1Client, predeploys.DevOptimismPortalAddr, proveReceipt.BlockNumber)
err = withdrawals.WaitForFinalizationPeriod(e2eutils.TimeoutCtx(t, 30*time.Second), l1Client, cfg.L1Deployments.OptimismPortalProxy, proveReceipt.BlockNumber)
require.Nil(t, err)
finReceipt := op_e2e.FinalizeWithdrawal(t, cfg, l1Client, cfg.Secrets.Alice, wdReceipt, wdParams)
......
......@@ -34,16 +34,6 @@ type L1Contracts struct {
// Remove afterwards?
}
func DevL1Contracts() L1Contracts {
return L1Contracts{
OptimismPortal: common.HexToAddress("0x6900000000000000000000000000000000000000"),
L2OutputOracle: common.HexToAddress("0x6900000000000000000000000000000000000001"),
L1CrossDomainMessenger: common.HexToAddress("0x6900000000000000000000000000000000000002"),
L1StandardBridge: common.HexToAddress("0x6900000000000000000000000000000000000003"),
L1ERC721Bridge: common.HexToAddress("0x6900000000000000000000000000000000000004"),
}
}
func (c L1Contracts) ToSlice() []common.Address {
fields := reflect.VisibleFields(reflect.TypeOf(c))
v := reflect.ValueOf(c)
......
package predeploys
import "github.com/ethereum/go-ethereum/common"
const (
DevL2OutputOracle = "0x6900000000000000000000000000000000000000"
DevOptimismPortal = "0x6900000000000000000000000000000000000001"
DevL1CrossDomainMessenger = "0x6900000000000000000000000000000000000002"
DevL1StandardBridge = "0x6900000000000000000000000000000000000003"
DevOptimismMintableERC20Factory = "0x6900000000000000000000000000000000000004"
DevAddressManager = "0x6900000000000000000000000000000000000005"
DevProxyAdmin = "0x6900000000000000000000000000000000000006"
DevWETH9 = "0x6900000000000000000000000000000000000007"
DevL1ERC721Bridge = "0x6900000000000000000000000000000000000008"
DevSystemConfig = "0x6900000000000000000000000000000000000009"
)
var (
DevL2OutputOracleAddr = common.HexToAddress(DevL2OutputOracle)
DevOptimismPortalAddr = common.HexToAddress(DevOptimismPortal)
DevL1CrossDomainMessengerAddr = common.HexToAddress(DevL1CrossDomainMessenger)
DevL1StandardBridgeAddr = common.HexToAddress(DevL1StandardBridge)
DevOptimismMintableERC20FactoryAddr = common.HexToAddress(DevOptimismMintableERC20Factory)
DevAddressManagerAddr = common.HexToAddress(DevAddressManager)
DevProxyAdminAddr = common.HexToAddress(DevProxyAdmin)
DevWETH9Addr = common.HexToAddress(DevWETH9)
DevL1ERC721BridgeAddr = common.HexToAddress(DevL1ERC721Bridge)
DevSystemConfigAddr = common.HexToAddress(DevSystemConfig)
DevPredeploys = make(map[string]*common.Address)
)
func init() {
DevPredeploys["L2OutputOracle"] = &DevL2OutputOracleAddr
DevPredeploys["OptimismPortal"] = &DevOptimismPortalAddr
DevPredeploys["L1CrossDomainMessenger"] = &DevL1CrossDomainMessengerAddr
DevPredeploys["L1StandardBridge"] = &DevL1StandardBridgeAddr
DevPredeploys["OptimismMintableERC20Factory"] = &DevOptimismMintableERC20FactoryAddr
DevPredeploys["AddressManager"] = &DevAddressManagerAddr
DevPredeploys["Admin"] = &DevProxyAdminAddr
DevPredeploys["WETH9"] = &DevWETH9Addr
DevPredeploys["L1ERC721Bridge"] = &DevL1ERC721BridgeAddr
DevPredeploys["SystemConfig"] = &DevSystemConfigAddr
}
......@@ -8,8 +8,11 @@ import (
"os"
"path/filepath"
"reflect"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
gstate "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
......@@ -74,10 +77,15 @@ type DeployConfig struct {
// L2OutputOracleChallenger is the address of the account that challenges L2 outputs.
L2OutputOracleChallenger common.Address `json:"l2OutputOracleChallenger"`
// CliqueSignerAddress represents the signer address for the clique consensus engine.
// It is used in the multi-process devnet to sign blocks.
CliqueSignerAddress common.Address `json:"cliqueSignerAddress"`
// L1UseClique represents whether or not to use the clique consensus engine.
L1UseClique bool `json:"l1UseClique"`
L1BlockTime uint64 `json:"l1BlockTime"`
L1GenesisBlockTimestamp hexutil.Uint64 `json:"l1GenesisBlockTimestamp"`
L1GenesisBlockNonce hexutil.Uint64 `json:"l1GenesisBlockNonce"`
CliqueSignerAddress common.Address `json:"cliqueSignerAddress"` // proof of stake genesis if left zeroed.
L1GenesisBlockGasLimit hexutil.Uint64 `json:"l1GenesisBlockGasLimit"`
L1GenesisBlockDifficulty *hexutil.Big `json:"l1GenesisBlockDifficulty"`
L1GenesisBlockMixHash common.Hash `json:"l1GenesisBlockMixHash"`
......@@ -181,7 +189,6 @@ func (d *DeployConfig) Copy() *DeployConfig {
if err = json.Unmarshal(raw, &cpy); err != nil {
panic(err)
}
return &cpy
}
......@@ -311,9 +318,22 @@ func (d *DeployConfig) Check() error {
return fmt.Errorf("%w: GovernanceToken owner cannot be address(0)", ErrInvalidDeployConfig)
}
}
// L2 block time must always be smaller than L1 block time
if d.L1BlockTime < d.L2BlockTime {
return fmt.Errorf("L2 block time (%d) is larger than L1 block time (%d)", d.L2BlockTime, d.L1BlockTime)
}
return nil
}
// SetDeployments will merge a Deployments into a DeployConfig.
func (d *DeployConfig) SetDeployments(deployments *L1Deployments) {
d.L1StandardBridgeProxy = deployments.L1StandardBridgeProxy
d.L1CrossDomainMessengerProxy = deployments.L1CrossDomainMessengerProxy
d.L1ERC721BridgeProxy = deployments.L1ERC721BridgeProxy
d.SystemConfigProxy = deployments.SystemConfigProxy
d.OptimismPortalProxy = deployments.OptimismPortalProxy
}
// GetDeployedAddresses will get the deployed addresses of deployed L1 contracts
// required for the L2 genesis creation. Legacy systems use the `Proxy__` prefix
// while modern systems use the `Proxy` suffix. First check for the legacy
......@@ -373,16 +393,6 @@ func (d *DeployConfig) GetDeployedAddresses(hh *hardhat.Hardhat) error {
return nil
}
// InitDeveloperDeployedAddresses will set the dev addresses on the DeployConfig
func (d *DeployConfig) InitDeveloperDeployedAddresses() error {
d.L1StandardBridgeProxy = predeploys.DevL1StandardBridgeAddr
d.L1CrossDomainMessengerProxy = predeploys.DevL1CrossDomainMessengerAddr
d.L1ERC721BridgeProxy = predeploys.DevL1ERC721BridgeAddr
d.OptimismPortalProxy = predeploys.DevOptimismPortalAddr
d.SystemConfigProxy = predeploys.DevSystemConfigAddr
return nil
}
func (d *DeployConfig) RegolithTime(genesisTime uint64) *uint64 {
if d.L2GenesisRegolithTimeOffset == nil {
return nil
......@@ -479,6 +489,64 @@ type L1Deployments struct {
SystemConfigProxy common.Address `json:"SystemConfigProxy"`
}
// GetName will return the name of the contract given an address.
func (d *L1Deployments) GetName(addr common.Address) string {
val := reflect.ValueOf(d)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
for i := 0; i < val.NumField(); i++ {
if addr == val.Field(i).Interface().(common.Address) {
return val.Type().Field(i).Name
}
}
return ""
}
// Check will ensure that the L1Deployments are sane
func (d *L1Deployments) Check() error {
val := reflect.ValueOf(d)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
for i := 0; i < val.NumField(); i++ {
name := val.Type().Field(i).Name
// Skip the non production ready contracts
if name == "DisputeGameFactory" || name == "DisputeGameFactoryProxy" {
continue
}
if val.Field(i).Interface().(common.Address) == (common.Address{}) {
return fmt.Errorf("%s is not set", name)
}
}
return nil
}
// ForEach will iterate over each contract in the L1Deployments
func (d *L1Deployments) ForEach(cb func(name string, addr common.Address)) {
val := reflect.ValueOf(d)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
for i := 0; i < val.NumField(); i++ {
name := val.Type().Field(i).Name
cb(name, val.Field(i).Interface().(common.Address))
}
}
// Copy will copy the L1Deployments struct
func (d *L1Deployments) Copy() *L1Deployments {
cpy := L1Deployments{}
data, err := json.Marshal(d)
if err != nil {
panic(err)
}
if err := json.Unmarshal(data, &cpy); err != nil {
panic(err)
}
return &cpy
}
// NewL1Deployments will create a new L1Deployments from a JSON file on disk
// at the given path.
func NewL1Deployments(path string) (*L1Deployments, error) {
......@@ -495,6 +563,20 @@ func NewL1Deployments(path string) (*L1Deployments, error) {
return &deployments, nil
}
// NewStateDump will read a Dump JSON file from disk
func NewStateDump(path string) (*gstate.Dump, error) {
file, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("dump at %s not found: %w", path, err)
}
var dump gstate.Dump
if err := json.Unmarshal(file, &dump); err != nil {
return nil, fmt.Errorf("cannot unmarshal dump: %w", err)
}
return &dump, nil
}
// NewL2ImmutableConfig will create an ImmutableConfig given an instance of a
// DeployConfig and a block.
func NewL2ImmutableConfig(config *DeployConfig, block *types.Block) (immutables.ImmutableConfig, error) {
......
......@@ -89,4 +89,9 @@ func TestL1Deployments(t *testing.T) {
require.NotEqual(t, deployments.ProxyAdmin, common.Address{})
require.NotEqual(t, deployments.SystemConfig, common.Address{})
require.NotEqual(t, deployments.SystemConfigProxy, common.Address{})
require.Equal(t, "AddressManager", deployments.GetName(deployments.AddressManager))
require.Equal(t, "OptimismPortalProxy", deployments.GetName(deployments.OptimismPortalProxy))
// One that doesn't exist returns empty string
require.Equal(t, "", deployments.GetName(common.Address{19: 0xff}))
}
......@@ -127,20 +127,22 @@ func NewL1Genesis(config *DeployConfig) (*core.Genesis, error) {
LondonBlock: big.NewInt(0),
ArrowGlacierBlock: big.NewInt(0),
GrayGlacierBlock: big.NewInt(0),
ShanghaiTime: u64ptr(0),
}
if config.CliqueSignerAddress != (common.Address{}) {
extraData := make([]byte, 0)
if config.L1UseClique {
// warning: clique has an overly strict block header timestamp check against the system wallclock,
// causing blocks to get scheduled as "future block" and not get mined instantly when produced.
chainConfig.Clique = &params.CliqueConfig{
Period: config.L1BlockTime,
Epoch: 30000,
}
extraData = append(append(make([]byte, 32), config.CliqueSignerAddress[:]...), make([]byte, crypto.SignatureLength)...)
} else {
chainConfig.MergeNetsplitBlock = big.NewInt(0)
chainConfig.TerminalTotalDifficulty = big.NewInt(0)
chainConfig.TerminalTotalDifficultyPassed = true
chainConfig.ShanghaiTime = u64ptr(0)
}
gasLimit := config.L1GenesisBlockGasLimit
......@@ -160,11 +162,6 @@ func NewL1Genesis(config *DeployConfig) (*core.Genesis, error) {
timestamp = hexutil.Uint64(time.Now().Unix())
}
extraData := make([]byte, 0)
if config.CliqueSignerAddress != (common.Address{}) {
extraData = append(append(make([]byte, 32), config.CliqueSignerAddress[:]...), make([]byte, crypto.SignatureLength)...)
}
return &core.Genesis{
Config: &chainConfig,
Nonce: uint64(config.L1GenesisBlockNonce),
......
......@@ -18,12 +18,8 @@ var (
codeNamespace = common.HexToAddress("0xc0D3C0d3C0d3C0D3c0d3C0d3c0D3C0d3c0d30000")
// l2PredeployNamespace represents the namespace of L2 predeploys
l2PredeployNamespace = common.HexToAddress("0x4200000000000000000000000000000000000000")
// l1PredeployNamespace represents the namespace of L1 predeploys
l1PredeployNamespace = common.HexToAddress("0x6900000000000000000000000000000000000000")
// bigL2PredeployNamespace represents the predeploy namespace as a big.Int
BigL2PredeployNamespace = new(big.Int).SetBytes(l2PredeployNamespace.Bytes())
// bigL1PredeployNamespace represents the predeploy namespace as a big.Int
bigL1PredeployNamespace = new(big.Int).SetBytes(l1PredeployNamespace.Bytes())
// bigCodeNamespace represents the predeploy namespace as a big.Int
bigCodeNameSpace = new(big.Int).SetBytes(codeNamespace.Bytes())
// implementationSlot represents the EIP 1967 implementation storage slot
......@@ -67,7 +63,7 @@ var devBalance = hexutil.MustDecodeBig("0x20000000000000000000000000000000000000
// AddressToCodeNamespace takes a predeploy address and computes
// the implementation address that the implementation should be deployed at
func AddressToCodeNamespace(addr common.Address) (common.Address, error) {
if !IsL1DevPredeploy(addr) && !IsL2DevPredeploy(addr) {
if !IsL2DevPredeploy(addr) {
return common.Address{}, fmt.Errorf("cannot handle non predeploy: %s", addr)
}
bigAddress := new(big.Int).SetBytes(addr[18:])
......@@ -75,10 +71,6 @@ func AddressToCodeNamespace(addr common.Address) (common.Address, error) {
return common.BigToAddress(num), nil
}
func IsL1DevPredeploy(addr common.Address) bool {
return bytes.Equal(addr[0:2], []byte{0x69, 0x00})
}
func IsL2DevPredeploy(addr common.Address) bool {
return bytes.Equal(addr[0:2], []byte{0x42, 0x00})
}
......
This diff is collapsed.
......@@ -16,11 +16,16 @@ import (
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)
// TestBuildL1DeveloperGenesis tests that the L1 genesis block can be built
// given a deploy config and an l1-allocs.json and a deploy.json that
// are generated from a deploy config. If new contracts are added, these
// mocks will need to be regenerated.
func TestBuildL1DeveloperGenesis(t *testing.T) {
b, err := os.ReadFile("testdata/test-deploy-config-full.json")
require.NoError(t, err)
......@@ -29,7 +34,15 @@ func TestBuildL1DeveloperGenesis(t *testing.T) {
require.NoError(t, dec.Decode(config))
config.L1GenesisBlockTimestamp = hexutil.Uint64(time.Now().Unix() - 100)
genesis, err := BuildL1DeveloperGenesis(config)
c, err := os.ReadFile("testdata/allocs-l1.json")
require.NoError(t, err)
dump := new(state.Dump)
require.NoError(t, json.NewDecoder(bytes.NewReader(c)).Decode(dump))
deployments, err := NewL1Deployments("testdata/deploy.json")
require.NoError(t, err)
genesis, err := BuildL1DeveloperGenesis(config, dump, nil, false)
require.NoError(t, err)
sim := backends.NewSimulatedBackend(
......@@ -38,9 +51,9 @@ func TestBuildL1DeveloperGenesis(t *testing.T) {
)
callOpts := &bind.CallOpts{}
oracle, err := bindings.NewL2OutputOracle(predeploys.DevL2OutputOracleAddr, sim)
oracle, err := bindings.NewL2OutputOracle(deployments.L2OutputOracleProxy, sim)
require.NoError(t, err)
portal, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, sim)
portal, err := bindings.NewOptimismPortal(deployments.OptimismPortalProxy, sim)
require.NoError(t, err)
proposer, err := oracle.PROPOSER(callOpts)
......@@ -66,42 +79,30 @@ func TestBuildL1DeveloperGenesis(t *testing.T) {
oracleAddr, err := portal.L2ORACLE(callOpts)
require.NoError(t, err)
require.EqualValues(t, predeploys.DevL2OutputOracleAddr, oracleAddr)
require.EqualValues(t, deployments.L2OutputOracleProxy, oracleAddr)
msgr, err := bindings.NewL1CrossDomainMessenger(predeploys.DevL1CrossDomainMessengerAddr, sim)
msgr, err := bindings.NewL1CrossDomainMessenger(deployments.L1CrossDomainMessengerProxy, sim)
require.NoError(t, err)
portalAddr, err := msgr.PORTAL(callOpts)
require.NoError(t, err)
require.Equal(t, predeploys.DevOptimismPortalAddr, portalAddr)
require.Equal(t, deployments.OptimismPortalProxy, portalAddr)
bridge, err := bindings.NewL1StandardBridge(predeploys.DevL1StandardBridgeAddr, sim)
bridge, err := bindings.NewL1StandardBridge(deployments.L1StandardBridgeProxy, sim)
require.NoError(t, err)
msgrAddr, err := bridge.Messenger(callOpts)
require.NoError(t, err)
require.Equal(t, predeploys.DevL1CrossDomainMessengerAddr, msgrAddr)
require.Equal(t, deployments.L1CrossDomainMessengerProxy, msgrAddr)
otherBridge, err := bridge.OTHERBRIDGE(callOpts)
require.NoError(t, err)
require.Equal(t, predeploys.L2StandardBridgeAddr, otherBridge)
factory, err := bindings.NewOptimismMintableERC20(predeploys.DevOptimismMintableERC20FactoryAddr, sim)
factory, err := bindings.NewOptimismMintableERC20(deployments.OptimismMintableERC20Factory, sim)
require.NoError(t, err)
bridgeAddr, err := factory.BRIDGE(callOpts)
require.NoError(t, err)
require.Equal(t, predeploys.DevL1StandardBridgeAddr, bridgeAddr)
weth9, err := bindings.NewWETH9(predeploys.DevWETH9Addr, sim)
require.NoError(t, err)
decimals, err := weth9.Decimals(callOpts)
require.NoError(t, err)
require.Equal(t, uint8(18), decimals)
symbol, err := weth9.Symbol(callOpts)
require.NoError(t, err)
require.Equal(t, "WETH", symbol)
name, err := weth9.Name(callOpts)
require.NoError(t, err)
require.Equal(t, "Wrapped Ether", name)
require.Equal(t, deployments.L1StandardBridgeProxy, bridgeAddr)
sysCfg, err := bindings.NewSystemConfig(predeploys.DevSystemConfigAddr, sim)
sysCfg, err := bindings.NewSystemConfig(deployments.SystemConfigProxy, sim)
require.NoError(t, err)
cfg, err := sysCfg.ResourceConfig(&bind.CallOpts{})
require.NoError(t, err)
......
......@@ -21,6 +21,7 @@ func BuildL2Genesis(config *DeployConfig, l1StartBlock *types.Block) (*core.Gene
db := state.NewMemoryStateDB(genspec)
if config.FundDevAccounts {
log.Info("Funding developer accounts in L2 genesis")
FundDevAccounts(db)
SetPrecompileBalances(db)
}
......
......@@ -73,17 +73,6 @@ func testBuildL2Genesis(t *testing.T, config *genesis.DeployConfig) *core.Genesi
return gen
}
func TestBuildL2DeveloperGenesis(t *testing.T) {
config, err := genesis.NewDeployConfig("./testdata/test-deploy-config-devnet-l1.json")
require.Nil(t, err)
config.EnableGovernance = false
config.FundDevAccounts = true
err = config.InitDeveloperDeployedAddresses()
require.NoError(t, err)
gen := testBuildL2Genesis(t, config)
require.Equal(t, 2344, len(gen.Alloc))
}
func TestBuildL2MainnetGenesis(t *testing.T) {
config, err := genesis.NewDeployConfig("./testdata/test-deploy-config-devnet-l1.json")
require.Nil(t, err)
......
......@@ -16,19 +16,13 @@ import (
// FundDevAccounts will fund each of the development accounts.
func FundDevAccounts(db vm.StateDB) {
for _, account := range DevAccounts {
db.CreateAccount(account)
if !db.Exist(account) {
db.CreateAccount(account)
}
db.AddBalance(account, devBalance)
}
}
// SetL1Proxies will set each of the proxies in the state. It requires
// a Proxy and ProxyAdmin deployment present so that the Proxy bytecode
// can be set in state and the ProxyAdmin can be set as the admin of the
// Proxy.
func SetL1Proxies(db vm.StateDB, proxyAdminAddr common.Address) error {
return setProxies(db, proxyAdminAddr, bigL1PredeployNamespace, 2048)
}
func setProxies(db vm.StateDB, proxyAdminAddr common.Address, namespace *big.Int, count uint64) error {
depBytecode, err := bindings.GetDeployedBytecode("Proxy")
if err != nil {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"AddressManager": "0x7aeb97910d4070426C00e820De4137D6d2ADf0AD",
"L1CrossDomainMessenger": "0x4562938D6831437F37Dd1BF5BBb7fe7a5F080eac",
"L1CrossDomainMessengerProxy": "0xa88B2060478401a52532814eddE6819d101802E2",
"L1ERC721Bridge": "0x7eC3b539C97c98D503Fb4FeE3dd4ee885DC192cd",
"L1ERC721BridgeProxy": "0xD16dbA9f860146F08C9EE83B891c138667021eC9",
"L1StandardBridge": "0x9a7EcB1c67f88396D252725F3259e9d8027F1562",
"L1StandardBridgeProxy": "0x6fB1869D7141C97Cf28668fA0A338BDC892F53c0",
"L2OutputOracle": "0x7F325Df611b236EE3EF469Da4a74f776c787d1B3",
"L2OutputOracleProxy": "0x48204903b06a64e3c44B0260F875497EA5316A02",
"OptimismMintableERC20Factory": "0x87658463F96977Fc95a068F1A206D2C0CF2db575",
"OptimismMintableERC20FactoryProxy": "0xA051F227dA1f5F1eEcbfCdcd7316cE299A233760",
"OptimismPortal": "0xb8D5D0Fa6E413b5de72C38a0a187731171b4F341",
"OptimismPortalProxy": "0xCF1a8a7F273DA1bd3112750Cc3691B46C541e8B7",
"ProxyAdmin": "0x36F4e85652236f9EdAeba78bBE9d8C2B55Ac5809",
"SystemConfig": "0xEc466e9A46914507c484DCC5cabA1Db787e34913",
"SystemConfigProxy": "0x73317009F4FadAfcDA357F3a082C7B68F5f8732F"
}
\ No newline at end of file
......@@ -6,20 +6,21 @@
"maxSequencerDrift": 20,
"sequencerWindowSize": 100,
"channelTimeout": 30,
"p2pSequencerAddress": "0x0000000000000000000000000000000000000000",
"l1UseClique": false,
"cliqueSignerAddress": "0x0000000000000000000000000000000000000000",
"p2pSequencerAddress": "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc",
"batchInboxAddress": "0x42000000000000000000000000000000000000ff",
"batchSenderAddress": "0x0000000000000000000000000000000000000000",
"l2OutputOracleSubmissionInterval": 6,
"batchSenderAddress": "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc",
"l2OutputOracleSubmissionInterval": 20,
"l2OutputOracleStartingBlockNumber": 0,
"l2OutputOracleStartingTimestamp": -1,
"l2OutputOracleProposer": "0x7770000000000000000000000000000000000001",
"l2OutputOracleChallenger": "0x7770000000000000000000000000000000000002",
"l2OutputOracleProposer": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
"l2OutputOracleChallenger": "0x15d34aaf54267db7d7c367839aaf71a00a2c6a65",
"l1BlockTime": 15,
"l1GenesisBlockNonce": "0x0",
"cliqueSignerAddress": "0x0000000000000000000000000000000000000000",
"l1GenesisBlockGasLimit": "0x1c9c380",
"l1GenesisBlockDifficulty": "0x1",
"finalSystemOwner": "0x0000000000000000000000000000000000000111",
"finalSystemOwner": "0xbcd4042de499d14e55001ccbb24a551f3b954096",
"portalGuardian": "0x0000000000000000000000000000000000000112",
"finalizationPeriodSeconds": 2,
"l1GenesisBlockMixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
......
......@@ -6,6 +6,7 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
......@@ -158,6 +159,7 @@ func BuildOptimism(immutable ImmutableConfig) (DeploymentResults, error) {
// can be properly set. The bytecode returned in the results is suitable to be
// inserted into the state via state surgery.
func BuildL2(constructors []deployer.Constructor) (DeploymentResults, error) {
log.Info("Creating L2 state")
deployments, err := deployer.Deploy(deployer.NewL2Backend(), constructors, l2Deployer)
if err != nil {
return nil, err
......
# op-e2e
The end to end tests in this repo depend on genesis state that is
created with the `bedrock-devnet` package. To create this state,
run the following commands from the root of the repository:
```bash
make install-geth
make devnet-allocs
```
This will leave artifacts in the `.devnet` directory that will be
read into `op-e2e` at runtime. The default deploy configuration
used for starting all `op-e2e` based tests can be found in
`packages/contracts-bedrock/deploy-config/devnetL1.json`. There
are some values that are safe to change in memory in `op-e2e` at
runtime, but others cannot be changed or else it will result in
broken tests. Any changes to `devnetL1.json` should result in
rebuilding the `.devnet` artifacts before the new values will
be present in the `op-e2e` tests.
......@@ -21,6 +21,8 @@ func TestBatchInLastPossibleBlocks(gt *testing.T) {
t := NewDefaultTesting(gt)
dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams)
dp.DeployConfig.SequencerWindowSize = 4
dp.DeployConfig.L2BlockTime = 2
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlDebug)
......
......@@ -26,6 +26,7 @@ func TestBatcher(gt *testing.T) {
MaxSequencerDrift: 20, // larger than L1 block time we simulate in this test (12)
SequencerWindowSize: 24,
ChannelTimeout: 20,
L1BlockTime: 12,
}
dp := e2eutils.MakeDeployParams(t, p)
sd := e2eutils.Setup(t, dp, defaultAlloc)
......@@ -345,6 +346,7 @@ func TestExtendedTimeWithoutL1Batches(gt *testing.T) {
MaxSequencerDrift: 20, // larger than L1 block time we simulate in this test (12)
SequencerWindowSize: 24,
ChannelTimeout: 20,
L1BlockTime: 12,
}
dp := e2eutils.MakeDeployParams(t, p)
sd := e2eutils.Setup(t, dp, defaultAlloc)
......@@ -402,6 +404,7 @@ func TestBigL2Txs(gt *testing.T) {
MaxSequencerDrift: 100,
SequencerWindowSize: 1000,
ChannelTimeout: 200, // give enough space to buffer large amounts of data before submitting it
L1BlockTime: 12,
}
dp := e2eutils.MakeDeployParams(t, p)
sd := e2eutils.Setup(t, dp, defaultAlloc)
......
......@@ -126,6 +126,7 @@ func (p *L2Proposer) sendTx(t Testing, data []byte) {
require.NoError(t, err, "need to sign tx")
err = p.l1.SendTransaction(t.Ctx(), tx)
log.Info("Proposer sent tx", "hash", tx.Hash(), "to", p.contractAddr)
require.NoError(t, err, "need to send tx")
p.lastTx = tx.Hash()
......
package actions
import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
......@@ -55,9 +55,10 @@ func TestProposer(gt *testing.T) {
sequencer.ActL1SafeSignal(t)
sequencer.ActL1FinalizedSignal(t)
require.Equal(t, sequencer.SyncStatus().UnsafeL2, sequencer.SyncStatus().FinalizedL2)
require.True(t, proposer.CanPropose(t))
// make proposals until there is nothing left to propose
for proposer.CanPropose(t) {
// and propose it to L1
proposer.ActMakeProposalTx(t)
// include proposal on L1
miner.ActL1StartBlock(12)(t)
......@@ -72,11 +73,15 @@ func TestProposer(gt *testing.T) {
// check that L1 stored the expected output root
outputOracleContract, err := bindings.NewL2OutputOracle(sd.DeploymentsL1.L2OutputOracleProxy, miner.EthClient())
require.NoError(t, err)
block := sequencer.SyncStatus().FinalizedL2
outputOnL1, err := outputOracleContract.GetL2OutputAfter(nil, new(big.Int).SetUint64(block.Number))
blockNumber, err := outputOracleContract.LatestBlockNumber(&bind.CallOpts{})
require.NoError(t, err)
require.Greater(t, int64(blockNumber.Uint64()), int64(0), "latest block number must be greater than 0")
block, err := seqEngine.EthClient().BlockByNumber(t.Ctx(), blockNumber)
require.NoError(t, err)
outputOnL1, err := outputOracleContract.GetL2OutputAfter(&bind.CallOpts{}, blockNumber)
require.NoError(t, err)
require.Less(t, block.Time, outputOnL1.Timestamp.Uint64(), "output is registered with L1 timestamp of proposal tx, past L2 block")
outputComputed, err := sequencer.RollupClient().OutputAtBlock(t.Ctx(), block.Number)
require.Less(t, block.Time(), outputOnL1.Timestamp.Uint64(), "output is registered with L1 timestamp of proposal tx, past L2 block")
outputComputed, err := sequencer.RollupClient().OutputAtBlock(t.Ctx(), blockNumber.Uint64())
require.NoError(t, err)
require.Equal(t, eth.Bytes32(outputOnL1.OutputRoot), outputComputed.OutputRoot, "output roots must match")
}
......@@ -37,6 +37,7 @@ func TestL2Sequencer_SequencerDrift(gt *testing.T) {
MaxSequencerDrift: 20, // larger than L1 block time we simulate in this test (12)
SequencerWindowSize: 24,
ChannelTimeout: 20,
L1BlockTime: 12,
}
dp := e2eutils.MakeDeployParams(t, p)
sd := e2eutils.Setup(t, dp, defaultAlloc)
......
......@@ -34,6 +34,7 @@ func TestL2Verifier_SequenceWindow(gt *testing.T) {
MaxSequencerDrift: 10,
SequencerWindowSize: 24,
ChannelTimeout: 10,
L1BlockTime: 15,
}
dp := e2eutils.MakeDeployParams(t, p)
sd := e2eutils.Setup(t, dp, defaultAlloc)
......
......@@ -25,6 +25,7 @@ func TestBatcherKeyRotation(gt *testing.T) {
t := NewDefaultTesting(gt)
dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams)
dp.DeployConfig.L2BlockTime = 2
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlDebug)
miner, seqEngine, sequencer := setupSequencerTest(t, sd, log)
......@@ -74,6 +75,10 @@ func TestBatcherKeyRotation(gt *testing.T) {
sysCfgOwner, err := bind.NewKeyedTransactorWithChainID(dp.Secrets.SysCfgOwner, sd.RollupCfg.L1ChainID)
require.NoError(t, err)
owner, err := sysCfgContract.Owner(&bind.CallOpts{})
require.NoError(t, err)
require.Equal(t, dp.Addresses.SysCfgOwner, owner, "system config owner mismatch")
// Change the batch sender key to Bob!
tx, err := sysCfgContract.SetBatcherHash(sysCfgOwner, dp.Addresses.Bob.Hash())
require.NoError(t, err)
......@@ -81,7 +86,12 @@ func TestBatcherKeyRotation(gt *testing.T) {
miner.ActL1StartBlock(12)(t)
miner.ActL1IncludeTx(dp.Addresses.SysCfgOwner)(t)
miner.ActL1EndBlock(t)
receipt, err := miner.EthClient().TransactionReceipt(t.Ctx(), tx.Hash())
require.NoError(t, err)
cfgChangeL1BlockNum := miner.l1Chain.CurrentBlock().Number.Uint64()
require.Equal(t, cfgChangeL1BlockNum, receipt.BlockNumber.Uint64())
// sequence L2 blocks, and submit with new batcher
sequencer.ActL1HeadSignal(t)
......@@ -91,17 +101,30 @@ func TestBatcherKeyRotation(gt *testing.T) {
miner.ActL1IncludeTx(dp.Addresses.Bob)(t)
miner.ActL1EndBlock(t)
// check that the first L2 payload that adopted the L1 block with the batcher key change indeed changed the batcher key in the system config
// check that the first L2 payload that adopted the L1 block with the batcher key change
// indeed changed the batcher key in the system config
engCl := seqEngine.EngineClient(t, sd.RollupCfg)
payload, err := engCl.PayloadByNumber(t.Ctx(), sequencer.L2Safe().Number+12) // 12 new L2 blocks: 5 with origin before L1 block with batch, 6 with origin of L1 block with batch, 1 with new origin that changed the batcher
require.NoError(t, err)
ref, err := derive.PayloadToBlockRef(payload, &sd.RollupCfg.Genesis)
require.NoError(t, err)
require.Equal(t, ref.L1Origin.Number, cfgChangeL1BlockNum, "L2 block with L1 origin that included config change")
require.Equal(t, ref.SequenceNumber, uint64(0), "first L2 block with this origin")
sysCfg, err := derive.PayloadToSystemConfig(payload, sd.RollupCfg)
require.NoError(t, err)
require.Equal(t, dp.Addresses.Bob, sysCfg.BatcherAddr, "bob should be batcher now")
// 12 new L2 blocks: 5 with origin before L1 block with batch, 6 with origin of L1 block
// with batch, 1 with new origin that changed the batcher
for i := 0; i <= 12; i++ {
payload, err := engCl.PayloadByNumber(t.Ctx(), sequencer.L2Safe().Number+uint64(i))
require.NoError(t, err)
ref, err := derive.PayloadToBlockRef(payload, &sd.RollupCfg.Genesis)
require.NoError(t, err)
if i < 6 {
require.Equal(t, ref.L1Origin.Number, cfgChangeL1BlockNum-2)
require.Equal(t, ref.SequenceNumber, uint64(i))
} else if i < 12 {
require.Equal(t, ref.L1Origin.Number, cfgChangeL1BlockNum-1)
require.Equal(t, ref.SequenceNumber, uint64(i-6))
} else {
require.Equal(t, ref.L1Origin.Number, cfgChangeL1BlockNum)
require.Equal(t, ref.SequenceNumber, uint64(0), "first L2 block with this origin")
sysCfg, err := derive.PayloadToSystemConfig(payload, sd.RollupCfg)
require.NoError(t, err)
require.Equal(t, dp.Addresses.Bob, sysCfg.BatcherAddr, "bob should be batcher now")
}
}
// sync from L1
sequencer.ActL2PipelineFull(t)
......
......@@ -19,7 +19,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
)
......@@ -31,11 +31,11 @@ type L1Bindings struct {
L2OutputOracle *bindings.L2OutputOracle
}
func NewL1Bindings(t Testing, l1Cl *ethclient.Client, deployments *e2eutils.DeploymentsL1) *L1Bindings {
optimismPortal, err := bindings.NewOptimismPortal(deployments.OptimismPortalProxy, l1Cl)
func NewL1Bindings(t Testing, l1Cl *ethclient.Client) *L1Bindings {
optimismPortal, err := bindings.NewOptimismPortal(config.L1Deployments.OptimismPortalProxy, l1Cl)
require.NoError(t, err)
l2OutputOracle, err := bindings.NewL2OutputOracle(deployments.L2OutputOracleProxy, l1Cl)
l2OutputOracle, err := bindings.NewL2OutputOracle(config.L1Deployments.L2OutputOracleProxy, l1Cl)
require.NoError(t, err)
return &L1Bindings{
......@@ -319,7 +319,7 @@ func (s *CrossLayerUser) ActDeposit(t Testing) {
// estimate gas used by deposit
gas, err := s.L2.env.EthCl.EstimateGas(t.Ctx(), ethereum.CallMsg{
From: s.L2.address,
To: s.L2.txToAddr,
To: &toAddr,
Value: depositTransferValue, // TODO: estimate gas does not support minting yet
Data: s.L2.txCallData,
AccessList: nil,
......
......@@ -52,6 +52,9 @@ func runCrossLayerUserTest(gt *testing.T, test regolithScheduledTest) {
sd := e2eutils.Setup(t, dp, defaultAlloc)
log := testlog.Logger(t, log.LvlDebug)
require.Equal(t, dp.Secrets.Addresses().Batcher, dp.DeployConfig.BatchSenderAddress)
require.Equal(t, dp.Secrets.Addresses().Proposer, dp.DeployConfig.L2OutputOracleProposer)
miner, seqEngine, seq := setupSequencerTest(t, sd, log)
batcher := NewL2Batcher(log, sd.RollupCfg, &BatcherCfg{
MinL1TxSize: 0,
......@@ -77,7 +80,7 @@ func runCrossLayerUserTest(gt *testing.T, test regolithScheduledTest) {
EthCl: l1Cl,
Signer: types.LatestSigner(sd.L1Cfg.Config),
AddressCorpora: addresses,
Bindings: NewL1Bindings(t, l1Cl, &sd.DeploymentsL1),
Bindings: NewL1Bindings(t, l1Cl),
}
l2UserEnv := &BasicUserEnv[*L2Bindings]{
EthCl: l2Cl,
......
......@@ -74,13 +74,13 @@ func TestERC20BridgeDeposits(t *testing.T) {
require.NotNil(t, event)
// Approve WETH9 with the bridge
tx, err = WETH9.Approve(opts, predeploys.DevL1StandardBridgeAddr, new(big.Int).SetUint64(math.MaxUint64))
tx, err = WETH9.Approve(opts, cfg.L1Deployments.L1StandardBridgeProxy, new(big.Int).SetUint64(math.MaxUint64))
require.NoError(t, err)
_, err = waitForTransaction(tx.Hash(), l1Client, 6*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.NoError(t, err)
// Bridge the WETH9
l1StandardBridge, err := bindings.NewL1StandardBridge(predeploys.DevL1StandardBridgeAddr, l1Client)
l1StandardBridge, err := bindings.NewL1StandardBridge(cfg.L1Deployments.L1StandardBridgeProxy, l1Client)
require.NoError(t, err)
tx, err = l1StandardBridge.BridgeERC20(opts, weth9Address, event.LocalToken, big.NewInt(100), 100000, []byte{})
require.NoError(t, err)
......@@ -90,7 +90,7 @@ func TestERC20BridgeDeposits(t *testing.T) {
t.Log("Deposit through L1StandardBridge", "gas used", depositReceipt.GasUsed)
// compute the deposit transaction hash + poll for it
portal, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
portal, err := bindings.NewOptimismPortal(cfg.L1Deployments.OptimismPortalProxy, l1Client)
require.NoError(t, err)
depIt, err := portal.FilterTransactionDeposited(&bind.FilterOpts{Start: 0}, nil, nil, nil)
......
package config
import (
"flag"
"fmt"
"os"
"path/filepath"
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/state"
)
var (
// All of the following variables are set in the init function
// and read from JSON files on disk that are generated by the
// foundry deploy script. The are globally exported to be used
// in end to end tests.
// L1Allocs represents the L1 genesis block state.
L1Allocs *state.Dump
// L1Deployments maps contract names to accounts in the L1
// genesis block state.
L1Deployments *genesis.L1Deployments
// DeployConfig represents the deploy config used by the system.
DeployConfig *genesis.DeployConfig
)
// Init testing to enable test flags
var _ = func() bool {
testing.Init()
return true
}()
func init() {
var l1AllocsPath, l1DeploymentsPath, deployConfigPath string
cwd, err := os.Getwd()
if err != nil {
panic(err)
}
root, err := findMonorepoRoot(cwd)
if err != nil {
panic(err)
}
defaultL1AllocsPath := filepath.Join(root, ".devnet", "allocs-l1.json")
defaultL1DeploymentsPath := filepath.Join(root, ".devnet", "addresses.json")
defaultDeployConfigPath := filepath.Join(root, "packages", "contracts-bedrock", "deploy-config", "devnetL1.json")
flag.StringVar(&l1AllocsPath, "l1-allocs", defaultL1AllocsPath, "")
flag.StringVar(&l1DeploymentsPath, "l1-deployments", defaultL1DeploymentsPath, "")
flag.StringVar(&deployConfigPath, "deploy-config", defaultDeployConfigPath, "")
flag.Parse()
if err := allExist(l1AllocsPath, l1DeploymentsPath, deployConfigPath); err != nil {
return
}
L1Allocs, err = genesis.NewStateDump(l1AllocsPath)
if err != nil {
panic(err)
}
L1Deployments, err = genesis.NewL1Deployments(l1DeploymentsPath)
if err != nil {
panic(err)
}
DeployConfig, err = genesis.NewDeployConfig(deployConfigPath)
if err != nil {
panic(err)
}
// Do not use clique in the in memory tests. Otherwise block building
// would be much more complex.
DeployConfig.L1UseClique = false
// Set the L1 genesis block timestamp to now
DeployConfig.L1GenesisBlockTimestamp = hexutil.Uint64(time.Now().Unix())
DeployConfig.FundDevAccounts = true
// Speed up the in memory tests
DeployConfig.L1BlockTime = 2
DeployConfig.L2BlockTime = 1
if L1Deployments != nil {
DeployConfig.SetDeployments(L1Deployments)
}
}
func allExist(filenames ...string) error {
for _, filename := range filenames {
if _, err := os.Stat(filename); err != nil {
fmt.Printf("file %s does not exist, skipping genesis generation\n", filename)
return err
}
}
return nil
}
// findMonorepoRoot will recursively search upwards for a go.mod file.
// This depends on the structure of the monorepo having a go.mod file at the root.
func findMonorepoRoot(startDir string) (string, error) {
dir, err := filepath.Abs(startDir)
if err != nil {
return "", err
}
for {
modulePath := filepath.Join(dir, "go.mod")
if _, err := os.Stat(modulePath); err == nil {
return dir, nil
}
parentDir := filepath.Dir(dir)
// Check if we reached the filesystem root
if parentDir == dir {
break
}
dir = parentDir
}
return "", fmt.Errorf("monorepo root not found")
}
......@@ -11,6 +11,7 @@ func TestCollectAddresses(t *testing.T) {
MaxSequencerDrift: 40,
SequencerWindowSize: 120,
ChannelTimeout: 120,
L1BlockTime: 15,
}
dp := MakeDeployParams(t, tp)
alloc := &AllocParams{PrefundTestUsers: true}
......
......@@ -14,14 +14,16 @@ import (
// DefaultMnemonicConfig is the default mnemonic used in testing.
// We prefer a mnemonic rather than direct private keys to make it easier
// to export all testing keys in external tooling for use during debugging.
// If these values are changed, it is subject to breaking tests. They
// must be in sync with the values in the DeployConfig used to create the system.
var DefaultMnemonicConfig = &MnemonicConfig{
Mnemonic: "test test test test test test test test test test test junk",
Deployer: "m/44'/60'/0'/0/1",
CliqueSigner: "m/44'/60'/0'/0/2",
Proposer: "m/44'/60'/0'/0/3",
Batcher: "m/44'/60'/0'/0/4",
CliqueSigner: "m/44'/60'/0'/0/0",
Proposer: "m/44'/60'/0'/0/1",
Batcher: "m/44'/60'/0'/0/2",
Deployer: "m/44'/60'/0'/0/3",
Alice: "m/44'/60'/0'/0/4",
SequencerP2P: "m/44'/60'/0'/0/5",
Alice: "m/44'/60'/0'/0/6",
Bob: "m/44'/60'/0'/0/7",
Mallory: "m/44'/60'/0'/0/8",
SysCfgOwner: "m/44'/60'/0'/0/9",
......@@ -32,8 +34,8 @@ var DefaultMnemonicConfig = &MnemonicConfig{
type MnemonicConfig struct {
Mnemonic string
Deployer string
CliqueSigner string
Deployer string
SysCfgOwner string
// rollup actors
......@@ -97,8 +99,8 @@ func (m *MnemonicConfig) Secrets() (*Secrets, error) {
return &Secrets{
Deployer: deployer,
CliqueSigner: cliqueSigner,
SysCfgOwner: sysCfgOwner,
CliqueSigner: cliqueSigner,
Proposer: proposer,
Batcher: batcher,
SequencerP2P: sequencerP2P,
......
......@@ -9,12 +9,11 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum-optimism/optimism/op-node/rollup"
)
......@@ -31,10 +30,6 @@ func WriteDefaultJWT(t TestingBase) string {
return jwtPath
}
func uint64ToBig(in uint64) *hexutil.Big {
return (*hexutil.Big)(new(big.Int).SetUint64(in))
}
// DeployParams bundles the deployment parameters to generate further testing inputs with.
type DeployParams struct {
DeployConfig *genesis.DeployConfig
......@@ -56,73 +51,18 @@ func MakeDeployParams(t require.TestingT, tp *TestParams) *DeployParams {
secrets, err := mnemonicCfg.Secrets()
require.NoError(t, err)
addresses := secrets.Addresses()
deployConfig := &genesis.DeployConfig{
L1ChainID: 901,
L2ChainID: 902,
L2BlockTime: 2,
MaxSequencerDrift: tp.MaxSequencerDrift,
SequencerWindowSize: tp.SequencerWindowSize,
ChannelTimeout: tp.ChannelTimeout,
P2PSequencerAddress: addresses.SequencerP2P,
BatchInboxAddress: common.Address{0: 0x42, 19: 0xff}, // tbd
BatchSenderAddress: addresses.Batcher,
L2OutputOracleSubmissionInterval: 6,
L2OutputOracleStartingTimestamp: -1,
L2OutputOracleProposer: addresses.Proposer,
L2OutputOracleChallenger: common.Address{}, // tbd
FinalSystemOwner: addresses.SysCfgOwner,
L1BlockTime: tp.L1BlockTime,
L1GenesisBlockNonce: 0,
CliqueSignerAddress: common.Address{}, // proof of stake, no clique
L1GenesisBlockTimestamp: hexutil.Uint64(time.Now().Unix()),
L1GenesisBlockGasLimit: 30_000_000,
L1GenesisBlockDifficulty: uint64ToBig(1),
L1GenesisBlockMixHash: common.Hash{},
L1GenesisBlockCoinbase: common.Address{},
L1GenesisBlockNumber: 0,
L1GenesisBlockGasUsed: 0,
L1GenesisBlockParentHash: common.Hash{},
L1GenesisBlockBaseFeePerGas: uint64ToBig(1000_000_000), // 1 gwei
FinalizationPeriodSeconds: 12,
deployConfig := config.DeployConfig.Copy()
deployConfig.MaxSequencerDrift = tp.MaxSequencerDrift
deployConfig.SequencerWindowSize = tp.SequencerWindowSize
deployConfig.ChannelTimeout = tp.ChannelTimeout
deployConfig.L1BlockTime = tp.L1BlockTime
deployConfig.L2GenesisRegolithTimeOffset = nil
L2GenesisBlockNonce: 0,
L2GenesisBlockGasLimit: 30_000_000,
L2GenesisBlockDifficulty: uint64ToBig(0),
L2GenesisBlockMixHash: common.Hash{},
L2GenesisBlockNumber: 0,
L2GenesisBlockGasUsed: 0,
L2GenesisBlockParentHash: common.Hash{},
L2GenesisBlockBaseFeePerGas: uint64ToBig(1000_000_000),
GasPriceOracleOverhead: 2100,
GasPriceOracleScalar: 1000_000,
DeploymentWaitConfirmations: 1,
SequencerFeeVaultRecipient: common.Address{19: 1},
BaseFeeVaultRecipient: common.Address{19: 2},
L1FeeVaultRecipient: common.Address{19: 3},
BaseFeeVaultMinimumWithdrawalAmount: uint64ToBig(1000_000_000), // 1 gwei
L1FeeVaultMinimumWithdrawalAmount: uint64ToBig(1000_000_000), // 1 gwei
SequencerFeeVaultMinimumWithdrawalAmount: uint64ToBig(1000_000_000), // 1 gwei
BaseFeeVaultWithdrawalNetwork: genesis.WithdrawalNetwork("local"), // L2 withdrawal network
L1FeeVaultWithdrawalNetwork: genesis.WithdrawalNetwork("local"), // L2 withdrawal network
SequencerFeeVaultWithdrawalNetwork: genesis.WithdrawalNetwork("local"), // L2 withdrawal network
EIP1559Elasticity: 10,
EIP1559Denominator: 50,
FundDevAccounts: false,
}
// Configure the DeployConfig with the expected developer L1
// addresses.
if err := deployConfig.InitDeveloperDeployedAddresses(); err != nil {
panic(err)
}
require.NoError(t, deployConfig.Check())
require.Equal(t, addresses.Batcher, deployConfig.BatchSenderAddress)
require.Equal(t, addresses.Proposer, deployConfig.L2OutputOracleProposer)
require.Equal(t, addresses.SequencerP2P, deployConfig.P2PSequencerAddress)
return &DeployParams{
DeployConfig: deployConfig,
......@@ -132,23 +72,12 @@ func MakeDeployParams(t require.TestingT, tp *TestParams) *DeployParams {
}
}
// DeploymentsL1 captures the L1 addresses used in the deployment,
// commonly just the developer predeploys during testing,
// but later deployed contracts may be used in some tests too.
type DeploymentsL1 struct {
L1CrossDomainMessengerProxy common.Address
L1StandardBridgeProxy common.Address
L2OutputOracleProxy common.Address
OptimismPortalProxy common.Address
SystemConfigProxy common.Address
}
// SetupData bundles the L1, L2, rollup and deployment configuration data: everything for a full test setup.
type SetupData struct {
L1Cfg *core.Genesis
L2Cfg *core.Genesis
RollupCfg *rollup.Config
DeploymentsL1 DeploymentsL1
DeploymentsL1 *genesis.L1Deployments
}
// AllocParams defines genesis allocations to apply on top of the genesis generated by deploy parameters.
......@@ -169,8 +98,14 @@ func Ether(v uint64) *big.Int {
// Setup computes the testing setup configurations from deployment configuration and optional allocation parameters.
func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *SetupData {
deployConf := deployParams.DeployConfig
l1Genesis, err := genesis.BuildL1DeveloperGenesis(deployConf)
deployConf := deployParams.DeployConfig.Copy()
deployConf.L1GenesisBlockTimestamp = hexutil.Uint64(time.Now().Unix())
require.NoError(t, deployConf.Check())
l1Deployments := config.L1Deployments.Copy()
require.NoError(t, l1Deployments.Check())
l1Genesis, err := genesis.BuildL1DeveloperGenesis(deployConf, config.L1Allocs, l1Deployments, true)
require.NoError(t, err, "failed to create l1 genesis")
if alloc.PrefundTestUsers {
for _, addr := range deployParams.Addresses.All() {
......@@ -218,18 +153,12 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *
L1ChainID: new(big.Int).SetUint64(deployConf.L1ChainID),
L2ChainID: new(big.Int).SetUint64(deployConf.L2ChainID),
BatchInboxAddress: deployConf.BatchInboxAddress,
DepositContractAddress: predeploys.DevOptimismPortalAddr,
L1SystemConfigAddress: predeploys.DevSystemConfigAddr,
DepositContractAddress: deployConf.OptimismPortalProxy,
L1SystemConfigAddress: deployConf.SystemConfigProxy,
RegolithTime: deployConf.RegolithTime(uint64(deployConf.L1GenesisBlockTimestamp)),
}
deploymentsL1 := DeploymentsL1{
L1CrossDomainMessengerProxy: predeploys.DevL1CrossDomainMessengerAddr,
L1StandardBridgeProxy: predeploys.DevL1StandardBridgeAddr,
L2OutputOracleProxy: predeploys.DevL2OutputOracleAddr,
OptimismPortalProxy: predeploys.DevOptimismPortalAddr,
SystemConfigProxy: predeploys.DevSystemConfigAddr,
}
require.NoError(t, rollupCfg.Check())
// Sanity check that the config is correct
require.Equal(t, deployParams.Secrets.Addresses().Batcher, deployParams.DeployConfig.BatchSenderAddress)
......@@ -240,7 +169,7 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) *
L1Cfg: l1Genesis,
L2Cfg: l2Genesis,
RollupCfg: rollupCfg,
DeploymentsL1: deploymentsL1,
DeploymentsL1: l1Deployments,
}
}
......@@ -252,46 +181,3 @@ func SystemConfigFromDeployConfig(deployConfig *genesis.DeployConfig) eth.System
GasLimit: uint64(deployConfig.L2GenesisBlockGasLimit),
}
}
// ForkedDeployConfig returns a deploy config that's suitable for use with a
// forked L1.
func ForkedDeployConfig(t require.TestingT, mnemonicCfg *MnemonicConfig, startBlock *types.Block) *genesis.DeployConfig {
startTag := rpc.BlockNumberOrHashWithHash(startBlock.Hash(), true)
secrets, err := mnemonicCfg.Secrets()
require.NoError(t, err)
addrs := secrets.Addresses()
marshalable := genesis.MarshalableRPCBlockNumberOrHash(startTag)
out := &genesis.DeployConfig{
L1StartingBlockTag: &marshalable,
L1ChainID: 1,
L2ChainID: 10,
L2BlockTime: 2,
MaxSequencerDrift: 3600,
SequencerWindowSize: 100,
ChannelTimeout: 40,
P2PSequencerAddress: addrs.SequencerP2P,
BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000000000000"),
BatchSenderAddress: addrs.Batcher,
FinalSystemOwner: addrs.SysCfgOwner,
L1GenesisBlockDifficulty: uint64ToBig(0),
L1GenesisBlockBaseFeePerGas: uint64ToBig(0),
L2OutputOracleSubmissionInterval: 10,
L2OutputOracleStartingTimestamp: int(startBlock.Time()),
L2OutputOracleProposer: addrs.Proposer,
L2OutputOracleChallenger: addrs.Deployer,
L2GenesisBlockGasLimit: hexutil.Uint64(15_000_000),
// taken from devnet, need to check this
L2GenesisBlockBaseFeePerGas: uint64ToBig(0x3B9ACA00),
L2GenesisBlockDifficulty: uint64ToBig(0),
L1BlockTime: 12,
CliqueSignerAddress: addrs.CliqueSigner,
FinalizationPeriodSeconds: 2,
DeploymentWaitConfirmations: 1,
EIP1559Elasticity: 10,
EIP1559Denominator: 50,
GasPriceOracleOverhead: 2100,
GasPriceOracleScalar: 1_000_000,
FundDevAccounts: true,
}
return out
}
......@@ -8,6 +8,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-e2e/config"
)
func TestWriteDefaultJWT(t *testing.T) {
......@@ -22,6 +23,7 @@ func TestSetup(t *testing.T) {
MaxSequencerDrift: 40,
SequencerWindowSize: 120,
ChannelTimeout: 120,
L1BlockTime: 15,
}
dp := MakeDeployParams(t, tp)
alloc := &AllocParams{PrefundTestUsers: true}
......@@ -32,6 +34,6 @@ func TestSetup(t *testing.T) {
require.Contains(t, sd.L2Cfg.Alloc, dp.Addresses.Alice)
require.Equal(t, sd.L2Cfg.Alloc[dp.Addresses.Alice].Balance, Ether(1e12))
require.Contains(t, sd.L1Cfg.Alloc, predeploys.DevOptimismPortalAddr)
require.Contains(t, sd.L1Cfg.Alloc, config.L1Deployments.OptimismPortalProxy)
require.Contains(t, sd.L2Cfg.Alloc, predeploys.L1BlockAddr)
}
......@@ -26,6 +26,11 @@ import (
"github.com/ethereum/go-ethereum/node"
)
var (
// errTimeout represents a timeout
errTimeout = errors.New("timeout")
)
func waitForL1OriginOnL2(l1BlockNum uint64, client *ethclient.Client, timeout time.Duration) (*types.Block, error) {
timeoutCh := time.After(timeout)
ctx, cancel := context.WithTimeout(context.Background(), timeout)
......@@ -56,7 +61,7 @@ func waitForL1OriginOnL2(l1BlockNum uint64, client *ethclient.Client, timeout ti
case err := <-headSub.Err():
return nil, fmt.Errorf("error in head subscription: %w", err)
case <-timeoutCh:
return nil, errors.New("timeout")
return nil, errTimeout
}
}
}
......@@ -77,7 +82,11 @@ func waitForTransaction(hash common.Hash, client *ethclient.Client, timeout time
select {
case <-timeoutCh:
return nil, errors.New("timeout")
tip, err := client.BlockByNumber(context.Background(), nil)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("receipt for transaction %s not found. tip block number is %d: %w", hash.Hex(), tip.NumberU64(), errTimeout)
case <-ticker.C:
}
}
......@@ -104,7 +113,7 @@ func waitForBlock(number *big.Int, client *ethclient.Client, timeout time.Durati
case err := <-headSub.Err():
return nil, fmt.Errorf("error in head subscription: %w", err)
case <-timeoutCh:
return nil, errors.New("timeout")
return nil, errTimeout
}
}
}
......
......@@ -9,6 +9,7 @@ import (
"testing"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/client"
"github.com/ethereum-optimism/optimism/op-node/eth"
......@@ -49,7 +50,8 @@ type OpGeth struct {
func NewOpGeth(t *testing.T, ctx context.Context, cfg *SystemConfig) (*OpGeth, error) {
logger := testlog.Logger(t, log.LvlCrit)
l1Genesis, err := genesis.BuildL1DeveloperGenesis(cfg.DeployConfig)
l1Genesis, err := genesis.BuildL1DeveloperGenesis(cfg.DeployConfig, config.L1Allocs, config.L1Deployments, true)
require.Nil(t, err)
l1Block := l1Genesis.ToBlock()
......
......@@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"github.com/stretchr/testify/require"
......@@ -42,6 +43,7 @@ import (
batchermetrics "github.com/ethereum-optimism/optimism/op-batcher/metrics"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-node/chaincfg"
"github.com/ethereum-optimism/optimism/op-node/eth"
......@@ -78,81 +80,27 @@ func newTxMgrConfig(l1Addr string, privKey *ecdsa.PrivateKey) txmgr.CLIConfig {
func DefaultSystemConfig(t *testing.T) SystemConfig {
secrets, err := e2eutils.DefaultMnemonicConfig.Secrets()
require.NoError(t, err)
addresses := secrets.Addresses()
deployConfig := &genesis.DeployConfig{
L1ChainID: 900,
L2ChainID: 901,
L2BlockTime: 1,
FinalizationPeriodSeconds: 60 * 60 * 24,
MaxSequencerDrift: 10,
SequencerWindowSize: 30,
ChannelTimeout: 10,
P2PSequencerAddress: addresses.SequencerP2P,
BatchInboxAddress: common.Address{0: 0x52, 19: 0xff}, // tbd
BatchSenderAddress: addresses.Batcher,
L2OutputOracleSubmissionInterval: 4,
L2OutputOracleStartingTimestamp: -1,
L2OutputOracleProposer: addresses.Proposer,
L2OutputOracleChallenger: common.Address{}, // tbd
FinalSystemOwner: addresses.SysCfgOwner,
L1BlockTime: 2,
L1GenesisBlockNonce: 4660,
CliqueSignerAddress: common.Address{}, // op-e2e used to run Clique, but now uses fake Proof of Stake.
L1GenesisBlockTimestamp: hexutil.Uint64(time.Now().Unix()),
L1GenesisBlockGasLimit: 30_000_000,
L1GenesisBlockDifficulty: uint642big(1),
L1GenesisBlockMixHash: common.Hash{},
L1GenesisBlockCoinbase: common.Address{},
L1GenesisBlockNumber: 0,
L1GenesisBlockGasUsed: 0,
L1GenesisBlockParentHash: common.Hash{},
L1GenesisBlockBaseFeePerGas: uint642big(7),
L2GenesisBlockNonce: 0,
L2GenesisBlockGasLimit: 30_000_000,
L2GenesisBlockDifficulty: uint642big(1),
L2GenesisBlockMixHash: common.Hash{},
L2GenesisBlockNumber: 0,
L2GenesisBlockGasUsed: 0,
L2GenesisBlockParentHash: common.Hash{},
L2GenesisBlockBaseFeePerGas: uint642big(7),
GasPriceOracleOverhead: 2100,
GasPriceOracleScalar: 1_000_000,
SequencerFeeVaultRecipient: common.Address{19: 1},
BaseFeeVaultRecipient: common.Address{19: 2},
L1FeeVaultRecipient: common.Address{19: 3},
BaseFeeVaultMinimumWithdrawalAmount: uint642big(1000_000_000), // 1 gwei
L1FeeVaultMinimumWithdrawalAmount: uint642big(1000_000_000), // 1 gwei
SequencerFeeVaultMinimumWithdrawalAmount: uint642big(1000_000_000), // 1 gwei
BaseFeeVaultWithdrawalNetwork: genesis.WithdrawalNetwork("local"), // L2 withdrawal network
L1FeeVaultWithdrawalNetwork: genesis.WithdrawalNetwork("local"), // L2 withdrawal network
SequencerFeeVaultWithdrawalNetwork: genesis.WithdrawalNetwork("local"), // L2 withdrawal network
DeploymentWaitConfirmations: 1,
EIP1559Elasticity: 2,
EIP1559Denominator: 8,
FundDevAccounts: true,
}
if err := deployConfig.InitDeveloperDeployedAddresses(); err != nil {
panic(err)
}
deployConfig := config.DeployConfig.Copy()
deployConfig.L1GenesisBlockTimestamp = hexutil.Uint64(time.Now().Unix())
require.NoError(t, deployConfig.Check())
l1Deployments := config.L1Deployments.Copy()
require.NoError(t, l1Deployments.Check())
return SystemConfig{
Secrets: secrets,
require.Equal(t, secrets.Addresses().Batcher, deployConfig.BatchSenderAddress)
require.Equal(t, secrets.Addresses().SequencerP2P, deployConfig.P2PSequencerAddress)
require.Equal(t, secrets.Addresses().Proposer, deployConfig.L2OutputOracleProposer)
Premine: make(map[common.Address]*big.Int),
// Tests depend on premine being filled with secrets addresses
premine := make(map[common.Address]*big.Int)
for _, addr := range secrets.Addresses().All() {
premine[addr] = new(big.Int).Mul(big.NewInt(1000), big.NewInt(params.Ether))
}
return SystemConfig{
Secrets: secrets,
Premine: premine,
DeployConfig: deployConfig,
L1Deployments: config.L1Deployments,
L1InfoPredeployAddress: predeploys.L1BlockAddr,
JWTFilePath: writeDefaultJWT(t),
JWTSecret: testingJWTSecret,
......@@ -169,7 +117,7 @@ func DefaultSystemConfig(t *testing.T) SystemConfig {
ListenPort: 0,
EnableAdmin: true,
},
L1EpochPollInterval: time.Second * 4,
L1EpochPollInterval: time.Second * 2,
ConfigPersistence: &rollupNode.DisabledConfigPersistence{},
},
"verifier": {
......@@ -213,7 +161,8 @@ type SystemConfig struct {
Secrets *e2eutils.Secrets
L1InfoPredeployAddress common.Address
DeployConfig *genesis.DeployConfig
DeployConfig *genesis.DeployConfig
L1Deployments *genesis.L1Deployments
JWTFilePath string
JWTSecret [32]byte
......@@ -355,7 +304,11 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
c = sys.TimeTravelClock
}
l1Genesis, err := genesis.BuildL1DeveloperGenesis(cfg.DeployConfig)
if err := cfg.DeployConfig.Check(); err != nil {
return nil, err
}
l1Genesis, err := genesis.BuildL1DeveloperGenesis(cfg.DeployConfig, config.L1Allocs, config.L1Deployments, true)
if err != nil {
return nil, err
}
......@@ -419,12 +372,15 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
L1ChainID: cfg.L1ChainIDBig(),
L2ChainID: cfg.L2ChainIDBig(),
BatchInboxAddress: cfg.DeployConfig.BatchInboxAddress,
DepositContractAddress: predeploys.DevOptimismPortalAddr,
L1SystemConfigAddress: predeploys.DevSystemConfigAddr,
DepositContractAddress: cfg.DeployConfig.OptimismPortalProxy,
L1SystemConfigAddress: cfg.DeployConfig.SystemConfigProxy,
RegolithTime: cfg.DeployConfig.RegolithTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
}
}
defaultConfig := makeRollupConfig()
if err := defaultConfig.Check(); err != nil {
return nil, err
}
sys.RollupConfig = &defaultConfig
// Initialize nodes
......@@ -620,11 +576,12 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
if sys.RollupNodes["sequencer"] == nil {
return sys, nil
}
// L2Output Submitter
sys.L2OutputSubmitter, err = l2os.NewL2OutputSubmitterFromCLIConfig(l2os.CLIConfig{
L1EthRpc: sys.Nodes["l1"].WSEndpoint(),
RollupRpc: sys.RollupNodes["sequencer"].HTTPEndpoint(),
L2OOAddress: predeploys.DevL2OutputOracleAddr.String(),
L2OOAddress: config.L1Deployments.L2OutputOracleProxy.Hex(),
PollInterval: 50 * time.Millisecond,
TxMgrConfig: newTxMgrConfig(sys.Nodes["l1"].WSEndpoint(), cfg.Secrets.Proposer),
AllowNonFinalized: cfg.NonFinalizedProposals,
......@@ -648,7 +605,7 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) {
RollupRpc: sys.RollupNodes["sequencer"].HTTPEndpoint(),
MaxPendingTransactions: 0,
MaxChannelDuration: 1,
MaxL1TxSize: 120_000,
MaxL1TxSize: 240_000,
CompressorConfig: compressor.CLIConfig{
TargetL1TxSizeBytes: cfg.BatcherTargetL1TxSizeBytes,
TargetNumFrames: 1,
......@@ -762,12 +719,6 @@ func (cfg SystemConfig) L2ChainIDBig() *big.Int {
return new(big.Int).SetUint64(cfg.DeployConfig.L2ChainID)
}
func uint642big(in uint64) *hexutil.Big {
b := new(big.Int).SetUint64(in)
hu := hexutil.Big(*b)
return &hu
}
func hexPriv(in *ecdsa.PrivateKey) string {
b := e2eutils.EncodePrivKey(in)
return hexutil.Encode(b)
......
This diff is collapsed.
......@@ -52,7 +52,7 @@ func TestGasPriceOracleFeeUpdates(t *testing.T) {
ethPrivKey := cfg.Secrets.SysCfgOwner
// Bind to the SystemConfig & GasPriceOracle contracts
sysconfig, err := bindings.NewSystemConfig(predeploys.DevSystemConfigAddr, l1Client)
sysconfig, err := bindings.NewSystemConfig(cfg.L1Deployments.SystemConfigProxy, l1Client)
require.Nil(t, err)
gpoContract, err := bindings.NewGasPriceOracleCaller(predeploys.GasPriceOracleAddr, l2Seq)
require.Nil(t, err)
......@@ -247,7 +247,7 @@ func TestMixedDepositValidity(t *testing.T) {
txTimeoutDuration := 10 * time.Duration(cfg.DeployConfig.L1BlockTime) * time.Second
// Bind to the deposit contract
depositContract, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
depositContract, err := bindings.NewOptimismPortal(cfg.L1Deployments.OptimismPortalProxy, l1Client)
require.NoError(t, err)
// Create a struct used to track our transactors and their transactions sent.
......@@ -410,7 +410,9 @@ func TestMixedWithdrawalValidity(t *testing.T) {
// Create our system configuration, funding all accounts we created for L1/L2, and start it
cfg := DefaultSystemConfig(t)
cfg.DeployConfig.FinalizationPeriodSeconds = 6
cfg.DeployConfig.L2BlockTime = 2
require.LessOrEqual(t, cfg.DeployConfig.FinalizationPeriodSeconds, uint64(6))
require.Equal(t, cfg.DeployConfig.FundDevAccounts, true)
sys, err := cfg.Start()
require.NoError(t, err, "error starting up system")
defer sys.Close()
......@@ -421,14 +423,37 @@ func TestMixedWithdrawalValidity(t *testing.T) {
l2Verif := sys.Clients["verifier"]
require.NoError(t, err)
systemConfig, err := bindings.NewSystemConfigCaller(cfg.L1Deployments.SystemConfig, l1Client)
require.NoError(t, err)
unsafeBlockSigner, err := systemConfig.UnsafeBlockSigner(nil)
require.NoError(t, err)
require.Equal(t, cfg.DeployConfig.P2PSequencerAddress, unsafeBlockSigner)
// The batcher has balance on L1
batcherBalance, err := l1Client.BalanceAt(context.Background(), cfg.DeployConfig.BatchSenderAddress, nil)
require.NoError(t, err)
require.NotEqual(t, batcherBalance, big.NewInt(0))
// The proposer has balance on L1
proposerBalance, err := l1Client.BalanceAt(context.Background(), cfg.DeployConfig.L2OutputOracleProposer, nil)
require.NoError(t, err)
require.NotEqual(t, proposerBalance, big.NewInt(0))
// Define our L1 transaction timeout duration.
txTimeoutDuration := 10 * time.Duration(cfg.DeployConfig.L1BlockTime) * time.Second
// Bind to the deposit contract
depositContract, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
depositContract, err := bindings.NewOptimismPortal(cfg.L1Deployments.OptimismPortalProxy, l1Client)
_ = depositContract
require.NoError(t, err)
l2OutputOracle, err := bindings.NewL2OutputOracleCaller(cfg.L1Deployments.L2OutputOracleProxy, l1Client)
require.NoError(t, err)
finalizationPeriod, err := l2OutputOracle.FINALIZATIONPERIODSECONDS(nil)
require.NoError(t, err)
require.Equal(t, cfg.DeployConfig.FinalizationPeriodSeconds, finalizationPeriod.Uint64())
// Create a struct used to track our transactors and their transactions sent.
type TestAccountState struct {
Account *TestAccount
......@@ -439,11 +464,10 @@ func TestMixedWithdrawalValidity(t *testing.T) {
}
// Create a test account state for our transactor.
transactorKey := cfg.Secrets.Alice
transactor := &TestAccountState{
Account: &TestAccount{
HDPath: e2eutils.DefaultMnemonicConfig.Alice,
Key: transactorKey,
Key: cfg.Secrets.Alice,
L1Opts: nil,
L2Opts: nil,
},
......@@ -482,6 +506,9 @@ func TestMixedWithdrawalValidity(t *testing.T) {
// Determine the address our request will come from
fromAddr := crypto.PubkeyToAddress(transactor.Account.Key.PublicKey)
fromBalance, err := l2Verif.BalanceAt(context.Background(), fromAddr, nil)
require.NoError(t, err)
require.Greaterf(t, fromBalance.Uint64(), uint64(700_000_000_000), "insufficient balance for %s", fromAddr)
// Initiate Withdrawal
withdrawAmount := big.NewInt(500_000_000_000)
......@@ -489,9 +516,18 @@ func TestMixedWithdrawalValidity(t *testing.T) {
tx, err := l2l1MessagePasser.InitiateWithdrawal(transactor.Account.L2Opts, fromAddr, big.NewInt(21000), nil)
require.Nil(t, err, "sending initiate withdraw tx")
t.Logf("Waiting for tx %s to be in sequencer", tx.Hash().Hex())
receiptSeq, err := waitForTransaction(tx.Hash(), l2Seq, txTimeoutDuration)
require.Nil(t, err, "withdrawal initiated on L2 sequencer")
require.Equal(t, receiptSeq.Status, types.ReceiptStatusSuccessful, "transaction failed")
verifierTip, err := l2Verif.BlockByNumber(context.Background(), nil)
require.Nil(t, err)
t.Logf("Waiting for tx %s to be in verifier. Verifier tip is %s:%d. Included in sequencer in block %s:%d", tx.Hash().Hex(), verifierTip.Hash().Hex(), verifierTip.NumberU64(), receiptSeq.BlockHash.Hex(), receiptSeq.BlockNumber)
// Wait for the transaction to appear in L2 verifier
receipt, err := waitForTransaction(tx.Hash(), l2Verif, txTimeoutDuration)
require.Nil(t, err, "withdrawal initiated on L2 sequencer")
require.Nilf(t, err, "withdrawal tx %s not found in verifier. included in block %s:%d", tx.Hash().Hex(), receiptSeq.BlockHash.Hex(), receiptSeq.BlockNumber)
require.Equal(t, receipt.Status, types.ReceiptStatusSuccessful, "transaction failed")
// Obtain the header for the block containing the transaction (used to calculate gas fees)
......@@ -511,7 +547,8 @@ func TestMixedWithdrawalValidity(t *testing.T) {
// Wait for the finalization period, then we can finalize this withdrawal.
ctx, cancel = context.WithTimeout(context.Background(), 40*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
blockNumber, err := withdrawals.WaitForOutputRootPublished(ctx, l1Client, predeploys.DevOptimismPortalAddr, receipt.BlockNumber)
require.NotEqual(t, cfg.L1Deployments.L2OutputOracleProxy, common.Address{})
blockNumber, err := withdrawals.WaitForOutputRootPublished(ctx, l1Client, cfg.L1Deployments.L2OutputOracleProxy, receipt.BlockNumber)
cancel()
require.Nil(t, err)
......@@ -520,9 +557,6 @@ func TestMixedWithdrawalValidity(t *testing.T) {
cancel()
require.Nil(t, err)
l2OutputOracle, err := bindings.NewL2OutputOracleCaller(predeploys.DevL2OutputOracleAddr, l1Client)
require.Nil(t, err)
rpcClient, err := rpc.Dial(sys.Nodes["verifier"].WSEndpoint())
require.Nil(t, err)
proofCl := gethclient.New(rpcClient)
......@@ -642,7 +676,7 @@ func TestMixedWithdrawalValidity(t *testing.T) {
// Wait for finalization and then create the Finalized Withdrawal Transaction
ctx, cancel = context.WithTimeout(context.Background(), 45*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel()
err = withdrawals.WaitForFinalizationPeriod(ctx, l1Client, predeploys.DevOptimismPortalAddr, header.Number)
err = withdrawals.WaitForFinalizationPeriod(ctx, l1Client, cfg.L1Deployments.OptimismPortalProxy, header.Number)
require.Nil(t, err)
// Finalize withdrawal
......
......@@ -8,7 +8,7 @@ import (
"time"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
......@@ -24,8 +24,9 @@ import (
func SendDepositTx(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l2Client *ethclient.Client, l1Opts *bind.TransactOpts, applyL2Opts DepositTxOptsFn) {
l2Opts := defaultDepositTxOpts(l1Opts)
applyL2Opts(l2Opts)
// Find deposit contract
depositContract, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
depositContract, err := bindings.NewOptimismPortal(config.L1Deployments.OptimismPortalProxy, l1Client)
require.Nil(t, err)
// Finally send TX
......
......@@ -9,6 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-node/withdrawals"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
......@@ -88,7 +89,7 @@ func ProveWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client,
ctx, cancel := context.WithTimeout(context.Background(), 40*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel()
blockNumber, err := withdrawals.WaitForOutputRootPublished(ctx, l1Client, predeploys.DevOptimismPortalAddr, l2WithdrawalReceipt.BlockNumber)
blockNumber, err := withdrawals.WaitForOutputRootPublished(ctx, l1Client, config.L1Deployments.L2OutputOracleProxy, l2WithdrawalReceipt.BlockNumber)
require.Nil(t, err)
rpcClient, err := rpc.Dial(l2Node.WSEndpoint())
......@@ -103,13 +104,13 @@ func ProveWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client,
require.Nil(t, err)
// Now create withdrawal
oracle, err := bindings.NewL2OutputOracleCaller(predeploys.DevL2OutputOracleAddr, l1Client)
oracle, err := bindings.NewL2OutputOracleCaller(config.L1Deployments.L2OutputOracleProxy, l1Client)
require.Nil(t, err)
params, err := withdrawals.ProveWithdrawalParameters(context.Background(), proofCl, receiptCl, l2WithdrawalReceipt.TxHash, header, oracle)
require.Nil(t, err)
portal, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
portal, err := bindings.NewOptimismPortal(config.L1Deployments.OptimismPortalProxy, l1Client)
require.Nil(t, err)
opts, err := bind.NewKeyedTransactorWithChainID(ethPrivKey, cfg.L1ChainIDBig())
......@@ -143,12 +144,13 @@ func FinalizeWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Clie
// Wait for finalization and then create the Finalized Withdrawal Transaction
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel()
err := withdrawals.WaitForFinalizationPeriod(ctx, l1Client, predeploys.DevOptimismPortalAddr, withdrawalProofReceipt.BlockNumber)
err := withdrawals.WaitForFinalizationPeriod(ctx, l1Client, config.L1Deployments.OptimismPortalProxy, withdrawalProofReceipt.BlockNumber)
require.Nil(t, err)
opts, err := bind.NewKeyedTransactorWithChainID(privKey, cfg.L1ChainIDBig())
require.Nil(t, err)
portal, err := bindings.NewOptimismPortal(predeploys.DevOptimismPortalAddr, l1Client)
portal, err := bindings.NewOptimismPortal(config.L1Deployments.OptimismPortalProxy, l1Client)
require.Nil(t, err)
// Finalize withdrawal
tx, err := portal.FinalizeWithdrawalTransaction(
......
......@@ -11,6 +11,7 @@ import (
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
......@@ -22,24 +23,25 @@ import (
var Subcommands = cli.Commands{
{
Name: "devnet",
Usage: "Initialize new L1 and L2 genesis files and rollup config suitable for a local devnet",
Name: "l1",
Usage: "Generates a L1 genesis state file",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "deploy-config",
Usage: "Path to hardhat deploy config file",
Name: "deploy-config",
Usage: "Path to hardhat deploy config file",
Required: true,
},
&cli.StringFlag{
Name: "outfile.l1",
Usage: "Path to L1 genesis output file",
Name: "l1-allocs",
Usage: "Path to L1 genesis state dump",
},
&cli.StringFlag{
Name: "outfile.l2",
Usage: "Path to L2 genesis output file",
Name: "l1-deployments",
Usage: "Path to L1 deployments file",
},
&cli.StringFlag{
Name: "outfile.rollup",
Usage: "Path to rollup output file",
Name: "outfile.l1",
Usage: "Path to L1 genesis output file",
},
},
Action: func(ctx *cli.Context) error {
......@@ -49,39 +51,36 @@ var Subcommands = cli.Commands{
return err
}
// Add the developer L1 addresses to the config
if err := config.InitDeveloperDeployedAddresses(); err != nil {
return err
var deployments *genesis.L1Deployments
if l1Deployments := ctx.String("l1-deployments"); l1Deployments != "" {
deployments, err = genesis.NewL1Deployments(l1Deployments)
if err != nil {
return err
}
}
if err := config.Check(); err != nil {
return err
if deployments != nil {
config.SetDeployments(deployments)
}
l1Genesis, err := genesis.BuildL1DeveloperGenesis(config)
if err != nil {
return err
if err := config.Check(); err != nil {
return fmt.Errorf("deploy config at %s invalid: %w", deployConfig, err)
}
l1StartBlock := l1Genesis.ToBlock()
l2Genesis, err := genesis.BuildL2Genesis(config, l1StartBlock)
if err != nil {
return err
var dump *state.Dump
if l1Allocs := ctx.String("l1-allocs"); l1Allocs != "" {
dump, err = genesis.NewStateDump(l1Allocs)
if err != nil {
return err
}
}
l2GenesisBlock := l2Genesis.ToBlock()
rollupConfig, err := config.RollupConfig(l1StartBlock, l2GenesisBlock.Hash(), l2GenesisBlock.Number().Uint64())
l1Genesis, err := genesis.BuildL1DeveloperGenesis(config, dump, deployments, true)
if err != nil {
return err
}
if err := writeGenesisFile(ctx.String("outfile.l1"), l1Genesis); err != nil {
return err
}
if err := writeGenesisFile(ctx.String("outfile.l2"), l2Genesis); err != nil {
return err
}
return writeGenesisFile(ctx.String("outfile.rollup"), rollupConfig)
return writeGenesisFile(ctx.String("outfile.l1"), l1Genesis)
},
},
{
......@@ -161,10 +160,10 @@ var Subcommands = cli.Commands{
log.Info("Using L1 Start Block", "number", l1StartBlock.Number(), "hash", l1StartBlock.Hash().Hex())
// Build the developer L2 genesis block
// Build the L2 genesis block
l2Genesis, err := genesis.BuildL2Genesis(config, l1StartBlock)
if err != nil {
return fmt.Errorf("error creating l2 developer genesis: %w", err)
return fmt.Errorf("error creating l2 genesis: %w", err)
}
l2GenesisBlock := l2Genesis.ToBlock()
......
......@@ -403,6 +403,11 @@ func (s *EthClient) GetStorageAt(ctx context.Context, address common.Address, st
// ReadStorageAt is a convenience method to read a single storage value at the given slot in the given account.
// The storage slot value is verified against the state-root of the given block if we do not trust the RPC provider, or directly retrieved without proof if we do trust the RPC.
func (s *EthClient) ReadStorageAt(ctx context.Context, address common.Address, storageSlot common.Hash, blockHash common.Hash) (common.Hash, error) {
// TODO: temp
if true {
return s.GetStorageAt(ctx, address, storageSlot, blockHash.String())
}
if s.trustRPC {
return s.GetStorageAt(ctx, address, storageSlot, blockHash.String())
}
......
......@@ -26,11 +26,11 @@ var MessagePassedTopic = crypto.Keccak256Hash([]byte("MessagePassed(uint256,addr
// WaitForOutputRootPublished waits until there is an output published for an L2 block number larger than the supplied l2BlockNumber
// This function polls and can block for a very long time if used on mainnet.
// This returns the block number to use for proof generation.
func WaitForOutputRootPublished(ctx context.Context, client *ethclient.Client, portalAddr common.Address, l2BlockNumber *big.Int) (uint64, error) {
func WaitForOutputRootPublished(ctx context.Context, client *ethclient.Client, l2OutputOracleAddr common.Address, l2BlockNumber *big.Int) (uint64, error) {
l2BlockNumber = new(big.Int).Set(l2BlockNumber) // Don't clobber caller owned l2BlockNumber
opts := &bind.CallOpts{Context: ctx}
l2OO, err := createL2OOCaller(ctx, client, portalAddr)
l2OO, err := bindings.NewL2OutputOracleCaller(l2OutputOracleAddr, client)
if err != nil {
return 0, err
}
......
......@@ -132,6 +132,15 @@ services:
OP_BATCHER_METRICS_ENABLED: "true"
OP_BATCHER_RPC_ENABLE_ADMIN: "true"
artifact-server:
depends_on:
- l1
image: nginx:1.25-alpine
ports:
- "8080:80"
volumes:
- "${PWD}/../.devnet/:/usr/share/nginx/html/"
stateviz:
build:
context: ../
......
......@@ -7,8 +7,8 @@ GETH_CHAINDATA_DIR="$GETH_DATA_DIR/geth/chaindata"
GETH_KEYSTORE_DIR="$GETH_DATA_DIR/keystore"
GENESIS_FILE_PATH="${GENESIS_FILE_PATH:-/genesis.json}"
CHAIN_ID=$(cat "$GENESIS_FILE_PATH" | jq -r .config.chainId)
BLOCK_SIGNER_PRIVATE_KEY="3e4bde571b86929bf08e2aaad9a6a1882664cd5e65b96fff7d03e1c4e6dfa15c"
BLOCK_SIGNER_ADDRESS="0xca062b0fd91172d89bcd4bb084ac4e21972cc467"
BLOCK_SIGNER_PRIVATE_KEY="ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
BLOCK_SIGNER_ADDRESS="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
RPC_PORT="${RPC_PORT:-8545}"
WS_PORT="${WS_PORT:-8546}"
......
......@@ -25,3 +25,4 @@ deployments/901
deployments/hardhat
deployments/getting-started
deployments/*/.deploy
deployments/1337
{
"l1ChainID": 900,
"l2ChainID": 901,
"l1ChainID": 901,
"l2ChainID": 902,
"l2BlockTime": 2,
"maxSequencerDrift": 300,
"sequencerWindowSize": 200,
"channelTimeout": 120,
"p2pSequencerAddress": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc",
"batchInboxAddress": "0xff00000000000000000000000000000000000000",
"batchInboxAddress": "0xff00000000000000000000000000000000000901",
"batchSenderAddress": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC",
"l2OutputOracleSubmissionInterval": 20,
"l2OutputOracleStartingTimestamp": -1,
"cliqueSignerAddress": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
"l1UseClique": true,
"l1StartingBlockTag": "earliest",
"l2OutputOracleSubmissionInterval": 6,
"l2OutputOracleStartingTimestamp": 0,
"l2OutputOracleStartingBlockNumber": 0,
"l2OutputOracleProposer": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
"l2OutputOracleChallenger": "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65",
"l2GenesisBlockGasLimit": "0x1c9c380",
"l1BlockTime": 3,
"cliqueSignerAddress": "0xca062b0fd91172d89bcd4bb084ac4e21972cc467",
"baseFeeVaultRecipient": "0xBcd4042DE499D14e55001CcbB24a551F3b954096",
"l1FeeVaultRecipient": "0x71bE63f3384f5fb98995898A86B02Fb2426c5788",
"sequencerFeeVaultRecipient": "0xfabb0ac9d68b0b445fb7357272ff202c5651694a",
"baseFeeVaultRecipient": "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955",
"l1FeeVaultRecipient": "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f",
"sequencerFeeVaultRecipient": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720",
"baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
"l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
"sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
"baseFeeVaultWithdrawalNetwork": 0,
"l1FeeVaultWithdrawalNetwork": 0,
"sequencerFeeVaultWithdrawalNetwork": 0,
"proxyAdminOwner": "0xBcd4042DE499D14e55001CcbB24a551F3b954096",
"finalSystemOwner": "0xBcd4042DE499D14e55001CcbB24a551F3b954096",
"portalGuardian": "0xBcd4042DE499D14e55001CcbB24a551F3b954096",
"baseFeeVaultWithdrawalNetwork": "remote",
"l1FeeVaultWithdrawalNetwork": "remote",
"sequencerFeeVaultWithdrawalNetwork": "remote",
"proxyAdminOwner": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720",
"finalSystemOwner": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720",
"portalGuardian": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720",
"finalizationPeriodSeconds": 2,
"deploymentWaitConfirmations": 1,
"fundDevAccounts": true,
"l2GenesisBlockBaseFeePerGas": "0x3B9ACA00",
"l2GenesisBlockBaseFeePerGas": "0x1",
"gasPriceOracleOverhead": 2100,
"gasPriceOracleScalar": 1000000,
"enableGovernance": true,
"governanceTokenSymbol": "OP",
"governanceTokenName": "Optimism",
"governanceTokenOwner": "0xBcd4042DE499D14e55001CcbB24a551F3b954096",
"eip1559Denominator": 8,
"eip1559Elasticity": 2,
"l1GenesisBlockTimestamp": "0x64935846",
"l1StartingBlockTag": "earliest",
"governanceTokenOwner": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720",
"eip1559Denominator": 50,
"eip1559Elasticity": 6,
"l1GenesisBlockTimestamp": "0x64c811bf",
"l2GenesisRegolithTimeOffset": "0x0",
"faultGameAbsolutePrestate": 96,
"faultGameMaxDepth": 4,
"faultGameMaxDuration": 120
}
}
\ No newline at end of file
......@@ -246,7 +246,7 @@ contract Deploy is Deployer {
/// @notice Deploy the DisputeGameFactoryProxy
function deployDisputeGameFactoryProxy() broadcast() public returns (address) {
if (block.chainid == 900) {
if (block.chainid == 901 || block.chainid == 1337) {
address proxyAdmin = mustGetAddress("ProxyAdmin");
Proxy proxy = new Proxy({
_admin: proxyAdmin
......@@ -347,7 +347,7 @@ contract Deploy is Deployer {
/// @notice Deploy the DisputeGameFactory
function deployDisputeGameFactory() broadcast() public returns (address) {
if (block.chainid == 900) {
if (block.chainid == 901 || block.chainid == 1337) {
DisputeGameFactory factory = new DisputeGameFactory();
save("DisputeGameFactory", address(factory));
console.log("DisputeGameFactory deployed at %s", address(factory));
......@@ -442,7 +442,7 @@ contract Deploy is Deployer {
/// @notice Initialize the DisputeGameFactory
function initializeDisputeGameFactory() broadcast() public {
if (block.chainid == 900) {
if (block.chainid == 901 || block.chainid == 1337) {
ProxyAdmin proxyAdmin = ProxyAdmin(mustGetAddress("ProxyAdmin"));
address disputeGameFactoryProxy = mustGetAddress("DisputeGameFactoryProxy");
address disputeGameFactory = mustGetAddress("DisputeGameFactory");
......@@ -676,7 +676,7 @@ contract Deploy is Deployer {
/// @notice Transfer ownership of the DisputeGameFactory contract to the final system owner
function transferDisputeGameFactoryOwnership() broadcast() public {
if (block.chainid == 900) {
if (block.chainid == 901 || block.chainid == 1337) {
DisputeGameFactory disputeGameFactory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
address owner = disputeGameFactory.owner();
address finalSystemOwner = cfg.finalSystemOwner();
......@@ -689,7 +689,7 @@ contract Deploy is Deployer {
/// @notice Sets the implementation for the `FAULT` game type in the `DisputeGameFactory`
function setFaultGameImplementation() broadcast() public {
if (block.chainid == 900) {
if (block.chainid == 901 || block.chainid == 1337) {
DisputeGameFactory factory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
Claim absolutePrestate = Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate()));
IBigStepper faultVm = IBigStepper(new AlphabetVM(absolutePrestate));
......
......@@ -87,7 +87,7 @@ contract DeployConfig is Script {
eip1559Denominator = stdJson.readUint(_json, "$.eip1559Denominator");
eip1559Elasticity = stdJson.readUint(_json, "$.eip1559Elasticity");
if (block.chainid == 900) {
if (block.chainid == 901 || block.chainid == 1337) {
faultGameAbsolutePrestate = stdJson.readUint(_json, "$.faultGameAbsolutePrestate");
faultGameMaxDepth = stdJson.readUint(_json, "$.faultGameMaxDepth");
faultGameMaxDuration = stdJson.readUint(_json, "$.faultGameMaxDuration");
......
......@@ -71,19 +71,21 @@ abstract contract Deployer is Script {
deploymentContext = _getDeploymentContext();
string memory deployFile = vm.envOr("DEPLOY_FILE", string("run-latest.json"));
deployPath = string.concat(root, "/broadcast/", deployScript, ".s.sol/", vm.toString(block.chainid), "/", deployFile);
uint256 chainId = vm.envOr("CHAIN_ID", block.chainid);
deployPath = string.concat(root, "/broadcast/", deployScript, ".s.sol/", vm.toString(chainId), "/", deployFile);
deploymentsDir = string.concat(root, "/deployments/", deploymentContext);
try vm.createDir(deploymentsDir, true) {} catch (bytes memory) {}
string memory chainIdPath = string.concat(deploymentsDir, "/.chainId");
try vm.readFile(chainIdPath) returns (string memory chainid) {
uint256 chainId = vm.parseUint(chainid);
require(chainId == block.chainid, "Misconfigured networks");
try vm.readFile(chainIdPath) returns (string memory localChainId) {
if (vm.envOr("STRICT_DEPLOYMENT", true)) {
require(vm.parseUint(localChainId) == chainId, "Misconfigured networks");
}
} catch {
vm.writeFile(chainIdPath, vm.toString(block.chainid));
vm.writeFile(chainIdPath, vm.toString(chainId));
}
console.log("Connected to network with chainid %s", block.chainid);
console.log("Connected to network with chainid %s", chainId);
tempDeploymentsPath = string.concat(deploymentsDir, "/.deploy");
try vm.readFile(tempDeploymentsPath) returns (string memory) {} catch {
......@@ -432,7 +434,7 @@ abstract contract Deployer is Script {
return context;
}
uint256 chainid = block.chainid;
uint256 chainid = vm.envOr("CHAIN_ID", block.chainid);
if (chainid == 1) {
return "mainnet";
} else if (chainid == 5) {
......@@ -441,7 +443,7 @@ abstract contract Deployer is Script {
return "optimism-goerli";
} else if (chainid == 10) {
return "optimism-mainnet";
} else if (chainid == 900) {
} else if (chainid == 901 || chainid == 1337) {
return "devnetL1";
} else if (chainid == 31337) {
return "hardhat";
......
......@@ -16,7 +16,7 @@ export enum L1ChainID {
MAINNET = 1,
GOERLI = 5,
HARDHAT_LOCAL = 31337,
BEDROCK_LOCAL_DEVNET = 900,
BEDROCK_LOCAL_DEVNET = 901,
}
/**
......@@ -27,7 +27,6 @@ export enum L2ChainID {
OPTIMISM_GOERLI = 420,
OPTIMISM_HARDHAT_LOCAL = 31337,
OPTIMISM_HARDHAT_DEVNET = 17,
OPTIMISM_BEDROCK_LOCAL_DEVNET = 901,
OPTIMISM_BEDROCK_ALPHA_TESTNET = 28528,
BASE_GOERLI = 84531,
BASE_MAINNET = 8453,
......
......@@ -69,7 +69,6 @@ export const DEPOSIT_CONFIRMATION_BLOCKS: {
[L2ChainID.OPTIMISM_GOERLI]: 12 as const,
[L2ChainID.OPTIMISM_HARDHAT_LOCAL]: 2 as const,
[L2ChainID.OPTIMISM_HARDHAT_DEVNET]: 2 as const,
[L2ChainID.OPTIMISM_BEDROCK_LOCAL_DEVNET]: 2 as const,
[L2ChainID.OPTIMISM_BEDROCK_ALPHA_TESTNET]: 12 as const,
[L2ChainID.BASE_GOERLI]: 12 as const,
[L2ChainID.BASE_MAINNET]: 50 as const,
......@@ -171,22 +170,6 @@ export const CONTRACT_ADDRESSES: {
},
l2: DEFAULT_L2_CONTRACT_ADDRESSES,
},
[L2ChainID.OPTIMISM_BEDROCK_LOCAL_DEVNET]: {
l1: {
AddressManager: '0x6900000000000000000000000000000000000005' as const,
L1CrossDomainMessenger:
'0x6900000000000000000000000000000000000002' as const,
L1StandardBridge: '0x6900000000000000000000000000000000000003' as const,
StateCommitmentChain:
'0x0000000000000000000000000000000000000000' as const,
CanonicalTransactionChain:
'0x0000000000000000000000000000000000000000' as const,
BondManager: '0x0000000000000000000000000000000000000000' as const,
OptimismPortal: '0x6900000000000000000000000000000000000001' as const,
L2OutputOracle: '0x6900000000000000000000000000000000000000' as const,
},
l2: DEFAULT_L2_CONTRACT_ADDRESSES,
},
[L2ChainID.OPTIMISM_BEDROCK_ALPHA_TESTNET]: {
l1: {
AddressManager: '0xb4e08DcE1F323608229265c9d4125E22a4B9dbAF' as const,
......
......@@ -4,7 +4,7 @@ import { task, types } from 'hardhat/config'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { Event, Contract, Wallet, providers, utils } from 'ethers'
import { Event, Contract, Wallet, providers, utils, ethers } from 'ethers'
import { predeploys, sleep } from '@eth-optimism/core-utils'
import Artifact__WETH9 from '@eth-optimism/contracts-bedrock/forge-artifacts/WETH9.sol/WETH9.json'
import Artifact__OptimismMintableERC20TokenFactory from '@eth-optimism/contracts-bedrock/forge-artifacts/OptimismMintableERC20Factory.sol/OptimismMintableERC20Factory.json'
......@@ -15,6 +15,7 @@ import Artifact__L2StandardBridge from '@eth-optimism/contracts-bedrock/forge-ar
import Artifact__OptimismPortal from '@eth-optimism/contracts-bedrock/forge-artifacts/OptimismPortal.sol/OptimismPortal.json'
import Artifact__L1CrossDomainMessenger from '@eth-optimism/contracts-bedrock/forge-artifacts/L1CrossDomainMessenger.sol/L1CrossDomainMessenger.json'
import Artifact__L1StandardBridge from '@eth-optimism/contracts-bedrock/forge-artifacts/L1StandardBridge.sol/L1StandardBridge.json'
import Artifact__L2OutputOracle from '@eth-optimism/contracts-bedrock/forge-artifacts/L2OutputOracle.sol/L2OutputOracle.json'
import {
CrossChainMessenger,
......@@ -144,30 +145,51 @@ task('deposit-erc20', 'Deposits WETH9 onto L2.')
let contractAddrs = CONTRACT_ADDRESSES[l2ChainId]
if (args.l1ContractsJsonPath) {
const data = await fs.readFile(args.l1ContractsJsonPath)
const json = JSON.parse(data.toString())
contractAddrs = {
l1: JSON.parse(data.toString()),
l1: {
AddressManager: json.AddressManager,
L1CrossDomainMessenger: json.L1CrossDomainMessengerProxy,
L1StandardBridge: json.L1StandardBridgeProxy,
StateCommitmentChain: ethers.constants.AddressZero,
CanonicalTransactionChain: ethers.constants.AddressZero,
BondManager: ethers.constants.AddressZero,
OptimismPortal: json.OptimismPortalProxy,
L2OutputOracle: json.L2OutputOracleProxy,
},
l2: DEFAULT_L2_CONTRACT_ADDRESSES,
} as OEContractsLike
}
console.log(`OptimismPortal: ${contractAddrs.l1.OptimismPortal}`)
const OptimismPortal = new hre.ethers.Contract(
contractAddrs.l1.OptimismPortal,
Artifact__OptimismPortal.abi,
signer
)
console.log(
`L1CrossDomainMessenger: ${contractAddrs.l1.L1CrossDomainMessenger}`
)
const L1CrossDomainMessenger = new hre.ethers.Contract(
contractAddrs.l1.L1CrossDomainMessenger,
Artifact__L1CrossDomainMessenger.abi,
signer
)
console.log(`L1StandardBridge: ${contractAddrs.l1.L1StandardBridge}`)
const L1StandardBridge = new hre.ethers.Contract(
contractAddrs.l1.L1StandardBridge,
Artifact__L1StandardBridge.abi,
signer
)
const L2OutputOracle = new hre.ethers.Contract(
contractAddrs.l1.L2OutputOracle,
Artifact__L2OutputOracle.abi,
signer
)
const L2ToL1MessagePasser = new hre.ethers.Contract(
predeploys.L2ToL1MessagePasser,
Artifact__L2ToL1MessagePasser.abi
......@@ -192,6 +214,10 @@ task('deposit-erc20', 'Deposits WETH9 onto L2.')
contracts: contractAddrs,
})
const params = await OptimismPortal.params()
console.log('Intial OptimismPortal.params:')
console.log(params)
console.log('Deploying WETH9 to L1')
const WETH9 = await deployWETH9(hre, true)
console.log(`Deployed to ${WETH9.address}`)
......@@ -221,33 +247,37 @@ task('deposit-erc20', 'Deposits WETH9 onto L2.')
await depositTx.wait()
console.log(`ERC20 deposited - ${depositTx.hash}`)
// Deposit might get reorged, wait 30s and also log for reorgs.
console.log('Checking to make sure deposit was successful')
// Deposit might get reorged, wait and also log for reorgs.
let prevBlockHash: string = ''
for (let i = 0; i < 30; i++) {
const messageReceipt = await messenger.waitForMessageReceipt(depositTx)
if (messageReceipt.receiptStatus !== 1) {
for (let i = 0; i < 12; i++) {
const messageReceipt = await signer.provider!.getTransactionReceipt(
depositTx.hash
)
if (messageReceipt.status !== 1) {
console.log(`Deposit failed, retrying...`)
}
if (
prevBlockHash !== '' &&
messageReceipt.transactionReceipt.blockHash !== prevBlockHash
) {
// Wait for stability, we want some amount of time after any reorg
if (prevBlockHash !== '' && messageReceipt.blockHash !== prevBlockHash) {
console.log(
`Block hash changed from ${prevBlockHash} to ${messageReceipt.transactionReceipt.blockHash}`
`Block hash changed from ${prevBlockHash} to ${messageReceipt.blockHash}`
)
// Wait for stability, we want at least 30 seconds after any reorg
i = 0
} else if (prevBlockHash !== '') {
console.log(`No reorg detected: ${i}`)
}
prevBlockHash = messageReceipt.transactionReceipt.blockHash
prevBlockHash = messageReceipt.blockHash
await sleep(1000)
}
console.log(`Deposit confirmed`)
const l2Balance = await OptimismMintableERC20.balanceOf(address)
if (l2Balance.lt(utils.parseEther('1'))) {
throw new Error('bad deposit')
throw new Error(
`bad deposit. recipient balance on L2: ${utils.formatEther(l2Balance)}`
)
}
console.log(`Deposit success`)
......@@ -291,6 +321,8 @@ task('deposit-erc20', 'Deposits WETH9 onto L2.')
setInterval(async () => {
const currentStatus = await messenger.getMessageStatus(withdraw)
console.log(`Message status: ${MessageStatus[currentStatus]}`)
const latest = await L2OutputOracle.latestBlockNumber()
console.log(`Latest L2OutputOracle commitment number: ${latest.toString()}`)
}, 3000)
const now = Math.floor(Date.now() / 1000)
......
......@@ -12,6 +12,7 @@ import Artifact__L2StandardBridge from '@eth-optimism/contracts-bedrock/forge-ar
import Artifact__OptimismPortal from '@eth-optimism/contracts-bedrock/forge-artifacts/OptimismPortal.sol/OptimismPortal.json'
import Artifact__L1CrossDomainMessenger from '@eth-optimism/contracts-bedrock/forge-artifacts/L1CrossDomainMessenger.sol/L1CrossDomainMessenger.json'
import Artifact__L1StandardBridge from '@eth-optimism/contracts-bedrock/forge-artifacts/L1StandardBridge.sol/L1StandardBridge.json'
import Artifact__L2OutputOracle from '@eth-optimism/contracts-bedrock/forge-artifacts/L2OutputOracle.sol/L2OutputOracle.json'
import {
CrossChainMessenger,
......@@ -88,8 +89,18 @@ task('deposit-eth', 'Deposits ether to L2.')
let contractAddrs = CONTRACT_ADDRESSES[l2ChainId]
if (args.l1ContractsJsonPath) {
const data = await fs.readFile(args.l1ContractsJsonPath)
const json = JSON.parse(data.toString())
contractAddrs = {
l1: JSON.parse(data.toString()),
l1: {
AddressManager: json.AddressManager,
L1CrossDomainMessenger: json.L1CrossDomainMessengerProxy,
L1StandardBridge: json.L1StandardBridgeProxy,
StateCommitmentChain: ethers.constants.AddressZero,
CanonicalTransactionChain: ethers.constants.AddressZero,
BondManager: ethers.constants.AddressZero,
OptimismPortal: json.OptimismPortalProxy,
L2OutputOracle: json.L2OutputOracleProxy,
},
l2: DEFAULT_L2_CONTRACT_ADDRESSES,
} as OEContractsLike
} else if (!contractAddrs) {
......@@ -145,24 +156,36 @@ task('deposit-eth', 'Deposits ether to L2.')
}
}
console.log(`OptimismPortal: ${contractAddrs.l1.OptimismPortal}`)
const OptimismPortal = new hre.ethers.Contract(
contractAddrs.l1.OptimismPortal,
Artifact__OptimismPortal.abi,
signer
)
console.log(
`L1CrossDomainMessenger: ${contractAddrs.l1.L1CrossDomainMessenger}`
)
const L1CrossDomainMessenger = new hre.ethers.Contract(
contractAddrs.l1.L1CrossDomainMessenger,
Artifact__L1CrossDomainMessenger.abi,
signer
)
console.log(`L1StandardBridge: ${contractAddrs.l1.L1StandardBridge}`)
const L1StandardBridge = new hre.ethers.Contract(
contractAddrs.l1.L1StandardBridge,
Artifact__L1StandardBridge.abi,
signer
)
console.log(`L2OutputOracle: ${contractAddrs.l1.L2OutputOracle}`)
const L2OutputOracle = new hre.ethers.Contract(
contractAddrs.l1.L2OutputOracle,
Artifact__L2OutputOracle.abi,
signer
)
const L2ToL1MessagePasser = new hre.ethers.Contract(
predeploys.L2ToL1MessagePasser,
Artifact__L2ToL1MessagePasser.abi
......@@ -187,11 +210,11 @@ task('deposit-eth', 'Deposits ether to L2.')
contracts: contractAddrs,
})
const opBalanceBefore = await signer.provider.getBalance(
const opBalanceBefore = await signer!.provider!.getBalance(
OptimismPortal.address
)
const l1BridgeBalanceBefore = await signer.provider.getBalance(
const l1BridgeBalanceBefore = await signer!.provider!.getBalance(
L1StandardBridge.address
)
......@@ -210,11 +233,11 @@ task('deposit-eth', 'Deposits ether to L2.')
`Deposit complete - included in block ${depositMessageReceipt.transactionReceipt.blockNumber}`
)
const opBalanceAfter = await signer.provider.getBalance(
const opBalanceAfter = await signer!.provider!.getBalance(
OptimismPortal.address
)
const l1BridgeBalanceAfter = await signer.provider.getBalance(
const l1BridgeBalanceAfter = await signer!.provider!.getBalance(
L1StandardBridge.address
)
......@@ -291,6 +314,8 @@ task('deposit-eth', 'Deposits ether to L2.')
const proveInterval = setInterval(async () => {
const currentStatus = await messenger.getMessageStatus(ethWithdrawReceipt)
console.log(`Message status: ${MessageStatus[currentStatus]}`)
const latest = await L2OutputOracle.latestBlockNumber()
console.log(`Latest L2OutputOracle commitment number: ${latest.toString()}`)
}, 3000)
try {
......@@ -394,7 +419,7 @@ task('deposit-eth', 'Deposits ether to L2.')
}
}
const opBalanceFinally = await signer.provider.getBalance(
const opBalanceFinally = await signer!.provider!.getBalance(
OptimismPortal.address
)
......
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