Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 37 additions & 13 deletions op-chain-ops/interopgen/recipe.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import (

type InteropDevRecipe struct {
L1ChainID uint64
L2ChainIDs []uint64
L2s []InteropDevL2Recipe
GenesisTimestamp uint64
}

func (r *InteropDevRecipe) Build(addrs devkeys.Addresses) (*WorldConfig, error) {
func (recipe *InteropDevRecipe) Build(addrs devkeys.Addresses) (*WorldConfig, error) {
r := recipe.hydrated()

// L1 genesis
l1Cfg := &L1Config{
ChainID: new(big.Int).SetUint64(r.L1ChainID),
Expand Down Expand Up @@ -88,19 +90,41 @@ func (r *InteropDevRecipe) Build(addrs devkeys.Addresses) (*WorldConfig, error)
Superchain: superchainCfg,
L2s: make(map[string]*L2Config),
}
for _, l2ChainID := range r.L2ChainIDs {
l2Cfg, err := InteropL2DevConfig(r.L1ChainID, l2ChainID, addrs)
for _, l2 := range r.L2s {
l2Cfg, err := l2.build(r.L1ChainID, addrs)
if err != nil {
return nil, fmt.Errorf("failed to generate L2 config for chain %d: %w", l2ChainID, err)
return nil, fmt.Errorf("failed to generate L2 config for chain %d: %w", l2.ChainID, err)
}
if err := prefundL2Accounts(l1Cfg, l2Cfg, addrs); err != nil {
return nil, fmt.Errorf("failed to prefund addresses on L1 for L2 chain %d: %w", l2ChainID, err)
return nil, fmt.Errorf("failed to prefund addresses on L1 for L2 chain %d: %w", l2.ChainID, err)
}
world.L2s[fmt.Sprintf("%d", l2ChainID)] = l2Cfg
world.L2s[fmt.Sprintf("%d", l2.ChainID)] = l2Cfg
}
return world, nil
}

func (r *InteropDevRecipe) hydrated() InteropDevRecipe {
out := InteropDevRecipe{
L1ChainID: r.L1ChainID,
L2s: make([]InteropDevL2Recipe, len(r.L2s)),
GenesisTimestamp: r.GenesisTimestamp,
}
for i, l := range r.L2s {
out.L2s[i] = l
if l.BlockTime == 0 {
out.L2s[i].BlockTime = defaultBlockTime
}
}
return out
}

const defaultBlockTime = 2

type InteropDevL2Recipe struct {
ChainID uint64
BlockTime uint64
}

func prefundL2Accounts(l1Cfg *L1Config, l2Cfg *L2Config, addrs devkeys.Addresses) error {
l1Cfg.Prefund[l2Cfg.BatchSenderAddress] = Ether(10_000_000)
l1Cfg.Prefund[l2Cfg.Deployer] = Ether(10_000_000)
Expand All @@ -125,10 +149,10 @@ func prefundL2Accounts(l1Cfg *L1Config, l2Cfg *L2Config, addrs devkeys.Addresses
return nil
}

func InteropL2DevConfig(l1ChainID, l2ChainID uint64, addrs devkeys.Addresses) (*L2Config, error) {
func (r *InteropDevL2Recipe) build(l1ChainID uint64, addrs devkeys.Addresses) (*L2Config, error) {
// Padded chain ID, hex encoded, prefixed with 0xff like inboxes, then 0x02 to signify devnet.
batchInboxAddress := common.HexToAddress(fmt.Sprintf("0xff02%016x", l2ChainID))
chainOps := devkeys.ChainOperatorKeys(new(big.Int).SetUint64(l2ChainID))
batchInboxAddress := common.HexToAddress(fmt.Sprintf("0xff02%016x", r.ChainID))
chainOps := devkeys.ChainOperatorKeys(new(big.Int).SetUint64(r.ChainID))

deployer, err := addrs.Address(chainOps(devkeys.DeployerRole))
if err != nil {
Expand Down Expand Up @@ -238,8 +262,8 @@ func InteropL2DevConfig(l1ChainID, l2ChainID uint64, addrs devkeys.Addresses) (*
},
L2CoreDeployConfig: genesis.L2CoreDeployConfig{
L1ChainID: l1ChainID,
L2ChainID: l2ChainID,
L2BlockTime: 2,
L2ChainID: r.ChainID,
L2BlockTime: r.BlockTime,
FinalizationPeriodSeconds: 2, // instant output finalization
MaxSequencerDrift: 300,
SequencerWindowSize: 200,
Expand All @@ -262,7 +286,7 @@ func InteropL2DevConfig(l1ChainID, l2ChainID uint64, addrs devkeys.Addresses) (*
DisputeMaxClockDuration: 302400, // 3.5 days (input in seconds)
}

l2Users := devkeys.ChainUserKeys(new(big.Int).SetUint64(l2ChainID))
l2Users := devkeys.ChainUserKeys(new(big.Int).SetUint64(r.ChainID))
for i := uint64(0); i < 20; i++ {
userAddr, err := addrs.Address(l2Users(i))
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions op-e2e/actions/interop/dsl/dsl.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ type InteropDSL struct {
createdUsers uint64
}

func NewInteropDSL(t helpers.Testing) *InteropDSL {
setup := SetupInterop(t)
func NewInteropDSL(t helpers.Testing, opts ...setupOption) *InteropDSL {
setup := SetupInterop(t, opts...)
actors := setup.CreateActors()
actors.PrepareChainState(t)

Expand Down
25 changes: 21 additions & 4 deletions op-e2e/actions/interop/dsl/interop.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,32 @@ func (actors *InteropActors) PrepareChainState(t helpers.Testing) {
// At a 2 second block time, this should be small enough to cover all events buffered in the supervisor event queue.
const messageExpiryTime = 120 // 2 minutes

// SetupInterop creates an InteropSetup to instantiate actors on, with 2 L2 chains.
func SetupInterop(t helpers.Testing) *InteropSetup {
logger := testlog.Logger(t, log.LevelDebug)
type setupOption func(*interopgen.InteropDevRecipe)

func SetBlockTimeForChainA(blockTime uint64) setupOption {
return func(recipe *interopgen.InteropDevRecipe) {
recipe.L2s[0].BlockTime = blockTime
}
}

func SetBlockTimeForChainB(blockTime uint64) setupOption {
return func(recipe *interopgen.InteropDevRecipe) {
recipe.L2s[1].BlockTime = blockTime
}
}

// SetupInterop creates an InteropSetup to instantiate actors on, with 2 L2 chains.
func SetupInterop(t helpers.Testing, opts ...setupOption) *InteropSetup {
recipe := interopgen.InteropDevRecipe{
L1ChainID: 900100,
L2ChainIDs: []uint64{900200, 900201},
L2s: []interopgen.InteropDevL2Recipe{{ChainID: 900200}, {ChainID: 900201}},
GenesisTimestamp: uint64(time.Now().Unix() + 3),
}
for _, opt := range opts {
opt(&recipe)
}

logger := testlog.Logger(t, log.LevelDebug)
hdWallet, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic)
require.NoError(t, err)
worldCfg, err := recipe.Build(hdWallet)
Expand Down
22 changes: 22 additions & 0 deletions op-e2e/actions/interop/proofs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,19 @@ func TestInteropFaultProofsInvalidBlock(gt *testing.T) {
runFppAndChallengerTests(gt, system, tests)
}

func TestInteropFaultProofs_VariedBlockTimes(gt *testing.T) {
t := helpers.NewDefaultTesting(gt)
system := dsl.NewInteropDSL(t, dsl.SetBlockTimeForChainA(1), dsl.SetBlockTimeForChainB(2))
actors := system.Actors

system.AddL2Block(system.Actors.ChainA)
system.AddL2Block(system.Actors.ChainB)

assertTime(t, actors.ChainA, 1, 1, 0, 0)
assertTime(t, actors.ChainB, 2, 2, 0, 0)
// TODO(#14479): Complete test case
}

func runFppAndChallengerTests(gt *testing.T, system *dsl.InteropDSL, tests []*transitionTest) {
for _, test := range tests {
test := test
Expand Down Expand Up @@ -873,6 +886,15 @@ func WithInteropEnabled(t helpers.StatefulTesting, actors *dsl.InteropActors, de
}
}

func assertTime(t helpers.Testing, chain *dsl.Chain, unsafe, crossUnsafe, localSafe, safe uint64) {
start := chain.L2Genesis.Timestamp
status := chain.Sequencer.SyncStatus()
require.Equal(t, start+unsafe, status.UnsafeL2.Time, "Unsafe")
require.Equal(t, start+crossUnsafe, status.CrossUnsafeL2.Time, "Cross Unsafe")
require.Equal(t, start+localSafe, status.LocalSafeL2.Time, "Local safe")
require.Equal(t, start+safe, status.SafeL2.Time, "Safe")
}

type transitionTest struct {
name string
agreedClaim []byte
Expand Down
2 changes: 1 addition & 1 deletion op-e2e/faultproofs/util_interop.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func StartInteropFaultDisputeSystem(t *testing.T, opts ...faultDisputeConfigOpts
}
recipe := interopgen.InteropDevRecipe{
L1ChainID: 900100,
L2ChainIDs: []uint64{900200, 900201},
L2s: []interopgen.InteropDevL2Recipe{{ChainID: 900200}, {ChainID: 900201}},
GenesisTimestamp: uint64(time.Now().Unix() + 3), // start chain 3 seconds from now
}
worldResources := interop.WorldResourcePaths{
Expand Down
2 changes: 1 addition & 1 deletion op-e2e/interop/interop_recipe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
func TestInteropDevRecipe(t *testing.T) {
rec := interopgen.InteropDevRecipe{
L1ChainID: 900100,
L2ChainIDs: []uint64{900200, 900201},
L2s: []interopgen.InteropDevL2Recipe{{ChainID: 900200}, {ChainID: 900201}},
GenesisTimestamp: uint64(1234567),
}
hd, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic)
Expand Down
2 changes: 1 addition & 1 deletion op-e2e/interop/interop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
func setupAndRun(t *testing.T, config SuperSystemConfig, fn func(*testing.T, SuperSystem)) {
recipe := interopgen.InteropDevRecipe{
L1ChainID: 900100,
L2ChainIDs: []uint64{900200, 900201},
L2s: []interopgen.InteropDevL2Recipe{{ChainID: 900200}, {ChainID: 900201}},
GenesisTimestamp: uint64(time.Now().Unix() + 3), // start chain 3 seconds from now
}
worldResources := WorldResourcePaths{
Expand Down
7 changes: 6 additions & 1 deletion op-node/cmd/interop/interop.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,14 @@ var InteropDevSetup = &cli.Command{
logCfg := oplog.ReadCLIConfig(cliCtx)
logger := oplog.NewLogger(cliCtx.App.Writer, logCfg)

l2ChainIDs := cliCtx.Uint64Slice(l2ChainIDsFlag.Name)
l2Recipes := make([]interopgen.InteropDevL2Recipe, len(l2ChainIDs))
for i, id := range l2ChainIDs {
l2Recipes[i] = interopgen.InteropDevL2Recipe{ChainID: id}
}
recipe := &interopgen.InteropDevRecipe{
L1ChainID: cliCtx.Uint64(l1ChainIDFlag.Name),
L2ChainIDs: cliCtx.Uint64Slice(l2ChainIDsFlag.Name),
L2s: l2Recipes,
GenesisTimestamp: cliCtx.Uint64(timestampFlag.Name),
}
if recipe.GenesisTimestamp == 0 {
Expand Down