Commit 5a18b066 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-e2e: Pass multiple chain configs through when running op-program in interop tests (#13731)

parent dd902048
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-program/client/claim" "github.com/ethereum-optimism/optimism/op-program/client/claim"
"github.com/ethereum-optimism/optimism/op-program/client/interop/types" "github.com/ethereum-optimism/optimism/op-program/client/interop/types"
"github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -355,20 +356,35 @@ func TestInteropFaultProofs(gt *testing.T) { ...@@ -355,20 +356,35 @@ func TestInteropFaultProofs(gt *testing.T) {
t, t,
logger, logger,
actors.L1Miner, actors.L1Miner,
actors.ChainA.Sequencer.L2Verifier,
actors.ChainA.SequencerEngine,
actors.ChainA.L2Genesis,
chain1End.BlockRef.Number,
checkResult, checkResult,
fpHelpers.WithInteropEnabled(), WithInteropEnabled(actors, test.agreedClaim, crypto.Keccak256Hash(test.disputedClaim), endTimestamp),
fpHelpers.WithAgreedPrestate(test.agreedClaim),
fpHelpers.WithL2Claim(crypto.Keccak256Hash(test.disputedClaim)),
fpHelpers.WithL2BlockNumber(endBlockNumA),
) )
}) })
} }
} }
func WithInteropEnabled(actors *InteropActors, agreedPrestate []byte, disputedClaim common.Hash, claimTimestamp uint64) fpHelpers.FixtureInputParam {
return func(f *fpHelpers.FixtureInputs) {
f.InteropEnabled = true
f.AgreedPrestate = agreedPrestate
f.L2OutputRoot = crypto.Keccak256Hash(agreedPrestate)
f.L2Claim = disputedClaim
f.L2BlockNumber = claimTimestamp
// TODO: Remove these once hints all specify the L2 chain ID
f.L2ChainID = actors.ChainA.ChainID.ToBig().Uint64()
f.L2Head = actors.ChainA.SequencerEngine.L2Chain().CurrentHeader().ParentHash
for _, chain := range []*Chain{actors.ChainA, actors.ChainB} {
f.L2Sources = append(f.L2Sources, &fpHelpers.FaultProofProgramL2Source{
Node: chain.Sequencer.L2Verifier,
Engine: chain.SequencerEngine,
ChainConfig: chain.L2Genesis.Config,
})
}
}
}
type transitionTest struct { type transitionTest struct {
name string name string
startTimestamp uint64 startTimestamp uint64
......
...@@ -6,7 +6,7 @@ import ( ...@@ -6,7 +6,7 @@ import (
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
e2ecfg "github.com/ethereum-optimism/optimism/op-e2e/config" e2ecfg "github.com/ethereum-optimism/optimism/op-e2e/config"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum-optimism/optimism/op-program/client/boot"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
altda "github.com/ethereum-optimism/optimism/op-alt-da" altda "github.com/ethereum-optimism/optimism/op-alt-da"
...@@ -14,7 +14,6 @@ import ( ...@@ -14,7 +14,6 @@ import (
"github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils"
"github.com/ethereum-optimism/optimism/op-program/host/config" "github.com/ethereum-optimism/optimism/op-program/host/config"
hostTypes "github.com/ethereum-optimism/optimism/op-program/host/types"
"github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -152,27 +151,17 @@ func WithL2Claim(claim common.Hash) FixtureInputParam { ...@@ -152,27 +151,17 @@ func WithL2Claim(claim common.Hash) FixtureInputParam {
} }
} }
func WithAgreedPrestate(prestate []byte) FixtureInputParam {
return func(f *FixtureInputs) {
f.AgreedPrestate = prestate
f.L2OutputRoot = crypto.Keccak256Hash(prestate)
}
}
func WithL2BlockNumber(num uint64) FixtureInputParam { func WithL2BlockNumber(num uint64) FixtureInputParam {
return func(f *FixtureInputs) { return func(f *FixtureInputs) {
f.L2BlockNumber = num f.L2BlockNumber = num
} }
} }
func WithInteropEnabled() FixtureInputParam {
return func(f *FixtureInputs) {
f.InteropEnabled = true
}
}
func (env *L2FaultProofEnv) RunFaultProofProgram(t helpers.Testing, l2ClaimBlockNum uint64, checkResult CheckResult, fixtureInputParams ...FixtureInputParam) { func (env *L2FaultProofEnv) RunFaultProofProgram(t helpers.Testing, l2ClaimBlockNum uint64, checkResult CheckResult, fixtureInputParams ...FixtureInputParam) {
RunFaultProofProgram(t, env.log, env.Miner, env.Sequencer.L2Verifier, env.Engine, env.Sd.L2Cfg, l2ClaimBlockNum, checkResult, fixtureInputParams...) defaultParam := WithPreInteropDefaults(t, l2ClaimBlockNum, env.Sequencer.L2Verifier, env.Engine)
combinedParams := []FixtureInputParam{defaultParam}
combinedParams = append(combinedParams, fixtureInputParams...)
RunFaultProofProgram(t, env.log, env.Miner, checkResult, combinedParams...)
} }
type TestParam func(p *e2eutils.TestParams) type TestParam func(p *e2eutils.TestParams)
...@@ -210,17 +199,17 @@ func NewBatcherCfg(params ...BatcherCfgParam) *helpers.BatcherCfg { ...@@ -210,17 +199,17 @@ func NewBatcherCfg(params ...BatcherCfgParam) *helpers.BatcherCfg {
} }
func NewOpProgramCfg( func NewOpProgramCfg(
t helpers.Testing,
rollupCfg *rollup.Config,
l2Genesis *params.ChainConfig,
fi *FixtureInputs, fi *FixtureInputs,
) *config.Config { ) *config.Config {
dfault := config.NewConfig(rollupCfg, l2Genesis, fi.L1Head, fi.L2Head, fi.L2OutputRoot, fi.L2Claim, fi.L2BlockNumber) var rollupConfigs []*rollup.Config
var chainConfigs []*params.ChainConfig
if dumpFixtures { for _, source := range fi.L2Sources {
dfault.DataDir = t.TempDir() rollupConfigs = append(rollupConfigs, source.Node.RollupCfg)
dfault.DataFormat = hostTypes.DataFormatPebble chainConfigs = append(chainConfigs, source.ChainConfig)
} }
dfault := config.NewConfig(rollupConfigs, chainConfigs, fi.L1Head, fi.L2Head, fi.L2OutputRoot, fi.L2Claim, fi.L2BlockNumber)
dfault.L2ChainID = boot.CustomChainIDIndicator
if fi.InteropEnabled { if fi.InteropEnabled {
dfault.AgreedPrestate = fi.AgreedPrestate dfault.AgreedPrestate = fi.AgreedPrestate
} }
......
package helpers package helpers
import ( import (
"encoding/json"
"errors"
"io/fs"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-program/client/claim"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/params"
"github.com/naoina/toml"
"github.com/stretchr/testify/require"
)
var (
dumpFixtures = false
fixtureDir string
) )
func init() {
fixtureDir = os.Getenv("OP_E2E_FPP_FIXTURE_DIR")
if fixtureDir != "" {
dumpFixtures = true
}
}
type TestFixture struct { type TestFixture struct {
Name string `toml:"name"` Name string `toml:"name"`
ExpectedStatus uint8 `toml:"expected-status"` ExpectedStatus uint8 `toml:"expected-status"`
Inputs FixtureInputs `toml:"inputs"` Inputs FixtureInputs `toml:"inputs"`
} }
type FaultProofProgramL2Source struct {
Node *helpers.L2Verifier
Engine *helpers.L2Engine
ChainConfig *params.ChainConfig
}
type FixtureInputs struct { type FixtureInputs struct {
L2BlockNumber uint64 `toml:"l2-block-number"` L2BlockNumber uint64 `toml:"l2-block-number"`
L2Claim common.Hash `toml:"l2-claim"` L2Claim common.Hash `toml:"l2-claim"`
...@@ -46,93 +27,6 @@ type FixtureInputs struct { ...@@ -46,93 +27,6 @@ type FixtureInputs struct {
L1Head common.Hash `toml:"l1-head"` L1Head common.Hash `toml:"l1-head"`
AgreedPrestate []byte `toml:"agreed-prestate"` AgreedPrestate []byte `toml:"agreed-prestate"`
InteropEnabled bool `toml:"use-interop"` InteropEnabled bool `toml:"use-interop"`
}
// Dumps a `fp-tests` test fixture to disk if the `OP_E2E_FPP_FIXTURE_DIR` environment variable is set.
//
// [fp-tests]: https://github.com/ethereum-optimism/fp-tests
func tryDumpTestFixture(
t helpers.Testing,
result error,
name string,
rollupCfg *rollup.Config,
l2Genesis *core.Genesis,
inputs FixtureInputs,
workDir string,
) {
if !dumpFixtures {
return
}
name = convertToKebabCase(name)
var expectedStatus uint8
if result == nil {
expectedStatus = 0
} else if errors.Is(result, claim.ErrClaimNotValid) {
expectedStatus = 1
} else {
expectedStatus = 2
}
fixture := TestFixture{
Name: name,
ExpectedStatus: expectedStatus,
Inputs: inputs,
}
fixturePath := filepath.Join(fixtureDir, name)
err := os.MkdirAll(filepath.Join(fixturePath), fs.ModePerm)
require.NoError(t, err, "failed to create fixture dir")
fixtureFilePath := filepath.Join(fixturePath, "fixture.toml")
serFixture, err := toml.Marshal(fixture)
require.NoError(t, err, "failed to serialize fixture")
require.NoError(t, os.WriteFile(fixtureFilePath, serFixture, fs.ModePerm), "failed to write fixture")
genesisPath := filepath.Join(fixturePath, "genesis.json")
serGenesis, err := l2Genesis.MarshalJSON()
require.NoError(t, err, "failed to serialize genesis")
require.NoError(t, os.WriteFile(genesisPath, serGenesis, fs.ModePerm), "failed to write genesis")
rollupPath := filepath.Join(fixturePath, "rollup.json")
serRollup, err := json.Marshal(rollupCfg)
require.NoError(t, err, "failed to serialize rollup")
require.NoError(t, os.WriteFile(rollupPath, serRollup, fs.ModePerm), "failed to write rollup")
// Copy the witness database into the fixture directory.
cmd := exec.Command("cp", "-r", workDir, filepath.Join(fixturePath, "witness-db"))
require.NoError(t, cmd.Run(), "Failed to copy witness DB")
// Compress the genesis file.
cmd = exec.Command("zstd", genesisPath)
_ = cmd.Run()
require.NoError(t, os.Remove(genesisPath), "Failed to remove uncompressed genesis file")
// Compress the witness database.
cmd = exec.Command(
"tar",
"--zstd",
"-cf",
filepath.Join(fixturePath, "witness-db.tar.zst"),
filepath.Join(fixturePath, "witness-db"),
)
cmd.Dir = filepath.Join(fixturePath)
require.NoError(t, cmd.Run(), "Failed to compress witness DB")
require.NoError(t, os.RemoveAll(filepath.Join(fixturePath, "witness-db")), "Failed to remove uncompressed witness DB")
}
// Convert to lower kebab case for strings containing `/`
func convertToKebabCase(input string) string {
if !strings.Contains(input, "/") {
return input
}
// Replace non-alphanumeric characters with underscores
re := regexp.MustCompile(`[^a-zA-Z0-9]+`)
snake := re.ReplaceAllString(input, "-")
// Convert to lower case L2Sources []*FaultProofProgramL2Source
return strings.ToLower(snake)
} }
...@@ -5,7 +5,6 @@ import ( ...@@ -5,7 +5,6 @@ import (
"github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/fakebeacon" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/fakebeacon"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-program/host" "github.com/ethereum-optimism/optimism/op-program/host"
hostcommon "github.com/ethereum-optimism/optimism/op-program/host/common" hostcommon "github.com/ethereum-optimism/optimism/op-program/host/common"
"github.com/ethereum-optimism/optimism/op-program/host/config" "github.com/ethereum-optimism/optimism/op-program/host/config"
...@@ -14,7 +13,6 @@ import ( ...@@ -14,7 +13,6 @@ import (
"github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/client"
"github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
...@@ -26,33 +24,50 @@ type L2 interface { ...@@ -26,33 +24,50 @@ type L2 interface {
RollupClient() *sources.RollupClient RollupClient() *sources.RollupClient
} }
func RunFaultProofProgram(t helpers.Testing, logger log.Logger, l1 *helpers.L1Miner, l2 *helpers.L2Verifier, l2Eng *helpers.L2Engine, l2ChainConfig *core.Genesis, l2ClaimBlockNum uint64, checkResult CheckResult, fixtureInputParams ...FixtureInputParam) { func WithPreInteropDefaults(t helpers.Testing, l2ClaimBlockNum uint64, l2 *helpers.L2Verifier, l2Eng *helpers.L2Engine) FixtureInputParam {
// Fetch the pre and post output roots for the fault proof. return func(f *FixtureInputs) {
l2PreBlockNum := l2ClaimBlockNum - 1 // Fetch the pre and post output roots for the fault proof.
if l2ClaimBlockNum == 0 { l2PreBlockNum := l2ClaimBlockNum - 1
// If we are at genesis, we assert that we don't move the chain at all. if l2ClaimBlockNum == 0 {
l2PreBlockNum = 0 // If we are at genesis, we assert that we don't move the chain at all.
l2PreBlockNum = 0
}
rollupClient := l2.RollupClient()
preRoot, err := rollupClient.OutputAtBlock(t.Ctx(), l2PreBlockNum)
require.NoError(t, err)
claimRoot, err := rollupClient.OutputAtBlock(t.Ctx(), l2ClaimBlockNum)
require.NoError(t, err)
f.L2BlockNumber = l2ClaimBlockNum
f.L2Claim = common.Hash(claimRoot.OutputRoot)
f.L2Head = preRoot.BlockRef.Hash
f.L2OutputRoot = common.Hash(preRoot.OutputRoot)
f.L2ChainID = l2.RollupCfg.L2ChainID.Uint64()
f.L2Sources = []*FaultProofProgramL2Source{
{
Node: l2,
Engine: l2Eng,
ChainConfig: l2Eng.L2Chain().Config(),
},
}
} }
preRoot, err := l2.RollupClient().OutputAtBlock(t.Ctx(), l2PreBlockNum) }
require.NoError(t, err)
claimRoot, err := l2.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum) func RunFaultProofProgram(t helpers.Testing, logger log.Logger, l1 *helpers.L1Miner, checkResult CheckResult, fixtureInputParams ...FixtureInputParam) {
require.NoError(t, err)
l1Head := l1.L1Chain().CurrentBlock() l1Head := l1.L1Chain().CurrentBlock()
fixtureInputs := &FixtureInputs{ fixtureInputs := &FixtureInputs{
L2BlockNumber: l2ClaimBlockNum, L1Head: l1Head.Hash(),
L2Claim: common.Hash(claimRoot.OutputRoot),
L2Head: preRoot.BlockRef.Hash,
L2OutputRoot: common.Hash(preRoot.OutputRoot),
L2ChainID: l2.RollupCfg.L2ChainID.Uint64(),
L1Head: l1Head.Hash(),
} }
for _, apply := range fixtureInputParams { for _, apply := range fixtureInputParams {
apply(fixtureInputs) apply(fixtureInputs)
} }
require.Greater(t, len(fixtureInputs.L2Sources), 0, "Must specify at least one L2 source")
// Run the fault proof program from the state transition from L2 block l2ClaimBlockNum - 1 -> l2ClaimBlockNum. // Run the fault proof program from the state transition from L2 block l2ClaimBlockNum - 1 -> l2ClaimBlockNum.
workDir := t.TempDir() workDir := t.TempDir()
var err error
if IsKonaConfigured() { if IsKonaConfigured() {
fakeBeacon := fakebeacon.NewBeacon( fakeBeacon := fakebeacon.NewBeacon(
logger, logger,
...@@ -63,29 +78,28 @@ func RunFaultProofProgram(t helpers.Testing, logger log.Logger, l1 *helpers.L1Mi ...@@ -63,29 +78,28 @@ func RunFaultProofProgram(t helpers.Testing, logger log.Logger, l1 *helpers.L1Mi
require.NoError(t, fakeBeacon.Start("127.0.0.1:0")) require.NoError(t, fakeBeacon.Start("127.0.0.1:0"))
defer fakeBeacon.Close() defer fakeBeacon.Close()
err := RunKonaNative(t, workDir, l2.RollupCfg, l1.HTTPEndpoint(), fakeBeacon.BeaconAddr(), l2Eng.HTTPEndpoint(), *fixtureInputs) l2Source := fixtureInputs.L2Sources[0]
err = RunKonaNative(t, workDir, l2Source.Node.RollupCfg, l1.HTTPEndpoint(), fakeBeacon.BeaconAddr(), l2Source.Engine.HTTPEndpoint(), *fixtureInputs)
checkResult(t, err) checkResult(t, err)
} else { } else {
programCfg := NewOpProgramCfg( programCfg := NewOpProgramCfg(fixtureInputs)
t,
l2.RollupCfg,
l2ChainConfig.Config,
fixtureInputs,
)
withInProcessPrefetcher := hostcommon.WithPrefetcher(func(ctx context.Context, logger log.Logger, kv kvstore.KV, cfg *config.Config) (hostcommon.Prefetcher, error) { withInProcessPrefetcher := hostcommon.WithPrefetcher(func(ctx context.Context, logger log.Logger, kv kvstore.KV, cfg *config.Config) (hostcommon.Prefetcher, error) {
// Set up in-process L1 sources // Set up in-process L1 sources
l1Cl := l1.L1Client(t, l2.RollupCfg) l1Cl := l1.L1ClientSimple(t)
l1BlobFetcher := l1.BlobSource() l1BlobFetcher := l1.BlobSource()
// Set up in-process L2 source // Set up in-process L2 source
sources, err := prefetcher.NewRetryingL2Sources(ctx, logger, []*rollup.Config{l2.RollupCfg}, []client.RPC{l2Eng.RPCClient()}, nil) var rpcClients []client.RPC
for _, source := range fixtureInputs.L2Sources {
rpcClients = append(rpcClients, source.Engine.RPCClient())
}
sources, err := prefetcher.NewRetryingL2Sources(ctx, logger, programCfg.Rollups, rpcClients, nil)
require.NoError(t, err, "failed to create L2 client") require.NoError(t, err, "failed to create L2 client")
executor := host.MakeProgramExecutor(logger, programCfg) executor := host.MakeProgramExecutor(logger, programCfg)
return prefetcher.NewPrefetcher(logger, l1Cl, l1BlobFetcher, l2.RollupCfg.L2ChainID.Uint64(), sources, kv, executor, cfg.L2Head, cfg.AgreedPrestate), nil return prefetcher.NewPrefetcher(logger, l1Cl, l1BlobFetcher, fixtureInputs.L2ChainID, sources, kv, executor, cfg.L2Head, cfg.AgreedPrestate), nil
}) })
err = hostcommon.FaultProofProgram(t.Ctx(), logger, programCfg, withInProcessPrefetcher) err = hostcommon.FaultProofProgram(t.Ctx(), logger, programCfg, withInProcessPrefetcher)
checkResult(t, err) checkResult(t, err)
} }
tryDumpTestFixture(t, err, t.Name(), l2.RollupCfg, l2ChainConfig, *fixtureInputs, workDir)
} }
...@@ -285,7 +285,7 @@ type FaultProofProgramTestScenario struct { ...@@ -285,7 +285,7 @@ type FaultProofProgramTestScenario struct {
// testFaultProofProgramScenario runs the fault proof program in several contexts, given a test scenario. // testFaultProofProgramScenario runs the fault proof program in several contexts, given a test scenario.
func testFaultProofProgramScenario(t *testing.T, ctx context.Context, sys *e2esys.System, s *FaultProofProgramTestScenario) { func testFaultProofProgramScenario(t *testing.T, ctx context.Context, sys *e2esys.System, s *FaultProofProgramTestScenario) {
preimageDir := t.TempDir() preimageDir := t.TempDir()
fppConfig := oppconf.NewConfig(sys.RollupConfig, sys.L2GenesisCfg.Config, s.L1Head, s.L2Head, s.L2OutputRoot, common.Hash(s.L2Claim), s.L2ClaimBlockNumber) fppConfig := oppconf.NewSingleChainConfig(sys.RollupConfig, sys.L2GenesisCfg.Config, s.L1Head, s.L2Head, s.L2OutputRoot, common.Hash(s.L2Claim), s.L2ClaimBlockNumber)
fppConfig.L1URL = sys.NodeEndpoint("l1").RPC() fppConfig.L1URL = sys.NodeEndpoint("l1").RPC()
fppConfig.L2URLs = []string{sys.NodeEndpoint("sequencer").RPC()} fppConfig.L2URLs = []string{sys.NodeEndpoint("sequencer").RPC()}
fppConfig.L1BeaconURL = sys.L1BeaconEndpoint().RestHTTP() fppConfig.L1BeaconURL = sys.L1BeaconEndpoint().RestHTTP()
......
...@@ -74,7 +74,7 @@ func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) { ...@@ -74,7 +74,7 @@ func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs()) cfg := configForArgs(t, addRequiredArgs())
rollupCfg, err := chaincfg.GetRollupConfig("op-sepolia") rollupCfg, err := chaincfg.GetRollupConfig("op-sepolia")
require.NoError(t, err) require.NoError(t, err)
defaultCfg := config.NewConfig( defaultCfg := config.NewSingleChainConfig(
rollupCfg, rollupCfg,
chainconfig.OPSepoliaChainConfig(), chainconfig.OPSepoliaChainConfig(),
common.HexToHash(l1HeadValue), common.HexToHash(l1HeadValue),
......
...@@ -25,6 +25,7 @@ import ( ...@@ -25,6 +25,7 @@ import (
) )
var ( var (
ErrMissingL2ChainID = errors.New("missing l2 chain id")
ErrMissingRollupConfig = errors.New("missing rollup config") ErrMissingRollupConfig = errors.New("missing rollup config")
ErrMissingL2Genesis = errors.New("missing l2 genesis") ErrMissingL2Genesis = errors.New("missing l2 genesis")
ErrInvalidL1Head = errors.New("invalid l1 head") ErrInvalidL1Head = errors.New("invalid l1 head")
...@@ -92,6 +93,9 @@ type Config struct { ...@@ -92,6 +93,9 @@ type Config struct {
} }
func (c *Config) Check() error { func (c *Config) Check() error {
if !c.InteropEnabled && c.L2ChainID == 0 {
return ErrMissingL2ChainID
}
if len(c.Rollups) == 0 { if len(c.Rollups) == 0 {
return ErrMissingRollupConfig return ErrMissingRollupConfig
} }
...@@ -142,26 +146,46 @@ func (c *Config) FetchingEnabled() bool { ...@@ -142,26 +146,46 @@ func (c *Config) FetchingEnabled() bool {
return c.L1URL != "" && len(c.L2URLs) > 0 && c.L1BeaconURL != "" return c.L1URL != "" && len(c.L2URLs) > 0 && c.L1BeaconURL != ""
} }
// NewConfig creates a Config with all optional values set to the CLI default value func NewSingleChainConfig(
func NewConfig(
rollupCfg *rollup.Config, rollupCfg *rollup.Config,
l2Genesis *params.ChainConfig, l2ChainConfig *params.ChainConfig,
l1Head common.Hash, l1Head common.Hash,
l2Head common.Hash, l2Head common.Hash,
l2OutputRoot common.Hash, l2OutputRoot common.Hash,
l2Claim common.Hash, l2Claim common.Hash,
l2ClaimBlockNum uint64, l2ClaimBlockNum uint64,
) *Config { ) *Config {
l2ChainID := l2Genesis.ChainID.Uint64() l2ChainID := l2ChainConfig.ChainID.Uint64()
_, err := params.LoadOPStackChainConfig(l2ChainID) _, err := params.LoadOPStackChainConfig(l2ChainID)
if err != nil { if err != nil {
// Unknown chain ID so assume it is custom // Unknown chain ID so assume it is custom
l2ChainID = boot.CustomChainIDIndicator l2ChainID = boot.CustomChainIDIndicator
} }
cfg := NewConfig(
[]*rollup.Config{rollupCfg},
[]*params.ChainConfig{l2ChainConfig},
l1Head,
l2Head,
l2OutputRoot,
l2Claim,
l2ClaimBlockNum)
cfg.L2ChainID = l2ChainID
return cfg
}
// NewConfig creates a Config with all optional values set to the CLI default value
func NewConfig(
rollupCfgs []*rollup.Config,
l2ChainConfigs []*params.ChainConfig,
l1Head common.Hash,
l2Head common.Hash,
l2OutputRoot common.Hash,
l2Claim common.Hash,
l2ClaimBlockNum uint64,
) *Config {
return &Config{ return &Config{
L2ChainID: l2ChainID, Rollups: rollupCfgs,
Rollups: []*rollup.Config{rollupCfg}, L2ChainConfigs: l2ChainConfigs,
L2ChainConfigs: []*params.ChainConfig{l2Genesis},
L1Head: l1Head, L1Head: l1Head,
L2Head: l2Head, L2Head: l2Head,
L2OutputRoot: l2OutputRoot, L2OutputRoot: l2OutputRoot,
......
...@@ -24,6 +24,7 @@ var ( ...@@ -24,6 +24,7 @@ var (
validL2Claim = common.Hash{0xcc} validL2Claim = common.Hash{0xcc}
validL2OutputRoot = common.Hash{0xdd} validL2OutputRoot = common.Hash{0xdd}
validL2ClaimBlockNum = uint64(15) validL2ClaimBlockNum = uint64(15)
validAgreedPrestate = []byte{1}
) )
// TestValidConfigIsValid checks that the config provided by validConfig is actually valid // TestValidConfigIsValid checks that the config provided by validConfig is actually valid
...@@ -32,6 +33,26 @@ func TestValidConfigIsValid(t *testing.T) { ...@@ -32,6 +33,26 @@ func TestValidConfigIsValid(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
} }
// TestValidInteropConfigIsValid checks that the config provided by validInteropConfig is actually valid
func TestValidInteropConfigIsValid(t *testing.T) {
err := validInteropConfig().Check()
require.NoError(t, err)
}
func TestL2BlockNum(t *testing.T) {
t.Run("RequiredForPreInterop", func(t *testing.T) {
cfg := validConfig()
cfg.L2ChainID = 0
require.ErrorIs(t, cfg.Check(), ErrMissingL2ChainID)
})
t.Run("NotRequiredForInterop", func(t *testing.T) {
cfg := validInteropConfig()
cfg.L2ChainID = 0
require.NoError(t, cfg.Check())
})
}
func TestRollupConfig(t *testing.T) { func TestRollupConfig(t *testing.T) {
t.Run("Required", func(t *testing.T) { t.Run("Required", func(t *testing.T) {
config := validConfig() config := validConfig()
...@@ -42,7 +63,7 @@ func TestRollupConfig(t *testing.T) { ...@@ -42,7 +63,7 @@ func TestRollupConfig(t *testing.T) {
t.Run("Invalid", func(t *testing.T) { t.Run("Invalid", func(t *testing.T) {
config := validConfig() config := validConfig()
config.Rollups = []*rollup.Config{&rollup.Config{}} config.Rollups = []*rollup.Config{{}}
err := config.Check() err := config.Check()
require.ErrorIs(t, err, rollup.ErrBlockTimeZero) require.ErrorIs(t, err, rollup.ErrBlockTimeZero)
}) })
...@@ -178,7 +199,7 @@ func TestCustomL2ChainID(t *testing.T) { ...@@ -178,7 +199,7 @@ func TestCustomL2ChainID(t *testing.T) {
}) })
t.Run("custom", func(t *testing.T) { t.Run("custom", func(t *testing.T) {
customChainConfig := &params.ChainConfig{ChainID: big.NewInt(0x1212121212)} customChainConfig := &params.ChainConfig{ChainID: big.NewInt(0x1212121212)}
cfg := NewConfig(validRollupConfig, customChainConfig, validL1Head, validL2Head, validL2OutputRoot, validL2Claim, validL2ClaimBlockNum) cfg := NewSingleChainConfig(validRollupConfig, customChainConfig, validL1Head, validL2Head, validL2OutputRoot, validL2Claim, validL2ClaimBlockNum)
require.Equal(t, cfg.L2ChainID, boot.CustomChainIDIndicator) require.Equal(t, cfg.L2ChainID, boot.CustomChainIDIndicator)
}) })
} }
...@@ -239,7 +260,15 @@ func TestDBFormat(t *testing.T) { ...@@ -239,7 +260,15 @@ func TestDBFormat(t *testing.T) {
} }
func validConfig() *Config { func validConfig() *Config {
cfg := NewConfig(validRollupConfig, validL2Genesis, validL1Head, validL2Head, validL2OutputRoot, validL2Claim, validL2ClaimBlockNum) cfg := NewSingleChainConfig(validRollupConfig, validL2Genesis, validL1Head, validL2Head, validL2OutputRoot, validL2Claim, validL2ClaimBlockNum)
cfg.DataDir = "/tmp/configTest" cfg.DataDir = "/tmp/configTest"
return cfg return cfg
} }
func validInteropConfig() *Config {
cfg := validConfig()
cfg.InteropEnabled = true
cfg.AgreedPrestate = validAgreedPrestate
cfg.L2OutputRoot = crypto.Keccak256Hash(cfg.AgreedPrestate)
return cfg
}
...@@ -25,7 +25,7 @@ func TestServerMode(t *testing.T) { ...@@ -25,7 +25,7 @@ func TestServerMode(t *testing.T) {
l1Head := common.Hash{0x11} l1Head := common.Hash{0x11}
l2OutputRoot := common.Hash{0x33} l2OutputRoot := common.Hash{0x33}
cfg := config.NewConfig(chaincfg.OPSepolia(), chainconfig.OPSepoliaChainConfig(), l1Head, common.Hash{0x22}, l2OutputRoot, common.Hash{0x44}, 1000) cfg := config.NewSingleChainConfig(chaincfg.OPSepolia(), chainconfig.OPSepoliaChainConfig(), l1Head, common.Hash{0x22}, l2OutputRoot, common.Hash{0x44}, 1000)
cfg.DataDir = dir cfg.DataDir = dir
cfg.ServerMode = true cfg.ServerMode = true
......
...@@ -320,9 +320,9 @@ func (p *Prefetcher) prefetch(ctx context.Context, hint string) error { ...@@ -320,9 +320,9 @@ func (p *Prefetcher) prefetch(ctx context.Context, hint string) error {
if err != nil { if err != nil {
return fmt.Errorf("failed to fetch L2 output root for block %s: %w", p.l2Head, err) return fmt.Errorf("failed to fetch L2 output root for block %s: %w", p.l2Head, err)
} }
hash := eth.OutputRoot(output) hash := common.Hash(eth.OutputRoot(output))
if requestedHash != common.Hash(hash) { if requestedHash != hash {
return fmt.Errorf("output root %x from block %v does not match requested root: %x", hash, p.l2Head, requestedHash) return fmt.Errorf("output root %v from block %v does not match requested root: %v", hash, p.l2Head, requestedHash)
} }
return p.kvStore.Put(preimage.Keccak256Key(hash).PreimageKey(), output.Marshal()) return p.kvStore.Put(preimage.Keccak256Key(hash).PreimageKey(), output.Marshal())
case l2.HintL2BlockData: case l2.HintL2BlockData:
......
...@@ -209,7 +209,7 @@ func (r *Runner) run(ctx context.Context, l1Head common.Hash, agreedBlockInfo et ...@@ -209,7 +209,7 @@ func (r *Runner) run(ctx context.Context, l1Head common.Hash, agreedBlockInfo et
fmt.Printf("Configuration: %s\n", argsStr) fmt.Printf("Configuration: %s\n", argsStr)
if r.runInProcess { if r.runInProcess {
offlineCfg := config.NewConfig( offlineCfg := config.NewSingleChainConfig(
r.rollupCfg, r.chainCfg, l1Head, agreedBlockInfo.Hash(), agreedOutputRoot, claimedOutputRoot, claimedBlockInfo.NumberU64()) r.rollupCfg, r.chainCfg, l1Head, agreedBlockInfo.Hash(), agreedOutputRoot, claimedOutputRoot, claimedBlockInfo.NumberU64())
offlineCfg.DataDir = r.dataDir offlineCfg.DataDir = r.dataDir
......
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