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
$(go_test) $(go_test_flags) --externalL2 ./external_$*/
test-ws: pre-test
$(go_test) $(go_test_flags) . ./e2eutils/...
$(go_test) $(go_test_flags) ./system/... ./e2eutils/... ./opgeth/... ./interop/...
.PHONY: test-ws
test-actions: pre-test
......@@ -25,7 +25,7 @@ test-actions: pre-test
.PHONY: test-actions
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
test-cannon: pre-test
......@@ -71,7 +71,7 @@ clean:
.PHONY: clean
fuzz:
go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFjordCostFunction ./
go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFastLzGethSolidity ./
go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFastLzCgo ./
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 ./opgeth
go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFastLzCgo ./opgeth
......@@ -24,10 +24,10 @@ import (
"github.com/stretchr/testify/require"
"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"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"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"
bindingspreview "github.com/ethereum-optimism/optimism/op-node/bindings/preview"
"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
......@@ -449,7 +449,7 @@ func (s *CrossLayerUser) getLatestWithdrawalParams(t Testing) (*withdrawals.Prov
header, err := s.L2.env.EthCl.HeaderByNumber(t.Ctx(), l2OutputBlockNr)
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)
return &params, nil
......
......@@ -6,11 +6,11 @@ import (
"testing"
"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/require"
"github.com/ethereum-optimism/optimism/op-e2e/system/bridge"
"github.com/ethereum-optimism/optimism/op-service/testlog"
)
func TestDevnet(t *testing.T) {
......@@ -29,7 +29,7 @@ func TestDevnet(t *testing.T) {
})
t.Run("Withdrawal", func(t *testing.T) {
t.Parallel()
e2e.RunWithdrawalsTest(t, sys)
bridge.RunWithdrawalsTest(t, sys)
})
}
......
......@@ -6,8 +6,9 @@ import (
"os"
"path/filepath"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"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/e2eutils"
op_service "github.com/ethereum-optimism/optimism/op-service"
......@@ -29,7 +30,7 @@ type System struct {
L1 *ethclient.Client
L2 *ethclient.Client
Rollup *sources.RollupClient
Cfg e2e.SystemConfig
Cfg e2esys.SystemConfig
}
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)
sys.Cfg = e2e.SystemConfig{
sys.Cfg = e2esys.SystemConfig{
DeployConfig: deployConfig,
L1Deployments: config.L1Deployments.Copy(),
Secrets: secrets,
......@@ -79,9 +80,9 @@ func NewSystem(ctx context.Context, lgr log.Logger) (sys *System, err error) {
func (s System) NodeClient(role string) *ethclient.Client {
switch role {
case e2e.RoleL1:
case e2esys.RoleL1:
return s.L1
case e2e.RoleSeq, e2e.RoleVerif:
case e2esys.RoleSeq, e2esys.RoleVerif:
// we have only one L2 node
return s.L2
default:
......@@ -94,7 +95,7 @@ func (s System) RollupClient(string) *sources.RollupClient {
return s.Rollup
}
func (s System) Config() e2e.SystemConfig {
func (s System) Config() e2esys.SystemConfig {
return s.Cfg
}
......
......@@ -2,13 +2,33 @@ package op_e2e
import (
"crypto/md5"
"fmt"
"os"
"runtime"
"strconv"
"strings"
"testing"
"github.com/ethereum-optimism/optimism/op-e2e/config"
"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"
func InitParallel(t e2eutils.TestingBase, args ...func(t e2eutils.TestingBase)) {
......
package op_e2e
package opnode
import (
"context"
......
......@@ -9,9 +9,10 @@ import (
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-e2e/system/e2esys"
"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-service/endpoint"
)
......@@ -37,7 +38,7 @@ func TestShim(t *testing.T) {
config.EthNodeVerbosity = config.LegacyLevelDebug
ec := (&e2e.ExternalRunner{
ec := (&e2esys.ExternalRunner{
Name: "TestShim",
BinPath: shimPath,
}).Run(t)
......
......@@ -11,6 +11,9 @@ import (
"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/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
......@@ -23,7 +26,6 @@ import (
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"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/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-service/predeploys"
......@@ -35,7 +37,7 @@ func TestBenchmarkCannon_FPP(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
cfg := op_e2e.DefaultSystemConfig(t)
cfg := e2esys.DefaultSystemConfig(t)
// We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier")
// 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) {
// 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 {
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
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)
require.NoError(t, err)
......
......@@ -5,6 +5,7 @@ import (
"testing"
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/disputegame"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame/preimage"
......
......@@ -5,6 +5,7 @@ import (
"testing"
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/disputegame"
"github.com/ethereum/go-ethereum/common"
......
......@@ -6,8 +6,9 @@ import (
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/game/types"
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/disputegame"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
......
......@@ -5,10 +5,11 @@ import (
"fmt"
"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/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/disputegame"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame/preimage"
......
......@@ -7,6 +7,10 @@ import (
"path/filepath"
"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/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
......@@ -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/vm"
"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/disputegame"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
......@@ -75,7 +78,7 @@ func TestPrecompiles(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
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
delete(cfg.Nodes, "verifier")
// Use a small sequencer window size to avoid test timeout while waiting for empty blocks
......@@ -101,7 +104,7 @@ func TestPrecompiles(t *testing.T) {
l2Head := agreedL2Output.BlockRef.Hash
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.ToAddr = &test.address
opts.Nonce = 0
......@@ -140,7 +143,7 @@ func TestPrecompiles(t *testing.T) {
l2Seq := sys.NodeClient("sequencer")
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.ToAddr = &test.address
opts.Nonce = 0
......@@ -174,7 +177,7 @@ func TestGranitePrecompiles(t *testing.T) {
op_e2e.InitParallel(t, op_e2e.UsesCannon)
ctx := context.Background()
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
delete(cfg.Nodes, "verifier")
// Use a small sequencer window size to avoid test timeout while waiting for empty blocks
......@@ -242,7 +245,7 @@ func TestGranitePrecompiles(t *testing.T) {
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()
l1Beacon := sys.L1BeaconEndpoint().RestHTTP()
rollupEndpoint := sys.RollupEndpoint("sequencer").RPC()
......
......@@ -6,6 +6,7 @@ import (
"testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/disputegame"
preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-program/client"
......
......@@ -4,8 +4,10 @@ import (
"crypto/ecdsa"
"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"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
......@@ -13,16 +15,16 @@ import (
"github.com/stretchr/testify/require"
)
type faultDisputeConfigOpts func(cfg *op_e2e.SystemConfig)
type faultDisputeConfigOpts func(cfg *e2esys.SystemConfig)
func WithBatcherStopped() faultDisputeConfigOpts {
return func(cfg *op_e2e.SystemConfig) {
return func(cfg *e2esys.SystemConfig) {
cfg.DisableBatcher = true
}
}
func WithBlobBatches() faultDisputeConfigOpts {
return func(cfg *op_e2e.SystemConfig) {
return func(cfg *e2esys.SystemConfig) {
cfg.DataAvailabilityType = batcherFlags.BlobsType
genesisActivation := hexutil.Uint64(0)
......@@ -33,7 +35,7 @@ func WithBlobBatches() faultDisputeConfigOpts {
}
func WithEcotone() faultDisputeConfigOpts {
return func(cfg *op_e2e.SystemConfig) {
return func(cfg *e2esys.SystemConfig) {
genesisActivation := hexutil.Uint64(0)
cfg.DeployConfig.L1CancunTimeOffset = &genesisActivation
cfg.DeployConfig.L2GenesisDeltaTimeOffset = &genesisActivation
......@@ -42,13 +44,13 @@ func WithEcotone() faultDisputeConfigOpts {
}
func WithSequencerWindowSize(size uint64) faultDisputeConfigOpts {
return func(cfg *op_e2e.SystemConfig) {
return func(cfg *e2esys.SystemConfig) {
cfg.DeployConfig.SequencerWindowSize = size
}
}
func StartFaultDisputeSystem(t *testing.T, opts ...faultDisputeConfigOpts) (*op_e2e.System, *ethclient.Client) {
cfg := op_e2e.DefaultSystemConfig(t)
func StartFaultDisputeSystem(t *testing.T, opts ...faultDisputeConfigOpts) (*e2esys.System, *ethclient.Client) {
cfg := e2esys.DefaultSystemConfig(t)
delete(cfg.Nodes, "verifier")
cfg.Nodes["sequencer"].SafeDBPath = t.TempDir()
cfg.DeployConfig.SequencerWindowSize = 4
......@@ -64,8 +66,8 @@ func StartFaultDisputeSystem(t *testing.T, opts ...faultDisputeConfigOpts) (*op_
return sys, sys.NodeClient("l1")
}
func SendKZGPointEvaluationTx(t *testing.T, sys *op_e2e.System, l2Node string, privateKey *ecdsa.PrivateKey) *types.Receipt {
return op_e2e.SendL2Tx(t, sys.Cfg, sys.NodeClient(l2Node), privateKey, func(opts *op_e2e.TxOpts) {
func SendKZGPointEvaluationTx(t *testing.T, sys *e2esys.System, l2Node string, privateKey *ecdsa.PrivateKey) *types.Receipt {
return helpers.SendL2Tx(t, sys.Cfg, sys.NodeClient(l2Node), privateKey, func(opts *helpers.TxOpts) {
precompile := common.BytesToAddress([]byte{0x0a})
opts.Gas = 100_000
opts.ToAddr = &precompile
......
package op_e2e
package interop
import (
"encoding/json"
......@@ -16,8 +16,6 @@ import (
)
func TestInteropDevRecipe(t *testing.T) {
InitParallel(t)
rec := interopgen.InteropDevRecipe{
L1ChainID: 900100,
L2ChainIDs: []uint64{900200, 900201},
......@@ -31,8 +29,8 @@ func TestInteropDevRecipe(t *testing.T) {
logger := testlog.Logger(t, log.LevelDebug)
require.NoError(t, worldCfg.Check(logger))
fa := foundry.OpenArtifactsDir("../packages/contracts-bedrock/forge-artifacts")
srcFS := foundry.NewSourceMapFS(os.DirFS("../packages/contracts-bedrock"))
fa := foundry.OpenArtifactsDir("../../packages/contracts-bedrock/forge-artifacts")
srcFS := foundry.NewSourceMapFS(os.DirFS("../../packages/contracts-bedrock"))
worldDeployment, worldOutput, err := interopgen.Deploy(logger, fa, srcFS, worldCfg)
require.NoError(t, err)
......
......@@ -6,9 +6,10 @@ import (
"testing"
"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/ethereum-optimism/optimism/op-chain-ops/interopgen"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
)
// TestInteropTrivial tests a simple interop scenario
......@@ -60,7 +61,7 @@ func TestInteropTrivial(t *testing.T) {
s2.SendL2Tx(
chainA,
"Alice",
func(l2Opts *op_e2e.TxOpts) {
func(l2Opts *helpers.TxOpts) {
l2Opts.ToAddr = &bobAddr
l2Opts.Value = big.NewInt(1000000)
l2Opts.GasFeeCap = big.NewInt(1_000_000_000)
......
......@@ -10,6 +10,8 @@ import (
"testing"
"time"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/stretchr/testify/require"
......@@ -26,7 +28,6 @@ import (
"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/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/geth"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/opnode"
......@@ -82,7 +83,7 @@ type SuperSystem interface {
// get the user key for a user on an L2
UserKey(id, username string) ecdsa.PrivateKey
// 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
Address(network string, username string) common.Address
}
......@@ -586,11 +587,11 @@ func (s *interopE2ESystem) L2IDs() []string {
func (s *interopE2ESystem) SendL2Tx(
id string,
sender string,
applyTxOpts op_e2e.TxOptsFn,
applyTxOpts helpers.TxOptsFn,
) *types.Receipt {
senderSecret := s.UserKey(id, sender)
require.NotNil(s.t, senderSecret, "no secret found for sender %s", sender)
return op_e2e.SendL2TxWithID(
return helpers.SendL2TxWithID(
s.t,
s.l2s[id].chainID,
s.L2GethClient(id),
......
//go:build cgo_test
// +build cgo_test
package op_e2e
package opgeth
import (
"context"
......
package op_e2e
package opgeth
import (
"context"
......@@ -7,6 +7,8 @@ import (
"reflect"
"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-e2e/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
......@@ -51,7 +53,7 @@ type OpGeth struct {
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)
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
require.NoError(t, gethNode.Node.Start())
node = gethNode
} else {
externalNode := (&ExternalRunner{
externalNode := (&e2esys.ExternalRunner{
Name: "l2",
BinPath: cfg.ExternalL2Shim,
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 (
"context"
......@@ -6,6 +6,10 @@ import (
"math/big"
"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/e2eutils/receipts"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
......@@ -20,12 +24,16 @@ import (
"github.com/stretchr/testify/require"
)
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
// TestERC20BridgeDeposits tests the the L1StandardBridge bridge ERC20
// functionality.
func TestERC20BridgeDeposits(t *testing.T) {
InitParallel(t)
op_e2e.InitParallel(t)
cfg := DefaultSystemConfig(t)
cfg := e2esys.DefaultSystemConfig(t)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
......
package op_e2e
package bridge
import (
"context"
......@@ -6,6 +6,11 @@ import (
"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-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
......@@ -16,8 +21,8 @@ import (
)
func TestMintOnRevertedDeposit(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
delete(cfg.Nodes, "verifier")
sys, err := cfg.Start(t)
require.NoError(t, err, "Error starting up system")
......@@ -44,7 +49,7 @@ func TestMintOnRevertedDeposit(t *testing.T) {
toAddr := common.Address{0xff, 0xff}
mintAmount := big.NewInt(9_000_000)
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
// trigger a revert by transferring more than we have available
l2Opts.Value = new(big.Int).Mul(common.Big2, startBalance)
......@@ -75,8 +80,8 @@ func TestMintOnRevertedDeposit(t *testing.T) {
}
func TestDepositTxCreateContract(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
delete(cfg.Nodes, "verifier")
sys, err := cfg.Start(t)
......@@ -125,7 +130,7 @@ func TestDepositTxCreateContract(t *testing.T) {
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.Value = common.Big0
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 (
"context"
......@@ -7,6 +7,9 @@ import (
"testing"
"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/common"
"github.com/ethereum/go-ethereum/crypto"
......@@ -22,7 +25,7 @@ import (
type CommonSystem interface {
NodeClient(role string) *ethclient.Client
RollupClient(role string) *sources.RollupClient
Config() SystemConfig
Config() e2esys.SystemConfig
TestAccount(int) *ecdsa.PrivateKey
}
......@@ -33,9 +36,9 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) {
t.Logf("WithdrawalsTest: running with FP == %t", e2eutils.UseFaultProofs())
cfg := sys.Config()
l1Client := sys.NodeClient(RoleL1)
l2Seq := sys.NodeClient(RoleSeq)
l2Verif := sys.NodeClient(RoleVerif)
l1Client := sys.NodeClient(e2esys.RoleL1)
l2Seq := sys.NodeClient(e2esys.RoleSeq)
l2Verif := sys.NodeClient(e2esys.RoleVerif)
// Transactor Account
ethPrivKey := sys.TestAccount(0)
......@@ -55,7 +58,7 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) {
mintAmount := big.NewInt(1_000_000_000_000)
opts.Value = mintAmount
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
})
t.Log("WithdrawalsTest: waiting for balance change...")
......@@ -78,7 +81,7 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) {
withdrawAmount := big.NewInt(500_000_000_000)
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.VerifyOnClients(l2Verif)
})
......@@ -97,7 +100,7 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) {
// Take fee into account
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)
diff = diff.Sub(diff, fees)
require.Equal(t, withdrawAmount, diff)
......@@ -109,7 +112,7 @@ func RunWithdrawalsTest(t *testing.T, sys CommonSystem) {
require.NoError(t, err)
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
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 (
"context"
......@@ -9,6 +9,11 @@ import (
"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/hexutil"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require"
......@@ -60,11 +65,11 @@ func (c *conductor) RPCEndpoint() string {
return fmt.Sprintf("http://%s:%d", localhost, c.rpcPort)
}
func setupSequencerFailoverTest(t *testing.T) (*System, map[string]*conductor, func()) {
InitParallel(t)
func setupSequencerFailoverTest(t *testing.T) (*e2esys.System, map[string]*conductor, func()) {
op_e2e.InitParallel(t)
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)
})
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
}
}
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()
var sys *System
var sys *e2esys.System
var conductors map[string]*conductor
var err error
......@@ -267,7 +272,7 @@ func setupConductor(
}, 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.
// 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.
......@@ -311,8 +316,8 @@ func setupBatcher(t *testing.T, sys *System, conductors map[string]*conductor) {
sys.BatchSubmitter = batcher
}
func sequencerFailoverSystemConfig(t *testing.T, ports map[string]int) SystemConfig {
cfg := EcotoneSystemConfig(t, &genesisTime)
func sequencerFailoverSystemConfig(t *testing.T, ports map[string]int) e2esys.SystemConfig {
cfg := e2esys.EcotoneSystemConfig(t, new(hexutil.Uint64))
delete(cfg.Nodes, "sequencer")
cfg.Nodes[Sequencer1Name] = sequencerCfg(ports[Sequencer1Name])
cfg.Nodes[Sequencer2Name] = sequencerCfg(ports[Sequencer2Name])
......@@ -372,7 +377,7 @@ func waitForLeadership(t *testing.T, c *conductor) error {
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)
defer cancel()
......@@ -486,7 +491,7 @@ func findFollower(t *testing.T, conductors map[string]*conductor) (string, *cond
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)
defer cancel()
......
package op_e2e
package conductor
import (
"context"
......@@ -6,6 +6,11 @@ import (
"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/ethclient"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"
"github.com/stretchr/testify/require"
......@@ -18,9 +23,9 @@ import (
)
func TestStopStartSequencer(t *testing.T) {
InitParallel(t)
op_e2e.InitParallel(t)
cfg := DefaultSystemConfig(t)
cfg := e2esys.DefaultSystemConfig(t)
sys, err := cfg.Start(t)
require.Nil(t, err, "Error starting up system")
......@@ -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) {
InitParallel(t)
op_e2e.InitParallel(t)
ctx := context.Background()
dir := t.TempDir()
stateFile := dir + "/state.json"
cfg := DefaultSystemConfig(t)
cfg := e2esys.DefaultSystemConfig(t)
// We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier")
cfg.Nodes["sequencer"].ConfigPersistence = node.NewConfigPersistence(stateFile)
......@@ -104,7 +117,7 @@ func TestPersistSequencerStateWhenChanged(t *testing.T) {
}
func TestLoadSequencerStateOnStarted_Stopped(t *testing.T) {
InitParallel(t)
op_e2e.InitParallel(t)
ctx := context.Background()
dir := t.TempDir()
stateFile := dir + "/state.json"
......@@ -113,7 +126,7 @@ func TestLoadSequencerStateOnStarted_Stopped(t *testing.T) {
configReader := node.NewConfigPersistence(stateFile)
require.NoError(t, configReader.SequencerStopped())
cfg := DefaultSystemConfig(t)
cfg := e2esys.DefaultSystemConfig(t)
// We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier")
seqCfg := cfg.Nodes["sequencer"]
......@@ -136,7 +149,7 @@ func TestLoadSequencerStateOnStarted_Stopped(t *testing.T) {
}
func TestLoadSequencerStateOnStarted_Started(t *testing.T) {
InitParallel(t)
op_e2e.InitParallel(t)
ctx := context.Background()
dir := t.TempDir()
stateFile := dir + "/state.json"
......@@ -145,7 +158,7 @@ func TestLoadSequencerStateOnStarted_Started(t *testing.T) {
configReader := node.NewConfigPersistence(stateFile)
require.NoError(t, configReader.SequencerStarted())
cfg := DefaultSystemConfig(t)
cfg := e2esys.DefaultSystemConfig(t)
// We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier")
seqCfg := cfg.Nodes["sequencer"]
......@@ -169,10 +182,10 @@ func TestLoadSequencerStateOnStarted_Started(t *testing.T) {
}
func TestPostUnsafePayload(t *testing.T) {
InitParallel(t)
op_e2e.InitParallel(t)
ctx := context.Background()
cfg := DefaultSystemConfig(t)
cfg := e2esys.DefaultSystemConfig(t)
cfg.Nodes["verifier"].RPC.EnableAdmin = true
cfg.DisableBatcher = true
......
package op_e2e
package contracts
import (
"errors"
"testing"
op_e2e "github.com/ethereum-optimism/optimism/op-e2e"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/log"
......@@ -13,9 +15,9 @@ import (
)
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
af := foundry.OpenArtifactsDir("../packages/contracts-bedrock/forge-artifacts")
af := foundry.OpenArtifactsDir("../../../packages/contracts-bedrock/forge-artifacts")
artifacts, err := af.ListArtifacts()
require.NoError(t, err)
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 (
"context"
......@@ -7,6 +7,11 @@ import (
"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-e2e/system/helpers"
"github.com/stretchr/testify/require"
batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags"
......@@ -19,7 +24,7 @@ import (
"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")
l2Verif := sys.NodeClient("verifier")
......@@ -37,7 +42,7 @@ func setupAliceAccount(t *testing.T, cfg SystemConfig, sys *System, ethPrivKey *
require.NoError(t, err)
mintAmount := big.NewInt(1_000_000_000_000)
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
ctx, cancel = context.WithTimeout(context.Background(), 15*time.Second)
......@@ -50,9 +55,9 @@ func setupAliceAccount(t *testing.T, cfg SystemConfig, sys *System, ethPrivKey *
}
func TestBrotliBatcherFjord(t *testing.T) {
InitParallel(t)
op_e2e.InitParallel(t)
cfg := DefaultSystemConfig(t)
cfg := e2esys.DefaultSystemConfig(t)
cfg.DataAvailabilityType = batcherFlags.BlobsType
genesisActivation := hexutil.Uint64(0)
......@@ -62,7 +67,7 @@ func TestBrotliBatcherFjord(t *testing.T) {
cfg.DeployConfig.L2GenesisFjordTimeOffset = &genesisActivation
// 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")
log := testlog.Logger(t, log.LevelInfo)
......@@ -76,7 +81,7 @@ func TestBrotliBatcherFjord(t *testing.T) {
setupAliceAccount(t, cfg, sys, ethPrivKey)
// 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.Nonce = 1 // Already have deposit
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 (
"context"
......@@ -7,6 +7,11 @@ import (
"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-e2e/system/helpers"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
......@@ -38,9 +43,9 @@ func TestSystem4844E2E(t *testing.T) {
}
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.BatcherBatchType = derive.SpanBatchType
cfg.DeployConfig.L1GenesisBlockBaseFeePerGas = (*hexutil.Big)(big.NewInt(7000))
......@@ -62,9 +67,9 @@ func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAva
// is started, as is required by the function.
var jamChan chan error
jamCtx, jamCancel := context.WithTimeout(context.Background(), 20*time.Second)
action := SystemConfigOption{
key: "beforeBatcherStart",
action: func(cfg *SystemConfig, s *System) {
action := e2esys.SystemConfigOption{
Key: "beforeBatcherStart",
Action: func(cfg *e2esys.SystemConfig, s *e2esys.System) {
driver := s.BatchSubmitter.TestDriver()
err := driver.JamTxPool(jamCtx)
require.NoError(t, err)
......@@ -108,7 +113,7 @@ func testSystem4844E2E(t *testing.T, multiBlob bool, daType batcherFlags.DataAva
require.NoError(t, err)
mintAmount := big.NewInt(1_000_000_000_000)
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
ctx2, cancel2 := context.WithTimeout(context.Background(), 20*time.Second)
......@@ -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")
// 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.Nonce = 1 // Already have deposit
opts.ToAddr = &common.Address{0xff, 0xff}
......@@ -237,9 +242,9 @@ func toIndexedBlobHashes(hs ...common.Hash) []eth.IndexedBlobHash {
// 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.
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
// 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.
......
package op_e2e
package da
import (
"context"
"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/fakebeacon"
"github.com/ethereum-optimism/optimism/op-service/client"
......@@ -16,7 +18,7 @@ import (
)
func TestGetVersion(t *testing.T) {
InitParallel(t)
op_e2e.InitParallel(t)
l := testlog.Logger(t, log.LevelInfo)
......@@ -36,7 +38,7 @@ func TestGetVersion(t *testing.T) {
}
func Test404NotFound(t *testing.T) {
InitParallel(t)
op_e2e.InitParallel(t)
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 (
"encoding/json"
......
package op_e2e
package e2esys
import (
"context"
......@@ -431,25 +431,25 @@ func (sys *System) Close() {
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 {
key string
role string
action systemConfigHook
Key string
Role string
Action SystemConfigHook
}
type SystemConfigOptions struct {
opts map[string]systemConfigHook
opts map[string]SystemConfigHook
}
func NewSystemConfigOptions(_opts []SystemConfigOption) (SystemConfigOptions, error) {
opts := make(map[string]systemConfigHook)
opts := make(map[string]SystemConfigHook)
for _, opt := range _opts {
if _, ok := opts[opt.key+":"+opt.role]; ok {
return SystemConfigOptions{}, fmt.Errorf("duplicate option for key %s and role %s", opt.key, opt.role)
if _, ok := opts[opt.Key+":"+opt.Role]; ok {
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{
......@@ -457,7 +457,7 @@ func NewSystemConfigOptions(_opts []SystemConfigOption) (SystemConfigOptions, er
}, 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]
return v, ok
}
......@@ -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
// of only websockets (which are required for external eth client tests).
for name, nodeCfg := range cfg.Nodes {
configureL1(nodeCfg, sys.EthInstances[RoleL1], sys.L1BeaconEndpoint())
configureL2(nodeCfg, sys.EthInstances[name], cfg.JWTSecret)
ConfigureL1(nodeCfg, sys.EthInstances[RoleL1], sys.L1BeaconEndpoint())
ConfigureL2(nodeCfg, sys.EthInstances[name], cfg.JWTSecret)
}
l1Client := sys.NodeClient(RoleL1)
......@@ -662,7 +662,7 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
if p, ok := p2pNodes[name]; ok {
return p, nil
}
h, err := sys.newMockNetPeer()
h, err := sys.NewMockNetPeer()
if err != nil {
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
var blackholeIP6 = net.ParseIP("100::")
// 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)
if err != nil {
return nil, err
......@@ -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{
L1NodeAddr: endpoint.SelectRPC(EnvRPCPreference(), l1Node.UserRPC()),
L1TrustRPC: false,
......@@ -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{
L2EngineAddr: endpoint.SelectRPC(EnvRPCPreference(), l2Node.AuthRPC()),
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 (
"context"
"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/log"
......@@ -16,7 +20,7 @@ import (
// TestCheckFjordScript ensures the op-chain-ops/cmd/check-fjord script runs successfully
// against a test chain with the fjord hardfork activated/unactivated
func TestCheckFjordScript(t *testing.T) {
InitParallel(t)
op_e2e.InitParallel(t)
genesisActivation := hexutil.Uint64(0)
tests := []struct {
name string
......@@ -37,11 +41,11 @@ func TestCheckFjordScript(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
InitParallel(t)
op_e2e.InitParallel(t)
log := testlog.Logger(t, log.LevelInfo)
cfg := DefaultSystemConfig(t)
cfg := e2esys.DefaultSystemConfig(t)
cfg.DeployConfig.L1CancunTimeOffset = &genesisActivation
cfg.DeployConfig.L2GenesisRegolithTimeOffset = &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 (
"context"
......@@ -7,6 +7,11 @@ import (
"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-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/receipts"
......@@ -22,10 +27,14 @@ import (
"github.com/stretchr/testify/require"
)
func TestMain(m *testing.M) {
op_e2e.RunMain(m)
}
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)
cfg.DeployConfig.L2GenesisRegolithTimeOffset = &offset
cfg.DeployConfig.L1CancunTimeOffset = &offset
......@@ -143,7 +152,7 @@ func TestCustomGasToken(t *testing.T) {
require.NoError(t, err)
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.VerifyOnClients(l2Verif)
})
......@@ -157,7 +166,7 @@ func TestCustomGasToken(t *testing.T) {
// Take fee into account
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)
diff = diff.Sub(diff, fees)
require.Equal(t, withdrawAmount, diff)
......@@ -169,7 +178,7 @@ func TestCustomGasToken(t *testing.T) {
startETHBalanceBeforeFinalize, err := l1Client.BalanceAt(context.Background(), fromAddr, nil)
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
proveFee := new(big.Int).Mul(new(big.Int).SetUint64(proveReceipt.GasUsed), proveReceipt.EffectiveGasPrice)
......@@ -318,7 +327,7 @@ func TestCustomGasToken(t *testing.T) {
withdrawnAmount := it.Event.Value
// 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, finalizeReceipt.Status)
if e2eutils.UseFaultProofs() {
......@@ -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.
// 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.
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")
deployerOpts, err := bind.NewKeyedTransactorWithChainID(cfg.Secrets.Deployer, cfg.L1ChainIDBig())
require.NoError(t, err)
......
package op_e2e
package helpers
import (
"context"
......@@ -7,6 +7,8 @@ import (
"testing"
"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/bindings"
......@@ -24,7 +26,7 @@ import (
// 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
// 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)
applyL2Opts(l2Opts)
......@@ -115,7 +117,7 @@ func SendL2TxWithID(t *testing.T, chainID *big.Int, l2Client *ethclient.Client,
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)
}
......@@ -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.
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)
// If tip + basefee > gas fee cap, clamp it to the gas fee cap
if x.Cmp(gasFeeCap) > 0 {
......
package op_e2e
package helpers
import (
"context"
......@@ -8,6 +8,8 @@ import (
"testing"
"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-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
......@@ -37,7 +39,7 @@ type ClientProvider interface {
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()
applyOpts(opts)
......@@ -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)
finalizeReceipt, resolveClaimReceipt, resolveReceipt := FinalizeWithdrawal(t, cfg, clients.NodeClient("l1"), ethPrivKey, proveReceipt, params)
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
ctx, cancel := context.WithTimeout(context.Background(), 40*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
defer cancel()
l1Client := clients.NodeClient(RoleL1)
l1Client := clients.NodeClient(e2esys.RoleL1)
var blockNumber uint64
var err error
if e2eutils.UseFaultProofs() {
......@@ -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
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
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 (
"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-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
func TestTxGossip(t *testing.T) {
InitParallel(t)
cfg := DefaultSystemConfig(t)
op_e2e.InitParallel(t)
cfg := e2esys.DefaultSystemConfig(t)
gethOpts := []geth.GethOption{
geth.WithP2P(),
}
......@@ -30,7 +35,7 @@ func TestTxGossip(t *testing.T) {
require.NoError(t, err)
// 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.Value = common.Big1
opts.VerifyOnClients(seqClient, verifClient)
......
package op_e2e
package proofs
import (
"context"
......@@ -16,11 +16,11 @@ func BuildOpProgramClient(t *testing.T) string {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
cmd := exec.CommandContext(ctx, "make", "op-program-client")
cmd.Dir = "../op-program"
cmd.Dir = "../../../op-program"
var out strings.Builder
cmd.Stdout = &out
cmd.Stderr = &out
require.NoErrorf(t, cmd.Run(), "Failed to build op-program-client: %v", &out)
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 (
"context"
......@@ -6,6 +6,11 @@ import (
"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-e2e/system/helpers"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
......@@ -86,10 +91,10 @@ func applySpanBatchActivation(active bool, dp *genesis.DeployConfig) {
// - update the state root via a tx
// - run program
func testVerifyL2OutputRootEmptyBlock(t *testing.T, detached bool, spanBatchActivated bool) {
InitParallel(t)
op_e2e.InitParallel(t)
ctx := context.Background()
cfg := DefaultSystemConfig(t)
cfg := e2esys.DefaultSystemConfig(t)
// We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier")
// 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
t.Log("Sending transactions to setup existing state, prior to challenged period")
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.Value = big.NewInt(1_000)
})
......@@ -163,7 +168,7 @@ func testVerifyL2OutputRootEmptyBlock(t *testing.T, detached bool, spanBatchActi
require.NoError(t, err, "could not start batch submitter")
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.Value = big.NewInt(1_000)
opts.Nonce = 1
......@@ -186,10 +191,10 @@ func testVerifyL2OutputRootEmptyBlock(t *testing.T, detached bool, spanBatchActi
}
func testVerifyL2OutputRoot(t *testing.T, detached bool, spanBatchActivated bool) {
InitParallel(t)
op_e2e.InitParallel(t)
ctx := context.Background()
cfg := DefaultSystemConfig(t)
cfg := e2esys.DefaultSystemConfig(t)
// We don't need a verifier - just the sequencer is enough
delete(cfg.Nodes, "verifier")
applySpanBatchActivation(spanBatchActivated, cfg.DeployConfig)
......@@ -209,15 +214,15 @@ func testVerifyL2OutputRoot(t *testing.T, detached bool, spanBatchActivated bool
aliceKey := cfg.Secrets.Alice
opts, err := bind.NewKeyedTransactorWithChainID(aliceKey, cfg.L1ChainIDBig())
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)
})
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.Value = big.NewInt(1_000)
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.Nonce = 2
})
......@@ -231,14 +236,14 @@ func testVerifyL2OutputRoot(t *testing.T, detached bool, spanBatchActivated bool
l2OutputRoot := agreedL2Output.OutputRoot
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)
})
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.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.Nonce = 4
})
......@@ -276,7 +281,7 @@ type FaultProofProgramTestScenario struct {
}
// 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()
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()
......
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