diff --git a/.circleci/config.yml b/.circleci/config.yml index c8822c39a9d..e4e3bdcfd69 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1146,6 +1146,10 @@ jobs: fork_base_rpc: description: Fork Base RPC type: string + dev_features: + description: Comma-separated list of dev features to enable (e.g., "OPTIMISM_PORTAL_INTEROP,ANOTHER_FEATURE") + type: string + default: "" docker: - image: <> resource_class: xlarge @@ -1176,6 +1180,8 @@ jobs: - restore_cache: name: Restore forked state key: forked-state-contracts-bedrock-tests-upgrade-<>-<>-{{ checksum "packages/contracts-bedrock/pinnedBlockNumber.txt" }} + - setup-dev-features: + dev_features: <> - run: name: Run tests command: just test-upgrade @@ -1594,14 +1600,10 @@ jobs: description: Timeout for when CircleCI kills the job if there's no output type: string default: 30m - use_circleci_runner: - description: Whether to use CircleCI runners (with Docker) instead of self-hosted runners - type: boolean - default: false - machine: - image: <<# parameters.use_circleci_runner >>ubuntu-2404:current<><<^ parameters.use_circleci_runner >>true<> - docker_layer_caching: <> - resource_class: <<# parameters.use_circleci_runner >>xlarge<><<^ parameters.use_circleci_runner >>ethereum-optimism/latitude-1<> + docker: + - image: <> + circleci_ip_ranges: true + resource_class: 2xlarge steps: - checkout-from-workspace # Restore cached Go modules @@ -2453,6 +2455,19 @@ workflows: - circleci-repo-readonly-authenticated-github-token requires: - initialize + - contracts-bedrock-tests-upgrade: + name: contracts-bedrock-tests-upgrade op-mainnet <> + fork_op_chain: op + fork_base_chain: mainnet + fork_base_rpc: https://ci-mainnet-l1-archive.optimism.io + dev_features: <> + matrix: + parameters: + dev_features: *dev_features_matrix + context: + - circleci-repo-readonly-authenticated-github-token + requires: + - initialize - contracts-bedrock-tests-upgrade: name: contracts-bedrock-tests-upgrade <>-mainnet fork_op_chain: <> @@ -2460,7 +2475,7 @@ workflows: fork_base_rpc: https://ci-mainnet-l1-archive.optimism.io matrix: parameters: - fork_op_chain: ["op", "base", "ink", "unichain"] + fork_op_chain: ["base", "ink", "unichain"] context: - circleci-repo-readonly-authenticated-github-token requires: @@ -3189,6 +3204,7 @@ workflows: no_output_timeout: 90m context: - circleci-repo-readonly-authenticated-github-token + - slack - discord requires: - contracts-bedrock-build diff --git a/devnet-sdk/testing/testlib/validators/forks.go b/devnet-sdk/testing/testlib/validators/forks.go index f60dcaa2e73..2f762ff75e2 100644 --- a/devnet-sdk/testing/testlib/validators/forks.go +++ b/devnet-sdk/testing/testlib/validators/forks.go @@ -6,7 +6,7 @@ import ( "github.com/ethereum-optimism/optimism/devnet-sdk/system" "github.com/ethereum-optimism/optimism/devnet-sdk/testing/systest" - "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum/go-ethereum/params" ) @@ -39,32 +39,32 @@ func getChainConfig(t systest.T, sys system.System, chainIdx uint64) (*params.Ch // IsForkActivated checks if a specific fork is activated at the given timestamp // based on the chain configuration. -func IsForkActivated(c *params.ChainConfig, forkName rollup.ForkName, timestamp uint64) (bool, error) { +func IsForkActivated(c *params.ChainConfig, forkName forks.Name, timestamp uint64) (bool, error) { if c == nil { return false, fmt.Errorf("provided chain config is nil") } switch forkName { - case rollup.Bedrock: + case forks.Bedrock: // Bedrock is activated based on block number, not timestamp return true, nil // Assuming bedrock is always active in the context of this validator - case rollup.Regolith: + case forks.Regolith: return c.IsOptimismRegolith(timestamp), nil - case rollup.Canyon: + case forks.Canyon: return c.IsOptimismCanyon(timestamp), nil - case rollup.Ecotone: + case forks.Ecotone: return c.IsOptimismEcotone(timestamp), nil - case rollup.Fjord: + case forks.Fjord: return c.IsOptimismFjord(timestamp), nil - case rollup.Granite: + case forks.Granite: return c.IsOptimismGranite(timestamp), nil - case rollup.Holocene: + case forks.Holocene: return c.IsOptimismHolocene(timestamp), nil - case rollup.Isthmus: + case forks.Isthmus: return c.IsOptimismIsthmus(timestamp), nil - case rollup.Jovian: + case forks.Jovian: return c.IsOptimismJovian(timestamp), nil - case rollup.Interop: + case forks.Interop: return c.IsInterop(timestamp), nil default: return false, fmt.Errorf("unknown fork name: %s", forkName) @@ -72,7 +72,7 @@ func IsForkActivated(c *params.ChainConfig, forkName rollup.ForkName, timestamp } // forkConfigValidator is a helper function that checks if a specific L2 chain meets a fork condition. -func forkConfigValidator(chainIdx uint64, forkName rollup.ForkName, shouldBeActive bool, forkConfigMarker interface{}) systest.PreconditionValidator { +func forkConfigValidator(chainIdx uint64, forkName forks.Name, shouldBeActive bool, forkConfigMarker interface{}) systest.PreconditionValidator { return func(t systest.T, sys system.System) (context.Context, error) { chainConfig, timestamp, err := getChainConfig(t, sys, chainIdx) if err != nil { @@ -105,7 +105,7 @@ type ChainConfigGetter = func(context.Context) *params.ChainConfig // AcquireForkConfig returns a ForkConfigGetter and a PreconditionValidator // that ensures a ForkConfig is available for the specified L2 chain. // The ForkConfig can be used to check if various forks are activated. -func acquireForkConfig(chainIdx uint64, forkName rollup.ForkName, shouldBeActive bool) (ChainConfigGetter, systest.PreconditionValidator) { +func acquireForkConfig(chainIdx uint64, forkName forks.Name, shouldBeActive bool) (ChainConfigGetter, systest.PreconditionValidator) { chainConfigMarker := new(byte) validator := forkConfigValidator(chainIdx, forkName, shouldBeActive, chainConfigMarker) return func(ctx context.Context) *params.ChainConfig { @@ -114,13 +114,13 @@ func acquireForkConfig(chainIdx uint64, forkName rollup.ForkName, shouldBeActive } // RequiresFork returns a validator that ensures a specific L2 chain has a specific fork activated. -func AcquireL2WithFork(chainIdx uint64, forkName rollup.ForkName) (ChainConfigGetter, systest.PreconditionValidator) { +func AcquireL2WithFork(chainIdx uint64, forkName forks.Name) (ChainConfigGetter, systest.PreconditionValidator) { return acquireForkConfig(chainIdx, forkName, true) } // RequiresNotFork returns a validator that ensures a specific L2 chain does not // have a specific fork activated. Will not work with the interop fork // specifically since interop is not an ordered release fork. -func AcquireL2WithoutFork(chainIdx uint64, forkName rollup.ForkName) (ChainConfigGetter, systest.PreconditionValidator) { +func AcquireL2WithoutFork(chainIdx uint64, forkName forks.Name) (ChainConfigGetter, systest.PreconditionValidator) { return acquireForkConfig(chainIdx, forkName, false) } diff --git a/devnet-sdk/testing/testlib/validators/validators_test.go b/devnet-sdk/testing/testlib/validators/validators_test.go index 17bc4829405..056999121a6 100644 --- a/devnet-sdk/testing/testlib/validators/validators_test.go +++ b/devnet-sdk/testing/testlib/validators/validators_test.go @@ -11,7 +11,7 @@ import ( "github.com/ethereum-optimism/optimism/devnet-sdk/system" "github.com/ethereum-optimism/optimism/devnet-sdk/testing/systest" "github.com/ethereum-optimism/optimism/devnet-sdk/types" - "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -33,7 +33,7 @@ func TestValidators(t *testing.T) { t.Run("multiple validators", func(t *testing.T) { walletGetter1, validator1 := AcquireL2WalletWithFunds(0, types.NewBalance(big.NewInt(1))) walletGetter2, validator2 := AcquireL2WalletWithFunds(0, types.NewBalance(big.NewInt(10))) - chainConfigGetter, l2ForkValidator := AcquireL2WithFork(0, rollup.Isthmus) + chainConfigGetter, l2ForkValidator := AcquireL2WithFork(0, forks.Isthmus) // We create a system that has a low-level L1 chain and at least one wallet systestSystem := &mockSystem{ @@ -109,7 +109,7 @@ func TestValidators(t *testing.T) { } // Get the validator for requiring Isthmus fork to be active - chainConfigGetter, validator := AcquireL2WithFork(0, rollup.Isthmus) + chainConfigGetter, validator := AcquireL2WithFork(0, forks.Isthmus) systestT := systest.NewT(t) // Apply the validator @@ -119,7 +119,7 @@ func TestValidators(t *testing.T) { // Verify the chain config getter works chainConfig := chainConfigGetter(ctx) require.NotNil(t, chainConfig) - isActive, err := IsForkActivated(chainConfig, rollup.Isthmus, 100) + isActive, err := IsForkActivated(chainConfig, forks.Isthmus, 100) require.NoError(t, err) require.True(t, isActive) }) @@ -143,7 +143,7 @@ func TestValidators(t *testing.T) { } // Get the validator for requiring Isthmus fork to be active - _, validator := AcquireL2WithFork(0, rollup.Isthmus) + _, validator := AcquireL2WithFork(0, forks.Isthmus) systestT := systest.NewT(t) // Apply the validator - should fail since fork is not active @@ -171,7 +171,7 @@ func TestValidators(t *testing.T) { } // Get the validator for requiring Isthmus fork to not be active - chainConfigGetter, validator := AcquireL2WithoutFork(0, rollup.Isthmus) + chainConfigGetter, validator := AcquireL2WithoutFork(0, forks.Isthmus) systestT := systest.NewT(t) // Apply the validator @@ -181,7 +181,7 @@ func TestValidators(t *testing.T) { // Verify the chain config getter works chainConfig := chainConfigGetter(ctx) require.NotNil(t, chainConfig) - isActive, err := IsForkActivated(chainConfig, rollup.Isthmus, 100) + isActive, err := IsForkActivated(chainConfig, forks.Isthmus, 100) require.NoError(t, err) require.False(t, isActive) }) @@ -205,7 +205,7 @@ func TestValidators(t *testing.T) { } // Get the validator for requiring Isthmus fork to not be active - _, validator := AcquireL2WithoutFork(0, rollup.Isthmus) + _, validator := AcquireL2WithoutFork(0, forks.Isthmus) systestT := systest.NewT(t) // Apply the validator - should fail since fork is active @@ -221,7 +221,7 @@ func TestValidators(t *testing.T) { } // Try to get chain config for an invalid chain index - _, validator := AcquireL2WithFork(0, rollup.Isthmus) + _, validator := AcquireL2WithFork(0, forks.Isthmus) systestT := systest.NewT(t) // Apply the validator - should fail since chain index is out of range diff --git a/go.mod b/go.mod index a55711bdd79..057eeba7802 100644 --- a/go.mod +++ b/go.mod @@ -162,7 +162,7 @@ require ( github.com/hashicorp/golang-lru v0.5.0 // indirect github.com/hashicorp/golang-lru/arc/v2 v2.0.7 // indirect github.com/hashicorp/raft-boltdb v0.0.0-20231211162105-6c830fa4535e // indirect - github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 // indirect + github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/influxdata/influxdb-client-go/v2 v2.4.0 // indirect @@ -308,7 +308,7 @@ require ( lukechampine.com/blake3 v1.3.0 // indirect ) -replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101603.3-rc.3 +replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101603.4-rc.1 // replace github.com/ethereum/go-ethereum => ../op-geth diff --git a/go.sum b/go.sum index 4e96d52c1a7..daec5bd6f99 100644 --- a/go.sum +++ b/go.sum @@ -238,8 +238,8 @@ github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.4-0.20251001155152-4eb15ccedf7e h1:iy1vBIzACYUyOVyoADUwvAiq2eOPC0yVsDUdolPwQjk= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.4-0.20251001155152-4eb15ccedf7e/go.mod h1:DYj7+vYJ4cIB7zera9mv4LcAynCL5u4YVfoeUu6Wa+w= -github.com/ethereum-optimism/op-geth v1.101603.3-rc.3 h1:KGpZouRMsMcl9MWOmYKJi+XR1gTT9/2STANv1G7oaNA= -github.com/ethereum-optimism/op-geth v1.101603.3-rc.3/go.mod h1:Wiy9cngs7ll1slc/dcHHRVuGhozWOpF1y6f31xENR7k= +github.com/ethereum-optimism/op-geth v1.101603.4-rc.1 h1:5ByBDUKBY/IHibukF/C9kjzaTk4SxUoXH449VuDrMn4= +github.com/ethereum-optimism/op-geth v1.101603.4-rc.1/go.mod h1:cnGR2M8zX91+rRQxXyNTEOEpw/IwdR8P11FQX7Xaqwk= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20251009180028-9b4658b9b7af h1:WWz0gJM/boaUImtJnROecPirAerKCLpAU4m6Tx0ArOg= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20251009180028-9b4658b9b7af/go.mod h1:NZ816PzLU1TLv1RdAvYAb6KWOj4Zm5aInT0YpDVml2Y= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= @@ -432,8 +432,8 @@ github.com/hashicorp/raft-boltdb v0.0.0-20231211162105-6c830fa4535e h1:SK4y8oR4Z github.com/hashicorp/raft-boltdb v0.0.0-20231211162105-6c830fa4535e/go.mod h1:EMz/UIuG93P0MBeHh6CbXQAEe8ckVJLZjhD17lBzK5Q= github.com/hashicorp/raft-boltdb/v2 v2.3.1 h1:ackhdCNPKblmOhjEU9+4lHSJYFkJd6Jqyvj6eW9pwkc= github.com/hashicorp/raft-boltdb/v2 v2.3.1/go.mod h1:n4S+g43dXF1tqDT+yzcXHhXM6y7MrlUd3TTwGRcUvQE= -github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4= -github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= diff --git a/mise.toml b/mise.toml index be52c50066e..58ea2bce478 100644 --- a/mise.toml +++ b/mise.toml @@ -38,7 +38,7 @@ anvil = "1.1.0" codecov-uploader = "0.8.0" goreleaser-pro = "2.11.2" kurtosis = "1.8.1" -op-acceptor = "op-acceptor/v3.6.1" +op-acceptor = "op-acceptor/v3.6.2" # Fake dependencies # Put things here if you need to track versions of tools or projects that can't diff --git a/op-acceptance-tests/justfile b/op-acceptance-tests/justfile index dda965f70f9..31525143eeb 100644 --- a/op-acceptance-tests/justfile +++ b/op-acceptance-tests/justfile @@ -1,6 +1,6 @@ REPO_ROOT := `realpath ..` # path to the root of the optimism monorepo KURTOSIS_DIR := REPO_ROOT + "/kurtosis-devnet" -ACCEPTOR_VERSION := env_var_or_default("ACCEPTOR_VERSION", "v3.6.1") +ACCEPTOR_VERSION := env_var_or_default("ACCEPTOR_VERSION", "v3.6.2") DOCKER_REGISTRY := env_var_or_default("DOCKER_REGISTRY", "us-docker.pkg.dev/oplabs-tools-artifacts/images") ACCEPTOR_IMAGE := env_var_or_default("ACCEPTOR_IMAGE", DOCKER_REGISTRY + "/op-acceptor:" + ACCEPTOR_VERSION) diff --git a/op-acceptance-tests/tests/base/withdrawal/init_test.go b/op-acceptance-tests/tests/base/withdrawal/init_test.go index 7154f5445ba..ac5aa8113ef 100644 --- a/op-acceptance-tests/tests/base/withdrawal/init_test.go +++ b/op-acceptance-tests/tests/base/withdrawal/init_test.go @@ -3,7 +3,6 @@ package withdrawal import ( "testing" - faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" "github.com/ethereum-optimism/optimism/op-devstack/compat" "github.com/ethereum-optimism/optimism/op-devstack/presets" ) @@ -13,14 +12,7 @@ func TestMain(m *testing.M) { // TODO(infra#401): Re-enable the test when the sysext missing toolset is implemented presets.WithCompatibleTypes(compat.SysGo), presets.WithMinimal(), - presets.WithProposerGameType(faultTypes.FastGameType), - // Fast game for test - presets.WithFastGame(), - // Deployer must be L1PAO to make op-deployer happy - presets.WithDeployerMatchL1PAO(), - // Guardian must be L1PAO to make AnchorStateRegistry's setRespectedGameType method work - presets.WithGuardianMatchL1PAO(), - // Fast finalization for fast withdrawal + presets.WithTimeTravel(), presets.WithFinalizationPeriodSeconds(1), // Satisfy OptimismPortal2 PROOF_MATURITY_DELAY_SECONDS check, avoid OptimismPortal_ProofNotOldEnough() revert presets.WithProofMaturityDelaySeconds(2), diff --git a/op-acceptance-tests/tests/base/withdrawal/withdrawal_test.go b/op-acceptance-tests/tests/base/withdrawal/withdrawal_test.go index d2b40beb723..a9e1e7814b3 100644 --- a/op-acceptance-tests/tests/base/withdrawal/withdrawal_test.go +++ b/op-acceptance-tests/tests/base/withdrawal/withdrawal_test.go @@ -15,7 +15,7 @@ func TestWithdrawal(gt *testing.T) { require := sys.T.Require() bridge := sys.StandardBridge() - require.EqualValues(faultTypes.FastGameType, bridge.RespectedGameType(), "Respected game type must be FastGame") + require.EqualValues(faultTypes.PermissionedGameType, bridge.RespectedGameType(), "Respected game type must be PermissionedGameType") initialL1Balance := eth.OneThirdEther @@ -45,6 +45,13 @@ func TestWithdrawal(gt *testing.T) { expectedL1UserBalance = expectedL1UserBalance.Sub(withdrawal.ProveGasCost()) l1User.VerifyBalanceExact(expectedL1UserBalance) + // Advance time until game is resolvable + sys.AdvanceTime(bridge.GameResolutionDelay()) + withdrawal.WaitForDisputeGameResolved() + + // Advance time to when game finalization and proof finalization delay has expired + sys.AdvanceTime(max(bridge.WithdrawalDelay()-bridge.GameResolutionDelay(), bridge.DisputeGameFinalityDelay())) + t.Logger().Info("Attempting to finalize", "proofMaturity", bridge.WithdrawalDelay(), "gameResolutionDelay", bridge.GameResolutionDelay(), "gameFinalityDelay", bridge.DisputeGameFinalityDelay()) withdrawal.Finalize(l1User) expectedL1UserBalance = expectedL1UserBalance.Sub(withdrawal.FinalizeGasCost()).Add(withdrawalAmount) diff --git a/op-acceptance-tests/tests/ecotone/fees_test.go b/op-acceptance-tests/tests/ecotone/fees_test.go index 10852f673eb..eb8731587e2 100644 --- a/op-acceptance-tests/tests/ecotone/fees_test.go +++ b/op-acceptance-tests/tests/ecotone/fees_test.go @@ -4,10 +4,10 @@ import ( "math/big" "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" ) @@ -16,7 +16,7 @@ func TestFees(gt *testing.T) { sys := presets.NewMinimal(t) require := t.Require() - err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, rollup.Ecotone) + err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, forks.Ecotone) require.NoError(err, "Ecotone fork must be active for this test") alice := sys.FunderL2.NewFundedEOA(eth.OneTenthEther) diff --git a/op-acceptance-tests/tests/fjord/check_scripts_test.go b/op-acceptance-tests/tests/fjord/check_scripts_test.go index 649f4a5e9de..53da549bd91 100644 --- a/op-acceptance-tests/tests/fjord/check_scripts_test.go +++ b/op-acceptance-tests/tests/fjord/check_scripts_test.go @@ -7,12 +7,12 @@ import ( "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum-optimism/optimism/op-core/forks" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" txib "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" "github.com/ethereum-optimism/optimism/op-service/txintent/contractio" "github.com/ethereum-optimism/optimism/op-service/txplan" @@ -34,7 +34,7 @@ func TestCheckFjordScript(gt *testing.T) { require := t.Require() ctx := t.Ctx() - err := dsl.RequiresL2Fork(ctx, sys, 0, rollup.Fjord) + err := dsl.RequiresL2Fork(ctx, sys, 0, forks.Fjord) require.NoError(err) wallet := sys.FunderL2.NewFundedEOA(eth.OneThirdEther) diff --git a/op-acceptance-tests/tests/fjord/fees_test.go b/op-acceptance-tests/tests/fjord/fees_test.go index f661e17a6f2..384eda832be 100644 --- a/op-acceptance-tests/tests/fjord/fees_test.go +++ b/op-acceptance-tests/tests/fjord/fees_test.go @@ -7,9 +7,9 @@ import ( dsl "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-core/forks" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" txib "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" ) @@ -19,7 +19,7 @@ func TestFees(gt *testing.T) { require := t.Require() ctx := t.Ctx() - err := dsl.RequiresL2Fork(ctx, sys, 0, rollup.Fjord) + err := dsl.RequiresL2Fork(ctx, sys, 0, forks.Fjord) require.NoError(err) operatorFee := dsl.NewOperatorFee(t, sys.L2Chain, sys.L1EL) operatorFee.SetOperatorFee(100000000, 500) diff --git a/op-acceptance-tests/tests/fusaka/fusaka_test.go b/op-acceptance-tests/tests/fusaka/fusaka_test.go index c0d8506dcc4..c5352a8105b 100644 --- a/op-acceptance-tests/tests/fusaka/fusaka_test.go +++ b/op-acceptance-tests/tests/fusaka/fusaka_test.go @@ -10,11 +10,11 @@ import ( "time" "github.com/ethereum-optimism/optimism/op-acceptance-tests/tests/interop/loadtest" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/presets" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/txinclude" "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" "github.com/ethereum-optimism/optimism/op-service/txintent/contractio" diff --git a/op-acceptance-tests/tests/interop/message/interop_msg_test.go b/op-acceptance-tests/tests/interop/message/interop_msg_test.go index 488d2fbe0bc..c5a2bef337e 100644 --- a/op-acceptance-tests/tests/interop/message/interop_msg_test.go +++ b/op-acceptance-tests/tests/interop/message/interop_msg_test.go @@ -9,13 +9,13 @@ import ( "github.com/ethereum-optimism/optimism/devnet-sdk/contracts/constants" "github.com/ethereum-optimism/optimism/op-acceptance-tests/tests/interop" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/dsl/contract" "github.com/ethereum-optimism/optimism/op-devstack/presets" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/plan" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/testutils" "github.com/ethereum-optimism/optimism/op-service/txintent" "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" diff --git a/op-acceptance-tests/tests/interop/proofs/proposer_test.go b/op-acceptance-tests/tests/interop/proofs/proposer_test.go index da20c56ad97..444720542a1 100644 --- a/op-acceptance-tests/tests/interop/proofs/proposer_test.go +++ b/op-acceptance-tests/tests/interop/proofs/proposer_test.go @@ -17,6 +17,6 @@ func TestProposer(gt *testing.T) { rootClaim := newGame.RootClaim().Value() l2SequenceNumber := newGame.L2SequenceNumber() - superRoot := sys.Supervisor.FetchSuperRootAtTimestamp(l2SequenceNumber.Uint64()) + superRoot := sys.Supervisor.FetchSuperRootAtTimestamp(l2SequenceNumber) t.Require().Equal(superRoot.SuperRoot[:], rootClaim[:]) } diff --git a/op-acceptance-tests/tests/interop/smoke/interop_smoke_test.go b/op-acceptance-tests/tests/interop/smoke/interop_smoke_test.go index c3891ca4777..881f834f428 100644 --- a/op-acceptance-tests/tests/interop/smoke/interop_smoke_test.go +++ b/op-acceptance-tests/tests/interop/smoke/interop_smoke_test.go @@ -3,10 +3,10 @@ package smoke import ( "testing" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/presets" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" txib "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" "github.com/ethereum-optimism/optimism/op-service/txintent/contractio" "github.com/ethereum/go-ethereum/core/types" diff --git a/op-acceptance-tests/tests/interop/smoke/smoke_test.go b/op-acceptance-tests/tests/interop/smoke/smoke_test.go index 4260c0378e4..749d66cd2b0 100644 --- a/op-acceptance-tests/tests/interop/smoke/smoke_test.go +++ b/op-acceptance-tests/tests/interop/smoke/smoke_test.go @@ -3,11 +3,11 @@ package smoke import ( "testing" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl/contract" "github.com/ethereum-optimism/optimism/op-devstack/presets" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" "github.com/ethereum-optimism/optimism/op-service/txintent/contractio" "github.com/ethereum-optimism/optimism/op-service/txplan" diff --git a/op-acceptance-tests/tests/interop/upgrade-singlechain/crossl2inbox_test.go b/op-acceptance-tests/tests/interop/upgrade-singlechain/crossl2inbox_test.go index 9ec7a9d787a..8083675cd36 100644 --- a/op-acceptance-tests/tests/interop/upgrade-singlechain/crossl2inbox_test.go +++ b/op-acceptance-tests/tests/interop/upgrade-singlechain/crossl2inbox_test.go @@ -4,12 +4,12 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/forks" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" "github.com/ethereum-optimism/optimism/op-devstack/stack/match" - "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ) @@ -22,7 +22,7 @@ func TestPostInbox(gt *testing.T) { require := t.Require() el := net.Escape().L2ELNode(match.FirstL2EL) - activationBlock := net.AwaitActivation(t, rollup.Interop) + activationBlock := net.AwaitActivation(t, forks.Interop) require.NotZero(activationBlock, "must not activate interop at genesis") pre := activationBlock.Number - 1 diff --git a/op-acceptance-tests/tests/interop/upgrade/post_test.go b/op-acceptance-tests/tests/interop/upgrade/post_test.go index 5e5ea29ae1e..dacf18248d4 100644 --- a/op-acceptance-tests/tests/interop/upgrade/post_test.go +++ b/op-acceptance-tests/tests/interop/upgrade/post_test.go @@ -7,19 +7,19 @@ import ( "testing" "time" - stypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum-optimism/optimism/op-acceptance-tests/tests/interop" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/forks" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" "github.com/ethereum-optimism/optimism/op-devstack/stack/match" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" + stypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" ) func TestPostInbox(gt *testing.T) { @@ -28,7 +28,7 @@ func TestPostInbox(gt *testing.T) { sys := presets.NewSimpleInterop(t) devtest.RunParallel(t, sys.L2Networks(), func(t devtest.T, net *dsl.L2Network) { require := t.Require() - activationBlock := net.AwaitActivation(t, rollup.Interop) + activationBlock := net.AwaitActivation(t, forks.Interop) el := net.Escape().L2ELNode(match.FirstL2EL) implAddrBytes, err := el.EthClient().GetStorageAt(t.Ctx(), predeploys.CrossL2InboxAddr, @@ -96,7 +96,7 @@ func testSupervisorAnchorBlock(t devtest.T, sys *presets.SimpleInterop) { t.Gate().True(upgradeTime.Before(deadline), "test must not time out before upgrade happens") } - activationBlock := net.AwaitActivation(t, rollup.Interop) + activationBlock := net.AwaitActivation(t, forks.Interop) sys.Supervisor.WaitForL2HeadToAdvanceTo(net.ChainID(), stypes.CrossSafe, activationBlock) logger.Info("Validating anchor block timing", diff --git a/op-acceptance-tests/tests/interop/upgrade/pre_test.go b/op-acceptance-tests/tests/interop/upgrade/pre_test.go index 9af93d1c726..8d3e75d9380 100644 --- a/op-acceptance-tests/tests/interop/upgrade/pre_test.go +++ b/op-acceptance-tests/tests/interop/upgrade/pre_test.go @@ -13,12 +13,12 @@ import ( "github.com/ethereum-optimism/optimism/devnet-sdk/contracts/constants" "github.com/ethereum-optimism/optimism/op-acceptance-tests/tests/interop" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" "github.com/ethereum-optimism/optimism/op-devstack/stack/match" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/txintent" stypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) diff --git a/op-acceptance-tests/tests/isthmus/erc20_bridge/erc20_bridge_test.go b/op-acceptance-tests/tests/isthmus/erc20_bridge/erc20_bridge_test.go index 9667fcf4a52..dfc19986418 100644 --- a/op-acceptance-tests/tests/isthmus/erc20_bridge/erc20_bridge_test.go +++ b/op-acceptance-tests/tests/isthmus/erc20_bridge/erc20_bridge_test.go @@ -3,11 +3,11 @@ package erc20bridge import ( "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/dsl/contract" "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" "github.com/ethereum-optimism/optimism/op-service/txplan" @@ -18,7 +18,7 @@ func TestERC20Bridge(gt *testing.T) { sys := presets.NewMinimal(t) require := t.Require() - err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, rollup.Isthmus) + err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, forks.Isthmus) require.NoError(err, "Isthmus fork must be active for this test") // Create users with same identity on both chains diff --git a/op-acceptance-tests/tests/isthmus/operator_fee/operator_fee_test.go b/op-acceptance-tests/tests/isthmus/operator_fee/operator_fee_test.go index 856aebeba48..c56dd56ffa6 100644 --- a/op-acceptance-tests/tests/isthmus/operator_fee/operator_fee_test.go +++ b/op-acceptance-tests/tests/isthmus/operator_fee/operator_fee_test.go @@ -3,16 +3,16 @@ package operatorfee import ( "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-node/rollup" ) func TestOperatorFee(gt *testing.T) { t := devtest.SerialT(gt) sys := presets.NewMinimal(t) - err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, rollup.Isthmus) + err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, forks.Isthmus) t.Require().NoError(err, "Isthmus fork must be active for this test") dsl.RunOperatorFeeTest(t, sys.L2Chain, sys.L1EL, sys.FunderL1, sys.FunderL2) } diff --git a/op-acceptance-tests/tests/isthmus/pectra/pectra_features_test.go b/op-acceptance-tests/tests/isthmus/pectra/pectra_features_test.go index e06338176f5..669ff8bdcfa 100644 --- a/op-acceptance-tests/tests/isthmus/pectra/pectra_features_test.go +++ b/op-acceptance-tests/tests/isthmus/pectra/pectra_features_test.go @@ -6,10 +6,10 @@ import ( "encoding/binary" "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/txplan" "github.com/ethereum/go-ethereum/common" @@ -31,7 +31,7 @@ func TestPectra(gt *testing.T) { sys := presets.NewMinimal(t) require := t.Require() - err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, rollup.Isthmus) + err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, forks.Isthmus) require.NoError(err, "Isthmus fork must be active for Pectra features") alice := sys.FunderL2.NewFundedEOA(eth.OneTenthEther) diff --git a/op-acceptance-tests/tests/isthmus/preinterop/proposer_test.go b/op-acceptance-tests/tests/isthmus/preinterop/proposer_test.go index e5e8a884565..3e0aea06e2d 100644 --- a/op-acceptance-tests/tests/isthmus/preinterop/proposer_test.go +++ b/op-acceptance-tests/tests/isthmus/preinterop/proposer_test.go @@ -18,6 +18,6 @@ func TestProposer(gt *testing.T) { rootClaim := newGame.RootClaim().Value() l2SequenceNumber := newGame.L2SequenceNumber() - superRoot := sys.Supervisor.FetchSuperRootAtTimestamp(l2SequenceNumber.Uint64()) + superRoot := sys.Supervisor.FetchSuperRootAtTimestamp(l2SequenceNumber) t.Require().Equal(superRoot.SuperRoot[:], rootClaim[:]) } diff --git a/op-acceptance-tests/tests/isthmus/withdrawal_root/withdrawals_root_test.go b/op-acceptance-tests/tests/isthmus/withdrawal_root/withdrawals_root_test.go index 89135d003b0..739a5ecfadc 100644 --- a/op-acceptance-tests/tests/isthmus/withdrawal_root/withdrawals_root_test.go +++ b/op-acceptance-tests/tests/isthmus/withdrawal_root/withdrawals_root_test.go @@ -3,10 +3,10 @@ package withdrawal import ( "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" ) @@ -15,7 +15,7 @@ func TestWithdrawalRoot(gt *testing.T) { sys := presets.NewMinimal(t) require := sys.T.Require() - err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, rollup.Isthmus) + err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, forks.Isthmus) require.NoError(err, "Isthmus fork must be active for this test") secondCheck, err := dsl.CheckForChainFork(t.Ctx(), sys.L2Networks(), t.Logger()) diff --git a/op-acceptance-tests/tests/jovian/da_footprint_test.go b/op-acceptance-tests/tests/jovian/da_footprint_test.go index f309dba6d7f..b7f4d2c4b05 100644 --- a/op-acceptance-tests/tests/jovian/da_footprint_test.go +++ b/op-acceptance-tests/tests/jovian/da_footprint_test.go @@ -10,10 +10,10 @@ import ( "github.com/ethereum-optimism/optimism/op-acceptance-tests/tests/interop/loadtest" "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/txinclude" @@ -121,7 +121,7 @@ func TestDAFootprint(gt *testing.T) { sys := presets.NewMinimal(t) require := t.Require() - err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, rollup.Jovian) + err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, forks.Jovian) require.NoError(err, "Jovian fork must be active for this test") env := newDAFootprintEnv(t, sys.L2Chain, sys.L1EL, sys.L2EL) diff --git a/op-acceptance-tests/tests/jovian/min_base_fee_test.go b/op-acceptance-tests/tests/jovian/min_base_fee_test.go index 28080e893bf..3ba1401de74 100644 --- a/op-acceptance-tests/tests/jovian/min_base_fee_test.go +++ b/op-acceptance-tests/tests/jovian/min_base_fee_test.go @@ -4,10 +4,10 @@ import ( "math/big" "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" "encoding/binary" @@ -122,7 +122,7 @@ func TestMinBaseFee(gt *testing.T) { sys := presets.NewMinimal(t) require := t.Require() - err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, rollup.Jovian) + err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, forks.Jovian) require.NoError(err, "Jovian fork must be active for this test") minBaseFee := newMinBaseFee(t, sys.L2Chain, sys.L1EL, sys.L2EL) diff --git a/op-acceptance-tests/tests/jovian/operator_fee_test.go b/op-acceptance-tests/tests/jovian/operator_fee_test.go index e2e9e046a4b..f26b551774a 100644 --- a/op-acceptance-tests/tests/jovian/operator_fee_test.go +++ b/op-acceptance-tests/tests/jovian/operator_fee_test.go @@ -3,16 +3,16 @@ package jovian import ( "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-node/rollup" ) func TestOperatorFee(gt *testing.T) { t := devtest.SerialT(gt) sys := presets.NewMinimal(t) - err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, rollup.Jovian) + err := dsl.RequiresL2Fork(t.Ctx(), sys, 0, forks.Jovian) t.Require().NoError(err, "Jovian fork must be active for this test") dsl.RunOperatorFeeTest(t, sys.L2Chain, sys.L1EL, sys.FunderL1, sys.FunderL2) } diff --git a/op-acceptance-tests/tests/proofs/cannon/init_test.go b/op-acceptance-tests/tests/proofs/cannon/init_test.go new file mode 100644 index 00000000000..d86e75daff9 --- /dev/null +++ b/op-acceptance-tests/tests/proofs/cannon/init_test.go @@ -0,0 +1,18 @@ +package cannon + +import ( + "testing" + + "github.com/ethereum-optimism/optimism/op-devstack/compat" + "github.com/ethereum-optimism/optimism/op-devstack/presets" +) + +func TestMain(m *testing.M) { + presets.DoMain(m, + presets.WithProofs(), + presets.WithJovianAtGenesis(), + presets.WithSafeDBEnabled(), + // Requires access to a challenger config which only sysgo provides + // These tests would also be exceptionally slow on real L1s + presets.WithCompatibleTypes(compat.SysGo)) +} diff --git a/op-acceptance-tests/tests/proofs/cannon/step_test.go b/op-acceptance-tests/tests/proofs/cannon/step_test.go new file mode 100644 index 00000000000..2c97e14f428 --- /dev/null +++ b/op-acceptance-tests/tests/proofs/cannon/step_test.go @@ -0,0 +1,28 @@ +package cannon + +import ( + "testing" + + "github.com/ethereum-optimism/optimism/op-devstack/devtest" + "github.com/ethereum-optimism/optimism/op-devstack/dsl/proofs" + "github.com/ethereum-optimism/optimism/op-devstack/presets" + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" +) + +func TestExecuteStep(gt *testing.T) { + t := devtest.ParallelT(gt) + sys := presets.NewMinimal(t) + + l1User := sys.FunderL1.NewFundedEOA(eth.ThousandEther) + blockNum := uint64(3) + sys.L2CL.Reached(types.LocalSafe, blockNum, 30) + + game := sys.DisputeGameFactory().StartCannonGame(l1User, proofs.WithL2SequenceNumber(blockNum)) + claim := game.DisputeL2SequenceNumber(l1User, game.RootClaim(), blockNum) + game.LogGameData() + claim = claim.WaitForCounterClaim() // Wait for the honest challenger to counter + claim = game.DisputeToStep(l1User, claim, 1000) // Skip down to max depth + game.LogGameData() + claim.WaitForCountered() +} diff --git a/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/init_test.go b/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/init_test.go index b209502c609..559f04bd796 100644 --- a/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/init_test.go +++ b/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/init_test.go @@ -4,18 +4,18 @@ import ( "testing" bss "github.com/ethereum-optimism/optimism/op-batcher/batcher" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/compat" "github.com/ethereum-optimism/optimism/op-devstack/presets" "github.com/ethereum-optimism/optimism/op-devstack/stack" "github.com/ethereum-optimism/optimism/op-devstack/sysgo" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" ) func TestMain(m *testing.M) { presets.DoMain(m, presets.WithSimpleWithSyncTester(), presets.WithCompatibleTypes(compat.SysGo), - presets.WithHardforkSequentialActivation(rollup.Bedrock, rollup.Jovian, 15), + presets.WithHardforkSequentialActivation(forks.Bedrock, forks.Jovian, 15), stack.MakeCommon(sysgo.WithBatcherOption(func(id stack.L2BatcherID, cfg *bss.CLIConfig) { // For supporting pre-delta batches cfg.BatchType = derive.SingularBatchType diff --git a/op-acceptance-tests/tests/sync_tester/sync_tester_hfs_ext/sync_tester_hfs_ext_test.go b/op-acceptance-tests/tests/sync_tester/sync_tester_hfs_ext/sync_tester_hfs_ext_test.go index ec6464500e1..6f411509690 100644 --- a/op-acceptance-tests/tests/sync_tester/sync_tester_hfs_ext/sync_tester_hfs_ext_test.go +++ b/op-acceptance-tests/tests/sync_tester/sync_tester_hfs_ext/sync_tester_hfs_ext_test.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/log" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/presets" @@ -17,7 +18,6 @@ import ( "github.com/ethereum-optimism/optimism/op-devstack/stack/match" "github.com/ethereum-optimism/optimism/op-devstack/sysgo" "github.com/ethereum-optimism/optimism/op-node/chaincfg" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/sync" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/testlog" @@ -40,14 +40,14 @@ const ( var ( // Network upgrade block numbers for op-sepolia - networkUpgradeBlocks = map[rollup.ForkName]uint64{ - rollup.Canyon: 4089330, - rollup.Delta: 5700330, - rollup.Ecotone: 8366130, - rollup.Fjord: 12597930, - rollup.Granite: 15837930, - rollup.Holocene: 20415330, - rollup.Isthmus: 26551530, + networkUpgradeBlocks = map[forks.Name]uint64{ + forks.Canyon: 4089330, + forks.Delta: 5700330, + forks.Ecotone: 8366130, + forks.Fjord: 12597930, + forks.Granite: 15837930, + forks.Holocene: 20415330, + forks.Isthmus: 26551530, } // Load configuration from environment variables with defaults @@ -61,59 +61,59 @@ var ( ) func TestSyncTesterHFS_Canyon_CLSync(gt *testing.T) { - hfsExt(gt, rollup.Canyon, sync.CLSync) + hfsExt(gt, forks.Canyon, sync.CLSync) } func TestSyncTesterHFS_Canyon_ELSync(gt *testing.T) { - hfsExt(gt, rollup.Canyon, sync.ELSync) + hfsExt(gt, forks.Canyon, sync.ELSync) } func TestSyncTesterHFS_Delta_CLSync(gt *testing.T) { - hfsExt(gt, rollup.Delta, sync.CLSync) + hfsExt(gt, forks.Delta, sync.CLSync) } func TestSyncTesterHFS_Delta_ELSync(gt *testing.T) { - hfsExt(gt, rollup.Delta, sync.ELSync) + hfsExt(gt, forks.Delta, sync.ELSync) } func TestSyncTesterHFS_Ecotone_CLSync(gt *testing.T) { - hfsExt(gt, rollup.Ecotone, sync.CLSync) + hfsExt(gt, forks.Ecotone, sync.CLSync) } func TestSyncTesterHFS_Ecotone_ELSync(gt *testing.T) { - hfsExt(gt, rollup.Ecotone, sync.ELSync) + hfsExt(gt, forks.Ecotone, sync.ELSync) } func TestSyncTesterHFS_Fjord_CLSync(gt *testing.T) { - hfsExt(gt, rollup.Fjord, sync.CLSync) + hfsExt(gt, forks.Fjord, sync.CLSync) } func TestSyncTesterHFS_Fjord_ELSync(gt *testing.T) { - hfsExt(gt, rollup.Fjord, sync.ELSync) + hfsExt(gt, forks.Fjord, sync.ELSync) } func TestSyncTesterHFS_Granite_CLSync(gt *testing.T) { - hfsExt(gt, rollup.Granite, sync.CLSync) + hfsExt(gt, forks.Granite, sync.CLSync) } func TestSyncTesterHFS_Granite_ELSync(gt *testing.T) { - hfsExt(gt, rollup.Granite, sync.ELSync) + hfsExt(gt, forks.Granite, sync.ELSync) } func TestSyncTesterHFS_Holocene_CLSync(gt *testing.T) { - hfsExt(gt, rollup.Holocene, sync.CLSync) + hfsExt(gt, forks.Holocene, sync.CLSync) } func TestSyncTesterHFS_Holocene_ELSync(gt *testing.T) { - hfsExt(gt, rollup.Holocene, sync.ELSync) + hfsExt(gt, forks.Holocene, sync.ELSync) } func TestSyncTesterHFS_Isthmus_CLSync(gt *testing.T) { - hfsExt(gt, rollup.Isthmus, sync.CLSync) + hfsExt(gt, forks.Isthmus, sync.CLSync) } func TestSyncTesterHFS_Isthmus_ELSync(gt *testing.T) { - hfsExt(gt, rollup.Isthmus, sync.ELSync) + hfsExt(gt, forks.Isthmus, sync.ELSync) } // getEnvOrDefault returns the environment variable value or the default if not set @@ -215,7 +215,7 @@ func setupOrchestrator(gt *testing.T, t devtest.T, blk, targetBlock uint64, l2CL return orch.(*sysgo.Orchestrator) } -func hfsExt(gt *testing.T, upgradeName rollup.ForkName, l2CLSyncMode sync.Mode) { +func hfsExt(gt *testing.T, upgradeName forks.Name, l2CLSyncMode sync.Mode) { t := devtest.ParallelT(gt) l := t.Logger() diff --git a/op-batcher/batcher/channel.go b/op-batcher/batcher/channel.go index 8270977a68c..b9299d11bf4 100644 --- a/op-batcher/batcher/channel.go +++ b/op-batcher/batcher/channel.go @@ -13,30 +13,26 @@ import ( // channel is a lightweight wrapper around a ChannelBuilder which keeps track of pending // and confirmed transactions for a single channel. type channel struct { + *ChannelBuilder // pending channel builder + log log.Logger metr metrics.Metricer cfg ChannelConfig - // pending channel builder - channelBuilder *ChannelBuilder - // Set of unconfirmed txID -> tx data. For tx resubmission - pendingTransactions map[string]txData - // Set of confirmed txID -> inclusion block. For determining if the channel is timed out - confirmedTransactions map[string]eth.BlockID - - // Inclusion block number of first confirmed TX - minInclusionBlock uint64 - // Inclusion block number of last confirmed TX - maxInclusionBlock uint64 + pendingTransactions map[string]txData // Set of unconfirmed txID -> tx data. For tx resubmission + confirmedTransactions map[string]eth.BlockID // Set of confirmed txID -> inclusion block. For determining if the channel is timed out + + minInclusionBlock uint64 // Inclusion block number of first confirmed TX + maxInclusionBlock uint64 // Inclusion block number of last confirmed TX } func newChannel(log log.Logger, metr metrics.Metricer, cfg ChannelConfig, rollupCfg *rollup.Config, latestL1OriginBlockNum uint64, channelOut derive.ChannelOut) *channel { cb := NewChannelBuilderWithChannelOut(cfg, rollupCfg, latestL1OriginBlockNum, channelOut) return &channel{ + ChannelBuilder: cb, log: log, metr: metr, cfg: cfg, - channelBuilder: cb, pendingTransactions: make(map[string]txData), confirmedTransactions: make(map[string]eth.BlockID), minInclusionBlock: math.MaxUint64, @@ -51,7 +47,7 @@ func (c *channel) TxFailed(id string) { // Rewind to the first frame of the failed tx // -- the frames are ordered, and we want to send them // all again. - c.channelBuilder.RewindFrameCursor(data.Frames()[0]) + c.RewindFrameCursor(data.Frames()[0]) delete(c.pendingTransactions, id) } else { c.log.Warn("unknown transaction marked as failed", "id", id) @@ -73,7 +69,7 @@ func (c *channel) TxConfirmed(id string, inclusionBlock eth.BlockID) bool { } delete(c.pendingTransactions, id) c.confirmedTransactions[id] = inclusionBlock - c.channelBuilder.FramePublished(inclusionBlock.Number) + c.FramePublished(inclusionBlock.Number) // Update min/max inclusion blocks for timeout check c.minInclusionBlock = min(c.minInclusionBlock, inclusionBlock.Number) @@ -95,11 +91,6 @@ func (c *channel) TxConfirmed(id string, inclusionBlock eth.BlockID) bool { return false } -// Timeout returns the channel timeout L1 block number. If there is no timeout set, it returns 0. -func (c *channel) Timeout() uint64 { - return c.channelBuilder.Timeout() -} - // isTimedOut returns true if submitted channel has timed out. // A channel has timed out if the difference in L1 Inclusion blocks between // the first & last included block is greater than or equal to the channel timeout. @@ -115,14 +106,10 @@ func (c *channel) isFullySubmitted() bool { return c.IsFull() && len(c.pendingTransactions)+c.PendingFrames() == 0 } -func (c *channel) NoneSubmitted() bool { +func (c *channel) noneSubmitted() bool { return len(c.confirmedTransactions) == 0 && len(c.pendingTransactions) == 0 } -func (c *channel) ID() derive.ChannelID { - return c.channelBuilder.ID() -} - // NextTxData dequeues the next frames from the channel and returns them encoded in a tx data packet. // If cfg.UseBlobs is false, it returns txData with a single frame. // If cfg.UseBlobs is true, it will read frames from its channel builder @@ -132,8 +119,8 @@ func (c *channel) ID() derive.ChannelID { func (c *channel) NextTxData() txData { nf := c.cfg.MaxFramesPerTx() txdata := txData{frames: make([]frameData, 0, nf), asBlob: c.cfg.UseBlobs} - for i := 0; i < nf && c.channelBuilder.HasPendingFrame(); i++ { - frame := c.channelBuilder.NextFrame() + for i := 0; i < nf && c.HasPendingFrame(); i++ { + frame := c.NextFrame() txdata.frames = append(txdata.frames, frame) } @@ -147,74 +134,10 @@ func (c *channel) NextTxData() txData { func (c *channel) HasTxData() bool { if c.IsFull() || // If the channel is full, we should start to submit it !c.cfg.UseBlobs { // If using calldata, we only send one frame per tx - return c.channelBuilder.HasPendingFrame() + return c.HasPendingFrame() } // Collect enough frames if channel is not full yet - return c.channelBuilder.PendingFrames() >= int(c.cfg.MaxFramesPerTx()) -} - -func (c *channel) IsFull() bool { - return c.channelBuilder.IsFull() -} - -func (c *channel) FullErr() error { - return c.channelBuilder.FullErr() -} - -func (c *channel) CheckTimeout(l1BlockNum uint64) { - c.channelBuilder.CheckTimeout(l1BlockNum) -} - -func (c *channel) AddBlock(block SizedBlock) (*derive.L1BlockInfo, error) { - return c.channelBuilder.AddBlock(block) -} - -func (c *channel) InputBytes() int { - return c.channelBuilder.InputBytes() -} - -func (c *channel) ReadyBytes() int { - return c.channelBuilder.ReadyBytes() -} - -func (c *channel) OutputBytes() int { - return c.channelBuilder.OutputBytes() -} - -func (c *channel) TotalFrames() int { - return c.channelBuilder.TotalFrames() -} - -func (c *channel) PendingFrames() int { - return c.channelBuilder.PendingFrames() -} - -func (c *channel) OutputFrames() error { - return c.channelBuilder.OutputFrames() -} - -// LatestL1Origin returns the latest L1 block origin from all the L2 blocks that have been added to the channel -func (c *channel) LatestL1Origin() eth.BlockID { - return c.channelBuilder.LatestL1Origin() -} - -// OldestL1Origin returns the oldest L1 block origin from all the L2 blocks that have been added to the channel -func (c *channel) OldestL1Origin() eth.BlockID { - return c.channelBuilder.OldestL1Origin() -} - -// LatestL2 returns the latest L2 block from all the L2 blocks that have been added to the channel -func (c *channel) LatestL2() eth.BlockID { - return c.channelBuilder.LatestL2() -} - -// OldestL2 returns the oldest L2 block from all the L2 blocks that have been added to the channel -func (c *channel) OldestL2() eth.BlockID { - return c.channelBuilder.OldestL2() -} - -func (c *channel) Close() { - c.channelBuilder.Close() + return c.PendingFrames() >= int(c.cfg.MaxFramesPerTx()) } func (c *channel) MaxInclusionBlock() uint64 { diff --git a/op-batcher/batcher/channel_builder.go b/op-batcher/batcher/channel_builder.go index c9f29283cd9..eab2f203726 100644 --- a/op-batcher/batcher/channel_builder.go +++ b/op-batcher/batcher/channel_builder.go @@ -133,12 +133,6 @@ func (c *ChannelBuilder) OutputBytes() int { return c.outputBytes } -// Blocks returns a backup list of all blocks that were added to the channel. It -// can be used in case the channel needs to be rebuilt. -func (c *ChannelBuilder) Blocks() []SizedBlock { - return c.blocks -} - // LatestL1Origin returns the latest L1 block origin from all the L2 blocks that have been added to the channel func (c *ChannelBuilder) LatestL1Origin() eth.BlockID { return c.latestL1Origin @@ -213,13 +207,6 @@ func (c *ChannelBuilder) AddBlock(block SizedBlock) (*derive.L1BlockInfo, error) return l1info, nil } -// Timeout management - -// Timeout returns the block number of the channel timeout. If no timeout is set it returns 0 -func (c *ChannelBuilder) Timeout() uint64 { - return c.timeout -} - // FramePublished should be called whenever a frame of this channel got // published with the L1-block number of the block that the frame got included // in. diff --git a/op-batcher/batcher/channel_manager.go b/op-batcher/batcher/channel_manager.go index b933de454f2..4e1ca799cc3 100644 --- a/op-batcher/batcher/channel_manager.go +++ b/op-batcher/batcher/channel_manager.go @@ -152,12 +152,12 @@ func (s *channelManager) rewindToBlock(block eth.BlockID) { // and removes the channel from the channelQueue, along with // any channels which are newer than the provided channel. func (s *channelManager) handleChannelInvalidated(c *channel) { - if len(c.channelBuilder.blocks) > 0 { + if len(c.ChannelBuilder.blocks) > 0 { // This is usually true, but there is an edge case // where a channel timed out before any blocks got added. // In that case we end up with an empty frame (header only), // and there are no blocks to requeue. - blockID := eth.ToBlockID(c.channelBuilder.blocks[0]) + blockID := eth.ToBlockID(c.ChannelBuilder.blocks[0]) s.rewindToBlock(blockID) } else { s.log.Debug("channelManager.handleChannelInvalidated: channel had no blocks") @@ -176,7 +176,7 @@ func (s *channelManager) handleChannelInvalidated(c *channel) { for i := invalidatedChannelIdx; i < len(s.channelQueue); i++ { s.log.Warn("Dropped channel", "id", s.channelQueue[i].ID(), - "none_submitted", s.channelQueue[i].NoneSubmitted(), + "none_submitted", s.channelQueue[i].noneSubmitted(), "fully_submitted", s.channelQueue[i].isFullySubmitted(), "timed_out", s.channelQueue[i].isTimedOut(), "full_reason", s.channelQueue[i].FullErr(), @@ -232,7 +232,7 @@ func (s *channelManager) TxData(l1Head eth.BlockID, isPectra, isThrottling, forc } // If the channel has already started being submitted, // return now and ensure no requeuing happens - if !channel.NoneSubmitted() { + if !channel.noneSubmitted() { return s.nextTxData(channel) } @@ -472,7 +472,7 @@ func (s *channelManager) outputFrames() error { "compr_ratio", comprRatio, ) - s.currentChannel.channelBuilder.co.DiscardCompressor() // Free up memory by discarding the compressor + s.currentChannel.ChannelBuilder.co.DiscardCompressor() // Free up memory by discarding the compressor return nil } @@ -586,7 +586,7 @@ func (s *channelManager) unsafeBytesInOpenChannels() int64 { var bytesInOpenChannels int64 for _, channel := range s.channelQueue { if channel.TotalFrames() == 0 { - for _, block := range channel.channelBuilder.blocks { + for _, block := range channel.ChannelBuilder.blocks { bytesInOpenChannels += int64(block.EstimatedDABytes()) } } diff --git a/op-batcher/batcher/channel_manager_test.go b/op-batcher/batcher/channel_manager_test.go index c8bce13262e..2aafe1f315d 100644 --- a/op-batcher/batcher/channel_manager_test.go +++ b/op-batcher/batcher/channel_manager_test.go @@ -153,7 +153,7 @@ func ChannelManager_Clear(t *testing.T, batchType uint) { // Process the blocks // We should have a pending channel with 1 frame require.NoError(m.processBlocks()) - require.NoError(m.currentChannel.channelBuilder.co.Flush()) + require.NoError(m.currentChannel.ChannelBuilder.co.Flush()) require.NoError(m.outputFrames()) _, err := m.nextTxData(m.currentChannel) require.NoError(err) @@ -270,7 +270,7 @@ func TestChannelManager_ChannelCreation(t *testing.T) { require.NoError(t, m.ensureChannelWithSpace(eth.BlockID{})) require.NotNil(t, m.currentChannel) - require.Equal(t, test.expectedChannelTimeout, m.currentChannel.Timeout()) + require.Equal(t, test.expectedChannelTimeout, m.currentChannel.timeout) }) } } @@ -693,7 +693,7 @@ func TestChannelManager_ChannelOutFactory(t *testing.T) { }) require.NoError(t, m.ensureChannelWithSpace(eth.BlockID{})) - require.IsType(t, &ChannelOutWrapper{}, m.currentChannel.channelBuilder.co) + require.IsType(t, &ChannelOutWrapper{}, m.currentChannel.ChannelBuilder.co) } // TestChannelManager_TxData seeds the channel manager with blocks and triggers the diff --git a/op-batcher/batcher/channel_test.go b/op-batcher/batcher/channel_test.go index 0e1365eceec..e1674fe8814 100644 --- a/op-batcher/batcher/channel_test.go +++ b/op-batcher/batcher/channel_test.go @@ -113,7 +113,7 @@ func TestChannelManager_NextTxData(t *testing.T) { frameNumber: uint16(0), }, } - channel.channelBuilder.frames = append(channel.channelBuilder.frames, frame) + channel.ChannelBuilder.frames = append(channel.ChannelBuilder.frames, frame) require.Equal(t, 1, channel.PendingFrames()) // Now the nextTxData function should return the frame @@ -142,7 +142,7 @@ func TestChannel_NextTxData_singleFrameTx(t *testing.T) { mockframes := makeMockFrameDatas(chID, n+1) // put multiple frames into channel, but less than target - ch.channelBuilder.frames = mockframes[:n-1] + ch.ChannelBuilder.frames = mockframes[:n-1] requireTxData := func(i int) { require.True(ch.HasTxData(), "expected tx data %d", i) @@ -160,7 +160,7 @@ func TestChannel_NextTxData_singleFrameTx(t *testing.T) { require.False(ch.HasTxData()) // put in last two - ch.channelBuilder.frames = append(ch.channelBuilder.frames, mockframes[n-1:n+1]...) + ch.ChannelBuilder.frames = append(ch.ChannelBuilder.frames, mockframes[n-1:n+1]...) for i := n - 1; i < n+1; i++ { requireTxData(i) } @@ -183,11 +183,11 @@ func TestChannel_NextTxData_multiFrameTx(t *testing.T) { mockframes := makeMockFrameDatas(chID, n+1) // put multiple frames into channel, but less than target - ch.channelBuilder.frames = append(ch.channelBuilder.frames, mockframes[:n-1]...) + ch.ChannelBuilder.frames = append(ch.ChannelBuilder.frames, mockframes[:n-1]...) require.False(ch.HasTxData()) // put in last two - ch.channelBuilder.frames = append(ch.channelBuilder.frames, mockframes[n-1:n+1]...) + ch.ChannelBuilder.frames = append(ch.ChannelBuilder.frames, mockframes[n-1:n+1]...) require.True(ch.HasTxData()) txdata := ch.NextTxData() require.Len(txdata.frames, n) @@ -240,7 +240,7 @@ func TestChannelTxConfirmed(t *testing.T) { frameNumber: uint16(0), }, } - m.currentChannel.channelBuilder.frames = append(m.currentChannel.channelBuilder.frames, frame) + m.currentChannel.ChannelBuilder.frames = append(m.currentChannel.ChannelBuilder.frames, frame) require.Equal(t, 1, m.currentChannel.PendingFrames()) returnedTxData, err := m.nextTxData(m.currentChannel) @@ -292,7 +292,7 @@ func TestChannelTxFailed(t *testing.T) { frameNumber: uint16(0), }, } - m.currentChannel.channelBuilder.frames = append(m.currentChannel.channelBuilder.frames, frame) + m.currentChannel.ChannelBuilder.frames = append(m.currentChannel.ChannelBuilder.frames, frame) require.Equal(t, 1, m.currentChannel.PendingFrames()) returnedTxData, err := m.nextTxData(m.currentChannel) expectedTxData := singleFrameTxData(frame) diff --git a/op-batcher/batcher/throttler/linear_strategy_test.go b/op-batcher/batcher/throttler/linear_strategy_test.go index bcef50f375b..8080d70ee43 100644 --- a/op-batcher/batcher/throttler/linear_strategy_test.go +++ b/op-batcher/batcher/throttler/linear_strategy_test.go @@ -46,61 +46,51 @@ func TestLinearStrategy_Update(t *testing.T) { tests := []struct { name string pendingBytes uint64 - targetBytes uint64 expectedIntensity float64 }{ { name: "zero load", pendingBytes: 0, - targetBytes: 0, expectedIntensity: TestIntensityMin, }, { name: "below threshold", pendingBytes: TestLinearThreshold / 2, - targetBytes: 0, expectedIntensity: TestIntensityMin, }, { name: "exactly at threshold", pendingBytes: TestLinearThreshold, - targetBytes: 0, expectedIntensity: TestIntensityMin, }, { name: "25% above threshold", pendingBytes: TestLinearThreshold + TestLinearThreshold/4, - targetBytes: 0, expectedIntensity: 0.25, }, { name: "50% above threshold", pendingBytes: TestLinearThreshold + TestLinearThreshold/2, - targetBytes: 0, expectedIntensity: 0.50, }, { name: "75% above threshold", pendingBytes: TestLinearThreshold + 3*TestLinearThreshold/4, - targetBytes: 0, expectedIntensity: 0.75, }, { name: "100% above threshold (max)", pendingBytes: TestLinearMaxThreshold, - targetBytes: 0, expectedIntensity: TestIntensityMax, }, { name: "beyond max threshold", pendingBytes: TestLinearMaxThreshold * 2, - targetBytes: 0, expectedIntensity: TestIntensityMax, }, { name: "with target bytes ignored", pendingBytes: TestLinearThreshold + TestLinearThreshold/2, - targetBytes: TestLinearThreshold * 10, // Target bytes should be ignored expectedIntensity: 0.50, }, } @@ -173,12 +163,10 @@ func TestLinearStrategy_Reset(t *testing.T) { func TestLinearStrategy_EdgeCases(t *testing.T) { t.Run("max threshold less than threshold", func(t *testing.T) { - require.Panics(t, func() { // Test when multiplier results in maxThreshold <= threshold NewLinearStrategy(TestLinearThreshold, 0, newTestLogger(t)) }) - }) t.Run("very large multiplier", func(t *testing.T) { diff --git a/op-batcher/batcher/throttler/pid_strategy_test.go b/op-batcher/batcher/throttler/pid_strategy_test.go index 835e9ece029..1bd4050da3c 100644 --- a/op-batcher/batcher/throttler/pid_strategy_test.go +++ b/op-batcher/batcher/throttler/pid_strategy_test.go @@ -299,31 +299,26 @@ func TestPIDStrategy_ErrorCalculation(t *testing.T) { testCases := []struct { name string pendingBytes uint64 - targetBytes uint64 expectError bool }{ { name: "no error at threshold", pendingBytes: TestPIDThreshold, - targetBytes: TestPIDThreshold, expectError: false, }, { name: "error above threshold", pendingBytes: TestPIDThreshold * 2, - targetBytes: TestPIDThreshold, expectError: true, }, { name: "no error below threshold", pendingBytes: TestPIDThreshold / 2, - targetBytes: TestPIDThreshold, expectError: false, }, { name: "error with different target", pendingBytes: TestPIDThreshold * 2, - targetBytes: TestPIDThreshold / 2, expectError: true, }, } diff --git a/op-batcher/batcher/throttler/quadratic_strategy_test.go b/op-batcher/batcher/throttler/quadratic_strategy_test.go index a88c0f0755b..a6b44e1789f 100644 --- a/op-batcher/batcher/throttler/quadratic_strategy_test.go +++ b/op-batcher/batcher/throttler/quadratic_strategy_test.go @@ -46,62 +46,52 @@ func TestQuadraticStrategy_Update(t *testing.T) { tests := []struct { name string pendingBytes uint64 - targetBytes uint64 expectedIntensity float64 }{ { name: "zero load", pendingBytes: 0, - targetBytes: 0, expectedIntensity: TestIntensityMin, }, { name: "below threshold", pendingBytes: TestQuadraticThreshold / 2, - targetBytes: 0, expectedIntensity: TestIntensityMin, }, { name: "exactly at threshold", pendingBytes: TestQuadraticThreshold, - targetBytes: 0, expectedIntensity: TestIntensityMin, }, { name: "25% above threshold", pendingBytes: TestQuadraticThreshold + TestQuadraticThreshold/4, - targetBytes: 0, expectedIntensity: 0.0625, // (0.25)^2 }, { name: "50% above threshold", pendingBytes: TestQuadraticThreshold + TestQuadraticThreshold/2, - targetBytes: 0, expectedIntensity: 0.25, // (0.5)^2 }, { name: "75% above threshold", pendingBytes: TestQuadraticThreshold + 3*TestQuadraticThreshold/4, - targetBytes: 0, expectedIntensity: 0.5625, // (0.75)^2 }, { name: "100% above threshold (max)", pendingBytes: TestQuadraticMaxThreshold, - targetBytes: 0, expectedIntensity: TestIntensityMax, }, { name: "beyond max threshold", pendingBytes: TestQuadraticMaxThreshold * 2, - targetBytes: 0, expectedIntensity: TestIntensityMax, }, { name: "with target bytes ignored", pendingBytes: TestQuadraticThreshold + TestQuadraticThreshold/2, - targetBytes: TestQuadraticThreshold * 10, // Target bytes should be ignored - expectedIntensity: 0.25, // (0.5)^2 + expectedIntensity: 0.25, // (0.5)^2 }, } diff --git a/op-batcher/batcher/throttler/step_strategy_test.go b/op-batcher/batcher/throttler/step_strategy_test.go index a4e668ee094..7c7f2d7d731 100644 --- a/op-batcher/batcher/throttler/step_strategy_test.go +++ b/op-batcher/batcher/throttler/step_strategy_test.go @@ -38,43 +38,36 @@ func TestStepStrategy_Update(t *testing.T) { tests := []struct { name string pendingBytes uint64 - targetBytes uint64 expectedIntensity float64 }{ { name: "zero load", pendingBytes: 0, - targetBytes: 0, expectedIntensity: TestIntensityMin, }, { name: "below threshold", pendingBytes: TestStepThreshold / 2, - targetBytes: 0, expectedIntensity: TestIntensityMin, }, { name: "exactly at threshold", pendingBytes: TestStepThreshold, - targetBytes: 0, expectedIntensity: TestIntensityMin, }, { name: "just above threshold", pendingBytes: TestStepThreshold + 1, - targetBytes: 0, expectedIntensity: TestIntensityMax, }, { name: "far above threshold", pendingBytes: TestStepThreshold * 10, - targetBytes: 0, expectedIntensity: TestIntensityMax, }, { name: "with target bytes ignored", pendingBytes: TestStepThreshold + 1000, - targetBytes: TestStepThreshold * 2, // Target bytes should be ignored in step strategy expectedIntensity: TestIntensityMax, }, } diff --git a/op-chain-ops/cmd/check-ecotone/main.go b/op-chain-ops/cmd/check-ecotone/main.go index 10d5f72e7ad..a1726d72c71 100644 --- a/op-chain-ops/cmd/check-ecotone/main.go +++ b/op-chain-ops/cmd/check-ecotone/main.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum-optimism/optimism/op-chain-ops/cmd/check-ecotone/bindings" + "github.com/ethereum-optimism/optimism/op-core/predeploys" nbindings "github.com/ethereum-optimism/optimism/op-node/bindings" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" op_service "github.com/ethereum-optimism/optimism/op-service" @@ -35,7 +36,6 @@ import ( "github.com/ethereum-optimism/optimism/op-service/dial" "github.com/ethereum-optimism/optimism/op-service/eth" oplog "github.com/ethereum-optimism/optimism/op-service/log" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/retry" "github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum-optimism/optimism/op-service/txmgr" diff --git a/op-chain-ops/cmd/check-fjord/checks/checks.go b/op-chain-ops/cmd/check-fjord/checks/checks.go index a7063bbde94..e24cfdada85 100644 --- a/op-chain-ops/cmd/check-fjord/checks/checks.go +++ b/op-chain-ops/cmd/check-fjord/checks/checks.go @@ -22,9 +22,9 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" - "github.com/ethereum-optimism/optimism/op-service/predeploys" ) type CheckFjordConfig struct { diff --git a/op-chain-ops/cmd/withdrawal/init.go b/op-chain-ops/cmd/withdrawal/init.go index ae84d72e0a2..341302bf26f 100644 --- a/op-chain-ops/cmd/withdrawal/init.go +++ b/op-chain-ops/cmd/withdrawal/init.go @@ -4,9 +4,9 @@ import ( "fmt" "math/big" + "github.com/ethereum-optimism/optimism/op-core/predeploys" op_service "github.com/ethereum-optimism/optimism/op-service" oplog "github.com/ethereum-optimism/optimism/op-service/log" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/urfave/cli/v2" ) diff --git a/op-chain-ops/genesis/config.go b/op-chain-ops/genesis/config.go index 564e90c3db8..514647c7a19 100644 --- a/op-chain-ops/genesis/config.go +++ b/op-chain-ops/genesis/config.go @@ -18,6 +18,7 @@ import ( altda "github.com/ethereum-optimism/optimism/op-alt-da" "github.com/ethereum-optimism/optimism/op-chain-ops/addresses" + "github.com/ethereum-optimism/optimism/op-core/forks" opparams "github.com/ethereum-optimism/optimism/op-node/params" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" @@ -434,25 +435,25 @@ func offsetToUpgradeTime(offset *hexutil.Uint64, genesisTime uint64) *uint64 { func (d *UpgradeScheduleDeployConfig) ForkTimeOffset(fork rollup.ForkName) *uint64 { switch fork { - case rollup.Regolith: + case forks.Regolith: return (*uint64)(d.L2GenesisRegolithTimeOffset) - case rollup.Canyon: + case forks.Canyon: return (*uint64)(d.L2GenesisCanyonTimeOffset) - case rollup.Delta: + case forks.Delta: return (*uint64)(d.L2GenesisDeltaTimeOffset) - case rollup.Ecotone: + case forks.Ecotone: return (*uint64)(d.L2GenesisEcotoneTimeOffset) - case rollup.Fjord: + case forks.Fjord: return (*uint64)(d.L2GenesisFjordTimeOffset) - case rollup.Granite: + case forks.Granite: return (*uint64)(d.L2GenesisGraniteTimeOffset) - case rollup.Holocene: + case forks.Holocene: return (*uint64)(d.L2GenesisHoloceneTimeOffset) - case rollup.Isthmus: + case forks.Isthmus: return (*uint64)(d.L2GenesisIsthmusTimeOffset) - case rollup.Jovian: + case forks.Jovian: return (*uint64)(d.L2GenesisJovianTimeOffset) - case rollup.Interop: + case forks.Interop: return (*uint64)(d.L2GenesisInteropTimeOffset) default: panic(fmt.Sprintf("unknown fork: %s", fork)) @@ -461,32 +462,32 @@ func (d *UpgradeScheduleDeployConfig) ForkTimeOffset(fork rollup.ForkName) *uint func (d *UpgradeScheduleDeployConfig) SetForkTimeOffset(fork rollup.ForkName, offset *uint64) { switch fork { - case rollup.Regolith: + case forks.Regolith: d.L2GenesisRegolithTimeOffset = (*hexutil.Uint64)(offset) - case rollup.Canyon: + case forks.Canyon: d.L2GenesisCanyonTimeOffset = (*hexutil.Uint64)(offset) - case rollup.Delta: + case forks.Delta: d.L2GenesisDeltaTimeOffset = (*hexutil.Uint64)(offset) - case rollup.Ecotone: + case forks.Ecotone: d.L2GenesisEcotoneTimeOffset = (*hexutil.Uint64)(offset) - case rollup.Fjord: + case forks.Fjord: d.L2GenesisFjordTimeOffset = (*hexutil.Uint64)(offset) - case rollup.Granite: + case forks.Granite: d.L2GenesisGraniteTimeOffset = (*hexutil.Uint64)(offset) - case rollup.Holocene: + case forks.Holocene: d.L2GenesisHoloceneTimeOffset = (*hexutil.Uint64)(offset) - case rollup.Isthmus: + case forks.Isthmus: d.L2GenesisIsthmusTimeOffset = (*hexutil.Uint64)(offset) - case rollup.Jovian: + case forks.Jovian: d.L2GenesisJovianTimeOffset = (*hexutil.Uint64)(offset) - case rollup.Interop: + case forks.Interop: d.L2GenesisInteropTimeOffset = (*hexutil.Uint64)(offset) default: panic(fmt.Sprintf("unknown fork: %s", fork)) } } -var scheduleableForks = rollup.ForksFrom(rollup.Regolith) +var scheduleableForks = forks.From(forks.Regolith) // ActivateForkAtOffset activates the given fork at the given offset. Previous forks are activated // at genesis and later forks are deactivated. @@ -494,7 +495,7 @@ var scheduleableForks = rollup.ForksFrom(rollup.Regolith) // ActivateForkAtOffset with the earliest fork and then SetForkTimeOffset to individually set later // forks. func (d *UpgradeScheduleDeployConfig) ActivateForkAtOffset(fork rollup.ForkName, offset uint64) { - if !rollup.IsValidFork(fork) || fork == rollup.Bedrock { + if !forks.IsValid(fork) || fork == forks.Bedrock { panic(fmt.Sprintf("invalid fork: %s", fork)) } ts := new(uint64) diff --git a/op-chain-ops/genesis/config_test.go b/op-chain-ops/genesis/config_test.go index 66ac9139c01..98fe0e1f9e2 100644 --- a/op-chain-ops/genesis/config_test.go +++ b/op-chain-ops/genesis/config_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/testlog" ) @@ -94,7 +95,7 @@ func TestForksCantActivateAtSamePostGenesisBlock(t *testing.T) { postGenesisOffset := uint64(1500) config := &UpgradeScheduleDeployConfig{} for _, fork := range config.forks() { - config.SetForkTimeOffset(rollup.ForkName(fork.Name), &postGenesisOffset) + config.SetForkTimeOffset(forks.Name(fork.Name), &postGenesisOffset) } err := config.Check(testlog.Logger(t, log.LevelDebug)) require.Error(t, err) @@ -153,7 +154,7 @@ func TestL1Deployments(t *testing.T) { // This test guarantees that getters and setters for all forks are present. func TestUpgradeScheduleDeployConfig_ForkGettersAndSetters(t *testing.T) { var d UpgradeScheduleDeployConfig - for i, fork := range rollup.ForksFrom(rollup.Regolith) { + for i, fork := range forks.From(forks.Regolith) { require.Nil(t, d.ForkTimeOffset(fork)) offset := uint64(i * 42) d.SetForkTimeOffset(fork, &offset) @@ -165,11 +166,11 @@ func TestUpgradeScheduleDeployConfig_ActivateForkAtOffset(t *testing.T) { var d UpgradeScheduleDeployConfig ts := uint64(42) t.Run("invalid", func(t *testing.T) { - require.Panics(t, func() { d.ActivateForkAtOffset(rollup.Bedrock, ts) }) + require.Panics(t, func() { d.ActivateForkAtOffset(forks.Bedrock, ts) }) }) t.Run("regolith", func(t *testing.T) { - d.ActivateForkAtOffset(rollup.Regolith, ts) + d.ActivateForkAtOffset(forks.Regolith, ts) require.EqualValues(t, &ts, d.L2GenesisRegolithTimeOffset) for _, fork := range scheduleableForks[1:] { require.Nil(t, d.ForkTimeOffset(fork)) @@ -177,7 +178,7 @@ func TestUpgradeScheduleDeployConfig_ActivateForkAtOffset(t *testing.T) { }) t.Run("ecotone", func(t *testing.T) { - d.ActivateForkAtOffset(rollup.Ecotone, ts) + d.ActivateForkAtOffset(forks.Ecotone, ts) require.EqualValues(t, &ts, d.L2GenesisEcotoneTimeOffset) for _, fork := range scheduleableForks[:3] { require.Zero(t, *d.ForkTimeOffset(fork)) @@ -201,14 +202,14 @@ func TestUpgradeScheduleDeployConfig_SolidityForkNumber(t *testing.T) { fork rollup.ForkName expected int64 }{ - {rollup.Delta, 1}, - {rollup.Ecotone, 2}, - {rollup.Fjord, 3}, - {rollup.Granite, 4}, - {rollup.Holocene, 5}, - {rollup.Isthmus, 6}, - {rollup.Jovian, 7}, - {rollup.Interop, 8}, + {forks.Delta, 1}, + {forks.Ecotone, 2}, + {forks.Fjord, 3}, + {forks.Granite, 4}, + {forks.Holocene, 5}, + {forks.Isthmus, 6}, + {forks.Jovian, 7}, + {forks.Interop, 8}, } for _, tt := range tests { var d UpgradeScheduleDeployConfig diff --git a/op-chain-ops/genesis/genesis.go b/op-chain-ops/genesis/genesis.go index 306f70df2dd..a7a437fc172 100644 --- a/op-chain-ops/genesis/genesis.go +++ b/op-chain-ops/genesis/genesis.go @@ -6,8 +6,8 @@ import ( "math/big" "time" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" diff --git a/op-chain-ops/genesis/layer_one.go b/op-chain-ops/genesis/layer_one.go index 7178cccebb9..dfcc5ee53d4 100644 --- a/op-chain-ops/genesis/layer_one.go +++ b/op-chain-ops/genesis/layer_one.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis/beacondeposit" - "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum-optimism/optimism/op-core/predeploys" ) // PrecompileCount represents the number of precompile addresses diff --git a/op-chain-ops/genesis/layer_two.go b/op-chain-ops/genesis/layer_two.go index 5a89ac0bfd3..20181596451 100644 --- a/op-chain-ops/genesis/layer_two.go +++ b/op-chain-ops/genesis/layer_two.go @@ -14,8 +14,8 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum-optimism/optimism/op-chain-ops/foundry" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" ) type L2AllocsMode string diff --git a/op-core/forks/forks.go b/op-core/forks/forks.go new file mode 100644 index 00000000000..6267734cb99 --- /dev/null +++ b/op-core/forks/forks.go @@ -0,0 +1,82 @@ +package forks + +import "fmt" + +// Name identifies a hardfork by name. +type Name string + +const ( + Bedrock Name = "bedrock" + Regolith Name = "regolith" + Canyon Name = "canyon" + Delta Name = "delta" + Ecotone Name = "ecotone" + Fjord Name = "fjord" + Granite Name = "granite" + Holocene Name = "holocene" + Isthmus Name = "isthmus" + Jovian Name = "jovian" + Interop Name = "interop" + // ADD NEW MAINLINE FORKS TO [All] BELOW! + + // Optional Forks - not part of mainline + PectraBlobSchedule Name = "pectrablobschedule" + + None Name = "" +) + +// All lists all known mainline forks in chronological order. +var All = []Name{ + Bedrock, + Regolith, + Canyon, + Delta, + Ecotone, + Fjord, + Granite, + Holocene, + Isthmus, + Jovian, + Interop, + // ADD NEW MAINLINE FORKS HERE! +} + +// AllOpt lists all optional forks in chronological order. +var AllOpt = []Name{ + PectraBlobSchedule, + // ADD NEW OPTIONAL FORKS HERE! +} + +// Latest returns the most recent fork in [All]. +var Latest = All[len(All)-1] + +// From returns the list of forks starting from the provided fork, inclusive. +func From(start Name) []Name { + for i, f := range All { + if f == start { + return All[i:] + } + } + panic(fmt.Sprintf("invalid fork: %s", start)) +} + +var next = func() map[Name]Name { + m := make(map[Name]Name, len(All)) + for i, f := range All { + if i == len(All)-1 { + m[f] = None + break + } + m[f] = All[i+1] + } + return m +}() + +// IsValid returns true if the provided fork is a known fork. +func IsValid(f Name) bool { + _, ok := next[f] + return ok +} + +// Next returns the fork that follows the provided fork, or None if it is the last. +func Next(f Name) Name { return next[f] } diff --git a/op-service/predeploys/addresses.go b/op-core/predeploys/addresses.go similarity index 100% rename from op-service/predeploys/addresses.go rename to op-core/predeploys/addresses.go diff --git a/op-service/predeploys/addresses_test.go b/op-core/predeploys/addresses_test.go similarity index 100% rename from op-service/predeploys/addresses_test.go rename to op-core/predeploys/addresses_test.go diff --git a/op-service/predeploys/eip2935.go b/op-core/predeploys/eip2935.go similarity index 100% rename from op-service/predeploys/eip2935.go rename to op-core/predeploys/eip2935.go diff --git a/op-service/predeploys/eip4788.go b/op-core/predeploys/eip4788.go similarity index 100% rename from op-service/predeploys/eip4788.go rename to op-core/predeploys/eip4788.go diff --git a/op-service/predeploys/legacy_addresses.go b/op-core/predeploys/legacy_addresses.go similarity index 100% rename from op-service/predeploys/legacy_addresses.go rename to op-core/predeploys/legacy_addresses.go diff --git a/op-service/predeploys/predeploy.go b/op-core/predeploys/predeploy.go similarity index 100% rename from op-service/predeploys/predeploy.go rename to op-core/predeploys/predeploy.go diff --git a/op-deployer/justfile b/op-deployer/justfile index 92fb5aed702..be50d106c12 100644 --- a/op-deployer/justfile +++ b/op-deployer/justfile @@ -6,7 +6,7 @@ test args='./...': build-contracts copy-contract-artifacts go test -v {{args}} build-contracts: - just ../packages/contracts-bedrock/forge-build + just ../packages/contracts-bedrock/build-no-tests copy-contract-artifacts: #!/bin/bash @@ -87,17 +87,16 @@ _validate_rpc: pre-deploy: build build-contracts # Run with: -# PRIVATE_KEY=0x1234.... NETWORK=sepolia just deploy-opcm 'op-contracts/v4.0.0-rc.8' -deploy-opcm release="dev" locator="$DEFAULT_LOCATOR": _validate_rpc +# PRIVATE_KEY=0x1234.... NETWORK=sepolia just deploy-opcm +deploy-opcm locator="$DEFAULT_LOCATOR": _validate_rpc #!/bin/bash echo "Using artifacts locator: {{locator}}" - ./bin/op-deployer bootstrap implementations \ + go run ./cmd/op-deployer bootstrap implementations \ --l1-rpc-url $ETH_RPC_URL \ --private-key $PRIVATE_KEY \ - --mips-version 7 \ --protocol-versions-proxy $PROTOCOL_VERSIONS_PROXY \ --superchain-config-proxy $SUPERCHAIN_CONFIG_PROXY \ - --l1-proxy-admin-owner $L1_PROXY_ADMIN_OWNER \ + --upgrade-controller $L1_PROXY_ADMIN_OWNER \ --superchain-proxy-admin $SUPERCHAIN_PROXY_ADMIN \ --challenger $CHALLENGER \ --outfile deploy-${NETWORK}.json @@ -107,7 +106,7 @@ deploy-opcm release="dev" locator="$DEFAULT_LOCATOR": _validate_rpc verify-opcm locator="$DEFAULT_LOCATOR": _validate_rpc #!/bin/bash echo "Using artifacts locator: {{locator}}" - ./bin/op-deployer verify \ + go run ./cmd/op-deployer verify \ --artifacts-locator {{locator}} \ --l1-rpc-url $ETH_RPC_URL \ --etherscan-api-key $ETHERSCAN_API_KEY \ diff --git a/op-deployer/pkg/deployer/inspect/semvers.go b/op-deployer/pkg/deployer/inspect/semvers.go index e373adf09fd..3f9a17fa21a 100644 --- a/op-deployer/pkg/deployer/inspect/semvers.go +++ b/op-deployer/pkg/deployer/inspect/semvers.go @@ -18,12 +18,12 @@ import ( "github.com/ethereum-optimism/optimism/op-chain-ops/script" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline" "github.com/ethereum-optimism/optimism/op-service/ioutil" "github.com/ethereum-optimism/optimism/op-service/jsonutil" oplog "github.com/ethereum-optimism/optimism/op-service/log" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" "github.com/urfave/cli/v2" diff --git a/op-deployer/pkg/deployer/integration_test/apply_test.go b/op-deployer/pkg/deployer/integration_test/apply_test.go index f7958028ab5..3d56200db75 100644 --- a/op-deployer/pkg/deployer/integration_test/apply_test.go +++ b/op-deployer/pkg/deployer/integration_test/apply_test.go @@ -44,7 +44,7 @@ import ( "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" - "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" diff --git a/op-deployer/pkg/deployer/manage/flags.go b/op-deployer/pkg/deployer/manage/flags.go index dc7db918f26..1f3185d780e 100644 --- a/op-deployer/pkg/deployer/manage/flags.go +++ b/op-deployer/pkg/deployer/manage/flags.go @@ -56,6 +56,18 @@ var ( EnvVars: deployer.PrefixEnvVar("DISPUTE_ABSOLUTE_PRESTATE"), Value: standard.DisputeAbsolutePrestate.Hex(), } + DisputeAbsolutePrestateCannonFlag = &cli.StringFlag{ + Name: "dispute-absolute-prestate-cannon", + Usage: "The absolute prestate hash for the CANNON dispute game. Defaults to the standard value.", + EnvVars: deployer.PrefixEnvVar("DISPUTE_ABSOLUTE_PRESTATE_CANNON"), + Value: standard.DisputeAbsolutePrestate.Hex(), + } + DisputeAbsolutePrestateCannonKonaFlag = &cli.StringFlag{ + Name: "dispute-absolute-prestate-cannon-kona", + Usage: "The absolute prestate hash for the CANNON_KONA dispute game. Defaults to the standard value.", + EnvVars: deployer.PrefixEnvVar("DISPUTE_ABSOLUTE_PRESTATE_CANNON_KONA"), + Value: standard.DisputeAbsolutePrestate.Hex(), + } DisputeMaxGameDepthFlag = &cli.Uint64Flag{ Name: "dispute-max-game-depth", Usage: "Maximum depth of the dispute game tree (value as string). Defaults to the standard value.", @@ -176,7 +188,8 @@ var Commands = cli.Commands{ // SystemConfigProxyFlag, OPChainProxyAdminFlag, - DisputeAbsolutePrestateFlag, + DisputeAbsolutePrestateCannonFlag, + DisputeAbsolutePrestateCannonKonaFlag, }, oplog.CLIFlags(deployer.EnvVarPrefix)...), Action: MigrateCLI, }, diff --git a/op-deployer/pkg/deployer/manage/migrate.go b/op-deployer/pkg/deployer/manage/migrate.go index 26da0631417..3c2c0f02734 100644 --- a/op-deployer/pkg/deployer/manage/migrate.go +++ b/op-deployer/pkg/deployer/manage/migrate.go @@ -111,8 +111,9 @@ func MigrateCLI(cliCtx *cli.Context) error { // At the moment we only support a single chain config EncodedChainConfigs: []OPChainConfig{ { - SystemConfigProxy: common.HexToAddress(cliCtx.String(SystemConfigProxyFlag.Name)), - CannonPrestate: common.HexToHash(cliCtx.String(DisputeAbsolutePrestateFlag.Name)), + SystemConfigProxy: common.HexToAddress(cliCtx.String(SystemConfigProxyFlag.Name)), + CannonPrestate: common.HexToHash(cliCtx.String(DisputeAbsolutePrestateCannonFlag.Name)), + CannonKonaPrestate: common.HexToHash(cliCtx.String(DisputeAbsolutePrestateCannonKonaFlag.Name)), }, }, } diff --git a/op-deployer/pkg/deployer/standard/standard.go b/op-deployer/pkg/deployer/standard/standard.go index 7d7ce3162a2..5ec49224b86 100644 --- a/op-deployer/pkg/deployer/standard/standard.go +++ b/op-deployer/pkg/deployer/standard/standard.go @@ -3,17 +3,15 @@ package standard import ( "fmt" - "github.com/ethereum/go-ethereum/common/hexutil" - - "github.com/ethereum-optimism/superchain-registry/validation" - - "github.com/ethereum/go-ethereum/superchain" - "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" - "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-core/forks" op_service "github.com/ethereum-optimism/optimism/op-service" + "github.com/ethereum-optimism/superchain-registry/validation" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/superchain" ) const ( @@ -185,13 +183,13 @@ func DefaultHardforkScheduleForTag(tag string) *genesis.UpgradeScheduleDeployCon case ContractsV160Tag, ContractsV170Beta1L2Tag: return sched case ContractsV180Tag, ContractsV200Tag, ContractsV300Tag: - sched.ActivateForkAtGenesis(rollup.Holocene) + sched.ActivateForkAtGenesis(forks.Holocene) case ContractsV400Tag, ContractsV410Tag: - sched.ActivateForkAtGenesis(rollup.Holocene) - sched.ActivateForkAtGenesis(rollup.Isthmus) + sched.ActivateForkAtGenesis(forks.Holocene) + sched.ActivateForkAtGenesis(forks.Isthmus) default: - sched.ActivateForkAtGenesis(rollup.Holocene) - sched.ActivateForkAtGenesis(rollup.Isthmus) + sched.ActivateForkAtGenesis(forks.Holocene) + sched.ActivateForkAtGenesis(forks.Isthmus) } return sched diff --git a/op-devstack/dsl/bridge.go b/op-devstack/dsl/bridge.go index 39cab10ed06..26ae4f0b84f 100644 --- a/op-devstack/dsl/bridge.go +++ b/op-devstack/dsl/bridge.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/stack/match" nodebindings "github.com/ethereum-optimism/optimism/op-node/bindings" @@ -18,7 +19,6 @@ import ( "github.com/ethereum-optimism/optimism/op-node/withdrawals" "github.com/ethereum-optimism/optimism/op-service/apis" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" "github.com/ethereum-optimism/optimism/op-service/txintent/contractio" "github.com/ethereum/go-ethereum/common" diff --git a/op-devstack/dsl/ecotone_fees.go b/op-devstack/dsl/ecotone_fees.go index d1970a94b92..ed0f85a46f1 100644 --- a/op-devstack/dsl/ecotone_fees.go +++ b/op-devstack/dsl/ecotone_fees.go @@ -3,11 +3,11 @@ package dsl import ( "math/big" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/stack/match" "github.com/ethereum-optimism/optimism/op-service/apis" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" ) diff --git a/op-devstack/dsl/fjord_fees.go b/op-devstack/dsl/fjord_fees.go index b27566634c7..739dd11055e 100644 --- a/op-devstack/dsl/fjord_fees.go +++ b/op-devstack/dsl/fjord_fees.go @@ -5,11 +5,11 @@ import ( "fmt" "math/big" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/stack/match" "github.com/ethereum-optimism/optimism/op-service/apis" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" "github.com/ethereum-optimism/optimism/op-service/txintent/contractio" "github.com/ethereum-optimism/optimism/op-service/txplan" diff --git a/op-devstack/dsl/l2_el.go b/op-devstack/dsl/l2_el.go index c4a8be53eab..ef66f6958df 100644 --- a/op-devstack/dsl/l2_el.go +++ b/op-devstack/dsl/l2_el.go @@ -7,11 +7,11 @@ import ( "strings" "time" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/stack" "github.com/ethereum-optimism/optimism/op-devstack/sysgo" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/retry" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" "github.com/ethereum/go-ethereum/common" diff --git a/op-devstack/dsl/operator_fee.go b/op-devstack/dsl/operator_fee.go index a15f607dfde..99ee6cff538 100644 --- a/op-devstack/dsl/operator_fee.go +++ b/op-devstack/dsl/operator_fee.go @@ -5,11 +5,11 @@ import ( "time" "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" + "github.com/ethereum-optimism/optimism/op-core/forks" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/stack/match" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" "github.com/ethereum-optimism/optimism/op-service/txintent/contractio" "github.com/ethereum/go-ethereum/core/types" @@ -142,7 +142,7 @@ func (of *OperatorFee) ValidateTransactionFees(from *EOA, to *EOA, amount *big.I of.require.NoError(err) // Infer active fork from block info - isJovian := of.l2Network.IsForkActive(rollup.Jovian, info.Time()) + isJovian := of.l2Network.IsForkActive(forks.Jovian, info.Time()) // Verify GPO upgraded when jovian is active // We have nothing to assert when jovian is inactive because an isthmus L2 can diff --git a/op-devstack/dsl/proofs/claim.go b/op-devstack/dsl/proofs/claim.go index 51051224e89..3842d750682 100644 --- a/op-devstack/dsl/proofs/claim.go +++ b/op-devstack/dsl/proofs/claim.go @@ -1,10 +1,14 @@ package proofs import ( + "context" "fmt" + "math/big" "slices" "time" + "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" @@ -43,12 +47,35 @@ func (c *Claim) Value() common.Hash { return c.claim.Value } +func (c *Claim) Bond() *big.Int { + return c.claim.Bond +} + +func (c *Claim) Position() types.Position { + return c.claim.Position +} + func (c *Claim) Claimant() common.Address { return c.claim.Claimant } -func (c *Claim) Depth() uint64 { - return uint64(c.claim.Depth()) +func (c *Claim) Depth() types.Depth { + return c.claim.Depth() +} + +func (c *Claim) asChallengerClaim() types.Claim { + return types.Claim{ + ClaimData: types.ClaimData{ + Value: c.claim.Value, + Bond: c.claim.Bond, + Position: c.claim.Position, + }, + CounteredBy: c.claim.CounteredBy, + Claimant: c.claim.Claimant, + Clock: c.claim.Clock, + ContractIndex: int(c.Index), + ParentContractIndex: int(c.claim.ParentContractIndex), + } } // WaitForCounterClaim waits for the claim to be countered by another claim being posted. @@ -60,6 +87,19 @@ func (c *Claim) WaitForCounterClaim(ignoreClaims ...*Claim) *Claim { return newClaim(c.t, c.require, counterIdx, counterClaim, c.game) } +// WaitForCountered waits until the claim is countered either by a child claim or by a step call. +func (c *Claim) WaitForCountered() { + timedCtx, cancel := context.WithTimeout(c.t.Ctx(), defaultTimeout) + defer cancel() + err := wait.For(timedCtx, time.Second, func() (bool, error) { + claim := c.game.claimAtIndex(c.Index) + return claim.CounteredBy != common.Address{}, nil + }) + if err != nil { // Avoid waiting time capturing game data when there's no error + c.require.NoErrorf(err, "Claim %v was not countered\n%v", c.Index, c.game.GameData()) + } +} + func (c *Claim) VerifyNoCounterClaim() { for i, claim := range c.game.allClaims() { c.require.NotEqualValuesf(c.Index, claim.ParentContractIndex, "Found unexpected counter-claim at index %v: %v", i, claim) @@ -71,6 +111,11 @@ func (c *Claim) Attack(eoa *dsl.EOA, newClaim common.Hash) *Claim { return c.WaitForCounterClaim() } +func (c *Claim) Defend(eoa *dsl.EOA, newClaim common.Hash) *Claim { + c.game.Defend(eoa, c.Index, newClaim) + return c.WaitForCounterClaim() +} + func containsClaim(claimIdx uint64, haystack []*Claim) bool { return slices.ContainsFunc(haystack, func(candidate *Claim) bool { return candidate.Index == claimIdx diff --git a/op-devstack/dsl/proofs/dispute_game_factory.go b/op-devstack/dsl/proofs/dispute_game_factory.go index 3dc0166df04..b9ed373f670 100644 --- a/op-devstack/dsl/proofs/dispute_game_factory.go +++ b/op-devstack/dsl/proofs/dispute_game_factory.go @@ -1,11 +1,17 @@ package proofs import ( + "context" "encoding/binary" "math/big" "time" + challengerConfig "github.com/ethereum-optimism/optimism/op-challenger/config" + "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/outputs" + "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/vm" + "github.com/ethereum-optimism/optimism/op-challenger/metrics" "github.com/ethereum-optimism/optimism/op-service/eth" + safetyTypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" @@ -21,37 +27,58 @@ import ( ) type DisputeGameFactory struct { - t devtest.T - require *require.Assertions - log log.Logger - l1Network *dsl.L1Network - ethClient apis.EthClient - dgf *bindings.DisputeGameFactory - addr common.Address - supervisor *dsl.Supervisor - gameHelper *GameHelper -} - -func NewDisputeGameFactory(t devtest.T, l1Network *dsl.L1Network, ethClient apis.EthClient, dgfAddr common.Address, supervisor *dsl.Supervisor) *DisputeGameFactory { + t devtest.T + require *require.Assertions + log log.Logger + l1Network *dsl.L1Network + ethClient apis.EthClient + dgf *bindings.DisputeGameFactory + addr common.Address + l2CL *dsl.L2CLNode + l2EL *dsl.L2ELNode + supervisor *dsl.Supervisor + gameHelper *GameHelper + challengerCfg *challengerConfig.Config + + honestTraces map[common.Address]challengerTypes.TraceAccessor +} + +func NewDisputeGameFactory( + t devtest.T, + l1Network *dsl.L1Network, + ethClient apis.EthClient, + dgfAddr common.Address, + l2CL *dsl.L2CLNode, + l2EL *dsl.L2ELNode, + supervisor *dsl.Supervisor, + challengerCfg *challengerConfig.Config, +) *DisputeGameFactory { dgf := bindings.NewDisputeGameFactory(bindings.WithClient(ethClient), bindings.WithTo(dgfAddr), bindings.WithTest(t)) return &DisputeGameFactory{ - t: t, - require: require.New(t), - log: t.Logger(), - l1Network: l1Network, - dgf: dgf, - addr: dgfAddr, - supervisor: supervisor, - ethClient: ethClient, + t: t, + require: require.New(t), + log: t.Logger(), + l1Network: l1Network, + dgf: dgf, + addr: dgfAddr, + l2CL: l2CL, + l2EL: l2EL, + supervisor: supervisor, + ethClient: ethClient, + challengerCfg: challengerCfg, + + honestTraces: make(map[common.Address]challengerTypes.TraceAccessor), } } type GameCfg struct { - allowFuture bool - allowUnsafe bool - rootClaimSet bool - rootClaim common.Hash + allowFuture bool + allowUnsafe bool + l2SequenceNumber uint64 + l2SequenceNumberSet bool + rootClaimSet bool + rootClaim common.Hash } type GameOpt interface { Apply(cfg *GameCfg) @@ -81,6 +108,13 @@ func WithRootClaim(claim common.Hash) GameOpt { }) } +func WithL2SequenceNumber(seqNum uint64) GameOpt { + return gameOptFn(func(c *GameCfg) { + c.l2SequenceNumber = seqNum + c.l2SequenceNumberSet = true + }) +} + func NewGameCfg(opts ...GameOpt) *GameCfg { cfg := &GameCfg{} for _, opt := range opts { @@ -97,7 +131,7 @@ func (f *DisputeGameFactory) getGameHelper(eoa *dsl.EOA) *GameHelper { if f.gameHelper != nil { return f.gameHelper } - gs := DeployGameHelper(f.t, eoa) + gs := DeployGameHelper(f.t, eoa, f.honestTraceForGame) f.gameHelper = gs return gs } @@ -109,13 +143,13 @@ func (f *DisputeGameFactory) GameCount() int64 { func (f *DisputeGameFactory) GameAtIndex(idx int64) *FaultDisputeGame { gameInfo := contract.Read(f.dgf.GameAtIndex(big.NewInt(idx))) game := bindings.NewFaultDisputeGame(bindings.WithClient(f.ethClient), bindings.WithTo(gameInfo.Proxy), bindings.WithTest(f.t)) - return NewFaultDisputeGame(f.t, f.require, gameInfo.Proxy, f.getGameHelper, game) + return NewFaultDisputeGame(f.t, f.require, gameInfo.Proxy, f.getGameHelper, f.honestTraceForGame, game) } func (f *DisputeGameFactory) GameImpl(gameType challengerTypes.GameType) *FaultDisputeGame { implAddr := contract.Read(f.dgf.GameImpls(uint32(gameType))) game := bindings.NewFaultDisputeGame(bindings.WithClient(f.ethClient), bindings.WithTo(implAddr), bindings.WithTest(f.t)) - return NewFaultDisputeGame(f.t, f.require, implAddr, f.getGameHelper, game) + return NewFaultDisputeGame(f.t, f.require, implAddr, f.getGameHelper, f.honestTraceForGame, game) } func (f *DisputeGameFactory) GameArgs(gameType challengerTypes.GameType) []byte { @@ -136,13 +170,16 @@ func (f *DisputeGameFactory) WaitForGame() *FaultDisputeGame { func (f *DisputeGameFactory) StartSuperCannonGame(eoa *dsl.EOA, opts ...GameOpt) *SuperFaultDisputeGame { f.require.NotNil(f.supervisor, "supervisor is required to start super games") - proposalTimestamp := f.supervisor.FetchSyncStatus().SafeTimestamp - return f.startSuperCannonGameOfType(eoa, proposalTimestamp, challengerTypes.SuperCannonGameType, opts...) + return f.startSuperCannonGameOfType(eoa, challengerTypes.SuperCannonGameType, opts...) } -func (f *DisputeGameFactory) startSuperCannonGameOfType(eoa *dsl.EOA, timestamp uint64, gameType challengerTypes.GameType, opts ...GameOpt) *SuperFaultDisputeGame { +func (f *DisputeGameFactory) startSuperCannonGameOfType(eoa *dsl.EOA, gameType challengerTypes.GameType, opts ...GameOpt) *SuperFaultDisputeGame { cfg := NewGameCfg(opts...) + timestamp := cfg.l2SequenceNumber + if !cfg.l2SequenceNumberSet { + timestamp = f.supervisor.FetchSyncStatus().SafeTimestamp + } extraData := f.createSuperGameExtraData(timestamp, cfg) rootClaim := cfg.rootClaim if !cfg.rootClaimSet { @@ -165,6 +202,77 @@ func (f *DisputeGameFactory) createSuperGameExtraData(timestamp uint64, cfg *Gam return extraData } +func (f *DisputeGameFactory) StartCannonGame(eoa *dsl.EOA, opts ...GameOpt) *FaultDisputeGame { + return f.startOutputRootGameOfType(eoa, challengerTypes.CannonGameType, f.honestTraceForGame, opts...) +} + +func (f *DisputeGameFactory) honestTraceForGame(game *FaultDisputeGame) challengerTypes.TraceAccessor { + if existing, ok := f.honestTraces[game.Address]; ok { + return existing + } + f.require.Equal(challengerTypes.CannonGameType, game.GameType(), "Honest trace only supported for cannon game types") + f.require.NotNil(f.challengerCfg, "Challenger config is required to create honest trace") + logger := f.t.Logger().New("role", "honestTrace") + prestateBlock := game.StartingL2SequenceNumber() + rollupClient := f.l2CL.Escape().RollupAPI() + prestateProvider := outputs.NewPrestateProvider(rollupClient, prestateBlock) + l1HeadHash := game.L1Head() + l1Head, err := f.ethClient.BlockRefByHash(f.t.Ctx(), l1HeadHash) + f.require.NoError(err, "Failed to fetch L1 Head") + + l2ElClient := f.l2EL.Escape().L2EthClient() + accessor, err := outputs.NewOutputCannonTraceAccessor( + logger, + metrics.NoopMetrics, + f.challengerCfg.Cannon, + vm.NewOpProgramServerExecutor(logger), + ðClientHeaderProvider{client: l2ElClient}, + prestateProvider, + f.challengerCfg.CannonAbsolutePreState, + rollupClient, + f.t.TempDir(), + l1Head.ID(), + game.SplitDepth(), + prestateBlock, + game.L2SequenceNumber(), + ) + f.require.NoError(err, "Failed to create cannon trace accessor") + f.honestTraces[game.Address] = accessor + return accessor +} + +func (f *DisputeGameFactory) startOutputRootGameOfType( + eoa *dsl.EOA, + gameType challengerTypes.GameType, + honestTraceProvider func(game *FaultDisputeGame) challengerTypes.TraceAccessor, + opts ...GameOpt) *FaultDisputeGame { + cfg := NewGameCfg(opts...) + blockNum := cfg.l2SequenceNumber + if !cfg.l2SequenceNumberSet { + blockNum = f.l2CL.SafeL2BlockRef().Number + } + extraData := f.createOutputGameExtraData(blockNum, cfg) + rootClaim := cfg.rootClaim + if !cfg.rootClaimSet { + // Default to correct root claim + response, err := f.l2CL.Escape().RollupAPI().OutputAtBlock(f.t.Ctx(), blockNum) + f.require.NoErrorf(err, "Failed to get output root at block %v", blockNum) + rootClaim = common.Hash(response.OutputRoot) + } + game, addr := f.createNewGame(eoa, gameType, rootClaim, extraData) + return NewFaultDisputeGame(f.t, f.require, addr, f.getGameHelper, honestTraceProvider, game) +} + +func (f *DisputeGameFactory) createOutputGameExtraData(blockNum uint64, cfg *GameCfg) []byte { + f.require.NotNil(f.l2CL, "L2 CL is required create output games") + if !cfg.allowFuture { + f.l2CL.Reached(safetyTypes.LocalSafe, blockNum, 30) + } + extraData := make([]byte, 32) + binary.BigEndian.PutUint64(extraData[24:], blockNum) + return extraData +} + func (f *DisputeGameFactory) createNewGame(eoa *dsl.EOA, gameType challengerTypes.GameType, claim common.Hash, extraData []byte) (*bindings.FaultDisputeGame, common.Address) { f.log.Info("Creating dispute game", "gameType", gameType, "claim", claim.Hex(), "extradata", common.Bytes2Hex(extraData)) @@ -209,3 +317,17 @@ func (a *GameHelperEOA) PerformMoves(game *FaultDisputeGame, moves ...GameHelper func (a *GameHelperEOA) Address() common.Address { return a.EOA.Address() } + +// ethClientHeaderProvider is an adapter for the L1Client interface used in op-node and devstack to +// the HeaderProvider interface used in challenger +type ethClientHeaderProvider struct { + client apis.EthClient +} + +func (p *ethClientHeaderProvider) HeaderByNumber(ctx context.Context, blockNum *big.Int) (*types.Header, error) { + info, err := p.client.InfoByNumber(ctx, blockNum.Uint64()) + if err != nil { + return nil, err + } + return info.Header(), nil +} diff --git a/op-devstack/dsl/proofs/fault_dispute_game.go b/op-devstack/dsl/proofs/fault_dispute_game.go index aa6bc8a15ae..fcf1d589d97 100644 --- a/op-devstack/dsl/proofs/fault_dispute_game.go +++ b/op-devstack/dsl/proofs/fault_dispute_game.go @@ -24,37 +24,57 @@ import ( type gameHelperProvider func(deployer *dsl.EOA) *GameHelper type FaultDisputeGame struct { - t devtest.T - require *require.Assertions - game *bindings.FaultDisputeGame - Address common.Address - helperProvider gameHelperProvider -} - -func NewFaultDisputeGame(t devtest.T, require *require.Assertions, addr common.Address, helperProvider gameHelperProvider, game *bindings.FaultDisputeGame) *FaultDisputeGame { - return &FaultDisputeGame{ + t devtest.T + require *require.Assertions + game *bindings.FaultDisputeGame + Address common.Address + helperProvider gameHelperProvider + honestTraceProvider func() challengerTypes.TraceAccessor +} + +func NewFaultDisputeGame( + t devtest.T, + require *require.Assertions, + addr common.Address, + helperProvider gameHelperProvider, + honestTrace func(game *FaultDisputeGame) challengerTypes.TraceAccessor, + game *bindings.FaultDisputeGame, +) *FaultDisputeGame { + fdg := &FaultDisputeGame{ t: t, require: require, game: game, Address: addr, helperProvider: helperProvider, } + fdg.honestTraceProvider = func() challengerTypes.TraceAccessor { + return honestTrace(fdg) + } + return fdg +} + +func (g *FaultDisputeGame) GameType() challengerTypes.GameType { + return challengerTypes.GameType(contract.Read(g.game.GameType())) } func (g *FaultDisputeGame) MaxDepth() challengerTypes.Depth { return challengerTypes.Depth(contract.Read(g.game.MaxGameDepth()).Uint64()) } -func (g *FaultDisputeGame) SplitDepth() uint64 { - return contract.Read(g.game.SplitDepth()).Uint64() +func (g *FaultDisputeGame) SplitDepth() challengerTypes.Depth { + return challengerTypes.Depth(contract.Read(g.game.SplitDepth()).Uint64()) } func (g *FaultDisputeGame) RootClaim() *Claim { return g.ClaimAtIndex(0) } -func (g *FaultDisputeGame) L2SequenceNumber() *big.Int { - return contract.Read(g.game.L2SequenceNumber()) +func (g *FaultDisputeGame) L2SequenceNumber() uint64 { + return contract.Read(g.game.L2SequenceNumber()).Uint64() +} + +func (g *FaultDisputeGame) StartingL2SequenceNumber() uint64 { + return contract.Read(g.game.StartingBlockNumber()) } func (g *FaultDisputeGame) ClaimAtIndex(claimIndex uint64) *Claim { @@ -62,6 +82,10 @@ func (g *FaultDisputeGame) ClaimAtIndex(claimIndex uint64) *Claim { return g.newClaim(claimIndex, claim) } +func (g *FaultDisputeGame) L1Head() common.Hash { + return contract.Read(g.game.L1Head()) +} + func (g *FaultDisputeGame) Attack(eoa *dsl.EOA, claimIdx uint64, newClaim common.Hash) { claim := g.claimAtIndex(claimIdx) g.t.Logf("Attacking claim %v (depth: %d) with counter-claim %v", claimIdx, claim.Position.Depth(), newClaim) @@ -74,10 +98,31 @@ func (g *FaultDisputeGame) Attack(eoa *dsl.EOA, claimIdx uint64, newClaim common g.t.Require().Equal(receipt.Status, types.ReceiptStatusSuccessful) } +func (g *FaultDisputeGame) Defend(eoa *dsl.EOA, claimIdx uint64, newClaim common.Hash) { + claim := g.claimAtIndex(claimIdx) + g.t.Logf("Defending claim %v (depth: %d) with counter-claim %v", claimIdx, claim.Position.Depth(), newClaim) + g.require.False(claim.IsRootPosition(), "Cannot defend the root claim") + + requiredBond := g.requiredBond(claim.Position.Defend()) + + defendCall := g.game.Defend(claim.Value, new(big.Int).SetUint64(claimIdx), newClaim) + + receipt := contract.Write(eoa, defendCall, txplan.WithValue(requiredBond), txplan.WithGasRatio(2)) + g.t.Require().Equal(receipt.Status, types.ReceiptStatusSuccessful) +} + func (g *FaultDisputeGame) PerformMoves(eoa *dsl.EOA, moves ...GameHelperMove) []*Claim { return g.helperProvider(eoa).PerformMoves(eoa, g, moves) } +func (g *FaultDisputeGame) DisputeL2SequenceNumber(eoa *dsl.EOA, startClaim *Claim, l2SequenceNumber uint64) *Claim { + return g.helperProvider(eoa).DisputeL2SequenceNumber(eoa, g, startClaim, l2SequenceNumber) +} + +func (g *FaultDisputeGame) DisputeToStep(eoa *dsl.EOA, startClaim *Claim, traceIndex uint64) *Claim { + return g.helperProvider(eoa).DisputeToStep(eoa, g, startClaim, traceIndex) +} + func (g *FaultDisputeGame) requiredBond(pos challengerTypes.Position) eth.ETH { return eth.WeiBig(contract.Read(g.game.GetRequiredBond((*bindings.Uint128)(pos.ToGIndex())))) } @@ -131,7 +176,6 @@ func (g *FaultDisputeGame) waitForClaim(timeout time.Duration, errorMsg string, } return false, nil }) - g.require.NoError(err, errorMsg) if err != nil { // Avoid waiting time capturing game data when there's no error g.require.NoErrorf(err, "%v\n%v", errorMsg, g.GameData()) } diff --git a/op-devstack/dsl/proofs/game_helper.go b/op-devstack/dsl/proofs/game_helper.go index a5075303958..76e60dc2408 100644 --- a/op-devstack/dsl/proofs/game_helper.go +++ b/op-devstack/dsl/proofs/game_helper.go @@ -3,6 +3,7 @@ package proofs import ( "bytes" "encoding/json" + "fmt" "math/big" "os" "path/filepath" @@ -32,13 +33,14 @@ type contractArtifactData struct { } type GameHelper struct { - t devtest.T - require *require.Assertions - contractAddr common.Address - abi abi.ABI + t devtest.T + require *require.Assertions + contractAddr common.Address + abi abi.ABI + honestTraceProvider func(game *FaultDisputeGame) challengerTypes.TraceAccessor } -func DeployGameHelper(t devtest.T, deployer *dsl.EOA) *GameHelper { +func DeployGameHelper(t devtest.T, deployer *dsl.EOA, honestTraceProvider func(game *FaultDisputeGame) challengerTypes.TraceAccessor) *GameHelper { req := require.New(t) artifactData := getGameHelperArtifactData(t) @@ -66,10 +68,11 @@ func DeployGameHelper(t devtest.T, deployer *dsl.EOA) *GameHelper { t.Logf("GameHelper contract deployed at: %s", contractAddr.Hex()) return &GameHelper{ - t: t, - require: require.New(t), - contractAddr: contractAddr, - abi: artifactData.ABI, + t: t, + require: require.New(t), + contractAddr: contractAddr, + abi: artifactData.ABI, + honestTraceProvider: honestTraceProvider, } } @@ -124,10 +127,11 @@ func (gs *GameHelper) AuthEOA(eoa *dsl.EOA) *GameHelper { gs.require.NoError(err) gs.require.Equal(types.ReceiptStatusSuccessful, receipt.Status) return &GameHelper{ - t: gs.t, - require: require.New(gs.t), - contractAddr: eoa.Address(), - abi: gs.abi, + t: gs.t, + require: require.New(gs.t), + contractAddr: eoa.Address(), + abi: gs.abi, + honestTraceProvider: gs.honestTraceProvider, } } @@ -161,7 +165,134 @@ func (gs *GameHelper) CreateGameWithClaims( return receipt.ContractAddress } +func (gs *GameHelper) DisputeL2SequenceNumber(eoa *dsl.EOA, game *FaultDisputeGame, startClaim *Claim, l2SequenceNumber uint64) *Claim { + splitDepth := game.SplitDepth() + startingSeqNumber := game.StartingL2SequenceNumber() + gs.require.Greater(l2SequenceNumber, startingSeqNumber, "Cannot dispute things at or prior to the starting block") + seqNumAtPosition := func(pos challengerTypes.Position) uint64 { + return pos.TraceIndex(splitDepth).Uint64() + startingSeqNumber + 1 + } + shouldMoveLeftFrom := func(pos challengerTypes.Position) bool { + // Move left when equal to the sequence number so that we disagree with it + return seqNumAtPosition(pos) >= l2SequenceNumber + } + finalClaim, gameState := gs.disputeTo(eoa, game, startClaim, splitDepth, shouldMoveLeftFrom) + + // Check that we landed in the right place + // We can only land on every second sequence number, starting from startingSeqNumber+1 + // And we want to land on the sequence number that's either equal to or one before l2SequenceNumber + // If it's equal to we would attack, if it's the one before we would defend to ensure the bottom + // half of the game is executing l2SequenceNumber. + finalPosition := seqNumAtPosition(finalClaim.Position()) + if l2SequenceNumber%2 == startingSeqNumber%2 { + gs.require.Equal(l2SequenceNumber-1, finalPosition) + // When defending the required status code depends on whether we provided the next trace or not. + disputedClaim, found := gameState.AncestorWithTraceIndex(finalClaim.asChallengerClaim(), finalClaim.Position().MoveRight().TraceIndex(game.MaxDepth())) + gs.require.True(found, "Did not find ancestor at target trace index") + statusCode := byte(0x00) + if disputedClaim.Position.Depth()%2 == splitDepth%2 { + statusCode = byte(0x01) + } + gs.t.Logf("Defend at split depth with status code %v", statusCode) + finalClaim = finalClaim.Defend(eoa, common.Hash{statusCode, 0xba, 0xd0}) + } else { + gs.t.Log("Attack at split depth") + gs.require.Equal(l2SequenceNumber, finalPosition) + // When attacking, the final block must be invalid so always use 0x01 as status code + finalClaim = finalClaim.Attack(eoa, common.Hash{0x01, 0xba, 0xd0}) + } + return finalClaim +} + +func (gs *GameHelper) DisputeToStep(eoa *dsl.EOA, game *FaultDisputeGame, startClaim *Claim, traceIndex uint64) *Claim { + splitDepth := game.SplitDepth() + maxDepth := game.MaxDepth() + if startClaim.Depth() < splitDepth { + gs.require.Greater(startClaim.Depth(), splitDepth, "Start claim must be past the game split depth") + } + traceIndexAtPosition := func(pos challengerTypes.Position) uint64 { + relativeFinalPosition, err := pos.RelativeToAncestorAtDepth(splitDepth + 1) + gs.require.NoError(err, "Failed to calculate relative position") + return relativeFinalPosition.TraceIndex(maxDepth - splitDepth - 1).Uint64() + } + shouldMoveLeftFrom := func(pos challengerTypes.Position) bool { + // Move left when equal to the trace index so that we disagree with it + return traceIndexAtPosition(pos) >= traceIndex + } + finalClaim, _ := gs.disputeTo(eoa, game, startClaim, maxDepth, shouldMoveLeftFrom) + // Check that we landed in the right place + // We can only land on every second sequence number, starting from startingSeqNumber+1 + // And we want to land on the sequence number that's either equal to or one before l2SequenceNumber + // If it's equal to we would attack, if it's the one before we would defend to ensure the bottom + // half of the game is executing l2SequenceNumber. + finalTraceIndex := traceIndexAtPosition(finalClaim.Position()) + if traceIndex%2 == 1 { + gs.require.Equal(traceIndex-1, finalTraceIndex) + } else { + gs.require.Equal(traceIndex, finalTraceIndex) + } + return finalClaim +} + +func (gs *GameHelper) disputeTo(eoa *dsl.EOA, game *FaultDisputeGame, startClaim *Claim, targetDepth challengerTypes.Depth, shouldMoveLeftFrom func(pos challengerTypes.Position) bool) (*Claim, challengerTypes.Game) { + honestTrace := gs.honestTraceProvider(game) + maxDepth := game.MaxDepth() + parentIdx := int64(startClaim.Index) + moves := make([]GameHelperMove, 0, targetDepth) + currentPos := startClaim.Position() + claims := allChallengerClaims(game) + gameState := challengerTypes.NewGameState(claims, maxDepth) + honestRootClaim, err := honestTrace.Get(gs.t.Ctx(), gameState, claims[0], challengerTypes.RootPosition) + gs.require.NoError(err, "Failed to get honest root claim") + agreeWithRoot := claims[0].Value == honestRootClaim + for currentPos.Depth() < targetDepth { + shouldAttack := shouldMoveLeftFrom(currentPos) + nextPos := currentPos.Defend() + if shouldAttack { + nextPos = currentPos.Attack() + } + claimValue := common.Hash{0xba, 0xd0} + gs.t.Logf("Disputing claim %v at depth %v with claim at depth %v", parentIdx, currentPos.Depth(), nextPos.Depth()) + if !shouldMoveLeftFrom(nextPos) || !gameState.AgreeWithClaimLevel(claims[len(claims)-1], agreeWithRoot) { + // Either we needed the honest actor to move right (defend) after this move or we are the honest actor + // so make sure we use an honest claim value. + value, err := honestTrace.Get(gs.t.Ctx(), gameState, startClaim.asChallengerClaim(), nextPos) + gs.require.NoError(err, "Failed to get trace value at position %v", nextPos) + claimValue = value + } + nextMove := Move(parentIdx, claimValue, shouldAttack) + + moves = append(moves, nextMove) + claims = append(claims, challengerTypes.Claim{ + ClaimData: challengerTypes.ClaimData{ + Value: nextMove.Claim, + Bond: big.NewInt(0), + Position: nextPos, + }, + Claimant: eoa.Address(), + Clock: challengerTypes.Clock{}, + ContractIndex: int(parentIdx + 1), + ParentContractIndex: int(parentIdx), + }) + gameState = challengerTypes.NewGameState(claims, maxDepth) + currentPos = nextPos + parentIdx++ + } + addedClaims := gs.PerformMoves(eoa, game, moves) + return addedClaims[len(addedClaims)-1], gameState +} + +func allChallengerClaims(game *FaultDisputeGame) []challengerTypes.Claim { + claims := game.allClaims() + challengerClaims := make([]challengerTypes.Claim, len(claims)) + for i, claim := range claims { + challengerClaims[i] = game.newClaim(uint64(i), claim).asChallengerClaim() + } + return challengerClaims +} + func (gs *GameHelper) PerformMoves(eoa *dsl.EOA, game *FaultDisputeGame, moves []GameHelperMove) []*Claim { + gs.t.Log("Performing moves: \n" + describeMoves(moves)) data, err := gs.abi.Pack("performMoves", game.Address, moves) gs.require.NoError(err) @@ -196,19 +327,39 @@ func (gs *GameHelper) PerformMoves(eoa *dsl.EOA, game *FaultDisputeGame, moves [ return claims } +func describeMoves(moves []GameHelperMove) string { + description := "" + for _, move := range moves { + moveType := "Defend" + if move.Attack { + moveType = "Attack" + } + description += fmt.Sprintf("%s claim %s, value %s\n", moveType, move.ParentIdx, move.Claim) + } + return description +} + func (gs *GameHelper) totalMoveBonds(game *FaultDisputeGame, moves []GameHelperMove) eth.ETH { claimPositions := map[uint64]challengerTypes.Position{ - 0: challengerTypes.RootPosition, + 0: challengerTypes.RootPosition, // The claim at index 0 is always in the root position } + preExistingClaimCount := game.claimCount() totalBond := eth.Ether(0) for i, move := range moves { parentPos := claimPositions[move.ParentIdx.Uint64()] - gs.require.NotEmpty(parentPos, "Move references non-existent parent - may be out of order") + if parentPos == (challengerTypes.Position{}) { + gs.require.LessOrEqual(move.ParentIdx.Uint64(), preExistingClaimCount, "No parent position found - moves may be out of order") + // Handle cases were there are existing claims and we're adding moves that reference them + gs.t.Logf("Loading parent position for existing claim at index %v", move.ParentIdx) + parentClaim := game.ClaimAtIndex(move.ParentIdx.Uint64()) + parentPos = parentClaim.Position() + claimPositions[move.ParentIdx.Uint64()] = parentPos + } childPos := parentPos.Defend() if move.Attack { childPos = parentPos.Attack() } - claimPositions[uint64(i)+1] = childPos + claimPositions[uint64(i)+preExistingClaimCount] = childPos bond := game.requiredBond(childPos) totalBond = totalBond.Add(bond) } diff --git a/op-devstack/dsl/proofs/super_fault_dispute_game.go b/op-devstack/dsl/proofs/super_fault_dispute_game.go index 7e096bd5c06..a680aabcfa5 100644 --- a/op-devstack/dsl/proofs/super_fault_dispute_game.go +++ b/op-devstack/dsl/proofs/super_fault_dispute_game.go @@ -1,6 +1,8 @@ package proofs import ( + "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" + "github.com/ethereum-optimism/optimism/op-devstack/dsl/contract" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" @@ -13,8 +15,16 @@ type SuperFaultDisputeGame struct { } func NewSuperFaultDisputeGame(t devtest.T, require *require.Assertions, addr common.Address, helperProvider gameHelperProvider, game *bindings.FaultDisputeGame) *SuperFaultDisputeGame { - fdg := NewFaultDisputeGame(t, require, addr, helperProvider, game) + honestTraceProvider := func(_ *FaultDisputeGame) types.TraceAccessor { + require.Fail("Honest trace not supported for super games") + return nil + } + fdg := NewFaultDisputeGame(t, require, addr, helperProvider, honestTraceProvider, game) return &SuperFaultDisputeGame{ FaultDisputeGame: fdg, } } + +func (g *SuperFaultDisputeGame) StartingL2SequenceNumber() uint64 { + return contract.Read(g.game.StartingSequenceNumber()) +} diff --git a/op-devstack/dsl/validators.go b/op-devstack/dsl/validators.go index 94328e43336..5eec1ebb779 100644 --- a/op-devstack/dsl/validators.go +++ b/op-devstack/dsl/validators.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum/params" @@ -22,26 +23,26 @@ func IsForkActivated(c *params.ChainConfig, forkName rollup.ForkName, timestamp } switch forkName { - case rollup.Bedrock: + case forks.Bedrock: // Bedrock is activated based on block number, not timestamp return true, nil // Assuming bedrock is always active in the context of this validator - case rollup.Regolith: + case forks.Regolith: return c.IsOptimismRegolith(timestamp), nil - case rollup.Canyon: + case forks.Canyon: return c.IsOptimismCanyon(timestamp), nil - case rollup.Ecotone: + case forks.Ecotone: return c.IsOptimismEcotone(timestamp), nil - case rollup.Fjord: + case forks.Fjord: return c.IsOptimismFjord(timestamp), nil - case rollup.Granite: + case forks.Granite: return c.IsOptimismGranite(timestamp), nil - case rollup.Holocene: + case forks.Holocene: return c.IsOptimismHolocene(timestamp), nil - case rollup.Isthmus: + case forks.Isthmus: return c.IsOptimismIsthmus(timestamp), nil - case rollup.Jovian: + case forks.Jovian: return c.IsOptimismJovian(timestamp), nil - case rollup.Interop: + case forks.Interop: return c.IsInterop(timestamp), nil default: return false, fmt.Errorf("unknown fork name: %s", forkName) diff --git a/op-devstack/presets/interop.go b/op-devstack/presets/interop.go index 0cfdfd32c45..88200a2413d 100644 --- a/op-devstack/presets/interop.go +++ b/op-devstack/presets/interop.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/dsl/proofs" @@ -14,7 +15,6 @@ import ( "github.com/ethereum-optimism/optimism/op-devstack/stack/match" "github.com/ethereum-optimism/optimism/op-devstack/sysgo" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/intentbuilder" - "github.com/ethereum-optimism/optimism/op-node/rollup" ) type SingleChainInterop struct { @@ -114,7 +114,7 @@ func (s *SimpleInterop) L2Networks() []*dsl.L2Network { } func (s *SimpleInterop) DisputeGameFactory() *proofs.DisputeGameFactory { - return proofs.NewDisputeGameFactory(s.T, s.L1Network, s.L1EL.EthClient(), s.L2ChainA.DisputeGameFactoryProxyAddr(), s.Supervisor) + return proofs.NewDisputeGameFactory(s.T, s.L1Network, s.L1EL.EthClient(), s.L2ChainA.DisputeGameFactoryProxyAddr(), nil, nil, s.Supervisor, nil) } func (s *SingleChainInterop) StandardBridge(l2Chain *dsl.L2Network) *dsl.StandardBridge { @@ -141,7 +141,7 @@ func WithUnscheduledInterop() stack.CommonOption { return stack.Combine( stack.MakeCommon(sysgo.WithDeployerOptions(func(p devtest.P, keys devkeys.Keys, builder intentbuilder.Builder) { for _, l2 := range builder.L2s() { - l2.WithForkAtOffset(rollup.Interop, nil) + l2.WithForkAtOffset(forks.Interop, nil) } })), stack.PostHydrate[stack.Orchestrator](func(sys stack.System) { @@ -175,7 +175,7 @@ func WithSuggestedInteropActivationOffset(offset uint64) stack.CommonOption { return stack.MakeCommon(sysgo.WithDeployerOptions( func(p devtest.P, keys devkeys.Keys, builder intentbuilder.Builder) { for _, l2Cfg := range builder.L2s() { - l2Cfg.WithForkAtOffset(rollup.Interop, &offset) + l2Cfg.WithForkAtOffset(forks.Interop, &offset) } }, )) diff --git a/op-devstack/presets/jovian.go b/op-devstack/presets/jovian.go index b0a96d76320..97c82807ee0 100644 --- a/op-devstack/presets/jovian.go +++ b/op-devstack/presets/jovian.go @@ -2,11 +2,11 @@ package presets import ( "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/stack" "github.com/ethereum-optimism/optimism/op-devstack/sysgo" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/intentbuilder" - "github.com/ethereum-optimism/optimism/op-node/rollup" ) // WithJovianAtGenesis configures all L2s to activate the Jovian fork at genesis in sysgo mode. @@ -14,7 +14,7 @@ func WithJovianAtGenesis() stack.CommonOption { return stack.MakeCommon(sysgo.WithDeployerOptions( func(p devtest.P, _ devkeys.Keys, builder intentbuilder.Builder) { for _, l2Cfg := range builder.L2s() { - l2Cfg.WithForkAtGenesis(rollup.Jovian) + l2Cfg.WithForkAtGenesis(forks.Jovian) } }, )) diff --git a/op-devstack/presets/minimal.go b/op-devstack/presets/minimal.go index d97d3b1c7ab..ac44c35e84d 100644 --- a/op-devstack/presets/minimal.go +++ b/op-devstack/presets/minimal.go @@ -1,8 +1,11 @@ package presets import ( + "time" + "github.com/ethereum/go-ethereum/log" + challengerConfig "github.com/ethereum-optimism/optimism/op-challenger/config" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/dsl/proofs" @@ -16,6 +19,7 @@ type Minimal struct { Log log.Logger T devtest.T ControlPlane stack.ControlPlane + system stack.ExtensibleSystem L1Network *dsl.L1Network L1EL *dsl.L1ELNode @@ -31,6 +35,9 @@ type Minimal struct { FaucetL2 *dsl.Faucet FunderL1 *dsl.Funder FunderL2 *dsl.Funder + + // May be nil if not using sysgo + challengerConfig *challengerConfig.Config } func (m *Minimal) L2Networks() []*dsl.L2Network { @@ -44,7 +51,13 @@ func (m *Minimal) StandardBridge() *dsl.StandardBridge { } func (m *Minimal) DisputeGameFactory() *proofs.DisputeGameFactory { - return proofs.NewDisputeGameFactory(m.T, m.L1Network, m.L1EL.EthClient(), m.L2Chain.DisputeGameFactoryProxyAddr(), nil) + return proofs.NewDisputeGameFactory(m.T, m.L1Network, m.L1EL.EthClient(), m.L2Chain.DisputeGameFactoryProxyAddr(), m.L2CL, m.L2EL, nil, m.challengerConfig) +} + +func (m *Minimal) AdvanceTime(amount time.Duration) { + ttSys, ok := m.system.(stack.TimeTravelSystem) + m.T.Require().True(ok, "attempting to advance time on incompatible system") + ttSys.AdvanceTime(amount) } func WithMinimal() stack.CommonOption { @@ -64,18 +77,25 @@ func minimalFromSystem(t devtest.T, system stack.ExtensibleSystem, orch stack.Or l2 := system.L2Network(match.Assume(t, match.L2ChainA)) sequencerCL := l2.L2CLNode(match.Assume(t, match.WithSequencerActive(t.Ctx()))) sequencerEL := l2.L2ELNode(match.Assume(t, match.EngineFor(sequencerCL))) + var challengerCfg *challengerConfig.Config + if len(l2.L2Challengers()) > 0 { + challengerCfg = l2.L2Challengers()[0].Config() + } + out := &Minimal{ - Log: t.Logger(), - T: t, - ControlPlane: orch.ControlPlane(), - L1Network: dsl.NewL1Network(system.L1Network(match.FirstL1Network)), - L1EL: dsl.NewL1ELNode(l1Net.L1ELNode(match.Assume(t, match.FirstL1EL))), - L2Chain: dsl.NewL2Network(l2, orch.ControlPlane()), - L2Batcher: dsl.NewL2Batcher(l2.L2Batcher(match.Assume(t, match.FirstL2Batcher))), - L2EL: dsl.NewL2ELNode(sequencerEL, orch.ControlPlane()), - L2CL: dsl.NewL2CLNode(sequencerCL, orch.ControlPlane()), - Wallet: dsl.NewRandomHDWallet(t, 30), // Random for test isolation - FaucetL2: dsl.NewFaucet(l2.Faucet(match.Assume(t, match.FirstFaucet))), + Log: t.Logger(), + T: t, + ControlPlane: orch.ControlPlane(), + system: system, + L1Network: dsl.NewL1Network(system.L1Network(match.FirstL1Network)), + L1EL: dsl.NewL1ELNode(l1Net.L1ELNode(match.Assume(t, match.FirstL1EL))), + L2Chain: dsl.NewL2Network(l2, orch.ControlPlane()), + L2Batcher: dsl.NewL2Batcher(l2.L2Batcher(match.Assume(t, match.FirstL2Batcher))), + L2EL: dsl.NewL2ELNode(sequencerEL, orch.ControlPlane()), + L2CL: dsl.NewL2CLNode(sequencerCL, orch.ControlPlane()), + Wallet: dsl.NewRandomHDWallet(t, 30), // Random for test isolation + FaucetL2: dsl.NewFaucet(l2.Faucet(match.Assume(t, match.FirstFaucet))), + challengerConfig: challengerCfg, } out.FaucetL1 = dsl.NewFaucet(out.L1Network.Escape().Faucet(match.Assume(t, match.FirstFaucet))) out.FunderL1 = dsl.NewFunder(out.Wallet, out.FaucetL1, out.L1EL) diff --git a/op-devstack/presets/proof.go b/op-devstack/presets/proof.go index 23202fd1805..fabda7b8a1c 100644 --- a/op-devstack/presets/proof.go +++ b/op-devstack/presets/proof.go @@ -2,11 +2,9 @@ package presets import ( faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" "github.com/ethereum-optimism/optimism/op-devstack/stack" "github.com/ethereum-optimism/optimism/op-devstack/sysgo" ps "github.com/ethereum-optimism/optimism/op-proposer/proposer" - "github.com/ethereum/go-ethereum/common" ) func WithProposerGameType(gameType faultTypes.GameType) stack.CommonOption { @@ -17,34 +15,6 @@ func WithProposerGameType(gameType faultTypes.GameType) stack.CommonOption { }))) } -// TODO(infra#401): Implement support in the sysext toolset -func WithFastGame() stack.CommonOption { - return stack.MakeCommon( - sysgo.WithDeployerOptions( - sysgo.WithAdditionalDisputeGames( - []state.AdditionalDisputeGame{ - { - ChainProofParams: state.ChainProofParams{ - DisputeGameType: uint32(faultTypes.FastGameType), - // Use Alphabet VM prestate which is a pre-determined fixed hash - DisputeAbsolutePrestate: common.HexToHash("0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98"), - DisputeMaxGameDepth: 14 + 3 + 1, - DisputeSplitDepth: 14, - DisputeClockExtension: 0, - DisputeMaxClockDuration: 0, - }, - VMType: state.VMTypeAlphabet, - UseCustomOracle: true, - OracleMinProposalSize: 10000, - OracleChallengePeriodSeconds: 0, - MakeRespected: true, - }, - }, - ), - ), - ) -} - // TODO(infra#401): Implement support in the sysext toolset func WithDeployerMatchL1PAO() stack.CommonOption { return stack.MakeCommon( diff --git a/op-devstack/presets/simple_with_synctester.go b/op-devstack/presets/simple_with_synctester.go index 0afb33bcd30..b8c7950322b 100644 --- a/op-devstack/presets/simple_with_synctester.go +++ b/op-devstack/presets/simple_with_synctester.go @@ -1,13 +1,13 @@ package presets import ( + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" "github.com/ethereum-optimism/optimism/op-devstack/shim" "github.com/ethereum-optimism/optimism/op-devstack/stack" "github.com/ethereum-optimism/optimism/op-devstack/stack/match" "github.com/ethereum-optimism/optimism/op-devstack/sysgo" - "github.com/ethereum-optimism/optimism/op-node/rollup" ) type SimpleWithSyncTester struct { @@ -43,6 +43,6 @@ func NewSimpleWithSyncTester(t devtest.T) *SimpleWithSyncTester { } } -func WithHardforkSequentialActivation(startFork, endFork rollup.ForkName, delta uint64) stack.CommonOption { +func WithHardforkSequentialActivation(startFork, endFork forks.Name, delta uint64) stack.CommonOption { return stack.MakeCommon(sysgo.WithDeployerOptions(sysgo.WithHardforkSequentialActivation(startFork, endFork, &delta))) } diff --git a/op-devstack/shim/l2_challenger.go b/op-devstack/shim/l2_challenger.go index 6eadba5e80a..a5fe76f431a 100644 --- a/op-devstack/shim/l2_challenger.go +++ b/op-devstack/shim/l2_challenger.go @@ -1,15 +1,24 @@ package shim -import "github.com/ethereum-optimism/optimism/op-devstack/stack" +import ( + "github.com/ethereum-optimism/optimism/op-challenger/config" + "github.com/ethereum-optimism/optimism/op-devstack/stack" +) type L2ChallengerConfig struct { CommonConfig - ID stack.L2ChallengerID + ID stack.L2ChallengerID + Config *config.Config } type rpcL2Challenger struct { commonImpl - id stack.L2ChallengerID + id stack.L2ChallengerID + config *config.Config +} + +func (r *rpcL2Challenger) Config() *config.Config { + return r.config } var _ stack.L2Challenger = (*rpcL2Challenger)(nil) @@ -19,6 +28,7 @@ func NewL2Challenger(cfg L2ChallengerConfig) stack.L2Challenger { return &rpcL2Challenger{ commonImpl: newCommon(cfg.CommonConfig), id: cfg.ID, + config: cfg.Config, } } diff --git a/op-devstack/stack/l2_challenger.go b/op-devstack/stack/l2_challenger.go index 81b394add03..c1caded6848 100644 --- a/op-devstack/stack/l2_challenger.go +++ b/op-devstack/stack/l2_challenger.go @@ -3,6 +3,7 @@ package stack import ( "log/slog" + "github.com/ethereum-optimism/optimism/op-challenger/config" "github.com/ethereum-optimism/optimism/op-service/eth" ) @@ -69,4 +70,5 @@ func (id L2ChallengerID) Match(elems []L2Challenger) []L2Challenger { type L2Challenger interface { Common ID() L2ChallengerID + Config() *config.Config } diff --git a/op-devstack/sysgo/deployer.go b/op-devstack/sysgo/deployer.go index edc2fd71083..a16f0e5cadb 100644 --- a/op-devstack/sysgo/deployer.go +++ b/op-devstack/sysgo/deployer.go @@ -13,6 +13,7 @@ import ( "github.com/holiman/uint256" "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/inspect" @@ -291,7 +292,7 @@ func WithDevFeatureEnabled(flag common.Hash) DeployerOption { func WithInteropAtGenesis() DeployerOption { return func(p devtest.P, keys devkeys.Keys, builder intentbuilder.Builder) { for _, l2Cfg := range builder.L2s() { - l2Cfg.WithForkAtGenesis(rollup.Interop) + l2Cfg.WithForkAtGenesis(forks.Interop) } } } @@ -300,13 +301,13 @@ func WithInteropAtGenesis() DeployerOption { // activate hardforks sequentially, starting from startFork and continuing // until (but not including) endFork. Each successive fork is scheduled at // an increasing offset. -func WithHardforkSequentialActivation(startFork, endFork rollup.ForkName, delta *uint64) DeployerOption { +func WithHardforkSequentialActivation(startFork, endFork forks.Name, delta *uint64) DeployerOption { return func(p devtest.P, keys devkeys.Keys, builder intentbuilder.Builder) { for _, l2Cfg := range builder.L2s() { l2Cfg.WithForkAtGenesis(startFork) activateWithOffset := false deactivate := false - for idx, refFork := range rollup.AllForks { + for idx, refFork := range forks.All { if deactivate || refFork == endFork { l2Cfg.WithForkAtOffset(refFork, nil) deactivate = true diff --git a/op-devstack/sysgo/l2_challenger.go b/op-devstack/sysgo/l2_challenger.go index 4a56e1fc194..ae5735644bd 100644 --- a/op-devstack/sysgo/l2_challenger.go +++ b/op-devstack/sysgo/l2_challenger.go @@ -21,12 +21,14 @@ type L2Challenger struct { id stack.L2ChallengerID service cliapp.Lifecycle l2NetIDs []stack.L2NetworkID + config *config.Config } func (p *L2Challenger) hydrate(system stack.ExtensibleSystem) { bFrontend := shim.NewL2Challenger(shim.L2ChallengerConfig{ CommonConfig: shim.NewCommonConfig(system.T()), ID: p.id, + Config: p.config, }) for _, netID := range p.l2NetIDs { @@ -176,6 +178,7 @@ func WithL2ChallengerPostDeploy(orch *Orchestrator, challengerID stack.L2Challen id: challengerID, service: svc, l2NetIDs: l2NetIDs, + config: cfg, } orch.challengers.Set(challengerID, c) } diff --git a/op-devstack/sysgo/l2_cl_p2p_util.go b/op-devstack/sysgo/l2_cl_p2p_util.go index 911434cd28e..4ea3e8df0ce 100644 --- a/op-devstack/sysgo/l2_cl_p2p_util.go +++ b/op-devstack/sysgo/l2_cl_p2p_util.go @@ -75,6 +75,7 @@ func getP2PClientsAndPeers(ctx context.Context, logger log.Logger, func WithL2CLP2PConnection(l2CL1ID, l2CL2ID stack.L2CLNodeID) stack.Option[*Orchestrator] { return stack.AfterDeploy(func(orch *Orchestrator) { require := orch.P().Require() + l := orch.P().Logger() l2CL1, ok := orch.l2CLs.Get(l2CL1ID) require.True(ok, "looking for L2 CL node 1 to connect p2p") @@ -87,15 +88,18 @@ func WithL2CLP2PConnection(l2CL1ID, l2CL2ID stack.L2CLNodeID) stack.Option[*Orch p := getP2PClientsAndPeers(ctx, logger, require, l2CL1, l2CL2) - connectPeer := func(p2pClient *sources.P2PClient, multiAddress string) { + connectPeer := func(l2CL L2CLNode, p2pClient *sources.P2PClient, multiAddress string) { err := retry.Do0(ctx, 6, retry.Exponential(), func() error { return p2pClient.ConnectPeer(ctx, multiAddress) }) - require.NoError(err, "failed to connect peer") + if err != nil { + l.Error("failed to connect L2CL peer", "l2CL", l2CL, "rpc", l2CL.UserRPC(), "multiAddress", multiAddress, "error", err) + } + require.NoError(err, "failed to connect L2CL peer") } - connectPeer(p.client1, p.peerInfo2.Addresses[0]) - connectPeer(p.client2, p.peerInfo1.Addresses[0]) + connectPeer(l2CL1, p.client1, p.peerInfo2.Addresses[0]) + connectPeer(l2CL2, p.client2, p.peerInfo1.Addresses[0]) check := func(peerDump *apis.PeerDump, peerInfo *apis.PeerInfo) { multiAddress := peerInfo.PeerID.String() diff --git a/op-e2e/actions/derivation/blocktime_test.go b/op-e2e/actions/derivation/blocktime_test.go index bd5594864af..3f79652d658 100644 --- a/op-e2e/actions/derivation/blocktime_test.go +++ b/op-e2e/actions/derivation/blocktime_test.go @@ -4,10 +4,10 @@ import ( "math/big" "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" upgradesHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/upgrades/helpers" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" @@ -165,9 +165,9 @@ func LargeL1Gaps(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { dp.DeployConfig.SequencerWindowSize = 4 dp.DeployConfig.MaxSequencerDrift = 32 if deltaTimeOffset != nil { - dp.DeployConfig.ActivateForkAtOffset(rollup.Delta, uint64(*deltaTimeOffset)) + dp.DeployConfig.ActivateForkAtOffset(forks.Delta, uint64(*deltaTimeOffset)) } else { - dp.DeployConfig.ActivateForkAtGenesis(rollup.Canyon) + dp.DeployConfig.ActivateForkAtGenesis(forks.Canyon) } // TODO(client-pod#831): The Ecotone (and Fjord) activation blocks don't include user txs, // so disabling these forks for now. diff --git a/op-e2e/actions/helpers/env.go b/op-e2e/actions/helpers/env.go index 7aca1228a1d..ded94f31252 100644 --- a/op-e2e/actions/helpers/env.go +++ b/op-e2e/actions/helpers/env.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/forks" e2ecfg "github.com/ethereum-optimism/optimism/op-e2e/config" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-node/rollup" @@ -52,7 +53,7 @@ func WithActiveGenesisFork(fork rollup.ForkName) EnvOpt { // DefaultFork specifies the default fork to use when setting up the action test environment. // Currently manually set to Holocene. // Replace with `var DefaultFork = func() rollup.ForkName { return rollup.AllForks[len(rollup.AllForks)-1] }()` after Interop launch. -const DefaultFork = rollup.Holocene +const DefaultFork = forks.Holocene // SetupEnv sets up a default action test environment. If no fork is specified, the default fork as // specified by the package variable [defaultFork] is used. diff --git a/op-e2e/actions/helpers/l2_sequencer.go b/op-e2e/actions/helpers/l2_sequencer.go index 65c5933dddb..97d8100b1a5 100644 --- a/op-e2e/actions/helpers/l2_sequencer.go +++ b/op-e2e/actions/helpers/l2_sequencer.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/config" "github.com/ethereum-optimism/optimism/op-node/metrics" "github.com/ethereum-optimism/optimism/op-node/node/safedb" @@ -212,7 +213,7 @@ func (s *L2Sequencer) ActBuildL2ToTime(t Testing, target uint64) { } } -func (s *L2Sequencer) ActBuildL2ToFork(t Testing, fork rollup.ForkName) eth.L2BlockRef { +func (s *L2Sequencer) ActBuildL2ToFork(t Testing, fork forks.Name) eth.L2BlockRef { require.NotNil(t, s.RollupCfg.ActivationTime(fork), "cannot activate %s when it is not scheduled", fork) for !s.RollupCfg.IsForkActive(fork, s.L2Unsafe().Time) { s.ActL2EmptyBlock(t) diff --git a/op-e2e/actions/helpers/l2_verifier.go b/op-e2e/actions/helpers/l2_verifier.go index b0b5f102650..c99e95e288b 100644 --- a/op-e2e/actions/helpers/l2_verifier.go +++ b/op-e2e/actions/helpers/l2_verifier.go @@ -155,9 +155,9 @@ func NewL2Verifier(t Testing, log log.Logger, l1 derive.L1Fetcher, var finalizer driver.Finalizer if cfg.AltDAEnabled() { - finalizer = finality.NewAltDAFinalizer(ctx, log, cfg, l1, altDASrc, ec) + finalizer = finality.NewAltDAFinalizer(ctx, log, cfg, nil, l1, altDASrc, ec) } else { - finalizer = finality.NewFinalizer(ctx, log, cfg, l1, ec) + finalizer = finality.NewFinalizer(ctx, log, cfg, nil, l1, ec) } sys.Register("finalizer", finalizer, opts) diff --git a/op-e2e/actions/helpers/user.go b/op-e2e/actions/helpers/user.go index 9cd00d83f8f..a863bd07be3 100644 --- a/op-e2e/actions/helpers/user.go +++ b/op-e2e/actions/helpers/user.go @@ -24,6 +24,7 @@ import ( "github.com/stretchr/testify/require" "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" + "github.com/ethereum-optimism/optimism/op-core/predeploys" legacybindings "github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/config" e2ehelpers "github.com/ethereum-optimism/optimism/op-e2e/system/helpers" @@ -31,7 +32,6 @@ import ( bindingspreview "github.com/ethereum-optimism/optimism/op-node/bindings/preview" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/withdrawals" - "github.com/ethereum-optimism/optimism/op-service/predeploys" ) type L1Bindings struct { diff --git a/op-e2e/actions/interop/dsl/inbox.go b/op-e2e/actions/interop/dsl/inbox.go index d89574e5d0a..bbd54a08fcc 100644 --- a/op-e2e/actions/interop/dsl/inbox.go +++ b/op-e2e/actions/interop/dsl/inbox.go @@ -8,10 +8,10 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/contracts/bindings/inbox" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" stypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) diff --git a/op-e2e/actions/interop/dsl/message.go b/op-e2e/actions/interop/dsl/message.go index 667376b9406..144e57e446f 100644 --- a/op-e2e/actions/interop/dsl/message.go +++ b/op-e2e/actions/interop/dsl/message.go @@ -1,9 +1,9 @@ package dsl import ( + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/contracts/bindings/inbox" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/require" ) diff --git a/op-e2e/actions/interop/emitter_contract_test.go b/op-e2e/actions/interop/emitter_contract_test.go index 5b827e93265..c1d98c74961 100644 --- a/op-e2e/actions/interop/emitter_contract_test.go +++ b/op-e2e/actions/interop/emitter_contract_test.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/interop/dsl" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/contracts/bindings/emit" @@ -22,7 +23,6 @@ import ( "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/event" - "github.com/ethereum-optimism/optimism/op-service/predeploys" stypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) diff --git a/op-e2e/actions/interop/interop_fork_test.go b/op-e2e/actions/interop/interop_fork_test.go index ca15daa3b80..e2cf0fd513e 100644 --- a/op-e2e/actions/interop/interop_fork_test.go +++ b/op-e2e/actions/interop/interop_fork_test.go @@ -4,12 +4,12 @@ import ( "math/big" "testing" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" actionhelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/interop/dsl" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" diff --git a/op-e2e/actions/proofs/activation_block_test.go b/op-e2e/actions/proofs/activation_block_test.go index 2926aae6ff9..5aaabb3e125 100644 --- a/op-e2e/actions/proofs/activation_block_test.go +++ b/op-e2e/actions/proofs/activation_block_test.go @@ -4,9 +4,9 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/forks" actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/stretchr/testify/require" @@ -16,7 +16,7 @@ import ( ) type activationBlockTestCfg struct { - fork rollup.ForkName + fork forks.Name numUpgradeTxs int } @@ -26,8 +26,8 @@ func TestActivationBlockTxOmission(gt *testing.T) { matrix := helpers.NewMatrix[activationBlockTestCfg]() matrix.AddDefaultTestCasesWithName( - string(rollup.Jovian), - activationBlockTestCfg{fork: rollup.Jovian, numUpgradeTxs: 5}, + string(forks.Jovian), + activationBlockTestCfg{fork: forks.Jovian, numUpgradeTxs: 5}, helpers.NewForkMatrix(helpers.Isthmus), testActivationBlockTxOmission, ) diff --git a/op-e2e/actions/proofs/helpers/env.go b/op-e2e/actions/proofs/helpers/env.go index 6ac2fc39185..6872c1d0e1e 100644 --- a/op-e2e/actions/proofs/helpers/env.go +++ b/op-e2e/actions/proofs/helpers/env.go @@ -4,6 +4,7 @@ import ( "math/rand" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/forks" e2ecfg "github.com/ethereum-optimism/optimism/op-e2e/config" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-program/client/boot" @@ -48,7 +49,7 @@ func NewL2FaultProofEnv[c any](t helpers.Testing, testCfg *TestCfg[c], tp *e2eut if testCfg.Hardfork == nil { t.Fatalf("HF not set") } - dp.DeployConfig.ActivateForkAtGenesis(rollup.ForkName(testCfg.Hardfork.Name)) + dp.DeployConfig.ActivateForkAtGenesis(forks.Name(testCfg.Hardfork.Name)) for _, override := range deployConfigOverrides { override(dp.DeployConfig) diff --git a/op-e2e/actions/proofs/helpers/matrix.go b/op-e2e/actions/proofs/helpers/matrix.go index 025d8a96c45..b8bf9c6e1f9 100644 --- a/op-e2e/actions/proofs/helpers/matrix.go +++ b/op-e2e/actions/proofs/helpers/matrix.go @@ -4,8 +4,8 @@ import ( "fmt" "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-program/client/claim" "github.com/ethereum/go-ethereum/common" ) @@ -117,15 +117,15 @@ type ForkMatrix = []*Hardfork // Hardfork definitions var ( - Regolith = &Hardfork{Name: string(rollup.Regolith), Precedence: 1} - Canyon = &Hardfork{Name: string(rollup.Canyon), Precedence: 2} - Delta = &Hardfork{Name: string(rollup.Delta), Precedence: 3} - Ecotone = &Hardfork{Name: string(rollup.Ecotone), Precedence: 4} - Fjord = &Hardfork{Name: string(rollup.Fjord), Precedence: 5} - Granite = &Hardfork{Name: string(rollup.Granite), Precedence: 6} - Holocene = &Hardfork{Name: string(rollup.Holocene), Precedence: 7} - Isthmus = &Hardfork{Name: string(rollup.Isthmus), Precedence: 8} - Jovian = &Hardfork{Name: string(rollup.Jovian), Precedence: 9} + Regolith = &Hardfork{Name: string(forks.Regolith), Precedence: 1} + Canyon = &Hardfork{Name: string(forks.Canyon), Precedence: 2} + Delta = &Hardfork{Name: string(forks.Delta), Precedence: 3} + Ecotone = &Hardfork{Name: string(forks.Ecotone), Precedence: 4} + Fjord = &Hardfork{Name: string(forks.Fjord), Precedence: 5} + Granite = &Hardfork{Name: string(forks.Granite), Precedence: 6} + Holocene = &Hardfork{Name: string(forks.Holocene), Precedence: 7} + Isthmus = &Hardfork{Name: string(forks.Isthmus), Precedence: 8} + Jovian = &Hardfork{Name: string(forks.Jovian), Precedence: 9} ) var ( diff --git a/op-e2e/actions/proofs/isthmus_fork_test.go b/op-e2e/actions/proofs/isthmus_fork_test.go index f6e426d7f8b..7688989edb0 100644 --- a/op-e2e/actions/proofs/isthmus_fork_test.go +++ b/op-e2e/actions/proofs/isthmus_fork_test.go @@ -12,11 +12,11 @@ import ( "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/accounts/abi/bind" diff --git a/op-e2e/actions/proofs/jovian_dafootprint_test.go b/op-e2e/actions/proofs/jovian_dafootprint_test.go index b8ba00388a8..0171167a269 100644 --- a/op-e2e/actions/proofs/jovian_dafootprint_test.go +++ b/op-e2e/actions/proofs/jovian_dafootprint_test.go @@ -6,12 +6,12 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/forks" + "github.com/ethereum-optimism/optimism/op-core/predeploys" actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" "github.com/ethereum-optimism/optimism/op-e2e/bindings" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -190,7 +190,7 @@ func Test_ProgramAction_JovianDAFootprint(gt *testing.T) { jovianAtGenesis := env.Sequencer.RollupCfg.IsJovian(env.Sequencer.RollupCfg.Genesis.L2Time) if !jovianAtGenesis { - env.Sequencer.ActBuildL2ToFork(t, rollup.Jovian) + env.Sequencer.ActBuildL2ToFork(t, forks.Jovian) } // We run three sub-steps. First, we test the default behavior. Then we update the scalar to @@ -213,10 +213,10 @@ func Test_ProgramAction_JovianDAFootprint(gt *testing.T) { genesisConfigFn helpers.DeployConfigOverride }{ "JovianAtGenesis": { - genesisConfigFn: func(dc *genesis.DeployConfig) { dc.ActivateForkAtGenesis(rollup.Jovian) }, + genesisConfigFn: func(dc *genesis.DeployConfig) { dc.ActivateForkAtGenesis(forks.Jovian) }, }, "JovianAfterGenesis": { - genesisConfigFn: func(dc *genesis.DeployConfig) { dc.ActivateForkAtOffset(rollup.Jovian, 4) }, + genesisConfigFn: func(dc *genesis.DeployConfig) { dc.ActivateForkAtOffset(forks.Jovian, 4) }, }, } diff --git a/op-e2e/actions/proofs/jovian_minbasefee_test.go b/op-e2e/actions/proofs/jovian_minbasefee_test.go index 967a54de8af..b7e5c7c5a77 100644 --- a/op-e2e/actions/proofs/jovian_minbasefee_test.go +++ b/op-e2e/actions/proofs/jovian_minbasefee_test.go @@ -5,11 +5,11 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/forks" + "github.com/ethereum-optimism/optimism/op-core/predeploys" actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" "github.com/ethereum-optimism/optimism/op-e2e/bindings" - "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" @@ -118,25 +118,25 @@ func Test_ProgramAction_JovianMinBaseFee(gt *testing.T) { }{ "JovianActivationAfterGenesis": { genesisConfigFn: func(dc *genesis.DeployConfig) { - dc.ActivateForkAtOffset(rollup.Jovian, 10) + dc.ActivateForkAtOffset(forks.Jovian, 10) }, minBaseFee: 0, }, "JovianActivationAtGenesisZeroMinBaseFee": { genesisConfigFn: func(dc *genesis.DeployConfig) { - dc.ActivateForkAtGenesis(rollup.Jovian) + dc.ActivateForkAtGenesis(forks.Jovian) }, minBaseFee: 0, }, "JovianActivationAtGenesisMinBaseFeeMedium": { genesisConfigFn: func(dc *genesis.DeployConfig) { - dc.ActivateForkAtGenesis(rollup.Jovian) + dc.ActivateForkAtGenesis(forks.Jovian) }, minBaseFee: 1_000_000_000, // 1 gwei }, "JovianActivationAtGenesisMinBaseFeeHigh": { genesisConfigFn: func(dc *genesis.DeployConfig) { - dc.ActivateForkAtGenesis(rollup.Jovian) + dc.ActivateForkAtGenesis(forks.Jovian) }, minBaseFee: 2_000_000_000, // 2 gwei }, diff --git a/op-e2e/actions/proofs/l1_blob_parameter_forks_test.go b/op-e2e/actions/proofs/l1_blob_parameter_forks_test.go index a1b4685c2ee..db3315fd097 100644 --- a/op-e2e/actions/proofs/l1_blob_parameter_forks_test.go +++ b/op-e2e/actions/proofs/l1_blob_parameter_forks_test.go @@ -6,11 +6,11 @@ import ( batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/predeploys" actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" legacybindings "github.com/ethereum-optimism/optimism/op-e2e/bindings" "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/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" diff --git a/op-e2e/actions/proofs/operator_fee_fix_transition_test.go b/op-e2e/actions/proofs/operator_fee_fix_transition_test.go index 24b2afba04d..7652428c3f9 100644 --- a/op-e2e/actions/proofs/operator_fee_fix_transition_test.go +++ b/op-e2e/actions/proofs/operator_fee_fix_transition_test.go @@ -5,12 +5,12 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/forks" + "github.com/ethereum-optimism/optimism/op-core/predeploys" actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" "github.com/ethereum-optimism/optimism/op-e2e/bindings" - "github.com/ethereum-optimism/optimism/op-node/rollup" "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/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -28,7 +28,7 @@ func Test_ProgramAction_OperatorFeeFixTransition(gt *testing.T) { t := actionsHelpers.NewDefaultTesting(gt) deployConfigOverrides := func(dp *genesis.DeployConfig) { - dp.ActivateForkAtOffset(rollup.Jovian, 15) + dp.ActivateForkAtOffset(forks.Jovian, 15) } testOperatorFeeScalar := uint32(345e6) @@ -140,7 +140,7 @@ func Test_ProgramAction_OperatorFeeFixTransition(gt *testing.T) { require.True(t, aliceFinalBalance.Cmp(aliceInitialBalance) < 0, "Alice's balance should decrease") // Now wind forward to jovian - unsafeL2Head = env.Sequencer.ActBuildL2ToFork(t, rollup.Jovian) + unsafeL2Head = env.Sequencer.ActBuildL2ToFork(t, forks.Jovian) // reset accounting aliceInitialBalance, _, _, _, operatorFeeVaultInitialBalance = getCurrentBalances(unsafeL2Head.Number) diff --git a/op-e2e/actions/proofs/operator_fee_test.go b/op-e2e/actions/proofs/operator_fee_test.go index b024be821a9..6b431b2a0ec 100644 --- a/op-e2e/actions/proofs/operator_fee_test.go +++ b/op-e2e/actions/proofs/operator_fee_test.go @@ -5,12 +5,12 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/predeploys" actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" "github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" diff --git a/op-e2e/actions/proofs/pectra_blob_schedule_test.go b/op-e2e/actions/proofs/pectra_blob_schedule_test.go index 71b9bba7b10..6511fcd3e72 100644 --- a/op-e2e/actions/proofs/pectra_blob_schedule_test.go +++ b/op-e2e/actions/proofs/pectra_blob_schedule_test.go @@ -4,11 +4,11 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/predeploys" actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" legacybindings "github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/stretchr/testify/require" "github.com/ethereum/go-ethereum/accounts/abi/bind" diff --git a/op-e2e/actions/proofs/system_config_test.go b/op-e2e/actions/proofs/system_config_test.go index a9e9ed33609..f24578c0bfb 100644 --- a/op-e2e/actions/proofs/system_config_test.go +++ b/op-e2e/actions/proofs/system_config_test.go @@ -8,10 +8,10 @@ import ( "github.com/stretchr/testify/require" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/forks" actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" "github.com/ethereum-optimism/optimism/op-e2e/bindings" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/eth" ) @@ -36,7 +36,7 @@ func testSystemConfigEarlyIsthmusUpgrade(gt *testing.T, testCfg *helpers.TestCfg t := actionsHelpers.NewDefaultTesting(gt) testSetup := func(dp *genesis.DeployConfig) { - dp.ActivateForkAtOffset(rollup.Isthmus, isthmusOffset) + dp.ActivateForkAtOffset(forks.Isthmus, isthmusOffset) } env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(), helpers.NewBatcherCfg(), testSetup) sequencer := env.Sequencer diff --git a/op-e2e/actions/upgrades/dencun_fork_test.go b/op-e2e/actions/upgrades/dencun_fork_test.go index 13c88fefc77..7c6a489dde6 100644 --- a/op-e2e/actions/upgrades/dencun_fork_test.go +++ b/op-e2e/actions/upgrades/dencun_fork_test.go @@ -4,18 +4,17 @@ import ( "context" "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" - "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" + transactions "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/log" "github.com/stretchr/testify/require" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - - "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" - "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions" - "github.com/ethereum-optimism/optimism/op-service/testlog" ) func TestDencunL1ForkAfterGenesis(gt *testing.T) { @@ -125,7 +124,7 @@ func TestDencunL2ForkAfterGenesis(gt *testing.T) { dp := e2eutils.MakeDeployParams(t, helpers.DefaultRollupTestParams()) require.Zero(t, *dp.DeployConfig.L1CancunTimeOffset) // This test will fork on the second block - dp.DeployConfig.ActivateForkAtOffset(rollup.Ecotone, dp.DeployConfig.L2BlockTime*2) + dp.DeployConfig.ActivateForkAtOffset(forks.Ecotone, dp.DeployConfig.L2BlockTime*2) sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) diff --git a/op-e2e/actions/upgrades/ecotone_fork_test.go b/op-e2e/actions/upgrades/ecotone_fork_test.go index 09aa995fc36..cb267dc4699 100644 --- a/op-e2e/actions/upgrades/ecotone_fork_test.go +++ b/op-e2e/actions/upgrades/ecotone_fork_test.go @@ -5,6 +5,7 @@ import ( "math/big" "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/stretchr/testify/require" @@ -16,11 +17,10 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/testlog" ) @@ -50,7 +50,7 @@ func TestEcotoneNetworkUpgradeTransactions(gt *testing.T) { require.Zero(t, *dp.DeployConfig.L1CancunTimeOffset) // Activate all forks at genesis, and schedule Ecotone the block after - dp.DeployConfig.ActivateForkAtOffset(rollup.Ecotone, uint64(ecotoneOffset)) + dp.DeployConfig.ActivateForkAtOffset(forks.Ecotone, uint64(ecotoneOffset)) require.NoError(t, dp.DeployConfig.Check(log), "must have valid config") sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc) diff --git a/op-e2e/actions/upgrades/fjord_fork_test.go b/op-e2e/actions/upgrades/fjord_fork_test.go index 24839388f1c..2880dfb006b 100644 --- a/op-e2e/actions/upgrades/fjord_fork_test.go +++ b/op-e2e/actions/upgrades/fjord_fork_test.go @@ -6,8 +6,8 @@ import ( "math/big" "testing" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -16,9 +16,9 @@ import ( "github.com/stretchr/testify/require" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/testlog" ) @@ -37,7 +37,7 @@ func TestFjordNetworkUpgradeTransactions(gt *testing.T) { // Activate all forks at genesis, and schedule Fjord the block after fjordOffset := uint64(2) - dp.DeployConfig.ActivateForkAtOffset(rollup.Fjord, fjordOffset) + dp.DeployConfig.ActivateForkAtOffset(forks.Fjord, fjordOffset) require.NoError(t, dp.DeployConfig.Check(log), "must have valid config") diff --git a/op-e2e/actions/upgrades/holocene_fork_test.go b/op-e2e/actions/upgrades/holocene_fork_test.go index f2fca1d19b4..f7073415dcc 100644 --- a/op-e2e/actions/upgrades/holocene_fork_test.go +++ b/op-e2e/actions/upgrades/holocene_fork_test.go @@ -9,15 +9,15 @@ import ( "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" "github.com/ethereum-optimism/optimism/op-e2e/system/e2esys" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/testlog" ) func TestHoloceneActivationAtGenesis(gt *testing.T) { t := helpers.NewDefaultTesting(gt) - env := helpers.SetupEnv(t, helpers.WithActiveGenesisFork(rollup.Holocene)) + env := helpers.SetupEnv(t, helpers.WithActiveGenesisFork(forks.Holocene)) // Start op-nodes env.Seq.ActL2PipelineFull(t) @@ -53,7 +53,7 @@ func TestHoloceneActivationAtGenesis(gt *testing.T) { func TestHoloceneLateActivationAndReset(gt *testing.T) { t := helpers.NewDefaultTesting(gt) holoceneOffset := uint64(24) - env := helpers.SetupEnv(t, helpers.WithActiveFork(rollup.Holocene, holoceneOffset)) + env := helpers.SetupEnv(t, helpers.WithActiveFork(forks.Holocene, holoceneOffset)) requireHoloceneTransformationLogs := func(role string, expNumLogs int) { recs := env.Logs.FindLogs(testlog.NewMessageContainsFilter("transforming to Holocene"), testlog.NewAttributesFilter("role", role)) @@ -135,7 +135,7 @@ func TestHoloceneLateActivationAndReset(gt *testing.T) { func TestHoloceneInvalidPayload(gt *testing.T) { t := helpers.NewDefaultTesting(gt) - env := helpers.SetupEnv(t, helpers.WithActiveGenesisFork(rollup.Holocene)) + env := helpers.SetupEnv(t, helpers.WithActiveGenesisFork(forks.Holocene)) ctx := context.Background() requireDepositOnlyLogs := func(role string, expNumLogs int) { diff --git a/op-e2e/config/init.go b/op-e2e/config/init.go index ded06e2496d..d06a243a4c0 100644 --- a/op-e2e/config/init.go +++ b/op-e2e/config/init.go @@ -13,13 +13,13 @@ import ( "time" "github.com/ethereum-optimism/optimism/cannon/mipsevm/versions" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/inspect" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "golang.org/x/exp/maps" @@ -257,7 +257,7 @@ func initAllocType(root string, allocType AllocType) { } upgradeSchedule := new(genesis.UpgradeScheduleDeployConfig) - upgradeSchedule.ActivateForkAtGenesis(rollup.ForkName(mode)) + upgradeSchedule.ActivateForkAtGenesis(forks.Name(mode)) upgradeOverridesJSON, err := json.Marshal(upgradeSchedule) if err != nil { panic(fmt.Errorf("failed to marshal upgrade schedule: %w", err)) diff --git a/op-e2e/e2eutils/addresses.go b/op-e2e/e2eutils/addresses.go index 46e639425a2..6e5bc5d419c 100644 --- a/op-e2e/e2eutils/addresses.go +++ b/op-e2e/e2eutils/addresses.go @@ -8,7 +8,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" - "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum-optimism/optimism/op-core/predeploys" ) func collectAllocAddrs(alloc types.GenesisAlloc) []common.Address { diff --git a/op-e2e/e2eutils/intentbuilder/builder.go b/op-e2e/e2eutils/intentbuilder/builder.go index bf55dcc98cd..c28dd86ffe7 100644 --- a/op-e2e/e2eutils/intentbuilder/builder.go +++ b/op-e2e/e2eutils/intentbuilder/builder.go @@ -14,10 +14,10 @@ import ( "github.com/ethereum-optimism/optimism/op-chain-ops/addresses" "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" ) @@ -93,8 +93,8 @@ type L2FeesConfigurator interface { } type L2HardforkConfigurator interface { - WithForkAtGenesis(fork rollup.ForkName) - WithForkAtOffset(fork rollup.ForkName, offset *uint64) + WithForkAtGenesis(fork forks.Name) + WithForkAtOffset(fork forks.Name, offset *uint64) } type Builder interface { @@ -438,10 +438,10 @@ func (c *l2Configurator) WithOperatorFeeConstant(value uint64) { c.builder.intent.Chains[c.chainIndex].OperatorFeeConstant = value } -func (c *l2Configurator) WithForkAtGenesis(fork rollup.ForkName) { +func (c *l2Configurator) WithForkAtGenesis(fork forks.Name) { var future bool - for _, refFork := range rollup.AllForks { - if refFork == rollup.Bedrock { + for _, refFork := range forks.All { + if refFork == forks.Bedrock { continue } @@ -457,8 +457,8 @@ func (c *l2Configurator) WithForkAtGenesis(fork rollup.ForkName) { } } -func (c *l2Configurator) WithForkAtOffset(fork rollup.ForkName, offset *uint64) { - require.True(c.t, rollup.IsValidFork(fork)) +func (c *l2Configurator) WithForkAtOffset(fork forks.Name, offset *uint64) { + require.True(c.t, forks.IsValid(fork)) key := fmt.Sprintf("l2Genesis%sTimeOffset", cases.Title(language.English).String(string(fork))) if offset == nil { diff --git a/op-e2e/e2eutils/intentbuilder/builder_test.go b/op-e2e/e2eutils/intentbuilder/builder_test.go index d32e4c9feeb..f959b5de150 100644 --- a/op-e2e/e2eutils/intentbuilder/builder_test.go +++ b/op-e2e/e2eutils/intentbuilder/builder_test.go @@ -12,10 +12,10 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum-optimism/optimism/op-chain-ops/addresses" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" ) @@ -119,8 +119,8 @@ func TestBuilder(t *testing.T) { // Test L2HardforkConfigurator methods isthmusOffset := uint64(8000) - l2Config.WithForkAtGenesis(rollup.Holocene) - l2Config.WithForkAtOffset(rollup.Isthmus, &isthmusOffset) + l2Config.WithForkAtGenesis(forks.Holocene) + l2Config.WithForkAtOffset(forks.Isthmus, &isthmusOffset) // Build the intent intent, err := builder.Build() diff --git a/op-e2e/e2eutils/setup_test.go b/op-e2e/e2eutils/setup_test.go index 9baf0be78c7..8eb2ed1b560 100644 --- a/op-e2e/e2eutils/setup_test.go +++ b/op-e2e/e2eutils/setup_test.go @@ -7,8 +7,8 @@ import ( "github.com/stretchr/testify/require" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-e2e/config" - "github.com/ethereum-optimism/optimism/op-service/predeploys" ) func TestWriteDefaultJWT(t *testing.T) { diff --git a/op-e2e/faultproofs/cannon_benchmark_test.go b/op-e2e/faultproofs/cannon_benchmark_test.go index 2d4b52e38a3..b26aef1ae28 100644 --- a/op-e2e/faultproofs/cannon_benchmark_test.go +++ b/op-e2e/faultproofs/cannon_benchmark_test.go @@ -26,9 +26,9 @@ import ( "github.com/ethereum-optimism/optimism/cannon/mipsevm" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "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" "github.com/ethereum-optimism/optimism/op-service/testlog" ) diff --git a/op-e2e/interop/supersystem.go b/op-e2e/interop/supersystem.go index 1c5ac711243..7d134fb13b0 100644 --- a/op-e2e/interop/supersystem.go +++ b/op-e2e/interop/supersystem.go @@ -29,6 +29,7 @@ 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" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/blobstore" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/contracts/bindings/emit" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/contracts/bindings/inbox" @@ -42,7 +43,6 @@ import ( oplog "github.com/ethereum-optimism/optimism/op-service/log" "github.com/ethereum-optimism/optimism/op-service/metrics" "github.com/ethereum-optimism/optimism/op-service/oppprof" - "github.com/ethereum-optimism/optimism/op-service/predeploys" oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" "github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum-optimism/optimism/op-service/testlog" diff --git a/op-e2e/opgeth/fastlz_test.go b/op-e2e/opgeth/fastlz_test.go index 5b03ca38eca..55ac91cd768 100644 --- a/op-e2e/opgeth/fastlz_test.go +++ b/op-e2e/opgeth/fastlz_test.go @@ -11,10 +11,10 @@ import ( "testing" "time" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/fastlz" "github.com/ethereum-optimism/optimism/op-e2e/system/e2esys" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" diff --git a/op-e2e/system/bridge/bridge_test.go b/op-e2e/system/bridge/bridge_test.go index 655cf612c9a..f157870c158 100644 --- a/op-e2e/system/bridge/bridge_test.go +++ b/op-e2e/system/bridge/bridge_test.go @@ -10,12 +10,12 @@ import ( "github.com/ethereum-optimism/optimism/op-e2e/system/e2esys" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "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" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/core/types" diff --git a/op-e2e/system/bridge/deposit_test.go b/op-e2e/system/bridge/deposit_test.go index a79147cee16..70d06c1c33b 100644 --- a/op-e2e/system/bridge/deposit_test.go +++ b/op-e2e/system/bridge/deposit_test.go @@ -8,7 +8,6 @@ import ( "time" op_e2e "github.com/ethereum-optimism/optimism/op-e2e" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/holiman/uint256" "github.com/ethereum-optimism/optimism/op-e2e/system/e2esys" @@ -16,6 +15,7 @@ import ( "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -129,7 +129,7 @@ func TestMintCallToDelegatedAccount(t *testing.T) { op_e2e.InitParallel(t) cfg := e2esys.DefaultSystemConfig(t) cfg.DeployConfig = cfg.DeployConfig.Copy() - cfg.DeployConfig.ActivateForkAtGenesis(rollup.Isthmus) + cfg.DeployConfig.ActivateForkAtGenesis(forks.Isthmus) delete(cfg.Nodes, "verifier") sys, err := cfg.Start(t) require.NoError(t, err, "Error starting up system") diff --git a/op-e2e/system/bridge/validity_test.go b/op-e2e/system/bridge/validity_test.go index bb10aba541e..3e3785d9678 100644 --- a/op-e2e/system/bridge/validity_test.go +++ b/op-e2e/system/bridge/validity_test.go @@ -18,6 +18,7 @@ import ( "github.com/ethereum-optimism/optimism/op-e2e/system/helpers" "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" + "github.com/ethereum-optimism/optimism/op-core/predeploys" legacybindings "github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/config/secrets" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" @@ -25,7 +26,6 @@ import ( "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-node/bindings" bindingspreview "github.com/ethereum-optimism/optimism/op-node/bindings/preview" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/testutils/fuzzerutils" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/abi/bind" diff --git a/op-e2e/system/e2esys/setup.go b/op-e2e/system/e2esys/setup.go index a79bb9b5384..3b214799e5d 100644 --- a/op-e2e/system/e2esys/setup.go +++ b/op-e2e/system/e2esys/setup.go @@ -45,6 +45,7 @@ import ( batcherCfg "github.com/ethereum-optimism/optimism/op-batcher/config" batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-core/predeploys" shared "github.com/ethereum-optimism/optimism/op-devstack/shared/challenger" "github.com/ethereum-optimism/optimism/op-e2e/config" "github.com/ethereum-optimism/optimism/op-e2e/config/secrets" @@ -74,7 +75,6 @@ import ( "github.com/ethereum-optimism/optimism/op-service/endpoint" "github.com/ethereum-optimism/optimism/op-service/eth" oplog "github.com/ethereum-optimism/optimism/op-service/log" - "github.com/ethereum-optimism/optimism/op-service/predeploys" oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" opsigner "github.com/ethereum-optimism/optimism/op-service/signer" "github.com/ethereum-optimism/optimism/op-service/sources" diff --git a/op-e2e/system/fees/fees_test.go b/op-e2e/system/fees/fees_test.go index c3a243fe48b..9c2dec22c2e 100644 --- a/op-e2e/system/fees/fees_test.go +++ b/op-e2e/system/fees/fees_test.go @@ -7,11 +7,11 @@ import ( op_e2e "github.com/ethereum-optimism/optimism/op-e2e" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "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-e2e/system/helpers" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" diff --git a/op-e2e/system/fees/gaspriceoracle_test.go b/op-e2e/system/fees/gaspriceoracle_test.go index 22ad06bb613..479f5d930bf 100644 --- a/op-e2e/system/fees/gaspriceoracle_test.go +++ b/op-e2e/system/fees/gaspriceoracle_test.go @@ -8,12 +8,12 @@ import ( op_e2e "github.com/ethereum-optimism/optimism/op-e2e" + "github.com/ethereum-optimism/optimism/op-core/predeploys" 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" ) diff --git a/op-e2e/system/helpers/withdrawal_helper.go b/op-e2e/system/helpers/withdrawal_helper.go index 787495e4aa5..c7edbbfea20 100644 --- a/op-e2e/system/helpers/withdrawal_helper.go +++ b/op-e2e/system/helpers/withdrawal_helper.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics" gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-e2e/config" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions" @@ -22,7 +23,6 @@ import ( "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/withdrawals" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/sources/batching" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" diff --git a/op-node/chaincfg/chains_test.go b/op-node/chaincfg/chains_test.go index fe2c1682dda..dd0ff560cab 100644 --- a/op-node/chaincfg/chains_test.go +++ b/op-node/chaincfg/chains_test.go @@ -77,7 +77,7 @@ var mainnetCfg = rollup.Config{ GraniteTime: u64Ptr(1726070401), HoloceneTime: u64Ptr(1736445601), IsthmusTime: u64Ptr(1746806401), - JovianTime: u64Ptr(1764086401), + JovianTime: u64Ptr(1764691201), ProtocolVersionsAddress: common.HexToAddress("0x8062AbC286f5e7D9428a0Ccb9AbD71e50d93b935"), ChainOpConfig: defaultOpConfig, } @@ -118,7 +118,7 @@ var sepoliaCfg = rollup.Config{ HoloceneTime: u64Ptr(1732633200), PectraBlobScheduleTime: u64Ptr(1742486400), IsthmusTime: u64Ptr(1744905600), - JovianTime: u64Ptr(1762963201), + JovianTime: u64Ptr(1763568001), ProtocolVersionsAddress: common.HexToAddress("0x79ADD5713B383DAa0a138d3C4780C7A1804a8090"), ChainOpConfig: defaultOpConfig, } diff --git a/op-node/flags/flags.go b/op-node/flags/flags.go index e7238352723..90326aeb8d8 100644 --- a/op-node/flags/flags.go +++ b/op-node/flags/flags.go @@ -252,6 +252,18 @@ var ( Value: false, Category: SequencerCategory, } + FinalityLookbackFlag = &cli.Uint64Flag{ + Name: "finality.lookback", + Usage: "Number of L1 blocks to look back for finality verification. Uses default calculation if 0 (considers alt-DA challenge/resolve windows if applicable).", + EnvVars: prefixEnvVars("FINALITY_LOOKBACK"), + Category: RollupCategory, + } + FinalityDelayFlag = &cli.Uint64Flag{ + Name: "finality.delay", + Usage: "Number of L1 blocks to traverse before trying to finalize L2 blocks again. Uses default (64) if 0.", + EnvVars: prefixEnvVars("FINALITY_DELAY"), + Category: RollupCategory, + } L1EpochPollIntervalFlag = &cli.DurationFlag{ Name: "l1.epoch-poll-interval", Usage: "Poll interval for retrieving new L1 epoch updates such as safe and finalized block changes. Disabled if 0 or negative.", @@ -450,6 +462,8 @@ var optionalFlags = []cli.Flag{ SequencerMaxSafeLagFlag, SequencerL1Confs, SequencerRecoverMode, + FinalityLookbackFlag, + FinalityDelayFlag, L1EpochPollIntervalFlag, RuntimeConfigReloadIntervalFlag, RPCAdminPersistence, diff --git a/op-node/rollup/attributes/engine_consolidate_test.go b/op-node/rollup/attributes/engine_consolidate_test.go index 702355ae0da..47086c518e8 100644 --- a/op-node/rollup/attributes/engine_consolidate_test.go +++ b/op-node/rollup/attributes/engine_consolidate_test.go @@ -13,9 +13,10 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum-optimism/optimism/op-core/forks" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testutils" ) @@ -232,126 +233,126 @@ func TestAttributesMatch(t *testing.T) { }{ { args: bedrockArgs(), - rollupCfg: cfg(rollup.Bedrock), + rollupCfg: cfg(forks.Bedrock), desc: "validBedrockArgs", }, { args: bedrockArgs(), - rollupCfg: cfg(rollup.Canyon), + rollupCfg: cfg(forks.Canyon), err: ErrCanyonMustHaveWithdrawals.Error() + ": block", desc: "bedrockArgsPostCanyon", }, { args: canyonArgs(), - rollupCfg: cfg(rollup.Canyon), + rollupCfg: cfg(forks.Canyon), desc: "validCanyonArgs", }, { args: ecotoneArgs(), - rollupCfg: cfg(rollup.Ecotone), + rollupCfg: cfg(forks.Ecotone), desc: "validEcotoneArgs", }, { args: holoceneArgs(), - rollupCfg: cfg(rollup.Holocene), + rollupCfg: cfg(forks.Holocene), desc: "validholoceneArgs", }, { args: jovianArgs(), - rollupCfg: cfg(rollup.Jovian), + rollupCfg: cfg(forks.Jovian), desc: "validJovianArgs", }, { args: mismatchedParentHashArgs(), - rollupCfg: cfg(rollup.Holocene), + rollupCfg: cfg(forks.Holocene), err: "parent hash field does not match", desc: "mismatchedParentHashArgs", }, { args: createMismatchedTimestamp(), - rollupCfg: cfg(rollup.Holocene), + rollupCfg: cfg(forks.Holocene), err: "timestamp field does not match", desc: "createMismatchedTimestamp", }, { args: createMismatchedPrevRandao(), - rollupCfg: cfg(rollup.Holocene), + rollupCfg: cfg(forks.Holocene), err: "random field does not match", desc: "createMismatchedPrevRandao", }, { args: createMismatchedTransactions(), - rollupCfg: cfg(rollup.Holocene), + rollupCfg: cfg(forks.Holocene), err: "transaction count does not match", desc: "createMismatchedTransactions", }, { args: ecotoneNoParentBeaconBlockRoot(), - rollupCfg: cfg(rollup.Holocene), + rollupCfg: cfg(forks.Holocene), err: "expected non-nil parent beacon block root", desc: "ecotoneNoParentBeaconBlockRoot", }, { args: ecotoneUnexpectedParentBeaconBlockRoot(), - rollupCfg: cfg(rollup.Holocene), + rollupCfg: cfg(forks.Holocene), err: "expected nil parent beacon block root but got non-nil", desc: "ecotoneUnexpectedParentBeaconBlockRoot", }, { args: ecotoneMismatchParentBeaconBlockRoot(), - rollupCfg: cfg(rollup.Ecotone), + rollupCfg: cfg(forks.Ecotone), err: "parent beacon block root does not match", desc: "ecotoneMismatchParentBeaconBlockRoot", }, { args: ecotoneMismatchParentBeaconBlockRootPtr(), - rollupCfg: cfg(rollup.Ecotone), + rollupCfg: cfg(forks.Ecotone), desc: "ecotoneMismatchParentBeaconBlockRootPtr", }, { args: ecotoneNilParentBeaconBlockRoots(), - rollupCfg: cfg(rollup.Ecotone), + rollupCfg: cfg(forks.Ecotone), desc: "ecotoneNilParentBeaconBlockRoots", }, { args: createMismatchedGasLimit(), - rollupCfg: cfg(rollup.Holocene), + rollupCfg: cfg(forks.Holocene), err: "gas limit does not match", desc: "createMismatchedGasLimit", }, { args: createNilGasLimit(), - rollupCfg: cfg(rollup.Holocene), + rollupCfg: cfg(forks.Holocene), err: "expected gaslimit in attributes to not be nil", desc: "createNilGasLimit", }, { args: createMismatchedFeeRecipient(), - rollupCfg: cfg(rollup.Holocene), + rollupCfg: cfg(forks.Holocene), err: "fee recipient data does not match", desc: "createMismatchedFeeRecipient", }, { args: createMismatchedEIP1559Params(), - rollupCfg: cfg(rollup.Holocene), + rollupCfg: cfg(forks.Holocene), err: "eip1559 parameters do not match", desc: "createMismatchedEIP1559Params", }, { args: jovianArgsMinBaseFeeMissingFromAttributes(), - rollupCfg: cfg(rollup.Jovian), + rollupCfg: cfg(forks.Jovian), err: "minBaseFee does not match", desc: "missingMinBaseFee", }, { args: jovianArgsMinBaseFeeMissingFromBlock(), - rollupCfg: cfg(rollup.Jovian), + rollupCfg: cfg(forks.Jovian), err: "invalid block extraData: MinBaseFee extraData should be 17 bytes, got 9", desc: "missingMinBaseFee", }, { args: jovianArgsInconsistentMinBaseFee(), - rollupCfg: cfg(rollup.Jovian), + rollupCfg: cfg(forks.Jovian), err: "minBaseFee does not match", desc: "inconsistentMinBaseFee", }, diff --git a/op-node/rollup/chain_spec.go b/op-node/rollup/chain_spec.go index e2a6ae44efc..9e432e21b71 100644 --- a/op-node/rollup/chain_spec.go +++ b/op-node/rollup/chain_spec.go @@ -1,9 +1,9 @@ package rollup import ( - "fmt" "math/big" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/params" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum/log" @@ -30,66 +30,8 @@ const ( // ChainSpec instead of reading the rollup configuration field directly. const maxSequencerDriftFjord = 1800 -type ForkName string - -const ( - Bedrock ForkName = "bedrock" - Regolith ForkName = "regolith" - Canyon ForkName = "canyon" - Delta ForkName = "delta" - Ecotone ForkName = "ecotone" - Fjord ForkName = "fjord" - Granite ForkName = "granite" - Holocene ForkName = "holocene" - Isthmus ForkName = "isthmus" - Jovian ForkName = "jovian" - Interop ForkName = "interop" - // ADD NEW FORKS TO AllForks BELOW! - None ForkName = "" -) - -var AllForks = []ForkName{ - Bedrock, - Regolith, - Canyon, - Delta, - Ecotone, - Fjord, - Granite, - Holocene, - Isthmus, - Jovian, - Interop, - // ADD NEW FORKS HERE! -} - -var LatestFork = AllForks[len(AllForks)-1] - -func ForksFrom(fork ForkName) []ForkName { - for i, f := range AllForks { - if f == fork { - return AllForks[i:] - } - } - panic(fmt.Sprintf("invalid fork: %s", fork)) -} - -var nextFork = func() map[ForkName]ForkName { - m := make(map[ForkName]ForkName, len(AllForks)) - for i, f := range AllForks { - if i == len(AllForks)-1 { - m[f] = None - break - } - m[f] = AllForks[i+1] - } - return m -}() - -func IsValidFork(fork ForkName) bool { - _, ok := nextFork[fork] - return ok -} +// Legacy type alias kept temporarily for rollup internals; external code should use forks.Name directly. +type ForkName = forks.Name type ChainSpec struct { config *Config @@ -175,36 +117,36 @@ func (s *ChainSpec) MaxSequencerDrift(t uint64) uint64 { func (s *ChainSpec) CheckForkActivation(log log.Logger, block eth.L2BlockRef) { if s.currentFork == "" { // Initialize currentFork if it is not set yet - s.currentFork = Bedrock + s.currentFork = forks.Bedrock if s.config.IsRegolith(block.Time) { - s.currentFork = Regolith + s.currentFork = forks.Regolith } if s.config.IsCanyon(block.Time) { - s.currentFork = Canyon + s.currentFork = forks.Canyon } if s.config.IsDelta(block.Time) { - s.currentFork = Delta + s.currentFork = forks.Delta } if s.config.IsEcotone(block.Time) { - s.currentFork = Ecotone + s.currentFork = forks.Ecotone } if s.config.IsFjord(block.Time) { - s.currentFork = Fjord + s.currentFork = forks.Fjord } if s.config.IsGranite(block.Time) { - s.currentFork = Granite + s.currentFork = forks.Granite } if s.config.IsHolocene(block.Time) { - s.currentFork = Holocene + s.currentFork = forks.Holocene } if s.config.IsIsthmus(block.Time) { - s.currentFork = Isthmus + s.currentFork = forks.Isthmus } if s.config.IsJovian(block.Time) { - s.currentFork = Jovian + s.currentFork = forks.Jovian } if s.config.IsInterop(block.Time) { - s.currentFork = Interop + s.currentFork = forks.Interop } log.Info("Current hardfork version detected", "forkName", s.currentFork) return @@ -212,31 +154,31 @@ func (s *ChainSpec) CheckForkActivation(log log.Logger, block eth.L2BlockRef) { foundActivationBlock := false - switch nextFork[s.currentFork] { - case Regolith: + switch forks.Next(s.currentFork) { + case forks.Regolith: foundActivationBlock = s.config.IsRegolithActivationBlock(block.Time) - case Canyon: + case forks.Canyon: foundActivationBlock = s.config.IsCanyonActivationBlock(block.Time) - case Delta: + case forks.Delta: foundActivationBlock = s.config.IsDeltaActivationBlock(block.Time) - case Ecotone: + case forks.Ecotone: foundActivationBlock = s.config.IsEcotoneActivationBlock(block.Time) - case Fjord: + case forks.Fjord: foundActivationBlock = s.config.IsFjordActivationBlock(block.Time) - case Granite: + case forks.Granite: foundActivationBlock = s.config.IsGraniteActivationBlock(block.Time) - case Holocene: + case forks.Holocene: foundActivationBlock = s.config.IsHoloceneActivationBlock(block.Time) - case Isthmus: + case forks.Isthmus: foundActivationBlock = s.config.IsIsthmusActivationBlock(block.Time) - case Jovian: + case forks.Jovian: foundActivationBlock = s.config.IsJovianActivationBlock(block.Time) - case Interop: + case forks.Interop: foundActivationBlock = s.config.IsInteropActivationBlock(block.Time) } if foundActivationBlock { - s.currentFork = nextFork[s.currentFork] + s.currentFork = forks.Next(s.currentFork) log.Info("Detected hardfork activation block", "forkName", s.currentFork, "timestamp", block.Time, "blockNum", block.Number, "hash", block.Hash) } } diff --git a/op-node/rollup/chain_spec_test.go b/op-node/rollup/chain_spec_test.go index 02601a4d9d8..8e488665d15 100644 --- a/op-node/rollup/chain_spec_test.go +++ b/op-node/rollup/chain_spec_test.go @@ -5,6 +5,7 @@ import ( "math/big" "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/common" @@ -159,55 +160,55 @@ func TestCheckForkActivation(t *testing.T) { { name: "Regolith activation", block: eth.L2BlockRef{Time: 10, Number: 5, Hash: common.Hash{0x5}}, - expectedCurrentFork: Regolith, + expectedCurrentFork: forks.Regolith, expectedLog: "Detected hardfork activation block", }, { name: "Still Regolith", block: eth.L2BlockRef{Time: 11, Number: 6, Hash: common.Hash{0x6}}, - expectedCurrentFork: Regolith, + expectedCurrentFork: forks.Regolith, expectedLog: "", }, { name: "Canyon activation", block: eth.L2BlockRef{Time: 20, Number: 7, Hash: common.Hash{0x7}}, - expectedCurrentFork: Canyon, + expectedCurrentFork: forks.Canyon, expectedLog: "Detected hardfork activation block", }, { name: "Granite activation", block: eth.L2BlockRef{Time: 60, Number: 8, Hash: common.Hash{0x8}}, - expectedCurrentFork: Granite, + expectedCurrentFork: forks.Granite, expectedLog: "Detected hardfork activation block", }, { name: "Holocene activation", block: eth.L2BlockRef{Time: 70, Number: 9, Hash: common.Hash{0x9}}, - expectedCurrentFork: Holocene, + expectedCurrentFork: forks.Holocene, expectedLog: "Detected hardfork activation block", }, { name: "Isthmus activation", block: eth.L2BlockRef{Time: 80, Number: 10, Hash: common.Hash{0xa}}, - expectedCurrentFork: Isthmus, + expectedCurrentFork: forks.Isthmus, expectedLog: "Detected hardfork activation block", }, { name: "Jovian activation", block: eth.L2BlockRef{Time: 90, Number: 11, Hash: common.Hash{0xb}}, - expectedCurrentFork: Jovian, + expectedCurrentFork: forks.Jovian, expectedLog: "Detected hardfork activation block", }, { name: "Interop activation", block: eth.L2BlockRef{Time: 100, Number: 11, Hash: common.Hash{0xb}}, - expectedCurrentFork: Interop, + expectedCurrentFork: forks.Interop, expectedLog: "Detected hardfork activation block", }, { name: "No more hardforks", block: eth.L2BlockRef{Time: 700, Number: 12, Hash: common.Hash{0xc}}, - expectedCurrentFork: Interop, + expectedCurrentFork: forks.Interop, expectedLog: "", }, } diff --git a/op-node/rollup/derive/attributes.go b/op-node/rollup/derive/attributes.go index 59f6d2dbb2f..55c2c3faf00 100644 --- a/op-node/rollup/derive/attributes.go +++ b/op-node/rollup/derive/attributes.go @@ -9,9 +9,9 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" ) type DependencySet interface { diff --git a/op-node/rollup/derive/attributes_queue_test.go b/op-node/rollup/derive/attributes_queue_test.go index 2f63983ab73..7e712022137 100644 --- a/op-node/rollup/derive/attributes_queue_test.go +++ b/op-node/rollup/derive/attributes_queue_test.go @@ -12,9 +12,9 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testutils" ) diff --git a/op-node/rollup/derive/attributes_test.go b/op-node/rollup/derive/attributes_test.go index 5d1056b4622..bb76436f550 100644 --- a/op-node/rollup/derive/attributes_test.go +++ b/op-node/rollup/derive/attributes_test.go @@ -8,9 +8,10 @@ import ( "math/rand" "testing" + "github.com/ethereum-optimism/optimism/op-core/forks" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/testutils" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" "github.com/ethereum/go-ethereum/common" @@ -230,7 +231,7 @@ func TestPreparePayloadAttributes(t *testing.T) { require.NoError(t, err) // sets config to post-interop - cfg.ActivateAtGenesis(rollup.Interop) + cfg.ActivateAtGenesis(forks.Interop) seqNumber := uint64(0) epoch := l1Info.ID() @@ -271,7 +272,7 @@ func TestPreparePayloadAttributes(t *testing.T) { l1Info.InfoNum = l2Parent.L1Origin.Number // same origin again, so the sequence number is not reset // sets config to post-interop - cfg.ActivateAtGenesis(rollup.Interop) + cfg.ActivateAtGenesis(forks.Interop) seqNumber := l2Parent.SequenceNumber + 1 epoch := l1Info.ID() @@ -297,7 +298,7 @@ func TestPreparePayloadAttributes(t *testing.T) { t.Run("holocene 1559 params", func(t *testing.T) { cfg := mkCfg() - cfg.ActivateAtGenesis(rollup.Holocene) + cfg.ActivateAtGenesis(forks.Holocene) rng := rand.New(rand.NewSource(1234)) l1Fetcher := &testutils.MockL1Source{} defer l1Fetcher.AssertExpectations(t) @@ -382,7 +383,7 @@ func TestPreparePayloadAttributes(t *testing.T) { t.Run("interop", func(t *testing.T) { prepareActivationAttributes := func(t *testing.T, depSet depset.DependencySet) *eth.PayloadAttributes { cfg := mkCfg() - cfg.ActivateAtGenesis(rollup.Isthmus) + cfg.ActivateAtGenesis(forks.Isthmus) interopTime := uint64(1000) cfg.InteropTime = &interopTime rng := rand.New(rand.NewSource(1234)) @@ -444,7 +445,7 @@ func TestPreparePayloadAttributes(t *testing.T) { t.Run("minimum base fee param", func(t *testing.T) { cfg := mkCfg() - cfg.ActivateAtGenesis(rollup.Jovian) + cfg.ActivateAtGenesis(forks.Jovian) rng := rand.New(rand.NewSource(1234)) l1Fetcher := &testutils.MockL1Source{} defer l1Fetcher.AssertExpectations(t) diff --git a/op-node/rollup/derive/batch_mux.go b/op-node/rollup/derive/batch_mux.go index f5eeb95613c..e18fc69d232 100644 --- a/op-node/rollup/derive/batch_mux.go +++ b/op-node/rollup/derive/batch_mux.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum/log" @@ -48,9 +49,9 @@ func (b *BatchMux) Reset(ctx context.Context, base eth.L1BlockRef, sysCfg eth.Sy return b.SingularBatchProvider.Reset(ctx, base, sysCfg) } -func (b *BatchMux) Transform(f rollup.ForkName) { +func (b *BatchMux) Transform(f forks.Name) { switch f { - case rollup.Holocene: + case forks.Holocene: b.TransformHolocene() } } diff --git a/op-node/rollup/derive/batch_mux_test.go b/op-node/rollup/derive/batch_mux_test.go index 2afc25a69dc..2cb82ec6fe6 100644 --- a/op-node/rollup/derive/batch_mux_test.go +++ b/op-node/rollup/derive/batch_mux_test.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/stretchr/testify/require" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/testlog" @@ -31,7 +32,7 @@ func TestBatchMux_LaterHolocene(t *testing.T) { require.IsType(t, new(BatchQueue), b.SingularBatchProvider) require.Equal(t, l1A, b.SingularBatchProvider.(*BatchQueue).origin) - b.Transform(rollup.Holocene) + b.Transform(forks.Holocene) require.IsType(t, new(BatchStage), b.SingularBatchProvider) require.Equal(t, l1A, b.SingularBatchProvider.(*BatchStage).origin) @@ -64,5 +65,5 @@ func TestBatchMux_ActiveHolocene(t *testing.T) { require.IsType(t, new(BatchStage), b.SingularBatchProvider) require.Equal(t, l1A, b.SingularBatchProvider.(*BatchStage).origin) - require.Panics(t, func() { b.Transform(rollup.Holocene) }) + require.Panics(t, func() { b.Transform(forks.Holocene) }) } diff --git a/op-node/rollup/derive/batches_test.go b/op-node/rollup/derive/batches_test.go index 3a668f66f52..ade8d9df4c3 100644 --- a/op-node/rollup/derive/batches_test.go +++ b/op-node/rollup/derive/batches_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/testlog" @@ -655,7 +656,7 @@ func TestValidBatch(t *testing.T) { // Add test cases for all forks from Jovian to assert that upgrade block must not contain user // txs. If a future fork should allow user txs in its upgrade block, it must be removed from // this list explicitly. - for _, fork := range rollup.ForksFrom(rollup.Jovian) { + for _, fork := range forks.From(forks.Jovian) { singularBatchTestCases = append(singularBatchTestCases, ValidBatchTestCase{ Name: fmt.Sprintf("user txs in %s upgrade block", fork), L1Blocks: []eth.L1BlockRef{l1A, l1B, l1C}, diff --git a/op-node/rollup/derive/channel_mux.go b/op-node/rollup/derive/channel_mux.go index 44246eeae39..c844cbd1e43 100644 --- a/op-node/rollup/derive/channel_mux.go +++ b/op-node/rollup/derive/channel_mux.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum/log" @@ -52,9 +53,9 @@ func (c *ChannelMux) Reset(ctx context.Context, base eth.L1BlockRef, sysCfg eth. return c.RawChannelProvider.Reset(ctx, base, sysCfg) } -func (c *ChannelMux) Transform(f rollup.ForkName) { +func (c *ChannelMux) Transform(f forks.Name) { switch f { - case rollup.Holocene: + case forks.Holocene: c.TransformHolocene() } } diff --git a/op-node/rollup/derive/channel_mux_test.go b/op-node/rollup/derive/channel_mux_test.go index 59fd669922a..05ad2f0e8a6 100644 --- a/op-node/rollup/derive/channel_mux_test.go +++ b/op-node/rollup/derive/channel_mux_test.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/metrics" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" @@ -34,7 +35,7 @@ func TestChannelMux_LaterHolocene(t *testing.T) { require.Equal(t, io.EOF, err) require.IsType(t, new(ChannelBank), c.RawChannelProvider) - c.Transform(rollup.Holocene) + c.Transform(forks.Holocene) require.IsType(t, new(ChannelAssembler), c.RawChannelProvider) err = c.Reset(ctx, l1B, eth.SystemConfig{}) @@ -65,5 +66,5 @@ func TestChannelMux_ActiveHolocene(t *testing.T) { require.Equal(t, io.EOF, err) require.IsType(t, new(ChannelAssembler), c.RawChannelProvider) - require.Panics(t, func() { c.Transform(rollup.Holocene) }) + require.Panics(t, func() { c.Transform(forks.Holocene) }) } diff --git a/op-node/rollup/derive/ecotone_upgrade_transactions.go b/op-node/rollup/derive/ecotone_upgrade_transactions.go index e2fed646dc8..9073c6affbc 100644 --- a/op-node/rollup/derive/ecotone_upgrade_transactions.go +++ b/op-node/rollup/derive/ecotone_upgrade_transactions.go @@ -10,7 +10,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-service/solabi" ) diff --git a/op-node/rollup/derive/fjord_upgrade_transactions.go b/op-node/rollup/derive/fjord_upgrade_transactions.go index 93f7595dd1d..5dd21b05424 100644 --- a/op-node/rollup/derive/fjord_upgrade_transactions.go +++ b/op-node/rollup/derive/fjord_upgrade_transactions.go @@ -3,7 +3,7 @@ package derive import ( "math/big" - "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" diff --git a/op-node/rollup/derive/frame_queue.go b/op-node/rollup/derive/frame_queue.go index 361f1cfda88..c2266aac3b8 100644 --- a/op-node/rollup/derive/frame_queue.go +++ b/op-node/rollup/derive/frame_queue.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/log" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" ) @@ -36,9 +37,9 @@ func NewFrameQueue(log log.Logger, cfg *rollup.Config, prev NextDataProvider) *F } } -func (fq *FrameQueue) Transform(f rollup.ForkName) { +func (fq *FrameQueue) Transform(f forks.Name) { switch f { - case rollup.Holocene: + case forks.Holocene: fq.log.Info("FrameQueue: resetting with Holocene activation") // With Holocene activation, the frame queue is simply reset fq.reset() diff --git a/op-node/rollup/derive/interop_upgrade_transactions.go b/op-node/rollup/derive/interop_upgrade_transactions.go index e3da85b32c5..bed2a600b88 100644 --- a/op-node/rollup/derive/interop_upgrade_transactions.go +++ b/op-node/rollup/derive/interop_upgrade_transactions.go @@ -3,7 +3,7 @@ package derive import ( "math/big" - "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" diff --git a/op-node/rollup/derive/interop_upgrade_transactions_test.go b/op-node/rollup/derive/interop_upgrade_transactions_test.go index 6c17f61331f..84fcc65bc84 100644 --- a/op-node/rollup/derive/interop_upgrade_transactions_test.go +++ b/op-node/rollup/derive/interop_upgrade_transactions_test.go @@ -4,7 +4,7 @@ import ( "encoding/hex" "testing" - "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) diff --git a/op-node/rollup/derive/isthmus_upgrade_transactions.go b/op-node/rollup/derive/isthmus_upgrade_transactions.go index 25bee50b061..c4b0efadb71 100644 --- a/op-node/rollup/derive/isthmus_upgrade_transactions.go +++ b/op-node/rollup/derive/isthmus_upgrade_transactions.go @@ -3,7 +3,7 @@ package derive import ( "math/big" - "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" diff --git a/op-node/rollup/derive/isthmus_upgrade_transactions_test.go b/op-node/rollup/derive/isthmus_upgrade_transactions_test.go index c005d57b161..b51df3d8ace 100644 --- a/op-node/rollup/derive/isthmus_upgrade_transactions_test.go +++ b/op-node/rollup/derive/isthmus_upgrade_transactions_test.go @@ -3,7 +3,7 @@ package derive import ( "testing" - "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) diff --git a/op-node/rollup/derive/jovian_upgrade_transactions.go b/op-node/rollup/derive/jovian_upgrade_transactions.go index ea773842a91..c7d544851d4 100644 --- a/op-node/rollup/derive/jovian_upgrade_transactions.go +++ b/op-node/rollup/derive/jovian_upgrade_transactions.go @@ -4,7 +4,7 @@ import ( "fmt" "math/big" - "github.com/ethereum-optimism/optimism/op-service/predeploys" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" diff --git a/op-node/rollup/derive/l1_block_info.go b/op-node/rollup/derive/l1_block_info.go index bac4689ebc6..0577125590f 100644 --- a/op-node/rollup/derive/l1_block_info.go +++ b/op-node/rollup/derive/l1_block_info.go @@ -13,9 +13,9 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/solabi" ) diff --git a/op-node/rollup/derive/l1_block_info_test.go b/op-node/rollup/derive/l1_block_info_test.go index ebcd60139dc..463eeb0a1fe 100644 --- a/op-node/rollup/derive/l1_block_info_test.go +++ b/op-node/rollup/derive/l1_block_info_test.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/testutils" @@ -112,7 +113,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{} - rollupCfg.ActivateAtGenesis(rollup.Regolith) + rollupCfg.ActivateAtGenesis(forks.Regolith) depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, 0) require.NoError(t, err) require.False(t, depTx.IsSystemTransaction) @@ -122,7 +123,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Ecotone) + rollupCfg.ActivateAtGenesis(forks.Ecotone) // run 1 block after ecotone transition timestamp := rollupCfg.Genesis.L2Time + rollupCfg.BlockTime depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, timestamp) @@ -135,7 +136,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Delta) + rollupCfg.ActivateAtGenesis(forks.Delta) ecotoneTime := rollupCfg.Genesis.L2Time + rollupCfg.BlockTime // activate ecotone just after genesis rollupCfg.EcotoneTime = &ecotoneTime depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, ecotoneTime) @@ -148,7 +149,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Ecotone) + rollupCfg.ActivateAtGenesis(forks.Ecotone) depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, rollupCfg.Genesis.L2Time) require.NoError(t, err) require.False(t, depTx.IsSystemTransaction) @@ -159,7 +160,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Isthmus) + rollupCfg.ActivateAtGenesis(forks.Isthmus) // run 1 block after isthmus transition timestamp := rollupCfg.Genesis.L2Time + rollupCfg.BlockTime depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, timestamp) @@ -172,7 +173,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Holocene) + rollupCfg.ActivateAtGenesis(forks.Holocene) isthmusTime := rollupCfg.Genesis.L2Time + rollupCfg.BlockTime // activate isthmus just after genesis rollupCfg.IsthmusTime = &isthmusTime depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, isthmusTime) @@ -187,7 +188,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Isthmus) + rollupCfg.ActivateAtGenesis(forks.Isthmus) depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, rollupCfg.Genesis.L2Time) require.NoError(t, err) require.False(t, depTx.IsSystemTransaction) @@ -198,7 +199,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Jovian) + rollupCfg.ActivateAtGenesis(forks.Jovian) // run 1 block after Jovian transition timestamp := rollupCfg.Genesis.L2Time + rollupCfg.BlockTime depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, timestamp) @@ -215,7 +216,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Isthmus) + rollupCfg.ActivateAtGenesis(forks.Isthmus) jovianTime := rollupCfg.Genesis.L2Time + rollupCfg.BlockTime // activate jovian just after genesis rollupCfg.InteropTime = &jovianTime depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, jovianTime) @@ -230,7 +231,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Jovian) + rollupCfg.ActivateAtGenesis(forks.Jovian) depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, rollupCfg.Genesis.L2Time) require.NoError(t, err) require.False(t, depTx.IsSystemTransaction) @@ -241,7 +242,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Interop) + rollupCfg.ActivateAtGenesis(forks.Interop) // run 1 block after interop transition timestamp := rollupCfg.Genesis.L2Time + rollupCfg.BlockTime depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, timestamp) @@ -254,7 +255,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Jovian) + rollupCfg.ActivateAtGenesis(forks.Jovian) interopTime := rollupCfg.Genesis.L2Time + rollupCfg.BlockTime // activate interop just after genesis rollupCfg.InteropTime = &interopTime depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, interopTime) @@ -268,7 +269,7 @@ func TestParseL1InfoDepositTxData(t *testing.T) { rng := rand.New(rand.NewSource(1234)) info := testutils.MakeBlockInfo(nil)(rng) rollupCfg := rollup.Config{BlockTime: 2, Genesis: rollup.Genesis{L2Time: 1000}} - rollupCfg.ActivateAtGenesis(rollup.Interop) + rollupCfg.ActivateAtGenesis(forks.Interop) depTx, err := L1InfoDeposit(&rollupCfg, params.MergedTestChainConfig, randomL1Cfg(rng, info), randomSeqNr(rng), info, rollupCfg.Genesis.L2Time) require.NoError(t, err) require.False(t, depTx.IsSystemTransaction) diff --git a/op-node/rollup/derive/pipeline.go b/op-node/rollup/derive/pipeline.go index bae024da1c2..67f0511eac4 100644 --- a/op-node/rollup/derive/pipeline.go +++ b/op-node/rollup/derive/pipeline.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" ) @@ -49,7 +50,7 @@ type ChannelFlusher interface { } type ForkTransformer interface { - Transform(rollup.ForkName) + Transform(forks.Name) } type L2Source interface { @@ -273,7 +274,7 @@ func (dp *DerivationPipeline) initialReset(ctx context.Context, resetL2Safe eth. func (db *DerivationPipeline) transformStages(oldOrigin, newOrigin eth.L1BlockRef) { fork := db.rollupCfg.IsActivationBlock(oldOrigin.Time, newOrigin.Time) - if fork == rollup.None { + if fork == forks.None { return } diff --git a/op-node/rollup/driver/config.go b/op-node/rollup/driver/config.go index 5446e4da16a..d519a7e4547 100644 --- a/op-node/rollup/driver/config.go +++ b/op-node/rollup/driver/config.go @@ -1,5 +1,7 @@ package driver +import "github.com/ethereum-optimism/optimism/op-node/rollup/finality" + type Config struct { // VerifierConfDepth is the distance to keep from the L1 head when reading L1 data for L2 derivation. VerifierConfDepth uint64 `json:"verifier_conf_depth"` @@ -24,4 +26,7 @@ type Config struct { // RecoverMode forces the sequencer to select the next L1 Origin exactly, and create an empty block, // to be compatible with verifiers forcefully generating the same block while catching up the sequencing window timeout. RecoverMode bool `json:"recover_mode"` + + // Finalizer contains runtime configuration for finality behavior. + Finalizer *finality.Config `json:"finalizer,omitempty"` } diff --git a/op-node/rollup/driver/driver.go b/op-node/rollup/driver/driver.go index cc402cecab8..f0a7c66098f 100644 --- a/op-node/rollup/driver/driver.go +++ b/op-node/rollup/driver/driver.go @@ -65,9 +65,9 @@ func NewDriver( var finalizer Finalizer if cfg.AltDAEnabled() { - finalizer = finality.NewAltDAFinalizer(driverCtx, log, cfg, l1, altDA, ec) + finalizer = finality.NewAltDAFinalizer(driverCtx, log, cfg, driverCfg.Finalizer, l1, altDA, ec) } else { - finalizer = finality.NewFinalizer(driverCtx, log, cfg, l1, ec) + finalizer = finality.NewFinalizer(driverCtx, log, cfg, driverCfg.Finalizer, l1, ec) } sys.Register("finalizer", finalizer) diff --git a/op-node/rollup/finality/altda.go b/op-node/rollup/finality/altda.go index ae32725c70e..d722fbf89c5 100644 --- a/op-node/rollup/finality/altda.go +++ b/op-node/rollup/finality/altda.go @@ -27,11 +27,14 @@ type AltDAFinalizer struct { backend AltDABackend } -func NewAltDAFinalizer(ctx context.Context, log log.Logger, cfg *rollup.Config, +// NewAltDAFinalizer creates a new AltDAFinalizer instance. +// The finalizerCfg parameter is optional and may be nil to use default finality behavior. +// When non-nil, any non-nil fields in finalizerCfg will override the defaults. +func NewAltDAFinalizer(ctx context.Context, log log.Logger, cfg *rollup.Config, finalizerCfg *Config, l1Fetcher FinalizerL1Interface, backend AltDABackend, ec EngineController) *AltDAFinalizer { - inner := NewFinalizer(ctx, log, cfg, l1Fetcher, ec) + inner := NewFinalizer(ctx, log, cfg, finalizerCfg, l1Fetcher, ec) // In alt-da mode, the finalization signal is proxied through the AltDA manager. // Finality signal will come from the DA contract or L1 finality whichever is last. diff --git a/op-node/rollup/finality/altda_test.go b/op-node/rollup/finality/altda_test.go index a3c1a384386..5f01180a831 100644 --- a/op-node/rollup/finality/altda_test.go +++ b/op-node/rollup/finality/altda_test.go @@ -81,11 +81,11 @@ func TestAltDAFinalityData(t *testing.T) { DAResolveWindow: 90, } // should return l1 finality if altda is not enabled - require.Equal(t, uint64(defaultFinalityLookback), calcFinalityLookback(cfg)) + require.Equal(t, uint64(defaultFinalityLookback), calcFinalityLookback(cfg, nil)) cfg.AltDAConfig = altDACfg expFinalityLookback := 181 - require.Equal(t, uint64(expFinalityLookback), calcFinalityLookback(cfg)) + require.Equal(t, uint64(expFinalityLookback), calcFinalityLookback(cfg, nil)) refA1 := eth.L2BlockRef{ Hash: testutils.RandomHash(rng), @@ -108,7 +108,7 @@ func TestAltDAFinalityData(t *testing.T) { emitter := &testutils.MockEmitter{} ec := new(fakeEngineController) - fi := NewAltDAFinalizer(context.Background(), logger, cfg, l1F, altDABackend, ec) + fi := NewAltDAFinalizer(context.Background(), logger, cfg, nil, l1F, altDABackend, ec) fi.AttachEmitter(emitter) require.NotNil(t, altDABackend.forwardTo, "altda backend must have access to underlying standard finalizer") diff --git a/op-node/rollup/finality/finalizer.go b/op-node/rollup/finality/finalizer.go index 4d520696d94..ceaf3f6fb59 100644 --- a/op-node/rollup/finality/finalizer.go +++ b/op-node/rollup/finality/finalizer.go @@ -34,9 +34,26 @@ const defaultFinalityLookback = 4*32 + 1 // We do not want to do this too often, since it requires fetching a L1 block by number, so no cache data. const finalityDelay = 64 +// Config contains runtime configuration for the finalizer. +type Config struct { + // FinalityLookback specifies the number of L1 blocks to look back for finality verification. + // When nil, uses the default finality lookback calculation (which considers both + // the default lookback and alt-DA challenge/resolve windows if applicable). + FinalityLookback *uint64 + + // FinalityDelay specifies the number of L1 blocks to traverse before trying to finalize L2 blocks again. + // When nil, defaults to 64 blocks. + FinalityDelay *uint64 +} + // calcFinalityLookback calculates the default finality lookback based on DA challenge window if altDA // mode is activated or L1 finality lookback. -func calcFinalityLookback(cfg *rollup.Config) uint64 { +func calcFinalityLookback(cfg *rollup.Config, finalizerCfg *Config) uint64 { + // If a custom finality lookback is configured, use it as an override + if finalizerCfg != nil && finalizerCfg.FinalityLookback != nil { + return *finalizerCfg.FinalityLookback + } + // in alt-da mode the longest finality lookback is a commitment is challenged on the last block of // the challenge window in which case it will be both challenge + resolve window. if cfg.AltDAEnabled() { @@ -49,6 +66,15 @@ func calcFinalityLookback(cfg *rollup.Config) uint64 { return defaultFinalityLookback } +// calcFinalityDelay calculates the finality delay based on the runtime config or returns the default. +func calcFinalityDelay(finalizerCfg *Config) uint64 { + // If a custom finality delay is configured, use it as an override + if finalizerCfg != nil && finalizerCfg.FinalityDelay != nil { + return *finalizerCfg.FinalityDelay + } + return finalityDelay +} + type FinalityData struct { // The last L2 block that was fully derived and inserted into the L2 engine while processing this L1 block. L2Block eth.L2BlockRef @@ -99,11 +125,18 @@ type Finalizer struct { // Maximum amount of L2 blocks to store in finalityData. finalityLookback uint64 + // Number of L1 blocks to traverse before trying to finalize L2 blocks again. + finalityDelay uint64 + l1Fetcher FinalizerL1Interface } -func NewFinalizer(ctx context.Context, log log.Logger, cfg *rollup.Config, l1Fetcher FinalizerL1Interface, ec EngineController) *Finalizer { - lookback := calcFinalityLookback(cfg) +// NewFinalizer creates a new Finalizer instance. +// The finalizerCfg parameter is optional and may be nil to use default finality behavior. +// When non-nil, any non-nil fields in finalizerCfg will override the defaults. +func NewFinalizer(ctx context.Context, log log.Logger, cfg *rollup.Config, finalizerCfg *Config, l1Fetcher FinalizerL1Interface, ec EngineController) *Finalizer { + lookback := calcFinalityLookback(cfg, finalizerCfg) + delay := calcFinalityDelay(finalizerCfg) return &Finalizer{ ctx: ctx, cfg: cfg, @@ -113,6 +146,7 @@ func NewFinalizer(ctx context.Context, log log.Logger, cfg *rollup.Config, l1Fet triedFinalizeAt: 0, finalityData: make([]FinalityData, 0, lookback), finalityLookback: lookback, + finalityDelay: delay, l1Fetcher: l1Fetcher, } } @@ -195,7 +229,7 @@ func (fi *Finalizer) onDerivationIdle(derivedFrom eth.L1BlockRef) { return // if no L1 information is finalized yet, then skip this } // If we recently tried finalizing, then don't try again just yet, but traverse more of L1 first. - if fi.triedFinalizeAt != 0 && derivedFrom.Number <= fi.triedFinalizeAt+finalityDelay { + if fi.triedFinalizeAt != 0 && derivedFrom.Number <= fi.triedFinalizeAt+fi.finalityDelay { return } fi.log.Debug("processing L1 finality information", "l1_finalized", fi.finalizedL1, "derived_from", derivedFrom, "previous", fi.triedFinalizeAt) diff --git a/op-node/rollup/finality/finalizer_test.go b/op-node/rollup/finality/finalizer_test.go index 4ab1cf492c1..fe5ef061db8 100644 --- a/op-node/rollup/finality/finalizer_test.go +++ b/op-node/rollup/finality/finalizer_test.go @@ -194,7 +194,7 @@ func TestEngineQueue_Finalize(t *testing.T) { emitter := &testutils.MockEmitter{} ec := new(fakeEngineController) - fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, l1F, ec) + fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, nil, l1F, ec) fi.AttachEmitter(emitter) // now say C1 was included in D and became the new safe head @@ -229,7 +229,7 @@ func TestEngineQueue_Finalize(t *testing.T) { emitter := &testutils.MockEmitter{} ec := new(fakeEngineController) - fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, l1F, ec) + fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, nil, l1F, ec) fi.AttachEmitter(emitter) // now say C1 was included in D and became the new safe head @@ -268,7 +268,7 @@ func TestEngineQueue_Finalize(t *testing.T) { emitter := &testutils.MockEmitter{} ec := new(fakeEngineController) - fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, l1F, ec) + fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, nil, l1F, ec) fi.AttachEmitter(emitter) fi.OnEvent(ctx, engine.SafeDerivedEvent{Safe: refC1, Source: refD}) @@ -352,7 +352,7 @@ func TestEngineQueue_Finalize(t *testing.T) { emitter := &testutils.MockEmitter{} ec := new(fakeEngineController) - fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, l1F, ec) + fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, nil, l1F, ec) fi.AttachEmitter(emitter) // now say B1 was included in C and became the new safe head @@ -389,7 +389,7 @@ func TestEngineQueue_Finalize(t *testing.T) { emitter := &testutils.MockEmitter{} ec := new(fakeEngineController) - fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, l1F, ec) + fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, nil, l1F, ec) fi.AttachEmitter(emitter) // now say B1 was included in C and became the new safe head @@ -486,7 +486,7 @@ func TestEngineQueue_Finalize(t *testing.T) { ec := new(fakeEngineController) fi := NewFinalizer(context.Background(), logger, &rollup.Config{ InteropTime: &refC1.Time, - }, l1F, ec) + }, nil, l1F, ec) fi.AttachEmitter(emitter) // now say C0 and C1 were included in D and became the new safe head @@ -504,3 +504,101 @@ func TestEngineQueue_Finalize(t *testing.T) { emitter.AssertExpectations(t) }) } + +func TestFinalizerConfig(t *testing.T) { + t.Run("uses custom finality lookback", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelError) + l1F := &testutils.MockL1Source{} + ec := new(fakeEngineController) + + customLookback := uint64(200) + finalizerCfg := &Config{ + FinalityLookback: &customLookback, + } + + fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, finalizerCfg, l1F, ec) + + require.Equal(t, customLookback, fi.finalityLookback, "should use custom finality lookback") + require.Equal(t, int(customLookback), cap(fi.finalityData), "finalityData capacity should match custom lookback") + }) + + t.Run("uses custom finality delay", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelError) + l1F := &testutils.MockL1Source{} + ec := new(fakeEngineController) + + customDelay := uint64(32) + finalizerCfg := &Config{ + FinalityDelay: &customDelay, + } + + fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, finalizerCfg, l1F, ec) + + require.Equal(t, customDelay, fi.finalityDelay, "should use custom finality delay") + }) + + t.Run("uses defaults when config is nil", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelError) + l1F := &testutils.MockL1Source{} + ec := new(fakeEngineController) + + fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, nil, l1F, ec) + + require.Equal(t, uint64(defaultFinalityLookback), fi.finalityLookback, "should use default finality lookback when config is nil") + require.Equal(t, uint64(finalityDelay), fi.finalityDelay, "should use default finality delay when config is nil") + }) + + t.Run("uses defaults when config fields are nil", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelError) + l1F := &testutils.MockL1Source{} + ec := new(fakeEngineController) + + // Passing empty config should behave same as nil + finalizerCfg := &Config{} + + fi := NewFinalizer(context.Background(), logger, &rollup.Config{}, finalizerCfg, l1F, ec) + + require.Equal(t, uint64(defaultFinalityLookback), fi.finalityLookback, "should use default finality lookback when config fields are nil") + require.Equal(t, uint64(finalityDelay), fi.finalityDelay, "should use default finality delay when config fields are nil") + }) + + t.Run("uses alt-da lookback when configured", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelError) + l1F := &testutils.MockL1Source{} + ec := new(fakeEngineController) + + cfg := &rollup.Config{ + AltDAConfig: &rollup.AltDAConfig{ + DAChallengeWindow: 90, + DAResolveWindow: 90, + }, + } + + fi := NewFinalizer(context.Background(), logger, cfg, nil, l1F, ec) + + expectedLookback := uint64(181) // 90 + 90 + 1 + require.Equal(t, expectedLookback, fi.finalityLookback, "should use alt-da calculated lookback") + }) + + t.Run("custom lookback overrides alt-da calculation", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelError) + l1F := &testutils.MockL1Source{} + ec := new(fakeEngineController) + + cfg := &rollup.Config{ + AltDAConfig: &rollup.AltDAConfig{ + DAChallengeWindow: 90, + DAResolveWindow: 90, + }, + } + + customLookback := uint64(300) + finalizerCfg := &Config{ + FinalityLookback: &customLookback, + } + + fi := NewFinalizer(context.Background(), logger, cfg, finalizerCfg, l1F, ec) + + require.Equal(t, customLookback, fi.finalityLookback, "custom lookback should override alt-da calculation") + }) +} diff --git a/op-node/rollup/sequencing/sequencer_test.go b/op-node/rollup/sequencing/sequencer_test.go index bcdd6cdd790..bf8a88419e6 100644 --- a/op-node/rollup/sequencing/sequencer_test.go +++ b/op-node/rollup/sequencing/sequencer_test.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-node/metrics" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" @@ -21,7 +22,6 @@ import ( "github.com/ethereum-optimism/optimism/op-service/clock" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/event" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testutils" ) diff --git a/op-node/rollup/types.go b/op-node/rollup/types.go index 7209663eca7..43cc795b923 100644 --- a/op-node/rollup/types.go +++ b/op-node/rollup/types.go @@ -10,6 +10,7 @@ import ( "time" altda "github.com/ethereum-optimism/optimism/op-alt-da" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" @@ -339,25 +340,25 @@ func (cfg *Config) Check() error { return err } - if err := checkFork(cfg.RegolithTime, cfg.CanyonTime, Regolith, Canyon); err != nil { + if err := checkFork(cfg.RegolithTime, cfg.CanyonTime, forks.Regolith, forks.Canyon); err != nil { return err } - if err := checkFork(cfg.CanyonTime, cfg.DeltaTime, Canyon, Delta); err != nil { + if err := checkFork(cfg.CanyonTime, cfg.DeltaTime, forks.Canyon, forks.Delta); err != nil { return err } - if err := checkFork(cfg.DeltaTime, cfg.EcotoneTime, Delta, Ecotone); err != nil { + if err := checkFork(cfg.DeltaTime, cfg.EcotoneTime, forks.Delta, forks.Ecotone); err != nil { return err } - if err := checkFork(cfg.EcotoneTime, cfg.FjordTime, Ecotone, Fjord); err != nil { + if err := checkFork(cfg.EcotoneTime, cfg.FjordTime, forks.Ecotone, forks.Fjord); err != nil { return err } - if err := checkFork(cfg.FjordTime, cfg.GraniteTime, Fjord, Granite); err != nil { + if err := checkFork(cfg.FjordTime, cfg.GraniteTime, forks.Fjord, forks.Granite); err != nil { return err } - if err := checkFork(cfg.GraniteTime, cfg.HoloceneTime, Granite, Holocene); err != nil { + if err := checkFork(cfg.GraniteTime, cfg.HoloceneTime, forks.Granite, forks.Holocene); err != nil { return err } - if err := checkFork(cfg.HoloceneTime, cfg.IsthmusTime, Holocene, Isthmus); err != nil { + if err := checkFork(cfg.HoloceneTime, cfg.IsthmusTime, forks.Holocene, forks.Isthmus); err != nil { return err } @@ -438,52 +439,52 @@ func (c *Config) IsForkActive(fork ForkName, timestamp uint64) bool { // IsRegolith returns true if the Regolith hardfork is active at or past the given timestamp. func (c *Config) IsRegolith(timestamp uint64) bool { - return c.IsForkActive(Regolith, timestamp) + return c.IsForkActive(forks.Regolith, timestamp) } // IsCanyon returns true if the Canyon hardfork is active at or past the given timestamp. func (c *Config) IsCanyon(timestamp uint64) bool { - return c.IsForkActive(Canyon, timestamp) + return c.IsForkActive(forks.Canyon, timestamp) } // IsDelta returns true if the Delta hardfork is active at or past the given timestamp. func (c *Config) IsDelta(timestamp uint64) bool { - return c.IsForkActive(Delta, timestamp) + return c.IsForkActive(forks.Delta, timestamp) } // IsEcotone returns true if the Ecotone hardfork is active at or past the given timestamp. func (c *Config) IsEcotone(timestamp uint64) bool { - return c.IsForkActive(Ecotone, timestamp) + return c.IsForkActive(forks.Ecotone, timestamp) } // IsFjord returns true if the Fjord hardfork is active at or past the given timestamp. func (c *Config) IsFjord(timestamp uint64) bool { - return c.IsForkActive(Fjord, timestamp) + return c.IsForkActive(forks.Fjord, timestamp) } // IsGranite returns true if the Granite hardfork is active at or past the given timestamp. func (c *Config) IsGranite(timestamp uint64) bool { - return c.IsForkActive(Granite, timestamp) + return c.IsForkActive(forks.Granite, timestamp) } // IsHolocene returns true if the Holocene hardfork is active at or past the given timestamp. func (c *Config) IsHolocene(timestamp uint64) bool { - return c.IsForkActive(Holocene, timestamp) + return c.IsForkActive(forks.Holocene, timestamp) } // IsIsthmus returns true if the Isthmus hardfork is active at or past the given timestamp. func (c *Config) IsIsthmus(timestamp uint64) bool { - return c.IsForkActive(Isthmus, timestamp) + return c.IsForkActive(forks.Isthmus, timestamp) } // IsJovian returns true if the Jovian hardfork is active at or past the given timestamp. func (c *Config) IsJovian(timestamp uint64) bool { - return c.IsForkActive(Jovian, timestamp) + return c.IsForkActive(forks.Jovian, timestamp) } // IsInterop returns true if the Interop hardfork is active at or past the given timestamp. func (c *Config) IsInterop(timestamp uint64) bool { - return c.IsForkActive(Interop, timestamp) + return c.IsForkActive(forks.Interop, timestamp) } func (c *Config) IsRegolithActivationBlock(l2BlockTime uint64) bool { @@ -561,26 +562,31 @@ func (c *Config) IsInteropActivationBlock(l2BlockTime uint64) bool { func (c *Config) ActivationTime(fork ForkName) *uint64 { // NEW FORKS MUST BE ADDED HERE switch fork { - case Interop: + case forks.Interop: return c.InteropTime - case Jovian: + case forks.Jovian: return c.JovianTime - case Isthmus: + case forks.Isthmus: return c.IsthmusTime - case Holocene: + case forks.Holocene: return c.HoloceneTime - case Granite: + case forks.Granite: return c.GraniteTime - case Fjord: + case forks.Fjord: return c.FjordTime - case Ecotone: + case forks.Ecotone: return c.EcotoneTime - case Delta: + case forks.Delta: return c.DeltaTime - case Canyon: + case forks.Canyon: return c.CanyonTime - case Regolith: + case forks.Regolith: return c.RegolithTime + + // Optional forks + case forks.PectraBlobSchedule: + return c.PectraBlobScheduleTime + default: panic(fmt.Sprintf("unknown fork: %v", fork)) } @@ -589,26 +595,31 @@ func (c *Config) ActivationTime(fork ForkName) *uint64 { func (c *Config) SetActivationTime(fork ForkName, timestamp *uint64) { // NEW FORKS MUST BE ADDED HERE switch fork { - case Interop: + case forks.Interop: c.InteropTime = timestamp - case Jovian: + case forks.Jovian: c.JovianTime = timestamp - case Isthmus: + case forks.Isthmus: c.IsthmusTime = timestamp - case Holocene: + case forks.Holocene: c.HoloceneTime = timestamp - case Granite: + case forks.Granite: c.GraniteTime = timestamp - case Fjord: + case forks.Fjord: c.FjordTime = timestamp - case Ecotone: + case forks.Ecotone: c.EcotoneTime = timestamp - case Delta: + case forks.Delta: c.DeltaTime = timestamp - case Canyon: + case forks.Canyon: c.CanyonTime = timestamp - case Regolith: + case forks.Regolith: c.RegolithTime = timestamp + + // Optional forks + case forks.PectraBlobSchedule: + c.PectraBlobScheduleTime = timestamp + default: panic(fmt.Sprintf("unknown fork: %v", fork)) } @@ -623,7 +634,7 @@ func (c *Config) IsActivationBlock(oldTime, newTime uint64) ForkName { return fork } } - return None + return forks.None } func (c *Config) IsActivationBlockForFork(l2BlockTime uint64, fork ForkName) bool { @@ -638,17 +649,17 @@ func (c *Config) ActivateAtGenesis(hardfork ForkName) { c.ActivateAt(hardfork, 0) } -var scheduleableForks = ForksFrom(Regolith) +var scheduleableForks = forks.From(forks.Regolith) // ActivateAt updates the config to activate the given fork at the given timestamp, all previous // forks at genesis, and all later forks are disabled. func (c *Config) ActivateAt(fork ForkName, timestamp uint64) { - if !IsValidFork(fork) { + if !forks.IsValid(fork) { panic(fmt.Sprintf("invalid fork: %s", fork)) } ts := new(uint64) // Special case: if only activating Bedrock, all scheduleable forks are disabled. - if fork == Bedrock { + if fork == forks.Bedrock { ts = nil } for i, f := range scheduleableForks { diff --git a/op-node/rollup/types_test.go b/op-node/rollup/types_test.go index 90069e22971..b1f8efbe528 100644 --- a/op-node/rollup/types_test.go +++ b/op-node/rollup/types_test.go @@ -12,16 +12,17 @@ import ( "testing" "time" - "github.com/ethereum-optimism/optimism/op-service/ptr" - "github.com/ethereum-optimism/optimism/op-service/testlog" - "github.com/ethereum/go-ethereum/log" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/ptr" + "github.com/ethereum-optimism/optimism/op-service/testlog" ) func randConfig() *Config { @@ -828,34 +829,34 @@ func TestGetPayloadVersion(t *testing.T) { func TestConfig_IsActivationBlock(t *testing.T) { // Map of fork names to their config field setters - forks := []struct { - name ForkName + tests := []struct { + name forks.Name setTime func(cfg *Config, ts uint64) }{ - {Canyon, func(cfg *Config, ts uint64) { cfg.CanyonTime = &ts }}, - {Delta, func(cfg *Config, ts uint64) { cfg.DeltaTime = &ts }}, - {Ecotone, func(cfg *Config, ts uint64) { cfg.EcotoneTime = &ts }}, - {Fjord, func(cfg *Config, ts uint64) { cfg.FjordTime = &ts }}, - {Granite, func(cfg *Config, ts uint64) { cfg.GraniteTime = &ts }}, - {Holocene, func(cfg *Config, ts uint64) { cfg.HoloceneTime = &ts }}, - {Isthmus, func(cfg *Config, ts uint64) { cfg.IsthmusTime = &ts }}, - {Interop, func(cfg *Config, ts uint64) { cfg.InteropTime = &ts }}, + {forks.Canyon, func(cfg *Config, ts uint64) { cfg.CanyonTime = &ts }}, + {forks.Delta, func(cfg *Config, ts uint64) { cfg.DeltaTime = &ts }}, + {forks.Ecotone, func(cfg *Config, ts uint64) { cfg.EcotoneTime = &ts }}, + {forks.Fjord, func(cfg *Config, ts uint64) { cfg.FjordTime = &ts }}, + {forks.Granite, func(cfg *Config, ts uint64) { cfg.GraniteTime = &ts }}, + {forks.Holocene, func(cfg *Config, ts uint64) { cfg.HoloceneTime = &ts }}, + {forks.Isthmus, func(cfg *Config, ts uint64) { cfg.IsthmusTime = &ts }}, + {forks.Interop, func(cfg *Config, ts uint64) { cfg.InteropTime = &ts }}, } - for _, fork := range forks { + for _, tc := range tests { ts := uint64(100) cfg := &Config{} - fork.setTime(cfg, ts) + tc.setTime(cfg, ts) - t.Run(string(fork.name), func(t *testing.T) { + t.Run(string(tc.name), func(t *testing.T) { // Crossing the fork boundary should return the fork name - require.Equal(t, fork.name, cfg.IsActivationBlock(ts-1, ts)) - require.Equal(t, fork.name, cfg.IsActivationBlock(ts-1, ts+10)) + require.Equal(t, tc.name, cfg.IsActivationBlock(ts-1, ts)) + require.Equal(t, tc.name, cfg.IsActivationBlock(ts-1, ts+10)) // Not crossing the fork boundary should return None - require.Equal(t, None, cfg.IsActivationBlock(ts, ts+1)) - require.Equal(t, None, cfg.IsActivationBlock(ts+1, ts+2)) + require.Equal(t, forks.None, cfg.IsActivationBlock(ts, ts+1)) + require.Equal(t, forks.None, cfg.IsActivationBlock(ts+1, ts+2)) // Before the fork - require.Equal(t, None, cfg.IsActivationBlock(ts-10, ts-1)) + require.Equal(t, forks.None, cfg.IsActivationBlock(ts-10, ts-1)) }) } } @@ -993,8 +994,8 @@ func TestConfig_ActivationBlockAndForFork(t *testing.T) { // IsActivationBlock should detect boundary crossing irrespective of block time granularity require.Equal(t, fork, cfg.IsActivationBlock(ts-1, ts)) require.Equal(t, fork, cfg.IsActivationBlock(ts-1, ts+10)) - require.Equal(t, None, cfg.IsActivationBlock(ts, ts+1)) - require.Equal(t, None, cfg.IsActivationBlock(ts+1, ts+2)) + require.Equal(t, forks.None, cfg.IsActivationBlock(ts, ts+1)) + require.Equal(t, forks.None, cfg.IsActivationBlock(ts+1, ts+2)) // IsActivationBlockForFork should be true for the first block(s) at/after activation, // i.e. for times in [ts, ts+BlockTime-1], and false otherwise. @@ -1014,7 +1015,7 @@ func TestConfig_ActivateAt(t *testing.T) { t.Run("Ecotone", func(t *testing.T) { var cfg Config ts := uint64(100) - cfg.ActivateAt(Ecotone, ts) + cfg.ActivateAt(forks.Ecotone, ts) require.Equal(t, Config{ RegolithTime: ptr.Zero64, CanyonTime: ptr.Zero64, @@ -1026,11 +1027,11 @@ func TestConfig_ActivateAt(t *testing.T) { t.Run("LatestFork", func(t *testing.T) { var cfg Config ts := uint64(100) - cfg.ActivateAt(LatestFork, ts) + cfg.ActivateAt(forks.Latest, ts) for _, f := range scheduleableForks { at := cfg.ActivationTime(f) require.NotNil(t, at) - if f == LatestFork { + if f == forks.Latest { require.EqualValues(t, ts, *at) } else { // prior forks at genesis (0) @@ -1042,7 +1043,7 @@ func TestConfig_ActivateAt(t *testing.T) { // Bedrock special case: disable all scheduleable forks t.Run("Bedrock", func(t *testing.T) { var cfg Config - cfg.ActivateAt(Bedrock, 0) + cfg.ActivateAt(forks.Bedrock, 0) for _, f := range scheduleableForks { require.Nil(t, cfg.ActivationTime(f)) } @@ -1055,7 +1056,7 @@ func TestConfig_ActivateAtGenesis(t *testing.T) { // Activate Ecotone at genesis t.Run("Ecotone", func(t *testing.T) { var cfg Config - cfg.ActivateAtGenesis(Ecotone) + cfg.ActivateAtGenesis(forks.Ecotone) require.Equal(t, Config{ RegolithTime: ptr.Zero64, CanyonTime: ptr.Zero64, @@ -1066,7 +1067,7 @@ func TestConfig_ActivateAtGenesis(t *testing.T) { t.Run("LatestFork", func(t *testing.T) { var cfg Config - cfg.ActivateAtGenesis(LatestFork) + cfg.ActivateAtGenesis(forks.Latest) for _, f := range scheduleableForks { at := cfg.ActivationTime(f) require.NotNil(t, at) @@ -1077,7 +1078,7 @@ func TestConfig_ActivateAtGenesis(t *testing.T) { // Bedrock special case: disable all scheduleable forks t.Run("Bedrock", func(t *testing.T) { var cfg Config - cfg.ActivateAtGenesis(Bedrock) + cfg.ActivateAtGenesis(forks.Bedrock) for _, f := range scheduleableForks { require.Nil(t, cfg.ActivationTime(f)) } diff --git a/op-node/service.go b/op-node/service.go index c87f61af6f7..6c10e1718be 100644 --- a/op-node/service.go +++ b/op-node/service.go @@ -21,6 +21,7 @@ import ( "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/driver" "github.com/ethereum-optimism/optimism/op-node/rollup/engine" + "github.com/ethereum-optimism/optimism/op-node/rollup/finality" "github.com/ethereum-optimism/optimism/op-node/rollup/interop" "github.com/ethereum-optimism/optimism/op-node/rollup/sync" "github.com/ethereum-optimism/optimism/op-service/cliiface" @@ -202,7 +203,7 @@ func NewConfigPersistence(ctx cliiface.Context) config.ConfigPersistence { } func NewDriverConfig(ctx cliiface.Context) *driver.Config { - return &driver.Config{ + cfg := &driver.Config{ VerifierConfDepth: ctx.Uint64(flags.VerifierL1Confs.Name), SequencerConfDepth: ctx.Uint64(flags.SequencerL1Confs.Name), SequencerEnabled: ctx.Bool(flags.SequencerEnabledFlag.Name), @@ -210,6 +211,20 @@ func NewDriverConfig(ctx cliiface.Context) *driver.Config { SequencerMaxSafeLag: ctx.Uint64(flags.SequencerMaxSafeLagFlag.Name), RecoverMode: ctx.Bool(flags.SequencerRecoverMode.Name), } + + // Populate finality config from flags. A finality config with null fields + // is handled the same way as a null finality config. + cfg.Finalizer = &finality.Config{} + if ctx.IsSet(flags.FinalityLookbackFlag.Name) { + lookback := ctx.Uint64(flags.FinalityLookbackFlag.Name) + cfg.Finalizer.FinalityLookback = &lookback + } + if ctx.IsSet(flags.FinalityDelayFlag.Name) { + delay := ctx.Uint64(flags.FinalityDelayFlag.Name) + cfg.Finalizer.FinalityDelay = &delay + } + + return cfg } func NewRollupConfigFromCLI(log log.Logger, ctx cliiface.Context) (*rollup.Config, error) { @@ -257,45 +272,12 @@ Conflicting configuration is deprecated, and will stop the op-node from starting } func applyOverrides(ctx cliiface.Context, rollupConfig *rollup.Config) { - if ctx.IsSet(opflags.CanyonOverrideFlagName) { - canyon := ctx.Uint64(opflags.CanyonOverrideFlagName) - rollupConfig.CanyonTime = &canyon - } - if ctx.IsSet(opflags.DeltaOverrideFlagName) { - delta := ctx.Uint64(opflags.DeltaOverrideFlagName) - rollupConfig.DeltaTime = &delta - } - if ctx.IsSet(opflags.EcotoneOverrideFlagName) { - ecotone := ctx.Uint64(opflags.EcotoneOverrideFlagName) - rollupConfig.EcotoneTime = &ecotone - } - if ctx.IsSet(opflags.FjordOverrideFlagName) { - fjord := ctx.Uint64(opflags.FjordOverrideFlagName) - rollupConfig.FjordTime = &fjord - } - if ctx.IsSet(opflags.GraniteOverrideFlagName) { - granite := ctx.Uint64(opflags.GraniteOverrideFlagName) - rollupConfig.GraniteTime = &granite - } - if ctx.IsSet(opflags.HoloceneOverrideFlagName) { - holocene := ctx.Uint64(opflags.HoloceneOverrideFlagName) - rollupConfig.HoloceneTime = &holocene - } - if ctx.IsSet(opflags.PectraBlobScheduleOverrideFlagName) { - pectrablobschedule := ctx.Uint64(opflags.PectraBlobScheduleOverrideFlagName) - rollupConfig.PectraBlobScheduleTime = &pectrablobschedule - } - if ctx.IsSet(opflags.IsthmusOverrideFlagName) { - isthmus := ctx.Uint64(opflags.IsthmusOverrideFlagName) - rollupConfig.IsthmusTime = &isthmus - } - if ctx.IsSet(opflags.JovianOverrideFlagName) { - jovian := ctx.Uint64(opflags.JovianOverrideFlagName) - rollupConfig.JovianTime = &jovian - } - if ctx.IsSet(opflags.InteropOverrideFlagName) { - interop := ctx.Uint64(opflags.InteropOverrideFlagName) - rollupConfig.InteropTime = &interop + for _, fork := range opflags.OverridableForks { + flagName := opflags.OverrideName(fork) + if ctx.IsSet(flagName) { + timestamp := ctx.Uint64(flagName) + rollupConfig.SetActivationTime(fork, ×tamp) + } } } diff --git a/op-node/withdrawals/utils.go b/op-node/withdrawals/utils.go index 7654b27e2b4..99d662502d4 100644 --- a/op-node/withdrawals/utils.go +++ b/op-node/withdrawals/utils.go @@ -15,11 +15,11 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient/gethclient" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "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" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" ) diff --git a/op-program/Dockerfile.repro.dockerignore b/op-program/Dockerfile.repro.dockerignore index 15d6cf76382..1cf8173ca25 100644 --- a/op-program/Dockerfile.repro.dockerignore +++ b/op-program/Dockerfile.repro.dockerignore @@ -4,6 +4,7 @@ !go.* # internal dependencies !cannon/ +!op-core/ !op-alt-da/ !op-node/ !op-preimage/ diff --git a/op-program/Dockerfile.vmcompat.dockerignore b/op-program/Dockerfile.vmcompat.dockerignore index 15d6cf76382..1cf8173ca25 100644 --- a/op-program/Dockerfile.vmcompat.dockerignore +++ b/op-program/Dockerfile.vmcompat.dockerignore @@ -4,6 +4,7 @@ !go.* # internal dependencies !cannon/ +!op-core/ !op-alt-da/ !op-node/ !op-preimage/ diff --git a/op-program/client/l2/engine.go b/op-program/client/l2/engine.go index 2d3cea18190..6dc0a5d2f6f 100644 --- a/op-program/client/l2/engine.go +++ b/op-program/client/l2/engine.go @@ -5,12 +5,12 @@ import ( "errors" "fmt" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-program/client/l2/engineapi" l2Types "github.com/ethereum-optimism/optimism/op-program/client/l2/types" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" diff --git a/op-program/client/l2/engineapi/block_processor.go b/op-program/client/l2/engineapi/block_processor.go index be7178b32ed..edf264868a7 100644 --- a/op-program/client/l2/engineapi/block_processor.go +++ b/op-program/client/l2/engineapi/block_processor.go @@ -5,8 +5,8 @@ import ( "fmt" "math/big" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc/eip1559" diff --git a/op-program/client/l2/engineapi/l2_engine_api_test.go b/op-program/client/l2/engineapi/l2_engine_api_test.go index 3828e3a28fd..01fbfcc7468 100644 --- a/op-program/client/l2/engineapi/l2_engine_api_test.go +++ b/op-program/client/l2/engineapi/l2_engine_api_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" - "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/beacon/engine" @@ -179,7 +179,7 @@ func createGenesisWithIsthmusTimeOffset(forkTimeOffset uint64) *core.Genesis { }, } - deployConfig.ActivateForkAtOffset(rollup.Isthmus, forkTimeOffset) + deployConfig.ActivateForkAtOffset(forks.Isthmus, forkTimeOffset) l1Genesis, err := genesis.NewL1Genesis(deployConfig) if err != nil { diff --git a/op-program/client/l2/oracle.go b/op-program/client/l2/oracle.go index c490b60911b..af5f3249afd 100644 --- a/op-program/client/l2/oracle.go +++ b/op-program/client/l2/oracle.go @@ -8,11 +8,11 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum-optimism/optimism/op-core/predeploys" preimage "github.com/ethereum-optimism/optimism/op-preimage" l2Types "github.com/ethereum-optimism/optimism/op-program/client/l2/types" "github.com/ethereum-optimism/optimism/op-program/client/mpt" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" ) // StateOracle defines the high-level API used to retrieve L2 state data pre-images diff --git a/op-service/eth/block_info.go b/op-service/eth/block_info.go index 3d09d8ba535..8d28b38c253 100644 --- a/op-service/eth/block_info.go +++ b/op-service/eth/block_info.go @@ -34,6 +34,7 @@ type BlockInfo interface { // HeaderRLP returns the RLP of the block header as per consensus rules // Returns an error if the header RLP could not be written HeaderRLP() ([]byte, error) + Header() *types.Header } func InfoToL1BlockRef(info BlockInfo) L1BlockRef { @@ -162,7 +163,11 @@ func (h *headerBlockInfo) HeaderRLP() ([]byte, error) { return rlp.EncodeToBytes(h.header) // usage is rare and mostly 1-time-use, no need to cache } -func (h headerBlockInfo) WithdrawalsRoot() *common.Hash { +func (h *headerBlockInfo) Header() *types.Header { + return h.header +} + +func (h *headerBlockInfo) WithdrawalsRoot() *common.Hash { return h.header.WithdrawalsHash } diff --git a/op-service/flags/flags.go b/op-service/flags/flags.go index 4ec4e59a918..8bc54ed04c2 100644 --- a/op-service/flags/flags.go +++ b/op-service/flags/flags.go @@ -6,101 +6,46 @@ import ( "github.com/urfave/cli/v2" + "github.com/ethereum-optimism/optimism/op-core/forks" "github.com/ethereum-optimism/optimism/op-node/chaincfg" opservice "github.com/ethereum-optimism/optimism/op-service" "github.com/ethereum-optimism/optimism/op-service/cliiface" ) const ( - RollupConfigFlagName = "rollup.config" - NetworkFlagName = "network" - CanyonOverrideFlagName = "override.canyon" - DeltaOverrideFlagName = "override.delta" - EcotoneOverrideFlagName = "override.ecotone" - FjordOverrideFlagName = "override.fjord" - GraniteOverrideFlagName = "override.granite" - HoloceneOverrideFlagName = "override.holocene" - PectraBlobScheduleOverrideFlagName = "override.pectrablobschedule" - IsthmusOverrideFlagName = "override.isthmus" - InteropOverrideFlagName = "override.interop" - JovianOverrideFlagName = "override.jovian" + RollupConfigFlagName = "rollup.config" + NetworkFlagName = "network" ) +// OverridableForks lists all forks that can be overridden via CLI flags or env vars. +// It's all mainline forks from Canyon onwards, plus all optional forks. +var OverridableForks = append(forks.From(forks.Canyon), forks.AllOpt...) + +func OverrideName(f forks.Name) string { return "override." + string(f) } + +func OverrideEnvVar(envPrefix string, fork forks.Name) []string { + return opservice.PrefixEnvVar(envPrefix, "OVERRIDE_"+strings.ToUpper(string(fork))) +} + func CLIFlags(envPrefix string, category string) []cli.Flag { - return []cli.Flag{ - &cli.Uint64Flag{ - Name: CanyonOverrideFlagName, - Usage: "Manually specify the Canyon fork timestamp, overriding the bundled setting", - EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_CANYON"), - Hidden: false, - Category: category, - }, - &cli.Uint64Flag{ - Name: DeltaOverrideFlagName, - Usage: "Manually specify the Delta fork timestamp, overriding the bundled setting", - EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_DELTA"), - Hidden: false, - Category: category, - }, - &cli.Uint64Flag{ - Name: EcotoneOverrideFlagName, - Usage: "Manually specify the Ecotone fork timestamp, overriding the bundled setting", - EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_ECOTONE"), - Hidden: false, - Category: category, - }, - &cli.Uint64Flag{ - Name: FjordOverrideFlagName, - Usage: "Manually specify the Fjord fork timestamp, overriding the bundled setting", - EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_FJORD"), - Hidden: false, - Category: category, - }, - &cli.Uint64Flag{ - Name: GraniteOverrideFlagName, - Usage: "Manually specify the Granite fork timestamp, overriding the bundled setting", - EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_GRANITE"), - Hidden: false, - Category: category, - }, - &cli.Uint64Flag{ - Name: HoloceneOverrideFlagName, - Usage: "Manually specify the Holocene fork timestamp, overriding the bundled setting", - EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_HOLOCENE"), - Hidden: false, - Category: category, - }, - &cli.Uint64Flag{ - Name: PectraBlobScheduleOverrideFlagName, - Usage: "Manually specify the PectraBlobSchedule fork timestamp, overriding the bundled setting", - EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_PECTRABLOBSCHEDULE"), - Hidden: false, - Category: category, - }, - &cli.Uint64Flag{ - Name: IsthmusOverrideFlagName, - Usage: "Manually specify the Isthmus fork timestamp, overriding the bundled setting", - EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_ISTHMUS"), - Hidden: false, - Category: category, - }, - &cli.Uint64Flag{ - Name: JovianOverrideFlagName, - Usage: "Manually specify the Jovian fork timestamp, overriding the bundled setting", - EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_JOVIAN"), - Hidden: false, - Category: category, - }, - &cli.Uint64Flag{ - Name: InteropOverrideFlagName, - Usage: "Manually specify the Interop fork timestamp, overriding the bundled setting", - EnvVars: opservice.PrefixEnvVar(envPrefix, "OVERRIDE_INTEROP"), - Hidden: false, - Category: category, - }, + return append(CLIOverrideFlags(envPrefix, category), CLINetworkFlag(envPrefix, category), CLIRollupConfigFlag(envPrefix, category), + ) +} + +func CLIOverrideFlags(envPrefix string, category string) []cli.Flag { + var flags []cli.Flag + for _, fork := range OverridableForks { + flags = append(flags, + &cli.Uint64Flag{ + Name: OverrideName(fork), + Usage: fmt.Sprintf("Manually specify the %s fork timestamp, overriding the bundled setting", fork), + EnvVars: OverrideEnvVar(envPrefix, fork), + Category: category, + }) } + return flags } func CLINetworkFlag(envPrefix string, category string) cli.Flag { diff --git a/op-service/sources/l2_client.go b/op-service/sources/l2_client.go index f5bc5fb358a..fc826d68a99 100644 --- a/op-service/sources/l2_client.go +++ b/op-service/sources/l2_client.go @@ -9,12 +9,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/apis" "github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/sources/caching" ) diff --git a/op-service/sources/types.go b/op-service/sources/types.go index efbbe78ed2c..c9d6cdeb178 100644 --- a/op-service/sources/types.go +++ b/op-service/sources/types.go @@ -14,8 +14,8 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" ) // Note: these types are used, instead of the geth types, to enable: diff --git a/op-service/testutils/l1info.go b/op-service/testutils/l1info.go index d15c9790c61..294b637b08d 100644 --- a/op-service/testutils/l1info.go +++ b/op-service/testutils/l1info.go @@ -36,6 +36,10 @@ type MockBlockInfo struct { InfoWithdrawalsRoot *common.Hash } +func (l *MockBlockInfo) Header() *types.Header { + panic("not implemented") +} + func (l *MockBlockInfo) Hash() common.Hash { return l.InfoHash } diff --git a/op-service/txinclude/isthmus_cost_oracle.go b/op-service/txinclude/isthmus_cost_oracle.go index 4083b87328c..a999d5c40e0 100644 --- a/op-service/txinclude/isthmus_cost_oracle.go +++ b/op-service/txinclude/isthmus_cost_oracle.go @@ -7,8 +7,8 @@ import ( "sync/atomic" "time" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/signer" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" diff --git a/op-service/txintent/bindings/FaultDisputeGame.go b/op-service/txintent/bindings/FaultDisputeGame.go index 9a4a01aab55..695e05f6b66 100644 --- a/op-service/txintent/bindings/FaultDisputeGame.go +++ b/op-service/txintent/bindings/FaultDisputeGame.go @@ -45,15 +45,18 @@ type FaultDisputeGame struct { L1Head func() TypedCall[common.Hash] `sol:"l1Head"` L2SequenceNumber func() TypedCall[*big.Int] `sol:"l2SequenceNumber"` Status func() TypedCall[uint8] `sol:"status"` + GameType func() TypedCall[uint32] `sol:"gameType"` // IFaultDisputeGame.sol read methods - ClaimDataLen func() TypedCall[*big.Int] `sol:"claimDataLen"` - ClaimData func(*big.Int) TypedCall[ClaimData] `sol:"claimData"` - GetRequiredBond func(position *Uint128) TypedCall[*big.Int] `sol:"getRequiredBond"` - MaxGameDepth func() TypedCall[*big.Int] `sol:"maxGameDepth"` - SplitDepth func() TypedCall[*big.Int] `sol:"splitDepth"` - SubGame func(parentClaimIndex *big.Int, subGameIndex *big.Int) TypedCall[*big.Int] `sol:"subgame"` - MaxClockDuration func() TypedCall[uint64] `sol:"maxClockDuration"` + ClaimDataLen func() TypedCall[*big.Int] `sol:"claimDataLen"` + ClaimData func(*big.Int) TypedCall[ClaimData] `sol:"claimData"` + GetRequiredBond func(position *Uint128) TypedCall[*big.Int] `sol:"getRequiredBond"` + MaxGameDepth func() TypedCall[*big.Int] `sol:"maxGameDepth"` + SplitDepth func() TypedCall[*big.Int] `sol:"splitDepth"` + SubGame func(parentClaimIndex *big.Int, subGameIndex *big.Int) TypedCall[*big.Int] `sol:"subgame"` + MaxClockDuration func() TypedCall[uint64] `sol:"maxClockDuration"` + StartingBlockNumber func() TypedCall[uint64] `sol:"startingBlockNumber"` + StartingSequenceNumber func() TypedCall[uint64] `sol:"startingSequenceNumber"` // IFaultDisputeGame.sol write methods Move func(targetClaim common.Hash, targetClaimIndex *big.Int, newClaim common.Hash, isAttack bool) TypedCall[any] `sol:"move"` diff --git a/op-service/txmgr/cli_test.go b/op-service/txmgr/cli_test.go index 892a9d498d5..759ce037d65 100644 --- a/op-service/txmgr/cli_test.go +++ b/op-service/txmgr/cli_test.go @@ -44,9 +44,9 @@ func configForArgs(args ...string) CLIConfig { } func TestFallbackToOsakaCellProofTimeIfKnown(t *testing.T) { - // No override, but we detect the L1 is Mainnet (no Osaka time yet) + // No override, but we detect the L1 is Mainnet cellProofTime := fallbackToOsakaCellProofTimeIfKnown(big.NewInt(1), math.MaxUint64) - require.Equal(t, uint64(18446744073709551615), cellProofTime) + require.Equal(t, uint64(1764798551), cellProofTime) // No override, but we detect the L1 is Sepolia cellProofTime = fallbackToOsakaCellProofTimeIfKnown(big.NewInt(11155111), math.MaxUint64) diff --git a/op-supervisor/supervisor/backend/processors/log_processor_test.go b/op-supervisor/supervisor/backend/processors/log_processor_test.go index 7d7580a15dd..05b6dbcb945 100644 --- a/op-supervisor/supervisor/backend/processors/log_processor_test.go +++ b/op-supervisor/supervisor/backend/processors/log_processor_test.go @@ -10,8 +10,8 @@ import ( "github.com/ethereum/go-ethereum/common" ethTypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) diff --git a/ops/ai-eng/contracts-test-maintenance/VERSION b/ops/ai-eng/contracts-test-maintenance/VERSION index 26aaba0e866..6085e946503 100644 --- a/ops/ai-eng/contracts-test-maintenance/VERSION +++ b/ops/ai-eng/contracts-test-maintenance/VERSION @@ -1 +1 @@ -1.2.0 +1.2.1 diff --git a/ops/ai-eng/contracts-test-maintenance/prompt/prompt.md b/ops/ai-eng/contracts-test-maintenance/prompt/prompt.md index 1adcc5f8df4..c2dd27ace99 100644 --- a/ops/ai-eng/contracts-test-maintenance/prompt/prompt.md +++ b/ops/ai-eng/contracts-test-maintenance/prompt/prompt.md @@ -543,6 +543,11 @@ contract L1FeeVault_Version_Test { - MUST pass before creating any PR 4. Search for any vm.expectRevert() without arguments and fix them +**INTERPRETING CI STATUS:** +- Only investigate actual code failures: build errors, test failures, lint violations +- "Code Review Requirements" status = waiting for reviewer approvals, not code issues +- Test-only changes cannot affect these CI jobs - skip them: `diff-asterisc-bytecode`, `op-program-compat` + **ZERO TOLERANCE - CI FAILURES:** - vm.expectRevert() must ALWAYS have arguments: either selector or bytes message - ALL tests must pass - no exceptions diff --git a/ops/docker/op-stack-go/Dockerfile.dockerignore b/ops/docker/op-stack-go/Dockerfile.dockerignore index 16a60a2bff6..280b1603456 100644 --- a/ops/docker/op-stack-go/Dockerfile.dockerignore +++ b/ops/docker/op-stack-go/Dockerfile.dockerignore @@ -4,6 +4,7 @@ !/cannon !/devnet-sdk +!/op-core !/op-batcher !/op-chain-ops !/op-deployer diff --git a/packages/contracts-bedrock/interfaces/safe/ITimelockGuard.sol b/packages/contracts-bedrock/interfaces/safe/ITimelockGuard.sol index 8d462136ed2..b96b3ce9747 100644 --- a/packages/contracts-bedrock/interfaces/safe/ITimelockGuard.sol +++ b/packages/contracts-bedrock/interfaces/safe/ITimelockGuard.sol @@ -12,10 +12,13 @@ interface ITimelockGuard { Cancelled, Executed } + struct ScheduledTransaction { + bytes32 txHash; uint256 executionTime; TransactionState state; ExecTransactionParams params; + uint256 nonce; } struct ExecTransactionParams { diff --git a/packages/contracts-bedrock/scripts/deploy/GenerateOPCMMigrateCalldata.sol b/packages/contracts-bedrock/scripts/deploy/GenerateOPCMMigrateCalldata.sol index 86a3a00d270..a33d0fae120 100644 --- a/packages/contracts-bedrock/scripts/deploy/GenerateOPCMMigrateCalldata.sol +++ b/packages/contracts-bedrock/scripts/deploy/GenerateOPCMMigrateCalldata.sol @@ -20,6 +20,7 @@ import { stdJson } from "forge-std/StdJson.sol"; /// Config example: /// { /// "cannonPrestate": "0x1234567890abcdef1234567890abcdef12345678", +/// "cannonKonaPrestate": "0x1122334455abcdef1234567890abcdef12345678", /// "usePermissionlessGame": true, /// "startingAnchorRoot": { /// "root": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd", @@ -45,6 +46,7 @@ import { stdJson } from "forge-std/StdJson.sol"; /// } contract GenerateOPCMMigrateCalldata is Script { bytes32 cannonPrestate; + bytes32 cannonKonaPrestate; bool usePermissionlessGame; Proposal startingAnchorRoot; address proposer; @@ -73,6 +75,7 @@ contract GenerateOPCMMigrateCalldata is Script { cannonPrestate = stdJson.readBytes32(json, "$.cannonPrestate"); require(cannonPrestate != bytes32(0), "GenerateOPCMMigrateCalldata: cannonPrestate cannot be 0"); + cannonKonaPrestate = stdJson.readBytes32(json, "$.cannonKonaPrestate"); usePermissionlessGame = stdJson.readBool(json, "$.usePermissionlessGame"); startingAnchorRoot = Proposal({ @@ -121,8 +124,7 @@ contract GenerateOPCMMigrateCalldata is Script { opChainConfigs[i] = IOPContractsManager.OpChainConfig({ systemConfigProxy: ISystemConfig(j[i].systemConfigProxy), cannonPrestate: Claim.wrap(cannonPrestate), - // TODO(#17743): cannon-kona for opcm.migrate - cannonKonaPrestate: Claim.wrap(bytes32(0)) + cannonKonaPrestate: Claim.wrap(cannonKonaPrestate) }); require( opChainConfigs[i].systemConfigProxy != ISystemConfig(address(0)), diff --git a/packages/contracts-bedrock/scripts/go-ffi/differential-testing.go b/packages/contracts-bedrock/scripts/go-ffi/differential-testing.go index 7c328d23f26..2bdb3e3ef16 100644 --- a/packages/contracts-bedrock/scripts/go-ffi/differential-testing.go +++ b/packages/contracts-bedrock/scripts/go-ffi/differential-testing.go @@ -20,8 +20,8 @@ import ( "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" "github.com/ethereum-optimism/optimism/cannon/mipsevm/memory" "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" + "github.com/ethereum-optimism/optimism/op-core/predeploys" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/predeploys" ) // ABI types diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInteropMigrator.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInteropMigrator.json index e50b7a602ee..5644c7edb07 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInteropMigrator.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInteropMigrator.json @@ -409,6 +409,11 @@ "name": "OPContractsManager_InvalidGameType", "type": "error" }, + { + "inputs": [], + "name": "PrestateNotSet", + "type": "error" + }, { "inputs": [], "name": "ReservedBitsSet", diff --git a/packages/contracts-bedrock/snapshots/abi/SaferSafes.json b/packages/contracts-bedrock/snapshots/abi/SaferSafes.json index e3656e7a7c7..5224ed6c5f1 100644 --- a/packages/contracts-bedrock/snapshots/abi/SaferSafes.json +++ b/packages/contracts-bedrock/snapshots/abi/SaferSafes.json @@ -305,6 +305,11 @@ "outputs": [ { "components": [ + { + "internalType": "bytes32", + "name": "txHash", + "type": "bytes32" + }, { "internalType": "uint256", "name": "executionTime", @@ -366,6 +371,11 @@ "internalType": "struct TimelockGuard.ExecTransactionParams", "name": "params", "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" } ], "internalType": "struct TimelockGuard.ScheduledTransaction[]", @@ -475,6 +485,11 @@ "outputs": [ { "components": [ + { + "internalType": "bytes32", + "name": "txHash", + "type": "bytes32" + }, { "internalType": "uint256", "name": "executionTime", @@ -536,6 +551,11 @@ "internalType": "struct TimelockGuard.ExecTransactionParams", "name": "params", "type": "tuple" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" } ], "internalType": "struct TimelockGuard.ScheduledTransaction", diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 0b1609d946e..8fe873558cd 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -24,8 +24,8 @@ "sourceCodeHash": "0xfca613b5d055ffc4c3cbccb0773ddb9030abedc1aa6508c9e2e7727cc0cd617b" }, "src/L1/OPContractsManager.sol:OPContractsManager": { - "initCodeHash": "0xaf9f3fe706ae2a15108451d7e665208254be8b6d398c3e738c8887a0f8cd7903", - "sourceCodeHash": "0xba3c7ef4834fda6df516249a77ef2ff6d7c512cf694f4322e696e57377086eec" + "initCodeHash": "0x6bf74671476f7a6c5d35cad90e16c7d0c1b1e7c4d33fb5f8e0966e1e3ca9cfe8", + "sourceCodeHash": "0x1e5421e93901d3a2b1c6021acf71b443bf66af4a9710ddbb331b1f8419e90dde" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { "initCodeHash": "0x0c8b15453d0f0bc5d9af07f104505e0bbb2b358f0df418289822fb73a8652b30", @@ -224,8 +224,8 @@ "sourceCodeHash": "0x7fc4789b082bc8ecd29c4c75a06058f0ff0b72f1c1028a42db6f1c35269c8865" }, "src/safe/SaferSafes.sol:SaferSafes": { - "initCodeHash": "0x2bee3bc687583bae2cb88edcf25ebe277b8d34b30bf9faac55ae6ec80080b8b9", - "sourceCodeHash": "0xed36bffcde1bf806a9bd9b599296f4818a6c123f5277d2f3e68635cb3f22973d" + "initCodeHash": "0xea63f8c74f2ce10cc53e460b5f7f5006a06ab5612adc7253885a1ca3df124adb", + "sourceCodeHash": "0x169dc281821d3951fb399deefb0b84021b8172cf32ca03526686421bb6478cb4" }, "src/universal/OptimismMintableERC20.sol:OptimismMintableERC20": { "initCodeHash": "0x3c85eed0d017dca8eda6396aa842ddc12492587b061e8c756a8d32c4610a9658", diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index 58930f9789f..38358594258 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -1813,7 +1813,7 @@ contract OPContractsManagerInteropMigrator is OPContractsManagerBase { // Get the proxyAdmin from the first system config. IProxyAdmin proxyAdmin = _input.opChainConfigs[0].systemConfigProxy.proxyAdmin(); - // Check that all of the configs have the same proxy admin owner and prestate. + // Check that all of the configs have the same proxy admin owner and prestates. for (uint256 i = 0; i < _input.opChainConfigs.length; i++) { // Different chains might actually have different ProxyAdmin contracts, but it's fine // as long as the owner of all of those contracts is the same. @@ -1823,6 +1823,19 @@ contract OPContractsManagerInteropMigrator is OPContractsManagerBase { if (_input.opChainConfigs[i].cannonPrestate.raw() != _input.opChainConfigs[0].cannonPrestate.raw()) { revert OPContractsManagerInteropMigrator_AbsolutePrestateMismatch(); } + if (isDevFeatureEnabled(DevFeatures.CANNON_KONA)) { + if ( + _input.opChainConfigs[i].cannonKonaPrestate.raw() + != _input.opChainConfigs[0].cannonKonaPrestate.raw() + ) { + revert OPContractsManagerInteropMigrator_AbsolutePrestateMismatch(); + } + } + } + + // Check that cannon prestate is non-empty + if (_input.opChainConfigs[0].cannonPrestate.raw() == bytes32(0)) { + revert OPContractsManager.PrestateNotSet(); } // Grab an array of portals from the configs. @@ -1935,16 +1948,16 @@ contract OPContractsManagerInteropMigrator is OPContractsManagerBase { existingLockbox.migrateLiquidity(newEthLockbox); // Before migrating the portal, clear out any implementations that might exist in the - // old DisputeGameFactory proxy. We clear out all 4 potential game types to be safe. + // old DisputeGameFactory proxy. We clear out all potential game types to be safe. IDisputeGameFactory oldDisputeGameFactory = IDisputeGameFactory(payable(address(portals[i].disputeGameFactory()))); - oldDisputeGameFactory.setImplementation(GameTypes.CANNON, IDisputeGame(address(0))); - oldDisputeGameFactory.setImplementation(GameTypes.SUPER_CANNON, IDisputeGame(address(0))); - oldDisputeGameFactory.setImplementation(GameTypes.PERMISSIONED_CANNON, IDisputeGame(address(0))); - oldDisputeGameFactory.setImplementation(GameTypes.SUPER_PERMISSIONED_CANNON, IDisputeGame(address(0))); + clearGameImplementation(oldDisputeGameFactory, GameTypes.CANNON); + clearGameImplementation(oldDisputeGameFactory, GameTypes.SUPER_CANNON); + clearGameImplementation(oldDisputeGameFactory, GameTypes.PERMISSIONED_CANNON); + clearGameImplementation(oldDisputeGameFactory, GameTypes.SUPER_PERMISSIONED_CANNON); if (isDevFeatureEnabled(DevFeatures.CANNON_KONA)) { - oldDisputeGameFactory.setImplementation(GameTypes.CANNON_KONA, IDisputeGame(address(0))); - oldDisputeGameFactory.setImplementation(GameTypes.SUPER_CANNON_KONA, IDisputeGame(address(0))); + clearGameImplementation(oldDisputeGameFactory, GameTypes.CANNON_KONA); + clearGameImplementation(oldDisputeGameFactory, GameTypes.SUPER_CANNON_KONA); } // Migrate the portal to the new ETHLockbox and AnchorStateRegistry. @@ -2035,6 +2048,34 @@ contract OPContractsManagerInteropMigrator is OPContractsManagerBase { GameTypes.SUPER_CANNON, IDisputeGame(implementations().superFaultDisputeGameImpl), gameArgs ); newDisputeGameFactory.setInitBond(GameTypes.SUPER_CANNON, _input.gameParameters.initBond); + + // If the cannon-kona game is being used, set that up too. + bytes32 cannonKonaPrestate = _input.opChainConfigs[0].cannonKonaPrestate.raw(); + if (isDevFeatureEnabled(DevFeatures.CANNON_KONA) && cannonKonaPrestate != bytes32(0)) { + gameArgs = LibGameArgs.encode( + LibGameArgs.GameArgs({ + absolutePrestate: cannonKonaPrestate, + vm: address(getImplementations().mipsImpl), + anchorStateRegistry: address(newAnchorStateRegistry), + weth: address(newPermissionlessDelayedWETHProxy), + l2ChainId: uint256(0), + proposer: address(0), + challenger: address(0) + }) + ); + newDisputeGameFactory.setImplementation( + GameTypes.SUPER_CANNON_KONA, IDisputeGame(implementations().superFaultDisputeGameImpl), gameArgs + ); + newDisputeGameFactory.setInitBond(GameTypes.SUPER_CANNON_KONA, _input.gameParameters.initBond); + } + } + } + + function clearGameImplementation(IDisputeGameFactory _dgf, GameType _gameType) internal { + if (isDevFeatureEnabled(DevFeatures.DEPLOY_V2_DISPUTE_GAMES)) { + _dgf.setImplementation(_gameType, IDisputeGame(address(0)), hex""); + } else { + _dgf.setImplementation(_gameType, IDisputeGame(address(0))); } } } @@ -2167,9 +2208,9 @@ contract OPContractsManager is ISemver { // -------- Constants and Variables -------- - /// @custom:semver 5.5.0 + /// @custom:semver 5.6.0 function version() public pure virtual returns (string memory) { - return "5.5.0"; + return "5.6.0"; } OPContractsManagerGameTypeAdder public immutable opcmGameTypeAdder; diff --git a/packages/contracts-bedrock/src/safe/LivenessModule2.sol b/packages/contracts-bedrock/src/safe/LivenessModule2.sol index 290d3f8017f..0651bd3b9b6 100644 --- a/packages/contracts-bedrock/src/safe/LivenessModule2.sol +++ b/packages/contracts-bedrock/src/safe/LivenessModule2.sol @@ -279,12 +279,16 @@ abstract contract LivenessModule2 { _cancelChallenge(callingSafe); } - /// @notice With successful challenge, removes all current owners from enabled safe, - /// appoints fallback as sole owner, and sets its quorum to 1. - /// @dev Note: After ownership transfer, the fallback owner becomes the sole owner - /// and is also still configured as the fallback owner. This means the - /// fallback owner effectively becomes its own fallback owner, maintaining - /// the ability to challenge itself if needed. + /// @notice With successful challenge, removes all current owners from enabled safe, appoints + /// fallback as sole owner, and sets its quorum to 1. + /// @dev After ownership transfer, the fallback owner becomes the sole owner and is also still + /// configured as the fallback owner. If the fallback owner would become unable to sign, + /// it would not be able challenge the safe again. For this reason, it is important that + /// the fallback owner has a way to preserve its own liveness. + /// + /// It is of critical importance that this function never reverts. If it were to do so, + /// the Safe would be permanently bricked. For this reason, the external calls from this + /// function are allowed to fail silently instead of reverting. /// @param _safe The Safe address to transfer ownership of. function changeOwnershipToFallback(Safe _safe) external { // Ensure Safe is configured with this module to prevent unauthorized execution. diff --git a/packages/contracts-bedrock/src/safe/SaferSafes.sol b/packages/contracts-bedrock/src/safe/SaferSafes.sol index 09afd1abe3a..533e360bd51 100644 --- a/packages/contracts-bedrock/src/safe/SaferSafes.sol +++ b/packages/contracts-bedrock/src/safe/SaferSafes.sol @@ -26,8 +26,8 @@ import { ISemver } from "interfaces/universal/ISemver.sol"; /// compatibility restrictions in the LivenessModule2 and TimelockGuard contracts. contract SaferSafes is LivenessModule2, TimelockGuard, ISemver { /// @notice Semantic version. - /// @custom:semver 1.8.0 - string public constant version = "1.8.0"; + /// @custom:semver 1.9.1 + string public constant version = "1.9.1"; /// @notice Error for when the liveness response period is insufficient. error SaferSafes_InsufficientLivenessResponsePeriod(); diff --git a/packages/contracts-bedrock/src/safe/TimelockGuard.sol b/packages/contracts-bedrock/src/safe/TimelockGuard.sol index d76f79473c7..57ef493ddf8 100644 --- a/packages/contracts-bedrock/src/safe/TimelockGuard.sol +++ b/packages/contracts-bedrock/src/safe/TimelockGuard.sol @@ -88,13 +88,17 @@ abstract contract TimelockGuard is BaseGuard { } /// @notice Scheduled transaction + /// @custom:field txHash The hash of the transaction. /// @custom:field executionTime The timestamp when execution becomes valid. /// @custom:field state The state of the transaction. /// @custom:field params The parameters of the transaction. + /// @custom:field nonce The nonce of the transaction. struct ScheduledTransaction { + bytes32 txHash; uint256 executionTime; TransactionState state; ExecTransactionParams params; + uint256 nonce; } /// @notice Parameters for the Safe's execTransaction function @@ -208,13 +212,15 @@ abstract contract TimelockGuard is BaseGuard { /// @notice Returns the blocking threshold, which is defined as the minimum number of owners /// that must coordinate to block a transaction from being executed by refusing to /// sign. + /// @dev Because `_safe.getOwners()` loops through the owners list, it could run out of gas if + /// there are a lot of owners. /// @param _safe The Safe address to query /// @return The current blocking threshold function _blockingThreshold(Safe _safe) internal view returns (uint256) { return _safe.getOwners().length - _safe.getThreshold() + 1; } - /// @notice Internal helper to get the guard address from a Safe + /// @notice Internal helper to check if TimelockGuard is enabled for a Safe /// @param _safe The Safe address /// @return The current guard address function _isGuardEnabled(Safe _safe) internal view returns (bool) { @@ -229,7 +235,7 @@ abstract contract TimelockGuard is BaseGuard { return _safeStates[_safe][_safeConfigNonces[_safe]]; } - /// @notice Internal helper function which can be overriden in a child contract to check if the + /// @notice Internal helper function which can be overridden in a child contract to check if the /// guard's configuration is valid in the context of other extensions that are enabled /// on the Safe. function _checkCombinedConfig(Safe _safe) internal view virtual; @@ -342,7 +348,8 @@ abstract contract TimelockGuard is BaseGuard { // Limit execution of transactions to owners of the Safe only. // This ensures that an attacker cannot simply collect valid signatures, but must also - // control a private key. + // control a private key. It is accepted as a trade-off that paymasters, relayers or UX + // wrappers cannot execute transactions with the TimelockGuard enabled. if (!callingSafe.isOwner(_msgSender)) { revert TimelockGuard_NotOwner(); } @@ -471,6 +478,9 @@ abstract contract TimelockGuard is BaseGuard { /// 1. Safe disables the guard via GuardManager.setGuard(address(0)). /// 2. Safe calls this clearTimelockGuard() function to remove stored configuration. /// 3. If Safe later re-enables the guard, it must call configureTimelockGuard() again. + /// Warning: Clearing the configuration allows all transactions previously scheduled to be + /// scheduled again, including cancelled transactions. It is strongly recommended to + /// manually increment the Safe's nonce when a scheduled transaction is cancelled. function clearTimelockGuard() external { Safe callingSafe = Safe(payable(msg.sender)); @@ -492,6 +502,11 @@ abstract contract TimelockGuard is BaseGuard { /// existing signature generation tools. Owners can use any method to sign the a /// transaction, including signing with a private key, calling the Safe's approveHash /// function, or EIP1271 contract signatures. + /// The Safe doesn't increase its nonce when a transaction is cancelled in the Timelock. + /// This means that it is possible to add the very same transaction a second time to the + /// safe queue, but it won't be possible to schedule it again in the Timelock. It is + /// recommended that the safe nonce is manually incremented when a scheduled transaction + /// is cancelled. /// @param _safe The Safe address to schedule the transaction for. /// @param _nonce The nonce of the Safe for the transaction being scheduled. /// @param _params The parameters of the transaction being scheduled. @@ -564,8 +579,13 @@ abstract contract TimelockGuard is BaseGuard { uint256 executionTime = block.timestamp + _currentSafeState(_safe).timelockDelay; // Schedule the transaction and add it to the pending transactions set - _currentSafeState(_safe).scheduledTransactions[txHash] = - ScheduledTransaction({ executionTime: executionTime, state: TransactionState.Pending, params: _params }); + _currentSafeState(_safe).scheduledTransactions[txHash] = ScheduledTransaction({ + txHash: txHash, + executionTime: executionTime, + state: TransactionState.Pending, + params: _params, + nonce: _nonce + }); _currentSafeState(_safe).pendingTxHashes.add(txHash); emit TransactionScheduled(_safe, txHash, executionTime); @@ -585,6 +605,9 @@ abstract contract TimelockGuard is BaseGuard { /// of checkNSignatures is that owners can use any method to sign the cancellation /// transaction inputs, including signing with a private key, calling the Safe's /// approveHash function, or EIP1271 contract signatures. + /// + /// It is allowed to cancel transactions from a disabled TimelockGuard, as a way of + /// clearing the queue that wouldn't be as blunt as calling `clearTimelockConfiguration`. /// @param _safe The Safe address to cancel the transaction for. /// @param _txHash The hash of the transaction being cancelled. /// @param _nonce The nonce of the Safe for the transaction being cancelled. diff --git a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol index 45195fba091..d09e898dffb 100644 --- a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol +++ b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol @@ -1803,8 +1803,11 @@ contract OPContractsManager_UpgradeSuperchainConfig_Test is OPContractsManager_U /// @title OPContractsManager_Migrate_Test /// @notice Tests the `migrate` function of the `OPContractsManager` contract. contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { - Claim absolutePrestate1 = Claim.wrap(bytes32(hex"ABBA")); - Claim absolutePrestate2 = Claim.wrap(bytes32(hex"DEAD")); + Claim cannonPrestate1 = Claim.wrap(bytes32(hex"ABBA")); + Claim cannonPrestate2 = Claim.wrap(bytes32(hex"DEAD")); + Claim cannonKonaPrestate1 = Claim.wrap(bytes32(hex"ABBACADABA")); + Claim cannonKonaPrestate2 = Claim.wrap(bytes32(hex"DEADBEEF")); + Claim emptyPrestate = Claim.wrap(bytes32(0)); /// @notice Function requires interop portal. function setUp() public override { @@ -1827,10 +1830,10 @@ contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { IOPContractsManager.OpChainConfig[] memory opChainConfigs = new IOPContractsManager.OpChainConfig[](2); opChainConfigs[0] = IOPContractsManager.OpChainConfig( - chainDeployOutput1.systemConfigProxy, absolutePrestate1, Claim.wrap(bytes32(0)) + chainDeployOutput1.systemConfigProxy, cannonPrestate1, cannonKonaPrestate1 ); opChainConfigs[1] = IOPContractsManager.OpChainConfig( - chainDeployOutput2.systemConfigProxy, absolutePrestate1, Claim.wrap(bytes32(0)) + chainDeployOutput2.systemConfigProxy, cannonPrestate1, cannonKonaPrestate1 ); return IOPContractsManagerInteropMigrator.MigrateInput({ @@ -1878,17 +1881,26 @@ contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { /// @param _disputeGameFactory The dispute game factory to check. function _assertOldGamesZeroed(IDisputeGameFactory _disputeGameFactory) internal view { // Assert that the old game implementations are now zeroed out. - assertEq(address(_disputeGameFactory.gameImpls(GameTypes.CANNON)), address(0)); - assertEq(address(_disputeGameFactory.gameImpls(GameTypes.SUPER_CANNON)), address(0)); - assertEq(address(_disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON)), address(0)); - assertEq(address(_disputeGameFactory.gameImpls(GameTypes.SUPER_PERMISSIONED_CANNON)), address(0)); + _assertGameIsEmpty(_disputeGameFactory, GameTypes.CANNON, "CANNON"); + _assertGameIsEmpty(_disputeGameFactory, GameTypes.SUPER_CANNON, "SUPER_CANNON"); + _assertGameIsEmpty(_disputeGameFactory, GameTypes.PERMISSIONED_CANNON, "PERMISSIONED_CANNON"); + _assertGameIsEmpty(_disputeGameFactory, GameTypes.SUPER_PERMISSIONED_CANNON, "SUPER_PERMISSIONED_CANNON"); if (isDevFeatureEnabled(DevFeatures.CANNON_KONA)) { // Only explicitly zeroed out if feature is enabled. Otherwise left unchanged (which may still be 0). - assertEq(address(_disputeGameFactory.gameImpls(GameTypes.CANNON_KONA)), address(0)); - assertEq(address(_disputeGameFactory.gameImpls(GameTypes.SUPER_CANNON_KONA)), address(0)); + _assertGameIsEmpty(_disputeGameFactory, GameTypes.CANNON_KONA, "CANNON_KONA"); + _assertGameIsEmpty(_disputeGameFactory, GameTypes.SUPER_CANNON_KONA, "SUPER_CANNON_KONA"); } } + function _assertGameIsEmpty(IDisputeGameFactory _dgf, GameType _gameType, string memory _label) internal view { + assertEq( + address(_dgf.gameImpls(_gameType)), + address(0), + string.concat("Game type set when it should not be: ", _label) + ); + assertEq(_dgf.gameArgs(_gameType), hex"", string.concat("Game args should be empty: ", _label)); + } + /// @notice Runs some tests after opcm.migrate function _runPostMigrateSmokeTests(IOPContractsManagerInteropMigrator.MigrateInput memory _input) internal { IDisputeGameFactory dgf = IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()); @@ -1898,17 +1910,28 @@ contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { (, uint256 l2SequenceNumberAnchor) = anchorStateRegistry.getAnchorRoot(); uint256 l2SequenceNumber = l2SequenceNumberAnchor + 1; - GameType[] memory gameTypes = new GameType[](_input.usePermissionlessGame ? 2 : 1); - gameTypes[0] = GameTypes.SUPER_PERMISSIONED_CANNON; - if (_input.usePermissionlessGame) { - gameTypes[1] = GameTypes.SUPER_CANNON; - } + GameType[] memory gameTypes = _getPostMigrateExpectedGameTypes(_input); + + address permissionlessWeth; for (uint256 i = 0; i < gameTypes.length; i++) { LibGameArgs.GameArgs memory gameArgs = LibGameArgs.decode(dgf.gameArgs(gameTypes[i])); - assertEq(gameArgs.absolutePrestate, absolutePrestate1.raw(), "gameArgs prestate mismatch"); + if (permissionlessWeth == address(0) && !isGamePermissioned(gameTypes[i])) { + // Remember the first permissionless weth we encounter + permissionlessWeth = gameArgs.weth; + } + assertEq(gameArgs.vm, opcm.implementations().mipsImpl, "gameArgs vm mismatch"); assertEq(gameArgs.anchorStateRegistry, address(anchorStateRegistry), "gameArgs asr mismatch"); assertEq(gameArgs.l2ChainId, 0, "gameArgs non-zero l2ChainId"); + if (gameTypes[i].raw() == GameTypes.SUPER_CANNON_KONA.raw()) { + assertEq(gameArgs.absolutePrestate, cannonKonaPrestate1.raw(), "gameArgs prestate mismatch"); + } else { + assertEq(gameArgs.absolutePrestate, cannonPrestate1.raw(), "gameArgs prestate mismatch"); + } + if (!isGamePermissioned(gameTypes[i])) { + // All permissionless FDG games should share the same weth contract + assertEq(gameArgs.weth, permissionlessWeth, "gameArgs weth mismatch"); + } Claim rootClaim = Claim.wrap(bytes32(uint256(1))); uint256 bondAmount = dgf.initBonds(gameTypes[i]); @@ -1945,107 +1968,106 @@ contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { } } + function _getPostMigrateExpectedGameTypes(IOPContractsManagerInteropMigrator.MigrateInput memory _input) + internal + returns (GameType[] memory gameTypes_) + { + uint256 gameCount = 1; + bytes32 cannonKonaPrestate = _input.opChainConfigs[0].cannonKonaPrestate.raw(); + if (_input.usePermissionlessGame) { + gameCount += 1; + if (isDevFeatureEnabled(DevFeatures.CANNON_KONA) && cannonKonaPrestate != bytes32(0)) { + gameCount += 1; + } + } + + gameTypes_ = new GameType[](gameCount); + gameTypes_[0] = GameTypes.SUPER_PERMISSIONED_CANNON; + if (_input.usePermissionlessGame) { + gameTypes_[1] = GameTypes.SUPER_CANNON; + if (isDevFeatureEnabled(DevFeatures.CANNON_KONA) && cannonKonaPrestate != bytes32(0)) { + gameTypes_[2] = GameTypes.SUPER_CANNON_KONA; + } + } + } + /// @notice Tests that the migration function succeeds when requesting to use the /// permissionless game. function test_migrate_withPermissionlessGame_succeeds() public { IOPContractsManagerInteropMigrator.MigrateInput memory input = _getDefaultInput(); + (IAnchorStateRegistry asr, IDisputeGameFactory dgf) = _runMigrationAndStandardChecks(input); - // Separate context to avoid stack too deep errors. - { - // Grab the existing DisputeGameFactory for each chain. - IDisputeGameFactory oldDisputeGameFactory1 = - IDisputeGameFactory(payable(chainDeployOutput1.systemConfigProxy.disputeGameFactory())); - IDisputeGameFactory oldDisputeGameFactory2 = - IDisputeGameFactory(payable(chainDeployOutput2.systemConfigProxy.disputeGameFactory())); + // Check the respected game type + assertEq(asr.respectedGameType().raw(), GameTypes.SUPER_CANNON.raw(), "Super Cannon game type mismatch"); - // Execute the migration. - _doMigration(input); - - // Assert that the old game implementations are now zeroed out. - _assertOldGamesZeroed(oldDisputeGameFactory1); - _assertOldGamesZeroed(oldDisputeGameFactory2); - } - - // Grab the two OptimismPortal addresses. - IOptimismPortal2 optimismPortal1 = - IOptimismPortal2(payable(chainDeployOutput1.systemConfigProxy.optimismPortal())); - IOptimismPortal2 optimismPortal2 = - IOptimismPortal2(payable(chainDeployOutput2.systemConfigProxy.optimismPortal())); - - // Grab the AnchorStateRegistry from the OptimismPortal for both chains, confirm same. + // Check initial bonds assertEq( - address(optimismPortal1.anchorStateRegistry()), - address(optimismPortal2.anchorStateRegistry()), - "AnchorStateRegistry mismatch" + dgf.initBonds(GameTypes.SUPER_CANNON), input.gameParameters.initBond, "Super Cannon init bond mismatch" ); - - // Extract the AnchorStateRegistry now that we know it's the same on both chains. - IAnchorStateRegistry anchorStateRegistry = optimismPortal1.anchorStateRegistry(); - - // Grab the DisputeGameFactory from the SystemConfig for both chains, confirm same. assertEq( - chainDeployOutput1.systemConfigProxy.disputeGameFactory(), - chainDeployOutput2.systemConfigProxy.disputeGameFactory(), - "DisputeGameFactory mismatch" + dgf.initBonds(GameTypes.SUPER_PERMISSIONED_CANNON), + input.gameParameters.initBond, + "Super Permissioned Cannon init bond mismatch" ); + if (isDevFeatureEnabled(DevFeatures.CANNON_KONA)) { + assertEq( + dgf.initBonds(GameTypes.SUPER_CANNON_KONA), + input.gameParameters.initBond, + "Super CannonKona init bond mismatch" + ); + } else { + assertEq( + dgf.initBonds(GameTypes.SUPER_CANNON_KONA), uint256(0), "Super CannonKona init bond should be zero" + ); + } - // Extract the DisputeGameFactory now that we know it's the same on both chains. - IDisputeGameFactory disputeGameFactory = - IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()); + // Check game configuration + _validateSuperGameImplParams(input, dgf, GameTypes.SUPER_PERMISSIONED_CANNON, "SUPER_PERMISSIONED_CANNON"); + _validateSuperGameImplParams(input, dgf, GameTypes.SUPER_CANNON, "SUPER_CANNON"); + if (isDevFeatureEnabled(DevFeatures.CANNON_KONA)) { + _validateSuperGameImplParams(input, dgf, GameTypes.SUPER_CANNON_KONA, "SUPER_CANNON_KONA"); + } else { + _assertGameIsEmpty(dgf, GameTypes.SUPER_CANNON_KONA, "SUPER_CANNON_KONA"); + } - // Grab the ETHLockbox from the OptimismPortal for both chains, confirm same. - assertEq(address(optimismPortal1.ethLockbox()), address(optimismPortal2.ethLockbox()), "ETHLockbox mismatch"); + _runPostMigrateSmokeTests(input); + } - // Extract the ETHLockbox now that we know it's the same on both chains. - IETHLockbox ethLockbox = optimismPortal1.ethLockbox(); + /// @notice Tests that permissionless migration reverts when cannon prestates are empty. + function test_migrate_permissionlessWithEmptyCannonPrestate_reverts() public { + IOPContractsManagerInteropMigrator.MigrateInput memory input = _getDefaultInput(); + input.opChainConfigs[0].cannonPrestate = emptyPrestate; + input.opChainConfigs[1].cannonPrestate = emptyPrestate; - // Check that the ETHLockbox was migrated correctly. - assertGt(address(ethLockbox).balance, 0, "ETHLockbox balance is zero"); - assertTrue(ethLockbox.authorizedPortals(optimismPortal1), "ETHLockbox does not have portal 1 authorized"); - assertTrue(ethLockbox.authorizedPortals(optimismPortal2), "ETHLockbox does not have portal 2 authorized"); + // Execute the migration. + _doMigration(input, IOPContractsManager.PrestateNotSet.selector); + } - // Check that the respected game type is the Super Cannon game type. - assertEq( - anchorStateRegistry.respectedGameType().raw(), - GameTypes.SUPER_CANNON.raw(), - "Super Cannon game type mismatch" - ); + /// @notice Tests that the permissionless migration succeeds when cannonKona prestates are empty. + function test_migrate_permissionlessWithEmptyCannonKonaPrestate_succeeds() public { + IOPContractsManagerInteropMigrator.MigrateInput memory input = _getDefaultInput(); + input.opChainConfigs[0].cannonKonaPrestate = emptyPrestate; + input.opChainConfigs[1].cannonKonaPrestate = emptyPrestate; + (IAnchorStateRegistry asr, IDisputeGameFactory dgf) = _runMigrationAndStandardChecks(input); - // Check that the starting anchor root is the same as the input. - (Hash root, uint256 l2SequenceNumber) = anchorStateRegistry.getAnchorRoot(); - assertEq(root.raw(), input.startingAnchorRoot.root.raw(), "Starting anchor root mismatch"); - assertEq( - l2SequenceNumber, - input.startingAnchorRoot.l2SequenceNumber, - "Starting anchor root L2 sequence number mismatch" - ); + // Check the respected game type + assertEq(asr.respectedGameType().raw(), GameTypes.SUPER_CANNON.raw(), "Super Cannon game type mismatch"); + // Check initial bonds assertEq( - disputeGameFactory.initBonds(GameTypes.SUPER_CANNON), - input.gameParameters.initBond, - "Super Cannon init bond mismatch" + dgf.initBonds(GameTypes.SUPER_CANNON), input.gameParameters.initBond, "Super Cannon init bond mismatch" ); assertEq( - disputeGameFactory.initBonds(GameTypes.SUPER_PERMISSIONED_CANNON), + dgf.initBonds(GameTypes.SUPER_PERMISSIONED_CANNON), input.gameParameters.initBond, "Super Permissioned Cannon init bond mismatch" ); + assertEq(dgf.initBonds(GameTypes.SUPER_CANNON_KONA), uint256(0), "Super CannonKona init bond should be zero"); - // Check that the Super Cannon game has the correct parameters. - IDisputeGame superFdgImpl = disputeGameFactory.gameImpls(GameTypes.SUPER_CANNON); - ISuperFaultDisputeGame superFdg = ISuperFaultDisputeGame(address(superFdgImpl)); - assertEq(superFdg.maxGameDepth(), input.gameParameters.maxGameDepth); - assertEq(superFdg.splitDepth(), input.gameParameters.splitDepth); - assertEq(superFdg.clockExtension().raw(), input.gameParameters.clockExtension.raw()); - assertEq(superFdg.maxClockDuration().raw(), input.gameParameters.maxClockDuration.raw()); - - // Check that the Super Permissioned Cannon game has the correct parameters. - IDisputeGame superPdgImpl = disputeGameFactory.gameImpls(GameTypes.SUPER_PERMISSIONED_CANNON); - ISuperPermissionedDisputeGame superPdg = ISuperPermissionedDisputeGame(address(superPdgImpl)); - assertEq(superPdg.maxGameDepth(), input.gameParameters.maxGameDepth); - assertEq(superPdg.splitDepth(), input.gameParameters.splitDepth); - assertEq(superPdg.clockExtension().raw(), input.gameParameters.clockExtension.raw()); - assertEq(superPdg.maxClockDuration().raw(), input.gameParameters.maxClockDuration.raw()); + // Check game configuration + _validateSuperGameImplParams(input, dgf, GameTypes.SUPER_PERMISSIONED_CANNON, "SUPER_PERMISSIONED_CANNON"); + _validateSuperGameImplParams(input, dgf, GameTypes.SUPER_CANNON, "SUPER_CANNON"); + _assertGameIsEmpty(dgf, GameTypes.SUPER_CANNON_KONA, "SUPER_CANNON_KONA"); _runPostMigrateSmokeTests(input); } @@ -2054,10 +2076,48 @@ contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { /// permissioned game (no permissioned game is deployed). function test_migrate_withoutPermissionlessGame_succeeds() public { IOPContractsManagerInteropMigrator.MigrateInput memory input = _getDefaultInput(); + input.usePermissionlessGame = false; + (IAnchorStateRegistry asr, IDisputeGameFactory dgf) = _runMigrationAndStandardChecks(input); + + // Check the respected game type + assertEq( + asr.respectedGameType().raw(), + GameTypes.SUPER_PERMISSIONED_CANNON.raw(), + "Super Permissioned Cannon game type mismatch" + ); + + // Check intial bonds + assertEq( + dgf.initBonds(GameTypes.SUPER_PERMISSIONED_CANNON), + input.gameParameters.initBond, + "Super Permissioned Cannon init bond mismatch" + ); + assertEq(dgf.initBonds(GameTypes.SUPER_CANNON), 0, "Super Cannon init bond mismatch"); + assertEq(dgf.initBonds(GameTypes.SUPER_CANNON_KONA), 0, "Super CannonKona init bond mismatch"); + + // Check game configuration + _validateSuperGameImplParams(input, dgf, GameTypes.SUPER_PERMISSIONED_CANNON, "SUPER_PERMISSIONED_CANNON"); + _assertGameIsEmpty(dgf, GameTypes.SUPER_CANNON, "SUPER_CANNON"); + _assertGameIsEmpty(dgf, GameTypes.SUPER_CANNON_KONA, "SUPER_CANNON_KONA"); + + _runPostMigrateSmokeTests(input); + } - // Change the input to not use the permissionless game. + /// @notice Tests that permissioned migration reverts when cannon prestates are empty. + function test_migrate_permissionedWithEmptyCannonPrestate_reverts() public { + IOPContractsManagerInteropMigrator.MigrateInput memory input = _getDefaultInput(); input.usePermissionlessGame = false; + input.opChainConfigs[0].cannonPrestate = emptyPrestate; + input.opChainConfigs[1].cannonPrestate = emptyPrestate; + // Execute the migration. + _doMigration(input, IOPContractsManager.PrestateNotSet.selector); + } + + function _runMigrationAndStandardChecks(IOPContractsManagerInteropMigrator.MigrateInput memory input) + internal + returns (IAnchorStateRegistry asr_, IDisputeGameFactory dgf_) + { // Separate context to avoid stack too deep errors. { // Grab the existing DisputeGameFactory for each chain. @@ -2080,7 +2140,7 @@ contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { IOptimismPortal2 optimismPortal2 = IOptimismPortal2(payable(chainDeployOutput2.systemConfigProxy.optimismPortal())); - // Grab the AnchorStateRegistry from the SystemConfig for both chains, confirm same. + // Grab the AnchorStateRegistry from the OptimismPortal for both chains, confirm same. assertEq( address(optimismPortal1.anchorStateRegistry()), address(optimismPortal2.anchorStateRegistry()), @@ -2088,7 +2148,16 @@ contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { ); // Extract the AnchorStateRegistry now that we know it's the same on both chains. - IAnchorStateRegistry anchorStateRegistry = optimismPortal1.anchorStateRegistry(); + asr_ = optimismPortal1.anchorStateRegistry(); + + // Check that the starting anchor root is the same as the input. + (Hash root, uint256 l2SequenceNumber) = asr_.getAnchorRoot(); + assertEq(root.raw(), input.startingAnchorRoot.root.raw(), "Starting anchor root mismatch"); + assertEq( + l2SequenceNumber, + input.startingAnchorRoot.l2SequenceNumber, + "Starting anchor root L2 sequence number mismatch" + ); // Grab the DisputeGameFactory from the SystemConfig for both chains, confirm same. assertEq( @@ -2098,17 +2167,9 @@ contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { ); // Extract the DisputeGameFactory now that we know it's the same on both chains. - IDisputeGameFactory disputeGameFactory = - IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()); + dgf_ = IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()); - // Check that the respected game type is the Super Cannon game type. - assertEq( - anchorStateRegistry.respectedGameType().raw(), - GameTypes.SUPER_PERMISSIONED_CANNON.raw(), - "Super Permissioned Cannon game type mismatch" - ); - - // Grab the ETHLockbox from the SystemConfig for both chains, confirm same. + // Grab the ETHLockbox from the OptimismPortal for both chains, confirm same. assertEq(address(optimismPortal1.ethLockbox()), address(optimismPortal2.ethLockbox()), "ETHLockbox mismatch"); // Extract the ETHLockbox now that we know it's the same on both chains. @@ -2118,40 +2179,37 @@ contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { assertGt(address(ethLockbox).balance, 0, "ETHLockbox balance is zero"); assertTrue(ethLockbox.authorizedPortals(optimismPortal1), "ETHLockbox does not have portal 1 authorized"); assertTrue(ethLockbox.authorizedPortals(optimismPortal2), "ETHLockbox does not have portal 2 authorized"); + } - // Check that the starting anchor root is the same as the input. - (Hash root, uint256 l2SequenceNumber) = anchorStateRegistry.getAnchorRoot(); - assertEq(root.raw(), input.startingAnchorRoot.root.raw(), "Starting anchor root mismatch"); + function _validateSuperGameImplParams( + IOPContractsManagerInteropMigrator.MigrateInput memory _input, + IDisputeGameFactory _dgf, + GameType _gameType, + string memory _label + ) + internal + view + { + IDisputeGame dgImpl = _dgf.gameImpls(_gameType); + ISuperFaultDisputeGame superImpl = ISuperFaultDisputeGame(address(dgImpl)); assertEq( - l2SequenceNumber, - input.startingAnchorRoot.l2SequenceNumber, - "Starting anchor root L2 sequence number mismatch" + superImpl.maxGameDepth(), + _input.gameParameters.maxGameDepth, + string.concat("MaxGameDepth mismatch: ", _label) ); - - // Check that the DisputeGameFactory has implementation for the Permissioned game. assertEq( - disputeGameFactory.initBonds(GameTypes.SUPER_PERMISSIONED_CANNON), - input.gameParameters.initBond, - "Super Permissioned Cannon init bond mismatch" + superImpl.splitDepth(), _input.gameParameters.splitDepth, string.concat("SplitDepth mismatch: ", _label) ); - - // Check that the DisputeGameFactory does not have an implementation for the regular game. assertEq( - address(disputeGameFactory.gameImpls(GameTypes.SUPER_CANNON)), - address(0), - "Super Cannon game type set when it should not be" + superImpl.clockExtension().raw(), + _input.gameParameters.clockExtension.raw(), + string.concat("ClockExtension mismatch: ", _label) + ); + assertEq( + superImpl.maxClockDuration().raw(), + _input.gameParameters.maxClockDuration.raw(), + string.concat("MaxClockDuration mismatch: ", _label) ); - assertEq(disputeGameFactory.initBonds(GameTypes.SUPER_CANNON), 0, "Super Cannon init bond mismatch"); - - // Check that the Super Permissioned Cannon game has the correct parameters. - IDisputeGame superPdgImpl = disputeGameFactory.gameImpls(GameTypes.SUPER_PERMISSIONED_CANNON); - ISuperPermissionedDisputeGame superPdg = ISuperPermissionedDisputeGame(address(superPdgImpl)); - assertEq(superPdg.maxGameDepth(), input.gameParameters.maxGameDepth); - assertEq(superPdg.splitDepth(), input.gameParameters.splitDepth); - assertEq(superPdg.clockExtension().raw(), input.gameParameters.clockExtension.raw()); - assertEq(superPdg.maxClockDuration().raw(), input.gameParameters.maxClockDuration.raw()); - - _runPostMigrateSmokeTests(input); } /// @notice Tests that the migration function reverts when the ProxyAdmin owners are @@ -2179,12 +2237,12 @@ contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { /// @notice Tests that the migration function reverts when the absolute prestates are /// mismatched. - function test_migrate_mismatchedAbsolutePrestates_reverts() public { + function test_migrate_mismatchedCannonPrestates_reverts() public { IOPContractsManagerInteropMigrator.MigrateInput memory input = _getDefaultInput(); // Set the prestates to be different. - input.opChainConfigs[0].cannonPrestate = absolutePrestate1; - input.opChainConfigs[0].cannonPrestate = absolutePrestate2; + input.opChainConfigs[0].cannonPrestate = cannonPrestate1; + input.opChainConfigs[1].cannonPrestate = cannonPrestate2; // Execute the migration. _doMigration( @@ -2192,6 +2250,28 @@ contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { ); } + /// @notice Tests that the migration function reverts when the absolute prestates are + /// mismatched. + function test_migrate_mismatchedKonaPrestates_reverts() public { + IOPContractsManagerInteropMigrator.MigrateInput memory input = _getDefaultInput(); + + // Set the prestates to be different. + input.opChainConfigs[0].cannonKonaPrestate = cannonKonaPrestate1; + input.opChainConfigs[1].cannonKonaPrestate = cannonKonaPrestate2; + + // Execute the migration. + if (isDevFeatureEnabled(DevFeatures.CANNON_KONA)) { + // We should revert if there is a mismatch and cannonaKona is enabled + _doMigration( + input, + OPContractsManagerInteropMigrator.OPContractsManagerInteropMigrator_AbsolutePrestateMismatch.selector + ); + } else { + // Otherwise, migration should run without reverting + _doMigration(input); + } + } + /// @notice Tests that the migration function reverts when the SuperchainConfig addresses are /// mismatched. function test_migrate_mismatchedSuperchainConfig_reverts() public { diff --git a/packages/contracts-bedrock/test/L1/OPContractsManagerStandardValidator.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManagerStandardValidator.t.sol index 5fb4992f42f..a99a358ea19 100644 --- a/packages/contracts-bedrock/test/L1/OPContractsManagerStandardValidator.t.sol +++ b/packages/contracts-bedrock/test/L1/OPContractsManagerStandardValidator.t.sol @@ -95,7 +95,7 @@ abstract contract OPContractsManagerStandardValidator_TestInit is CommonTest, Di Claim cannonPrestate; /// @notice The CannonKona absolute prestate. - Claim cannonKonaPrestate = Claim.wrap(bytes32(keccak256("cannonKona"))); + Claim cannonKonaPrestate = Claim.wrap(bytes32(keccak256("cannonKonaPrestate"))); /// @notice The proposer role set on the PermissionedDisputeGame instance. address proposer; diff --git a/packages/contracts-bedrock/test/safe/TimelockGuard.t.sol b/packages/contracts-bedrock/test/safe/TimelockGuard.t.sol index f3bff3735b5..8ddb4fb1a11 100644 --- a/packages/contracts-bedrock/test/safe/TimelockGuard.t.sol +++ b/packages/contracts-bedrock/test/safe/TimelockGuard.t.sol @@ -505,9 +505,11 @@ contract TimelockGuard_ScheduledTransaction_Test is TimelockGuard_TestInit { TimelockGuard.ScheduledTransaction memory scheduledTransaction = timelockGuard.scheduledTransaction(safe, dummyTx.hash); + assertEq(scheduledTransaction.txHash, dummyTx.hash); assertEq(scheduledTransaction.executionTime, INIT_TIME + TIMELOCK_DELAY); assert(scheduledTransaction.state == TimelockGuard.TransactionState.Pending); assertEq(keccak256(abi.encode(scheduledTransaction.params)), keccak256(abi.encode(dummyTx.params))); + assertEq(scheduledTransaction.nonce, dummyTx.nonce); } } @@ -525,9 +527,13 @@ contract TimelockGuard_PendingTransactions_Test is TimelockGuard_TestInit { dummyTx.scheduleTransaction(timelockGuard); TimelockGuard.ScheduledTransaction[] memory pendingTransactions = timelockGuard.pendingTransactions(safe); + // verify the pending transaction is the one we scheduled assertEq(pendingTransactions.length, 1); - // ensure the hash of the transaction params are the same + assertEq(pendingTransactions[0].txHash, dummyTx.hash); + assertEq(pendingTransactions[0].executionTime, INIT_TIME + TIMELOCK_DELAY); + assert(pendingTransactions[0].state == TimelockGuard.TransactionState.Pending); assertEq(pendingTransactions[0].params.to, dummyTx.params.to); + assertEq(pendingTransactions[0].nonce, dummyTx.nonce); assertEq(keccak256(abi.encode(pendingTransactions[0].params)), keccak256(abi.encode(dummyTx.params))); } diff --git a/packages/contracts-bedrock/test/setup/DisputeGames.sol b/packages/contracts-bedrock/test/setup/DisputeGames.sol index bd5dff7bede..4ec7493c70d 100644 --- a/packages/contracts-bedrock/test/setup/DisputeGames.sol +++ b/packages/contracts-bedrock/test/setup/DisputeGames.sol @@ -56,6 +56,11 @@ contract DisputeGames is FeatureFlags { return address(gameProxy); } + function isGamePermissioned(GameType _gameType) internal pure returns (bool) { + return _gameType.raw() == GameTypes.PERMISSIONED_CANNON.raw() + || _gameType.raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw(); + } + enum GameArg { PRESTATE, VM,