Commit c72a75e8 authored by protolambda's avatar protolambda Committed by GitHub

op-e2e: Organize e2e system tests in subdirs (#11939)

* op-e2e: organize system tests

* op-e2e: update CI make targets

* op-e2e: fix artifacts file paths

* op-e2e: Fix paths.

* op-e2e: Fix paths again

---------
Co-authored-by: default avatarAdrian Sutton <adrian@oplabs.co>
parent 4e2fdf37
...@@ -17,7 +17,7 @@ test-external-%: pre-test ...@@ -17,7 +17,7 @@ test-external-%: pre-test
$(go_test) $(go_test_flags) --externalL2 ./external_$*/ $(go_test) $(go_test_flags) --externalL2 ./external_$*/
test-ws: pre-test test-ws: pre-test
$(go_test) $(go_test_flags) . ./e2eutils/... $(go_test) $(go_test_flags) ./system/... ./e2eutils/... ./opgeth/... ./interop/...
.PHONY: test-ws .PHONY: test-ws
test-actions: pre-test test-actions: pre-test
...@@ -25,7 +25,7 @@ test-actions: pre-test ...@@ -25,7 +25,7 @@ test-actions: pre-test
.PHONY: test-actions .PHONY: test-actions
test-http: pre-test test-http: pre-test
OP_E2E_USE_HTTP=true $(go_test) $(go_test_flags) . ./e2eutils/... OP_E2E_USE_HTTP=true $(go_test) $(go_test_flags) ./system/... ./e2eutils/... ./opgeth/... ./interop/...
.PHONY: test-http .PHONY: test-http
test-cannon: pre-test test-cannon: pre-test
...@@ -71,7 +71,7 @@ clean: ...@@ -71,7 +71,7 @@ clean:
.PHONY: clean .PHONY: clean
fuzz: fuzz:
go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFjordCostFunction ./ go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFjordCostFunction ./opgeth
go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFastLzGethSolidity ./ go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFastLzGethSolidity ./opgeth
go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFastLzCgo ./ go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFastLzCgo ./opgeth
...@@ -24,10 +24,10 @@ import ( ...@@ -24,10 +24,10 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
e2e "github.com/ethereum-optimism/optimism/op-e2e"
legacybindings "github.com/ethereum-optimism/optimism/op-e2e/bindings" legacybindings "github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/config" "github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
e2ehelpers "github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-node/bindings" "github.com/ethereum-optimism/optimism/op-node/bindings"
bindingspreview "github.com/ethereum-optimism/optimism/op-node/bindings/preview" bindingspreview "github.com/ethereum-optimism/optimism/op-node/bindings/preview"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/rollup/derive"
...@@ -449,7 +449,7 @@ func (s *CrossLayerUser) getLatestWithdrawalParams(t Testing) (*withdrawals.Prov ...@@ -449,7 +449,7 @@ func (s *CrossLayerUser) getLatestWithdrawalParams(t Testing) (*withdrawals.Prov
header, err := s.L2.env.EthCl.HeaderByNumber(t.Ctx(), l2OutputBlockNr) header, err := s.L2.env.EthCl.HeaderByNumber(t.Ctx(), l2OutputBlockNr)
require.NoError(t, err) require.NoError(t, err)
params, err := e2e.ProveWithdrawalParameters(t.Ctx(), s.L2.env.Bindings.ProofClient, s.L2.env.EthCl, s.L2.env.EthCl, s.lastL2WithdrawalTxHash, header, &s.L1.env.Bindings.L2OutputOracle.L2OutputOracleCaller, &s.L1.env.Bindings.DisputeGameFactory.DisputeGameFactoryCaller, &s.L1.env.Bindings.OptimismPortal2.OptimismPortal2Caller) params, err := e2ehelpers.ProveWithdrawalParameters(t.Ctx(), s.L2.env.Bindings.ProofClient, s.L2.env.EthCl, s.L2.env.EthCl, s.lastL2WithdrawalTxHash, header, &s.L1.env.Bindings.L2OutputOracle.L2OutputOracleCaller, &s.L1.env.Bindings.DisputeGameFactory.DisputeGameFactoryCaller, &s.L1.env.Bindings.OptimismPortal2.OptimismPortal2Caller)
require.NoError(t, err) require.NoError(t, err)
return &params, nil return &params, nil
......
...@@ -6,11 +6,11 @@ import ( ...@@ -6,11 +6,11 @@ import (
"testing" "testing"
"time" "time"
e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-e2e/system/bridge"
"github.com/ethereum-optimism/optimism/op-service/testlog"
) )
func TestDevnet(t *testing.T) { func TestDevnet(t *testing.T) {
...@@ -29,7 +29,7 @@ func TestDevnet(t *testing.T) { ...@@ -29,7 +29,7 @@ func TestDevnet(t *testing.T) {
}) })
t.Run("Withdrawal", func(t *testing.T) { t.Run("Withdrawal", func(t *testing.T) {
t.Parallel() t.Parallel()
e2e.RunWithdrawalsTest(t, sys) bridge.RunWithdrawalsTest(t, sys)
}) })
} }
......
...@@ -6,8 +6,9 @@ import ( ...@@ -6,8 +6,9 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/config" "github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
op_service "github.com/ethereum-optimism/optimism/op-service" op_service "github.com/ethereum-optimism/optimism/op-service"
...@@ -29,7 +30,7 @@ type System struct { ...@@ -29,7 +30,7 @@ type System struct {
L1 *ethclient.Client L1 *ethclient.Client
L2 *ethclient.Client L2 *ethclient.Client
Rollup *sources.RollupClient Rollup *sources.RollupClient
Cfg e2e.SystemConfig Cfg e2esys.SystemConfig
} }
func NewSystem(ctx context.Context, lgr log.Logger) (sys *System, err error) { func NewSystem(ctx context.Context, lgr log.Logger) (sys *System, err error) {
...@@ -69,7 +70,7 @@ func NewSystem(ctx context.Context, lgr log.Logger) (sys *System, err error) { ...@@ -69,7 +70,7 @@ func NewSystem(ctx context.Context, lgr log.Logger) (sys *System, err error) {
} }
// Incomplete SystemConfig suffices for withdrawal test (only consumer right now) // Incomplete SystemConfig suffices for withdrawal test (only consumer right now)
sys.Cfg = e2e.SystemConfig{ sys.Cfg = e2esys.SystemConfig{
DeployConfig: deployConfig, DeployConfig: deployConfig,
L1Deployments: config.L1Deployments.Copy(), L1Deployments: config.L1Deployments.Copy(),
Secrets: secrets, Secrets: secrets,
...@@ -79,9 +80,9 @@ func NewSystem(ctx context.Context, lgr log.Logger) (sys *System, err error) { ...@@ -79,9 +80,9 @@ func NewSystem(ctx context.Context, lgr log.Logger) (sys *System, err error) {
func (s System) NodeClient(role string) *ethclient.Client { func (s System) NodeClient(role string) *ethclient.Client {
switch role { switch role {
case e2e.RoleL1: case e2esys.RoleL1:
return s.L1 return s.L1
case e2e.RoleSeq, e2e.RoleVerif: case e2esys.RoleSeq, e2esys.RoleVerif:
// we have only one L2 node // we have only one L2 node
return s.L2 return s.L2
default: default:
...@@ -94,7 +95,7 @@ func (s System) RollupClient(string) *sources.RollupClient { ...@@ -94,7 +95,7 @@ func (s System) RollupClient(string) *sources.RollupClient {
return s.Rollup return s.Rollup
} }
func (s System) Config() e2e.SystemConfig { func (s System) Config() e2esys.SystemConfig {
return s.Cfg return s.Cfg
} }
......
...@@ -2,13 +2,33 @@ package op_e2e ...@@ -2,13 +2,33 @@ package op_e2e
import ( import (
"crypto/md5" "crypto/md5"
"fmt"
"os" "os"
"runtime"
"strconv" "strconv"
"strings" "strings"
"testing"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
) )
func RunMain(m *testing.M) {
if config.ExternalL2Shim != "" {
fmt.Println("Running tests with external L2 process adapter at ", config.ExternalL2Shim)
// As these are integration tests which launch many other processes, the
// default parallelism makes the tests flaky. This change aims to
// reduce the flakiness of these tests.
maxProcs := runtime.NumCPU() / 4
if maxProcs == 0 {
maxProcs = 1
}
runtime.GOMAXPROCS(maxProcs)
}
os.Exit(m.Run())
}
var enableParallelTesting bool = os.Getenv("OP_E2E_DISABLE_PARALLEL") != "true" var enableParallelTesting bool = os.Getenv("OP_E2E_DISABLE_PARALLEL") != "true"
func InitParallel(t e2eutils.TestingBase, args ...func(t e2eutils.TestingBase)) { func InitParallel(t e2eutils.TestingBase, args ...func(t e2eutils.TestingBase)) {
......
package op_e2e package opnode
import ( import (
"context" "context"
......
...@@ -9,9 +9,10 @@ import ( ...@@ -9,9 +9,10 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/config" "github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-service/endpoint" "github.com/ethereum-optimism/optimism/op-service/endpoint"
) )
...@@ -37,7 +38,7 @@ func TestShim(t *testing.T) { ...@@ -37,7 +38,7 @@ func TestShim(t *testing.T) {
config.EthNodeVerbosity = config.LegacyLevelDebug config.EthNodeVerbosity = config.LegacyLevelDebug
ec := (&e2e.ExternalRunner{ ec := (&e2esys.ExternalRunner{
Name: "TestShim", Name: "TestShim",
BinPath: shimPath, BinPath: shimPath,
}).Run(t) }).Run(t)
......
...@@ -11,6 +11,9 @@ import ( ...@@ -11,6 +11,9 @@ import (
"testing" "testing"
"time" "time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
...@@ -23,7 +26,6 @@ import ( ...@@ -23,7 +26,6 @@ import (
"github.com/ethereum-optimism/optimism/cannon/mipsevm" "github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/predeploys"
...@@ -35,7 +37,7 @@ func TestBenchmarkCannon_FPP(t *testing.T) { ...@@ -35,7 +37,7 @@ func TestBenchmarkCannon_FPP(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon) op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background() ctx := context.Background()
cfg := op_e2e.DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
// We don't need a verifier - just the sequencer is enough // We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier") delete(cfg.Nodes, "verifier")
// Use a small sequencer window size to avoid test timeout while waiting for empty blocks // Use a small sequencer window size to avoid test timeout while waiting for empty blocks
...@@ -102,7 +104,7 @@ func TestBenchmarkCannon_FPP(t *testing.T) { ...@@ -102,7 +104,7 @@ func TestBenchmarkCannon_FPP(t *testing.T) {
// TODO(client-pod#906): Use maximum witness size for assertions against pages allocated by the VM // TODO(client-pod#906): Use maximum witness size for assertions against pages allocated by the VM
} }
func createBigContracts(ctx context.Context, t *testing.T, cfg op_e2e.SystemConfig, client *ethclient.Client, key *ecdsa.PrivateKey, numContracts int) []common.Address { func createBigContracts(ctx context.Context, t *testing.T, cfg e2esys.SystemConfig, client *ethclient.Client, key *ecdsa.PrivateKey, numContracts int) []common.Address {
/* /*
contract Big { contract Big {
bytes constant foo = hex"<24.4 KB of random data>"; bytes constant foo = hex"<24.4 KB of random data>";
...@@ -162,7 +164,7 @@ func createBigContracts(ctx context.Context, t *testing.T, cfg op_e2e.SystemConf ...@@ -162,7 +164,7 @@ func createBigContracts(ctx context.Context, t *testing.T, cfg op_e2e.SystemConf
return addrs return addrs
} }
func callBigContracts(ctx context.Context, t *testing.T, cfg op_e2e.SystemConfig, client *ethclient.Client, key *ecdsa.PrivateKey, addrs []common.Address) *types.Receipt { func callBigContracts(ctx context.Context, t *testing.T, cfg e2esys.SystemConfig, client *ethclient.Client, key *ecdsa.PrivateKey, addrs []common.Address) *types.Receipt {
multicall3, err := bindings.NewMultiCall3(predeploys.MultiCall3Addr, client) multicall3, err := bindings.NewMultiCall3(predeploys.MultiCall3Addr, client)
require.NoError(t, err) require.NoError(t, err)
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"testing" "testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e" op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame/preimage" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame/preimage"
......
...@@ -5,6 +5,7 @@ import ( ...@@ -5,6 +5,7 @@ import (
"testing" "testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e" op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
......
...@@ -6,8 +6,9 @@ import ( ...@@ -6,8 +6,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum-optimism/optimism/op-challenger/game/types"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e" op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
......
...@@ -5,10 +5,11 @@ import ( ...@@ -5,10 +5,11 @@ import (
"fmt" "fmt"
"testing" "testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types" gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame/preimage" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame/preimage"
......
...@@ -7,6 +7,10 @@ import ( ...@@ -7,6 +7,10 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/versions" "github.com/ethereum-optimism/optimism/cannon/mipsevm/versions"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
...@@ -19,7 +23,6 @@ import ( ...@@ -19,7 +23,6 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/vm" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/vm"
"github.com/ethereum-optimism/optimism/op-challenger/metrics" "github.com/ethereum-optimism/optimism/op-challenger/metrics"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
...@@ -75,7 +78,7 @@ func TestPrecompiles(t *testing.T) { ...@@ -75,7 +78,7 @@ func TestPrecompiles(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon) op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background() ctx := context.Background()
genesisTime := hexutil.Uint64(0) genesisTime := hexutil.Uint64(0)
cfg := op_e2e.EcotoneSystemConfig(t, &genesisTime) cfg := e2esys.EcotoneSystemConfig(t, &genesisTime)
// We don't need a verifier - just the sequencer is enough // We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier") delete(cfg.Nodes, "verifier")
// Use a small sequencer window size to avoid test timeout while waiting for empty blocks // Use a small sequencer window size to avoid test timeout while waiting for empty blocks
...@@ -101,7 +104,7 @@ func TestPrecompiles(t *testing.T) { ...@@ -101,7 +104,7 @@ func TestPrecompiles(t *testing.T) {
l2Head := agreedL2Output.BlockRef.Hash l2Head := agreedL2Output.BlockRef.Hash
l2OutputRoot := agreedL2Output.OutputRoot l2OutputRoot := agreedL2Output.OutputRoot
receipt := op_e2e.SendL2Tx(t, cfg, l2Seq, aliceKey, func(opts *op_e2e.TxOpts) { receipt := helpers.SendL2Tx(t, cfg, l2Seq, aliceKey, func(opts *helpers.TxOpts) {
opts.Gas = 1_000_000 opts.Gas = 1_000_000
opts.ToAddr = &test.address opts.ToAddr = &test.address
opts.Nonce = 0 opts.Nonce = 0
...@@ -140,7 +143,7 @@ func TestPrecompiles(t *testing.T) { ...@@ -140,7 +143,7 @@ func TestPrecompiles(t *testing.T) {
l2Seq := sys.NodeClient("sequencer") l2Seq := sys.NodeClient("sequencer")
aliceKey := sys.Cfg.Secrets.Alice aliceKey := sys.Cfg.Secrets.Alice
receipt := op_e2e.SendL2Tx(t, sys.Cfg, l2Seq, aliceKey, func(opts *op_e2e.TxOpts) { receipt := helpers.SendL2Tx(t, sys.Cfg, l2Seq, aliceKey, func(opts *helpers.TxOpts) {
opts.Gas = 1_000_000 opts.Gas = 1_000_000
opts.ToAddr = &test.address opts.ToAddr = &test.address
opts.Nonce = 0 opts.Nonce = 0
...@@ -174,7 +177,7 @@ func TestGranitePrecompiles(t *testing.T) { ...@@ -174,7 +177,7 @@ func TestGranitePrecompiles(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon) op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background() ctx := context.Background()
genesisTime := hexutil.Uint64(0) genesisTime := hexutil.Uint64(0)
cfg := op_e2e.GraniteSystemConfig(t, &genesisTime) cfg := e2esys.GraniteSystemConfig(t, &genesisTime)
// We don't need a verifier - just the sequencer is enough // We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier") delete(cfg.Nodes, "verifier")
// Use a small sequencer window size to avoid test timeout while waiting for empty blocks // Use a small sequencer window size to avoid test timeout while waiting for empty blocks
...@@ -242,7 +245,7 @@ func TestGranitePrecompiles(t *testing.T) { ...@@ -242,7 +245,7 @@ func TestGranitePrecompiles(t *testing.T) {
runCannon(t, ctx, sys, inputs) runCannon(t, ctx, sys, inputs)
} }
func runCannon(t *testing.T, ctx context.Context, sys *op_e2e.System, inputs utils.LocalGameInputs, extraVmArgs ...string) { func runCannon(t *testing.T, ctx context.Context, sys *e2esys.System, inputs utils.LocalGameInputs, extraVmArgs ...string) {
l1Endpoint := sys.NodeEndpoint("l1").RPC() l1Endpoint := sys.NodeEndpoint("l1").RPC()
l1Beacon := sys.L1BeaconEndpoint().RestHTTP() l1Beacon := sys.L1BeaconEndpoint().RestHTTP()
rollupEndpoint := sys.RollupEndpoint("sequencer").RPC() rollupEndpoint := sys.RollupEndpoint("sequencer").RPC()
......
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"testing" "testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e" op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame"
preimage "github.com/ethereum-optimism/optimism/op-preimage" preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-program/client" "github.com/ethereum-optimism/optimism/op-program/client"
......
...@@ -4,8 +4,10 @@ import ( ...@@ -4,8 +4,10 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags" batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
...@@ -13,16 +15,16 @@ import ( ...@@ -13,16 +15,16 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
type faultDisputeConfigOpts func(cfg *op_e2e.SystemConfig) type faultDisputeConfigOpts func(cfg *e2esys.SystemConfig)
func WithBatcherStopped() faultDisputeConfigOpts { func WithBatcherStopped() faultDisputeConfigOpts {
return func(cfg *op_e2e.SystemConfig) { return func(cfg *e2esys.SystemConfig) {
cfg.DisableBatcher = true cfg.DisableBatcher = true
} }
} }
func WithBlobBatches() faultDisputeConfigOpts { func WithBlobBatches() faultDisputeConfigOpts {
return func(cfg *op_e2e.SystemConfig) { return func(cfg *e2esys.SystemConfig) {
cfg.DataAvailabilityType = batcherFlags.BlobsType cfg.DataAvailabilityType = batcherFlags.BlobsType
genesisActivation := hexutil.Uint64(0) genesisActivation := hexutil.Uint64(0)
...@@ -33,7 +35,7 @@ func WithBlobBatches() faultDisputeConfigOpts { ...@@ -33,7 +35,7 @@ func WithBlobBatches() faultDisputeConfigOpts {
} }
func WithEcotone() faultDisputeConfigOpts { func WithEcotone() faultDisputeConfigOpts {
return func(cfg *op_e2e.SystemConfig) { return func(cfg *e2esys.SystemConfig) {
genesisActivation := hexutil.Uint64(0) genesisActivation := hexutil.Uint64(0)
cfg.DeployConfig.L1CancunTimeOffset = &genesisActivation cfg.DeployConfig.L1CancunTimeOffset = &genesisActivation
cfg.DeployConfig.L2GenesisDeltaTimeOffset = &genesisActivation cfg.DeployConfig.L2GenesisDeltaTimeOffset = &genesisActivation
...@@ -42,13 +44,13 @@ func WithEcotone() faultDisputeConfigOpts { ...@@ -42,13 +44,13 @@ func WithEcotone() faultDisputeConfigOpts {
} }
func WithSequencerWindowSize(size uint64) faultDisputeConfigOpts { func WithSequencerWindowSize(size uint64) faultDisputeConfigOpts {
return func(cfg *op_e2e.SystemConfig) { return func(cfg *e2esys.SystemConfig) {
cfg.DeployConfig.SequencerWindowSize = size cfg.DeployConfig.SequencerWindowSize = size
} }
} }
func StartFaultDisputeSystem(t *testing.T, opts ...faultDisputeConfigOpts) (*op_e2e.System, *ethclient.Client) { func StartFaultDisputeSystem(t *testing.T, opts ...faultDisputeConfigOpts) (*e2esys.System, *ethclient.Client) {
cfg := op_e2e.DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
delete(cfg.Nodes, "verifier") delete(cfg.Nodes, "verifier")
cfg.Nodes["sequencer"].SafeDBPath = t.TempDir() cfg.Nodes["sequencer"].SafeDBPath = t.TempDir()
cfg.DeployConfig.SequencerWindowSize = 4 cfg.DeployConfig.SequencerWindowSize = 4
...@@ -64,8 +66,8 @@ func StartFaultDisputeSystem(t *testing.T, opts ...faultDisputeConfigOpts) (*op_ ...@@ -64,8 +66,8 @@ func StartFaultDisputeSystem(t *testing.T, opts ...faultDisputeConfigOpts) (*op_
return sys, sys.NodeClient("l1") return sys, sys.NodeClient("l1")
} }
func SendKZGPointEvaluationTx(t *testing.T, sys *op_e2e.System, l2Node string, privateKey *ecdsa.PrivateKey) *types.Receipt { func SendKZGPointEvaluationTx(t *testing.T, sys *e2esys.System, l2Node string, privateKey *ecdsa.PrivateKey) *types.Receipt {
return op_e2e.SendL2Tx(t, sys.Cfg, sys.NodeClient(l2Node), privateKey, func(opts *op_e2e.TxOpts) { return helpers.SendL2Tx(t, sys.Cfg, sys.NodeClient(l2Node), privateKey, func(opts *helpers.TxOpts) {
precompile := common.BytesToAddress([]byte{0x0a}) precompile := common.BytesToAddress([]byte{0x0a})
opts.Gas = 100_000 opts.Gas = 100_000
opts.ToAddr = &precompile opts.ToAddr = &precompile
......
package op_e2e package interop
import ( import (
"encoding/json" "encoding/json"
...@@ -16,8 +16,6 @@ import ( ...@@ -16,8 +16,6 @@ import (
) )
func TestInteropDevRecipe(t *testing.T) { func TestInteropDevRecipe(t *testing.T) {
InitParallel(t)
rec := interopgen.InteropDevRecipe{ rec := interopgen.InteropDevRecipe{
L1ChainID: 900100, L1ChainID: 900100,
L2ChainIDs: []uint64{900200, 900201}, L2ChainIDs: []uint64{900200, 900201},
...@@ -31,8 +29,8 @@ func TestInteropDevRecipe(t *testing.T) { ...@@ -31,8 +29,8 @@ func TestInteropDevRecipe(t *testing.T) {
logger := testlog.Logger(t, log.LevelDebug) logger := testlog.Logger(t, log.LevelDebug)
require.NoError(t, worldCfg.Check(logger)) require.NoError(t, worldCfg.Check(logger))
fa := foundry.OpenArtifactsDir("../packages/contracts-bedrock/forge-artifacts") fa := foundry.OpenArtifactsDir("../../packages/contracts-bedrock/forge-artifacts")
srcFS := foundry.NewSourceMapFS(os.DirFS("../packages/contracts-bedrock")) srcFS := foundry.NewSourceMapFS(os.DirFS("../../packages/contracts-bedrock"))
worldDeployment, worldOutput, err := interopgen.Deploy(logger, fa, srcFS, worldCfg) worldDeployment, worldOutput, err := interopgen.Deploy(logger, fa, srcFS, worldCfg)
require.NoError(t, err) require.NoError(t, err)
......
...@@ -6,9 +6,10 @@ import ( ...@@ -6,9 +6,10 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum-optimism/optimism/op-chain-ops/interopgen"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/op-chain-ops/interopgen"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
) )
// TestInteropTrivial tests a simple interop scenario // TestInteropTrivial tests a simple interop scenario
...@@ -60,7 +61,7 @@ func TestInteropTrivial(t *testing.T) { ...@@ -60,7 +61,7 @@ func TestInteropTrivial(t *testing.T) {
s2.SendL2Tx( s2.SendL2Tx(
chainA, chainA,
"Alice", "Alice",
func(l2Opts *op_e2e.TxOpts) { func(l2Opts *helpers.TxOpts) {
l2Opts.ToAddr = &bobAddr l2Opts.ToAddr = &bobAddr
l2Opts.Value = big.NewInt(1000000) l2Opts.Value = big.NewInt(1000000)
l2Opts.GasFeeCap = big.NewInt(1_000_000_000) l2Opts.GasFeeCap = big.NewInt(1_000_000_000)
......
...@@ -10,6 +10,8 @@ import ( ...@@ -10,6 +10,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -26,7 +28,6 @@ import ( ...@@ -26,7 +28,6 @@ import (
"github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys"
"github.com/ethereum-optimism/optimism/op-chain-ops/foundry" "github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
"github.com/ethereum-optimism/optimism/op-chain-ops/interopgen" "github.com/ethereum-optimism/optimism/op-chain-ops/interopgen"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/fakebeacon" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/fakebeacon"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/opnode" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/opnode"
...@@ -82,7 +83,7 @@ type SuperSystem interface { ...@@ -82,7 +83,7 @@ type SuperSystem interface {
// get the user key for a user on an L2 // get the user key for a user on an L2
UserKey(id, username string) ecdsa.PrivateKey UserKey(id, username string) ecdsa.PrivateKey
// send a transaction on an L2 on the given network, from the given user // send a transaction on an L2 on the given network, from the given user
SendL2Tx(network string, username string, applyTxOpts op_e2e.TxOptsFn) *types.Receipt SendL2Tx(network string, username string, applyTxOpts helpers.TxOptsFn) *types.Receipt
// get the address for a user on an L2 // get the address for a user on an L2
Address(network string, username string) common.Address Address(network string, username string) common.Address
} }
...@@ -586,11 +587,11 @@ func (s *interopE2ESystem) L2IDs() []string { ...@@ -586,11 +587,11 @@ func (s *interopE2ESystem) L2IDs() []string {
func (s *interopE2ESystem) SendL2Tx( func (s *interopE2ESystem) SendL2Tx(
id string, id string,
sender string, sender string,
applyTxOpts op_e2e.TxOptsFn, applyTxOpts helpers.TxOptsFn,
) *types.Receipt { ) *types.Receipt {
senderSecret := s.UserKey(id, sender) senderSecret := s.UserKey(id, sender)
require.NotNil(s.t, senderSecret, "no secret found for sender %s", sender) require.NotNil(s.t, senderSecret, "no secret found for sender %s", sender)
return op_e2e.SendL2TxWithID( return helpers.SendL2TxWithID(
s.t, s.t,
s.l2s[id].chainID, s.l2s[id].chainID,
s.L2GethClient(id), s.L2GethClient(id),
......
//go:build cgo_test //go:build cgo_test
// +build cgo_test // +build cgo_test
package op_e2e package opgeth
import ( import (
"context" "context"
......
package op_e2e package opgeth
import ( import (
"context" "context"
...@@ -7,6 +7,8 @@ import ( ...@@ -7,6 +7,8 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum-optimism/optimism/op-e2e/config" "github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
...@@ -51,7 +53,7 @@ type OpGeth struct { ...@@ -51,7 +53,7 @@ type OpGeth struct {
lgr log.Logger lgr log.Logger
} }
func NewOpGeth(t testing.TB, ctx context.Context, cfg *SystemConfig) (*OpGeth, error) { func NewOpGeth(t testing.TB, ctx context.Context, cfg *e2esys.SystemConfig) (*OpGeth, error) {
logger := testlog.Logger(t, log.LevelCrit) logger := testlog.Logger(t, log.LevelCrit)
l1Genesis, err := genesis.BuildL1DeveloperGenesis(cfg.DeployConfig, config.L1Allocs, config.L1Deployments) l1Genesis, err := genesis.BuildL1DeveloperGenesis(cfg.DeployConfig, config.L1Allocs, config.L1Deployments)
...@@ -92,7 +94,7 @@ func NewOpGeth(t testing.TB, ctx context.Context, cfg *SystemConfig) (*OpGeth, e ...@@ -92,7 +94,7 @@ func NewOpGeth(t testing.TB, ctx context.Context, cfg *SystemConfig) (*OpGeth, e
require.NoError(t, gethNode.Node.Start()) require.NoError(t, gethNode.Node.Start())
node = gethNode node = gethNode
} else { } else {
externalNode := (&ExternalRunner{ externalNode := (&e2esys.ExternalRunner{
Name: "l2", Name: "l2",
BinPath: cfg.ExternalL2Shim, BinPath: cfg.ExternalL2Shim,
Genesis: l2Genesis, Genesis: l2Genesis,
......
package altda
import (
"testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
)
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
package altda
import (
"context"
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-batcher/flags"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/stretchr/testify/require"
)
func TestBatcherConcurrentAltDARequests(t *testing.T) {
op_e2e.InitParallel(t)
numL1TxsExpected := int64(10)
cfg := e2esys.DefaultSystemConfig(t)
cfg.DeployConfig.UseAltDA = true
cfg.BatcherMaxPendingTransactions = 0 // no limit on parallel txs
// ensures that batcher txs are as small as possible
cfg.BatcherMaxL1TxSizeBytes = derive.FrameV0OverHeadSize + 1 /*version bytes*/ + 1
cfg.BatcherBatchType = 0
cfg.DataAvailabilityType = flags.CalldataType
cfg.BatcherMaxConcurrentDARequest = uint64(numL1TxsExpected)
// disable batcher because we start it manually below
cfg.DisableBatcher = true
sys, err := cfg.Start(t)
require.NoError(t, err, "Error starting up system")
defer sys.Close()
// make every request take 5 seconds, such that only concurrent requests will be able to make progress fast enough
sys.FakeAltDAServer.SetPutRequestLatency(5 * time.Second)
l1Client := sys.NodeClient("l1")
l2Seq := sys.NodeClient("sequencer")
// we wait for numL1TxsExpected L2 blocks to have been produced, just to make sure the sequencer is working properly
_, err = geth.WaitForBlock(big.NewInt(numL1TxsExpected), l2Seq, time.Duration(cfg.DeployConfig.L2BlockTime*uint64(numL1TxsExpected))*time.Second)
require.NoError(t, err, "Waiting for L2 blocks")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
startingL1BlockNum, err := l1Client.BlockNumber(ctx)
require.NoError(t, err)
// start batch submission
driver := sys.BatchSubmitter.TestDriver()
err = driver.StartBatchSubmitting()
require.NoError(t, err)
totalBatcherTxsCount := int64(0)
// wait for up to 5 L1 blocks, expecting 10 L2 batcher txs in them.
// usually only 3 is required, but it's possible additional L1 blocks will be created
// before the batcher starts, so we wait additional blocks.
for i := int64(0); i < 5; i++ {
block, err := geth.WaitForBlock(big.NewInt(int64(startingL1BlockNum)+i), l1Client, time.Duration(cfg.DeployConfig.L1BlockTime*2)*time.Second)
require.NoError(t, err, "Waiting for l1 blocks")
// there are possibly other services (proposer/challenger) in the background sending txs
// so we only count the batcher txs
batcherTxCount, err := transactions.TransactionsBySender(block, cfg.DeployConfig.BatchSenderAddress)
require.NoError(t, err)
totalBatcherTxsCount += int64(batcherTxCount)
if totalBatcherTxsCount >= numL1TxsExpected {
return
}
}
t.Fatal("Expected at least 10 transactions from the batcher")
}
package op_e2e package bridge
import ( import (
"context" "context"
...@@ -6,6 +6,10 @@ import ( ...@@ -6,6 +6,10 @@ import (
"math/big" "math/big"
"testing" "testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/receipts" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/receipts"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
...@@ -20,12 +24,16 @@ import ( ...@@ -20,12 +24,16 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
// TestERC20BridgeDeposits tests the the L1StandardBridge bridge ERC20 // TestERC20BridgeDeposits tests the the L1StandardBridge bridge ERC20
// functionality. // functionality.
func TestERC20BridgeDeposits(t *testing.T) { func TestERC20BridgeDeposits(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
sys, err := cfg.Start(t) sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system") require.Nil(t, err, "Error starting up system")
......
package op_e2e package bridge
import ( import (
"context" "context"
...@@ -6,6 +6,11 @@ import ( ...@@ -6,6 +6,11 @@ import (
"testing" "testing"
"time" "time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
...@@ -16,8 +21,8 @@ import ( ...@@ -16,8 +21,8 @@ import (
) )
func TestMintOnRevertedDeposit(t *testing.T) { func TestMintOnRevertedDeposit(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
delete(cfg.Nodes, "verifier") delete(cfg.Nodes, "verifier")
sys, err := cfg.Start(t) sys, err := cfg.Start(t)
require.NoError(t, err, "Error starting up system") require.NoError(t, err, "Error starting up system")
...@@ -44,7 +49,7 @@ func TestMintOnRevertedDeposit(t *testing.T) { ...@@ -44,7 +49,7 @@ func TestMintOnRevertedDeposit(t *testing.T) {
toAddr := common.Address{0xff, 0xff} toAddr := common.Address{0xff, 0xff}
mintAmount := big.NewInt(9_000_000) mintAmount := big.NewInt(9_000_000)
opts.Value = mintAmount opts.Value = mintAmount
SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *DepositTxOpts) { helpers.SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *helpers.DepositTxOpts) {
l2Opts.ToAddr = toAddr l2Opts.ToAddr = toAddr
// trigger a revert by transferring more than we have available // trigger a revert by transferring more than we have available
l2Opts.Value = new(big.Int).Mul(common.Big2, startBalance) l2Opts.Value = new(big.Int).Mul(common.Big2, startBalance)
...@@ -75,8 +80,8 @@ func TestMintOnRevertedDeposit(t *testing.T) { ...@@ -75,8 +80,8 @@ func TestMintOnRevertedDeposit(t *testing.T) {
} }
func TestDepositTxCreateContract(t *testing.T) { func TestDepositTxCreateContract(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
delete(cfg.Nodes, "verifier") delete(cfg.Nodes, "verifier")
sys, err := cfg.Start(t) sys, err := cfg.Start(t)
...@@ -125,7 +130,7 @@ func TestDepositTxCreateContract(t *testing.T) { ...@@ -125,7 +130,7 @@ func TestDepositTxCreateContract(t *testing.T) {
deployData := append(deployPrefix, sstoreContract...) deployData := append(deployPrefix, sstoreContract...)
l2Receipt := SendDepositTx(t, cfg, l1Client, l2Client, opts, func(l2Opts *DepositTxOpts) { l2Receipt := helpers.SendDepositTx(t, cfg, l1Client, l2Client, opts, func(l2Opts *helpers.DepositTxOpts) {
l2Opts.Data = deployData l2Opts.Data = deployData
l2Opts.Value = common.Big0 l2Opts.Value = common.Big0
l2Opts.IsCreation = true l2Opts.IsCreation = true
......
package bridge
import (
"context"
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
)
// TestL2SequencerRPCDepositTx checks that the L2 sequencer will not accept DepositTx type transactions.
// The acceptance of these transactions would allow for arbitrary minting of ETH in L2.
func TestL2SequencerRPCDepositTx(t *testing.T) {
op_e2e.InitParallel(t)
// Create our system configuration for L1/L2 and start it
cfg := e2esys.DefaultSystemConfig(t)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
// Obtain our sequencer, verifier, and transactor keypair.
l2Seq := sys.NodeClient("sequencer")
l2Verif := sys.NodeClient("verifier")
txSigningKey := sys.Cfg.Secrets.Alice
require.Nil(t, err)
// Create a deposit tx to send over RPC.
tx := types.NewTx(&types.DepositTx{
SourceHash: common.Hash{},
From: crypto.PubkeyToAddress(txSigningKey.PublicKey),
To: &common.Address{0xff, 0xff},
Mint: big.NewInt(1000),
Value: big.NewInt(1000),
Gas: 0,
IsSystemTransaction: false,
Data: nil,
})
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
err = l2Seq.SendTransaction(ctx, tx)
cancel()
require.Error(t, err, "a DepositTx was accepted by L2 sequencer over RPC when it should not have been.")
ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
err = l2Verif.SendTransaction(ctx, tx)
cancel()
require.Error(t, err, "a DepositTx was accepted by L2 verifier over RPC when it should not have been.")
}
package op_e2e package bridge
import ( import (
"context" "context"
...@@ -7,6 +7,9 @@ import ( ...@@ -7,6 +7,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
...@@ -22,7 +25,7 @@ import ( ...@@ -22,7 +25,7 @@ import (
type CommonSystem interface { type CommonSystem interface {
NodeClient(role string) *ethclient.Client NodeClient(role string) *ethclient.Client
RollupClient(role string) *sources.RollupClient RollupClient(role string) *sources.RollupClient
Config() SystemConfig Config() e2esys.SystemConfig
TestAccount(int) *ecdsa.PrivateKey TestAccount(int) *ecdsa.PrivateKey
} }
...@@ -33,9 +36,9 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) { ...@@ -33,9 +36,9 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) {
t.Logf("WithdrawalsTest: running with FP == %t", e2eutils.UseFaultProofs()) t.Logf("WithdrawalsTest: running with FP == %t", e2eutils.UseFaultProofs())
cfg := sys.Config() cfg := sys.Config()
l1Client := sys.NodeClient(RoleL1) l1Client := sys.NodeClient(e2esys.RoleL1)
l2Seq := sys.NodeClient(RoleSeq) l2Seq := sys.NodeClient(e2esys.RoleSeq)
l2Verif := sys.NodeClient(RoleVerif) l2Verif := sys.NodeClient(e2esys.RoleVerif)
// Transactor Account // Transactor Account
ethPrivKey := sys.TestAccount(0) ethPrivKey := sys.TestAccount(0)
...@@ -55,7 +58,7 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) { ...@@ -55,7 +58,7 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) {
mintAmount := big.NewInt(1_000_000_000_000) mintAmount := big.NewInt(1_000_000_000_000)
opts.Value = mintAmount opts.Value = mintAmount
t.Logf("WithdrawalsTest: depositing %v with L2 start balance %v...", mintAmount, startBalanceBeforeDeposit) t.Logf("WithdrawalsTest: depositing %v with L2 start balance %v...", mintAmount, startBalanceBeforeDeposit)
SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *DepositTxOpts) { helpers.SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *helpers.DepositTxOpts) {
l2Opts.Value = common.Big0 l2Opts.Value = common.Big0
}) })
t.Log("WithdrawalsTest: waiting for balance change...") t.Log("WithdrawalsTest: waiting for balance change...")
...@@ -78,7 +81,7 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) { ...@@ -78,7 +81,7 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) {
withdrawAmount := big.NewInt(500_000_000_000) withdrawAmount := big.NewInt(500_000_000_000)
t.Logf("WithdrawalsTest: sending L2 withdrawal for %v...", withdrawAmount) t.Logf("WithdrawalsTest: sending L2 withdrawal for %v...", withdrawAmount)
tx, receipt := SendWithdrawal(t, cfg, l2Seq, ethPrivKey, func(opts *WithdrawalTxOpts) { tx, receipt := helpers.SendWithdrawal(t, cfg, l2Seq, ethPrivKey, func(opts *helpers.WithdrawalTxOpts) {
opts.Value = withdrawAmount opts.Value = withdrawAmount
opts.VerifyOnClients(l2Verif) opts.VerifyOnClients(l2Verif)
}) })
...@@ -97,7 +100,7 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) { ...@@ -97,7 +100,7 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) {
// Take fee into account // Take fee into account
diff = new(big.Int).Sub(startBalanceBeforeWithdrawal, endBalanceAfterWithdrawal) diff = new(big.Int).Sub(startBalanceBeforeWithdrawal, endBalanceAfterWithdrawal)
fees := calcGasFees(receipt.GasUsed, tx.GasTipCap(), tx.GasFeeCap(), header.BaseFee) fees := helpers.CalcGasFees(receipt.GasUsed, tx.GasTipCap(), tx.GasFeeCap(), header.BaseFee)
fees = fees.Add(fees, receipt.L1Fee) fees = fees.Add(fees, receipt.L1Fee)
diff = diff.Sub(diff, fees) diff = diff.Sub(diff, fees)
require.Equal(t, withdrawAmount, diff) require.Equal(t, withdrawAmount, diff)
...@@ -109,7 +112,7 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) { ...@@ -109,7 +112,7 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) {
require.NoError(t, err) require.NoError(t, err)
t.Log("WithdrawalsTest: ProveAndFinalizeWithdrawal...") t.Log("WithdrawalsTest: ProveAndFinalizeWithdrawal...")
proveReceipt, finalizeReceipt, resolveClaimReceipt, resolveReceipt := ProveAndFinalizeWithdrawal(t, cfg, sys, RoleVerif, ethPrivKey, receipt) proveReceipt, finalizeReceipt, resolveClaimReceipt, resolveReceipt := helpers.ProveAndFinalizeWithdrawal(t, cfg, sys, e2esys.RoleVerif, ethPrivKey, receipt)
// Verify balance after withdrawal // Verify balance after withdrawal
ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second) ctx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
......
package bridge
import (
"testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/stretchr/testify/require"
)
// TestWithdrawals checks that a deposit and then withdrawal execution succeeds. It verifies the
// balance changes on L1 and L2 and has to include gas fees in the balance checks.
// It does not check that the withdrawal can be executed prior to the end of the finality period.
func TestWithdrawals(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
cfg.DeployConfig.FinalizationPeriodSeconds = 2 // 2s finalization period
cfg.L1FinalizedDistance = 2 // Finalize quick, don't make the proposer wait too long
sys, err := cfg.Start(t)
require.NoError(t, err, "Error starting up system")
RunWithdrawalsTest(t, sys)
}
package conductor
import (
"testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
)
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
package op_e2e package conductor
import ( import (
"context" "context"
...@@ -9,6 +9,11 @@ import ( ...@@ -9,6 +9,11 @@ import (
"testing" "testing"
"time" "time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -60,11 +65,11 @@ func (c *conductor) RPCEndpoint() string { ...@@ -60,11 +65,11 @@ func (c *conductor) RPCEndpoint() string {
return fmt.Sprintf("http://%s:%d", localhost, c.rpcPort) return fmt.Sprintf("http://%s:%d", localhost, c.rpcPort)
} }
func setupSequencerFailoverTest(t *testing.T) (*System, map[string]*conductor, func()) { func setupSequencerFailoverTest(t *testing.T) (*e2esys.System, map[string]*conductor, func()) {
InitParallel(t) op_e2e.InitParallel(t)
ctx := context.Background() ctx := context.Background()
sys, conductors, err := retry.Do2(ctx, maxSetupRetries, retryStrategy, func() (*System, map[string]*conductor, error) { sys, conductors, err := retry.Do2(ctx, maxSetupRetries, retryStrategy, func() (*e2esys.System, map[string]*conductor, error) {
return setupHAInfra(t, ctx) return setupHAInfra(t, ctx)
}) })
require.NoError(t, err, "Expected to successfully setup sequencers and conductors after retry") require.NoError(t, err, "Expected to successfully setup sequencers and conductors after retry")
...@@ -138,10 +143,10 @@ func setupSequencerFailoverTest(t *testing.T) (*System, map[string]*conductor, f ...@@ -138,10 +143,10 @@ func setupSequencerFailoverTest(t *testing.T) (*System, map[string]*conductor, f
} }
} }
func setupHAInfra(t *testing.T, ctx context.Context) (*System, map[string]*conductor, error) { func setupHAInfra(t *testing.T, ctx context.Context) (*e2esys.System, map[string]*conductor, error) {
startTime := time.Now() startTime := time.Now()
var sys *System var sys *e2esys.System
var conductors map[string]*conductor var conductors map[string]*conductor
var err error var err error
...@@ -267,7 +272,7 @@ func setupConductor( ...@@ -267,7 +272,7 @@ func setupConductor(
}, nil }, nil
} }
func setupBatcher(t *testing.T, sys *System, conductors map[string]*conductor) { func setupBatcher(t *testing.T, sys *e2esys.System, conductors map[string]*conductor) {
// enable active sequencer follow mode. // enable active sequencer follow mode.
// in sequencer HA, all batcher / proposer requests will be proxied by conductor so that we can make sure // in sequencer HA, all batcher / proposer requests will be proxied by conductor so that we can make sure
// that requests are always handled by leader. // that requests are always handled by leader.
...@@ -311,8 +316,8 @@ func setupBatcher(t *testing.T, sys *System, conductors map[string]*conductor) { ...@@ -311,8 +316,8 @@ func setupBatcher(t *testing.T, sys *System, conductors map[string]*conductor) {
sys.BatchSubmitter = batcher sys.BatchSubmitter = batcher
} }
func sequencerFailoverSystemConfig(t *testing.T, ports map[string]int) SystemConfig { func sequencerFailoverSystemConfig(t *testing.T, ports map[string]int) e2esys.SystemConfig {
cfg := EcotoneSystemConfig(t, &genesisTime) cfg := e2esys.EcotoneSystemConfig(t, new(hexutil.Uint64))
delete(cfg.Nodes, "sequencer") delete(cfg.Nodes, "sequencer")
cfg.Nodes[Sequencer1Name] = sequencerCfg(ports[Sequencer1Name]) cfg.Nodes[Sequencer1Name] = sequencerCfg(ports[Sequencer1Name])
cfg.Nodes[Sequencer2Name] = sequencerCfg(ports[Sequencer2Name]) cfg.Nodes[Sequencer2Name] = sequencerCfg(ports[Sequencer2Name])
...@@ -372,7 +377,7 @@ func waitForLeadership(t *testing.T, c *conductor) error { ...@@ -372,7 +377,7 @@ func waitForLeadership(t *testing.T, c *conductor) error {
return wait.For(ctx, 1*time.Second, condition) return wait.For(ctx, 1*time.Second, condition)
} }
func waitForLeadershipChange(t *testing.T, prev *conductor, prevID string, conductors map[string]*conductor, sys *System) string { func waitForLeadershipChange(t *testing.T, prev *conductor, prevID string, conductors map[string]*conductor, sys *e2esys.System) string {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel() defer cancel()
...@@ -486,7 +491,7 @@ func findFollower(t *testing.T, conductors map[string]*conductor) (string, *cond ...@@ -486,7 +491,7 @@ func findFollower(t *testing.T, conductors map[string]*conductor) (string, *cond
return "", nil return "", nil
} }
func ensureOnlyOneLeader(t *testing.T, sys *System, conductors map[string]*conductor) { func ensureOnlyOneLeader(t *testing.T, sys *e2esys.System, conductors map[string]*conductor) {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel() defer cancel()
......
package op_e2e package conductor
import ( import (
"context" "context"
......
package op_e2e package conductor
import ( import (
"context" "context"
...@@ -6,6 +6,11 @@ import ( ...@@ -6,6 +6,11 @@ import (
"testing" "testing"
"time" "time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -18,9 +23,9 @@ import ( ...@@ -18,9 +23,9 @@ import (
) )
func TestStopStartSequencer(t *testing.T) { func TestStopStartSequencer(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
sys, err := cfg.Start(t) sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system") require.Nil(t, err, "Error starting up system")
...@@ -74,13 +79,21 @@ func TestStopStartSequencer(t *testing.T) { ...@@ -74,13 +79,21 @@ func TestStopStartSequencer(t *testing.T) {
) )
} }
func latestBlock(t *testing.T, client *ethclient.Client) uint64 {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
blockAfter, err := client.BlockNumber(ctx)
require.Nil(t, err, "Error getting latest block")
return blockAfter
}
func TestPersistSequencerStateWhenChanged(t *testing.T) { func TestPersistSequencerStateWhenChanged(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
ctx := context.Background() ctx := context.Background()
dir := t.TempDir() dir := t.TempDir()
stateFile := dir + "/state.json" stateFile := dir + "/state.json"
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
// We don't need a verifier - just the sequencer is enough // We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier") delete(cfg.Nodes, "verifier")
cfg.Nodes["sequencer"].ConfigPersistence = node.NewConfigPersistence(stateFile) cfg.Nodes["sequencer"].ConfigPersistence = node.NewConfigPersistence(stateFile)
...@@ -104,7 +117,7 @@ func TestPersistSequencerStateWhenChanged(t *testing.T) { ...@@ -104,7 +117,7 @@ func TestPersistSequencerStateWhenChanged(t *testing.T) {
} }
func TestLoadSequencerStateOnStarted_Stopped(t *testing.T) { func TestLoadSequencerStateOnStarted_Stopped(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
ctx := context.Background() ctx := context.Background()
dir := t.TempDir() dir := t.TempDir()
stateFile := dir + "/state.json" stateFile := dir + "/state.json"
...@@ -113,7 +126,7 @@ func TestLoadSequencerStateOnStarted_Stopped(t *testing.T) { ...@@ -113,7 +126,7 @@ func TestLoadSequencerStateOnStarted_Stopped(t *testing.T) {
configReader := node.NewConfigPersistence(stateFile) configReader := node.NewConfigPersistence(stateFile)
require.NoError(t, configReader.SequencerStopped()) require.NoError(t, configReader.SequencerStopped())
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
// We don't need a verifier - just the sequencer is enough // We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier") delete(cfg.Nodes, "verifier")
seqCfg := cfg.Nodes["sequencer"] seqCfg := cfg.Nodes["sequencer"]
...@@ -136,7 +149,7 @@ func TestLoadSequencerStateOnStarted_Stopped(t *testing.T) { ...@@ -136,7 +149,7 @@ func TestLoadSequencerStateOnStarted_Stopped(t *testing.T) {
} }
func TestLoadSequencerStateOnStarted_Started(t *testing.T) { func TestLoadSequencerStateOnStarted_Started(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
ctx := context.Background() ctx := context.Background()
dir := t.TempDir() dir := t.TempDir()
stateFile := dir + "/state.json" stateFile := dir + "/state.json"
...@@ -145,7 +158,7 @@ func TestLoadSequencerStateOnStarted_Started(t *testing.T) { ...@@ -145,7 +158,7 @@ func TestLoadSequencerStateOnStarted_Started(t *testing.T) {
configReader := node.NewConfigPersistence(stateFile) configReader := node.NewConfigPersistence(stateFile)
require.NoError(t, configReader.SequencerStarted()) require.NoError(t, configReader.SequencerStarted())
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
// We don't need a verifier - just the sequencer is enough // We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier") delete(cfg.Nodes, "verifier")
seqCfg := cfg.Nodes["sequencer"] seqCfg := cfg.Nodes["sequencer"]
...@@ -169,10 +182,10 @@ func TestLoadSequencerStateOnStarted_Started(t *testing.T) { ...@@ -169,10 +182,10 @@ func TestLoadSequencerStateOnStarted_Started(t *testing.T) {
} }
func TestPostUnsafePayload(t *testing.T) { func TestPostUnsafePayload(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
ctx := context.Background() ctx := context.Background()
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
cfg.Nodes["verifier"].RPC.EnableAdmin = true cfg.Nodes["verifier"].RPC.EnableAdmin = true
cfg.DisableBatcher = true cfg.DisableBatcher = true
......
package op_e2e package contracts
import ( import (
"errors" "errors"
"testing" "testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -13,9 +15,9 @@ import ( ...@@ -13,9 +15,9 @@ import (
) )
func TestArtifacts(t *testing.T) { func TestArtifacts(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
logger := testlog.Logger(t, log.LevelWarn) // lower this log level to get verbose test dump of all artifacts logger := testlog.Logger(t, log.LevelWarn) // lower this log level to get verbose test dump of all artifacts
af := foundry.OpenArtifactsDir("../packages/contracts-bedrock/forge-artifacts") af := foundry.OpenArtifactsDir("../../../packages/contracts-bedrock/forge-artifacts")
artifacts, err := af.ListArtifacts() artifacts, err := af.ListArtifacts()
require.NoError(t, err) require.NoError(t, err)
require.NotEmpty(t, artifacts) require.NotEmpty(t, artifacts)
......
package contracts
import (
"testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
)
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
package op_e2e package da
import ( import (
"context" "context"
...@@ -7,6 +7,11 @@ import ( ...@@ -7,6 +7,11 @@ import (
"testing" "testing"
"time" "time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags" batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags"
...@@ -19,7 +24,7 @@ import ( ...@@ -19,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
func setupAliceAccount(t *testing.T, cfg SystemConfig, sys *System, ethPrivKey *ecdsa.PrivateKey) { func setupAliceAccount(t *testing.T, cfg e2esys.SystemConfig, sys *e2esys.System, ethPrivKey *ecdsa.PrivateKey) {
l1Client := sys.NodeClient("l1") l1Client := sys.NodeClient("l1")
l2Verif := sys.NodeClient("verifier") l2Verif := sys.NodeClient("verifier")
...@@ -37,7 +42,7 @@ func setupAliceAccount(t *testing.T, cfg SystemConfig, sys *System, ethPrivKey * ...@@ -37,7 +42,7 @@ func setupAliceAccount(t *testing.T, cfg SystemConfig, sys *System, ethPrivKey *
require.NoError(t, err) require.NoError(t, err)
mintAmount := big.NewInt(1_000_000_000_000) mintAmount := big.NewInt(1_000_000_000_000)
opts.Value = mintAmount opts.Value = mintAmount
SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *DepositTxOpts) {}) helpers.SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *helpers.DepositTxOpts) {})
// Confirm balance // Confirm balance
ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second) ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second)
...@@ -50,9 +55,9 @@ func setupAliceAccount(t *testing.T, cfg SystemConfig, sys *System, ethPrivKey * ...@@ -50,9 +55,9 @@ func setupAliceAccount(t *testing.T, cfg SystemConfig, sys *System, ethPrivKey *
} }
func TestBrotliBatcherFjord(t *testing.T) { func TestBrotliBatcherFjord(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
cfg.DataAvailabilityType = batcherFlags.BlobsType cfg.DataAvailabilityType = batcherFlags.BlobsType
genesisActivation := hexutil.Uint64(0) genesisActivation := hexutil.Uint64(0)
...@@ -62,7 +67,7 @@ func TestBrotliBatcherFjord(t *testing.T) { ...@@ -62,7 +67,7 @@ func TestBrotliBatcherFjord(t *testing.T) {
cfg.DeployConfig.L2GenesisFjordTimeOffset = &genesisActivation cfg.DeployConfig.L2GenesisFjordTimeOffset = &genesisActivation
// set up batcher to use brotli // set up batcher to use brotli
sys, err := cfg.Start(t, SystemConfigOption{"compressionAlgo", "brotli", nil}) sys, err := cfg.Start(t, e2esys.SystemConfigOption{Key: "compressionAlgo", Role: "brotli", Action: nil})
require.Nil(t, err, "Error starting up system") require.Nil(t, err, "Error starting up system")
log := testlog.Logger(t, log.LevelInfo) log := testlog.Logger(t, log.LevelInfo)
...@@ -76,7 +81,7 @@ func TestBrotliBatcherFjord(t *testing.T) { ...@@ -76,7 +81,7 @@ func TestBrotliBatcherFjord(t *testing.T) {
setupAliceAccount(t, cfg, sys, ethPrivKey) setupAliceAccount(t, cfg, sys, ethPrivKey)
// Submit TX to L2 sequencer node // Submit TX to L2 sequencer node
receipt := SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *TxOpts) { receipt := helpers.SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *helpers.TxOpts) {
opts.Value = big.NewInt(1_000_000_000) opts.Value = big.NewInt(1_000_000_000)
opts.Nonce = 1 // Already have deposit opts.Nonce = 1 // Already have deposit
opts.ToAddr = &common.Address{0xff, 0xff} opts.ToAddr = &common.Address{0xff, 0xff}
......
package da
import (
"testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
)
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
package da
import (
"context"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"
)
// TestSystemE2EDencunAtGenesis tests if L2 finalizes when blobs are present on L1
func TestSystemE2EDencunAtGenesisWithBlobs(t *testing.T) {
op_e2e.InitParallel(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cfg := e2esys.DefaultSystemConfig(t)
cfg.DeployConfig.L1CancunTimeOffset = new(hexutil.Uint64)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
// send a blob-containing txn on l1
ethPrivKey := sys.Cfg.Secrets.Alice
txData := transactions.CreateEmptyBlobTx(true, sys.Cfg.L1ChainIDBig().Uint64())
tx := types.MustSignNewTx(ethPrivKey, types.LatestSignerForChainID(cfg.L1ChainIDBig()), txData)
// send blob-containing txn
sendCtx, sendCancel := context.WithTimeout(context.Background(), 15*time.Second)
defer sendCancel()
l1Client := sys.NodeClient("l1")
err = l1Client.SendTransaction(sendCtx, tx)
require.NoError(t, err, "Sending L1 empty blob tx")
// Wait for transaction on L1
blockContainsBlob, err := wait.ForReceiptOK(ctx, l1Client, tx.Hash())
require.Nil(t, err, "Waiting for blob tx on L1")
// end sending blob-containing txns on l1
l2Client := sys.NodeClient("sequencer")
finalizedBlock, err := geth.WaitForL1OriginOnL2(sys.RollupConfig, blockContainsBlob.BlockNumber.Uint64(), l2Client, 30*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for L1 origin of blob tx on L2")
finalizationTimeout := 30 * time.Duration(cfg.DeployConfig.L1BlockTime) * time.Second
_, err = geth.WaitForBlockToBeSafe(finalizedBlock.Header().Number, l2Client, finalizationTimeout)
require.Nil(t, err, "Waiting for safety of L2 block")
}
package op_e2e package da
import ( import (
"context" "context"
...@@ -7,6 +7,11 @@ import ( ...@@ -7,6 +7,11 @@ import (
"testing" "testing"
"time" "time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -38,9 +43,9 @@ func TestSystem4844E2E(t *testing.T) { ...@@ -38,9 +43,9 @@ func TestSystem4844E2E(t *testing.T) {
} }
func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAvailabilityType) { func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAvailabilityType) {
InitParallel(t) op_e2e.InitParallel(t)
cfg := EcotoneSystemConfig(t, &genesisTime) cfg := e2esys.EcotoneSystemConfig(t, new(hexutil.Uint64))
cfg.DataAvailabilityType = daType cfg.DataAvailabilityType = daType
cfg.BatcherBatchType = derive.SpanBatchType cfg.BatcherBatchType = derive.SpanBatchType
cfg.DeployConfig.L1GenesisBlockBaseFeePerGas = (*hexutil.Big)(big.NewInt(7000)) cfg.DeployConfig.L1GenesisBlockBaseFeePerGas = (*hexutil.Big)(big.NewInt(7000))
...@@ -62,9 +67,9 @@ func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAva ...@@ -62,9 +67,9 @@ func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAva
// is started, as is required by the function. // is started, as is required by the function.
var jamChan chan error var jamChan chan error
jamCtx, jamCancel := context.WithTimeout(context.Background(), 20*time.Second) jamCtx, jamCancel := context.WithTimeout(context.Background(), 20*time.Second)
action := SystemConfigOption{ action := e2esys.SystemConfigOption{
key: "beforeBatcherStart", Key: "beforeBatcherStart",
action: func(cfg *SystemConfig, s *System) { Action: func(cfg *e2esys.SystemConfig, s *e2esys.System) {
driver := s.BatchSubmitter.TestDriver() driver := s.BatchSubmitter.TestDriver()
err := driver.JamTxPool(jamCtx) err := driver.JamTxPool(jamCtx)
require.NoError(t, err) require.NoError(t, err)
...@@ -108,7 +113,7 @@ func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAva ...@@ -108,7 +113,7 @@ func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAva
require.NoError(t, err) require.NoError(t, err)
mintAmount := big.NewInt(1_000_000_000_000) mintAmount := big.NewInt(1_000_000_000_000)
opts.Value = mintAmount opts.Value = mintAmount
SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *DepositTxOpts) {}) helpers.SendDepositTx(t, cfg, l1Client, l2Verif, opts, func(l2Opts *helpers.DepositTxOpts) {})
// Confirm balance // Confirm balance
ctx2, cancel2 := context.WithTimeout(context.Background(), 20*time.Second) ctx2, cancel2 := context.WithTimeout(context.Background(), 20*time.Second)
...@@ -120,7 +125,7 @@ func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAva ...@@ -120,7 +125,7 @@ func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAva
require.Equal(t, mintAmount, diff, "Did not get expected balance change") require.Equal(t, mintAmount, diff, "Did not get expected balance change")
// Submit TX to L2 sequencer node // Submit TX to L2 sequencer node
receipt := SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *TxOpts) { receipt := helpers.SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *helpers.TxOpts) {
opts.Value = big.NewInt(1_000_000_000) opts.Value = big.NewInt(1_000_000_000)
opts.Nonce = 1 // Already have deposit opts.Nonce = 1 // Already have deposit
opts.ToAddr = &common.Address{0xff, 0xff} opts.ToAddr = &common.Address{0xff, 0xff}
...@@ -237,9 +242,9 @@ func toIndexedBlobHashes(hs ...common.Hash) []eth.IndexedBlobHash { ...@@ -237,9 +242,9 @@ func toIndexedBlobHashes(hs ...common.Hash) []eth.IndexedBlobHash {
// We then send a couple of expensive Deposit transactions, which drives up the // We then send a couple of expensive Deposit transactions, which drives up the
// gas price. The L1 blob gas limit is set to a low value to speed up this process. // gas price. The L1 blob gas limit is set to a low value to speed up this process.
func TestBatcherAutoDA(t *testing.T) { func TestBatcherAutoDA(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
cfg := EcotoneSystemConfig(t, &genesisTime) cfg := e2esys.EcotoneSystemConfig(t, new(hexutil.Uint64))
cfg.DataAvailabilityType = batcherFlags.AutoType cfg.DataAvailabilityType = batcherFlags.AutoType
// We set the genesis fee values and block gas limit such that calldata txs are initially cheaper, // We set the genesis fee values and block gas limit such that calldata txs are initially cheaper,
// but then drive up the base fee over the coming L1 blocks such that blobs become cheaper again. // but then drive up the base fee over the coming L1 blocks such that blobs become cheaper again.
......
package op_e2e package da
import ( import (
"context" "context"
"testing" "testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/fakebeacon" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/fakebeacon"
"github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/client"
...@@ -16,7 +18,7 @@ import ( ...@@ -16,7 +18,7 @@ import (
) )
func TestGetVersion(t *testing.T) { func TestGetVersion(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
l := testlog.Logger(t, log.LevelInfo) l := testlog.Logger(t, log.LevelInfo)
...@@ -36,7 +38,7 @@ func TestGetVersion(t *testing.T) { ...@@ -36,7 +38,7 @@ func TestGetVersion(t *testing.T) {
} }
func Test404NotFound(t *testing.T) { func Test404NotFound(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
l := testlog.Logger(t, log.LevelInfo) l := testlog.Logger(t, log.LevelInfo)
......
package da
import (
"context"
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/stretchr/testify/require"
)
func TestBatcherMultiTx(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
cfg.BatcherMaxPendingTransactions = 0 // no limit on parallel txs
// ensures that batcher txs are as small as possible
cfg.BatcherMaxL1TxSizeBytes = derive.FrameV0OverHeadSize + 1 /*version bytes*/ + 1
cfg.DisableBatcher = true
sys, err := cfg.Start(t)
require.NoError(t, err, "Error starting up system")
l1Client := sys.NodeClient("l1")
l2Seq := sys.NodeClient("sequencer")
_, err = geth.WaitForBlock(big.NewInt(10), l2Seq, time.Duration(cfg.DeployConfig.L2BlockTime*15)*time.Second)
require.NoError(t, err, "Waiting for L2 blocks")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
l1Number, err := l1Client.BlockNumber(ctx)
require.NoError(t, err)
// start batch submission
driver := sys.BatchSubmitter.TestDriver()
err = driver.StartBatchSubmitting()
require.NoError(t, err)
totalBatcherTxsCount := int64(0)
// wait for up to 5 L1 blocks, usually only 3 is required, but it's
// possible additional L1 blocks will be created before the batcher starts,
// so we wait additional blocks.
for i := int64(0); i < 5; i++ {
block, err := geth.WaitForBlock(big.NewInt(int64(l1Number)+i), l1Client, time.Duration(cfg.DeployConfig.L1BlockTime*2)*time.Second)
require.NoError(t, err, "Waiting for l1 blocks")
// there are possibly other services (proposer/challenger) in the background sending txs
// so we only count the batcher txs
batcherTxCount, err := transactions.TransactionsBySender(block, cfg.DeployConfig.BatchSenderAddress)
require.NoError(t, err)
totalBatcherTxsCount += int64(batcherTxCount)
if totalBatcherTxsCount >= 10 {
return
}
}
t.Fatal("Expected at least 10 transactions from the batcher")
}
package da
import (
"context"
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"
)
// TestSystemBatchType run each system e2e test case in singular batch mode and span batch mode.
// If the test case tests batch submission and advancing safe head, it should be tested in both singular and span batch mode.
func TestSystemBatchType(t *testing.T) {
tests := []struct {
name string
f func(*testing.T, func(*e2esys.SystemConfig))
}{
{"StopStartBatcher", StopStartBatcher},
}
for _, test := range tests {
test := test
t.Run(test.name+"_SingularBatch", func(t *testing.T) {
test.f(t, func(sc *e2esys.SystemConfig) {
sc.BatcherBatchType = derive.SingularBatchType
})
})
t.Run(test.name+"_SpanBatch", func(t *testing.T) {
test.f(t, func(sc *e2esys.SystemConfig) {
sc.BatcherBatchType = derive.SpanBatchType
})
})
t.Run(test.name+"_SpanBatchMaxBlocks", func(t *testing.T) {
test.f(t, func(sc *e2esys.SystemConfig) {
sc.BatcherBatchType = derive.SpanBatchType
sc.BatcherMaxBlocksPerSpanBatch = 2
})
})
}
}
func StopStartBatcher(t *testing.T, cfgMod func(*e2esys.SystemConfig)) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
cfgMod(&cfg)
sys, err := cfg.Start(t)
require.NoError(t, err, "Error starting up system")
rollupClient := sys.RollupClient("verifier")
l2Seq := sys.NodeClient("sequencer")
l2Verif := sys.NodeClient("verifier")
// retrieve the initial sync status
seqStatus, err := rollupClient.SyncStatus(context.Background())
require.NoError(t, err)
nonce := uint64(0)
sendTx := func() *types.Receipt {
// Submit TX to L2 sequencer node
receipt := helpers.SendL2Tx(t, cfg, l2Seq, cfg.Secrets.Alice, func(opts *helpers.TxOpts) {
opts.ToAddr = &common.Address{0xff, 0xff}
opts.Value = big.NewInt(1_000_000_000)
opts.Nonce = nonce
})
nonce++
return receipt
}
// send a transaction
receipt := sendTx()
// wait until the block the tx was first included in shows up in the safe chain on the verifier
safeBlockInclusionDuration := time.Duration(6*cfg.DeployConfig.L1BlockTime) * time.Second
_, err = geth.WaitForBlock(receipt.BlockNumber, l2Verif, safeBlockInclusionDuration)
require.NoError(t, err, "Waiting for block on verifier")
require.NoError(t, wait.ForProcessingFullBatch(context.Background(), rollupClient))
// ensure the safe chain advances
newSeqStatus, err := rollupClient.SyncStatus(context.Background())
require.NoError(t, err)
require.Greater(t, newSeqStatus.SafeL2.Number, seqStatus.SafeL2.Number, "Safe chain did not advance")
driver := sys.BatchSubmitter.TestDriver()
// stop the batch submission
err = driver.StopBatchSubmitting(context.Background())
require.NoError(t, err)
// wait for any old safe blocks being submitted / derived
time.Sleep(safeBlockInclusionDuration)
// get the initial sync status
seqStatus, err = rollupClient.SyncStatus(context.Background())
require.NoError(t, err)
// send another tx
sendTx()
time.Sleep(safeBlockInclusionDuration)
// ensure that the safe chain does not advance while the batcher is stopped
newSeqStatus, err = rollupClient.SyncStatus(context.Background())
require.NoError(t, err)
require.Equal(t, newSeqStatus.SafeL2.Number, seqStatus.SafeL2.Number, "Safe chain advanced while batcher was stopped")
// start the batch submission
err = driver.StartBatchSubmitting()
require.NoError(t, err)
time.Sleep(safeBlockInclusionDuration)
// send a third tx
receipt = sendTx()
// wait until the block the tx was first included in shows up in the safe chain on the verifier
_, err = geth.WaitForBlock(receipt.BlockNumber, l2Verif, safeBlockInclusionDuration)
require.NoError(t, err, "Waiting for block on verifier")
require.NoError(t, wait.ForProcessingFullBatch(context.Background(), rollupClient))
// ensure that the safe chain advances after restarting the batcher
newSeqStatus, err = rollupClient.SyncStatus(context.Background())
require.NoError(t, err)
require.Greater(t, newSeqStatus.SafeL2.Number, seqStatus.SafeL2.Number, "Safe chain did not advance after batcher was restarted")
}
package op_e2e package e2esys
import ( import (
"encoding/json" "encoding/json"
......
package op_e2e package e2esys
import ( import (
"context" "context"
...@@ -431,25 +431,25 @@ func (sys *System) Close() { ...@@ -431,25 +431,25 @@ func (sys *System) Close() {
require.NoError(sys.t, combinedErr, "Failed to stop system") require.NoError(sys.t, combinedErr, "Failed to stop system")
} }
type systemConfigHook func(sCfg *SystemConfig, s *System) type SystemConfigHook func(sCfg *SystemConfig, s *System)
type SystemConfigOption struct { type SystemConfigOption struct {
key string Key string
role string Role string
action systemConfigHook Action SystemConfigHook
} }
type SystemConfigOptions struct { type SystemConfigOptions struct {
opts map[string]systemConfigHook opts map[string]SystemConfigHook
} }
func NewSystemConfigOptions(_opts []SystemConfigOption) (SystemConfigOptions, error) { func NewSystemConfigOptions(_opts []SystemConfigOption) (SystemConfigOptions, error) {
opts := make(map[string]systemConfigHook) opts := make(map[string]SystemConfigHook)
for _, opt := range _opts { for _, opt := range _opts {
if _, ok := opts[opt.key+":"+opt.role]; ok { if _, ok := opts[opt.Key+":"+opt.Role]; ok {
return SystemConfigOptions{}, fmt.Errorf("duplicate option for key %s and role %s", opt.key, opt.role) return SystemConfigOptions{}, fmt.Errorf("duplicate option for key %s and role %s", opt.Key, opt.Role)
} }
opts[opt.key+":"+opt.role] = opt.action opts[opt.Key+":"+opt.Role] = opt.Action
} }
return SystemConfigOptions{ return SystemConfigOptions{
...@@ -457,7 +457,7 @@ func NewSystemConfigOptions(_opts []SystemConfigOption) (SystemConfigOptions, er ...@@ -457,7 +457,7 @@ func NewSystemConfigOptions(_opts []SystemConfigOption) (SystemConfigOptions, er
}, nil }, nil
} }
func (s *SystemConfigOptions) Get(key, role string) (systemConfigHook, bool) { func (s *SystemConfigOptions) Get(key, role string) (SystemConfigHook, bool) {
v, ok := s.opts[key+":"+role] v, ok := s.opts[key+":"+role]
return v, ok return v, ok
} }
...@@ -643,8 +643,8 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste ...@@ -643,8 +643,8 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
// TODO: refactor testing to allow use of in-process rpc connections instead // TODO: refactor testing to allow use of in-process rpc connections instead
// of only websockets (which are required for external eth client tests). // of only websockets (which are required for external eth client tests).
for name, nodeCfg := range cfg.Nodes { for name, nodeCfg := range cfg.Nodes {
configureL1(nodeCfg, sys.EthInstances[RoleL1], sys.L1BeaconEndpoint()) ConfigureL1(nodeCfg, sys.EthInstances[RoleL1], sys.L1BeaconEndpoint())
configureL2(nodeCfg, sys.EthInstances[name], cfg.JWTSecret) ConfigureL2(nodeCfg, sys.EthInstances[name], cfg.JWTSecret)
} }
l1Client := sys.NodeClient(RoleL1) l1Client := sys.NodeClient(RoleL1)
...@@ -662,7 +662,7 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste ...@@ -662,7 +662,7 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
if p, ok := p2pNodes[name]; ok { if p, ok := p2pNodes[name]; ok {
return p, nil return p, nil
} }
h, err := sys.newMockNetPeer() h, err := sys.NewMockNetPeer()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to init p2p host for node %s", name) return nil, fmt.Errorf("failed to init p2p host for node %s", name)
} }
...@@ -883,7 +883,7 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste ...@@ -883,7 +883,7 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
var blackholeIP6 = net.ParseIP("100::") var blackholeIP6 = net.ParseIP("100::")
// mocknet doesn't allow us to add a peerstore without fully creating the peer ourselves // mocknet doesn't allow us to add a peerstore without fully creating the peer ourselves
func (sys *System) newMockNetPeer() (host.Host, error) { func (sys *System) NewMockNetPeer() (host.Host, error) {
sk, _, err := ic.GenerateECDSAKeyPair(rand.Reader) sk, _, err := ic.GenerateECDSAKeyPair(rand.Reader)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -940,7 +940,7 @@ func (sys *System) TestAccount(idx int) *ecdsa.PrivateKey { ...@@ -940,7 +940,7 @@ func (sys *System) TestAccount(idx int) *ecdsa.PrivateKey {
} }
} }
func configureL1(rollupNodeCfg *rollupNode.Config, l1Node services.EthInstance, beaconEndpoint endpoint.RestHTTP) { func ConfigureL1(rollupNodeCfg *rollupNode.Config, l1Node services.EthInstance, beaconEndpoint endpoint.RestHTTP) {
rollupNodeCfg.L1 = &rollupNode.L1EndpointConfig{ rollupNodeCfg.L1 = &rollupNode.L1EndpointConfig{
L1NodeAddr: endpoint.SelectRPC(EnvRPCPreference(), l1Node.UserRPC()), L1NodeAddr: endpoint.SelectRPC(EnvRPCPreference(), l1Node.UserRPC()),
L1TrustRPC: false, L1TrustRPC: false,
...@@ -955,7 +955,7 @@ func configureL1(rollupNodeCfg *rollupNode.Config, l1Node services.EthInstance, ...@@ -955,7 +955,7 @@ func configureL1(rollupNodeCfg *rollupNode.Config, l1Node services.EthInstance,
} }
} }
func configureL2(rollupNodeCfg *rollupNode.Config, l2Node services.EthInstance, jwtSecret [32]byte) { func ConfigureL2(rollupNodeCfg *rollupNode.Config, l2Node services.EthInstance, jwtSecret [32]byte) {
rollupNodeCfg.L2 = &rollupNode.L2EndpointConfig{ rollupNodeCfg.L2 = &rollupNode.L2EndpointConfig{
L2EngineAddr: endpoint.SelectRPC(EnvRPCPreference(), l2Node.AuthRPC()), L2EngineAddr: endpoint.SelectRPC(EnvRPCPreference(), l2Node.AuthRPC()),
L2EngineJWTSecret: jwtSecret, L2EngineJWTSecret: jwtSecret,
......
This diff is collapsed.
package fees
import (
"context"
"math"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
legacybindings "github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/predeploys"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/stretchr/testify/require"
)
// TestGasPriceOracleFeeUpdates checks that the gas price oracle cannot be locked by mis-configuring parameters.
func TestGasPriceOracleFeeUpdates(t *testing.T) {
op_e2e.InitParallel(t)
ctx, ctxCancel := context.WithCancel(context.Background())
defer ctxCancel()
maxScalars := eth.EcotoneScalars{
BaseFeeScalar: math.MaxUint32,
BlobBaseFeeScalar: math.MaxUint32,
}
var cancel context.CancelFunc
// Create our system configuration for L1/L2 and start it
cfg := e2esys.DefaultSystemConfig(t)
sys, err := cfg.Start(t)
require.NoError(t, err, "Error starting up system")
// Obtain our sequencer, verifier, and transactor keypair.
l1Client := sys.NodeClient("l1")
l2Seq := sys.NodeClient("sequencer")
// l2Verif := sys.NodeClient("verifier")
ethPrivKey := cfg.Secrets.SysCfgOwner
// Bind to the SystemConfig & GasPriceOracle contracts
sysconfig, err := legacybindings.NewSystemConfig(cfg.L1Deployments.SystemConfigProxy, l1Client)
require.NoError(t, err)
gpoContract, err := legacybindings.NewGasPriceOracleCaller(predeploys.GasPriceOracleAddr, l2Seq)
require.NoError(t, err)
// Obtain our signer.
opts, err := bind.NewKeyedTransactorWithChainID(ethPrivKey, cfg.L1ChainIDBig())
require.NoError(t, err)
// Define our L1 transaction timeout duration.
txTimeoutDuration := 10 * time.Duration(cfg.DeployConfig.L1BlockTime) * time.Second
// Update the gas config, wait for it to show up on L2, & verify that it was set as intended
opts.Context, cancel = context.WithTimeout(ctx, txTimeoutDuration)
tx, err := sysconfig.SetGasConfigEcotone(opts, maxScalars.BaseFeeScalar, maxScalars.BlobBaseFeeScalar)
cancel()
require.NoError(t, err, "SetGasConfigEcotone update tx")
receipt, err := wait.ForReceiptOK(ctx, l1Client, tx.Hash())
require.NoError(t, err, "Waiting for sysconfig set gas config update tx")
_, err = geth.WaitForL1OriginOnL2(sys.RollupConfig, receipt.BlockNumber.Uint64(), l2Seq, txTimeoutDuration)
require.NoError(t, err, "waiting for L2 block to include the sysconfig update")
baseFeeScalar, err := gpoContract.BaseFeeScalar(&bind.CallOpts{})
require.NoError(t, err, "reading base fee scalar")
require.Equal(t, baseFeeScalar, maxScalars.BaseFeeScalar)
blobBaseFeeScalar, err := gpoContract.BlobBaseFeeScalar(&bind.CallOpts{})
require.NoError(t, err, "reading blob base fee scalar")
require.Equal(t, blobBaseFeeScalar, maxScalars.BlobBaseFeeScalar)
// Now modify the scalar value & ensure that the gas params can be modified
normalScalars := eth.EcotoneScalars{
BaseFeeScalar: 1e6,
BlobBaseFeeScalar: 1e6,
}
opts.Context, cancel = context.WithTimeout(context.Background(), txTimeoutDuration)
tx, err = sysconfig.SetGasConfigEcotone(opts, normalScalars.BaseFeeScalar, normalScalars.BlobBaseFeeScalar)
cancel()
require.NoError(t, err, "SetGasConfigEcotone update tx")
receipt, err = wait.ForReceiptOK(ctx, l1Client, tx.Hash())
require.NoError(t, err, "Waiting for sysconfig set gas config update tx")
_, err = geth.WaitForL1OriginOnL2(sys.RollupConfig, receipt.BlockNumber.Uint64(), l2Seq, txTimeoutDuration)
require.NoError(t, err, "waiting for L2 block to include the sysconfig update")
baseFeeScalar, err = gpoContract.BaseFeeScalar(&bind.CallOpts{})
require.NoError(t, err, "reading base fee scalar")
require.Equal(t, baseFeeScalar, normalScalars.BaseFeeScalar)
blobBaseFeeScalar, err = gpoContract.BlobBaseFeeScalar(&bind.CallOpts{})
require.NoError(t, err, "reading blob base fee scalar")
require.Equal(t, blobBaseFeeScalar, normalScalars.BlobBaseFeeScalar)
}
package fees
import (
"context"
"fmt"
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/stretchr/testify/require"
)
func L1InfoFromState(ctx context.Context, contract *bindings.L1Block, l2Number *big.Int, ecotone bool) (*derive.L1BlockInfo, error) {
var err error
out := &derive.L1BlockInfo{}
opts := bind.CallOpts{
BlockNumber: l2Number,
Context: ctx,
}
out.Number, err = contract.Number(&opts)
if err != nil {
return nil, fmt.Errorf("failed to get number: %w", err)
}
out.Time, err = contract.Timestamp(&opts)
if err != nil {
return nil, fmt.Errorf("failed to get timestamp: %w", err)
}
out.BaseFee, err = contract.Basefee(&opts)
if err != nil {
return nil, fmt.Errorf("failed to get base fee: %w", err)
}
blockHashBytes, err := contract.Hash(&opts)
if err != nil {
return nil, fmt.Errorf("failed to get block hash: %w", err)
}
out.BlockHash = common.BytesToHash(blockHashBytes[:])
out.SequenceNumber, err = contract.SequenceNumber(&opts)
if err != nil {
return nil, fmt.Errorf("failed to get sequence number: %w", err)
}
if !ecotone {
overhead, err := contract.L1FeeOverhead(&opts)
if err != nil {
return nil, fmt.Errorf("failed to get l1 fee overhead: %w", err)
}
out.L1FeeOverhead = eth.Bytes32(common.BigToHash(overhead))
scalar, err := contract.L1FeeScalar(&opts)
if err != nil {
return nil, fmt.Errorf("failed to get l1 fee scalar: %w", err)
}
out.L1FeeScalar = eth.Bytes32(common.BigToHash(scalar))
}
batcherHash, err := contract.BatcherHash(&opts)
if err != nil {
return nil, fmt.Errorf("failed to get batch sender: %w", err)
}
out.BatcherAddr = common.BytesToAddress(batcherHash[:])
if ecotone {
blobBaseFeeScalar, err := contract.BlobBaseFeeScalar(&opts)
if err != nil {
return nil, fmt.Errorf("failed to get blob basefee scalar: %w", err)
}
out.BlobBaseFeeScalar = blobBaseFeeScalar
baseFeeScalar, err := contract.BaseFeeScalar(&opts)
if err != nil {
return nil, fmt.Errorf("failed to get basefee scalar: %w", err)
}
out.BaseFeeScalar = baseFeeScalar
blobBaseFee, err := contract.BlobBaseFee(&opts)
if err != nil {
return nil, fmt.Errorf("failed to get blob basefee: %w", err)
}
out.BlobBaseFee = blobBaseFee
}
return out, nil
}
func TestL1InfoContract(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
l1Client := sys.NodeClient("l1")
l2Seq := sys.NodeClient("sequencer")
l2Verif := sys.NodeClient("verifier")
endVerifBlockNumber := big.NewInt(4)
endSeqBlockNumber := big.NewInt(6)
endVerifBlock, err := geth.WaitForBlock(endVerifBlockNumber, l2Verif, time.Minute)
require.Nil(t, err)
endSeqBlock, err := geth.WaitForBlock(endSeqBlockNumber, l2Seq, time.Minute)
require.Nil(t, err)
seqL1Info, err := bindings.NewL1Block(cfg.L1InfoPredeployAddress, l2Seq)
require.Nil(t, err)
verifL1Info, err := bindings.NewL1Block(cfg.L1InfoPredeployAddress, l2Verif)
require.Nil(t, err)
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
fillInfoLists := func(start *types.Block, contract *bindings.L1Block, client *ethclient.Client) ([]*derive.L1BlockInfo, []*derive.L1BlockInfo) {
var txList, stateList []*derive.L1BlockInfo
for b := start; ; {
var infoFromTx *derive.L1BlockInfo
infoFromTx, err := derive.L1BlockInfoFromBytes(sys.RollupConfig, b.Time(), b.Transactions()[0].Data())
require.NoError(t, err)
txList = append(txList, infoFromTx)
ecotone := sys.RollupConfig.IsEcotone(b.Time()) && !sys.RollupConfig.IsEcotoneActivationBlock(b.Time())
infoFromState, err := L1InfoFromState(ctx, contract, b.Number(), ecotone)
require.Nil(t, err)
stateList = append(stateList, infoFromState)
// Genesis L2 block contains no L1 Deposit TX
if b.NumberU64() == 1 {
return txList, stateList
}
b, err = client.BlockByHash(ctx, b.ParentHash())
require.Nil(t, err)
}
}
l1InfosFromSequencerTransactions, l1InfosFromSequencerState := fillInfoLists(endSeqBlock, seqL1Info, l2Seq)
l1InfosFromVerifierTransactions, l1InfosFromVerifierState := fillInfoLists(endVerifBlock, verifL1Info, l2Verif)
l1blocks := make(map[common.Hash]*derive.L1BlockInfo)
maxL1Hash := l1InfosFromSequencerTransactions[0].BlockHash
for h := maxL1Hash; ; {
b, err := l1Client.BlockByHash(ctx, h)
require.Nil(t, err)
l1blocks[h] = &derive.L1BlockInfo{
Number: b.NumberU64(),
Time: b.Time(),
BaseFee: b.BaseFee(),
BlockHash: h,
SequenceNumber: 0, // ignored, will be overwritten
BatcherAddr: sys.RollupConfig.Genesis.SystemConfig.BatcherAddr,
}
if sys.RollupConfig.IsEcotone(b.Time()) && !sys.RollupConfig.IsEcotoneActivationBlock(b.Time()) {
scalars, err := sys.RollupConfig.Genesis.SystemConfig.EcotoneScalars()
require.NoError(t, err)
l1blocks[h].BlobBaseFeeScalar = scalars.BlobBaseFeeScalar
l1blocks[h].BaseFeeScalar = scalars.BaseFeeScalar
if excess := b.ExcessBlobGas(); excess != nil {
l1blocks[h].BlobBaseFee = eip4844.CalcBlobFee(*excess)
} else {
l1blocks[h].BlobBaseFee = big.NewInt(1)
}
} else {
l1blocks[h].L1FeeOverhead = sys.RollupConfig.Genesis.SystemConfig.Overhead
l1blocks[h].L1FeeScalar = sys.RollupConfig.Genesis.SystemConfig.Scalar
}
h = b.ParentHash()
if b.NumberU64() == 0 {
break
}
}
checkInfoList := func(name string, list []*derive.L1BlockInfo) {
for _, info := range list {
if expected, ok := l1blocks[info.BlockHash]; ok {
expected.SequenceNumber = info.SequenceNumber // the seq nr is not part of the L1 info we know in advance, so we ignore it.
require.Equal(t, expected, info)
} else {
t.Fatalf("Did not find block hash for L1 Info: %v in test %s", info, name)
}
}
}
checkInfoList("On sequencer with tx", l1InfosFromSequencerTransactions)
checkInfoList("On sequencer with state", l1InfosFromSequencerState)
checkInfoList("On verifier with tx", l1InfosFromVerifierTransactions)
checkInfoList("On verifier with state", l1InfosFromVerifierState)
}
package op_e2e package fjord
import ( import (
"context" "context"
"testing" "testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
...@@ -16,7 +20,7 @@ import ( ...@@ -16,7 +20,7 @@ import (
// TestCheckFjordScript ensures the op-chain-ops/cmd/check-fjord script runs successfully // TestCheckFjordScript ensures the op-chain-ops/cmd/check-fjord script runs successfully
// against a test chain with the fjord hardfork activated/unactivated // against a test chain with the fjord hardfork activated/unactivated
func TestCheckFjordScript(t *testing.T) { func TestCheckFjordScript(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
genesisActivation := hexutil.Uint64(0) genesisActivation := hexutil.Uint64(0)
tests := []struct { tests := []struct {
name string name string
...@@ -37,11 +41,11 @@ func TestCheckFjordScript(t *testing.T) { ...@@ -37,11 +41,11 @@ func TestCheckFjordScript(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
log := testlog.Logger(t, log.LevelInfo) log := testlog.Logger(t, log.LevelInfo)
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
cfg.DeployConfig.L1CancunTimeOffset = &genesisActivation cfg.DeployConfig.L1CancunTimeOffset = &genesisActivation
cfg.DeployConfig.L2GenesisRegolithTimeOffset = &genesisActivation cfg.DeployConfig.L2GenesisRegolithTimeOffset = &genesisActivation
cfg.DeployConfig.L2GenesisCanyonTimeOffset = &genesisActivation cfg.DeployConfig.L2GenesisCanyonTimeOffset = &genesisActivation
......
package fjord
import (
"testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
)
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
package op_e2e package gastoken
import ( import (
"context" "context"
...@@ -7,6 +7,11 @@ import ( ...@@ -7,6 +7,11 @@ import (
"testing" "testing"
"time" "time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/receipts" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/receipts"
...@@ -22,10 +27,14 @@ import ( ...@@ -22,10 +27,14 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
func TestCustomGasToken(t *testing.T) { func TestCustomGasToken(t *testing.T) {
InitParallel(t, SkipOnFaultProofs) // Custom Gas Token feature is not yet compatible with fault proofs op_e2e.InitParallel(t, op_e2e.SkipOnFaultProofs) // Custom Gas Token feature is not yet compatible with fault proofs
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
offset := hexutil.Uint64(0) offset := hexutil.Uint64(0)
cfg.DeployConfig.L2GenesisRegolithTimeOffset = &offset cfg.DeployConfig.L2GenesisRegolithTimeOffset = &offset
cfg.DeployConfig.L1CancunTimeOffset = &offset cfg.DeployConfig.L1CancunTimeOffset = &offset
...@@ -143,7 +152,7 @@ func TestCustomGasToken(t *testing.T) { ...@@ -143,7 +152,7 @@ func TestCustomGasToken(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
withdrawAmount := big.NewInt(5) withdrawAmount := big.NewInt(5)
tx, receipt := SendWithdrawal(t, cfg, l2Seq, cfg.Secrets.Alice, func(opts *WithdrawalTxOpts) { tx, receipt := helpers.SendWithdrawal(t, cfg, l2Seq, cfg.Secrets.Alice, func(opts *helpers.WithdrawalTxOpts) {
opts.Value = withdrawAmount opts.Value = withdrawAmount
opts.VerifyOnClients(l2Verif) opts.VerifyOnClients(l2Verif)
}) })
...@@ -157,7 +166,7 @@ func TestCustomGasToken(t *testing.T) { ...@@ -157,7 +166,7 @@ func TestCustomGasToken(t *testing.T) {
// Take fee into account // Take fee into account
diff := new(big.Int).Sub(startBalanceBeforeWithdrawal, endBalanceAfterWithdrawal) diff := new(big.Int).Sub(startBalanceBeforeWithdrawal, endBalanceAfterWithdrawal)
fees := calcGasFees(receipt.GasUsed, tx.GasTipCap(), tx.GasFeeCap(), header.BaseFee) fees := helpers.CalcGasFees(receipt.GasUsed, tx.GasTipCap(), tx.GasFeeCap(), header.BaseFee)
fees = fees.Add(fees, receipt.L1Fee) fees = fees.Add(fees, receipt.L1Fee)
diff = diff.Sub(diff, fees) diff = diff.Sub(diff, fees)
require.Equal(t, withdrawAmount, diff) require.Equal(t, withdrawAmount, diff)
...@@ -169,7 +178,7 @@ func TestCustomGasToken(t *testing.T) { ...@@ -169,7 +178,7 @@ func TestCustomGasToken(t *testing.T) {
startETHBalanceBeforeFinalize, err := l1Client.BalanceAt(context.Background(), fromAddr, nil) startETHBalanceBeforeFinalize, err := l1Client.BalanceAt(context.Background(), fromAddr, nil)
require.NoError(t, err) require.NoError(t, err)
proveReceipt, finalizeReceipt, resolveClaimReceipt, resolveReceipt := ProveAndFinalizeWithdrawal(t, cfg, sys, "verifier", ethPrivKey, receipt) proveReceipt, finalizeReceipt, resolveClaimReceipt, resolveReceipt := helpers.ProveAndFinalizeWithdrawal(t, cfg, sys, "verifier", ethPrivKey, receipt)
// Verify L1 ETH balance change // Verify L1 ETH balance change
proveFee := new(big.Int).Mul(new(big.Int).SetUint64(proveReceipt.GasUsed), proveReceipt.EffectiveGasPrice) proveFee := new(big.Int).Mul(new(big.Int).SetUint64(proveReceipt.GasUsed), proveReceipt.EffectiveGasPrice)
...@@ -318,7 +327,7 @@ func TestCustomGasToken(t *testing.T) { ...@@ -318,7 +327,7 @@ func TestCustomGasToken(t *testing.T) {
withdrawnAmount := it.Event.Value withdrawnAmount := it.Event.Value
// Finalize the withdrawal // Finalize the withdrawal
proveReceipt, finalizeReceipt, resolveClaimReceipt, resolveReceipt := ProveAndFinalizeWithdrawal(t, cfg, sys, "verifier", cfg.Secrets.Alice, receipt) proveReceipt, finalizeReceipt, resolveClaimReceipt, resolveReceipt := helpers.ProveAndFinalizeWithdrawal(t, cfg, sys, "verifier", cfg.Secrets.Alice, receipt)
require.Equal(t, types.ReceiptStatusSuccessful, proveReceipt.Status) require.Equal(t, types.ReceiptStatusSuccessful, proveReceipt.Status)
require.Equal(t, types.ReceiptStatusSuccessful, finalizeReceipt.Status) require.Equal(t, types.ReceiptStatusSuccessful, finalizeReceipt.Status)
if e2eutils.UseFaultProofs() { if e2eutils.UseFaultProofs() {
...@@ -462,7 +471,7 @@ func callViaSafe(opts *bind.TransactOpts, client *ethclient.Client, safeAddress ...@@ -462,7 +471,7 @@ func callViaSafe(opts *bind.TransactOpts, client *ethclient.Client, safeAddress
// setCustomGasToeken enables the Custom Gas Token feature on a chain where it wasn't enabled at genesis. // setCustomGasToeken enables the Custom Gas Token feature on a chain where it wasn't enabled at genesis.
// It reads existing parameters from the SystemConfig contract, inserts the supplied cgtAddress and reinitializes that contract. // It reads existing parameters from the SystemConfig contract, inserts the supplied cgtAddress and reinitializes that contract.
// To do this it uses the ProxyAdmin and StorageSetter from the supplied cfg. // To do this it uses the ProxyAdmin and StorageSetter from the supplied cfg.
func setCustomGasToken(t *testing.T, cfg SystemConfig, sys *System, cgtAddress common.Address) { func setCustomGasToken(t *testing.T, cfg e2esys.SystemConfig, sys *e2esys.System, cgtAddress common.Address) {
l1Client := sys.NodeClient("l1") l1Client := sys.NodeClient("l1")
deployerOpts, err := bind.NewKeyedTransactorWithChainID(cfg.Secrets.Deployer, cfg.L1ChainIDBig()) deployerOpts, err := bind.NewKeyedTransactorWithChainID(cfg.Secrets.Deployer, cfg.L1ChainIDBig())
require.NoError(t, err) require.NoError(t, err)
......
package op_e2e package helpers
import ( import (
"context" "context"
...@@ -7,6 +7,8 @@ import ( ...@@ -7,6 +7,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/bindings"
...@@ -24,7 +26,7 @@ import ( ...@@ -24,7 +26,7 @@ import (
// The L2 transaction options can be configured by modifying the DepositTxOps value supplied to applyL2Opts // The L2 transaction options can be configured by modifying the DepositTxOps value supplied to applyL2Opts
// Will verify that the transaction is included with the expected status on L1 and L2 // Will verify that the transaction is included with the expected status on L1 and L2
// Returns the receipt of the L2 transaction // Returns the receipt of the L2 transaction
func SendDepositTx(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, l2Client *ethclient.Client, l1Opts *bind.TransactOpts, applyL2Opts DepositTxOptsFn) *types.Receipt { func SendDepositTx(t *testing.T, cfg e2esys.SystemConfig, l1Client *ethclient.Client, l2Client *ethclient.Client, l1Opts *bind.TransactOpts, applyL2Opts DepositTxOptsFn) *types.Receipt {
l2Opts := defaultDepositTxOpts(l1Opts) l2Opts := defaultDepositTxOpts(l1Opts)
applyL2Opts(l2Opts) applyL2Opts(l2Opts)
...@@ -115,7 +117,7 @@ func SendL2TxWithID(t *testing.T, chainID *big.Int, l2Client *ethclient.Client, ...@@ -115,7 +117,7 @@ func SendL2TxWithID(t *testing.T, chainID *big.Int, l2Client *ethclient.Client,
return receipt return receipt
} }
func SendL2Tx(t *testing.T, cfg SystemConfig, l2Client *ethclient.Client, privKey *ecdsa.PrivateKey, applyTxOpts TxOptsFn) *types.Receipt { func SendL2Tx(t *testing.T, cfg e2esys.SystemConfig, l2Client *ethclient.Client, privKey *ecdsa.PrivateKey, applyTxOpts TxOptsFn) *types.Receipt {
return SendL2TxWithID(t, cfg.L2ChainIDBig(), l2Client, privKey, applyTxOpts) return SendL2TxWithID(t, cfg.L2ChainIDBig(), l2Client, privKey, applyTxOpts)
} }
...@@ -152,9 +154,9 @@ func defaultTxOpts() *TxOpts { ...@@ -152,9 +154,9 @@ func defaultTxOpts() *TxOpts {
} }
} }
// calcGasFees determines the actual cost of the transaction given a specific base fee // CalcGasFees determines the actual cost of the transaction given a specific base fee
// This does not include the L1 data fee charged from L2 transactions. // This does not include the L1 data fee charged from L2 transactions.
func calcGasFees(gasUsed uint64, gasTipCap *big.Int, gasFeeCap *big.Int, baseFee *big.Int) *big.Int { func CalcGasFees(gasUsed uint64, gasTipCap *big.Int, gasFeeCap *big.Int, baseFee *big.Int) *big.Int {
x := new(big.Int).Add(gasTipCap, baseFee) x := new(big.Int).Add(gasTipCap, baseFee)
// If tip + basefee > gas fee cap, clamp it to the gas fee cap // If tip + basefee > gas fee cap, clamp it to the gas fee cap
if x.Cmp(gasFeeCap) > 0 { if x.Cmp(gasFeeCap) > 0 {
......
package op_e2e package helpers
import ( import (
"context" "context"
...@@ -8,6 +8,8 @@ import ( ...@@ -8,6 +8,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
...@@ -37,7 +39,7 @@ type ClientProvider interface { ...@@ -37,7 +39,7 @@ type ClientProvider interface {
NodeClient(name string) *ethclient.Client NodeClient(name string) *ethclient.Client
} }
func SendWithdrawal(t *testing.T, cfg SystemConfig, l2Client *ethclient.Client, privKey *ecdsa.PrivateKey, applyOpts WithdrawalTxOptsFn) (*types.Transaction, *types.Receipt) { func SendWithdrawal(t *testing.T, cfg e2esys.SystemConfig, l2Client *ethclient.Client, privKey *ecdsa.PrivateKey, applyOpts WithdrawalTxOptsFn) (*types.Transaction, *types.Receipt) {
opts := defaultWithdrawalTxOpts() opts := defaultWithdrawalTxOpts()
applyOpts(opts) applyOpts(opts)
...@@ -94,18 +96,18 @@ func defaultWithdrawalTxOpts() *WithdrawalTxOpts { ...@@ -94,18 +96,18 @@ func defaultWithdrawalTxOpts() *WithdrawalTxOpts {
} }
} }
func ProveAndFinalizeWithdrawal(t *testing.T, cfg SystemConfig, clients ClientProvider, l2NodeName string, ethPrivKey *ecdsa.PrivateKey, l2WithdrawalReceipt *types.Receipt) (*types.Receipt, *types.Receipt, *types.Receipt, *types.Receipt) { func ProveAndFinalizeWithdrawal(t *testing.T, cfg e2esys.SystemConfig, clients ClientProvider, l2NodeName string, ethPrivKey *ecdsa.PrivateKey, l2WithdrawalReceipt *types.Receipt) (*types.Receipt, *types.Receipt, *types.Receipt, *types.Receipt) {
params, proveReceipt := ProveWithdrawal(t, cfg, clients, l2NodeName, ethPrivKey, l2WithdrawalReceipt) params, proveReceipt := ProveWithdrawal(t, cfg, clients, l2NodeName, ethPrivKey, l2WithdrawalReceipt)
finalizeReceipt, resolveClaimReceipt, resolveReceipt := FinalizeWithdrawal(t, cfg, clients.NodeClient("l1"), ethPrivKey, proveReceipt, params) finalizeReceipt, resolveClaimReceipt, resolveReceipt := FinalizeWithdrawal(t, cfg, clients.NodeClient("l1"), ethPrivKey, proveReceipt, params)
return proveReceipt, finalizeReceipt, resolveClaimReceipt, resolveReceipt return proveReceipt, finalizeReceipt, resolveClaimReceipt, resolveReceipt
} }
func ProveWithdrawal(t *testing.T, cfg SystemConfig, clients ClientProvider, l2NodeName string, ethPrivKey *ecdsa.PrivateKey, l2WithdrawalReceipt *types.Receipt) (withdrawals.ProvenWithdrawalParameters, *types.Receipt) { func ProveWithdrawal(t *testing.T, cfg e2esys.SystemConfig, clients ClientProvider, l2NodeName string, ethPrivKey *ecdsa.PrivateKey, l2WithdrawalReceipt *types.Receipt) (withdrawals.ProvenWithdrawalParameters, *types.Receipt) {
// Get l2BlockNumber for proof generation // Get l2BlockNumber for proof generation
ctx, cancel := context.WithTimeout(context.Background(), 40*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 40*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel() defer cancel()
l1Client := clients.NodeClient(RoleL1) l1Client := clients.NodeClient(e2esys.RoleL1)
var blockNumber uint64 var blockNumber uint64
var err error var err error
if e2eutils.UseFaultProofs() { if e2eutils.UseFaultProofs() {
...@@ -176,7 +178,7 @@ func ProveWithdrawalParameters(ctx context.Context, proofCl withdrawals.ProofCli ...@@ -176,7 +178,7 @@ func ProveWithdrawalParameters(ctx context.Context, proofCl withdrawals.ProofCli
} }
} }
func FinalizeWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Client, privKey *ecdsa.PrivateKey, withdrawalProofReceipt *types.Receipt, params withdrawals.ProvenWithdrawalParameters) (*types.Receipt, *types.Receipt, *types.Receipt) { func FinalizeWithdrawal(t *testing.T, cfg e2esys.SystemConfig, l1Client *ethclient.Client, privKey *ecdsa.PrivateKey, withdrawalProofReceipt *types.Receipt, params withdrawals.ProvenWithdrawalParameters) (*types.Receipt, *types.Receipt, *types.Receipt) {
// Wait for finalization and then create the Finalized Withdrawal Transaction // Wait for finalization and then create the Finalized Withdrawal Transaction
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel() defer cancel()
......
package p2p
import (
"context"
"math/big"
"slices"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/opnode"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
rollupNode "github.com/ethereum-optimism/optimism/op-node/node"
"github.com/ethereum-optimism/optimism/op-node/p2p"
"github.com/ethereum-optimism/optimism/op-node/rollup/driver"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/retry"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/stretchr/testify/require"
)
// TestSystemMockP2P sets up a L1 Geth node, a rollup node, and a L2 geth node and then confirms that
// the nodes can sync L2 blocks before they are confirmed on L1.
func TestSystemMockP2P(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
// Disable batcher, so we don't sync from L1 & set a large sequence window so we only have unsafe blocks
cfg.DisableBatcher = true
cfg.DeployConfig.SequencerWindowSize = 100_000
cfg.DeployConfig.MaxSequencerDrift = 100_000
// disable at the start, so we don't miss any gossiped blocks.
cfg.Nodes["sequencer"].Driver.SequencerStopped = true
// connect the nodes
cfg.P2PTopology = map[string][]string{
"verifier": {"sequencer"},
}
var published, received []common.Hash
seqTracer, verifTracer := new(opnode.FnTracer), new(opnode.FnTracer)
seqTracer.OnPublishL2PayloadFn = func(ctx context.Context, payload *eth.ExecutionPayloadEnvelope) {
published = append(published, payload.ExecutionPayload.BlockHash)
}
verifTracer.OnUnsafeL2PayloadFn = func(ctx context.Context, from peer.ID, payload *eth.ExecutionPayloadEnvelope) {
received = append(received, payload.ExecutionPayload.BlockHash)
}
cfg.Nodes["sequencer"].Tracer = seqTracer
cfg.Nodes["verifier"].Tracer = verifTracer
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
// Enable the sequencer now that everyone is ready to receive payloads.
rollupClient := sys.RollupClient("sequencer")
verifierPeerID := sys.RollupNodes["verifier"].P2P().Host().ID()
check := func() bool {
sequencerBlocksTopicPeers := sys.RollupNodes["sequencer"].P2P().GossipOut().AllBlockTopicsPeers()
return slices.Contains[[]peer.ID](sequencerBlocksTopicPeers, verifierPeerID)
}
// poll to see if the verifier node is connected & meshed on gossip.
// Without this verifier, we shouldn't start sending blocks around, or we'll miss them and fail the test.
backOffStrategy := retry.Exponential()
for i := 0; i < 10; i++ {
if check() {
break
}
time.Sleep(backOffStrategy.Duration(i))
}
require.True(t, check(), "verifier must be meshed with sequencer for gossip test to proceed")
require.NoError(t, rollupClient.StartSequencer(context.Background(), sys.L2GenesisCfg.ToBlock().Hash()))
l2Seq := sys.NodeClient("sequencer")
l2Verif := sys.NodeClient("verifier")
// Transactor Account
ethPrivKey := cfg.Secrets.Alice
// Submit TX to L2 sequencer node
receiptSeq := helpers.SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *helpers.TxOpts) {
opts.ToAddr = &common.Address{0xff, 0xff}
opts.Value = big.NewInt(1_000_000_000)
// Wait until the block it was first included in shows up in the safe chain on the verifier
opts.VerifyOnClients(l2Verif)
})
// Verify that everything that was received was published
require.GreaterOrEqual(t, len(published), len(received))
require.Subset(t, published, received)
// Verify that the tx was received via p2p
require.Contains(t, received, receiptSeq.BlockHash)
}
// TestSystemDenseTopology sets up a dense p2p topology with 3 verifier nodes and 1 sequencer node.
func TestSystemDenseTopology(t *testing.T) {
t.Skip("Skipping dense topology test to avoid flakiness. @refcell address in p2p scoring pr.")
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
// slow down L1 blocks so we can see the L2 blocks arrive well before the L1 blocks do.
// Keep the seq window small so the L2 chain is started quick
cfg.DeployConfig.L1BlockTime = 10
// Append additional nodes to the system to construct a dense p2p network
cfg.Nodes["verifier2"] = &rollupNode.Config{
Driver: driver.Config{
VerifierConfDepth: 0,
SequencerConfDepth: 0,
SequencerEnabled: false,
},
L1EpochPollInterval: time.Second * 4,
}
cfg.Nodes["verifier3"] = &rollupNode.Config{
Driver: driver.Config{
VerifierConfDepth: 0,
SequencerConfDepth: 0,
SequencerEnabled: false,
},
L1EpochPollInterval: time.Second * 4,
}
cfg.Loggers["verifier2"] = testlog.Logger(t, log.LevelInfo).New("role", "verifier")
cfg.Loggers["verifier3"] = testlog.Logger(t, log.LevelInfo).New("role", "verifier")
// connect the nodes
cfg.P2PTopology = map[string][]string{
"verifier": {"sequencer", "verifier2", "verifier3"},
"verifier2": {"sequencer", "verifier", "verifier3"},
"verifier3": {"sequencer", "verifier", "verifier2"},
}
// Set peer scoring for each node, but without banning
for _, node := range cfg.Nodes {
params, err := p2p.GetScoringParams("light", &node.Rollup)
require.NoError(t, err)
node.P2P = &p2p.Config{
ScoringParams: params,
BanningEnabled: false,
}
}
var published, received1, received2, received3 []common.Hash
seqTracer, verifTracer, verifTracer2, verifTracer3 := new(opnode.FnTracer), new(opnode.FnTracer), new(opnode.FnTracer), new(opnode.FnTracer)
seqTracer.OnPublishL2PayloadFn = func(ctx context.Context, payload *eth.ExecutionPayloadEnvelope) {
published = append(published, payload.ExecutionPayload.BlockHash)
}
verifTracer.OnUnsafeL2PayloadFn = func(ctx context.Context, from peer.ID, payload *eth.ExecutionPayloadEnvelope) {
received1 = append(received1, payload.ExecutionPayload.BlockHash)
}
verifTracer2.OnUnsafeL2PayloadFn = func(ctx context.Context, from peer.ID, payload *eth.ExecutionPayloadEnvelope) {
received2 = append(received2, payload.ExecutionPayload.BlockHash)
}
verifTracer3.OnUnsafeL2PayloadFn = func(ctx context.Context, from peer.ID, payload *eth.ExecutionPayloadEnvelope) {
received3 = append(received3, payload.ExecutionPayload.BlockHash)
}
cfg.Nodes["sequencer"].Tracer = seqTracer
cfg.Nodes["verifier"].Tracer = verifTracer
cfg.Nodes["verifier2"].Tracer = verifTracer2
cfg.Nodes["verifier3"].Tracer = verifTracer3
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
l2Seq := sys.NodeClient("sequencer")
l2Verif := sys.NodeClient("verifier")
l2Verif2 := sys.NodeClient("verifier2")
l2Verif3 := sys.NodeClient("verifier3")
// Transactor Account
ethPrivKey := cfg.Secrets.Alice
// Submit TX to L2 sequencer node
receiptSeq := helpers.SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *helpers.TxOpts) {
opts.ToAddr = &common.Address{0xff, 0xff}
opts.Value = big.NewInt(1_000_000_000)
// Wait until the block it was first included in shows up in the safe chain on the verifiers
opts.VerifyOnClients(l2Verif, l2Verif2, l2Verif3)
})
// Verify that everything that was received was published
require.GreaterOrEqual(t, len(published), len(received1))
require.GreaterOrEqual(t, len(published), len(received2))
require.GreaterOrEqual(t, len(published), len(received3))
require.ElementsMatch(t, published, received1[:len(published)])
require.ElementsMatch(t, published, received2[:len(published)])
require.ElementsMatch(t, published, received3[:len(published)])
// Verify that the tx was received via p2p
require.Contains(t, received1, receiptSeq.BlockHash)
require.Contains(t, received2, receiptSeq.BlockHash)
require.Contains(t, received3, receiptSeq.BlockHash)
}
package p2p
import (
"testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
)
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
package p2p
import (
"context"
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/opnode"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-node/metrics"
rollupNode "github.com/ethereum-optimism/optimism/op-node/node"
"github.com/ethereum-optimism/optimism/op-node/p2p"
"github.com/ethereum-optimism/optimism/op-node/rollup/driver"
"github.com/ethereum-optimism/optimism/op-service/endpoint"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/oppprof"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/stretchr/testify/require"
)
func TestSystemP2PAltSync(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
// remove default verifier node
delete(cfg.Nodes, "verifier")
// Add more verifier nodes
cfg.Nodes["alice"] = &rollupNode.Config{
Driver: driver.Config{
VerifierConfDepth: 0,
SequencerConfDepth: 0,
SequencerEnabled: false,
},
L1EpochPollInterval: time.Second * 4,
}
cfg.Nodes["bob"] = &rollupNode.Config{
Driver: driver.Config{
VerifierConfDepth: 0,
SequencerConfDepth: 0,
SequencerEnabled: false,
},
L1EpochPollInterval: time.Second * 4,
}
cfg.Loggers["alice"] = testlog.Logger(t, log.LevelInfo).New("role", "alice")
cfg.Loggers["bob"] = testlog.Logger(t, log.LevelInfo).New("role", "bob")
// connect the nodes
cfg.P2PTopology = map[string][]string{
"sequencer": {"alice", "bob"},
"alice": {"sequencer", "bob"},
"bob": {"alice", "sequencer"},
}
// Enable the P2P req-resp based sync
cfg.P2PReqRespSync = true
// Disable batcher, so there will not be any L1 data to sync from
cfg.DisableBatcher = true
var published []string
seqTracer := new(opnode.FnTracer)
// The sequencer still publishes the blocks to the tracer, even if they do not reach the network due to disabled P2P
seqTracer.OnPublishL2PayloadFn = func(ctx context.Context, payload *eth.ExecutionPayloadEnvelope) {
published = append(published, payload.ExecutionPayload.ID().String())
}
// Blocks are now received via the RPC based alt-sync method
cfg.Nodes["sequencer"].Tracer = seqTracer
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
l2Seq := sys.NodeClient("sequencer")
// Transactor Account
ethPrivKey := cfg.Secrets.Alice
// Submit a TX to L2 sequencer node
receiptSeq := helpers.SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *helpers.TxOpts) {
opts.ToAddr = &common.Address{0xff, 0xff}
opts.Value = big.NewInt(1_000_000_000)
})
// Gossip is able to respond to IWANT messages for the duration of heartbeat_time * message_window = 0.5 * 12 = 6
// Wait till we pass that, and then we'll have missed some blocks that cannot be retrieved in any way from gossip
time.Sleep(time.Second * 10)
// set up our syncer node, connect it to alice/bob
cfg.Loggers["syncer"] = testlog.Logger(t, log.LevelInfo).New("role", "syncer")
// Create a peer, and hook up alice and bob
h, err := sys.NewMockNetPeer()
require.NoError(t, err)
_, err = sys.Mocknet.LinkPeers(sys.RollupNodes["alice"].P2P().Host().ID(), h.ID())
require.NoError(t, err)
_, err = sys.Mocknet.LinkPeers(sys.RollupNodes["bob"].P2P().Host().ID(), h.ID())
require.NoError(t, err)
// Configure the new rollup node that'll be syncing
var syncedPayloads []string
syncNodeCfg := &rollupNode.Config{
Driver: driver.Config{VerifierConfDepth: 0},
Rollup: *sys.RollupConfig,
P2PSigner: nil,
RPC: rollupNode.RPCConfig{
ListenAddr: "127.0.0.1",
ListenPort: 0,
EnableAdmin: true,
},
P2P: &p2p.Prepared{HostP2P: h, EnableReqRespSync: true},
Metrics: rollupNode.MetricsConfig{Enabled: false}, // no metrics server
Pprof: oppprof.CLIConfig{},
L1EpochPollInterval: time.Second * 10,
Tracer: &opnode.FnTracer{
OnUnsafeL2PayloadFn: func(ctx context.Context, from peer.ID, payload *eth.ExecutionPayloadEnvelope) {
syncedPayloads = append(syncedPayloads, payload.ExecutionPayload.ID().String())
},
},
}
e2esys.ConfigureL1(syncNodeCfg, sys.EthInstances["l1"], sys.L1BeaconEndpoint())
syncerL2Engine, err := geth.InitL2("syncer", sys.L2GenesisCfg, cfg.JWTFilePath)
require.NoError(t, err)
require.NoError(t, syncerL2Engine.Node.Start())
e2esys.ConfigureL2(syncNodeCfg, syncerL2Engine, cfg.JWTSecret)
syncerNode, err := rollupNode.New(ctx, syncNodeCfg, cfg.Loggers["syncer"], "", metrics.NewMetrics(""))
require.NoError(t, err)
err = syncerNode.Start(ctx)
require.NoError(t, err)
defer func() {
require.NoError(t, syncerNode.Stop(ctx))
}()
// connect alice and bob to our new syncer node
_, err = sys.Mocknet.ConnectPeers(sys.RollupNodes["alice"].P2P().Host().ID(), syncerNode.P2P().Host().ID())
require.NoError(t, err)
_, err = sys.Mocknet.ConnectPeers(sys.RollupNodes["bob"].P2P().Host().ID(), syncerNode.P2P().Host().ID())
require.NoError(t, err)
rpc := syncerL2Engine.UserRPC().(endpoint.ClientRPC).ClientRPC()
l2Verif := ethclient.NewClient(rpc)
// It may take a while to sync, but eventually we should see the sequenced data show up
receiptVerif, err := wait.ForReceiptOK(ctx, l2Verif, receiptSeq.TxHash)
require.Nil(t, err, "Waiting for L2 tx on verifier")
require.Equal(t, receiptSeq, receiptVerif)
// Verify that the tx was received via P2P sync
require.Contains(t, syncedPayloads, eth.BlockID{Hash: receiptVerif.BlockHash, Number: receiptVerif.BlockNumber.Uint64()}.String())
// Verify that everything that was received was published
require.GreaterOrEqual(t, len(published), len(syncedPayloads))
require.Subset(t, published, syncedPayloads)
}
package op_e2e package p2p
import ( import (
"math/big" "math/big"
"testing" "testing"
"time" "time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestTxGossip(t *testing.T) { func TestTxGossip(t *testing.T) {
InitParallel(t) op_e2e.InitParallel(t)
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
gethOpts := []geth.GethOption{ gethOpts := []geth.GethOption{
geth.WithP2P(), geth.WithP2P(),
} }
...@@ -30,7 +35,7 @@ func TestTxGossip(t *testing.T) { ...@@ -30,7 +35,7 @@ func TestTxGossip(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
// Send a transaction to the verifier and it should be gossiped to the sequencer and included in a block. // Send a transaction to the verifier and it should be gossiped to the sequencer and included in a block.
SendL2Tx(t, cfg, verifClient, cfg.Secrets.Alice, func(opts *TxOpts) { helpers.SendL2Tx(t, cfg, verifClient, cfg.Secrets.Alice, func(opts *helpers.TxOpts) {
opts.ToAddr = &common.Address{0xaa} opts.ToAddr = &common.Address{0xaa}
opts.Value = common.Big1 opts.Value = common.Big1
opts.VerifyOnClients(seqClient, verifClient) opts.VerifyOnClients(seqClient, verifClient)
......
package op_e2e package proofs
import ( import (
"context" "context"
...@@ -16,11 +16,11 @@ func BuildOpProgramClient(t *testing.T) string { ...@@ -16,11 +16,11 @@ func BuildOpProgramClient(t *testing.T) string {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel() defer cancel()
cmd := exec.CommandContext(ctx, "make", "op-program-client") cmd := exec.CommandContext(ctx, "make", "op-program-client")
cmd.Dir = "../op-program" cmd.Dir = "../../../op-program"
var out strings.Builder var out strings.Builder
cmd.Stdout = &out cmd.Stdout = &out
cmd.Stderr = &out cmd.Stderr = &out
require.NoErrorf(t, cmd.Run(), "Failed to build op-program-client: %v", &out) require.NoErrorf(t, cmd.Run(), "Failed to build op-program-client: %v", &out)
t.Log("Built op-program-client successfully") t.Log("Built op-program-client successfully")
return "../op-program/bin/op-program-client" return "../../../op-program/bin/op-program-client"
} }
package proofs
import (
"testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
)
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
package proofs
import (
"context"
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
func TestL2OutputSubmitterFaultProofs(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.SkipOnL2OO)
cfg := e2esys.DefaultSystemConfig(t)
cfg.NonFinalizedProposals = true // speed up the time till we see output proposals
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
l1Client := sys.NodeClient("l1")
rollupClient := sys.RollupClient("sequencer")
disputeGameFactory, err := bindings.NewDisputeGameFactoryCaller(cfg.L1Deployments.DisputeGameFactoryProxy, l1Client)
require.Nil(t, err)
initialGameCount, err := disputeGameFactory.GameCount(&bind.CallOpts{})
require.Nil(t, err)
l2Verif := sys.NodeClient("verifier")
_, err = geth.WaitForBlock(big.NewInt(6), l2Verif, 10*time.Duration(cfg.DeployConfig.L2BlockTime)*time.Second)
require.Nil(t, err)
timeoutCh := time.After(15 * time.Second)
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
latestGameCount, err := disputeGameFactory.GameCount(&bind.CallOpts{})
require.Nil(t, err)
if latestGameCount.Cmp(initialGameCount) > 0 {
caller := batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize)
committedL2Output, err := disputeGameFactory.GameAtIndex(&bind.CallOpts{}, new(big.Int).Sub(latestGameCount, common.Big1))
require.Nil(t, err)
proxy, err := contracts.NewFaultDisputeGameContract(context.Background(), metrics.NoopContractMetrics, committedL2Output.Proxy, caller)
require.Nil(t, err)
claim, err := proxy.GetClaim(context.Background(), 0)
require.Nil(t, err)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
_, gameBlockNumber, err := proxy.GetBlockRange(ctx)
require.Nil(t, err)
l2Output, err := rollupClient.OutputAtBlock(ctx, gameBlockNumber)
require.Nil(t, err)
require.EqualValues(t, l2Output.OutputRoot, claim.Value)
break
}
select {
case <-timeoutCh:
t.Fatalf("State root oracle not updated")
case <-ticker.C:
}
}
}
package proofs
import (
"context"
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/stretchr/testify/require"
)
func TestL2OutputSubmitter(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.SkipOnFaultProofs)
cfg := e2esys.DefaultSystemConfig(t)
cfg.NonFinalizedProposals = true // speed up the time till we see output proposals
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
l1Client := sys.NodeClient("l1")
rollupClient := sys.RollupClient("sequencer")
// OutputOracle is already deployed
l2OutputOracle, err := bindings.NewL2OutputOracleCaller(cfg.L1Deployments.L2OutputOracleProxy, l1Client)
require.Nil(t, err)
initialOutputBlockNumber, err := l2OutputOracle.LatestBlockNumber(&bind.CallOpts{})
require.Nil(t, err)
// Wait until the second output submission from L2. The output submitter submits outputs from the
// unsafe portion of the chain which gets reorged on startup. The sequencer has an out of date view
// when it creates it's first block and uses and old L1 Origin. It then does not submit a batch
// for that block and subsequently reorgs to match what the verifier derives when running the
// reconcillation process.
l2Verif := sys.NodeClient("verifier")
_, err = geth.WaitForBlock(big.NewInt(6), l2Verif, 10*time.Duration(cfg.DeployConfig.L2BlockTime)*time.Second)
require.Nil(t, err)
// Wait for batch submitter to update L2 output oracle.
timeoutCh := time.After(15 * time.Second)
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
l2ooBlockNumber, err := l2OutputOracle.LatestBlockNumber(&bind.CallOpts{})
require.Nil(t, err)
// Wait for the L2 output oracle to have been changed from the initial
// timestamp set in the contract constructor.
if l2ooBlockNumber.Cmp(initialOutputBlockNumber) > 0 {
// Retrieve the l2 output committed at this updated timestamp.
committedL2Output, err := l2OutputOracle.GetL2OutputAfter(&bind.CallOpts{}, l2ooBlockNumber)
require.NotEqual(t, [32]byte{}, committedL2Output.OutputRoot, "Empty L2 Output")
require.Nil(t, err)
// Fetch the corresponding L2 block and assert the committed L2
// output matches the block's state root.
//
// NOTE: This assertion will change once the L2 output format is
// finalized.
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
l2Output, err := rollupClient.OutputAtBlock(ctx, l2ooBlockNumber.Uint64())
require.Nil(t, err)
require.Equal(t, l2Output.OutputRoot[:], committedL2Output.OutputRoot[:])
break
}
select {
case <-timeoutCh:
t.Fatalf("State root oracle not updated")
case <-ticker.C:
}
}
}
package op_e2e package proofs
import ( import (
"context" "context"
...@@ -6,6 +6,11 @@ import ( ...@@ -6,6 +6,11 @@ import (
"testing" "testing"
"time" "time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind"
...@@ -86,10 +91,10 @@ func applySpanBatchActivation(active bool, dp *genesis.DeployConfig) { ...@@ -86,10 +91,10 @@ func applySpanBatchActivation(active bool, dp *genesis.DeployConfig) {
// - update the state root via a tx // - update the state root via a tx
// - run program // - run program
func testVerifyL2OutputRootEmptyBlock(t *testing.T, detached bool, spanBatchActivated bool) { func testVerifyL2OutputRootEmptyBlock(t *testing.T, detached bool, spanBatchActivated bool) {
InitParallel(t) op_e2e.InitParallel(t)
ctx := context.Background() ctx := context.Background()
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
// We don't need a verifier - just the sequencer is enough // We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier") delete(cfg.Nodes, "verifier")
// Use a small sequencer window size to avoid test timeout while waiting for empty blocks // Use a small sequencer window size to avoid test timeout while waiting for empty blocks
...@@ -117,7 +122,7 @@ func testVerifyL2OutputRootEmptyBlock(t *testing.T, detached bool, spanBatchActi ...@@ -117,7 +122,7 @@ func testVerifyL2OutputRootEmptyBlock(t *testing.T, detached bool, spanBatchActi
t.Log("Sending transactions to setup existing state, prior to challenged period") t.Log("Sending transactions to setup existing state, prior to challenged period")
aliceKey := cfg.Secrets.Alice aliceKey := cfg.Secrets.Alice
receipt := SendL2Tx(t, cfg, l2Seq, aliceKey, func(opts *TxOpts) { receipt := helpers.SendL2Tx(t, cfg, l2Seq, aliceKey, func(opts *helpers.TxOpts) {
opts.ToAddr = &cfg.Secrets.Addresses().Bob opts.ToAddr = &cfg.Secrets.Addresses().Bob
opts.Value = big.NewInt(1_000) opts.Value = big.NewInt(1_000)
}) })
...@@ -163,7 +168,7 @@ func testVerifyL2OutputRootEmptyBlock(t *testing.T, detached bool, spanBatchActi ...@@ -163,7 +168,7 @@ func testVerifyL2OutputRootEmptyBlock(t *testing.T, detached bool, spanBatchActi
require.NoError(t, err, "could not start batch submitter") require.NoError(t, err, "could not start batch submitter")
t.Log("Add a transaction to the next batch after sequence of empty blocks") t.Log("Add a transaction to the next batch after sequence of empty blocks")
receipt = SendL2Tx(t, cfg, l2Seq, aliceKey, func(opts *TxOpts) { receipt = helpers.SendL2Tx(t, cfg, l2Seq, aliceKey, func(opts *helpers.TxOpts) {
opts.ToAddr = &cfg.Secrets.Addresses().Bob opts.ToAddr = &cfg.Secrets.Addresses().Bob
opts.Value = big.NewInt(1_000) opts.Value = big.NewInt(1_000)
opts.Nonce = 1 opts.Nonce = 1
...@@ -186,10 +191,10 @@ func testVerifyL2OutputRootEmptyBlock(t *testing.T, detached bool, spanBatchActi ...@@ -186,10 +191,10 @@ func testVerifyL2OutputRootEmptyBlock(t *testing.T, detached bool, spanBatchActi
} }
func testVerifyL2OutputRoot(t *testing.T, detached bool, spanBatchActivated bool) { func testVerifyL2OutputRoot(t *testing.T, detached bool, spanBatchActivated bool) {
InitParallel(t) op_e2e.InitParallel(t)
ctx := context.Background() ctx := context.Background()
cfg := DefaultSystemConfig(t) cfg := e2esys.DefaultSystemConfig(t)
// We don't need a verifier - just the sequencer is enough // We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier") delete(cfg.Nodes, "verifier")
applySpanBatchActivation(spanBatchActivated, cfg.DeployConfig) applySpanBatchActivation(spanBatchActivated, cfg.DeployConfig)
...@@ -209,15 +214,15 @@ func testVerifyL2OutputRoot(t *testing.T, detached bool, spanBatchActivated bool ...@@ -209,15 +214,15 @@ func testVerifyL2OutputRoot(t *testing.T, detached bool, spanBatchActivated bool
aliceKey := cfg.Secrets.Alice aliceKey := cfg.Secrets.Alice
opts, err := bind.NewKeyedTransactorWithChainID(aliceKey, cfg.L1ChainIDBig()) opts, err := bind.NewKeyedTransactorWithChainID(aliceKey, cfg.L1ChainIDBig())
require.Nil(t, err) require.Nil(t, err)
SendDepositTx(t, cfg, l1Client, l2Seq, opts, func(l2Opts *DepositTxOpts) { helpers.SendDepositTx(t, cfg, l1Client, l2Seq, opts, func(l2Opts *helpers.DepositTxOpts) {
l2Opts.Value = big.NewInt(100_000_000) l2Opts.Value = big.NewInt(100_000_000)
}) })
SendL2Tx(t, cfg, l2Seq, aliceKey, func(opts *TxOpts) { helpers.SendL2Tx(t, cfg, l2Seq, aliceKey, func(opts *helpers.TxOpts) {
opts.ToAddr = &cfg.Secrets.Addresses().Bob opts.ToAddr = &cfg.Secrets.Addresses().Bob
opts.Value = big.NewInt(1_000) opts.Value = big.NewInt(1_000)
opts.Nonce = 1 opts.Nonce = 1
}) })
SendWithdrawal(t, cfg, l2Seq, aliceKey, func(opts *WithdrawalTxOpts) { helpers.SendWithdrawal(t, cfg, l2Seq, aliceKey, func(opts *helpers.WithdrawalTxOpts) {
opts.Value = big.NewInt(500) opts.Value = big.NewInt(500)
opts.Nonce = 2 opts.Nonce = 2
}) })
...@@ -231,14 +236,14 @@ func testVerifyL2OutputRoot(t *testing.T, detached bool, spanBatchActivated bool ...@@ -231,14 +236,14 @@ func testVerifyL2OutputRoot(t *testing.T, detached bool, spanBatchActivated bool
l2OutputRoot := agreedL2Output.OutputRoot l2OutputRoot := agreedL2Output.OutputRoot
t.Log("Sending transactions to modify existing state, within challenged period") t.Log("Sending transactions to modify existing state, within challenged period")
SendDepositTx(t, cfg, l1Client, l2Seq, opts, func(l2Opts *DepositTxOpts) { helpers.SendDepositTx(t, cfg, l1Client, l2Seq, opts, func(l2Opts *helpers.DepositTxOpts) {
l2Opts.Value = big.NewInt(5_000) l2Opts.Value = big.NewInt(5_000)
}) })
SendL2Tx(t, cfg, l2Seq, cfg.Secrets.Bob, func(opts *TxOpts) { helpers.SendL2Tx(t, cfg, l2Seq, cfg.Secrets.Bob, func(opts *helpers.TxOpts) {
opts.ToAddr = &cfg.Secrets.Addresses().Alice opts.ToAddr = &cfg.Secrets.Addresses().Alice
opts.Value = big.NewInt(100) opts.Value = big.NewInt(100)
}) })
SendWithdrawal(t, cfg, l2Seq, aliceKey, func(opts *WithdrawalTxOpts) { helpers.SendWithdrawal(t, cfg, l2Seq, aliceKey, func(opts *helpers.WithdrawalTxOpts) {
opts.Value = big.NewInt(100) opts.Value = big.NewInt(100)
opts.Nonce = 4 opts.Nonce = 4
}) })
...@@ -276,7 +281,7 @@ type FaultProofProgramTestScenario struct { ...@@ -276,7 +281,7 @@ type FaultProofProgramTestScenario struct {
} }
// testFaultProofProgramScenario runs the fault proof program in several contexts, given a test scenario. // testFaultProofProgramScenario runs the fault proof program in several contexts, given a test scenario.
func testFaultProofProgramScenario(t *testing.T, ctx context.Context, sys *System, s *FaultProofProgramTestScenario) { func testFaultProofProgramScenario(t *testing.T, ctx context.Context, sys *e2esys.System, s *FaultProofProgramTestScenario) {
preimageDir := t.TempDir() preimageDir := t.TempDir()
fppConfig := oppconf.NewConfig(sys.RollupConfig, sys.L2GenesisCfg.Config, s.L1Head, s.L2Head, s.L2OutputRoot, common.Hash(s.L2Claim), s.L2ClaimBlockNumber) fppConfig := oppconf.NewConfig(sys.RollupConfig, sys.L2GenesisCfg.Config, s.L1Head, s.L2Head, s.L2OutputRoot, common.Hash(s.L2Claim), s.L2ClaimBlockNumber)
fppConfig.L1URL = sys.NodeEndpoint("l1").RPC() fppConfig.L1URL = sys.NodeEndpoint("l1").RPC()
......
package runcfg
import (
"context"
"fmt"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-service/retry"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
func TestRuntimeConfigReload(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
// to speed up the test, make it reload the config more often, and do not impose a long conf depth
cfg.Nodes["verifier"].RuntimeConfigReloadInterval = time.Second * 5
cfg.Nodes["verifier"].Driver.VerifierConfDepth = 1
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
initialRuntimeConfig := sys.RollupNodes["verifier"].RuntimeConfig()
// close the EL node, since we want to block derivation, to solely rely on the reloading mechanism for updates.
sys.EthInstances["verifier"].Close()
l1 := sys.NodeClient("l1")
// Change the system-config via L1
sysCfgContract, err := bindings.NewSystemConfig(cfg.L1Deployments.SystemConfigProxy, l1)
require.NoError(t, err)
newUnsafeBlocksSigner := common.Address{0x12, 0x23, 0x45}
require.NotEqual(t, initialRuntimeConfig.P2PSequencerAddress(), newUnsafeBlocksSigner, "changing to a different address")
opts, err := bind.NewKeyedTransactorWithChainID(cfg.Secrets.SysCfgOwner, cfg.L1ChainIDBig())
require.Nil(t, err)
// the unsafe signer address is part of the runtime config
tx, err := sysCfgContract.SetUnsafeBlockSigner(opts, newUnsafeBlocksSigner)
require.NoError(t, err)
// wait for the change to confirm
_, err = wait.ForReceiptOK(context.Background(), l1, tx.Hash())
require.NoError(t, err)
// wait for the address to change
_, err = retry.Do(context.Background(), 10, retry.Fixed(time.Second*10), func() (struct{}, error) {
v := sys.RollupNodes["verifier"].RuntimeConfig().P2PSequencerAddress()
if v == newUnsafeBlocksSigner {
return struct{}{}, nil
}
return struct{}{}, fmt.Errorf("no change yet, seeing %s but looking for %s", v, newUnsafeBlocksSigner)
})
require.NoError(t, err)
}
package runcfg
import (
"context"
"errors"
"fmt"
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-service/client"
"github.com/ethereum-optimism/optimism/op-service/endpoint"
"github.com/ethereum-optimism/optimism/op-service/retry"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)
func TestRecommendedProtocolVersionChange(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
require.NotEqual(t, common.Address{}, cfg.L1Deployments.ProtocolVersions, "need ProtocolVersions contract deployment")
// to speed up the test, make it reload the config more often, and do not impose a long conf depth
cfg.Nodes["verifier"].RuntimeConfigReloadInterval = time.Second * 5
cfg.Nodes["verifier"].Driver.VerifierConfDepth = 1
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
runtimeConfig := sys.RollupNodes["verifier"].RuntimeConfig()
// Change the superchain-config via L1
l1 := sys.NodeClient("l1")
_, build, major, minor, patch, preRelease := params.OPStackSupport.Parse()
newRecommendedProtocolVersion := params.ProtocolVersionV0{Build: build, Major: major + 1, Minor: minor, Patch: patch, PreRelease: preRelease}.Encode()
require.NotEqual(t, runtimeConfig.RecommendedProtocolVersion(), newRecommendedProtocolVersion, "changing to a different protocol version")
protVersions, err := bindings.NewProtocolVersions(cfg.L1Deployments.ProtocolVersionsProxy, l1)
require.NoError(t, err)
// ProtocolVersions contract is owned by same key as SystemConfig in devnet
opts, err := bind.NewKeyedTransactorWithChainID(cfg.Secrets.SysCfgOwner, cfg.L1ChainIDBig())
require.NoError(t, err)
// Change recommended protocol version
tx, err := protVersions.SetRecommended(opts, new(big.Int).SetBytes(newRecommendedProtocolVersion[:]))
require.NoError(t, err)
// wait for the change to confirm
_, err = wait.ForReceiptOK(context.Background(), l1, tx.Hash())
require.NoError(t, err)
// wait for the recommended protocol version to change
_, err = retry.Do(context.Background(), 10, retry.Fixed(time.Second*10), func() (struct{}, error) {
v := sys.RollupNodes["verifier"].RuntimeConfig().RecommendedProtocolVersion()
if v == newRecommendedProtocolVersion {
return struct{}{}, nil
}
return struct{}{}, fmt.Errorf("no change yet, seeing %s but looking for %s", v, newRecommendedProtocolVersion)
})
require.NoError(t, err)
}
func TestRequiredProtocolVersionChangeAndHalt(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
// to speed up the test, make it reload the config more often, and do not impose a long conf depth
cfg.Nodes["verifier"].RuntimeConfigReloadInterval = time.Second * 5
cfg.Nodes["verifier"].Driver.VerifierConfDepth = 1
// configure halt in verifier op-node
cfg.Nodes["verifier"].RollupHalt = "major"
// configure halt in verifier op-geth node
cfg.GethOptions["verifier"] = append(cfg.GethOptions["verifier"], []geth.GethOption{
func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error {
ethCfg.RollupHaltOnIncompatibleProtocolVersion = "major"
return nil
},
}...)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
runtimeConfig := sys.RollupNodes["verifier"].RuntimeConfig()
// Change the superchain-config via L1
l1 := sys.NodeClient("l1")
_, build, major, minor, patch, preRelease := params.OPStackSupport.Parse()
newRequiredProtocolVersion := params.ProtocolVersionV0{Build: build, Major: major + 1, Minor: minor, Patch: patch, PreRelease: preRelease}.Encode()
require.NotEqual(t, runtimeConfig.RequiredProtocolVersion(), newRequiredProtocolVersion, "changing to a different protocol version")
protVersions, err := bindings.NewProtocolVersions(cfg.L1Deployments.ProtocolVersionsProxy, l1)
require.NoError(t, err)
// ProtocolVersions contract is owned by same key as SystemConfig in devnet
opts, err := bind.NewKeyedTransactorWithChainID(cfg.Secrets.SysCfgOwner, cfg.L1ChainIDBig())
require.NoError(t, err)
// Change required protocol version
tx, err := protVersions.SetRequired(opts, new(big.Int).SetBytes(newRequiredProtocolVersion[:]))
require.NoError(t, err)
// wait for the change to confirm
_, err = wait.ForReceiptOK(context.Background(), l1, tx.Hash())
require.NoError(t, err)
// wait for the required protocol version to take effect by halting the verifier that opted in, and halting the op-geth node that opted in.
_, err = retry.Do(context.Background(), 10, retry.Fixed(time.Second*10), func() (struct{}, error) {
if !sys.RollupNodes["verifier"].Stopped() {
return struct{}{}, errors.New("verifier rollup node is not closed yet")
}
return struct{}{}, nil
})
require.NoError(t, err)
t.Log("verified that op-node closed!")
// Checking if the engine is down is not trivial in op-e2e.
// In op-geth we have halting tests covering the Engine API, in op-e2e we instead check if the API stops.
_, err = retry.Do(context.Background(), 10, retry.Fixed(time.Second*10), func() (struct{}, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
available := client.IsURLAvailable(ctx, sys.NodeEndpoint("verifier").(endpoint.HttpRPC).HttpRPC())
if !available && ctx.Err() == nil { // waiting for client to stop responding to RPC requests (slow dials with timeout don't count)
return struct{}{}, nil
}
return struct{}{}, errors.New("verifier EL node is not closed yet")
})
require.NoError(t, err)
t.Log("verified that op-geth closed!")
}
package runcfg
import (
"testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
)
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
package verifier
import (
"context"
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
func TestSystemE2EDencunAtGenesis(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
cfg.DeployConfig.L1CancunTimeOffset = new(hexutil.Uint64)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
runE2ESystemTest(t, sys)
head, err := sys.NodeClient("l1").BlockByNumber(context.Background(), big.NewInt(0))
require.NoError(t, err)
require.NotNil(t, head.ExcessBlobGas(), "L1 is building dencun blocks since genesis")
}
// TestSystemE2E sets up a L1 Geth node, a rollup node, and a L2 geth node and then confirms that L1 deposits are reflected on L2.
// All nodes are run in process (but are the full nodes, not mocked or stubbed).
func TestSystemE2E(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
runE2ESystemTest(t, sys)
}
func runE2ESystemTest(t *testing.T, sys *e2esys.System) {
log := testlog.Logger(t, log.LevelInfo)
log.Info("genesis", "l2", sys.RollupConfig.Genesis.L2, "l1", sys.RollupConfig.Genesis.L1, "l2_time", sys.RollupConfig.Genesis.L2Time)
l1Client := sys.NodeClient("l1")
l2Seq := sys.NodeClient("sequencer")
l2Verif := sys.NodeClient("verifier")
// Transactor Account
ethPrivKey := sys.Cfg.Secrets.Alice
// Send Transaction & wait for success
fromAddr := sys.Cfg.Secrets.Addresses().Alice
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
startBalance, err := l2Verif.BalanceAt(ctx, fromAddr, nil)
require.Nil(t, err)
// Send deposit transaction
opts, err := bind.NewKeyedTransactorWithChainID(ethPrivKey, sys.Cfg.L1ChainIDBig())
require.Nil(t, err)
mintAmount := big.NewInt(1_000_000_000_000)
opts.Value = mintAmount
helpers.SendDepositTx(t, sys.Cfg, l1Client, l2Verif, opts, func(l2Opts *helpers.DepositTxOpts) {})
// Confirm balance
ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
endBalance, err := wait.ForBalanceChange(ctx, l2Verif, fromAddr, startBalance)
require.Nil(t, err)
diff := new(big.Int)
diff = diff.Sub(endBalance, startBalance)
require.Equal(t, mintAmount, diff, "Did not get expected balance change")
// Submit TX to L2 sequencer node
receipt := helpers.SendL2Tx(t, sys.Cfg, l2Seq, ethPrivKey, func(opts *helpers.TxOpts) {
opts.Value = big.NewInt(1_000_000_000)
opts.Nonce = 1 // Already have deposit
opts.ToAddr = &common.Address{0xff, 0xff}
opts.VerifyOnClients(l2Verif)
})
// Verify blocks match after batch submission on verifiers and sequencers
verifBlock, err := l2Verif.BlockByNumber(context.Background(), receipt.BlockNumber)
require.Nil(t, err)
seqBlock, err := l2Seq.BlockByNumber(context.Background(), receipt.BlockNumber)
require.Nil(t, err)
require.Equal(t, verifBlock.NumberU64(), seqBlock.NumberU64(), "Verifier and sequencer blocks not the same after including a batch tx")
require.Equal(t, verifBlock.ParentHash(), seqBlock.ParentHash(), "Verifier and sequencer blocks parent hashes not the same after including a batch tx")
require.Equal(t, verifBlock.Hash(), seqBlock.Hash(), "Verifier and sequencer blocks not the same after including a batch tx")
rollupClient := sys.RollupClient("sequencer")
// basic check that sync status works
seqStatus, err := rollupClient.SyncStatus(context.Background())
require.Nil(t, err)
require.LessOrEqual(t, seqBlock.NumberU64(), seqStatus.UnsafeL2.Number)
// basic check that version endpoint works
seqVersion, err := rollupClient.Version(context.Background())
require.Nil(t, err)
require.NotEqual(t, "", seqVersion)
}
package verifier
import (
"context"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
)
// TestConfirmationDepth runs the rollup with both sequencer and verifier not immediately processing the tip of the chain.
func TestConfirmationDepth(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
cfg.DeployConfig.SequencerWindowSize = 4
cfg.DeployConfig.MaxSequencerDrift = 10 * cfg.DeployConfig.L1BlockTime
seqConfDepth := uint64(2)
verConfDepth := uint64(5)
cfg.Nodes["sequencer"].Driver.SequencerConfDepth = seqConfDepth
cfg.Nodes["sequencer"].Driver.VerifierConfDepth = 0
cfg.Nodes["verifier"].Driver.VerifierConfDepth = verConfDepth
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
log := testlog.Logger(t, log.LevelInfo)
log.Info("genesis", "l2", sys.RollupConfig.Genesis.L2, "l1", sys.RollupConfig.Genesis.L1, "l2_time", sys.RollupConfig.Genesis.L2Time)
l1Client := sys.NodeClient("l1")
l2Seq := sys.NodeClient("sequencer")
l2Verif := sys.NodeClient("verifier")
// Wait enough time for the sequencer to submit a block with distance from L1 head, submit it,
// and for the slower verifier to read a full sequence window and cover confirmation depth for reading and some margin
<-time.After(time.Duration((cfg.DeployConfig.SequencerWindowSize+verConfDepth+3)*cfg.DeployConfig.L1BlockTime) * time.Second)
// within a second, get both L1 and L2 verifier and sequencer block heads
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
l1Head, err := l1Client.BlockByNumber(ctx, nil)
require.NoError(t, err)
l2SeqHead, err := l2Seq.BlockByNumber(ctx, nil)
require.NoError(t, err)
l2VerHead, err := l2Verif.BlockByNumber(ctx, nil)
require.NoError(t, err)
seqInfo, err := derive.L1BlockInfoFromBytes(sys.RollupConfig, l2SeqHead.Time(), l2SeqHead.Transactions()[0].Data())
require.NoError(t, err)
require.LessOrEqual(t, seqInfo.Number+seqConfDepth, l1Head.NumberU64(), "the seq L2 head block should have an origin older than the L1 head block by at least the sequencer conf depth")
verInfo, err := derive.L1BlockInfoFromBytes(sys.RollupConfig, l2VerHead.Time(), l2VerHead.Transactions()[0].Data())
require.NoError(t, err)
require.LessOrEqual(t, verInfo.Number+verConfDepth, l1Head.NumberU64(), "the ver L2 head block should have an origin older than the L1 head block by at least the verifier conf depth")
}
package verifier
import (
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/stretchr/testify/require"
)
// TestFinalize tests if L2 finalizes after sufficient time after L1 finalizes
func TestFinalize(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
l2Seq := sys.NodeClient("sequencer")
l2Finalized, err := geth.WaitForBlockToBeFinalized(big.NewInt(12), l2Seq, 1*time.Minute)
require.NoError(t, err, "must be able to fetch a finalized L2 block")
require.NotZerof(t, l2Finalized.NumberU64(), "must have finalized L2 block")
}
package verifier
import (
"context"
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require"
)
// TestPendingGasLimit tests the configuration of the gas limit of the pending block,
// and if it does not conflict with the regular gas limit on the verifier or sequencer.
func TestPendingGasLimit(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
// configure the L2 gas limit to be high, and the pending gas limits to be lower for resource saving.
cfg.DeployConfig.L2GenesisBlockGasLimit = 30_000_000
cfg.GethOptions["sequencer"] = append(cfg.GethOptions["sequencer"], []geth.GethOption{
func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error {
ethCfg.Miner.GasCeil = 10_000_000
ethCfg.Miner.RollupComputePendingBlock = true
return nil
},
}...)
cfg.GethOptions["verifier"] = append(cfg.GethOptions["verifier"], []geth.GethOption{
func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error {
ethCfg.Miner.GasCeil = 9_000_000
ethCfg.Miner.RollupComputePendingBlock = true
return nil
},
}...)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
log := testlog.Logger(t, log.LevelInfo)
log.Info("genesis", "l2", sys.RollupConfig.Genesis.L2, "l1", sys.RollupConfig.Genesis.L1, "l2_time", sys.RollupConfig.Genesis.L2Time)
l2Verif := sys.NodeClient("verifier")
l2Seq := sys.NodeClient("sequencer")
checkGasLimit := func(client *ethclient.Client, number *big.Int, expected uint64) *types.Header {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
header, err := client.HeaderByNumber(ctx, number)
cancel()
require.NoError(t, err)
require.Equal(t, expected, header.GasLimit)
return header
}
// check if the gaslimits are matching the expected values,
// and that the verifier/sequencer can use their locally configured gas limit for the pending block.
for {
checkGasLimit(l2Seq, big.NewInt(-1), 10_000_000)
checkGasLimit(l2Verif, big.NewInt(-1), 9_000_000)
checkGasLimit(l2Seq, nil, 30_000_000)
latestVerifHeader := checkGasLimit(l2Verif, nil, 30_000_000)
// Stop once the verifier passes genesis:
// this implies we checked a new block from the sequencer, on both sequencer and verifier nodes.
if latestVerifHeader.Number.Uint64() > 0 {
break
}
time.Sleep(500 * time.Millisecond)
}
}
// TestPendingBlockIsLatest tests that we serve the latest block as pending block
func TestPendingBlockIsLatest(t *testing.T) {
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
l2Seq := sys.NodeClient("sequencer")
t.Run("block", func(t *testing.T) {
for i := 0; i < 10; i++ {
pending, err := l2Seq.BlockByNumber(context.Background(), big.NewInt(rpc.PendingBlockNumber.Int64()))
require.NoError(t, err)
latest, err := l2Seq.BlockByNumber(context.Background(), nil)
require.NoError(t, err)
if pending.NumberU64() == latest.NumberU64() {
require.Equal(t, pending.Hash(), latest.Hash(), "pending must exactly match latest block")
return
}
// re-try until we have the same number, as the requests are not an atomic bundle, and the sequencer may create a block.
}
t.Fatal("failed to get pending block with same number as latest block")
})
t.Run("header", func(t *testing.T) {
for i := 0; i < 10; i++ {
pending, err := l2Seq.HeaderByNumber(context.Background(), big.NewInt(rpc.PendingBlockNumber.Int64()))
require.NoError(t, err)
latest, err := l2Seq.HeaderByNumber(context.Background(), nil)
require.NoError(t, err)
if pending.Number.Uint64() == latest.Number.Uint64() {
require.Equal(t, pending.Hash(), latest.Hash(), "pending must exactly match latest header")
return
}
// re-try until we have the same number, as the requests are not an atomic bundle, and the sequencer may create a block.
}
t.Fatal("failed to get pending header with same number as latest header")
})
}
package verifier
import (
"context"
"math/big"
"testing"
"time"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
func TestMissingBatchE2E(t *testing.T) {
op_e2e.InitParallel(t)
// Note this test zeroes the balance of the batch-submitter to make the batches unable to go into L1.
// The test logs may look scary, but this is expected:
// 'batcher unable to publish transaction role=batcher err="insufficient funds for gas * price + value"'
cfg := e2esys.DefaultSystemConfig(t)
// small sequence window size so the test does not take as long
cfg.DeployConfig.SequencerWindowSize = 4
// Specifically set batch submitter balance to stop batches from being included
cfg.Premine[cfg.Secrets.Addresses().Batcher] = big.NewInt(0)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
l2Seq := sys.NodeClient("sequencer")
l2Verif := sys.NodeClient("verifier")
seqRollupClient := sys.RollupClient("sequencer")
// Transactor Account
ethPrivKey := cfg.Secrets.Alice
// Submit TX to L2 sequencer node
receipt := helpers.SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *helpers.TxOpts) {
opts.ToAddr = &common.Address{0xff, 0xff}
opts.Value = big.NewInt(1_000_000_000)
})
// Wait until the block it was first included in shows up in the safe chain on the verifier
_, err = geth.WaitForBlock(receipt.BlockNumber, l2Verif, time.Duration((sys.RollupConfig.SeqWindowSize+4)*cfg.DeployConfig.L1BlockTime)*time.Second)
require.Nil(t, err, "Waiting for block on verifier")
// Assert that the transaction is not found on the verifier
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
_, err = l2Verif.TransactionReceipt(ctx, receipt.TxHash)
require.Equal(t, ethereum.NotFound, err, "Found transaction in verifier when it should not have been included")
// Wait a short time for the L2 reorg to occur on the sequencer as well.
err = wait.ForSafeBlock(ctx, seqRollupClient, receipt.BlockNumber.Uint64())
require.Nil(t, err, "timeout waiting for L2 reorg on sequencer safe head")
// Assert that the reconciliation process did an L2 reorg on the sequencer to remove the invalid block
ctx2, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
block, err := l2Seq.BlockByNumber(ctx2, receipt.BlockNumber)
if err != nil {
require.Equal(t, "not found", err.Error(), "A not found error indicates the chain must have re-orged back before it")
} else {
require.NotEqual(t, block.Hash(), receipt.BlockHash, "L2 Sequencer did not reorg out transaction on it's safe chain")
}
}
package verifier
import (
"testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
)
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
This diff is collapsed.
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