diff --git a/.circleci/Untitled b/.circleci/Untitled new file mode 100644 index 00000000000..30eb64ea43c --- /dev/null +++ b/.circleci/Untitled @@ -0,0 +1 @@ +c-contracts_changed \ No newline at end of file diff --git a/.circleci/config.yml b/.circleci/config.yml index 9f1a5b2f67b..fca6747cd00 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -108,6 +108,8 @@ workflows: .* c-go-cache-version << pipeline.parameters.go-cache-version >> .circleci/continue/main.yml rust/.* c-rust_files_changed true .circleci/continue/main.yml ^(?!docs/public-docs/).+ c-non_docs_changes true .circleci/continue/main.yml + (packages/contracts-bedrock|\.circleci|\.github|ops/check-changed)/.* c-contracts_changed true .circleci/continue/main.yml + ^(package\.json|mise\.toml)$ c-contracts_changed true .circleci/continue/main.yml # Docs CI — trigger on docs/public-docs/ changes .* c-default_docker_image << pipeline.parameters.default_docker_image >> .circleci/continue/docs-ci.yml diff --git a/.circleci/continue/main.yml b/.circleci/continue/main.yml index 2ee3a0404a9..418573a4061 100644 --- a/.circleci/continue/main.yml +++ b/.circleci/continue/main.yml @@ -77,6 +77,11 @@ parameters: c-go-cache-version: type: string default: "v0.0" + # Set to true by path-filtering when contracts or rebuild-all paths change. + # When false, contract feature matrix jobs are skipped entirely. + c-contracts_changed: + type: boolean + default: false # Passthrough declarations for setup config parameters. # CircleCI forwards all explicitly-passed pipeline parameters to continuation configs. # Without these declarations, manually triggered pipelines fail with "Unexpected argument(s)". @@ -149,7 +154,7 @@ parameters: default: "v0.0" orbs: - utils: ethereum-optimism/circleci-utils@1.0.25 + utils: ethereum-optimism/circleci-utils@1.0.27 go: circleci/go@1.8.0 gcp-cli: circleci/gcp-cli@3.0.1 slack: circleci/slack@6.0.0 @@ -1513,6 +1518,19 @@ jobs: command: just update-selectors working_directory: packages/contracts-bedrock + required-contracts-ci: + docker: + - image: <> + resource_class: small + parameters: + always-succed: + description: Force always succeed (skip API gate; for contracts-feature-tests-short) + type: boolean + default: false + steps: + - utils/ci-gate: + always-succeed: << parameters.always-succed >> + contracts-bedrock-checks-fast: docker: - image: <> @@ -1673,6 +1691,20 @@ jobs: command: | go run ./ops/scripts/check-nut-locks + nut-provenance-verify: + docker: + - image: <> + resource_class: 2xlarge + steps: + - utils/checkout-with-mise: + enable-mise-cache: true + - install-contracts-dependencies + - check-changed: + patterns: op-core/nuts + - run: + name: verify NUT bundle provenance + command: ./ops/scripts/nut-provenance-verify-changed.sh + go-tests: parameters: notify: @@ -1777,7 +1809,8 @@ jobs: description: Environment overrides type: string default: "" - machine: true + docker: + - image: <> resource_class: <> steps: - utils/checkout-with-mise: @@ -1823,10 +1856,6 @@ jobs: op-acceptance-tests: parameters: - gate: - description: The gate to run. Reads package list from op-acceptance-tests/gates/.txt. If empty, runs all tests. - type: string - default: "" l2_cl_kind: description: "L2 consensus layer client (op-node or kona-node)" type: string @@ -1880,7 +1909,7 @@ jobs: working_directory: op-acceptance-tests no_output_timeout: <> command: | - LOG_LEVEL=info just acceptance-test "<>" + LOG_LEVEL=info just acceptance-test - run: name: Print results (summary) working_directory: op-acceptance-tests @@ -2615,6 +2644,9 @@ workflows: - check-nut-locks: context: - circleci-repo-readonly-authenticated-github-token + - nut-provenance-verify: + context: + - circleci-repo-readonly-authenticated-github-token - fuzz-golang: name: fuzz-golang-<> on_changes: <> @@ -2777,10 +2809,9 @@ workflows: - cannon-prestate - rust-binaries-for-sysgo - go-binaries-for-sysgo - # IN-MEMORY (base gate) - op-node/op-reth + # IN-MEMORY - op-node/op-reth - op-acceptance-tests: name: memory-all-opn-op-reth - gate: "base" l2_el_kind: op-reth no_output_timeout: 120m context: @@ -2792,10 +2823,9 @@ workflows: - cannon-prestate - rust-binaries-for-sysgo - go-binaries-for-sysgo - # IN-MEMORY (base gate) - kona/op-reth + # IN-MEMORY - kona/op-reth - op-acceptance-tests: name: memory-all-kona-op-reth - gate: "base" l2_cl_kind: kona-node l2_el_kind: op-reth no_output_timeout: 120m @@ -3002,19 +3032,29 @@ workflows: context: - slack - circleci-repo-readonly-authenticated-github-token + - rust-build-binary: + name: rust-workspace-binaries + directory: rust + profile: "release" + save_cache: true + persist_to_workspace: true + rust_files_changed: << pipeline.parameters.c-rust_files_changed >> + context: + - circleci-repo-readonly-authenticated-github-token - go-tests-with-fault-proof-deps: name: op-e2e-cannon-tests notify: true mentions: "@proofs-team" no_output_timeout: 90m test_timeout: 480m - resource_class: xlarge + resource_class: 2xlarge context: - slack - circleci-repo-readonly-authenticated-github-token requires: - contracts-bedrock-build - cannon-prestate + - rust-workspace-binaries - publish-cannon-prestates: context: - slack @@ -3164,4 +3204,210 @@ workflows: - circleci-repo-readonly-authenticated-github-token - slack + contracts-feature-tests: + when: + or: + - and: + - equal: ["webhook", << pipeline.trigger_source >>] + - << pipeline.parameters.c-contracts_changed >> + - << pipeline.parameters.c-non_docs_changes >> + # Always run on develop (mirrors previous check-changed whitelist behavior) + - and: + - equal: ["webhook", << pipeline.trigger_source >>] + - equal: ["develop", << pipeline.git.branch >>] + - << pipeline.parameters.c-non_docs_changes >> + # Merge queue (merge gate). Match checkout branch. + - matches: + pattern: "^gh-readonly-queue/.*" + value: << pipeline.git.branch >> + - and: + - equal: [true, <>] + - equal: ["api", << pipeline.trigger_source >>] + jobs: + - contracts-bedrock-tests: + # Heavily fuzz any fuzz tests within added or modified test files. + name: contracts-bedrock-tests-heavy-fuzz-modified <> + test_list: git diff origin/develop...HEAD --name-only --diff-filter=AM -- './test/**/*.t.sol' | sed 's|packages/contracts-bedrock/||' + test_timeout: 1h + test_profile: ciheavy + features: <> + matrix: + parameters: + features: &features_matrix + - main + - CUSTOM_GAS_TOKEN + - OPTIMISM_PORTAL_INTEROP + - OPCM_V2 + - OPCM_V2,CUSTOM_GAS_TOKEN + - OPCM_V2,OPTIMISM_PORTAL_INTEROP + - OPCM_V2,ZK_DISPUTE_GAME + - OPCM_V2,CANNON_KONA + - OPCM_V2,SUPER_ROOT_GAMES_MIGRATION + context: + - circleci-repo-readonly-authenticated-github-token + - slack + # On PRs, run tests with lite profile for better build times. + - contracts-bedrock-tests: + name: contracts-bedrock-tests <> + test_list: find test -name "*.t.sol" + test_profile: liteci + features: <> + matrix: + parameters: + features: *features_matrix + context: + - circleci-repo-readonly-authenticated-github-token + - slack + filters: + branches: + ignore: develop + # On develop, run tests with ci profile to mirror production. + - contracts-bedrock-tests: + name: contracts-bedrock-tests-develop <> + test_list: find test -name "*.t.sol" + test_profile: ci + features: <> + matrix: + parameters: + features: *features_matrix + context: + - circleci-repo-readonly-authenticated-github-token + - slack + filters: + branches: + only: develop + - contracts-bedrock-coverage: + # Generate coverage reports. + name: contracts-bedrock-coverage <> + test_timeout: 1h + test_profile: cicoverage + features: <> + matrix: + parameters: + features: *features_matrix + context: + - circleci-repo-readonly-authenticated-github-token + - slack + # On PRs, run upgrade tests with lite profile for better build times. + - 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 + test_profile: liteci + features: <> + matrix: + parameters: + features: *features_matrix + context: + - circleci-repo-readonly-authenticated-github-token + - slack + filters: + branches: + ignore: develop + # On develop, run upgrade tests with ci profile to mirror production. + - contracts-bedrock-tests-upgrade: + name: contracts-bedrock-tests-upgrade-develop op-mainnet <> + fork_op_chain: op + fork_base_chain: mainnet + fork_base_rpc: https://ci-mainnet-l1-archive.optimism.io + test_profile: ci + features: <> + matrix: + parameters: + features: *features_matrix + context: + - circleci-repo-readonly-authenticated-github-token + - slack + filters: + branches: + only: develop + # On PRs, run chain-specific upgrade tests with lite profile for better build times. + - contracts-bedrock-tests-upgrade: + name: contracts-bedrock-tests-upgrade <>-mainnet + fork_op_chain: <> + fork_base_chain: mainnet + fork_base_rpc: https://ci-mainnet-l1-archive.optimism.io + test_profile: liteci + matrix: + parameters: + fork_op_chain: ["op", "ink", "unichain"] + context: + - circleci-repo-readonly-authenticated-github-token + - slack + filters: + branches: + ignore: develop + # On develop, run chain-specific upgrade tests with ci profile to mirror production. + - contracts-bedrock-tests-upgrade: + name: contracts-bedrock-tests-upgrade-develop <>-mainnet + fork_op_chain: <> + fork_base_chain: mainnet + fork_base_rpc: https://ci-mainnet-l1-archive.optimism.io + test_profile: ci + matrix: + parameters: + fork_op_chain: ["op", "ink", "unichain"] + context: + - circleci-repo-readonly-authenticated-github-token + - slack + filters: + branches: + only: develop + # Always run L2 fork tests with ci profile + - contracts-bedrock-tests-l2-fork: + name: contracts-bedrock-tests-l2-fork op-mainnet + fork_op_chain: op-mainnet + l2_fork_rpc: https://op-mainnet-rpc.optimism.io/ + l2_fork_block_number: latest + test_profile: ci + context: + - circleci-repo-readonly-authenticated-github-token + - slack + - contracts-bedrock-checks-fast: + context: + - circleci-repo-readonly-authenticated-github-token + - slack + # ----------------------------------------------------------------------- + # required-contracts-ci: GitHub required status for this workflow. Terminal requires + # keep this job scheduled even when upstream jobs fail; ci-gate then checks they passed. + # ----------------------------------------------------------------------- + - required-contracts-ci: + requires: + - contracts-bedrock-tests main: terminal + - contracts-bedrock-tests-heavy-fuzz-modified main: terminal + - contracts-bedrock-coverage main: terminal + - contracts-bedrock-tests-upgrade op-mainnet main: terminal + - contracts-bedrock-checks-fast: terminal + context: + - circleci-api-token + # ============================================================================ + # Required contracts CI gate (skip) — runs when no contract changes + # Produces the required-contracts-ci status so the merge queue doesn't hang. + # ============================================================================ + contracts-feature-tests-short: + when: + not: # these conditions should be kept in sync with the ones in contracts-feature-tests + or: + - and: + - equal: ["webhook", << pipeline.trigger_source >>] + - << pipeline.parameters.c-contracts_changed >> + - << pipeline.parameters.c-non_docs_changes >> + # Always run on develop (mirrors previous check-changed whitelist behavior) + - and: + - equal: ["webhook", << pipeline.trigger_source >>] + - equal: ["develop", << pipeline.git.branch >>] + - << pipeline.parameters.c-non_docs_changes >> + # Merge queue (merge gate). Match checkout branch. + - matches: + pattern: "^gh-readonly-queue/.*" + value: << pipeline.git.branch >> + - and: + - equal: [true, <>] + - equal: ["api", << pipeline.trigger_source >>] + jobs: + - required-contracts-ci: + always-succed: true + context: + - circleci-api-token diff --git a/.circleci/continue/rust-ci.yml b/.circleci/continue/rust-ci.yml index 0ca75948f57..49c1f63833e 100644 --- a/.circleci/continue/rust-ci.yml +++ b/.circleci/continue/rust-ci.yml @@ -4,7 +4,7 @@ version: 2.1 # This file contains all Rust CI commands, parameterized jobs, crate-specific jobs, and workflows. orbs: - utils: ethereum-optimism/circleci-utils@1.0.25 + utils: ethereum-optimism/circleci-utils@1.0.27 gcp-cli: circleci/gcp-cli@3.0.1 codecov: codecov/codecov@5.0.3 @@ -122,7 +122,7 @@ commands: toolchain_version: description: The specific toolchain version for stable channel type: string - default: "1.92.0" + default: "1.94.0" target: description: A custom target architecture to add to the toolchain type: string @@ -794,7 +794,8 @@ jobs: op-reth-compact-codec: docker: - image: <> - resource_class: medium + # This job frequently gets killed for smaller resource_class + resource_class: xlarge steps: - utils/checkout-with-mise: checkout-method: blobless @@ -1133,7 +1134,7 @@ workflows: - rust-build-binary: name: rust-msrv directory: rust - toolchain: "1.92.0" + toolchain: "1.94.0" context: *rust-ci-context # ----------------------------------------------------------------------- @@ -1144,7 +1145,7 @@ workflows: directory: rust command: | just check-no-std - toolchain: "1.92.0" + toolchain: "1.94.0" context: *rust-ci-context - rust-ci-cargo-hack-build: @@ -1174,14 +1175,6 @@ workflows: cache_profile: debug context: *rust-ci-context - - rust-ci-cargo-tests: - name: op-reth-tests-edge - directory: rust - command: "--justfile op-reth/justfile test" - flags: "edge" - cache_profile: debug - context: *rust-ci-context - # ----------------------------------------------------------------------- # Kona crate-specific jobs (lint, FPVM builds, benches, coverage) # ----------------------------------------------------------------------- @@ -1236,14 +1229,6 @@ workflows: cache_profile: debug context: *rust-ci-context - - rust-ci-cargo-tests: - name: op-reth-tests-edge - directory: rust - command: "--justfile op-reth/justfile test" - flags: "edge" - cache_profile: debug - context: *rust-ci-context - - kona-build-fpvm: name: kona-build-fpvm-cannon-client target: "cannon-client" @@ -1253,7 +1238,6 @@ workflows: requires: - rust-tests - op-reth-integration-tests - - op-reth-tests-edge - kona-build-fpvm-cannon-client # ========================================================================== diff --git a/.claude/skills/run-acceptance-tests/SKILL.md b/.claude/skills/run-acceptance-tests/SKILL.md new file mode 100644 index 00000000000..74a509b887c --- /dev/null +++ b/.claude/skills/run-acceptance-tests/SKILL.md @@ -0,0 +1,16 @@ +--- +name: run-acceptance-tests +description: Build dependencies and run acceptance tests locally in the Optimism monorepo. Handles contracts, cannon prestates, Rust binaries, and optional kona prestate. +--- + +# Run Acceptance Tests + +## When to Use + +- Before merging changes that affect devnet behavior +- When CI acceptance tests fail and you need to reproduce locally +- When asked to verify a change works end-to-end + +## Guide + +@docs/ai/acceptance-tests.md diff --git a/.claude/skills/vm-compat-triage/SKILL.md b/.claude/skills/vm-compat-triage/SKILL.md index 748f9e50ba9..cc1d877c2f2 100644 --- a/.claude/skills/vm-compat-triage/SKILL.md +++ b/.claude/skills/vm-compat-triage/SKILL.md @@ -17,8 +17,7 @@ Use when the `analyze-op-program-client` CI job fails on a PR. The job runs `vm- - `gh` CLI authenticated with GitHub - `jq` available -- `vm-compat` binary (install: `mise use -g ubi:ChainSafe/vm-compat@1.1.0`, or download from GitHub releases — binary name is `analyzer-linux-arm64` / `analyzer-linux-amd64`) -- `llvm-objdump` — **Linux only** (install: `sudo apt-get install -y llvm`). Not available on macOS. On macOS, use `just run-vm-compat` in the `op-program` directory which runs the analysis inside Docker. +- Docker — required for `just run-vm-compat` and `just regenerate-vm-compat-baseline`. These targets build and run the analysis inside Docker, so no local `vm-compat` or `llvm-objdump` installation is needed. If Docker is not available, ask the user to run the just target. - The PR URL or number (ask the user if not provided) ## MIPS64 Syscall Reference @@ -270,44 +269,29 @@ Only proceed if ALL findings are marked as either unreachable or acceptable (non **Do NOT manually add entries to the existing baseline.** The baseline must be regenerated from scratch so that stale entries (from code paths that no longer exist) are removed. -To regenerate: +To regenerate, use the `just regenerate-vm-compat-baseline` target from the `op-program` directory in the PR branch worktree. This requires Docker and handles everything end-to-end: -1. Run vm-compat with **no baseline** to get the complete report for the current code: +1. Runs vm-compat with **no baseline** to get the complete report +2. Normalizes the output by stripping assembly-level fields (`line`, `file`, `absPath`) that cause false positives when they change +3. Overwrites the baseline JSON file ```bash -cd op-program && vm-compat analyze \ - --with-trace=true --skip-warnings=false --format=json \ - --vm-profile-config vm-profiles/cannon-multithreaded-64.yaml \ - --report-output-path /tmp/vm-compat-full-report.json \ - ./client/cmd/main.go +cd op-program && just regenerate-vm-compat-baseline ``` -2. Normalize the output by stripping `line`, `file`, and `absPath` fields (these are assembly positions, not Go source lines, and cause false positives when they change): - -```bash -cat /tmp/vm-compat-full-report.json | jq 'walk( - if type == "object" and has("line") then del(.line) else . end | - if type == "object" and has("absPath") then del(.absPath) else . end | - if type == "object" and has("file") then del(.file) else . end -)' > op-program/compatibility-test/baseline-cannon-multithreaded-64.json -``` +If Docker is not available, ask the user to run this command. -3. This replaces the entire baseline with the current state. The old baseline is not merged — it is replaced. +This replaces the entire baseline with the current state. The old baseline is not merged — it is replaced. ### Step 7: Verify -After regenerating the baseline, re-run `vm-compat` with the new baseline to confirm zero new findings: +After regenerating the baseline, re-run vm-compat with the new baseline to confirm zero new findings: ```bash -cd op-program && vm-compat analyze \ - --with-trace=true --skip-warnings=false --format=json \ - --vm-profile-config vm-profiles/cannon-multithreaded-64.yaml \ - --baseline-report compatibility-test/baseline-cannon-multithreaded-64.json \ - --report-output-path /tmp/verify.json \ - ./client/cmd/main.go +cd op-program && just run-vm-compat ``` -If the output file contains an empty array `[]`, the baseline is complete. +If it exits successfully with no findings, the baseline is complete. If Docker is not available, ask the user to run this command. ## Notes diff --git a/.gitignore b/.gitignore index 4031cb1d276..61e8428ec60 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ coverage.json **/lcov-upgrade.info **/lcov-all.info +# Rust files +**/target + yarn-error.log .yarn/* !.yarn/releases @@ -50,4 +53,7 @@ __pycache__ crytic-export # ignore local asdf config -.tool-versions \ No newline at end of file +.tool-versions + +# Rust files +**/target diff --git a/.gitmodules b/.gitmodules index 1856b3a961a..a365d035460 100644 --- a/.gitmodules +++ b/.gitmodules @@ -32,9 +32,6 @@ [submodule "packages/contracts-bedrock/lib/superchain-registry"] path = packages/contracts-bedrock/lib/superchain-registry url = https://github.com/ethereum-optimism/superchain-registry -[submodule "rust/kona/crates/protocol/registry/superchain-registry"] - path = rust/kona/crates/protocol/registry/superchain-registry - url = https://github.com/ethereum-optimism/superchain-registry [submodule "op-rbuilder"] path = op-rbuilder url = https://github.com/flashbots/op-rbuilder diff --git a/.semgrep/rules/sol-rules.yaml b/.semgrep/rules/sol-rules.yaml index d8cf6f16a10..850875124cb 100644 --- a/.semgrep/rules/sol-rules.yaml +++ b/.semgrep/rules/sol-rules.yaml @@ -244,7 +244,6 @@ rules: - /packages/contracts-bedrock/src/L2/L2StandardBridgeInterop.sol - /packages/contracts-bedrock/src/L2/CrossL2Inbox.sol - /packages/contracts-bedrock/src/L1/ResourceMetering.sol - - /packages/contracts-bedrock/src/L1/OPContractsManager.sol - /packages/contracts-bedrock/src/L1/DataAvailabilityChallenge.sol - id: sol-safety-use-disable-initializer @@ -320,14 +319,12 @@ rules: include: - /packages/contracts-bedrock/src exclude: - - /packages/contracts-bedrock/src/L1/OPContractsManager.sol - /packages/contracts-bedrock/src/L1/opcm/OPContractsManagerV2.sol - /packages/contracts-bedrock/src/L1/opcm/OPContractsManagerContainer.sol - /packages/contracts-bedrock/src/L1/opcm/OPContractsManagerUtils.sol - /packages/contracts-bedrock/src/L1/opcm/OPContractsManagerUtilsCaller.sol - /packages/contracts-bedrock/src/L1/opcm/OPContractsManagerMigrator.sol - /packages/contracts-bedrock/src/L1/OptimismPortal2.sol - - /packages/contracts-bedrock/src/L1/OptimismPortalInterop.sol - /packages/contracts-bedrock/src/L2/FeeVault.sol - /packages/contracts-bedrock/src/L2/OptimismMintableERC721.sol - /packages/contracts-bedrock/src/L2/OptimismMintableERC721Factory.sol diff --git a/AGENTS.md b/AGENTS.md index 95abd2a6c7c..08404a83711 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -68,6 +68,7 @@ More detailed guidance for AI agents can be found in: - [docs/ai/contract-dev.md](docs/ai/contract-dev.md) - Smart contract development - [docs/ai/go-dev.md](docs/ai/go-dev.md) - Go service development - [docs/ai/rust-dev.md](docs/ai/rust-dev.md) - Rust development (kona, op-reth, alloy crates) +- [docs/ai/acceptance-tests.md](docs/ai/acceptance-tests.md) - Building and running acceptance tests locally ## External References diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000000..8f155079fbb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,576 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [17.0.0](https://github.com/bluealloy/revm/compare/op-revm-v16.0.0...op-revm-v17.0.0) - 2026-03-04 + +### Other + +- bump revm-database-interface to v10.0.0 + +## [16.0.0](https://github.com/bluealloy/revm/compare/op-revm-v15.0.0...op-revm-v16.0.0) - 2026-03-02 + +### Other + +- *(op-revm)* remove unnecessary enveloped_tx clone in reward_beneficiary ([#3455](https://github.com/bluealloy/revm/pull/3455)) +- *(op-revm)* fix operator fee field doc comments ([#3457](https://github.com/bluealloy/revm/pull/3457)) +- [**breaking**] add logs to Revert and Halt variants of ExecutionResult ([#3424](https://github.com/bluealloy/revm/pull/3424)) +- [**breaking**] add ResultGas struct to ExecutionResult ([#3413](https://github.com/bluealloy/revm/pull/3413)) +- remove GPL mention and update gmp feature comments ([#3383](https://github.com/bluealloy/revm/pull/3383)) +- *(handler)* extract duplicate ContextError handling ([#3312](https://github.com/bluealloy/revm/pull/3312)) +- update default hardfork to Osaka (Ethereum) and Jovian (Optimism) ([#3326](https://github.com/bluealloy/revm/pull/3326)) + +## [15.0.0](https://github.com/bluealloy/revm/compare/op-revm-v14.1.0...op-revm-v15.0.0) - 2026-01-15 + +### Added + +- new gas params, tx initial gas and codedeposit ([#3260](https://github.com/bluealloy/revm/pull/3260)) +- move GasParams to Cfg ([#3229](https://github.com/bluealloy/revm/pull/3229)) +- BAL EIP-7928 ([#3070](https://github.com/bluealloy/revm/pull/3070)) +- early return if the l1 fee scalar is zero ([#3213](https://github.com/bluealloy/revm/pull/3213)) +- Restrict Database::Error. JournaledAccountTr ([#3199](https://github.com/bluealloy/revm/pull/3199)) + +### Other + +- fix typos, grammar errors, and improve documentation consistency ([#3294](https://github.com/bluealloy/revm/pull/3294)) +- happy new year, 2026 licence ([#3272](https://github.com/bluealloy/revm/pull/3272)) +- Remove redundant tx fetch in Optimism handler gas accounting ([#3220](https://github.com/bluealloy/revm/pull/3220)) +- *(fmt)* merge all imports ([#3184](https://github.com/bluealloy/revm/pull/3184)) + +## [14.1.0](https://github.com/bluealloy/revm/compare/op-revm-v14.0.0...op-revm-v14.1.0) - 2025-11-14 + +### Fixed + +- *(op-revm)* return error when enveloped_tx is missing ([#3143](https://github.com/bluealloy/revm/pull/3143)) + +## [14.0.0](https://github.com/bluealloy/revm/compare/op-revm-v12.0.2...op-revm-v14.0.0) - 2025-11-10 + +### Added + +- *(precompiles)* add performant PrecompileError::OtherCowStr variant ([#3144](https://github.com/bluealloy/revm/pull/3144)) +- process precompile logs to inspector ([#3148](https://github.com/bluealloy/revm/pull/3148)) + +## [12.0.2](https://github.com/bluealloy/revm/compare/op-revm-v12.0.1...op-revm-v12.0.2) - 2025-11-10 + +### Fixed + +- *(op)* Ensure L1Block account is always loaded ([#3150](https://github.com/bluealloy/revm/pull/3150)) + +## [12.0.1](https://github.com/bluealloy/revm/compare/op-revm-v12.0.0...op-revm-v12.0.1) - 2025-11-07 + +### Other + +- updated the following local packages: revm + +## [12.0.0](https://github.com/bluealloy/revm/compare/op-revm-v11.2.0...op-revm-v12.0.0) - 2025-10-30 + +### Added + +- JournaledAccount, a nice way to update and track changes ([#3086](https://github.com/bluealloy/revm/pull/3086)) + +### Fixed + +- *(jovian)* fixes the DA footprint update storage slot. fix l1 fork associated with Jovian. ([#3120](https://github.com/bluealloy/revm/pull/3120)) +- *(op-revm)* add missing enveloped_tx validation in validate_env ([#3094](https://github.com/bluealloy/revm/pull/3094)) + +### Other + +- *(op)* use helper function in validate against state ([#3069](https://github.com/bluealloy/revm/pull/3069)) + + +## [11.3.0](https://github.com/bluealloy/revm/compare/op-revm-v11.2.0...op-revm-v11.3.0) - 2025-10-28 + +### Added + +- *(precompiles/jovian)* add jovian precompiles to revm ([#3128](https://github.com/bluealloy/revm/pull/3128)) + + +## [11.2.0](https://github.com/bluealloy/revm/compare/op-revm-v11.1.2...op-revm-v11.2.0) - 2025-10-17 + +### Other + +- updated the following local packages: revm + +## [11.1.2](https://github.com/bluealloy/revm/compare/op-revm-v11.1.1...op-revm-v11.1.2) - 2025-10-15 + +### Other + +- updated the following local packages: revm + +## [11.1.1](https://github.com/bluealloy/revm/compare/op-revm-v11.1.0...op-revm-v11.1.1) - 2025-10-15 + +### Other + +- updated the following local packages: revm + +## [11.1.0](https://github.com/bluealloy/revm/compare/op-revm-v11.0.0...op-revm-v11.1.0) - 2025-10-09 + +### Fixed + +- *(op-revm)* return error instead of panic when enveloped_tx is missing ([#3055](https://github.com/bluealloy/revm/pull/3055)) + +### Other + +- *(op)* backport of #3073 fix for l1block info ([#3076](https://github.com/bluealloy/revm/pull/3076)) +- backport v89 changelog ([#3075](https://github.com/bluealloy/revm/pull/3075)) +- *(op)* split paths for deposit tx in caller deduction ([#3041](https://github.com/bluealloy/revm/pull/3041)) + +## [10.1.1](https://github.com/bluealloy/revm/compare/op-revm-v10.0.0...op-revm-v10.1.1) - 2025-09-23 + +## [11.0.0](https://github.com/bluealloy/revm/compare/op-revm-v10.1.0...op-revm-v11.0.0) - 2025-10-07 + +### Added + +- *(jovian)* add da footprint block limit. ([#3003](https://github.com/bluealloy/revm/pull/3003)) +- *(op-revm)* implement jovian operator fee fix ([#2996](https://github.com/bluealloy/revm/pull/2996)) +- *(op-revm)* Add an option to disable "fee-charge" on `op-revm` ([#2980](https://github.com/bluealloy/revm/pull/2980)) +- [**breaking**] Remove kzg-rs ([#2909](https://github.com/bluealloy/revm/pull/2909)) + +### Fixed + +- add missing is_fee_charge_disabled check ([#3007](https://github.com/bluealloy/revm/pull/3007)) +- Apply spelling corrections from PRs #2926, #2915, #2908 ([#2978](https://github.com/bluealloy/revm/pull/2978)) +- *(op-revm)* clear enveloped_tx for deposit txs in build_fill and align docs ([#2957](https://github.com/bluealloy/revm/pull/2957)) + +### Other + +- changelog update for v87 ([#3056](https://github.com/bluealloy/revm/pull/3056)) +- add boundless ([#3043](https://github.com/bluealloy/revm/pull/3043)) +- helper function gas_balance_spending ([#3030](https://github.com/bluealloy/revm/pull/3030)) +- helper caller_initial_modification added ([#3032](https://github.com/bluealloy/revm/pull/3032)) +- EvmTr and InspectorEvmTr receive all/all_mut fn ([#3037](https://github.com/bluealloy/revm/pull/3037)) +- add ensure_enough_balance helper ([#3033](https://github.com/bluealloy/revm/pull/3033)) +- *(op-revm)* propagate optional_fee_charge feature ([#3020](https://github.com/bluealloy/revm/pull/3020)) +- Set l2_block in try_fetch for pre-Isthmus forks; add reload tests ([#2994](https://github.com/bluealloy/revm/pull/2994)) +- prealloc few frames ([#2965](https://github.com/bluealloy/revm/pull/2965)) +- treat empty input as zero operator fee in operator_fee_charge ([#2973](https://github.com/bluealloy/revm/pull/2973)) +- add SECURITY.md ([#2956](https://github.com/bluealloy/revm/pull/2956)) +- *(op-revm)* rm redundant phantom ([#2943](https://github.com/bluealloy/revm/pull/2943)) +- *(op-revm)* add serialize DepositTransactionParts test ([#2942](https://github.com/bluealloy/revm/pull/2942)) +- *(handler)* provide `&CallInputs`to`PrecompileProvider::run` ([#2921](https://github.com/bluealloy/revm/pull/2921)) + +## [10.1.0](https://github.com/bluealloy/revm/compare/op-revm-v10.0.0...op-revm-v10.1.0) - 2025-09-23 + +### Added + +- *(op-revm)* Add an option to disable "fee-charge" on `op-revm` ([#2980](https://github.com/bluealloy/revm/pull/2980)) + +## [10.0.0](https://github.com/bluealloy/revm/compare/op-revm-v9.0.1...op-revm-v10.0.0) - 2025-08-23 + +### Added + +- *(fusaka)* Add PrecompileId ([#2904](https://github.com/bluealloy/revm/pull/2904)) + +### Fixed + +- *(handler)* correct transaction ID decrement logic ([#2892](https://github.com/bluealloy/revm/pull/2892)) + +## [9.0.1](https://github.com/bluealloy/revm/compare/op-revm-v9.0.0...op-revm-v9.0.1) - 2025-08-12 + +### Other + +- updated the following local packages: revm + +## [9.0.0](https://github.com/bluealloy/revm/compare/op-revm-v8.1.0...op-revm-v9.0.0) - 2025-08-06 + +### Added + +- fix renamed functions for system_call ([#2824](https://github.com/bluealloy/revm/pull/2824)) +- refactor test utils ([#2813](https://github.com/bluealloy/revm/pull/2813)) +- add system transaction inspection support ([#2808](https://github.com/bluealloy/revm/pull/2808)) +- Align naming of SystemCallEvm function to ExecuteEvm ([#2814](https://github.com/bluealloy/revm/pull/2814)) +- rename bn128 to bn254 for Ethereum standard consistency ([#2810](https://github.com/bluealloy/revm/pull/2810)) + +### Fixed + +- *(op-revm)* system tx not enveloped ([#2807](https://github.com/bluealloy/revm/pull/2807)) +- nonce changed is not reverted in journal if fail due to insufficient balance ([#2805](https://github.com/bluealloy/revm/pull/2805)) + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- *(op-revm)* Adds caller nonce assertion to op-revm intergation tests ([#2815](https://github.com/bluealloy/revm/pull/2815)) +- *(op-revm)* Full test coverage `OpTransactionError` ([#2818](https://github.com/bluealloy/revm/pull/2818)) +- Update test data for renamed tests ([#2817](https://github.com/bluealloy/revm/pull/2817)) +- reuse global crypto provide idea ([#2786](https://github.com/bluealloy/revm/pull/2786)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +- add OnceLock re-export with no_std support ([#2787](https://github.com/bluealloy/revm/pull/2787)) +- Add dyn Crypto trait to PrecompileFn ([#2772](https://github.com/bluealloy/revm/pull/2772)) + +## [8.1.0](https://github.com/bluealloy/revm/compare/op-revm-v8.0.3...op-revm-v8.1.0) - 2025-07-23 + +### Added + +- *(osaka)* update EIP-7825 constant ([#2753](https://github.com/bluealloy/revm/pull/2753)) + +### Fixed + +- gas deduction with `disable_balance_check` ([#2699](https://github.com/bluealloy/revm/pull/2699)) + +### Other + +- *(op-revm)* test for optional balance check ([#2746](https://github.com/bluealloy/revm/pull/2746)) +- change gas parameter to immutable reference ([#2702](https://github.com/bluealloy/revm/pull/2702)) + +## [8.0.3](https://github.com/bluealloy/revm/compare/op-revm-v8.0.2...op-revm-v8.0.3) - 2025-07-14 + +### Other + +- simplify gas calculations by introducing a used() method ([#2703](https://github.com/bluealloy/revm/pull/2703)) + +## [8.0.2](https://github.com/bluealloy/revm/compare/op-revm-v8.0.1...op-revm-v8.0.2) - 2025-07-03 + +### Other + +- updated the following local packages: revm + +## [8.0.1](https://github.com/bluealloy/revm/compare/op-revm-v7.0.1...op-revm-v8.0.1) - 2025-06-30 + +### Added + +- optional_eip3541 ([#2661](https://github.com/bluealloy/revm/pull/2661)) + +### Other + +- cargo clippy --fix --all ([#2671](https://github.com/bluealloy/revm/pull/2671)) +- *(op/handler)* verify caller account is touched by zero value transfer ([#2669](https://github.com/bluealloy/revm/pull/2669)) +- use TxEnv::builder ([#2652](https://github.com/bluealloy/revm/pull/2652)) + +## [7.0.1](https://github.com/bluealloy/revm/compare/op-revm-v7.0.0...op-revm-v7.0.1) - 2025-06-20 + +### Fixed + +- call stack_frame.clear() at end ([#2656](https://github.com/bluealloy/revm/pull/2656)) + +## [7.0.0](https://github.com/bluealloy/revm/compare/op-revm-v6.0.0...op-revm-v7.0.0) - 2025-06-19 + +### Added + +- add fallible conversion from OpHaltReason to HaltReason ([#2649](https://github.com/bluealloy/revm/pull/2649)) +- remove EOF ([#2644](https://github.com/bluealloy/revm/pull/2644)) +- *(precompile)* rug/gmp-based modexp ([#2596](https://github.com/bluealloy/revm/pull/2596)) +- enable P256 in Osaka ([#2601](https://github.com/bluealloy/revm/pull/2601)) + +### Other + +- re-use frame allocation ([#2636](https://github.com/bluealloy/revm/pull/2636)) +- rename `transact` methods ([#2616](https://github.com/bluealloy/revm/pull/2616)) + +## [6.0.0](https://github.com/bluealloy/revm/compare/op-revm-v5.0.1...op-revm-v6.0.0) - 2025-06-06 + +### Added + +- add with_caller for system_transact ([#2587](https://github.com/bluealloy/revm/pull/2587)) +- *(Osaka)* EIP-7825 tx limit cap ([#2575](https://github.com/bluealloy/revm/pull/2575)) +- expand timestamp/block_number to u256 ([#2546](https://github.com/bluealloy/revm/pull/2546)) +- transact multi tx ([#2517](https://github.com/bluealloy/revm/pull/2517)) + +### Fixed + +- *(multitx)* Add local flags for create and selfdestruct ([#2581](https://github.com/bluealloy/revm/pull/2581)) + +### Other + +- tag v75 revm v24.0.1 ([#2563](https://github.com/bluealloy/revm/pull/2563)) ([#2589](https://github.com/bluealloy/revm/pull/2589)) +- *(op-revm)* impl type alias for Default OpEvm ([#2576](https://github.com/bluealloy/revm/pull/2576)) +- *(docs)* add lints to database-interface and op-revm crates ([#2568](https://github.com/bluealloy/revm/pull/2568)) +- ContextTr rm *_ref, and add *_mut fn ([#2560](https://github.com/bluealloy/revm/pull/2560)) +- *(test)* preserve order of fields in json fixtures ([#2541](https://github.com/bluealloy/revm/pull/2541)) + +## [5.0.1](https://github.com/bluealloy/revm/compare/op-revm-v5.0.0...op-revm-v5.0.1) - 2025-05-31 + +### Other + +- updated the following local packages: revm + +## [5.0.0](https://github.com/bluealloy/revm/compare/op-revm-v4.0.2...op-revm-v5.0.0) - 2025-05-22 + +### Added + +- *(op-revm)* add testdata comparison utility for EVM execution output ([#2525](https://github.com/bluealloy/revm/pull/2525)) + +### Other + +- make crates.io version badge clickable ([#2526](https://github.com/bluealloy/revm/pull/2526)) + +## [4.0.2](https://github.com/bluealloy/revm/compare/op-revm-v4.0.1...op-revm-v4.0.2) - 2025-05-09 + +### Fixed + +- *(op)* bump nonce on deposit ([#2503](https://github.com/bluealloy/revm/pull/2503)) +- *(op)* call cleanup on local context ([#2499](https://github.com/bluealloy/revm/pull/2499)) + +### Other + +- *(op)* revert previous and localize fix ([#2504](https://github.com/bluealloy/revm/pull/2504)) + +## [4.0.1](https://github.com/bluealloy/revm/compare/op-revm-v4.0.0...op-revm-v4.0.1) - 2025-05-09 + +### Fixed + +- *(op)* mark caller account as touched ([#2495](https://github.com/bluealloy/revm/pull/2495)) + +### Other + +- *(op)* Add test coverage to OP result module ([#2491](https://github.com/bluealloy/revm/pull/2491)) +- *(op)* Add test coverage to `OpTransactionError` ([#2490](https://github.com/bluealloy/revm/pull/2490)) + +## [4.0.0](https://github.com/bluealloy/revm/compare/op-revm-v3.1.0...op-revm-v4.0.0) - 2025-05-07 + +Dependency bump + +## [3.1.0](https://github.com/bluealloy/revm/compare/op-revm-v3.0.2...op-revm-v3.1.0) - 2025-05-07 + +### Added + +- system_call switch order of inputs, address than bytes ([#2485](https://github.com/bluealloy/revm/pull/2485)) +- *(Osaka)* disable EOF ([#2480](https://github.com/bluealloy/revm/pull/2480)) +- skip cloning of call input from shared memory ([#2462](https://github.com/bluealloy/revm/pull/2462)) +- *(Handler)* merge state validation with deduct_caller ([#2460](https://github.com/bluealloy/revm/pull/2460)) +- *(tx)* Add Either RecoveredAuthorization ([#2448](https://github.com/bluealloy/revm/pull/2448)) +- add precompiles getter to OpPrecompiles ([#2444](https://github.com/bluealloy/revm/pull/2444)) +- *(EOF)* Changes needed for devnet-1 ([#2377](https://github.com/bluealloy/revm/pull/2377)) + +### Other + +- *(op)* Set l2 block num in reloaded isthmus l1 block info ([#2465](https://github.com/bluealloy/revm/pull/2465)) +- Add clones to FrameData ([#2482](https://github.com/bluealloy/revm/pull/2482)) +- *(op)* Add test for verifying default OpSpecId update ([#2478](https://github.com/bluealloy/revm/pull/2478)) +- copy edit The Book ([#2463](https://github.com/bluealloy/revm/pull/2463)) +- bump dependency version ([#2431](https://github.com/bluealloy/revm/pull/2431)) +- fixed broken link ([#2421](https://github.com/bluealloy/revm/pull/2421)) +- backport from release branch ([#2415](https://github.com/bluealloy/revm/pull/2415)) ([#2416](https://github.com/bluealloy/revm/pull/2416)) + +## [3.0.2](https://github.com/bluealloy/revm/compare/op-revm-v3.0.1...op-revm-v3.0.2) - 2025-04-15 + +### Other + +## [3.0.1](https://github.com/bluealloy/revm/compare/op-revm-v3.0.0...op-revm-v3.0.1) - 2025-04-13 + +### Fixed + +- *(isthmus)* Add input size limitations to bls12-381 {G1/G2} MSM + pairing ([#2406](https://github.com/bluealloy/revm/pull/2406)) + +## [3.0.0](https://github.com/bluealloy/revm/compare/op-revm-v2.0.0...op-revm-v3.0.0) - 2025-04-09 + +### Added + +- support for system calls ([#2350](https://github.com/bluealloy/revm/pull/2350)) + +### Other + +- bump alloy 13.0.0 and alloy-primitives v1.0.0 ([#2394](https://github.com/bluealloy/revm/pull/2394)) +- fixed `EIP` to `RIP` ([#2388](https://github.com/bluealloy/revm/pull/2388)) +- clean unsed indicatif ([#2379](https://github.com/bluealloy/revm/pull/2379)) +- *(op-inspector)* Add test for inspecting logs ([#2352](https://github.com/bluealloy/revm/pull/2352)) +- *(op-tx)* Cover DepositTransactionParts constructor in test ([#2358](https://github.com/bluealloy/revm/pull/2358)) +- add 0x prefix to b256! and address! calls ([#2345](https://github.com/bluealloy/revm/pull/2345)) + +## [2.0.0](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0...op-revm-v2.0.0) - 2025-03-28 + +### Added + +- cache precompile warming ([#2317](https://github.com/bluealloy/revm/pull/2317)) +- Add arkworks wrapper for bls12-381 ([#2316](https://github.com/bluealloy/revm/pull/2316)) +- provide more context to precompiles ([#2318](https://github.com/bluealloy/revm/pull/2318)) +- Add a wrapper for arkworks for EIP196 ([#2305](https://github.com/bluealloy/revm/pull/2305)) + +### Fixed + +- *(isthmus)* Correctly filter refunds for deposit transactions ([#2330](https://github.com/bluealloy/revm/pull/2330)) + +### Other + +- Remove LATEST variant from SpecId enum ([#2299](https://github.com/bluealloy/revm/pull/2299)) + +## [1.0.0](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0-alpha.6...op-revm-v1.0.0) - 2025-03-24 + +### Other + +- *(op-precompiles)* Add test for checking that op default precompiles is updated ([#2291](https://github.com/bluealloy/revm/pull/2291)) +- *(op-precompiles)* Add missing g2 add tests ([#2253](https://github.com/bluealloy/revm/pull/2253)) + +## [1.0.0-alpha.6](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0-alpha.5...op-revm-v1.0.0-alpha.6) - 2025-03-21 + +### Added + +- InspectEvm fn renames, inspector docs, book cleanup ([#2275](https://github.com/bluealloy/revm/pull/2275)) +- Return Fatal error on bls precompiles if in no_std ([#2249](https://github.com/bluealloy/revm/pull/2249)) +- Remove PrecompileError from PrecompileProvider ([#2233](https://github.com/bluealloy/revm/pull/2233)) + +### Fixed + +- *(op)* deposit txs are identifier 126 or 0x7e not 0x7f ([#2237](https://github.com/bluealloy/revm/pull/2237)) + +### Other + +- bring operator fee fixes to trunk ([#2273](https://github.com/bluealloy/revm/pull/2273)) +- *(op-test-cov)* Add test for serializing deposit transaction parts ([#2267](https://github.com/bluealloy/revm/pull/2267)) +- *(op-precompiles)* Check subset of l1 precompiles in op ([#2204](https://github.com/bluealloy/revm/pull/2204)) +- *(op-handler)* Add test for halted deposit tx post regolith ([#2269](https://github.com/bluealloy/revm/pull/2269)) +- *(op)* Remove redundant trait DepositTransaction ([#2265](https://github.com/bluealloy/revm/pull/2265)) +- Fix sys deposit tx gas test ([#2263](https://github.com/bluealloy/revm/pull/2263)) +- remove wrong `&mut` and duplicated spec ([#2276](https://github.com/bluealloy/revm/pull/2276)) +- *(op-precompiles)* clean up op tx tests ([#2242](https://github.com/bluealloy/revm/pull/2242)) +- make str to SpecId conversion fallible ([#2236](https://github.com/bluealloy/revm/pull/2236)) +- *(op-precompiles)* Add tests for bls12-381 map fp to g ([#2241](https://github.com/bluealloy/revm/pull/2241)) +- add a safe blst wrapper ([#2223](https://github.com/bluealloy/revm/pull/2223)) +- *(op-precompiles)* Reuse tests for bls12-381 msm tests for pairing ([#2239](https://github.com/bluealloy/revm/pull/2239)) +- *(op-precompiles)* add bls12-381 g2 add and msm tests ([#2231](https://github.com/bluealloy/revm/pull/2231)) +- *(op-precompiles)* Add test for g1 msm ([#2227](https://github.com/bluealloy/revm/pull/2227)) +- simplify single UT for OpSpecId compatibility. ([#2216](https://github.com/bluealloy/revm/pull/2216)) +- use AccessListItem associated type instead of AccessList ([#2214](https://github.com/bluealloy/revm/pull/2214)) + +## [1.0.0-alpha.5](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0-alpha.4...op-revm-v1.0.0-alpha.5) - 2025-03-16 + +### Added + +- *(docs)* MyEvm example and book cleanup ([#2218](https://github.com/bluealloy/revm/pull/2218)) +- add test for calling `bn128_pair` before and after granite ([#2200](https://github.com/bluealloy/revm/pull/2200)) + +### Other + +- *(op-precompiles)* Add test for calling g1 add ([#2205](https://github.com/bluealloy/revm/pull/2205)) +- *(op-test)* Clean up precompile tests ([#2206](https://github.com/bluealloy/revm/pull/2206)) +- fix typo in method name ([#2202](https://github.com/bluealloy/revm/pull/2202)) +- Add tests for checking fjord precompile activation ([#2199](https://github.com/bluealloy/revm/pull/2199)) + +## [1.0.0-alpha.4](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0-alpha.3...op-revm-v1.0.0-alpha.4) - 2025-03-12 + +### Added + +- Add tx/block to EvmExecution trait ([#2195](https://github.com/bluealloy/revm/pull/2195)) +- rename inspect_previous to inspect_replay ([#2194](https://github.com/bluealloy/revm/pull/2194)) + +### Other + +- add debug to precompiles type ([#2193](https://github.com/bluealloy/revm/pull/2193)) + +## [1.0.0-alpha.3](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0-alpha.2...op-revm-v1.0.0-alpha.3) - 2025-03-11 + +### Fixed + +- fix(op) enable proper precompiles p256 ([#2186](https://github.com/bluealloy/revm/pull/2186)) +- *(op)* fix inspection call ([#2184](https://github.com/bluealloy/revm/pull/2184)) +- correct propagate features ([#2177](https://github.com/bluealloy/revm/pull/2177)) + +### Other + +- remove CTX phantomdata from precompile providers ([#2178](https://github.com/bluealloy/revm/pull/2178)) + +## [1.0.0-alpha.2](https://github.com/bluealloy/revm/compare/op-revm-v1.0.0-alpha.1...op-revm-v1.0.0-alpha.2) - 2025-03-10 + +### Other + +- updated the following local packages: revm + +## [1.0.0-alpha.1](https://github.com/bluealloy/revm/releases/tag/revm-optimism-v1.0.0-alpha.1) - 2025-02-16 + +### Added + +- Split Inspector trait from EthHandler into standalone crate (#2075) +- Introduce Auth and AccessList traits (#2079) +- derive Eq for OpSpec (#2073) +- *(op)* Isthmus precompiles (#2054) +- Evm structure (Cached Instructions and Precompiles) (#2049) +- simplify InspectorContext (#2036) +- Context execution (#2013) +- EthHandler trait (#2001) +- extract and export `estimate_tx_compressed_size` (#1985) +- *(EIP-7623)* Increase calldata cost. backport from rel/v51 (#1965) +- simplify Transaction trait (#1959) +- Split inspector.rs (#1958) +- align Block trait (#1957) +- expose precompile address in Journal, DB::Error: StdError (#1956) +- add isthmus spec (#1938) +- integrate codspeed (#1935) +- Make Ctx journal generic (#1933) +- Restucturing Part7 Handler and Context rework (#1865) +- restructuring Part6 transaction crate (#1814) +- Restructuring Part3 inspector crate (#1788) +- restructure Part2 database crate (#1784) +- project restructuring Part1 (#1776) +- introducing EvmWiring, a chain-specific configuration (#1672) +- *(examples)* generate block traces (#895) +- implement EIP-4844 (#668) +- *(Shanghai)* All EIPs: push0, warm coinbase, limit/measure initcode (#376) +- Migrate `primitive_types::U256` to `ruint::Uint<256, 4>` (#239) +- Introduce ByteCode format, Update Readme (#156) + +### Fixed + +- make macro crate-agnostic (#1802) +- fix typos ([#620](https://github.com/bluealloy/revm/pull/620)) + +### Other + +- set alpha.1 version +- backport op l1 fetch perf (#2076) +- remove OpSpec (#2074) +- Add helpers with_inspector with_precompile (#2063) +- *(op)* backport isthmus operator fee (#2059) +- Bump licence year to 2025 (#2058) +- rename OpHaltReason (#2042) +- simplify some generics (#2032) +- align crates versions (#1983) +- Make inspector use generics, rm associated types (#1934) +- add OpTransaction conversion tests (#1939) +- fix comments and docs into more sensible (#1920) +- Rename PRAGUE_EOF to OSAKA (#1903) +- refactor L1BlockInfo::tx_estimated_size_fjord (#1856) +- *(primitives)* replace HashMap re-exports with alloy_primitives::map (#1805) +- Test for l1 gas used and l1 fee for ecotone tx (#1748) +- *(deps)* bump anyhow from 1.0.88 to 1.0.89 (#1772) +- Bump new logo (#1735) +- *(README)* add rbuilder to used-by (#1585) +- added simular to used-by (#1521) +- add Trin to used by list (#1393) +- Fix typo in readme ([#1185](https://github.com/bluealloy/revm/pull/1185)) +- Add Hardhat to the "Used by" list ([#1164](https://github.com/bluealloy/revm/pull/1164)) +- Add VERBS to used by list ([#1141](https://github.com/bluealloy/revm/pull/1141)) +- license date and revm docs (#1080) +- *(docs)* Update the benchmark docs to point to revm package (#906) +- *(docs)* Update top-level benchmark docs (#894) +- clang requirement (#784) +- Readme Updates (#756) +- Logo (#743) +- book workflow ([#537](https://github.com/bluealloy/revm/pull/537)) +- add example to revm crate ([#468](https://github.com/bluealloy/revm/pull/468)) +- Update README.md ([#424](https://github.com/bluealloy/revm/pull/424)) +- add no_std to primitives ([#366](https://github.com/bluealloy/revm/pull/366)) +- revm-precompiles to revm-precompile +- Bump v20, changelog ([#350](https://github.com/bluealloy/revm/pull/350)) +- typos (#232) +- Add support for old forks. ([#191](https://github.com/bluealloy/revm/pull/191)) +- revm bump 1.8. update libs. snailtracer rename ([#159](https://github.com/bluealloy/revm/pull/159)) +- typo fixes +- fix readme typo +- Big Refactor. Machine to Interpreter. refactor instructions. call/create struct ([#52](https://github.com/bluealloy/revm/pull/52)) +- readme. debuger update +- Bump revm v0.3.0. README updated +- readme +- Add time elapsed for tests +- readme updated +- Include Basefee into cost calc. readme change +- Initialize precompile accounts +- Status update. Taking a break +- Merkle calc. Tweaks and debugging for eip158 +- Replace aurora bn lib with parity's. All Bn128Add/Mul/Pair tests passes +- TEMP +- one tab removed +- readme +- README Example simplified +- Gas calculation for Call/Create. Example Added +- readme usage +- README changes +- Static gas cost added +- Subroutine changelogs and reverts +- Readme postulates +- Spelling +- Restructure project +- First iteration. Machine is looking okay diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000000..0c6bf0a3b2a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,69 @@ +[package] +name = "op-revm" +description = "Optimism variant of Revm" +version = "17.0.0" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +# revm +revm.workspace = true +auto_impl.workspace = true + +# Optional +serde = { workspace = true, features = ["derive", "rc"], optional = true } + +[dev-dependencies] +rstest.workspace = true +alloy-sol-types.workspace = true +sha2.workspace = true +serde_json = { workspace = true, features = ["alloc", "preserve_order"] } +serde = { workspace = true, features = ["derive"] } +alloy-primitives.workspace = true + +[features] +default = ["std", "c-kzg", "secp256k1", "portable", "blst"] +std = [ + "serde?/std", + "revm/std", + "alloy-sol-types/std", + "sha2/std", + "serde_json/std", + "alloy-primitives/std", +] +serde = ["dep:serde", "revm/serde", "alloy-primitives/serde"] +portable = ["revm/portable"] + +dev = [ + "revm/dev", + "memory_limit", + "optional_balance_check", + "optional_block_gas_limit", + "optional_eip3541", + "optional_eip3607", + "optional_no_base_fee", +] +memory_limit = ["revm/memory_limit"] +optional_balance_check = ["revm/optional_balance_check"] +optional_block_gas_limit = ["revm/optional_block_gas_limit"] +optional_eip3541 = ["revm/optional_eip3541"] +optional_eip3607 = ["revm/optional_eip3607"] +optional_no_base_fee = ["revm/optional_no_base_fee"] +optional_fee_charge = ["revm/optional_fee_charge"] + +# See comments in `revm-precompile` +secp256k1 = ["revm/secp256k1"] +c-kzg = ["revm/c-kzg"] +blst = ["revm/blst"] +bn = ["revm/bn"] diff --git a/cannon/cmd/run.go b/cannon/cmd/run.go index 5835bc721f7..288f9e88a52 100644 --- a/cannon/cmd/run.go +++ b/cannon/cmd/run.go @@ -523,14 +523,21 @@ func Run(ctx *cli.Context) error { l.Info("Stopping at preimage read") break } - if len(stopAtPreimageKeyPrefix) > 0 && - slices.Equal(lastPreimageKey[:len(stopAtPreimageKeyPrefix)], stopAtPreimageKeyPrefix) { + matchesKeyPrefix := len(stopAtPreimageKeyPrefix) > 0 && + slices.Equal(lastPreimageKey[:len(stopAtPreimageKeyPrefix)], stopAtPreimageKeyPrefix) + matchesSize := stopAtPreimageLargerThan != 0 && len(lastPreimageValue) > stopAtPreimageLargerThan + if matchesKeyPrefix && matchesSize { + // Both type and size conditions specified - require both to match + l.Info("Stopping at preimage read", "keyPrefix", common.Bytes2Hex(stopAtPreimageKeyPrefix), "size", len(lastPreimageValue), "min", stopAtPreimageLargerThan) + break + } + if matchesKeyPrefix && stopAtPreimageLargerThan == 0 { if stopAtPreimageOffset == lastPreimageOffset && step >= stopAtPreimageStep { l.Info("Stopping at preimage read", "keyPrefix", common.Bytes2Hex(stopAtPreimageKeyPrefix), "offset", lastPreimageOffset, "step", step) break } } - if stopAtPreimageLargerThan != 0 && len(lastPreimageValue) > stopAtPreimageLargerThan { + if matchesSize && len(stopAtPreimageKeyPrefix) == 0 { l.Info("Stopping at preimage read", "size", len(lastPreimageValue), "min", stopAtPreimageLargerThan) break } diff --git a/docs/ai/acceptance-tests.md b/docs/ai/acceptance-tests.md new file mode 100644 index 00000000000..2b91777e464 --- /dev/null +++ b/docs/ai/acceptance-tests.md @@ -0,0 +1,99 @@ +# Acceptance Tests + +Guidance for AI agents building and running acceptance tests in the Optimism monorepo. See [dev-workflow.md](dev-workflow.md) for tool versions and general workflow. + +## What Are Acceptance Tests? + +Acceptance tests live in `op-acceptance-tests/tests/` and run full in-process devnet scenarios. They exercise the entire stack — contracts, Go services, and Rust binaries — in a single `go test` process. This means all dependencies must be built locally before running them. + +## Running Tests + +All `just` targets below automatically build dependencies (contracts, cannon prestates, Rust binaries) before running tests. The builds are incremental — re-running is fast when nothing changed. + +**Prerequisites:** mise tools must be installed (see [dev-workflow.md](dev-workflow.md#setup)), and a working C toolchain (`clang` or `gcc`) must be available for Rust builds. + +Always set `RUST_JIT_BUILD=1` when running locally. This lets the test framework automatically build any Rust binaries it needs (e.g. op-reth) using cargo's rebuild detection, so you don't have to pre-build them separately. + +Run from `op-acceptance-tests/`: + +### Specific Tests or Packages (recommended) + +```bash +# Run a single test +RUST_JIT_BUILD=1 cd op-acceptance-tests && mise exec -- just test -run TestMyTest ./op-acceptance-tests/tests/base/ + +# Run a package +RUST_JIT_BUILD=1 cd op-acceptance-tests && mise exec -- just test ./op-acceptance-tests/tests/base/... +``` + +The `just test` target builds deps, then runs `go test -count=1 -timeout 30m` with your arguments. + +### All Tests + +```bash +RUST_JIT_BUILD=1 cd op-acceptance-tests && mise exec -- just acceptance-test +``` + +Runs all test packages with gotestsum, structured logging, and auto-tuned parallelism. + +### Gated Subsets + +Gate files in `op-acceptance-tests/gates/` list package subsets: + +```bash +RUST_JIT_BUILD=1 cd op-acceptance-tests && mise exec -- just acceptance-test base +``` + +This runs only packages listed in `gates/base.txt`. + +### Kona Reproducible Prestate + +Some tests (e.g. superfaultproofs, interop fault proofs) require a reproducible kona prestate. This is **not** handled by `build-deps` or `RUST_JIT_BUILD`: + +```bash +mise exec -- just reproducible-prestate-kona +``` + +**Requires Docker.** If Docker is not available in your environment, ask the user to run this command for you. + +## What `build-deps` Does + +The `just build-deps` target (called automatically by `just test` and `just acceptance-test`) runs these steps when not in CI: + +1. **mise** — `mise install` (ensures gotestsum, forge, etc. are available) +2. **Contracts** — `cd packages/contracts-bedrock && just install && just build-no-tests` +3. **Cannon prestates** — `just cannon-prestates` (builds cannon, op-program, and prestate artifacts) +4. **Rust binaries** — `just build-rust-release` (kona-node, op-rbuilder, rollup-boost) + +You can also run `just build-deps` directly to pre-build without running tests. + +## Tuning Parallelism (`acceptance-test` only) + +When using `just acceptance-test`, the runner auto-detects CPU count and sets: +- `ACCEPTANCE_TEST_JOBS` — number of packages to test in parallel (default: CPU count) +- `ACCEPTANCE_TEST_PARALLEL` — `go test -parallel` value per package (default: CPU count / 2) +- `ACCEPTANCE_TEST_TIMEOUT` — per-package timeout (default: 2h) + +Override with environment variables: + +```bash +ACCEPTANCE_TEST_PARALLEL=2 ACCEPTANCE_TEST_TIMEOUT=1h cd op-acceptance-tests && mise exec -- just acceptance-test +``` + +## Log Output (`acceptance-test` only) + +When using `just acceptance-test`, logs are written to `op-acceptance-tests/logs/testrun-/`: +- `all.log` — full test output +- `raw_go_events.log` — JSON test events +- `flaky-tests.txt` — tests marked with `MarkFlaky()` + +Results XML goes to `op-acceptance-tests/results/results.xml`. + +When using `just test`, output goes to stdout only. + +## Common Issues + +- **Missing prestates** — Run `cd op-acceptance-tests && mise exec -- just build-deps` or `mise exec -- just cannon-prestates` from the repo root. +- **Stale contracts** — Rebuild with `cd packages/contracts-bedrock && mise exec -- just build-no-tests`. +- **Missing Rust binaries** — Run `mise exec -- just build-rust-release` from the repo root. +- **gotestsum not found** — Run `mise install` to install all pinned tools. diff --git a/docs/ai/dev-workflow.md b/docs/ai/dev-workflow.md index c2b6005fd1f..421b0e39c6a 100644 --- a/docs/ai/dev-workflow.md +++ b/docs/ai/dev-workflow.md @@ -1,6 +1,6 @@ # Development Workflow -Common workflow guidance for AI agents working in the Optimism monorepo. Language-specific details are in [go-dev.md](go-dev.md) and [rust-dev.md](rust-dev.md). +Common workflow guidance for AI agents working in the Optimism monorepo. Language-specific details are in [go-dev.md](go-dev.md) and [rust-dev.md](rust-dev.md). For end-to-end testing, see [acceptance-tests.md](acceptance-tests.md). ## Tool Versions @@ -8,6 +8,14 @@ All tool versions are pinned in `mise.toml` at the repo root. Always access tool If mise reports the repo isn't trusted, ask the user to run `mise trust` — never trust it automatically. +### Setup + +Run `mise install` to install all pinned tools (just, gotestsum, forge, etc.). AI agent shells typically do not have mise activated, so prefix commands with `mise exec --` to ensure tools are on `PATH`: + +```bash +mise exec -- just +``` + ## Build System The repo uses [Just](https://github.com/casey/just) as its build system. Shared justfile infrastructure lives in `justfiles/`. Each component has its own justfile — run `just --list` in any directory to see available targets. diff --git a/docs/ai/rust-dev.md b/docs/ai/rust-dev.md index d3b47e2212c..04bbc92c167 100644 --- a/docs/ai/rust-dev.md +++ b/docs/ai/rust-dev.md @@ -47,6 +47,30 @@ just test-unit just test-docs ``` +### Running op-reth E2E Tests + +The op-reth E2E tests (`rust/op-reth/tests/proofs/`) run a full devnet with op-geth (sequencer) and op-reth (validator). They require two build prerequisites: + +1. **Forge artifacts** — the devnet deploys contracts from compiled artifacts: + ```bash + cd packages/contracts-bedrock + mise exec -- just build-no-tests + ``` + +2. **op-reth release binary** — the test harness (`op-devstack/sysgo/rust_binary.go`) only searches `target/release/`, not `target/debug/`. Options: + ```bash + # Option A: let the test build it (slow first run, cached after) + RUST_JIT_BUILD=1 go test -v -run TestName ./rust/op-reth/tests/proofs/core/ + + # Option B: pre-build the binary + cd rust && just build-op-reth + ``` + +Run from the monorepo root: +```bash +mise exec -- go test -v -run TestExecutePayloadSuccess -count=1 ./rust/op-reth/tests/proofs/core/ +``` + ### Generating Prestates Kona prestates are built via Docker: diff --git a/docs/public-docs/DOCS_CONTRIBUTING.md b/docs/public-docs/DOCS_CONTRIBUTING.md index 1f9f5a4c874..9cfe07520dd 100644 --- a/docs/public-docs/DOCS_CONTRIBUTING.md +++ b/docs/public-docs/DOCS_CONTRIBUTING.md @@ -22,8 +22,8 @@ Thanks for taking the time to contribute! ❤️ ## Overview -Optimism's documentation is open-source and hosted on GitHub in the `ethereum-optimism/docs` repository. The documentation is rendered at [docs.optimism.io](https://docs.optimism.io). You can contribute either by: -- Forking the `docs` repository and working locally +Optimism's documentation is open-source and hosted on GitHub in the [`ethereum-optimism/optimism`](https://github.com/ethereum-optimism/optimism) monorepo under [`docs/public-docs`](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs). The documentation is rendered at [docs.optimism.io](https://docs.optimism.io). You can contribute either by: +- Forking the `optimism` repository and working locally - Using the "Suggest edits" button on any documentation page for smaller updates All contributions, pull requests, and issues should be in English at this time. @@ -67,10 +67,10 @@ Follow these [docs](https://www.mintlify.com/docs/installation) for local change - Fix any reported issues - Verify content accuracy - Test all links and references -- Target the `mintlify` branch (`main` needs to be cleaned up) +- Target the `develop` branch ### Submission Guidelines -1. Create a [new pull request](https://github.com/ethereum-optimism/docs/issues/new/choose) +1. Create a [new pull request](https://github.com/ethereum-optimism/optimism/compare) 2. Choose appropriate PR type or use blank template 3. Provide clear title and accurate description 4. Add labels diff --git a/docs/public-docs/README.md b/docs/public-docs/README.md index b27d2409157..baa3d106130 100644 --- a/docs/public-docs/README.md +++ b/docs/public-docs/README.md @@ -1,6 +1,6 @@ # Optimism Docs -This repo houses the Optimism Docs located at [docs.optimism.io](https://docs.optimism.io/). All documentation-related updates and new content will be tracked and maintained in this repo. +This directory houses the Optimism Docs located at [docs.optimism.io](https://docs.optimism.io/). All documentation-related updates and new content will be tracked and maintained here, within the [`ethereum-optimism/optimism`](https://github.com/ethereum-optimism/optimism) monorepo. ## Local Development diff --git a/docs/public-docs/STYLE_GUIDE.md b/docs/public-docs/STYLE_GUIDE.md index c52315d01d2..ea84f63f64e 100644 --- a/docs/public-docs/STYLE_GUIDE.md +++ b/docs/public-docs/STYLE_GUIDE.md @@ -6,7 +6,7 @@ This Style Guide aims to assist Optimists in writing technical content with a co This doc doesn't cover all questions or use-cases. Our guide is based on the [Microsoft Writing Style Guide](https://learn.microsoft.com/en-us/style-guide/welcome/). Please reference their guide for any use-case or situation we do not cover here. -* For docs-related questions or comments, create an issue in the [docs repo](https://github.com/ethereum-optimism/docs/issues). +* For docs-related questions or comments, create an issue in the [docs repo](https://github.com/ethereum-optimism/optimism/issues). * For support-related questions or comments, create an issue in the [developers repo](https://github.com/ethereum-optimism/developers/issues). ## Table of Contents @@ -23,7 +23,7 @@ This doc doesn't cover all questions or use-cases. Our guide is based on the [Mi ### Folder structure -The folder structure for the [docs.optimism.io](https://github.com/ethereum-optimism/docs) repository is organized into several high-level categories. +The folder structure for the [docs.optimism.io](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs) repository is organized into several high-level categories. The left sidebar (side navigation) is managed in the `docs.json` file, which should be edited only for adding or deleting pages. Frequent edits may lead to merge conflicts due to ongoing content updates. Accept changes from others when committing a PR. @@ -77,7 +77,7 @@ See below for when to use title or sentence case. > * Select the **Settings** tab. * Use sentence case for body content and short phrases, even when the content is a link. Sentence case means you only capitalize the first letter of the sentence. - **Example:** If you're trying to figure out how to do something specific as a node operator, you might search our collection of tutorials or [suggest a new one](https://github.com/ethereum-optimism/docs/issues). + **Example:** If you're trying to figure out how to do something specific as a node operator, you might search our collection of tutorials or [suggest a new one](https://github.com/ethereum-optimism/optimism/issues). * Use lowercase in code snippets by default, unless the code block uses capitalization (e.g., for the name of a function or variable) and you are referring to the function or variable elsewhere within the technical documentation. **Examples**: Run `git add` or Import `useState` diff --git a/docs/public-docs/app-developers/reference/rpc-providers.mdx b/docs/public-docs/app-developers/reference/rpc-providers.mdx index f3b4e3e0ac6..6042ee1b606 100644 --- a/docs/public-docs/app-developers/reference/rpc-providers.mdx +++ b/docs/public-docs/app-developers/reference/rpc-providers.mdx @@ -228,7 +228,7 @@ The following providers offer production-grade RPC access to OP Stack networks. The OP Stack RPC Directory is maintained by OP Labs with the following policies: -* Providers must submit a docs PR to the [docs](https://github.com/ethereum-optimism/docs/) to be added +* Providers must submit a docs PR to the [docs](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/) to be added * To be listed, providers must support at least one network in the [OP Stack ecosystem](/op-stack/protocol/superchain-registry) * Anyone can submit a PR to remove a provider that does not support a listed network diff --git a/docs/public-docs/chain-operators/guides/management/fee-vaults.mdx b/docs/public-docs/chain-operators/guides/management/fee-vaults.mdx new file mode 100644 index 00000000000..1f92351ed92 --- /dev/null +++ b/docs/public-docs/chain-operators/guides/management/fee-vaults.mdx @@ -0,0 +1,121 @@ +--- +title: Fee vault operations +description: How to configure, monitor, and withdraw from fee vaults on your OP Stack chain. +--- + +This guide covers the operational aspects of managing fee vaults on your OP Stack chain. For a conceptual overview of how fee vaults work, see [Fee vaults](/op-stack/transactions/fee-vaults). + +## Prerequisites + +- Access to the **ProxyAdminOwner** account (required for configuration changes) +- An RPC endpoint for your L2 chain +- `cast` CLI tool installed ([Foundry](https://book.getfoundry.sh/getting-started/installation)) + +## Fee vault addresses + +| Vault | Address | +|-------|---------| +| `SequencerFeeVault` | `0x4200000000000000000000000000000000000011` | +| `BaseFeeVault` | `0x4200000000000000000000000000000000000019` | +| `L1FeeVault` | `0x420000000000000000000000000000000000001A` | +| `OperatorFeeVault` | `0x420000000000000000000000000000000000001B` | + +## Checking vault state + +### View current balance + +```bash +export L2_RPC= +export VAULT= + +cast balance $VAULT --rpc-url $L2_RPC +``` + +### View configuration + +```bash +# Recipient address +cast call $VAULT "recipient()" --rpc-url $L2_RPC + +# Minimum withdrawal amount (in wei) +cast call $VAULT "minWithdrawalAmount()" --rpc-url $L2_RPC + +# Withdrawal network (0 = L1, 1 = L2) +cast call $VAULT "withdrawalNetwork()" --rpc-url $L2_RPC + +# Total ETH withdrawn historically +cast call $VAULT "totalProcessed()" --rpc-url $L2_RPC +``` + +## Updating configuration + + + Configuration changes require the **ProxyAdminOwner** account. If your chain uses a multisig as the ProxyAdminOwner, these calls must be executed through the multisig. + + +### Set recipient + +```bash +export L2_RPC= +export VAULT= +export PK= + +cast send --rpc-url $L2_RPC --private-key $PK \ + $VAULT "setRecipient(address)" +``` + +### Set minimum withdrawal amount + +```bash +cast send --rpc-url $L2_RPC --private-key $PK \ + $VAULT "setMinWithdrawalAmount(uint256)" +``` + +### Set withdrawal network + +```bash +# 0 = L1, 1 = L2 +cast send --rpc-url $L2_RPC --private-key $PK \ + $VAULT "setWithdrawalNetwork(uint8)" <0_OR_1> +``` + +## Withdrawing fees + +Withdrawals are **permissionless** — anyone can trigger them once the vault balance meets the minimum threshold. + +### Trigger a withdrawal + +```bash +cast send --rpc-url $L2_RPC --private-key $PK \ + $VAULT "withdraw()" +``` + +This withdraws the **entire vault balance** to the configured recipient. + +### Withdrawal behavior by network + +- **L2 withdrawal (`withdrawalNetwork = 1`)**: Funds are transferred immediately to the recipient on L2. The transaction completes in a single step. +- **L1 withdrawal (`withdrawalNetwork = 0`)**: An L2-to-L1 withdrawal is initiated via the `L2ToL1MessagePasser`. After calling `withdraw()`, you must still: + 1. Wait for the withdrawal to be included in an L2 output root + 2. Prove the withdrawal on L1 + 3. Wait for the finalization period + 4. Finalize the withdrawal on L1 + + For details on completing L1 withdrawals, see [Withdrawal flow](/op-stack/bridging/withdrawal-flow). + +## Initial configuration during deployment + +Fee vault recipients, minimum withdrawal amounts, and withdrawal networks are configured during chain deployment with `op-deployer`. For details on setting these parameters, see the [op-deployer setup guide](/chain-operators/tutorials/create-l2-rollup/op-deployer-setup). + +## Monitoring + +It's good practice to monitor your fee vaults regularly: + +- **Vault balances**: Track balances to know when withdrawals can be triggered. +- **`totalProcessed`**: Monitor cumulative withdrawals over time to understand revenue trends. + +## Next steps + +- Read the [fee vaults explainer](/op-stack/transactions/fee-vaults) to understand how vaults work at the protocol level. +- See [Transaction Fees 101](/chain-operators/guides/management/transaction-fees-101) to learn how to tune fee parameters. +- Review [fee components and formulas](/op-stack/transactions/fees) for detailed fee calculations. diff --git a/docs/public-docs/chain-operators/guides/management/transaction-fees-101.mdx b/docs/public-docs/chain-operators/guides/management/transaction-fees-101.mdx index 630df1ecb41..79956109b5c 100644 --- a/docs/public-docs/chain-operators/guides/management/transaction-fees-101.mdx +++ b/docs/public-docs/chain-operators/guides/management/transaction-fees-101.mdx @@ -11,7 +11,7 @@ On an OP stack chain a transaction **Total Fee** is made of three main component `Total Fee = L2 Fee + L1 Fee + Operator Fee` -Fees are gathered in dedicated contract vaults that collect the different fee components (for example `BaseFeeVault`, `SequencerFeeVault`, etc.). +Fees are gathered in dedicated contract [fee vaults](/op-stack/transactions/fee-vaults) that collect the different fee components (for example `BaseFeeVault`, `SequencerFeeVault`, etc.). See the [fee vault operations guide](/chain-operators/guides/management/fee-vaults) for how to manage and withdraw from these vaults. ## 1. L2 Fee diff --git a/docs/public-docs/chain-operators/tools/op-deployer/reference/custom-deployments.mdx b/docs/public-docs/chain-operators/tools/op-deployer/reference/custom-deployments.mdx index 318bb7c4e5f..19fff6905cc 100644 --- a/docs/public-docs/chain-operators/tools/op-deployer/reference/custom-deployments.mdx +++ b/docs/public-docs/chain-operators/tools/op-deployer/reference/custom-deployments.mdx @@ -125,7 +125,8 @@ genesis and rollup config files. ## Upgrading -The `op-deployer upgrade` command has been deprecated. For L1 contract upgrades, use +The `op-deployer upgrade` command supports upgrades up to `op-contracts/v5.0.0` only. It does **not** support +upgrading from `op-contracts/v5.0.0` to `op-contracts/v6.0.0`. For upgrades beyond v5.0.0, use [superchain-ops](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide) or interact with the -OPCM directly. See the [deprecation notice](/notices/op-deployer-upgrade-deprecation) for details. +OPCM directly. See the [notice](/notices/op-deployer-upgrade-deprecation) for details. diff --git a/docs/public-docs/chain-operators/tools/op-deployer/usage/upgrade.mdx b/docs/public-docs/chain-operators/tools/op-deployer/usage/upgrade.mdx index 41b977f83d5..f4a8490c712 100644 --- a/docs/public-docs/chain-operators/tools/op-deployer/usage/upgrade.mdx +++ b/docs/public-docs/chain-operators/tools/op-deployer/usage/upgrade.mdx @@ -1,10 +1,11 @@ --- -title: Upgrade Command (Deprecated) -description: The op-deployer upgrade command has been deprecated. +title: Upgrade Command +description: The op-deployer upgrade command supports upgrades up to op-contracts/v5.0.0. --- -The `op-deployer upgrade` command has been deprecated and is no longer maintained. For L1 contract upgrades, use +The `op-deployer upgrade` command can be used for upgrades up to `op-contracts/v5.0.0`. It does **not** support +upgrading from `op-contracts/v5.0.0` to `op-contracts/v6.0.0`. For upgrades beyond v5.0.0, use [superchain-ops](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide) or interact with the -OPCM directly. See the [deprecation notice](/notices/op-deployer-upgrade-deprecation) for details. +OPCM directly. See the [notice](/notices/op-deployer-upgrade-deprecation) for details. diff --git a/docs/public-docs/chain-operators/tutorials/create-l2-rollup/code-setup.mdx b/docs/public-docs/chain-operators/tutorials/create-l2-rollup/code-setup.mdx index 2d527b90e5e..345dee538ed 100644 --- a/docs/public-docs/chain-operators/tutorials/create-l2-rollup/code-setup.mdx +++ b/docs/public-docs/chain-operators/tutorials/create-l2-rollup/code-setup.mdx @@ -3,10 +3,10 @@ title: L2 Rollup Code Examples description: Complete working code examples for the Create L2 Rollup tutorial --- -This page contains complete working code examples for the Create L2 Rollup tutorial. You can find all the code and configuration files in the [create-l2-rollup-example directory](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/). +This page contains complete working code examples for the Create L2 Rollup tutorial. You can find all the code and configuration files in the [create-l2-rollup-example directory](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/). - For the complete working implementation, visit the [Create L2 Rollup code on GitHub](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/). + For the complete working implementation, visit the [Create L2 Rollup code on GitHub](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/). ## Quick Start diff --git a/docs/public-docs/chain-operators/tutorials/create-l2-rollup/create-l2-rollup.mdx b/docs/public-docs/chain-operators/tutorials/create-l2-rollup/create-l2-rollup.mdx index 92ca9821e2d..76cb3e74969 100644 --- a/docs/public-docs/chain-operators/tutorials/create-l2-rollup/create-l2-rollup.mdx +++ b/docs/public-docs/chain-operators/tutorials/create-l2-rollup/create-l2-rollup.mdx @@ -29,15 +29,15 @@ If you want to get started quickly, you can use the complete working implementat **Complete working example** - A complete, working implementation is available in the [`create-l2-rollup-example/`](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/) directory. This includes all necessary scripts, Docker Compose configuration, and example environment files. + A complete, working implementation is available in the [`create-l2-rollup-example/`](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/) directory. This includes all necessary scripts, Docker Compose configuration, and example environment files. ### Automated setup steps 1. **Clone and navigate to the code directory:** ```bash - git clone https://github.com/ethereum-optimism/docs.git - cd docs/create-l2-rollup-example + git clone https://github.com/ethereum-optimism/optimism.git + cd optimism/docs/public-docs/create-l2-rollup-example ``` 2. **Configure your environment:** diff --git a/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-batcher-setup.mdx b/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-batcher-setup.mdx index 9915d5142e2..b2ed2a1ef01 100644 --- a/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-batcher-setup.mdx +++ b/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-batcher-setup.mdx @@ -12,7 +12,7 @@ After you have spun up your sequencer, you need to configure a batcher to submit **Automated Setup Available** - For a complete working setup with all components, check out the [automated approach](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/) in the code directory. + For a complete working setup with all components, check out the [automated approach](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/) in the code directory. ## Understanding the batcher's role diff --git a/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-challenger-setup.mdx b/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-challenger-setup.mdx index 8ceb7a4e341..1eca54d193c 100644 --- a/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-challenger-setup.mdx +++ b/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-challenger-setup.mdx @@ -13,7 +13,7 @@ After you have spun up your sequencer, batcher, and proposer, the final step is **Automated Setup Available** - For a complete working setup with all components including automated prestate generation, check out the [automated approach](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/) in the code directory. + For a complete working setup with all components including automated prestate generation, check out the [automated approach](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/) in the code directory. This guide provides step-by-step instructions for setting up the configuration and monitoring options for `op-challenger`. The challenger is a critical fault proofs component that monitors dispute games and challenges invalid claims to protect your OP Stack chain. diff --git a/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-deployer-setup.mdx b/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-deployer-setup.mdx index 654f19535cd..84cc605df77 100644 --- a/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-deployer-setup.mdx +++ b/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-deployer-setup.mdx @@ -12,7 +12,7 @@ Welcome to the first step of creating your own L2 rollup testnet! In this sectio **Quick Setup Available** - For a complete automated setup that includes op-deployer deployment, check out the [`code/`](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/) directory. The automated setup handles all contract deployment and configuration automatically. + For a complete automated setup that includes op-deployer deployment, check out the [`code/`](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/) directory. The automated setup handles all contract deployment and configuration automatically. ## About op-deployer @@ -30,7 +30,7 @@ There are a couple of ways to install `op-deployer`: **Quick Setup Available** - For automated installation, you can use the download script from the [code directory](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/). This script automatically downloads the latest version for your system. + For automated installation, you can use the download script from the [code directory](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/). This script automatically downloads the latest version for your system. @@ -108,7 +108,7 @@ There are a couple of ways to install `op-deployer`: ``` - **Pro Tip**: Use the automated download script from the [code directory](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/) to avoid manual version management. It automatically detects your platform and downloads the latest version. + **Pro Tip**: Use the automated download script from the [code directory](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/) to avoid manual version management. It automatically detects your platform and downloads the latest version. @@ -258,9 +258,10 @@ The intent file defines your chain's configuration. [[chains]] id = "0x000000000000000000000000000000000000000000000000000000000016de8d" - baseFeeVaultRecipient = "0x..." # base_Fee_Vault_Recipient address - l1FeeVaultRecipient = "0x..." # l1_Fee_Vault_Recipient address - sequencerFeeVaultRecipient = "0x..." # sequencer_Fee_Vault_Recipient address + baseFeeVaultRecipient = "0x..." # receives base fees + l1FeeVaultRecipient = "0x..." # receives L1 data fees + sequencerFeeVaultRecipient = "0x..." # receives priority fees (tips) + operatorFeeVaultRecipient = "0x..." # receives operator fees eip1559DenominatorCanyon = 250 eip1559Denominator = 50 eip1559Elasticity = 6 @@ -298,9 +299,18 @@ The intent file defines your chain's configuration. **Chain Configuration:** * `id`: Unique identifier for your chain - * `*FeeVaultRecipient`: Addresses receiving various protocol fees + * `*FeeVaultRecipient`: Addresses receiving protocol fees (required — deployment fails if any are set to the zero address). See [fee vaults](/op-stack/transactions/fee-vaults) for details on each vault. * `eip1559*`: Parameters for dynamic gas price calculation + **Fee Vault Optional Overrides:** + + Each vault also supports optional parameters that can be set via deploy overrides. If not specified, the following defaults apply: + + | Parameter | Default | + |-----------|---------| + | `*MinimumWithdrawalAmount` | 10 ETH | + | `*WithdrawalNetwork` | `local` (L2) | + **Chain Roles:** * `l1ProxyAdminOwner`: Can upgrade L1 contract implementations (usually same as superchain proxyAdminOwner) diff --git a/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-proposer-setup.mdx b/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-proposer-setup.mdx index bb010ffca0b..e812f0ad1dd 100644 --- a/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-proposer-setup.mdx +++ b/docs/public-docs/chain-operators/tutorials/create-l2-rollup/op-proposer-setup.mdx @@ -12,7 +12,7 @@ After you have spun up your sequencer and batcher, you need to attach a proposer **Automated Setup Available** - For a complete working setup with all components, check out the [automated approach](https://github.com/ethereum-optimism/docs/tree/main/create-l2-rollup-example/) in the code directory. + For a complete working setup with all components, check out the [automated approach](https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs/create-l2-rollup-example/) in the code directory. This guide assumes you already have a functioning sequencer, batcher, and the necessary L1 contracts deployed using [`op-deployer`](./op-deployer-setup). If you haven't set up your sequencer and batcher yet, please refer to the [sequencer guide](./op-geth-setup) and [batcher guide](./op-batcher-setup) first. diff --git a/docs/public-docs/chain-operators/tutorials/l1-contract-upgrades/op-deployer-upgrade.mdx b/docs/public-docs/chain-operators/tutorials/l1-contract-upgrades/op-deployer-upgrade.mdx index 9a15bc11235..77764aefba1 100644 --- a/docs/public-docs/chain-operators/tutorials/l1-contract-upgrades/op-deployer-upgrade.mdx +++ b/docs/public-docs/chain-operators/tutorials/l1-contract-upgrades/op-deployer-upgrade.mdx @@ -1,25 +1,28 @@ --- -title: Upgrade L1 contracts using op-deployer (Deprecated) -description: The op-deployer upgrade command has been deprecated. This page documents which versions it was available for. +title: Upgrade L1 contracts using op-deployer +description: Learn how to use the op-deployer upgrade command to upgrade L1 contracts up to op-contracts/v5.0.0. --- -The `op-deployer upgrade` command has been deprecated and is no longer maintained. For L1 contract upgrades, use +The `op-deployer upgrade` command can be used for upgrades up to `op-contracts/v5.0.0`. It does **not** support +upgrading from `op-contracts/v5.0.0` to `op-contracts/v6.0.0`. For upgrades beyond v5.0.0, use [superchain-ops](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide) or interact with the OPCM directly. See the [deprecation notice](/notices/op-deployer-upgrade-deprecation) for details. ## Version availability -The `op-deployer upgrade` command supported the following contract upgrade paths: +The `op-deployer upgrade` command supports the following contract upgrade paths (upgrades must be performed in steps): | Upgrade path | op-deployer version | Status | |---|---|---| -| op-contracts/v1.8.0 to op-contracts/v2.0.0 | v0.2.x | Deprecated | -| op-contracts/v2.0.0 to op-contracts/v3.0.0 | v0.3.x | Deprecated | +| op-contracts/v1.8.0 to op-contracts/v2.0.0 | v0.2.x | Available | +| op-contracts/v2.0.0 to op-contracts/v3.0.0 | v0.3.x | Available | +| op-contracts/v3.0.0 to op-contracts/v4.0.0 | v0.4.x | Available | +| op-contracts/v4.0.0 to op-contracts/v5.0.0 | v0.5.x | Available | Each minor version of `op-deployer` supported a single release of the governance-approved smart contracts. See the [releases guide](/chain-operators/tools/op-deployer/reference/releases) for more information on versioning. ## Migration -For all future L1 contract upgrades, use [superchain-ops](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide). For non-Optimism governed chains, you can interact with the OPCM directly using your own tooling. +For L1 contract upgrades beyond `op-contracts/v5.0.0`, use [superchain-ops](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide). For non-Optimism governed chains, you can interact with the OPCM directly using your own tooling. diff --git a/docs/public-docs/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide.mdx b/docs/public-docs/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide.mdx index 75f767988c6..7d3cee2f2a9 100644 --- a/docs/public-docs/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide.mdx +++ b/docs/public-docs/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide.mdx @@ -5,7 +5,7 @@ description: Learn about using superchain-ops to upgrade your chain This guide outlines the process for upgrading Optimism chains using the `superchain-ops` repository. It's intended primarily for OP Stack chains managed by the Security Council, those with the Foundation or Security Council as signers, and/or chains requiring a highly secure process. -For chains that don't require the enhanced security of superchain-ops or security council signing, alternative upgrade tooling may be used. Note that the `op-deployer upgrade` command [has been deprecated](/notices/op-deployer-upgrade-deprecation). +For chains that don't require the enhanced security of superchain-ops or security council signing, alternative upgrade tooling may be used. Note that the `op-deployer upgrade` command only supports upgrades [up to `op-contracts/v5.0.0`](/notices/op-deployer-upgrade-deprecation). For non-Optimism governed chains, you can use your own tooling to interact with the OPCM directly to upgrade your chain. diff --git a/docs/public-docs/chain-operators/tutorials/l1-contract-upgrades/upgrade-op-contracts-1-3-1-8.mdx b/docs/public-docs/chain-operators/tutorials/l1-contract-upgrades/upgrade-op-contracts-1-3-1-8.mdx index 47e6182f5e7..95b407a78ee 100644 --- a/docs/public-docs/chain-operators/tutorials/l1-contract-upgrades/upgrade-op-contracts-1-3-1-8.mdx +++ b/docs/public-docs/chain-operators/tutorials/l1-contract-upgrades/upgrade-op-contracts-1-3-1-8.mdx @@ -192,6 +192,8 @@ Run the deployment process with the following command: kfoplabs/upgrade-v1.3.0-v1.8.0-permissioned /deploy_config.json /deployments.json ``` +The source code for the `kfoplabs/upgrade-v1.3.0-v1.8.0-permissioned` image is available in the [`perm/op-contracts/v1.8.0` branch of the Optimism monorepo](https://github.com/ethereum-optimism/optimism/tree/perm/op-contracts/v1.8.0). If you need to fork or customize the upgrade script (e.g. to support L3s), start from that branch. + ### 5. Verify outputs The deployment should output four files: @@ -211,3 +213,4 @@ Now you have the calldata that can be executed onchain to perform the L1 contrac * [superchain-ops Repository](https://github.com/ethereum-optimism/superchain-ops) * [Optimism Monorepo](https://github.com/ethereum-optimism/optimism) +* [Upgrade script source code (`perm/op-contracts/v1.8.0` branch)](https://github.com/ethereum-optimism/optimism/tree/perm/op-contracts/v1.8.0) diff --git a/docs/public-docs/chain-operators/tutorials/migrating-permissionless.mdx b/docs/public-docs/chain-operators/tutorials/migrating-permissionless.mdx index 4715418bfd9..d326935231c 100644 --- a/docs/public-docs/chain-operators/tutorials/migrating-permissionless.mdx +++ b/docs/public-docs/chain-operators/tutorials/migrating-permissionless.mdx @@ -184,15 +184,12 @@ For detailed information about privileged roles and their security implications, ### Adding the PermissionlessDisputeGame to a chain -To enable the permissionless dispute game, you must call the `addGameType()`function on the `OPContractsManager.sol` (OPCM) contract. +To enable the permissionless dispute game, call the `upgrade()` function on the `OPContractsManagerV2` (OPCM) contract with the appropriate `DisputeGameConfig` entries. This is typically done via `op-deployer manage add-game-type-v2`. -This function adds the permissionless dispute game to the system. +The upgrade will: -This method will: - -1. Deploy the `FaultDisputeGame` contract -2. Setup the `DelayedWethProxy` for the new game -3. Reinitialize the `AnchorStateRegistry` to add the new game type. +1. Register the `FaultDisputeGame` implementation on the `DisputeGameFactory` with the correct game arguments (absolute prestate, VM, anchor state registry, delayed WETH, chain ID). +2. Set the initial bond for the new game type. See a high‐level implementation from this [docs](/chain-operators/tutorials/dispute-games) or [this superchain-ops template](https://github.com/ethereum-optimism/superchain-ops/blob/main/src/template/AddGameTypeTemplate.sol). diff --git a/docs/public-docs/docs.json b/docs/public-docs/docs.json index 64a320a6f08..1aacc44c020 100644 --- a/docs/public-docs/docs.json +++ b/docs/public-docs/docs.json @@ -736,7 +736,7 @@ }, { "source": "/connect/contribute/docs-contribute", - "destination": "https://github.com/ethereum-optimism/docs/blob/main/CONTRIBUTING.md" + "destination": "https://github.com/ethereum-optimism/optimism/blob/develop/docs/public-docs/DOCS_CONTRIBUTING.md" }, { "source": "/connect/contribute/stack-contribute", @@ -744,11 +744,11 @@ }, { "source": "/connect/contribute/style-guide", - "destination": "https://github.com/ethereum-optimism/docs/blob/main/STYLE_GUIDE.md" + "destination": "https://github.com/ethereum-optimism/optimism/blob/develop/docs/public-docs/STYLE_GUIDE.md" }, { "source": "/reference/contribute/style-guide", - "destination": "https://github.com/ethereum-optimism/docs/blob/main/STYLE_GUIDE.md" + "destination": "https://github.com/ethereum-optimism/optimism/blob/develop/docs/public-docs/STYLE_GUIDE.md" }, { "source": "/connect/resources", @@ -1792,7 +1792,7 @@ }, { "source": "/reference/contribute/docs-contribute", - "destination": "https://github.com/ethereum-optimism/docs/blob/main/CONTRIBUTING.md" + "destination": "https://github.com/ethereum-optimism/optimism/blob/develop/docs/public-docs/DOCS_CONTRIBUTING.md" }, { "source": "/reference/glossary", @@ -1920,6 +1920,7 @@ "chain-operators/guides/management/key-management", "chain-operators/guides/management/operations", "chain-operators/guides/management/transaction-fees-101", + "chain-operators/guides/management/fee-vaults", "chain-operators/guides/management/troubleshooting" ] } @@ -2285,6 +2286,7 @@ "group": "Transactions", "pages": [ "/op-stack/transactions/fees", + "/op-stack/transactions/fee-vaults", "/op-stack/transactions/flashblocks", "/op-stack/transactions/forced-transaction", "/op-stack/transactions/transaction-finality", @@ -2368,6 +2370,7 @@ { "group": "Notices", "pages": [ + "notices/req-resp-cl-sync-deprecation", "notices/op-geth-deprecation", "notices/op-deployer-upgrade-deprecation", { @@ -2719,6 +2722,12 @@ "pages": [ "rust/op-alloy/glossary" ] + }, + { + "group": "op-revm", + "pages": [ + "rust/op-revm/index" + ] } ] } @@ -2755,7 +2764,7 @@ }, { "label": "GitHub", - "href": "https://github.com/ethereum-optimism/docs" + "href": "https://github.com/ethereum-optimism/optimism/tree/develop/docs/public-docs" } ] } diff --git a/docs/public-docs/node-operators/reference/architecture/rollup-node.mdx b/docs/public-docs/node-operators/reference/architecture/rollup-node.mdx index e9f2750318c..ffa538cc107 100644 --- a/docs/public-docs/node-operators/reference/architecture/rollup-node.mdx +++ b/docs/public-docs/node-operators/reference/architecture/rollup-node.mdx @@ -117,7 +117,7 @@ It is important to regularly monitor your node, and you can optionally configure Got an idea for a new tutorial? We'd love to hear it. - Head over to GitHub to [suggest a new tutorial](https://github.com/ethereum-optimism/docs/issues/new?assignees=\&labels=tutorial%2Cdocumentation%2Ccommunity-request\&projects=\&template=suggest_tutorial.yaml\&title=%5BTUTORIAL%5D+Add+PR+title). + Head over to GitHub to [suggest a new tutorial](https://github.com/ethereum-optimism/optimism/issues/new?assignees=\&labels=tutorial%2Cdocumentation%2Ccommunity-request\&projects=\&template=suggest_tutorial.yaml\&title=%5BTUTORIAL%5D+Add+PR+title). | Tutorial Name | Description | Difficulty Level | diff --git a/docs/public-docs/notices/op-deployer-upgrade-deprecation.mdx b/docs/public-docs/notices/op-deployer-upgrade-deprecation.mdx index e39440052d8..a0b3e1b63ad 100644 --- a/docs/public-docs/notices/op-deployer-upgrade-deprecation.mdx +++ b/docs/public-docs/notices/op-deployer-upgrade-deprecation.mdx @@ -11,17 +11,18 @@ categories: is_imported_content: 'false' --- -The `upgrade` and `manage` commands in `op-deployer` are deprecated and no longer maintained. OP Labs uses the OP Contracts Manager (OPCM) for upgrade and chain management operations, and will focus `op-deployer` on initial chain deployments only. +The `manage` command in `op-deployer` is deprecated and no longer maintained. The `upgrade` command can still be used for upgrades up to `op-contracts/v5.0.0` but does **not** support upgrading from `op-contracts/v5.0.0` to `op-contracts/v6.0.0`. For upgrades beyond v5.0.0, use the OPCM directly or superchain-ops. ## What this means -* The `op-deployer upgrade` and `op-deployer manage` subcommands are no longer supported and will not receive updates. +* The `op-deployer manage` subcommand is no longer supported and will not receive updates. +* The `op-deployer upgrade` command can be used for the upgrade path from `op-contracts/v1.8.0` up to `op-contracts/v5.0.0` (in steps: v1.8.0 → v2.0.0 → v3.0.0 → v4.0.0 → v5.0.0). It does **not** support upgrading from `op-contracts/v5.0.0` to `op-contracts/v6.0.0`. * `op-deployer` itself is **not** deprecated. It remains the recommended tool for initial chain deployments via the `bootstrap`, `init`, `apply`, and `inspect` commands. -* For L1 contract upgrades, use [superchain-ops](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide) or interact with the OPCM directly. +* For L1 contract upgrades beyond `op-contracts/v5.0.0`, use [superchain-ops](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide) or interact with the OPCM directly. ## Action required -If you are currently using `op-deployer upgrade` or `op-deployer manage` for L1 contract upgrades, migrate to one of the following approaches: +If you need to upgrade beyond `op-contracts/v5.0.0`, migrate to one of the following approaches: 1. **[superchain-ops](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide)** — recommended for OP Stack chains managed by the Security Council, chains with the Foundation or Security Council as signers, and chains requiring a highly secure upgrade process. 2. **OPCM directly** — for non-Optimism governed chains, you can interact with the OP Contracts Manager directly using your own tooling. @@ -29,5 +30,5 @@ If you are currently using `op-deployer upgrade` or `op-deployer manage` for L1 ## Resources * [superchain-ops upgrade guide](/chain-operators/tutorials/l1-contract-upgrades/superchain-ops-guide) -* [OP Contracts Manager reference](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OPContractsManager.sol) +* [OP Contracts Manager reference](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerV2.sol) * [OPCM design documentation](https://github.com/ethereum-optimism/design-docs/blob/main/protocol/op-contracts-manager-arch.md) diff --git a/docs/public-docs/notices/op-geth-deprecation.mdx b/docs/public-docs/notices/op-geth-deprecation.mdx index 3d5273372e1..50f1b9a93a9 100644 --- a/docs/public-docs/notices/op-geth-deprecation.mdx +++ b/docs/public-docs/notices/op-geth-deprecation.mdx @@ -51,12 +51,14 @@ Syncing an op-reth node as soon as possible helps ensure a snapshot is available ### Permissionless Chain Operators -In parallel, the fault proof program is moving from **op-program** to **kona client**. Current op-program deployments are expected to remain usable until the next hardfork, Karst, when chain operators will need to migrate to **kona-client**. Optimism will handle the onchain prestate updates for managed chains. If you operate a permissionless fault proof chain, watch for a separate notice with specific steps. +In parallel, the fault proof program is moving from **op-program** to **kona client**. Current op-program deployments are expected to remain usable until the next hardfork, Karst, when chain operators will need to migrate to **kona-client**. Optimism will handle the onchain prestate updates for managed chains. If you operate a permissionless fault proof chain, checkout our guide on [how to run historical proofs with op-reth](https://docs.optimism.io/node-operators/tutorials/reth-historical-proofs). ## Resources - [op-reth repository](https://github.com/ethereum-optimism/optimism/tree/develop/rust) - [op-reth configuration](https://docs.optimism.io/node-operators/guides/configuration/execution-clients#op-reth-configuration) - [op-reth OP Mainnet Snapshots](https://datadirs.optimism.io/) +- [op-reth historical proofs guide](https://docs.optimism.io/node-operators/tutorials/reth-historical-proofs) +- [op-stack rust docs](https://docs.optimism.io/rust) - [How to use Snapshots](https://docs.optimism.io/op-mainnet/network-information/snapshots) - [kona repository](https://github.com/ethereum-optimism/optimism/tree/develop/rust/kona) diff --git a/docs/public-docs/notices/req-resp-cl-sync-deprecation.mdx b/docs/public-docs/notices/req-resp-cl-sync-deprecation.mdx new file mode 100644 index 00000000000..07cd12e1b8f --- /dev/null +++ b/docs/public-docs/notices/req-resp-cl-sync-deprecation.mdx @@ -0,0 +1,40 @@ +--- +title: Deprecation of Req/Res CL P2P sync +description: The op-node Req/Res consensus-layer P2P sync client is being deprecated in favor of execution-layer syncing. +lang: en-US +content_type: notice +topic: req-resp-cl-sync-deprecation +personas: + - node-operator + - chain-operator +categories: + - infrastructure + - protocol +is_imported_content: 'false' +--- + +The `op-node` request-response (Req/Res) consensus-layer (CL) P2P sync client is being deprecated in favor of syncing through the execution layer (EL) client. + +This change simplifies `op-node` configuration, removes fragile sync logic, and relies on the execution client's native P2P sync, which is the more battle-tested path. + +## What this means + +- The Req/Res CL P2P sync **client** in `op-node` is deprecated. +- `op-node` should rely on its connected EL node, such as **op-geth** or **op-reth**, to reach the chain tip in the presence of gaps between local state and chain tip received over gossip. +- Operators should ensure their EL nodes have healthy P2P connectivity and enough peers to sync independently. +- If you still explicitly set `--syncmode.req-resp=true`, plan to remove that override. +- The Req/Res **server** path will remain temporarily to support older nodes, but it is also planned for removal later. + +## Action required + +### Node operators + +Move away from the deprecated Req/Res client path and rely on EL syncing. + +- Ensure your EL node has healthy P2P connectivity. +- Remove any explicit `--syncmode.req-resp=true` override unless you need temporary backward compatibility. +- If you are running an older release where Req/Res is still enabled by default, set `--syncmode.req-resp=false` to opt into the new behavior now. + + + Once the Req/Res client path is fully removed, nodes with unhealthy EL peer connectivity may fail to catch up to the unsafe tip. + diff --git a/docs/public-docs/op-stack/protocol/smart-contracts.mdx b/docs/public-docs/op-stack/protocol/smart-contracts.mdx index ae0acf569d4..d34299f2ee2 100644 --- a/docs/public-docs/op-stack/protocol/smart-contracts.mdx +++ b/docs/public-docs/op-stack/protocol/smart-contracts.mdx @@ -505,6 +505,7 @@ contract. If the ERC20 token is native to L1, it will be burnt. The `SequencerFeeVault` is the contract that holds any fees paid to the Sequencer during transaction processing and block production. +See [fee vaults](/op-stack/transactions/fee-vaults) for details. * **Address:** `0x4200000000000000000000000000000000000011` * **Introduced:** Legacy @@ -632,7 +633,8 @@ have the ability to upgrade any of the other predeploy contracts. The `BaseFeeVault` predeploy receives the base fees on L2. The base fee is not burnt on L2 like it is on L1. Once the contract has received a certain amount -of fees, the ETH can be withdrawn to an immutable address on L1. +of fees, the ETH can be withdrawn to a configured recipient. +See [fee vaults](/op-stack/transactions/fee-vaults) for details. * **Address:** `0x4200000000000000000000000000000000000019` * **Introduced:** Bedrock @@ -643,7 +645,8 @@ of fees, the ETH can be withdrawn to an immutable address on L1. The `L1FeeVault` predeploy receives the L1 portion of the transaction fees. Once the contract has received a certain amount of fees, the ETH can be -withdrawn to an immutable address on L1. +withdrawn to a configured recipient. +See [fee vaults](/op-stack/transactions/fee-vaults) for details. * **Address:** `0x420000000000000000000000000000000000001a` * **Introduced:** Bedrock @@ -654,7 +657,8 @@ withdrawn to an immutable address on L1. The `OperatorFeeVault` predeploy (introduced with the [Isthmus hardfork](https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/isthmus/predeploys.md#operatorfeevault)) receives the operator portion of the transaction fees. Once the contract has received a certain amount of fees, funds can be withdrawn to -the BaseFeeVault on the L2 network. +a configured recipient. +See [fee vaults](/op-stack/transactions/fee-vaults) for details. * **Address:** `0x420000000000000000000000000000000000001B` * **Introduced:** Isthmus diff --git a/docs/public-docs/op-stack/reference/glossary.mdx b/docs/public-docs/op-stack/reference/glossary.mdx index 6d85aa3ca73..a31703f678f 100644 --- a/docs/public-docs/op-stack/reference/glossary.mdx +++ b/docs/public-docs/op-stack/reference/glossary.mdx @@ -3,7 +3,7 @@ title: Glossary description: Learn the meaning of important terminology used throughout the Optimism Developer Documentation. --- -The glossary provides definitions of important terminology used throughout the Optimism Developer Documentation. To make revisions to this page, please [submit an issue](https://github.com/ethereum-optimism/docs/issues/new?assignees=\&labels=glossary%2Cdocumentation%2Ccommunity-request\&projects=\&template=suggest_glossary_term.yaml\&title=%5BGLOSSARY%5D+Add+PR+title). +The glossary provides definitions of important terminology used throughout the Optimism Developer Documentation. To make revisions to this page, please [submit an issue](https://github.com/ethereum-optimism/optimism/issues/new?assignees=\&labels=glossary%2Cdocumentation%2Ccommunity-request\&projects=\&template=suggest_glossary_term.yaml\&title=%5BGLOSSARY%5D+Add+PR+title). ## Table of contents diff --git a/docs/public-docs/op-stack/transactions/fee-vaults.mdx b/docs/public-docs/op-stack/transactions/fee-vaults.mdx new file mode 100644 index 00000000000..5c9a480fec0 --- /dev/null +++ b/docs/public-docs/op-stack/transactions/fee-vaults.mdx @@ -0,0 +1,65 @@ +--- +title: Fee vaults +description: Learn how fee vaults work on OP Stack chains, where transaction fees are collected, and how the withdrawal mechanism operates. +--- + +Fee vaults are predeploy contracts on OP Stack L2 chains that collect and hold the different components of transaction fees. Unlike Ethereum where the base fee is burned, OP Stack chains route all fees into dedicated vault contracts, allowing chain operators to withdraw and manage collected revenue. + +## Overview + +Every OP Stack chain has four fee vaults, each collecting a specific fee component: + +| Vault | Address | Collects | Introduced | +|-------|---------|----------|------------| +| `SequencerFeeVault` | `0x4200000000000000000000000000000000000011` | Priority fees (tips) | Legacy | +| `BaseFeeVault` | `0x4200000000000000000000000000000000000019` | Base fees (not burned on L2) | Bedrock | +| `L1FeeVault` | `0x420000000000000000000000000000000000001A` | L1 data fees | Bedrock | +| `OperatorFeeVault` | `0x420000000000000000000000000000000000001B` | Operator fees | Isthmus | + +### How fees flow into vaults + +When a transaction is executed on an OP Stack chain, the total fee is split across vaults: + +- **Base fee** (`gasUsed × baseFee`) goes to the `BaseFeeVault` +- **Priority fee** (`gasUsed × priorityFee`) goes to the `SequencerFeeVault` +- **L1 data fee** goes to the `L1FeeVault` +- **Operator fee** (`operatorFeeScalar × gasUsed + operatorFeeConstant`) goes to the `OperatorFeeVault` + +Each component has its own formula. For the full breakdown, see [Transaction fees](/op-stack/transactions/fees). + +## Vault configuration + +Each fee vault has three configurable parameters: + +| Parameter | Description | +|-----------|-------------| +| **recipient** | The address that receives withdrawn funds | +| **minWithdrawalAmount** | Minimum ETH balance required before a withdrawal can be triggered | +| **withdrawalNetwork** | Whether funds are withdrawn to an L1 or L2 address | + +### Withdrawal network + +The `withdrawalNetwork` parameter determines how funds are routed when withdrawn: + +- **L1 (`0`)**: Funds are sent to the recipient on L1 via the `L2ToL1MessagePasser`. This initiates a standard L2-to-L1 withdrawal that must be proven and finalized on L1. +- **L2 (`1`)**: Funds are sent directly to the recipient on L2 via a simple ETH transfer. + +## Withdrawal mechanism + +Fee vault withdrawals are **permissionless** — anyone can trigger a withdrawal by calling the `withdraw()` function on any vault. This design ensures that collected fees can always be moved to the configured recipient without relying on a specific operator. + +### How withdrawals work + +1. The caller invokes `withdraw()` on the vault contract. +2. The vault checks that its balance meets the `minWithdrawalAmount` threshold. +3. The entire vault balance is withdrawn (not a partial amount). +4. The `totalProcessed` counter is incremented. +5. Funds are routed based on `withdrawalNetwork`: + - **L2**: Direct ETH transfer to the recipient. + - **L1**: A withdrawal is initiated through the `L2ToL1MessagePasser` with a 400,000 gas limit. The withdrawal must then be [proven and finalized](/op-stack/bridging/withdrawal-flow) on L1. + +## Next steps + +- Learn how to [configure and withdraw from fee vaults](/chain-operators/guides/management/fee-vaults) as a chain operator. +- Understand [transaction fee components](/op-stack/transactions/fees) in detail. +- Review the [smart contracts reference](/op-stack/protocol/smart-contracts) for all predeploy addresses. diff --git a/docs/public-docs/op-stack/transactions/fees.mdx b/docs/public-docs/op-stack/transactions/fees.mdx index d0c75ac5e08..5afab669d1f 100644 --- a/docs/public-docs/op-stack/transactions/fees.mdx +++ b/docs/public-docs/op-stack/transactions/fees.mdx @@ -227,7 +227,7 @@ The Operator fee is a new fee component which enables more customizable fee stru ### Mechanism -The Operator fee is automatically charged for any transaction that is included in a block after the Isthmus activation. This fee is deducted directly from the address that sent the transaction and follows the same semantics as existing fees charged in the EVM. The collected operator fees are sent to the **Operator Fee Vault**, a new vault similar to existing fee vaults. +The Operator fee is automatically charged for any transaction that is included in a block after the Isthmus activation. This fee is deducted directly from the address that sent the transaction and follows the same semantics as existing fees charged in the EVM. The collected operator fees are sent to the **Operator Fee Vault**, a new vault similar to existing [fee vaults](/op-stack/transactions/fee-vaults). **Deposit transactions do not get charged operator fees.** For all deposit transactions, regardless of the operator fee parameter configuration, the operator fee is always zero. @@ -279,25 +279,12 @@ The Operator fee follows standard EVM fee semantics: Transaction pools must account for the additional operator fee when validating transactions. Transactions without sufficient balance to cover the worst-case total cost (including operator fee) will be rejected. -## Sequencer fee vault +## Fee vaults -The Sequencer fee vault collects and holds transaction fees paid to the sequencer during block production on OP Mainnet. These fees cover the cost of posting transaction data to L1, ensuring network sustainability and data availability. - -### Fee collection and distribution - -* **Purpose**: The sequencer deposits collected fees into the Sequencer fee vault. These fees reimburse the sequencer for gas costs when submitting transaction batches to L1. -* **Vault address**: The Sequencer fee vault is predeployed at the address `0x4200000000000000000000000000000000000011` on the OP Mainnet. -* **Fee usage**: Stored fees are eventually transferred to a designated recipient address (e.g., a treasury or distribution contract). - -### How it works - -1. **Fee collection**: During the processing of transactions, the sequencer collects fees from users as part of their transaction costs. These fees are primarily used to cover the gas expenses of posting transaction data to Ethereum L1. -2. **Storage**: Collected fees are deposited into the Sequencer fee vault contract. -3. **Distribution**: The fees are later distributed to the appropriate recipient, typically covering operational costs like L1 gas fees for data availability. - -This system ensures effective fee management, maintaining the security and operation of the Optimism network. +Each fee component is routed to a dedicated [fee vault](/op-stack/transactions/fee-vaults) contract on L2. Unlike Ethereum where the base fee is burned, OP Stack chains collect all fees in these vaults, allowing chain operators to withdraw and manage collected revenue. See the [fee vaults](/op-stack/transactions/fee-vaults) page for details on how vaults work and the [fee vault operations guide](/chain-operators/guides/management/fee-vaults) for managing them. ## Next steps +* Learn how [fee vaults](/op-stack/transactions/fee-vaults) collect and distribute transaction fees. * Read the [differences between Ethereum and OP Stack Chains](/op-stack/protocol/differences) guide. * Read the [L2 to L1 Transactions](/app-developers/bridging/messaging#for-l1-to-l2-transactions) guide. diff --git a/docs/public-docs/rust/index.mdx b/docs/public-docs/rust/index.mdx index fd510d8d158..9f6d4c46f35 100644 --- a/docs/public-docs/rust/index.mdx +++ b/docs/public-docs/rust/index.mdx @@ -1,6 +1,6 @@ --- title: "OP Stack Rust" -description: "Documentation for Rust implementations of the OP Stack: Kona, op-reth, and op-alloy" +description: "Documentation for Rust implementations of the OP Stack: Kona, op-reth, op-alloy, and op-revm" --- # OP Stack Rust @@ -8,7 +8,7 @@ description: "Documentation for Rust implementations of the OP Stack: Kona, op-r Rust implementations for the OP Stack, built by [OP Labs](https://www.oplabs.co/). A unified documentation site for OP Stack Rust components: **Kona** (rollup node & fault proofs), -**op-reth** (execution client), and **op-alloy** (types & providers). +**op-reth** (execution client), **op-alloy** (types & providers), and **op-revm** (OP Stack EVM). ## Quick Start @@ -32,7 +32,7 @@ op-reth node --chain base ## Components - + Modular rollup node and fault proof system. Spec-compliant, performant, and extensible with `no_std` support. @@ -42,6 +42,9 @@ op-reth node --chain base OP Stack types and providers for the Alloy ecosystem. Consensus, RPC, and network crates. + + Optimism variant of revm — deposit transactions, L1/operator fee accounting, and OP Stack precompiles. + ## Built with Kona SDK diff --git a/docs/public-docs/rust/op-revm/index.mdx b/docs/public-docs/rust/op-revm/index.mdx new file mode 100644 index 00000000000..80aea622f2c --- /dev/null +++ b/docs/public-docs/rust/op-revm/index.mdx @@ -0,0 +1,88 @@ +--- +title: "op-revm" +description: "op-revm is the Optimism variant of revm, implementing OP Stack modifications to the EVM." +--- + +`op-revm` is the Optimism variant of [revm](https://github.com/bluealloy/revm) — +the OP Stack's modifications to the Ethereum Virtual Machine, packaged as a +custom EVM built on top of the upstream `revm` framework. + +## Features + +`op-revm` extends `revm` with everything the OP Stack needs on top of vanilla +Ethereum execution: + +- **Deposit transactions** — the L1-to-L2 deposit transaction type and its + execution semantics. +- **L1 cost accounting** — `L1BlockInfo` and per-transaction L1 fee / blob fee + calculation. +- **Operator fees** — operator fee handling introduced in Isthmus and refined + in Jovian. +- **OP-specific precompiles** — including accelerated BN254 pairing. +- **OP halt reasons & transaction errors** — OP Stack–specific execution + failure modes. +- **Hardfork-aware spec selection** — `OpSpecId` selects the right behavior for + each OP Stack hardfork (Bedrock, Regolith, Canyon, Ecotone, Fjord, Granite, + Holocene, Isthmus, Jovian, …). + +## Provenance + +`op-revm` is vendored from upstream +[`bluealloy/revm`'s `crates/op-revm`](https://github.com/bluealloy/revm/tree/main/crates/op-revm) +and imported into the monorepo so it can evolve in lock-step with the rest of +the OP Stack Rust code. The upstream release history is preserved in +[`rust/op-revm/CHANGELOG.md`](https://github.com/ethereum-optimism/optimism/blob/develop/rust/op-revm/CHANGELOG.md). + +## Crate features + +The crate exposes the usual `revm` feature knobs, forwarded through to the +underlying `revm` crate: + +- `default = ["std", "c-kzg", "secp256k1", "portable", "blst"]` +- `std` — enables `std`-dependent code paths in `revm`, `alloy-primitives`, + `serde_json`, etc. +- `serde` — derives `serde` impls and forwards to `revm/serde` and + `alloy-primitives/serde`. +- `portable`, `c-kzg`, `secp256k1`, `blst`, `bn` — pass-through feature gates + for the cryptographic backends. +- `dev`, `memory_limit`, `optional_balance_check`, `optional_block_gas_limit`, + `optional_eip3541`, `optional_eip3607`, `optional_no_base_fee`, + `optional_fee_charge` — debugging and testing knobs forwarded to `revm`. + +`op-revm` supports `no_std` builds: disabling default features (or building +with `--no-default-features`) produces a crate suitable for fault-proof and +zkVM targets such as `riscv32imac-unknown-none-elf`. + +## Building & testing + +From the `rust/` workspace root: + +```bash +# Build +cargo build -p op-revm + +# Run tests with all features +cargo nextest run -p op-revm --all-features + +# no_std check (mirrors upstream's riscv32imac CI) +cargo build -p op-revm \ + --target riscv32imac-unknown-none-elf \ + --no-default-features +``` + +The `no_std` build is also exercised by `just check-no-std` and runs in CI on +every PR that touches `rust/**`. + +## Using op-revm + +`op-revm` is the EVM used by [op-reth](/rust/op-reth) for OP Stack block +execution, and by [Kona](/rust/kona/intro/overview) inside the fault-proof +program and rollup node. Most users will consume it transitively through one +of those components rather than depending on it directly; depend on `op-revm` +directly only when building a custom OP Stack execution environment (for +example, an alternate client or a zkVM proof backend). + +## License + +`op-revm` is licensed under the MIT License — see +[`rust/op-revm/LICENSE`](https://github.com/ethereum-optimism/optimism/blob/develop/rust/op-revm/LICENSE). diff --git a/go.mod b/go.mod index 9b5a6de9207..a6d743c3acf 100644 --- a/go.mod +++ b/go.mod @@ -109,7 +109,7 @@ require ( github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect - github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect + github.com/crate-crypto/go-eth-kzg v1.5.0 // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/dchest/siphash v1.2.3 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect @@ -260,7 +260,6 @@ require ( github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel/metric v1.40.0 // indirect - go.opentelemetry.io/otel/sdk v1.40.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect go.uber.org/dig v1.18.0 // indirect go.uber.org/fx v1.22.2 // indirect @@ -280,7 +279,7 @@ require ( lukechampine.com/blake3 v1.3.0 // indirect ) -replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101701.0-rc.3 +replace github.com/ethereum/go-ethereum => github.com/ethereum-optimism/op-geth v1.101702.1-rc.1 // replace github.com/ethereum/go-ethereum => ../op-geth diff --git a/go.sum b/go.sum index c6137907704..7790969f51f 100644 --- a/go.sum +++ b/go.sum @@ -163,8 +163,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= -github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= +github.com/crate-crypto/go-eth-kzg v1.5.0 h1:FYRiJMJG2iv+2Dy3fi14SVGjcPteZ5HAAUe4YWlJygc= +github.com/crate-crypto/go-eth-kzg v1.5.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -220,8 +220,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.101701.0-rc.3 h1:eQS0Y9rWG4/8/EGhZ3rh8hmKsTw+dalLwCmhSncefhA= -github.com/ethereum-optimism/op-geth v1.101701.0-rc.3/go.mod h1:Jws4nBy37/q7vgx8i/nC/dDTSYQbPIsW/ihwOAiIqHE= +github.com/ethereum-optimism/op-geth v1.101702.1-rc.1 h1:2p7pzvmAeZ6xR6pqltf3l6cwCu8HwGR4eWom3v8PwkM= +github.com/ethereum-optimism/op-geth v1.101702.1-rc.1/go.mod h1:HzvOtk7c9KwFaSxRvUBPFHGSjIjomWtw4iSXX6vruQE= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20260115192958-fb86a23cd30e h1:TO1tUcwbhIrNuea/LCsQJSQ5HDWCHdrzT/5MLC1aIU4= github.com/ethereum-optimism/superchain-registry/validation v0.0.0-20260115192958-fb86a23cd30e/go.mod h1:NZ816PzLU1TLv1RdAvYAb6KWOj4Zm5aInT0YpDVml2Y= github.com/ethereum/c-kzg-4844/v2 v2.1.6 h1:xQymkKCT5E2Jiaoqf3v4wsNgjZLY0lRSkZn27fRjSls= diff --git a/justfile b/justfile index 1f99a1e9bf8..5d4c4c21b0d 100644 --- a/justfile +++ b/justfile @@ -6,7 +6,7 @@ PYTHON := env('PYTHON', 'python3') TEST_TIMEOUT := env('TEST_TIMEOUT', '10m') -TEST_PKGS := "./op-alt-da/... ./op-batcher/... ./op-chain-ops/... ./op-node/... ./op-proposer/... ./op-challenger/... ./op-faucet/... ./op-dispute-mon/... ./op-conductor/... ./op-program/... ./op-service/... ./op-supervisor/... ./op-test-sequencer/... ./op-fetcher/... ./op-e2e/system/... ./op-e2e/e2eutils/... ./op-e2e/opgeth/... ./op-e2e/interop/... ./op-e2e/actions/altda ./op-e2e/actions/batcher ./op-e2e/actions/derivation ./op-e2e/actions/helpers ./op-e2e/actions/interop ./op-e2e/actions/proofs ./op-e2e/actions/proposer ./op-e2e/actions/safedb ./op-e2e/actions/sequencer ./op-e2e/actions/sync ./op-e2e/actions/upgrades ./packages/contracts-bedrock/scripts/checks/... ./op-dripper/... ./op-devstack/... ./op-deployer/pkg/deployer/artifacts/... ./op-deployer/pkg/deployer/broadcaster/... ./op-deployer/pkg/deployer/clean/... ./op-deployer/pkg/deployer/integration_test/ ./op-deployer/pkg/deployer/integration_test/cli/... ./op-deployer/pkg/deployer/standard/... ./op-deployer/pkg/deployer/state/... ./op-deployer/pkg/deployer/verify/... ./op-sync-tester/... ./op-supernode/..." +TEST_PKGS := "./op-alt-da/... ./op-batcher/... ./op-chain-ops/... ./op-node/... ./op-proposer/... ./op-challenger/... ./op-faucet/... ./op-dispute-mon/... ./op-conductor/... ./op-program/... ./op-service/... ./op-supervisor/... ./op-test-sequencer/... ./op-fetcher/... ./op-e2e/system/... ./op-e2e/e2eutils/... ./op-e2e/opgeth/... ./op-e2e/interop/... ./op-e2e/actions/altda ./op-e2e/actions/batcher ./op-e2e/actions/derivation ./op-e2e/actions/helpers ./op-e2e/actions/interop ./op-e2e/actions/proofs ./op-e2e/actions/proposer ./op-e2e/actions/safedb ./op-e2e/actions/sequencer ./op-e2e/actions/sync ./op-e2e/actions/upgrades ./packages/contracts-bedrock/scripts/checks/... ./ops/scripts/... ./op-dripper/... ./op-devstack/... ./op-deployer/pkg/deployer/artifacts/... ./op-deployer/pkg/deployer/broadcaster/... ./op-deployer/pkg/deployer/clean/... ./op-deployer/pkg/deployer/integration_test/ ./op-deployer/pkg/deployer/integration_test/cli/... ./op-deployer/pkg/deployer/standard/... ./op-deployer/pkg/deployer/state/... ./op-deployer/pkg/deployer/verify/... ./op-sync-tester/... ./op-supernode/..." FRAUD_PROOF_TEST_PKGS := "./op-e2e/faultproofs/..." @@ -344,7 +344,7 @@ update-op-geth: # Build all Rust binaries (release) for sysgo tests. build-rust-release: - cd rust && cargo build --release --bin kona-node + cd rust && cargo build --release --bin kona-node --bin kona-host cd op-rbuilder && cargo build --release -p op-rbuilder --bin op-rbuilder cd rollup-boost && cargo build --release -p rollup-boost --bin rollup-boost @@ -352,6 +352,15 @@ build-rust-release: check-nut-locks: go run ./ops/scripts/check-nut-locks +# Snapshots current-upgrade-bundle.json as a fork's NUT bundle and updates the lock file. +nut-snapshot-for fork: + go run ./ops/scripts/nut-snapshot-for {{fork}} + +# Verifies a fork's NUT bundle was correctly built from its recorded commit. +nut-provenance-verify fork: + go run ./ops/scripts/nut-provenance-verify {{fork}} + + # Checks that TODO comments have corresponding issues. todo-checker: ./ops/scripts/todo-checker.sh diff --git a/mise.toml b/mise.toml index 6899e37b15d..e4822eab208 100644 --- a/mise.toml +++ b/mise.toml @@ -6,7 +6,7 @@ go = "1.24.13" golangci-lint = "2.8.0" gotestsum = "1.12.3" mockery = "2.53.3" -rust = "1.92.0" +rust = "1.94.0" python = "3.12.0" uv = "0.5.5" jq = "1.7.1" diff --git a/op-acceptance-tests/gates/base.txt b/op-acceptance-tests/gates/base.txt deleted file mode 100644 index 6f73a09ba86..00000000000 --- a/op-acceptance-tests/gates/base.txt +++ /dev/null @@ -1,12 +0,0 @@ -./op-acceptance-tests/tests/base -./op-acceptance-tests/tests/base/deposit -./op-acceptance-tests/tests/base/chain -./op-acceptance-tests/tests/ecotone -./op-acceptance-tests/tests/fjord -./op-acceptance-tests/tests/isthmus -./op-acceptance-tests/tests/isthmus/operator_fee -./op-acceptance-tests/tests/isthmus/withdrawal_root -./op-acceptance-tests/tests/isthmus/erc20_bridge -./op-acceptance-tests/tests/isthmus/pectra -./op-acceptance-tests/tests/jovian/bpo2 -./op-acceptance-tests/tests/jovian/pectra diff --git a/op-acceptance-tests/justfile b/op-acceptance-tests/justfile index 7b68fa982dc..c1a55bc15b1 100644 --- a/op-acceptance-tests/justfile +++ b/op-acceptance-tests/justfile @@ -4,44 +4,43 @@ REPO_ROOT := `realpath ..` # path to the root of the optimism monorepo default: @just acceptance-test -# Run acceptance tests, optionally filtered by a gate (reads packages from gates/.txt) -acceptance-test gate="": +# Build all dependencies for local acceptance test runs. Skipped in CI where jobs handle this. +build-deps: #!/usr/bin/env bash set -euo pipefail - GATE="{{gate}}" - if [[ -n "$GATE" ]]; then - echo -e "DEVNET: in-memory, GATE: $GATE\n" - else - echo -e "DEVNET: in-memory, MODE: all tests\n" - fi + if [[ -n "${CIRCLECI:-}" ]]; then exit 0; fi - # Build dependencies for in-process mode if not in CI. - # In CI jobs already take care of this, so we skip it. - if [[ -z "${CIRCLECI:-}" ]]; then - echo "Building contracts (local build)..." - cd {{REPO_ROOT}} - echo " - Updating submodules..." - git submodule update --init --recursive --single-branch -j 8 - echo " - Installing mise..." - mise install - cd packages/contracts-bedrock - echo " - Installing contracts..." - just install - echo " - Forge build..." - just build-no-tests - cd {{REPO_ROOT}} - - echo "Checking cannon dependencies..." - if [ ! -e {{REPO_ROOT}}/cannon/bin/cannon ] || [ ! -e {{REPO_ROOT}}/op-program/bin/prestate-mt64.bin.gz ]; then - echo "Building cannon dependencies..." - cd {{REPO_ROOT}} - make cannon-prestates - fi - - echo "Building Rust binaries (kona-node, op-rbuilder, rollup-boost)..." - cd {{REPO_ROOT}} - just build-rust-release - fi + echo "Building contracts (local build)..." + cd {{REPO_ROOT}} + echo " - Installing mise..." + mise install + cd packages/contracts-bedrock + echo " - Installing contracts..." + just install + echo " - Forge build..." + just build-no-tests + cd {{REPO_ROOT}} + + echo "Building cannon dependencies..." + cd {{REPO_ROOT}} + just cannon-prestates + + echo "Building Rust binaries (kona-node, op-rbuilder, rollup-boost)..." + cd {{REPO_ROOT}} + just build-rust-release + +# Run specific acceptance tests. Builds dependencies first, then passes all arguments to go test. +# Examples: +# just test ./op-acceptance-tests/tests/base/... +# just test -run TestMyTest ./op-acceptance-tests/tests/base/ +test *args: build-deps + cd {{REPO_ROOT}} && go test -count=1 -timeout 30m {{args}} + +# Run acceptance tests +acceptance-test: + #!/usr/bin/env bash + set -euo pipefail + echo -e "DEVNET: in-memory\n" LOG_LEVEL="$(echo "${LOG_LEVEL:-info}" | grep -E '^(debug|info|warn|error)$' || echo 'info')" echo "LOG_LEVEL: $LOG_LEVEL" @@ -66,7 +65,7 @@ acceptance-test gate="": JOBS="${ACCEPTANCE_TEST_JOBS:-$DEFAULT_JOBS}" TEST_PARALLEL="${ACCEPTANCE_TEST_PARALLEL:-$DEFAULT_TEST_PARALLEL}" - TEST_TIMEOUT="${ACCEPTANCE_TEST_TIMEOUT:-2h}" + TEST_TIMEOUT="${ACCEPTANCE_TEST_TIMEOUT:-30m}" echo "CPU COUNT: $CPU_COUNT" echo "PACKAGE JOBS: $JOBS" echo "TEST PARALLELISM: $TEST_PARALLEL" @@ -92,25 +91,7 @@ acceptance-test gate="": grep -RIn "MarkFlaky(" ./op-acceptance-tests/tests > "$FLAKY_REPORT" || true fi - # Determine which packages to test - if [[ -n "$GATE" ]]; then - GATE_FILE="{{REPO_ROOT}}/op-acceptance-tests/gates/${GATE}.txt" - if [[ ! -f "$GATE_FILE" ]]; then - echo "error: gate file not found: $GATE_FILE" >&2 - exit 1 - fi - # Read non-empty, non-comment lines from the gate file - TEST_PACKAGES=() - while IFS= read -r line; do - line="${line%%#*}" # strip comments - line="${line// /}" # strip whitespace - [[ -z "$line" ]] && continue - TEST_PACKAGES+=("$line") - done < "$GATE_FILE" - echo "Gate '$GATE': ${#TEST_PACKAGES[@]} packages" - else - TEST_PACKAGES=("./op-acceptance-tests/tests/...") - fi + TEST_PACKAGES=("./op-acceptance-tests/tests/...") set +e LOG_LEVEL="${LOG_LEVEL}" {{REPO_ROOT}}/ops/scripts/gotestsum-split.sh \ diff --git a/op-acceptance-tests/tests/base/conductor/leadership_transfer_test.go b/op-acceptance-tests/tests/base/conductor/leadership_transfer_test.go index 9f396a6e3d0..769c6787366 100644 --- a/op-acceptance-tests/tests/base/conductor/leadership_transfer_test.go +++ b/op-acceptance-tests/tests/base/conductor/leadership_transfer_test.go @@ -10,6 +10,7 @@ import ( "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/sysgo" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/log" "github.com/stretchr/testify/require" @@ -23,6 +24,12 @@ type conductorWithInfo struct { // TestConductorLeadershipTransfer checks if the leadership transfer works correctly on the conductors func TestConductorLeadershipTransfer(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with kona-node: + // + // --- FAIL: TestConductorLeadershipTransfer (63.04s) + // panic: interface conversion: sysgo.L2CLNode is *sysgo.KonaNode, not *sysgo.OpNode [recovered] + // panic: interface conversion: sysgo.L2CLNode is *sysgo.KonaNode, not *sysgo.OpNode + sysgo.SkipOnKonaNode(t, "not supported") logger := testlog.Logger(t, log.LevelInfo).With("Test", "TestConductorLeadershipTransfer") sys := presets.NewMinimalWithConductors(t) diff --git a/op-acceptance-tests/tests/depreqres/reqressyncdisabled/divergence/divergence_test.go b/op-acceptance-tests/tests/depreqres/reqressyncdisabled/divergence/divergence_test.go index 6a509035026..c4c2e604e0f 100644 --- a/op-acceptance-tests/tests/depreqres/reqressyncdisabled/divergence/divergence_test.go +++ b/op-acceptance-tests/tests/depreqres/reqressyncdisabled/divergence/divergence_test.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum-optimism/optimism/op-acceptance-tests/tests/depreqres/common" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/presets" + "github.com/ethereum-optimism/optimism/op-devstack/sysgo" "github.com/ethereum-optimism/optimism/op-node/rollup/sync" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" @@ -19,6 +20,15 @@ import ( // the corresponding block, and therefore does not serve it. func TestCLELDivergence(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-31|10:19:50.846] + // assertions.go:387: Error Trace: /Users/josh/repos/optimism/op-acceptance-tests/tests/depreqres/reqressyncdisabled/divergence/divergence_test.go:34 + // assertions.go:387: Error: Not equal: + // assertions.go:387: expected: 0x1 + // assertions.go:387: actual : 0x0 + // assertions.go:387: Test: TestCLELDivergence + sysgo.SkipOnKonaNode(t, "not supported") sys := presets.NewSingleChainMultiNodeWithoutP2PWithoutCheck(t, common.ReqRespSyncDisabledOpts(sync.ELSync)...) require := t.Require() l := t.Logger() diff --git a/op-acceptance-tests/tests/flashblocks/flashblocks_stream_test.go b/op-acceptance-tests/tests/flashblocks/flashblocks_stream_test.go index e29196631d0..8de3ce1033c 100644 --- a/op-acceptance-tests/tests/flashblocks/flashblocks_stream_test.go +++ b/op-acceptance-tests/tests/flashblocks/flashblocks_stream_test.go @@ -1,167 +1,87 @@ package flashblocks import ( - "context" - "encoding/json" - "log/slog" - "os" - "strconv" + "sync" "testing" - "time" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/presets" - "github.com/ethereum-optimism/optimism/op-service/log/logfilter" - "github.com/ethereum-optimism/optimism/op-service/logmods" + "github.com/ethereum-optimism/optimism/op-devstack/sysgo" + "github.com/ethereum-optimism/optimism/op-service/client" + "github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum/go-ethereum/log" - "github.com/stretchr/testify/require" ) -const maxExpectedFlashblocks = 20 - -// TestFlashblocksStream checks we can connect to the flashblocks stream across multiple CL backends. +// TestFlashblocksStream checks that block numbers and indices always increase across both the +// rollup-boost and op-rbuilder streams. func TestFlashblocksStream(gt *testing.T) { t := devtest.ParallelT(gt) - logger := t.Logger() + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-30|22:44:52.250] + // assertions.go:387: Error Trace: /home/circleci/project/op-devstack/sysgo/l2_cl_kona.go:99 + // assertions.go:387: /home/circleci/project/op-devstack/sysgo/mixed_runtime.go:456 + // assertions.go:387: /home/circleci/project/op-devstack/sysgo/singlechain_build.go:182 + // assertions.go:387: /home/circleci/project/op-devstack/sysgo/singlechain_build.go:276 + // assertions.go:387: /home/circleci/project/op-devstack/sysgo/singlechain_flashblocks.go:36 + // assertions.go:387: /home/circleci/project/op-devstack/sysgo/singlechain_runtime.go:105 + // assertions.go:387: /home/circleci/project/op-devstack/sysgo/singlechain_flashblocks.go:53 + // assertions.go:387: /home/circleci/project/op-devstack/presets/flashblocks.go:43 + // assertions.go:387: /home/circleci/project/op-acceptance-tests/tests/flashblocks/flashblocks_stream_test.go:26 + // assertions.go:387: Error: Received unexpected error: + // assertions.go:387: context deadline exceeded + // assertions.go:387: Test: TestFlashblocksStream + // assertions.go:387: Messages: need user RPC + sysgo.SkipOnKonaNode(t, "not supported (fail to get user rpc)") sys := presets.NewSingleChainWithFlashblocks(t) - filterHandler, ok := logmods.FindHandler[logfilter.FilterHandler](logger.Handler()) - if ok { - filterHandler.Set(logfilter.DefaultMute( - logfilter.Level(slog.LevelError).Show(), - logfilter.Select("kind", "L2CLNode").Show(), - )) - } - tracer := t.Tracer() - ctx := t.Ctx() - - ctx, span := tracer.Start(ctx, "test chains") - defer span.End() - - ctx, cancel := context.WithTimeout(ctx, 30*time.Second) - defer cancel() - - flashblocksStreamRate := os.Getenv("FLASHBLOCKS_STREAM_RATE_MS") - if flashblocksStreamRate == "" { - logger.Warn("FLASHBLOCKS_STREAM_RATE_MS is not set, using default of 250ms") - flashblocksStreamRate = "250" - } - - flashblocksStreamRateMs, err := strconv.Atoi(flashblocksStreamRate) - require.NoError(t, err, "failed to parse FLASHBLOCKS_STREAM_RATE_MS: %s", err) - - logger.Info("Flashblocks stream rate", "rate", flashblocksStreamRateMs) - - oprbuilderNode := sys.L2OPRBuilder - rollupBoostNode := sys.L2RollupBoost - _, span = tracer.Start(ctx, "test chain") - defer span.End() - - expectedChainID := sys.L2Chain.ChainID().ToBig() - require.Equal(t, oprbuilderNode.Escape().ChainID().ToBig(), expectedChainID, "flashblocks builder node chain id should match expected chain id") - - DriveViaTestSequencer(t, sys, 3) - testDuration := time.Duration(int64(flashblocksStreamRateMs*maxExpectedFlashblocks*2)) * time.Millisecond - failureTolerance := int(0.15 * float64(maxExpectedFlashblocks)) + driveViaTestSequencer(t, sys, 3) - logger.Debug("Test duration", "duration", testDuration, "failure tolerance (of flashblocks)", failureTolerance) - - builderOutput := make(chan []byte, maxExpectedFlashblocks) - defer close(builderOutput) - builderDone := make(chan struct{}) + var wg sync.WaitGroup + defer wg.Wait() + wg.Add(1) go func() { - err := oprbuilderNode.FlashblocksClient().ReadAll(ctx, logger.With("stream_source", "op-rbuilder"), testDuration, builderOutput, builderDone) - require.NoError(t, err) + defer wg.Done() + ensureFlashblocksIncrease(t, sys.L2OPRBuilder.FlashblocksClient(), t.Logger().With("stream_source", "op-rbuilder")) }() - builderMessages := make([]string, 0) - - output := make(chan []byte, maxExpectedFlashblocks) - defer close(output) - doneListening := make(chan struct{}) - streamedMessages := make([]string, 0) + wg.Add(1) go func() { - err := rollupBoostNode.FlashblocksClient().ReadAll(ctx, logger.With("stream_source", "rollup-boost"), testDuration, output, doneListening) - require.NoError(t, err) + defer wg.Done() + ensureFlashblocksIncrease(t, sys.L2RollupBoost.FlashblocksClient(), t.Logger().With("stream_source", "rollup-boost")) }() - listening := true - for listening { - select { - case <-doneListening: - doneListening = nil - case <-builderDone: - builderDone = nil - case msg := <-output: - streamedMessages = append(streamedMessages, string(msg)) - case msg := <-builderOutput: - builderMessages = append(builderMessages, string(msg)) - } - - if doneListening == nil && builderDone == nil { - listening = false - } - } - - logger.Info("Completed WebSocket stream reading", "msg_count", len(streamedMessages), "builder_msg_count", len(builderMessages)) - - if len(builderMessages) > 0 { - logger.Info("Sample builder message", "payload", builderMessages[0]) - } - - totalFlashblocksProduced := evaluateFlashblocksStream(t, logger, streamedMessages, failureTolerance) - require.Greater(t, totalFlashblocksProduced, 0, "expected to receive flashblocks from rollup-boost stream") - logger.Info("Flashblocks stream validation completed", "total_flashblocks_produced", totalFlashblocksProduced) + // Note that rollup boost may deliberately drop flashblocks from rbuilder to mitigate + // flashblock reorgs. See https://blog.base.dev/flashblocks-deep-dive. + // Otherwise, we could assert that the streams match (after aligning on the same start and end + // flashblocks). } -func evaluateFlashblocksStream(t devtest.T, logger log.Logger, streamedMessages []string, failureTolerance int) int { - require.Greater(t, len(streamedMessages), 0, "should have received at least one message from WebSocket") - flashblocks := make([]Flashblock, len(streamedMessages)) - - failures := 0 - for i, msg := range streamedMessages { - var flashblock Flashblock - if err := json.Unmarshal([]byte(msg), &flashblock); err != nil { - logger.Warn("Failed to unmarshal WebSocket message", "error", err) - failures++ - if failures > failureTolerance { - logger.Error("failed to unmarshal streamed messages into flashblocks beyond the failure tolerance of %d", failureTolerance) - t.FailNow() - } - continue - } - - flashblocks[i] = flashblock - } - - totalFlashblocksProduced := 0 +func ensureFlashblocksIncrease(t devtest.T, wsClient *client.WSClient, logger log.Logger) { + const numFlashblocks = 20 + client := sources.NewFlashblockClient(wsClient, logger, numFlashblocks) + startClient(t, client) - lastIndex := -1 lastBlockNumber := -1 + lastIndex := -1 + for range numFlashblocks { + select { + case <-t.Ctx().Done(): + t.Require().NoError(t.Ctx().Err(), "before %d flashblocks were seen", numFlashblocks) + case flashblock, ok := <-client.Next(): + t.Require().True(ok, "client channel closed before we saw %d flashblocks", numFlashblocks) + t.Require().NotNil(flashblock) + currentBlockNumber := flashblock.Metadata.BlockNumber + currentIndex := flashblock.Index + + if currentBlockNumber == lastBlockNumber { + t.Require().Greater(currentIndex, lastIndex) + } else { + t.Require().Greater(currentBlockNumber, lastBlockNumber) + t.Require().Zero(currentIndex) + } - for _, flashblock := range flashblocks { - currentIndex, currentBlockNumber := flashblock.Index, flashblock.Metadata.BlockNumber - - if lastBlockNumber == -1 { - totalFlashblocksProduced += 1 - lastIndex = currentIndex lastBlockNumber = currentBlockNumber - continue - } - - require.Greater(t, lastIndex, -1, "some bug: last index should be greater than -1 by now") - require.Greater(t, currentIndex, -1, "some bug: current index should be greater than -1 by now") - - if currentBlockNumber == lastBlockNumber { - require.Greater(t, currentIndex, lastIndex, "some bug: current index should be greater than last index from the stream") - - totalFlashblocksProduced += (currentIndex - lastIndex) - } else if currentBlockNumber > lastBlockNumber { - totalFlashblocksProduced += (currentIndex + 1) + lastIndex = currentIndex } - - lastIndex = currentIndex - lastBlockNumber = currentBlockNumber } - - return totalFlashblocksProduced } diff --git a/op-acceptance-tests/tests/flashblocks/flashblocks_transfer_test.go b/op-acceptance-tests/tests/flashblocks/flashblocks_transfer_test.go index a612a65e60f..34b6b1cc668 100644 --- a/op-acceptance-tests/tests/flashblocks/flashblocks_transfer_test.go +++ b/op-acceptance-tests/tests/flashblocks/flashblocks_transfer_test.go @@ -1,133 +1,120 @@ package flashblocks import ( - "context" - "encoding/json" - "fmt" + "math/big" "strings" + "sync" "testing" - "time" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/presets" + "github.com/ethereum-optimism/optimism/op-devstack/sysgo" "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum-optimism/optimism/op-service/txplan" "github.com/stretchr/testify/require" ) -type timedMessage struct { - message []byte - timestamp time.Time -} - -// TestFlashblocksTransfer checks that a transfer gets reflected in a flashblock before the transaction is confirmed in a block -// This test concurrently: -// - listens to the Flashblocks stream for 20s and collects all those streamed Flashblocks along with the timestamp when they were received. -// - Makes a transaction from Alice to Bob with a pre-known amount and records an approximated txn confirmation time (with upto nanosecond granularity) just after that txn was done. - +// TestFlashblocksTransfer checks that a transfer is reflected in the op-rbuilder +// flashblock stream for the same block that eventually includes the transaction. +// // Expectations: -// - After flashblock streaming is done (20s), the transaction's already included in a (real) block. -// - There must have been a Flashblock containing a new_account_balance corresponding to Bob's account. This flashblock would be representative of the flashblock including Alice-to-Bob transaction. -// - That Flashblock's time (in seconds) must be less than or equal to the Transaction's block time (in seconds). (Can't check the block time beyond the granularity of seconds) -// - That Flashblock's time in nanoseconds must be before the approximated transaction confirmation time recorded previously. +// +// - There must have been a Flashblock whose metadata.receipts contains Alice's transaction hash. +// This identifies the flashblock that carried Alice's transfer to Bob. +// - The transaction's confirmed block number must match the flashblock's block number. +// - If Bob's balance is reported in new_account_balances for that flashblock, it must match the +// on-chain balance at the transaction's inclusion block. func TestFlashblocksTransfer(gt *testing.T) { t := devtest.ParallelT(gt) - logger := t.Logger() - tracer := t.Tracer() - ctx := t.Ctx() + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-30|22:44:52.250] + // assertions.go:387: Error Trace: /op-devstack/sysgo/l2_cl_kona.go:99 + // assertions.go:387: /op-devstack/sysgo/mixed_runtime.go:456 + // assertions.go:387: /op-devstack/sysgo/singlechain_build.go:182 + // assertions.go:387: /op-devstack/sysgo/singlechain_build.go:276 + // assertions.go:387: /op-devstack/sysgo/singlechain_flashblocks.go:36 + // assertions.go:387: /op-devstack/sysgo/singlechain_runtime.go:105 + // assertions.go:387: /op-devstack/sysgo/singlechain_flashblocks.go:53 + // assertions.go:387: /op-devstack/presets/flashblocks.go:43 + // assertions.go:387: /op-acceptance-tests/tests/flashblocks/flashblocks_transfer_test.go:38 + // assertions.go:387: Error: Received unexpected error: + // assertions.go:387: context deadline exceeded + // assertions.go:387: Test: TestFlashblocksTransfer + // assertions.go:387: Messages: need user RPC + sysgo.SkipOnKonaNode(t, "not supported (fail to get user rpc)") sys := presets.NewSingleChainWithFlashblocks(t) - topLevelCtx, span := tracer.Start(ctx, "test chains") - defer span.End() - - ctx, cancel := context.WithTimeout(topLevelCtx, 45*time.Second) - defer cancel() - _, span = tracer.Start(ctx, fmt.Sprintf("test chain %s", sys.L2Chain.String())) - defer span.End() - // Drive a couple blocks on the test sequencer so the faucet L2 funding tx has a chance to land before we rely on it. - DriveViaTestSequencer(t, sys, 2) + driveViaTestSequencer(t, sys, 2) + + // Subscribe directly to op-rbuilder here: rollup-boost may intentionally drop + // flashblocks, but this test needs to observe the flashblock carrying Alice's + // transfer to Bob. + fbClient := sources.NewFlashblockClient( + sys.L2OPRBuilder.FlashblocksClient(), + t.Logger().With("stream_source", "op-rbuilder"), + 100, + ) + startClient(t, fbClient) - alice := sys.FunderL2.NewFundedEOA(eth.ThreeHundredthsEther) bob := sys.Wallet.NewEOA(sys.L2EL) - bobAddress := bob.Address().Hex() - - // flashblocks listener - start goroutine and wait for it to be running - flashblocksClient := sys.L2RollupBoost.FlashblocksClient() - output := make(chan []byte, 100) - doneListening := make(chan struct{}) - go func() { - err := flashblocksClient.ReadAll(ctx, logger.With("stream_source", "rollup-boost"), 20*time.Second, output, doneListening) - if err != nil { - t.Require().NoError(err, "failed to listen for flashblocks") - } - }() - - var executedTransaction *txplan.PlannedTx - var transactionApproxConfirmationTime time.Time - var expectedBobBalance string - - // transactor + alice := sys.FunderL2.NewFundedEOA(eth.ThreeHundredthsEther) + bobAddress := bob.Address() + tx := txplan.NewPlannedTx(alice.Plan(), txplan.WithTo(&bobAddress), txplan.WithValue(eth.OneHundredthEther)) + signedTx, err := tx.Signed.Eval(t.Ctx()) + t.Require().NoError(err) + txHash := strings.ToLower(signedTx.Hash().Hex()) + + // Buffer the result so cleanup cannot deadlock if we time out before reading it. + txCh := make(chan error, 1) + var wg sync.WaitGroup + defer wg.Wait() + wg.Add(1) go func() { - bobBalance := bob.GetBalance() - - depositAmount := eth.OneHundredthEther - bobAddr := bob.Address() - executedTransaction = alice.Transact( - alice.Plan(), - txplan.WithTo(&bobAddr), - txplan.WithValue(depositAmount), - ) - transactionApproxConfirmationTime = time.Now() - newBobBalance := bobBalance.Add(depositAmount) - expectedBobBalance = newBobBalance.Hex() - bob.VerifyBalanceExact(newBobBalance) + defer wg.Done() + _, err := tx.Success.Eval(t.Ctx()) + txCh <- err + close(txCh) }() - streamedMessages := make([]timedMessage, 0) - listening := true - for listening { + var blockNumber int + var observedBalance *big.Int +outer: + for { select { - case <-doneListening: - listening = false - case msg := <-output: - streamedMessages = append(streamedMessages, timedMessage{message: msg, timestamp: time.Now()}) + case fb, ok := <-fbClient.Next(): + t.Require().True(ok, "client channel closed before we found the transaction") + if _, found := fb.Metadata.Receipts[txHash]; found { + blockNumber = fb.Metadata.BlockNumber + if balanceStr, ok := fb.Metadata.NewAccountBalances[strings.ToLower(bob.Address().Hex())]; ok { + observedBalance, ok = new(big.Int).SetString(balanceStr[2:], 16) + t.Require().True(ok) + } + break outer + } + case <-t.Ctx().Done(): + t.Require().NoError(t.Ctx().Err(), "never found the transaction in flashblock receipts") } } - require.Greater(t, len(streamedMessages), 0, "should have received at least one message from the flashblocks stream") - require.NotNil(t, executedTransaction, "should have executed a transaction") - - var bobFlashblockTime time.Time - var bobFlashblock *Flashblock - var observedBobBalance string - for _, msg := range streamedMessages { - flashblock := &Flashblock{} - err := json.Unmarshal(msg.message, flashblock) - require.NoError(t, err, "should be able to unmarshal the message") - - bobBalance := flashblock.Metadata.NewAccountBalances[strings.ToLower(bobAddress)] - if bobBalance != "" && bobBalance != "0x0" { - bobFlashblockTime = msg.timestamp - bobFlashblock = flashblock - observedBobBalance = bobBalance - break - } + select { + case err := <-txCh: + t.Require().NoError(err) + case <-t.Ctx().Done(): + t.Require().NoError(t.Ctx().Err()) } - require.NotNil(t, bobFlashblock, "should have received a flashblock corresponding to Bob's receival of the funds") - - txBlock, err := executedTransaction.IncludedBlock.Eval(ctx) - require.NoError(t, err, "should be able to evaluate the block in which the transaction was included") + txBlock, err := tx.IncludedBlock.Eval(t.Ctx()) + t.Require().NoError(err) + require.Equal(t, int(txBlock.Number), blockNumber, "the transaction's block number should be the same as the flashblock's block number") - txBlockNum := int(txBlock.Number) // block number of the block in which the transaction was included / confirmed - flashblockParentBlockNum := int(bobFlashblock.Metadata.BlockNumber) // block number of the parent block of the flashblock which first recorded the update in Bob's account balance (representative of the flashblock which included this transaction) - - txBlockTimeSeconds := int64(txBlock.Time) // timestamp of the block in which the transaction was included / confirmed - txFlashblockTimeInSeconds := bobFlashblockTime.Unix() // timestamp of the flashblock which supposedly included Bob's transaction + if observedBalance == nil { + t.Require().Fail("matched flashblock via receipts but Bob was absent from new_account_balances", "bob=%s txHash=%s", bob.Address(), txHash) + } - require.Equal(t, observedBobBalance, expectedBobBalance, "Bob's balance must be correct as per exactly what Alice transferred to them") - require.Equal(t, txBlockNum, flashblockParentBlockNum, "the transaction's block number should be the same as the flashblock's parent block number") - require.LessOrEqual(t, txFlashblockTimeInSeconds, txBlockTimeSeconds, "the transaction's block time (in seconds) should be less than or equal to the flashblock's time (in seconds)") - require.Less(t, bobFlashblockTime.UnixNano(), transactionApproxConfirmationTime.UnixNano(), "flashblock time should be before the transaction's (approximated) confirmation time") + expectedBalance, err := sys.L2EL.EthClient().BalanceAt(t.Ctx(), bob.Address(), new(big.Int).SetUint64(txBlock.Number)) + t.Require().NoError(err) + require.Equal(t, expectedBalance, observedBalance, "Bob's balance must match the on-chain balance at the transaction inclusion block when reported in flashblock metadata") } diff --git a/op-acceptance-tests/tests/flashblocks/utils.go b/op-acceptance-tests/tests/flashblocks/utils.go index 6d3262112a7..b0d68553a28 100644 --- a/op-acceptance-tests/tests/flashblocks/utils.go +++ b/op-acceptance-tests/tests/flashblocks/utils.go @@ -1,66 +1,20 @@ package flashblocks import ( - "encoding/json" - "strings" + "context" + "sync" "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/sources" "github.com/ethereum-optimism/optimism/op-test-sequencer/sequencer/seqtypes" "github.com/stretchr/testify/require" ) -type Flashblock struct { - PayloadID string `json:"payload_id"` - Index int `json:"index"` - Diff struct { - StateRoot string `json:"state_root"` - ReceiptsRoot string `json:"receipts_root"` - LogsBloom string `json:"logs_bloom"` - GasUsed string `json:"gas_used"` - BlockHash string `json:"block_hash"` - Transactions []any `json:"transactions"` - Withdrawals []any `json:"withdrawals"` - } `json:"diff"` - Metadata struct { - BlockNumber int `json:"block_number"` - NewAccountBalances map[string]string `json:"new_account_balances"` - Receipts map[string]interface{} `json:"receipts"` - } `json:"metadata"` -} - -type FlashblocksStreamMode string - -const ( - FlashblocksStreamMode_Leader FlashblocksStreamMode = "leader" - FlashblocksStreamMode_Follower FlashblocksStreamMode = "follower" -) - -// UnmarshalJSON implements custom unmarshaling for Flashblock to lower case the keys of .metadata.new_account_balances. -func (f *Flashblock) UnmarshalJSON(data []byte) error { - type TempFlashblock Flashblock // need a type alias to avoid infinite recursion - temp := (*TempFlashblock)(f) - - if err := json.Unmarshal(data, temp); err != nil { - return err - } - if f.Metadata.NewAccountBalances == nil { - return nil - } - - loweredBalances := make(map[string]string) - for key, value := range f.Metadata.NewAccountBalances { - loweredBalances[strings.ToLower(key)] = value - } - f.Metadata.NewAccountBalances = loweredBalances - - return nil -} - -// DriveViaTestSequencer explicitly builds a few blocks to ensure the builder/rollup-boost +// driveViaTestSequencer explicitly builds a few blocks to ensure the builder/rollup-boost // have payloads to serve before we start listening for flashblocks. -func DriveViaTestSequencer(t devtest.T, sys *presets.SingleChainWithFlashblocks, count int) { +func driveViaTestSequencer(t devtest.T, sys *presets.SingleChainWithFlashblocks, count int) { t.Helper() ts := sys.TestSequencer.Escape().ControlAPI(sys.L2Chain.ChainID()) ctx := t.Ctx() @@ -78,3 +32,17 @@ func DriveViaTestSequencer(t devtest.T, sys *presets.SingleChainWithFlashblocks, head = sys.L2EL.BlockRefByLabel(eth.Unsafe) sys.Log.Info("Pre-listen unsafe head", "unsafe", head) } + +func startClient(t devtest.T, client *sources.FlashblockClient) { + ctx, cancel := context.WithCancel(t.Ctx()) + var wg sync.WaitGroup + t.Cleanup(func() { + cancel() + wg.Wait() + }) + wg.Add(1) + go func() { + defer wg.Done() + t.Require().NoError(client.Start(ctx)) + }() +} diff --git a/op-acceptance-tests/tests/interop/proofs/serial/interop_fault_proofs_test.go b/op-acceptance-tests/tests/interop/proofs/serial/interop_fault_proofs_test.go index 51922df6c11..e95042b5613 100644 --- a/op-acceptance-tests/tests/interop/proofs/serial/interop_fault_proofs_test.go +++ b/op-acceptance-tests/tests/interop/proofs/serial/interop_fault_proofs_test.go @@ -18,12 +18,24 @@ func TestInteropFaultProofs(gt *testing.T) { sfp.RunSuperFaultProofTest(t, sys) } +func TestInteropFaultProofs_PreForkActivation(gt *testing.T) { + t := devtest.SerialT(gt) + sys := presets.NewSimpleInteropSupernodeProofs(t, presets.WithChallengerCannonKonaEnabled(), presets.WithSuggestedInteropActivationOffset(365*24*60*60)) + sfp.RunPreForkActivationTest(t, sys) +} + func TestInteropFaultProofs_ConsolidateValidCrossChainMessage(gt *testing.T) { t := devtest.ParallelT(gt) sys := presets.NewSimpleInteropSupernodeProofs(t, presets.WithChallengerCannonKonaEnabled()) sfp.RunConsolidateValidCrossChainMessageTest(t, sys) } +func TestInteropFaultProofs_DepositMessage(gt *testing.T) { + t := devtest.SerialT(gt) + sys := presets.NewSimpleInteropSupernodeProofs(t, presets.WithChallengerCannonKonaEnabled()) + sfp.RunDepositMessageTest(t, sys) +} + func TestInteropFaultProofs_VariedBlockTimes(gt *testing.T) { t := devtest.SerialT(gt) // TODO(#19828): endTimestamp may align with a no-op transition for the slower chain, @@ -58,9 +70,6 @@ func TestInteropFaultProofs_VariedBlockTimes_FasterChainB(gt *testing.T) { func TestInteropFaultProofs_InvalidBlock(gt *testing.T) { t := devtest.SerialT(gt) - // TODO(#19411): Re-enable once the invalid-block supernode proof expectations match the - // native Kona FPP and challenger provider behavior again. - t.Skip("Temporarily skipped while investigating invalid-block supernode proof mismatches") sys := presets.NewSimpleInteropSupernodeProofs(t, presets.WithChallengerCannonKonaEnabled()) sfp.RunInvalidBlockTest(t, sys) } diff --git a/op-acceptance-tests/tests/proofs/cannon/step_test.go b/op-acceptance-tests/tests/proofs/cannon/step_test.go index addf858771d..f358e516435 100644 --- a/op-acceptance-tests/tests/proofs/cannon/step_test.go +++ b/op-acceptance-tests/tests/proofs/cannon/step_test.go @@ -5,12 +5,14 @@ import ( "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl/proofs" + "github.com/ethereum-optimism/optimism/op-devstack/sysgo" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) func TestExecuteStep_Cannon(gt *testing.T) { t := devtest.ParallelT(gt) + sysgo.SkipOnOpReth(t, "not supported (timeout)") sys := newSystem(t) l1User := sys.FunderL1.NewFundedEOA(eth.ThousandEther) @@ -28,6 +30,19 @@ func TestExecuteStep_Cannon(gt *testing.T) { func TestExecuteStep_CannonKona(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-31|10:33:38.442] + // assertions.go:387: Error Trace: /optimism/op-devstack/dsl/proofs/game_helper.go:263 + // assertions.go:387: /optimism/op-devstack/dsl/proofs/game_helper.go:196 + // assertions.go:387: /optimism/op-devstack/dsl/proofs/fault_dispute_game.go:124 + // assertions.go:387: /optimism/op-acceptance-tests/tests/proofs/cannon/step_test.go:40 + // assertions.go:387: /.local/share/mise/installs/go/1.24.13/src/runtime/asm_arm64.s:1223 + // assertions.go:387: Error: Received unexpected error: + // assertions.go:387: failed to get safe head at L1 block 0xe926b953777546729b2607011590354a6a42dc35e36b7ea68c9dd4b470261541:6: not found + // assertions.go:387: Test: TestExecuteStep_CannonKona + // assertions.go:387: Messages: Failed to get honest root claim + sysgo.SkipOnKonaNode(t, "not supported") sys := newSystem(t) l1User := sys.FunderL1.NewFundedEOA(eth.ThousandEther) diff --git a/op-acceptance-tests/tests/safeheaddb_clsync/safeheaddb_test.go b/op-acceptance-tests/tests/safeheaddb_clsync/safeheaddb_test.go index da441258a0e..8699482b0b0 100644 --- a/op-acceptance-tests/tests/safeheaddb_clsync/safeheaddb_test.go +++ b/op-acceptance-tests/tests/safeheaddb_clsync/safeheaddb_test.go @@ -13,6 +13,18 @@ import ( func TestPreserveDatabaseOnCLResync(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with op-reth: + // + // assertions.go:387: ERROR[03-31|09:40:50.281] + // assertions.go:387: Error Trace: /optimism/op-devstack/sysgo/l2_el_p2p_util.go:61 + // assertions.go:387: /optimism/op-devstack/dsl/l2_el.go:281 + // assertions.go:387: /optimism/op-acceptance-tests/tests/safeheaddb_clsync/safeheaddb_test.go:42 + // assertions.go:387: Error: Received unexpected error: + // assertions.go:387: context deadline exceeded + // assertions.go:387: Test: TestPreserveDatabaseOnCLResync + // assertions.go:387: Messages: The peer was not connected + // assertions.go:387: + sysgo.SkipOnOpReth(t, "not supported (peering issue)") sys := presets.NewSingleChainMultiNode(t, presets.WithGlobalL2CLOption(sysgo.L2CLOptionFn(func(p devtest.T, _ sysgo.ComponentTarget, cfg *sysgo.L2CLConfig) { cfg.SequencerSyncMode = sync.CLSync diff --git a/op-acceptance-tests/tests/safeheaddb_elsync/safeheaddb_test.go b/op-acceptance-tests/tests/safeheaddb_elsync/safeheaddb_test.go index 5ddfe16c5d0..22b5c53e830 100644 --- a/op-acceptance-tests/tests/safeheaddb_elsync/safeheaddb_test.go +++ b/op-acceptance-tests/tests/safeheaddb_elsync/safeheaddb_test.go @@ -12,16 +12,38 @@ import ( ) func newSingleChainMultiNodeELSync(t devtest.T) *presets.SingleChainMultiNode { - return presets.NewSingleChainMultiNode(t, + // Use WithoutCheck because the default preset sync check uses 30 attempts + // (60s) for CrossSafe matching, which is insufficient for EL Sync mode. + // EL Sync must complete the initial sync phase before derivation can start, + // so CrossSafe takes longer to advance than in CL Sync mode. + sys := presets.NewSingleChainMultiNodeWithoutCheck(t, presets.WithGlobalL2CLOption(sysgo.L2CLOptionFn(func(p devtest.T, _ sysgo.ComponentTarget, cfg *sysgo.L2CLConfig) { cfg.VerifierSyncMode = sync.ELSync cfg.SafeDBPath = p.TempDir() })), ) + // Run the initial sync check with 60 attempts (120s) to accommodate EL Sync. + dsl.CheckAll(t, + sys.L2CLB.MatchedFn(sys.L2CL, types.CrossSafe, 60), + sys.L2CLB.MatchedFn(sys.L2CL, types.LocalUnsafe, 60), + ) + return sys } func TestTruncateDatabaseOnELResync(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with op-reth: + // + // assertions.go:387: ERROR[03-31|09:41:28.788] + // assertions.go:387: Error Trace: /optimism/op-devstack/sysgo/l2_el_p2p_util.go:61 + // assertions.go:387: /optimism/op-devstack/dsl/l2_el.go:281 + // assertions.go:387: /optimism/op-acceptance-tests/tests/safeheaddb_elsync/safeheaddb_test.go:44 + // assertions.go:387: Error: Received unexpected error: + // assertions.go:387: dial tcp 127.0.0.1:55994: i/o timeout + // assertions.go:387: Test: TestTruncateDatabaseOnELResync + // assertions.go:387: Messages: The peer was not connected + // assertions.go:387: + sysgo.SkipOnOpReth(t, "not supported (peering issue)") sys := newSingleChainMultiNodeELSync(t) dsl.CheckAll(t, @@ -51,6 +73,16 @@ func TestTruncateDatabaseOnELResync(gt *testing.T) { func TestNotTruncateDatabaseOnRestartWithExistingDatabase(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-31|10:35:59.154] + // assertions.go:387: Error Trace: /Users/josh/repos/optimism/op-devstack/dsl/safedb.go:22 + // assertions.go:387: /Users/josh/repos/optimism/op-devstack/dsl/l2_cl.go:432 + // assertions.go:387: /Users/josh/repos/optimism/op-acceptance-tests/tests/safeheaddb_elsync/safeheaddb_test.go:74 + // assertions.go:387: Error: Expected value not to be nil. + // assertions.go:387: Test: TestNotTruncateDatabaseOnRestartWithExistingDatabase + // assertions.go:387: Messages: no safe head data available at L1 block 4 + sysgo.SkipOnKonaNode(t, "not supported") sys := newSingleChainMultiNodeELSync(t) dsl.CheckAll(t, diff --git a/op-acceptance-tests/tests/superfaultproofs/superfaultproofs.go b/op-acceptance-tests/tests/superfaultproofs/superfaultproofs.go index 777bbc44656..cd66695402b 100644 --- a/op-acceptance-tests/tests/superfaultproofs/superfaultproofs.go +++ b/op-acceptance-tests/tests/superfaultproofs/superfaultproofs.go @@ -133,7 +133,7 @@ func optimisticBlockAtTimestamp(t devtest.T, queryAPI apis.SupernodeQueryAPI, ch t.Require().NoError(err) out, ok := resp.OptimisticAtTimestamp[chainID] t.Require().Truef(ok, "no optimistic output for chain %v at timestamp %d", chainID, timestamp) - return interopTypes.OptimisticBlock{BlockHash: out.Output.BlockRef.Hash, OutputRoot: out.Output.OutputRoot} + return interopTypes.OptimisticBlock{BlockHash: out.Output.BlockHash, OutputRoot: out.OutputRoot} } // marshalTransition serializes a transition state with the given super root, step, and progress. @@ -727,6 +727,105 @@ func RunVariedBlockTimesTest(t devtest.T, sys *presets.SimpleInterop) { } } +// RunPreForkActivationTest verifies that super-root transitions produce +// correct results when the interop fork is scheduled but not yet active. +// It sends an initiating message on chain A and a (reverting) executing +// message on chain B to ensure the proof system handles interop-related +// transactions correctly even before the fork activates. +func RunPreForkActivationTest(t devtest.T, sys *presets.SimpleInterop) { + t.Require().NotNil(sys.SuperRoots, "supernode is required for this test") + rng := rand.New(rand.NewSource(1234)) + + chains := orderedChains(sys) + t.Require().Len(chains, 2, "expected exactly 2 interop chains") + + aliceA := sys.FunderA.NewFundedEOA(eth.OneEther) + aliceB := aliceA.AsEL(sys.L2ELB) + sys.FunderB.Fund(aliceB, eth.OneEther) + + // Send an initiating message on chain A (just emits a log via EventLogger). + eventLogger := aliceA.DeployEventLogger() + initMsg := aliceA.SendRandomInitMessage(rng, eventLogger, 2, 10) + + // Execute the message on chain B. Interop is not active so the CrossL2Inbox + // call reverts, but the tx is still included. This mirrors the original action + // test which verified the supervisor does not re-org out reverted interop + // transactions when the fork is inactive. + execMsg := aliceB.SendExecMessage(initMsg, dsl.WithFixedGasLimit(100_000), dsl.WithExpectRevert()) + + endTimestamp := sys.L2ChainB.TimestampForBlockNum(bigs.Uint64Strict(execMsg.BlockNumber())) + t.Require().False(chains[0].Cfg.IsInterop(endTimestamp), "Interop should not be active") + + sys.SuperRoots.AwaitValidatedTimestamp(endTimestamp) + l1Head := latestRequiredL1(sys.SuperRoots.SuperRootAtTimestamp(endTimestamp)) + + startTimestamp := endTimestamp - 1 + start := superRootAtTimestamp(t, chains, startTimestamp) + end := superRootAtTimestamp(t, chains, endTimestamp) + + firstOptimistic := optimisticBlockAtTimestamp(t, sys.SuperRoots.QueryAPI(), chains[0].ID, endTimestamp) + secondOptimistic := optimisticBlockAtTimestamp(t, sys.SuperRoots.QueryAPI(), chains[1].ID, endTimestamp) + + step1 := marshalTransition(start, 1, firstOptimistic) + step2 := marshalTransition(start, 2, firstOptimistic, secondOptimistic) + padding := func(step uint64) []byte { + return marshalTransition(start, step, firstOptimistic, secondOptimistic) + } + + tests := []*transitionTest{ + { + Name: "FirstChainOptimisticBlock", + AgreedClaim: start.Marshal(), + DisputedClaim: step1, + DisputedTraceIndex: 0, + L1Head: l1Head, + ClaimTimestamp: endTimestamp, + ExpectValid: true, + }, + { + Name: "SecondChainOptimisticBlock", + AgreedClaim: step1, + DisputedClaim: step2, + DisputedTraceIndex: 1, + L1Head: l1Head, + ClaimTimestamp: endTimestamp, + ExpectValid: true, + }, + { + Name: "FirstPaddingStep", + AgreedClaim: step2, + DisputedClaim: padding(3), + DisputedTraceIndex: 2, + L1Head: l1Head, + ClaimTimestamp: endTimestamp, + ExpectValid: true, + }, + { + Name: "Consolidate", + AgreedClaim: padding(consolidateStep), + DisputedClaim: end.Marshal(), + DisputedTraceIndex: consolidateStep, + L1Head: l1Head, + ClaimTimestamp: endTimestamp, + ExpectValid: true, + }, + } + + challengerCfg := sys.L2ChainA.Escape().L2Challengers()[0].Config() + gameDepth := sys.DisputeGameFactory().GameImpl(gameTypes.SuperCannonKonaGameType).SplitDepth() + + for _, test := range tests { + t.Run(test.Name+"-fpp", func(t devtest.T) { + runKonaInteropProgram(t, challengerCfg.CannonKona, test.L1Head.Hash, + test.AgreedClaim, crypto.Keccak256Hash(test.DisputedClaim), + test.ClaimTimestamp, test.ExpectValid) + }) + t.Run(test.Name+"-challenger", func(t devtest.T) { + runChallengerProviderTest(t, sys.SuperRoots.QueryAPI(), gameDepth, startTimestamp, test.ClaimTimestamp, test) + }) + } +} + func RunConsolidateValidCrossChainMessageTest(t devtest.T, sys *presets.SimpleInterop) { t.Require().NotNil(sys.SuperRoots, "supernode is required for this test") rng := rand.New(rand.NewSource(1234)) @@ -955,3 +1054,74 @@ func RunInvalidBlockTest(t devtest.T, sys *presets.SimpleInterop) { }) } } + +// RunDepositMessageTest verifies that the fault proof system correctly handles +// consolidation when a cross-chain message is initiated via an L1 deposit transaction. +func RunDepositMessageTest(t devtest.T, sys *presets.SimpleInterop) { + t.Require().NotNil(sys.SuperRoots, "supernode is required for this test") + rng := rand.New(rand.NewSource(5678)) + + chains := orderedChains(sys) + t.Require().Len(chains, 2, "expected exactly 2 interop chains") + + aliceA := sys.FunderA.NewFundedEOA(eth.OneEther) + aliceL1 := aliceA.AsEL(sys.L1EL) + sys.FunderL1.Fund(aliceL1, eth.OneEther) + aliceB := aliceA.AsEL(sys.L2ELB) + sys.FunderB.Fund(aliceB, eth.OneEther) + + eventLogger := aliceA.DeployEventLogger() + depositEOA := aliceA.ViaDepositTx(aliceL1, sys.L2ELA, sys.L2ChainA) + initMsg := depositEOA.SendRandomInitMessage(rng, eventLogger) + execMsg := aliceB.SendExecMessage(initMsg) + + endTimestamp := sys.L2ChainB.TimestampForBlockNum(bigs.Uint64Strict(execMsg.BlockNumber())) + startTimestamp := endTimestamp - 1 + + sys.SuperRoots.AwaitValidatedTimestamp(endTimestamp) + l1HeadCurrent := latestRequiredL1(sys.SuperRoots.SuperRootAtTimestamp(endTimestamp)) + + start := superRootAtTimestamp(t, chains, startTimestamp) + end := superRootAtTimestamp(t, chains, endTimestamp) + + firstOptimistic := optimisticBlockAtTimestamp(t, sys.SuperRoots.QueryAPI(), chains[0].ID, endTimestamp) + secondOptimistic := optimisticBlockAtTimestamp(t, sys.SuperRoots.QueryAPI(), chains[1].ID, endTimestamp) + paddingStep := func(step uint64) []byte { + return marshalTransition(start, step, firstOptimistic, secondOptimistic) + } + + tests := []*transitionTest{ + { + Name: "Consolidate", + AgreedClaim: paddingStep(consolidateStep), + DisputedClaim: end.Marshal(), + DisputedTraceIndex: consolidateStep, + ExpectValid: true, + L1Head: l1HeadCurrent, + ClaimTimestamp: endTimestamp, + }, + { + Name: "Consolidate-InvalidNoChange", + AgreedClaim: paddingStep(consolidateStep), + DisputedClaim: paddingStep(consolidateStep), + DisputedTraceIndex: consolidateStep, + ExpectValid: false, + L1Head: l1HeadCurrent, + ClaimTimestamp: endTimestamp, + }, + } + + challengerCfg := sys.L2ChainA.Escape().L2Challengers()[0].Config() + gameDepth := sys.DisputeGameFactory().GameImpl(gameTypes.SuperCannonKonaGameType).SplitDepth() + for _, test := range tests { + t.Run(test.Name+"-fpp", func(t devtest.T) { + runKonaInteropProgram(t, challengerCfg.CannonKona, test.L1Head.Hash, + test.AgreedClaim, crypto.Keccak256Hash(test.DisputedClaim), + test.ClaimTimestamp, test.ExpectValid) + }) + + t.Run(test.Name+"-challenger", func(t devtest.T) { + runChallengerProviderTest(t, sys.SuperRoots.QueryAPI(), gameDepth, startTimestamp, test.ClaimTimestamp, test) + }) + } +} diff --git a/op-acceptance-tests/tests/sync/clsync/gap_clp2p/sync_test.go b/op-acceptance-tests/tests/sync/clsync/gap_clp2p/sync_test.go index d56828d53d0..fb16729e4fe 100644 --- a/op-acceptance-tests/tests/sync/clsync/gap_clp2p/sync_test.go +++ b/op-acceptance-tests/tests/sync/clsync/gap_clp2p/sync_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-devstack/devtest" + "github.com/ethereum-optimism/optimism/op-devstack/sysgo" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -11,6 +12,18 @@ import ( // TestSyncAfterInitialELSync tests that blocks received out of order would be processed in order when running in CL sync mode. Note that this is not going to happen when running in EL sync mode, which relies on healthy ELP2P, something that is disabled in this test. func TestSyncAfterInitialELSync(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-31|10:38:08.992] + // "\n\tError Trace:\t/optimism/op-devstack/dsl/l2_el.go:192\n\t + // \t\t\t\t/optimism/op-acceptance-tests/tests/sync/clsync/gap_clp2p/sync_test.go:46 + // \n\tError: + // \tReceived unexpected error:\n\t + // \toperation failed permanently after 2 attempts: expected head for label=latest to advance to target=5, + // but got current=2 + // \tTest: \tTestSyncAfterInitialELSync\n" + + sysgo.SkipOnKonaNode(t, "not supported") sys := newGapCLP2PSystem(t) require := t.Require() diff --git a/op-acceptance-tests/tests/sync/elsync/gap_clp2p/sync_test.go b/op-acceptance-tests/tests/sync/elsync/gap_clp2p/sync_test.go index 2dd083f7cee..19954dfe819 100644 --- a/op-acceptance-tests/tests/sync/elsync/gap_clp2p/sync_test.go +++ b/op-acceptance-tests/tests/sync/elsync/gap_clp2p/sync_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-devstack/devtest" + "github.com/ethereum-optimism/optimism/op-devstack/sysgo" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -46,6 +47,16 @@ func TestReachUnsafeTipByAppendingUnsafePayload(gt *testing.T) { // while maintaining correct Engine API semantics. func TestCLUnsafeNotRewoundOnInvalidDuringELSync(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with op-reth: + // + // assertions.go:387: ERROR[03-31|09:41:58.089] + // assertions.go:387: Error Trace: /optimism/op-devstack/dsl/l2_cl.go:279 + // assertions.go:387: /optimism/op-acceptance-tests/tests/sync/elsync/gap_clp2p/sync_test.go:96 + // assertions.go:387: Error: Received unexpected error: + // assertions.go:387: expected head not to advance: unsafe + // assertions.go:387: Test: TestCLUnsafeNotRewoundOnInvalidDuringELSync + // assertions.go:387: + sysgo.SkipOnOpReth(t, "not supported") sys := newGapCLP2PSystem(t) logger := t.Logger() require := t.Require() diff --git a/op-acceptance-tests/tests/sync/elsync/gap_elp2p/sync_test.go b/op-acceptance-tests/tests/sync/elsync/gap_elp2p/sync_test.go index ae2a15255e7..574c69be0ad 100644 --- a/op-acceptance-tests/tests/sync/elsync/gap_elp2p/sync_test.go +++ b/op-acceptance-tests/tests/sync/elsync/gap_elp2p/sync_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/ethereum-optimism/optimism/op-devstack/devtest" + "github.com/ethereum-optimism/optimism/op-devstack/sysgo" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" "github.com/ethereum/go-ethereum" @@ -55,6 +56,17 @@ import ( // - With ELP2P enabled, repeated FCU attempts eventually validate and advance the canonical chain. func TestL2ELP2PCanonicalChainAdvancedByFCU(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with op-reth: + // + // assertions.go:387: ERROR[03-31|09:58:15.522] + // assertions.go:387: Error Trace: /optimism/op-devstack/dsl/l2_el.go:64 + // assertions.go:387: /optimism/op-acceptance-tests/tests/sync/elsync/gap_elp2p/sync_test.go:111 + // assertions.go:387: Error: Received unexpected error: + // assertions.go:387: failed to determine block-hash of hash 0x8b94830f261ef4568bc2ba248f52b27f9a7c366e8157794c93bdd05ca4735564, could not get payload: not found + // assertions.go:387: Test: TestL2ELP2PCanonicalChainAdvancedByFCU + // assertions.go:387: Messages: block not found using block hash + // assertions.go:387: + sysgo.SkipOnOpReth(t, "not supported") sys := newGapELP2PSystem(t) require := t.Require() logger := t.Logger() @@ -393,6 +405,14 @@ func TestSafeDoesNotAdvanceWhenUnsafeIsSyncing_NoELP2P(gt *testing.T) { // invalid payloads—whether rejected at the CL or EL—do not advance the chain. func TestInvalidPayloadThroughCLP2P(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-31|10:42:03.034] + // assertions.go:387: Error Trace: /Users/josh/repos/optimism/op-acceptance-tests/tests/sync/elsync/gap_elp2p/sync_test.go:436 + // assertions.go:387: Error: An error is expected but got nil. + // assertions.go:387: Test: TestInvalidPayloadThroughCLP2P + // assertions.go:387: + sysgo.SkipOnKonaNode(t, "not supported") sys := newGapELP2PSystem(t) logger := t.Logger() require := t.Require() diff --git a/op-acceptance-tests/tests/sync/elsync/reorg/sync_test.go b/op-acceptance-tests/tests/sync/elsync/reorg/sync_test.go index 01935ea8057..91438bdab0e 100644 --- a/op-acceptance-tests/tests/sync/elsync/reorg/sync_test.go +++ b/op-acceptance-tests/tests/sync/elsync/reorg/sync_test.go @@ -5,6 +5,7 @@ import ( "time" "github.com/ethereum-optimism/optimism/op-devstack/devtest" + "github.com/ethereum-optimism/optimism/op-devstack/sysgo" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" "github.com/ethereum-optimism/optimism/op-test-sequencer/sequencer/seqtypes" @@ -18,6 +19,15 @@ import ( // 4. CLP2P is restored, the verifier backfills and the unsafe gap is closed. func TestUnsafeGapFillAfterSafeReorg(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-30|22:17:00.549] + // assertions.go:387: Error Trace: /op-devstack/dsl/l2_el.go:204 + // assertions.go:387: /op-acceptance-tests/tests/sync/elsync/reorg/sync_test.go:78 + // assertions.go:387: Error: Received unexpected error: + // assertions.go:387: operation failed permanently after 30 attempts: expected head to reorg 0xae5a516a6654d4ee6a2edfb9a8e2db12106991b1a29fbb3953dd5afb8a60914e:12, but got 0xae5a516a6654d4ee6a2edfb9a8e2db12106991b1a29fbb3953dd5afb8a60914e:12 + // assertions.go:387: Test: TestUnsafeGapFillAfterSafeReorg + sysgo.SkipOnKonaNode(t, "not supported (timeout)") sys := newReorgSystem(t) require := t.Require() logger := t.Logger() @@ -71,74 +81,21 @@ func TestUnsafeGapFillAfterSafeReorg(gt *testing.T) { logger.Info("Triggered L1 reorg", "l1", l1BlockAfterReorg) require.NotEqual(l1BlockAfterReorg.Hash, l1BlockBeforeReorg.Hash) - // Need to poll until the L2CL detects L1 Reorg and trigger L2 Reorg - // What happens: - // L2CL detects L1 Reorg and reset the pipeline. op-node example logs: "reset: detected L1 reorg" - // L2EL detects L2 Reorg and reorgs. op-geth example logs: "Chain reorg detected" - sys.L2EL.ReorgTriggered(l2BlockBeforeReorg, 30) - l2BlockAfterReorg := sys.L2EL.BlockRefByNumber(l2BlockBeforeReorg.Number) - require.NotEqual(l2BlockAfterReorg.Hash, l2BlockBeforeReorg.Hash) - logger.Info("Triggered L2 reorg", "l2", l2BlockAfterReorg) - // Batcher re-submits batch using updated L1 view - sys.L2EL.Reached(eth.Safe, l2BlockAfterReorg.Number, 30) - require.GreaterOrEqual(sys.L1EL.BlockRefByNumber(l2BlockAfterReorg.L1Origin.Number).Number, l1BlockAfterReorg.Number) - - // Check the divergence before restarting verifier L2CLB - verUnsafe := sys.L2ELB.BlockRefByLabel(eth.Unsafe) - seqUnsafe := sys.L2EL.BlockRefByLabel(eth.Unsafe) - logger.Info("Unsafe heads", "seq", seqUnsafe, "ver", verUnsafe) - // Verifier unsafe head cannot advance yet because L2CLB is down - require.Greater(seqUnsafe.Number, verUnsafe.Number) - // Verifier unsafe head diverged - canonicalFromSeq := sys.L2EL.BlockRefByNumber(verUnsafe.Number) - require.NotEqual(canonicalFromSeq.Hash, verUnsafe.Hash) - logger.Info("Verifer unsafe head diverged", "verUnsafe", verUnsafe, "canonical", canonicalFromSeq) - var rewindTo eth.L2BlockRef - for i := verUnsafe.Number; i > 0; i-- { - ver := sys.L2ELB.BlockRefByNumber(i) - seq := sys.L2EL.BlockRefByNumber(i) - if ver.Hash == seq.Hash { - rewindTo = ver - break - } - } - logger.Info("Verifier diverged", "rewindTo", rewindTo) - require.Greater(l1BlockAfterReorg.Number, rewindTo.L1Origin.Number) + // Wait for the sequencer's safe L2 head to reference the new L1 chain. + // After the L1 reorg, the L2CL detects it, resets its pipeline, and the batcher + // re-submits batches with the new L1 view. We verify this by polling until the + // safe head's L1 origin hash matches the post-reorg L1 block — proving L2 + // actually switched to the new L1 fork, not just that block numbers advanced. + sys.L2EL.WaitL1OriginHash(eth.Safe, l1BlockAfterReorg.ID(), 30) - // Restart verifier L2CL. CLP2P disabled + // Restart verifier CL and verify it applies the reorg sys.L2CLB.Start() - - // Safe block reorged. Verifier L2CL will read the new L1 and reorg the safe chain - // Unsafe head will also be updated because safe chain reorged - sys.L2ELB.ReorgTriggered(l2BlockBeforeReorg, 10) - logger.Info("Triggered L2 safe reorg at verifier", "l2", l2BlockAfterReorg) - sys.L2ELB.Matched(sys.L2EL, eth.Safe, 5) - // L2CLB has no P2P connection, so unsafe gap always exists - seqUnsafe = sys.L2EL.BlockRefByLabel(eth.Unsafe) - verUnsafe = sys.L2ELB.BlockRefByLabel(eth.Unsafe) - logger.Info("Verifier unsafe gap", "gap", seqUnsafe.Number-verUnsafe.Number, "seqUnsafe", seqUnsafe.Number, "verUnsafe", verUnsafe.Number) - - // Reenable CLP2P - // L2CLB will receive unsafe payloads from sequencer - // Unsafe gap will be observed by the L2CLB, and it will be smart enough to close the gap, - // using RR Sync(soon be deprecated), or rely on EL Sync(desired) + // Reconnect CLP2P so verifier can backfill the unsafe gap sys.L2CLB.ConnectPeer(sys.L2CL) sys.L2CL.ConnectPeer(sys.L2CLB) - - // Unsafe gap is closed sys.L2ELB.Matched(sys.L2EL, types.LocalUnsafe, 50) - - seqUnsafe = sys.L2EL.BlockRefByLabel(eth.Unsafe) - verUnsafe = sys.L2ELB.BlockRefByLabel(eth.Unsafe) - logger.Info("Verifier unsafe gap closed", "gap", seqUnsafe.Number-verUnsafe.Number, "seqUnsafe", seqUnsafe.Number, "verUnsafe", verUnsafe.Number) - - gt.Cleanup(func() { - sys.L2CLB.Start() - sys.L2CLB.ConnectPeer(sys.L2CL) - sys.L2CL.ConnectPeer(sys.L2CLB) - }) } // TestUnsafeGapFillAfterUnsafeReorg_RestartL2CL demonstrates the flow where: @@ -148,6 +105,24 @@ func TestUnsafeGapFillAfterSafeReorg(gt *testing.T) { // 4. Verifier then backfills and closes the unsafe gap once reconnected via CLP2P. func TestUnsafeGapFillAfterUnsafeReorg_RestartL2CL(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-30|22:17:07.231] + // assertions.go:387: Error Trace: /optimism/op-devstack/dsl/l2_el.go:204 + // assertions.go:387: /optimism/op-acceptance-tests/tests/sync/elsync/reorg/sync_test.go:211 + // assertions.go:387: Error: Received unexpected error: + // assertions.go:387: operation failed permanently after 30 attempts: expected head to reorg 0x893d77533b0ff9b37a92090679bf256d987b4535f06186ec71f29e68ddccd9a5:14, but got 0x893d77533b0ff9b37a92090679bf256d987b4535f06186ec71f29e68ddccd9a5:14 + // assertions.go:387: Test: TestUnsafeGapFillAfterUnsafeReorg_RestartL2CL + sysgo.SkipOnKonaNode(t, "not supported (timeout)") + // Example error with op-reth: + // + // assertions.go:387: + // Error Trace: /op-devstack/dsl/l2_el.go:430 + // /op-acceptance-tests/tests/sync/elsync/reorg/sync_test.go:218 + // Error: Received unexpected error: + // operation failed permanently after 50 attempts: expected head to match: unsafe + // Test: TestUnsafeGapFillAfterUnsafeReorg_RestartL2CL + sysgo.FlakyOnOpReth(t, "") sys := newReorgSystem(t) require := t.Require() logger := t.Logger() @@ -270,6 +245,15 @@ func TestUnsafeGapFillAfterUnsafeReorg_RestartL2CL(gt *testing.T) { // 4. CLP2P is restored Verifier, the verifier backfills and the unsafe gap is closed. func TestUnsafeGapFillAfterUnsafeReorg_RestartCLP2P(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-31|11:15:39.398] + // assertions.go:387: Error Trace: /optimism/op-devstack/dsl/l2_el.go:204 + // assertions.go:387: /optimism/op-acceptance-tests/tests/sync/elsync/reorg/sync_test.go:356 + // assertions.go:387: Error: Received unexpected error: + // assertions.go:387: operation failed permanently after 30 attempts: expected head to reorg 0x166970054ad16ad090210e5d1045538eeccd2afd88ea991b010de026d0106870:18, but got 0x166970054ad16ad090210e5d1045538eeccd2afd88ea991b010de026d0106870:18 + // assertions.go:387: Test: TestUnsafeGapFillAfterUnsafeReorg_RestartCLP2P + sysgo.SkipOnKonaNode(t, "not supported (timeout)") sys := newReorgSystem(t) require := t.Require() logger := t.Logger() diff --git a/op-acceptance-tests/tests/sync/follow_l2/sync_test.go b/op-acceptance-tests/tests/sync/follow_l2/sync_test.go index f3e33c476d9..42ca10f62ca 100644 --- a/op-acceptance-tests/tests/sync/follow_l2/sync_test.go +++ b/op-acceptance-tests/tests/sync/follow_l2/sync_test.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" + "github.com/ethereum-optimism/optimism/op-devstack/sysgo" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" "github.com/ethereum-optimism/optimism/op-test-sequencer/sequencer/seqtypes" @@ -14,6 +15,19 @@ import ( func TestFollowL2_Safe_Finalized_CurrentL1(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-31|11:33:11.255] + // assertions.go:387: Error Trace: /optimism/op-devstack/sysgo/singlechain_variants.go:143 + // assertions.go:387: /optimism/op-devstack/sysgo/singlechain_variants.go:53 + // assertions.go:387: /optimism/op-devstack/presets/singlechain_twoverifiers.go:24 + // assertions.go:387: /optimism/op-acceptance-tests/tests/sync/follow_l2/setup_test.go:24 + // assertions.go:387: /optimism/op-acceptance-tests/tests/sync/follow_l2/sync_test.go:18 + // assertions.go:387: Error: Should be true + // assertions.go:387: Test: TestFollowL2_Safe_Finalized_CurrentL1 + // assertions.go:387: Messages: single-chain test sequencer requires an op-node CL node + sysgo.SkipOnKonaNode(t, "not supported") + sysgo.FlakyOnOpReth(t, "timeouts in merge queue but not locally") sys := newSingleChainTwoVerifiersFollowL2(t) logger := t.Logger() @@ -56,6 +70,18 @@ func TestFollowL2_Safe_Finalized_CurrentL1(gt *testing.T) { func TestFollowL2_ReorgRecovery(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-31|11:31:11.567] + // assertions.go:387: Error Trace: /optimism/op-devstack/sysgo/singlechain_variants.go:143 + // assertions.go:387: /optimism/op-devstack/sysgo/singlechain_variants.go:53 + // assertions.go:387: /optimism/op-devstack/presets/singlechain_twoverifiers.go:24 + // assertions.go:387: /optimism/op-acceptance-tests/tests/sync/follow_l2/setup_test.go:24 + // assertions.go:387: /optimism/op-acceptance-tests/tests/sync/follow_l2/sync_test.go:60 + // assertions.go:387: Error: Should be true + // assertions.go:387: Test: TestFollowL2_ReorgRecovery + // assertions.go:387: Messages: single-chain test sequencer requires an op-node CL node + sysgo.SkipOnKonaNode(t, "not supported") sys := newSingleChainTwoVerifiersFollowL2(t) require := t.Require() logger := t.Logger() @@ -133,6 +159,18 @@ func TestFollowL2_ReorgRecovery(gt *testing.T) { func TestFollowL2_WithoutCLP2P(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with kona-node: + // + // assertions.go:387: ERROR[03-31|11:27:57.797] + // assertions.go:387: Error Trace: /optimism/op-devstack/sysgo/singlechain_variants.go:143 + // assertions.go:387: /optimism/op-devstack/sysgo/singlechain_variants.go:53 + // assertions.go:387: /optimism/op-devstack/presets/singlechain_twoverifiers.go:24 + // assertions.go:387: /optimism/op-acceptance-tests/tests/sync/follow_l2/setup_test.go:24 + // assertions.go:387: /optimism/op-acceptance-tests/tests/sync/follow_l2/sync_test.go:136 + // assertions.go:387: Error: Should be true + // assertions.go:387: Test: TestFollowL2_WithoutCLP2P + // assertions.go:387: Messages: single-chain test sequencer requires an op-node CL nod + sysgo.SkipOnKonaNode(t, "not supported") sys := newSingleChainTwoVerifiersFollowL2(t) require := t.Require() logger := t.Logger() diff --git a/op-acceptance-tests/tests/sync/manual/sync_test.go b/op-acceptance-tests/tests/sync/manual/sync_test.go index 7b0bfdb9bf3..05c55ff73e9 100644 --- a/op-acceptance-tests/tests/sync/manual/sync_test.go +++ b/op-acceptance-tests/tests/sync/manual/sync_test.go @@ -14,6 +14,16 @@ import ( func TestVerifierManualSync(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error using op-reth: + // + // assertions.go:387: ERROR[03-31|10:02:09.740] + // assertions.go:387: Error Trace: /optimism/op-devstack/dsl/l2_el.go:64 + // assertions.go:387: /optimism/op-acceptance-tests/tests/sync/manual/sync_test.go:53 + // assertions.go:387: Error: Received unexpected error: + // assertions.go:387: failed to determine block-hash of hash 0x2f6324eaff3942802eff5ddd47872544aa02182c222bf90042d5f715dfa72308, could not get payload: not found + // assertions.go:387: Test: TestVerifierManualSync + // assertions.go:387: Messages: block not found using block hash + sysgo.SkipOnOpReth(t, "not supported") // Disable ELP2P and Batcher sys := presets.NewSingleChainMultiNodeWithoutP2PWithoutCheck(t, diff --git a/op-acceptance-tests/tests/sync_tester/sync_tester_elsync_multi/sync_test.go b/op-acceptance-tests/tests/sync_tester/sync_tester_elsync_multi/sync_test.go index 8e9127f7467..bdf53ec3d4f 100644 --- a/op-acceptance-tests/tests/sync_tester/sync_tester_elsync_multi/sync_test.go +++ b/op-acceptance-tests/tests/sync_tester/sync_tester_elsync_multi/sync_test.go @@ -29,6 +29,7 @@ func simpleWithSyncTesterOpts() []presets.Option { func TestMultiELSync(gt *testing.T) { t := devtest.ParallelT(gt) + sysgo.FlakyOnKonaNode(t, "fails in ci but passes locally") sys := presets.NewSimpleWithSyncTester(t, simpleWithSyncTesterOpts()...) require := t.Require() diff --git a/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/sync_tester_hfs_test.go b/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/sync_tester_hfs_test.go index 2264100c46c..547e9a557ab 100644 --- a/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/sync_tester_hfs_test.go +++ b/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/sync_tester_hfs_test.go @@ -35,6 +35,15 @@ func simpleWithSyncTesterOpts() []presets.Option { func TestSyncTesterHardforks(gt *testing.T) { t := devtest.ParallelT(gt) + // Example error with op-reth: + // + // assertions.go:387: ERROR[03-31|10:08:04.055] + // assertions.go:387: Error Trace: /optimism/op-devstack/dsl/check.go:26 + // assertions.go:387: /optimism/op-acceptance-tests/tests/sync_tester/sync_tester_hfs/sync_tester_hfs_test.go:54 + // assertions.go:387: Error: Received unexpected error: + // assertions.go:387: operation failed permanently after 42 attempts: expected head to advance: unsafe + // assertions.go:387: Test: TestSyncTesterHardforks + sysgo.SkipOnOpReth(t, "not supported") sys := presets.NewSimpleWithSyncTester(t, simpleWithSyncTesterOpts()...) require := t.Require() diff --git a/op-chain-ops/README.md b/op-chain-ops/README.md index f39b2cc5b6b..1b9d21d28a2 100644 --- a/op-chain-ops/README.md +++ b/op-chain-ops/README.md @@ -30,7 +30,6 @@ Utils: cmd/ ├── check-canyon - Checks for Canyon network upgrade ├── check-delta - Checks for Delta network upgrade -├── check-deploy-config - Checks of the (legacy) Deploy Config ├── check-derivation - Check that transactions can be confirmed and safety can be consolidated ├── check-ecotone - Checks for Ecotone network upgrade ├── check-fjord - Checks for Fjord network upgrade diff --git a/op-chain-ops/addresses/contracts.go b/op-chain-ops/addresses/contracts.go index 7efecff81c4..9d6c29b2947 100644 --- a/op-chain-ops/addresses/contracts.go +++ b/op-chain-ops/addresses/contracts.go @@ -27,8 +27,6 @@ type SuperchainContracts struct { // - these contracts are shared by all OpChains that are members of the same superchain // - these contracts are not upgradable, but can be replaced by new contract releases/deployments type ImplementationsContracts struct { - OpcmImpl common.Address - OpcmContractsContainerImpl common.Address OpcmGameTypeAdderImpl common.Address OpcmDeployerImpl common.Address OpcmUpgraderImpl common.Address @@ -40,7 +38,6 @@ type ImplementationsContracts struct { OpcmContainerImpl common.Address DelayedWethImpl common.Address OptimismPortalImpl common.Address - OptimismPortalInteropImpl common.Address EthLockboxImpl common.Address PreimageOracleImpl common.Address MipsImpl common.Address diff --git a/op-chain-ops/cmd/check-deploy-config/main.go b/op-chain-ops/cmd/check-deploy-config/main.go deleted file mode 100644 index 5092bbc25ad..00000000000 --- a/op-chain-ops/cmd/check-deploy-config/main.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "os" - "path/filepath" - "strings" - - "github.com/mattn/go-isatty" - "github.com/urfave/cli/v2" - - "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" - oplog "github.com/ethereum-optimism/optimism/op-service/log" - "github.com/ethereum/go-ethereum/log" -) - -func main() { - color := isatty.IsTerminal(os.Stderr.Fd()) - oplog.SetGlobalLogHandler(log.NewTerminalHandler(os.Stderr, color)) - - app := &cli.App{ - Name: "check-deploy-config", - Usage: "Check that a deploy config is valid", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "path", - Required: true, - Usage: "File system path to the deploy config", - }, - }, - Action: entrypoint, - } - - if err := app.Run(os.Args); err != nil { - log.Crit("error checking deploy config", "err", err) - } -} - -func entrypoint(ctx *cli.Context) error { - path := ctx.String("path") - - name := strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)) - log.Info("Checking deploy config", "name", name, "path", path) - - config, err := genesis.NewDeployConfig(path) - if err != nil { - return err - } - - cfg := oplog.DefaultCLIConfig() - logger := oplog.NewLogger(ctx.App.Writer, cfg) - - // Check the config, no need to call `CheckAddresses()` - if err := config.Check(logger); err != nil { - return err - } - - log.Info("Valid deploy config") - return nil -} diff --git a/op-chain-ops/cmd/op-run-block/main.go b/op-chain-ops/cmd/op-run-block/main.go index e5bbee03061..a8ae29c8969 100644 --- a/op-chain-ops/cmd/op-run-block/main.go +++ b/op-chain-ops/cmd/op-run-block/main.go @@ -155,11 +155,11 @@ func mainAction(c *cli.Context) error { Overrides: nil, }, outW) - witness, err := stateless.NewWitness(header, chCtx) + witness, err := stateless.NewWitness(header, chCtx, false) if err != nil { return fmt.Errorf("failed to prepare witness data collector: %w", err) } - state.StartPrefetcher("debug", witness, nil) + state.StartPrefetcher("debug", witness) defer func() { // Even if the EVM fails, try to export witness data for the state-transition up to the error. witnessDump := witness.ToExecutionWitness() out, err := json.MarshalIndent(witnessDump, "", " ") @@ -305,13 +305,12 @@ func Process(logger log.Logger, config *params.ChainConfig, chainCtx *remoteChainCtx, outW io.Writer) (*core.ProcessResult, error) { var ( receipts types.Receipts - usedGas = new(uint64) header = block.CreateGethHeader() blockHash = block.Hash blockNumber = new(big.Int).SetUint64(uint64(block.Number)) blockTime = uint64(block.Time) allLogs []*types.Log - gp = new(core.GasPool).AddGas(uint64(block.GasLimit)) + gp = core.NewGasPool(uint64(block.GasLimit)) ) // Mutate the block and state according to any hard-fork specs @@ -344,7 +343,7 @@ func Process(logger log.Logger, config *params.ChainConfig, } statedb.SetTxContext(tx.Hash(), i) - receipt, err := core.ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, blockTime, tx, usedGas, vmenv) + receipt, err := core.ApplyTransactionWithEVM(msg, gp, statedb, blockNumber, blockHash, blockTime, tx, vmenv) if err != nil { return nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -366,6 +365,6 @@ func Process(logger log.Logger, config *params.ChainConfig, Receipts: receipts, Requests: nil, Logs: allLogs, - GasUsed: *usedGas, + GasUsed: gp.Used(), }, nil } diff --git a/op-chain-ops/cmd/op-simulate/main.go b/op-chain-ops/cmd/op-simulate/main.go index 714cdd1a903..bf07506037a 100644 --- a/op-chain-ops/cmd/op-simulate/main.go +++ b/op-chain-ops/cmd/op-simulate/main.go @@ -312,8 +312,7 @@ func simulate(ctx context.Context, logger log.Logger, conf *params.ChainConfig, state.SetTxContext(tx.Hash(), 0) cCtx := &simChainContext{eng: beacon.New(ethash.NewFaker()), head: header, cfg: conf} - gp := core.GasPool(tx.Gas()) - usedGas := uint64(0) + gp := core.NewGasPool(tx.Gas()) vmConfig := vm.Config{} if doProfile { @@ -326,7 +325,7 @@ func simulate(ctx context.Context, logger log.Logger, conf *params.ChainConfig, // nil block-author, since it defaults to header.coinbase blockCtx := core.NewEVMBlockContext(header, cCtx, nil, conf, state) evm := vm.NewEVM(blockCtx, state, conf, vmConfig) - receipt, err := core.ApplyTransaction(evm, &gp, state, header, tx, &usedGas) + receipt, err := core.ApplyTransaction(evm, gp, state, header, tx) if err != nil { return fmt.Errorf("failed to apply tx: %w", err) } diff --git a/op-chain-ops/genesis/config.go b/op-chain-ops/genesis/config.go index 89e1ca9399b..b06c3c68496 100644 --- a/op-chain-ops/genesis/config.go +++ b/op-chain-ops/genesis/config.go @@ -1241,7 +1241,6 @@ type L1Deployments struct { OptimismMintableERC20Factory common.Address `json:"OptimismMintableERC20Factory"` OptimismMintableERC20FactoryProxy common.Address `json:"OptimismMintableERC20FactoryProxy"` OptimismPortal common.Address `json:"OptimismPortal"` - OptimismPortalInterop common.Address `json:"OptimismPortalInterop"` OptimismPortalProxy common.Address `json:"OptimismPortalProxy"` ETHLockbox common.Address `json:"ETHLockbox"` ETHLockboxProxy common.Address `json:"ETHLockboxProxy"` @@ -1269,7 +1268,6 @@ func CreateL1DeploymentsFromContracts(contracts *addresses.L1Contracts) *L1Deplo OptimismMintableERC20Factory: contracts.OptimismMintableErc20FactoryImpl, OptimismMintableERC20FactoryProxy: contracts.OptimismMintableErc20FactoryProxy, OptimismPortal: contracts.OptimismPortalImpl, - OptimismPortalInterop: contracts.OptimismPortalInteropImpl, OptimismPortalProxy: contracts.OptimismPortalProxy, ETHLockbox: contracts.EthLockboxImpl, ETHLockboxProxy: contracts.EthLockboxProxy, diff --git a/op-chain-ops/interopgen/configs.go b/op-chain-ops/interopgen/configs.go index 5182a41fb14..d2942143e01 100644 --- a/op-chain-ops/interopgen/configs.go +++ b/op-chain-ops/interopgen/configs.go @@ -71,15 +71,16 @@ type L2Config struct { Challenger common.Address SystemConfigOwner common.Address genesis.L2InitializationConfig - Prefund map[common.Address]*big.Int - SaltMixer string - GasLimit uint64 - DisputeGameType uint32 - DisputeAbsolutePrestate common.Hash - DisputeMaxGameDepth uint64 - DisputeSplitDepth uint64 - DisputeClockExtension uint64 - DisputeMaxClockDuration uint64 + Prefund map[common.Address]*big.Int + SaltMixer string + GasLimit uint64 + DisputeGameType uint32 + DisputeAbsolutePrestate common.Hash + DisputeKonaAbsolutePrestate common.Hash + DisputeMaxGameDepth uint64 + DisputeSplitDepth uint64 + DisputeClockExtension uint64 + DisputeMaxClockDuration uint64 } func (c *L2Config) Check(log log.Logger) error { diff --git a/op-chain-ops/interopgen/deploy.go b/op-chain-ops/interopgen/deploy.go index e4340d6eeda..f1e99ba56af 100644 --- a/op-chain-ops/interopgen/deploy.go +++ b/op-chain-ops/interopgen/deploy.go @@ -243,7 +243,7 @@ func DeployL2ToL1(l1Host *script.Host, superCfg *SuperchainConfig, superDeployme BasefeeScalar: cfg.GasPriceOracleBaseFeeScalar, BlobBaseFeeScalar: cfg.GasPriceOracleBlobBaseFeeScalar, L2ChainId: new(big.Int).SetUint64(cfg.L2ChainID), - Opcm: superDeployment.Opcm, + Opcm: superDeployment.OpcmV2, SaltMixer: cfg.SaltMixer, GasLimit: cfg.GasLimit, DisputeGameType: cfg.DisputeGameType, @@ -273,38 +273,57 @@ func MigrateInterop( ) (*InteropDeployment, error) { l2ChainIDs := maps.Keys(l2Deployments) sort.Strings(l2ChainIDs) - chainConfigs := make([]manage.OPChainConfig, len(l2Deployments)) + + // We don't have a super root at genesis. But stub the starting anchor root anyways to facilitate super DG testing. + startingAnchorRoot := common.Hash(opcm.PermissionedGameStartingAnchorRoot) + + // Build chain system config addresses for V2 migrate input. + chainSystemConfigs := make([]common.Address, len(l2Deployments)) for i, l2ChainID := range l2ChainIDs { - l2Deployment := l2Deployments[l2ChainID] - chainConfigs[i] = manage.OPChainConfig{ - SystemConfigProxy: l2Deployment.SystemConfigProxy, - CannonPrestate: l2Cfgs[l2ChainID].DisputeAbsolutePrestate, - } + chainSystemConfigs[i] = l2Deployments[l2ChainID].SystemConfigProxy } - // For now get the fault game parameters from the first chain + // ABI-encode the cannon prestates as game args (from the first chain config). l2ChainID := l2ChainIDs[0] - // We don't have a super root at genesis. But stub the starting anchor root anyways to facilitate super DG testing. - startingAnchorRoot := common.Hash(opcm.PermissionedGameStartingAnchorRoot) + cannonGameArgs := common.LeftPadBytes(l2Cfgs[l2ChainID].DisputeAbsolutePrestate.Bytes(), 32) + cannonKonaGameArgs := common.LeftPadBytes(l2Cfgs[l2ChainID].DisputeKonaAbsolutePrestate.Bytes(), 32) + + const ( + GameTypeCannon = uint32(0) + GameTypeSuperCannon = uint32(4) + GameTypeSuperCannonKona = uint32(9) + ) + imi := manage.InteropMigrationInput{ Prank: superCfg.ProxyAdminOwner, - Opcm: superDeployment.Opcm, - MigrateInputV1: &manage.MigrateInputV1{ - UsePermissionlessGame: true, + Opcm: superDeployment.OpcmV2, + MigrateInputV2: &manage.MigrateInputV2{ + ChainSystemConfigs: chainSystemConfigs, + DisputeGameConfigs: []manage.DisputeGameConfig{ + { + Enabled: true, + InitBond: big.NewInt(0), + GameType: GameTypeCannon, + GameArgs: cannonGameArgs, + }, + { + Enabled: true, + InitBond: big.NewInt(0), + GameType: GameTypeSuperCannon, + GameArgs: cannonGameArgs, + }, + { + Enabled: true, + InitBond: big.NewInt(0), + GameType: GameTypeSuperCannonKona, + GameArgs: cannonKonaGameArgs, + }, + }, StartingAnchorRoot: manage.Proposal{ Root: startingAnchorRoot, L2SequenceNumber: big.NewInt(int64(l1GenesisTimestamp)), }, - GameParameters: manage.GameParameters{ - Proposer: l2Cfgs[l2ChainID].Proposer, - Challenger: l2Cfgs[l2ChainID].Challenger, - MaxGameDepth: l2Cfgs[l2ChainID].DisputeMaxGameDepth, - SplitDepth: l2Cfgs[l2ChainID].DisputeSplitDepth, - InitBond: big.NewInt(0), - ClockExtension: l2Cfgs[l2ChainID].DisputeClockExtension, - MaxClockDuration: l2Cfgs[l2ChainID].DisputeMaxClockDuration, - }, - OpChainConfigs: chainConfigs, + StartingRespectedGameType: GameTypeSuperCannon, }, } output, err := manage.Migrate(l1Host, imi) diff --git a/op-chain-ops/interopgen/deployments.go b/op-chain-ops/interopgen/deployments.go index 0cfa0254082..4ea1c35b27a 100644 --- a/op-chain-ops/interopgen/deployments.go +++ b/op-chain-ops/interopgen/deployments.go @@ -23,7 +23,6 @@ type Implementations struct { OpcmContainer common.Address `json:"OPCMContainer"` DelayedWETHImpl common.Address `json:"DelayedWETHImpl"` OptimismPortalImpl common.Address `json:"OptimismPortalImpl"` - OptimismPortalInteropImpl common.Address `json:"OptimismPortalInteropImpl"` ETHLockboxImpl common.Address `json:"ETHLockboxImpl"` PreimageOracleSingleton common.Address `json:"PreimageOracleSingleton"` MipsSingleton common.Address `json:"MipsSingleton"` diff --git a/op-chain-ops/interopgen/recipe.go b/op-chain-ops/interopgen/recipe.go index 1cbb651a645..51884a4ed9a 100644 --- a/op-chain-ops/interopgen/recipe.go +++ b/op-chain-ops/interopgen/recipe.go @@ -298,15 +298,16 @@ func (r *InteropDevL2Recipe) build(l1ChainID uint64, addrs devkeys.Addresses) (* ChainFeesRecipient: common.Address{}, }, }, - Prefund: make(map[common.Address]*big.Int), - SaltMixer: "", - GasLimit: 60_000_000, - DisputeGameType: 1, // PERMISSIONED_CANNON Game Type - DisputeAbsolutePrestate: common.HexToHash("0x038512e02c4c3f7bdaec27d00edf55b7155e0905301e1a88083e4e0a6764d54c"), - DisputeMaxGameDepth: 73, - DisputeSplitDepth: 30, - DisputeClockExtension: 10800, // 3 hours (input in seconds) - DisputeMaxClockDuration: 302400, // 3.5 days (input in seconds) + Prefund: make(map[common.Address]*big.Int), + SaltMixer: "", + GasLimit: 60_000_000, + DisputeGameType: 1, // PERMISSIONED_CANNON Game Type + DisputeAbsolutePrestate: common.HexToHash("0x038512e02c4c3f7bdaec27d00edf55b7155e0905301e1a88083e4e0a6764d54c"), + DisputeKonaAbsolutePrestate: common.HexToHash("0x035ef680a6fa34c50d8d8169075b5d133ecd7b38fe2b2a83cc76fc81ae5d7c52"), + DisputeMaxGameDepth: 73, + DisputeSplitDepth: 30, + DisputeClockExtension: 10800, // 3 hours (input in seconds) + DisputeMaxClockDuration: 302400, // 3.5 days (input in seconds) } l2Users := devkeys.ChainUserKeys(new(big.Int).SetUint64(r.ChainID)) diff --git a/op-chain-ops/script/forking/db.go b/op-chain-ops/script/forking/db.go index 5efe8fddb8c..c9ba2aa6aa8 100644 --- a/op-chain-ops/script/forking/db.go +++ b/op-chain-ops/script/forking/db.go @@ -39,6 +39,10 @@ func (f *ForkDB) Snapshot() *snapshot.Tree { return nil } +func (f *ForkDB) Commit(*state.StateUpdate) error { + panic("unimplemented") +} + var _ state.Database = (*ForkDB)(nil) func NewForkDB(source ForkSource) *ForkDB { diff --git a/op-chain-ops/script/forking/reader.go b/op-chain-ops/script/forking/reader.go index 06340ae0fae..86c91adbdbf 100644 --- a/op-chain-ops/script/forking/reader.go +++ b/op-chain-ops/script/forking/reader.go @@ -1,6 +1,8 @@ package forking import ( + "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -36,12 +38,20 @@ func (f *forkStateReader) Storage(addr common.Address, slot common.Hash) (common return common.Hash(v), nil } -func (f *forkStateReader) Code(addr common.Address, codeHash common.Hash) ([]byte, error) { - return f.trie.ContractCode(addr, codeHash) +func (f *forkStateReader) Code(addr common.Address, codeHash common.Hash) []byte { + result, err := f.trie.ContractCode(addr, codeHash) + if err != nil { + panic(fmt.Errorf("get contract code for address %q and codeHash %q: %w", addr, codeHash, err)) + } + return result } -func (f *forkStateReader) CodeSize(addr common.Address, codeHash common.Hash) (int, error) { - return f.trie.ContractCodeSize(addr, codeHash) +func (f *forkStateReader) CodeSize(addr common.Address, codeHash common.Hash) int { + result, err := f.trie.ContractCodeSize(addr, codeHash) + if err != nil { + panic(fmt.Errorf("get contract code size for address %q and codeHash %q: %w", addr, codeHash, err)) + } + return result } func (f *forkStateReader) Copy() state.Reader { diff --git a/op-chain-ops/script/forking/state.go b/op-chain-ops/script/forking/state.go index 80ef0ffa8b1..284f8a8b113 100644 --- a/op-chain-ops/script/forking/state.go +++ b/op-chain-ops/script/forking/state.go @@ -44,6 +44,10 @@ type ForkableState struct { var _ VMStateDB = (*ForkableState)(nil) +func (fst *ForkableState) EmitLogsForBurnAccounts() { + panic("unimplemented") +} + func NewForkableState(base VMStateDB) *ForkableState { return &ForkableState{ selected: base, diff --git a/op-challenger/game/fault/trace/cannon/provider.go b/op-challenger/game/fault/trace/cannon/provider.go index e2f636a5dd3..2204bd94680 100644 --- a/op-challenger/game/fault/trace/cannon/provider.go +++ b/op-challenger/game/fault/trace/cannon/provider.go @@ -14,7 +14,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum-optimism/optimism/op-challenger/config" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/vm" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" @@ -163,18 +162,18 @@ type CannonTraceProviderForTest struct { *CannonTraceProvider } -func NewTraceProviderForTest(logger log.Logger, m vm.Metricer, cfg *config.Config, localInputs utils.LocalGameInputs, dir string, gameDepth types.Depth) *CannonTraceProviderForTest { +func NewTraceProviderForTest(logger log.Logger, m vm.Metricer, vmCfg vm.Config, serverExecutor vm.OracleServerExecutor, prestate string, localInputs utils.LocalGameInputs, dir string, gameDepth types.Depth) *CannonTraceProviderForTest { p := &CannonTraceProvider{ logger: logger, dir: dir, - prestate: cfg.CannonAbsolutePreState, - generator: vm.NewExecutor(logger, m, cfg.Cannon, vm.NewOpProgramServerExecutor(logger), cfg.CannonAbsolutePreState, localInputs), + prestate: prestate, + generator: vm.NewExecutor(logger, m, vmCfg, serverExecutor, prestate, localInputs), gameDepth: gameDepth, preimageLoader: utils.NewPreimageLoader(func() (utils.PreimageSource, error) { return kvstore.NewDiskKV(logger, vm.PreimageDir(dir), kvtypes.DataFormatFile) }), - stateConverter: NewStateConverter(cfg.Cannon), - cfg: cfg.Cannon, + stateConverter: NewStateConverter(vmCfg), + cfg: vmCfg, } return &CannonTraceProviderForTest{p} } diff --git a/op-challenger/game/fault/trace/super/provider_supernode.go b/op-challenger/game/fault/trace/super/provider_supernode.go index cdea05fb9b0..41ada9f8421 100644 --- a/op-challenger/game/fault/trace/super/provider_supernode.go +++ b/op-challenger/game/fault/trace/super/provider_supernode.go @@ -129,8 +129,8 @@ func (s *SuperNodeTraceProvider) GetPreimageBytes(ctx context.Context, pos types } expectedState.PendingProgress = append(expectedState.PendingProgress, interopTypes.OptimisticBlock{ - BlockHash: optimistic.Output.BlockRef.Hash, - OutputRoot: optimistic.Output.OutputRoot, + BlockHash: optimistic.Output.BlockHash, + OutputRoot: optimistic.OutputRoot, }) } return expectedState.Marshal(), nil diff --git a/op-challenger/game/fault/trace/super/provider_supernode_test.go b/op-challenger/game/fault/trace/super/provider_supernode_test.go index db0d9664a92..191d118c472 100644 --- a/op-challenger/game/fault/trace/super/provider_supernode_test.go +++ b/op-challenger/game/fault/trace/super/provider_supernode_test.go @@ -146,13 +146,14 @@ func TestSuperNodeProvider_Get(t *testing.T) { // Make super roots be safe only after L1 head prev.Data.VerifiedRequiredL1 = eth.BlockID{Number: l1Head.Number, Hash: common.Hash{0xaa}} next.Data.VerifiedRequiredL1 = eth.BlockID{Number: l1Head.Number + 1, Hash: common.Hash{0xbb}} + unsafeOutput := ð.OutputV0{ + StateRoot: eth.Bytes32{0xdf}, + MessagePasserStorageRoot: eth.Bytes32{0xde}, + BlockHash: common.Hash{0xcd}, + } next.OptimisticAtTimestamp[eth.ChainIDFromUInt64(1)] = eth.OutputWithRequiredL1{ - Output: ð.OutputResponse{ - OutputRoot: eth.Bytes32{0xad}, - BlockRef: eth.L2BlockRef{Hash: common.Hash{0xcd}}, - WithdrawalStorageRoot: common.Hash{0xde}, - StateRoot: common.Hash{0xdf}, - }, + Output: unsafeOutput, + OutputRoot: eth.OutputRoot(unsafeOutput), RequiredL1: eth.BlockID{Number: l1Head.Number + 1, Hash: common.Hash{0xbb}}, } stubSuperNode.Add(prev) @@ -172,13 +173,14 @@ func TestSuperNodeProvider_Get(t *testing.T) { // Make super roots be safe only after L1 head prev.Data.VerifiedRequiredL1 = eth.BlockID{Number: l1Head.Number, Hash: common.Hash{0xaa}} next.Data.VerifiedRequiredL1 = eth.BlockID{Number: l1Head.Number + 1, Hash: common.Hash{0xbb}} + unsafeOutput := ð.OutputV0{ + StateRoot: eth.Bytes32{0xdf}, + MessagePasserStorageRoot: eth.Bytes32{0xde}, + BlockHash: common.Hash{0xcd}, + } next.OptimisticAtTimestamp[eth.ChainIDFromUInt64(2)] = eth.OutputWithRequiredL1{ - Output: ð.OutputResponse{ - OutputRoot: eth.Bytes32{0xad}, - BlockRef: eth.L2BlockRef{Hash: common.Hash{0xcd}}, - WithdrawalStorageRoot: common.Hash{0xde}, - StateRoot: common.Hash{0xdf}, - }, + Output: unsafeOutput, + OutputRoot: eth.OutputRoot(unsafeOutput), RequiredL1: eth.BlockID{Number: l1Head.Number + 1, Hash: common.Hash{0xbb}}, } stubSuperNode.Add(prev) @@ -422,18 +424,6 @@ func createSuperNodeProvider(t *testing.T) (*SuperNodeTraceProvider, *stubSuperN return provider, stubSuperNode, l1Head } -func toOutputResponse(output *eth.OutputV0) *eth.OutputResponse { - return ð.OutputResponse{ - Version: output.Version(), - OutputRoot: eth.OutputRoot(output), - BlockRef: eth.L2BlockRef{ - Hash: output.BlockHash, - }, - WithdrawalStorageRoot: common.Hash(output.MessagePasserStorageRoot), - StateRoot: common.Hash(output.StateRoot), - } -} - func createValidSuperNodeSuperRoots(l1Head eth.BlockID) (eth.SuperRootAtTimestampResponse, eth.SuperRootAtTimestampResponse) { rng := rand.New(rand.NewSource(1)) outputA1 := testutils.RandomOutputV0(rng) @@ -455,11 +445,13 @@ func createValidSuperNodeSuperRoots(l1Head eth.BlockID) (eth.SuperRootAtTimestam ChainIDs: []eth.ChainID{chainID1, chainID2}, OptimisticAtTimestamp: map[eth.ChainID]eth.OutputWithRequiredL1{ chainID1: { - Output: toOutputResponse(outputA1), + Output: outputA1, + OutputRoot: eth.OutputRoot(outputA1), RequiredL1: l1Head, }, chainID2: { - Output: toOutputResponse(outputB1), + Output: outputB1, + OutputRoot: eth.OutputRoot(outputB1), RequiredL1: l1Head, }, }, @@ -474,11 +466,13 @@ func createValidSuperNodeSuperRoots(l1Head eth.BlockID) (eth.SuperRootAtTimestam ChainIDs: []eth.ChainID{chainID1, chainID2}, OptimisticAtTimestamp: map[eth.ChainID]eth.OutputWithRequiredL1{ chainID1: { - Output: toOutputResponse(outputA2), + Output: outputA2, + OutputRoot: eth.OutputRoot(outputA2), RequiredL1: l1Head, }, chainID2: { - Output: toOutputResponse(outputB2), + Output: outputB2, + OutputRoot: eth.OutputRoot(outputB2), RequiredL1: l1Head, }, }, @@ -492,13 +486,15 @@ func createValidSuperNodeSuperRoots(l1Head eth.BlockID) (eth.SuperRootAtTimestam } func expectSuperNodeValidTransition(t *testing.T, provider *SuperNodeTraceProvider, prev eth.SuperRootAtTimestampResponse, next eth.SuperRootAtTimestampResponse) { + chain1 := next.OptimisticAtTimestamp[eth.ChainIDFromUInt64(1)] chain1OptimisticBlock := interopTypes.OptimisticBlock{ - BlockHash: next.OptimisticAtTimestamp[eth.ChainIDFromUInt64(1)].Output.BlockRef.Hash, - OutputRoot: next.OptimisticAtTimestamp[eth.ChainIDFromUInt64(1)].Output.OutputRoot, + BlockHash: chain1.Output.BlockHash, + OutputRoot: chain1.OutputRoot, } + chain2 := next.OptimisticAtTimestamp[eth.ChainIDFromUInt64(2)] chain2OptimisticBlock := interopTypes.OptimisticBlock{ - BlockHash: next.OptimisticAtTimestamp[eth.ChainIDFromUInt64(2)].Output.BlockRef.Hash, - OutputRoot: next.OptimisticAtTimestamp[eth.ChainIDFromUInt64(2)].Output.OutputRoot, + BlockHash: chain2.Output.BlockHash, + OutputRoot: chain2.OutputRoot, } expectedFirstStep := &interopTypes.TransitionState{ SuperRoot: prev.Data.Super.Marshal(), diff --git a/op-challenger/game/fault/trace/utils/provider.go b/op-challenger/game/fault/trace/utils/provider.go index 5e602bbc2ab..fe9a2f35fc0 100644 --- a/op-challenger/game/fault/trace/utils/provider.go +++ b/op-challenger/game/fault/trace/utils/provider.go @@ -91,7 +91,7 @@ func FirstPrecompilePreimageLoad() PreimageOpt { func PreimageLargerThan(size int) PreimageOpt { return func() preimageOpts { - return []string{"--stop-at-preimage-larger-than", strconv.Itoa(size)} + return []string{"--stop-at-preimage-type", "keccak", "--stop-at-preimage-larger-than", strconv.Itoa(size)} } } diff --git a/op-challenger/game/fault/trace/vm/kona_super_server_executor.go b/op-challenger/game/fault/trace/vm/kona_super_server_executor.go index 89db00c4b37..d15b3bc6cc3 100644 --- a/op-challenger/game/fault/trace/vm/kona_super_server_executor.go +++ b/op-challenger/game/fault/trace/vm/kona_super_server_executor.go @@ -54,6 +54,10 @@ func (s *KonaSuperExecutor) OracleCommand(cfg Config, dataDir string, inputs uti args = append(args, "--l1-config-path", cfg.L1GenesisPath) } + if cfg.DepsetConfigPath != "" { + args = append(args, "--depset-cfg", cfg.DepsetConfigPath) + } + if cfg.EnableExperimentalWitnessEndpoint { args = append(args, "--enable-experimental-witness-endpoint") } diff --git a/op-challenger/game/fault/trace/vm/kona_super_server_executor_test.go b/op-challenger/game/fault/trace/vm/kona_super_server_executor_test.go index 2264b17b5eb..93ea6327d28 100644 --- a/op-challenger/game/fault/trace/vm/kona_super_server_executor_test.go +++ b/op-challenger/game/fault/trace/vm/kona_super_server_executor_test.go @@ -32,6 +32,51 @@ func TestKonaSuperExecutorWithWitnessEndpoint(t *testing.T) { require.True(t, slices.Contains(args, "--enable-experimental-witness-endpoint")) } +func TestKonaSuperExecutorWithDepsetConfig(t *testing.T) { + t.Parallel() + executor := NewKonaSuperExecutor() + cfg := Config{ + Server: "/path/to/kona", + L1: "http://l1", + L1Beacon: "http://beacon", + L2s: []string{"http://l2a", "http://l2b"}, + DepsetConfigPath: "/path/to/depset.json", + } + inputs := utils.LocalGameInputs{ + L1Head: common.Hash{0x11}, + AgreedPreState: []byte{0x01, 0x02}, + L2Claim: common.Hash{0x44}, + L2SequenceNumber: big.NewInt(100), + } + + args, err := executor.OracleCommand(cfg, "/data", inputs) + require.NoError(t, err) + require.True(t, slices.Contains(args, "--depset-cfg")) + idx := slices.Index(args, "--depset-cfg") + require.Equal(t, "/path/to/depset.json", args[idx+1]) +} + +func TestKonaSuperExecutorWithoutDepsetConfig(t *testing.T) { + t.Parallel() + executor := NewKonaSuperExecutor() + cfg := Config{ + Server: "/path/to/kona", + L1: "http://l1", + L1Beacon: "http://beacon", + L2s: []string{"http://l2a", "http://l2b"}, + } + inputs := utils.LocalGameInputs{ + L1Head: common.Hash{0x11}, + AgreedPreState: []byte{0x01, 0x02}, + L2Claim: common.Hash{0x44}, + L2SequenceNumber: big.NewInt(100), + } + + args, err := executor.OracleCommand(cfg, "/data", inputs) + require.NoError(t, err) + require.False(t, slices.Contains(args, "--depset-cfg")) +} + func TestKonaSuperExecutorWithoutWitnessEndpoint(t *testing.T) { t.Parallel() executor := NewKonaSuperExecutor() diff --git a/op-core/nuts/README.md b/op-core/nuts/README.md new file mode 100644 index 00000000000..372cb699544 --- /dev/null +++ b/op-core/nuts/README.md @@ -0,0 +1,56 @@ +# NUT Bundles + +Network Upgrade Transaction (NUT) bundles define the L2 deposit transactions that activate a hardfork. Each bundle is a JSON file containing ordered transactions (implementation deployments, proxy upgrades, etc.) that the rollup node embeds and executes at the fork activation block. + +## Files + +| File | Purpose | +|------|---------| +| `fork_lock.toml` | Lock file mapping fork names to bundle paths, sha256 hashes, and source commits | +| `op-node/rollup/derive/_nut_bundle.json` | Embedded bundle consumed by op-node at fork activation | + +## Workflow + +### Generating a bundle + +```bash +cd packages/contracts-bedrock +just generate-nut-bundle +``` + +### Snapshotting a bundle for a fork + +```bash +just nut-snapshot-for +``` + +This copies `current-upgrade-bundle.json` to `op-node/rollup/derive/_nut_bundle.json` and updates `fork_lock.toml` with the sha256 hash and the merge-base commit with `origin/develop`. + +**Important:** The recorded commit is the merge-base with develop, not HEAD. This ensures the commit survives squash-merge. Contract changes must be merged to develop in a separate PR *before* snapshotting the bundle. + + +### Verifying a bundle + +```bash +just nut-provenance-verify +``` + +Checks that: +1. The bundle file exists and its sha256 matches the lock +2. Creates a temporary worktree at the recorded commit, regenerates the bundle, and compares byte-for-byte + +Requires `forge` for the provenance check (step 2). + +### CI checks + +- **`check-nut-locks`** — Verifies all bundle hashes match their lock entries, all entries have a commit, and every `*_nut_bundle.json` file has a corresponding lock entry. Runs in CI on every PR. + +## fork_lock.toml schema + +```toml +[] +bundle = "op-node/rollup/derive/_nut_bundle.json" # repo-relative path +hash = "sha256:" # sha256 of bundle contents +commit = "" # commit that produced the bundle +``` + diff --git a/op-core/nuts/fork_lock.toml b/op-core/nuts/fork_lock.toml index b1205cb2089..5d31c05997f 100644 --- a/op-core/nuts/fork_lock.toml +++ b/op-core/nuts/fork_lock.toml @@ -1,6 +1,10 @@ -# NUT Bundle Fork Lock -# To update a locked bundle, update both the bundle file and this hash in the same PR. +# To update a fork's bundle, run: just nut-snapshot-for +# Contract changes must be merged to develop before snapshotting. [karst] -bundle = "op-node/rollup/derive/karst_nut_bundle.json" -hash = "sha256:b9c610d09ca05ab24ef84ea38e4f563d71401f592f9eff13fa97dac879bee600" + bundle = "op-node/rollup/derive/karst_nut_bundle.json" + hash = "sha256:6145f900384f0aa2cdc63f2267a747b8c958bf1c09bacce8c29037c3eaa75d44" + commit = "cba7aba0c98aae22720b21c3a023990a486cb6e0" + +# REVIEWER NOTE: Changes to this file affect which NUT bundles are embedded +# into op-node for hardfork activations. Review carefully. diff --git a/op-core/nuts/lock.go b/op-core/nuts/lock.go new file mode 100644 index 00000000000..b804538734b --- /dev/null +++ b/op-core/nuts/lock.go @@ -0,0 +1,74 @@ +package nuts + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/BurntSushi/toml" + + opservice "github.com/ethereum-optimism/optimism/op-service" +) + +// ForkLockEntry represents a single fork's entry in fork_lock.toml. +type ForkLockEntry struct { + Bundle string `toml:"bundle"` + Hash string `toml:"hash"` + Commit string `toml:"commit"` +} + +// ForkLock is the full contents of fork_lock.toml, keyed by fork name. +type ForkLock map[string]ForkLockEntry + +// LockFilePath returns the absolute path to fork_lock.toml relative to the given directory. +func LockFilePath(dir string) (string, error) { + root, err := opservice.FindMonorepoRoot(dir) + if err != nil { + return "", fmt.Errorf("finding monorepo root: %w", err) + } + return filepath.Join(root, "op-core", "nuts", "fork_lock.toml"), nil +} + +// ReadLockFile reads and parses fork_lock.toml from the monorepo root. +func ReadLockFile(dir string) (ForkLock, string, error) { + lockPath, err := LockFilePath(dir) + if err != nil { + return nil, "", err + } + var locks ForkLock + if _, err := toml.DecodeFile(lockPath, &locks); err != nil { + return nil, "", fmt.Errorf("reading fork lock file: %w", err) + } + return locks, lockPath, nil +} + +// WriteLockFile writes fork_lock.toml back to disk with a header comment. +func WriteLockFile(lockPath string, locks ForkLock) error { + f, err := os.Create(lockPath) + if err != nil { + return fmt.Errorf("opening fork lock file for writing: %w", err) + } + defer f.Close() + + _, err = fmt.Fprint(f, `# To update a fork's bundle, run: just nut-snapshot-for +# Contract changes must be merged to develop before snapshotting. + +`) + if err != nil { + return err + } + + enc := toml.NewEncoder(f) + if err := enc.Encode(locks); err != nil { + return fmt.Errorf("writing fork lock file: %w", err) + } + + _, err = fmt.Fprint(f, ` +# REVIEWER NOTE: Changes to this file affect which NUT bundles are embedded +# into op-node for hardfork activations. Review carefully. +`) + if err != nil { + return err + } + return nil +} diff --git a/op-deployer/pkg/deployer/bootstrap/implementations_test.go b/op-deployer/pkg/deployer/bootstrap/implementations_test.go index b461ec71220..77eda8e7e56 100644 --- a/op-deployer/pkg/deployer/bootstrap/implementations_test.go +++ b/op-deployer/pkg/deployer/bootstrap/implementations_test.go @@ -97,9 +97,9 @@ func testImplementations(t *testing.T, forkRPCURL string) { // Assert that addresses stay the same between runs t.Log("Deploying first implementation contracts bundle") deployment1 := deploy() - require.NotEqual(t, common.Address{}, deployment1.Opcm, "Opcm address should be set") + require.NotEqual(t, common.Address{}, deployment1.OpcmV2, "OpcmV2 address should be set") t.Log("Deploying second implementation contracts bundle") deployment2 := deploy() - require.NotEqual(t, common.Address{}, deployment2.Opcm, "Opcm address should be set") + require.NotEqual(t, common.Address{}, deployment2.OpcmV2, "OpcmV2 address should be set") require.Equal(t, deployment1, deployment2) } diff --git a/op-deployer/pkg/deployer/devfeatures.go b/op-deployer/pkg/deployer/devfeatures.go index 9705cfd5e0f..d73295663ac 100644 --- a/op-deployer/pkg/deployer/devfeatures.go +++ b/op-deployer/pkg/deployer/devfeatures.go @@ -9,7 +9,7 @@ import ( // Development feature flag constants that mirror the solidity DevFeatures library. // These use a 32 byte bitmap for easy integration between op-deployer and contracts. var ( - // OptimismPortalInteropDevFlag enables the OptimismPortalInterop contract. + // OptimismPortalInteropDevFlag enables interop features in OptimismPortal2. OptimismPortalInteropDevFlag = common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001") // CannonKonaDevFlag enables Kona as the default cannon prover. diff --git a/op-deployer/pkg/deployer/integration_test/apply_test.go b/op-deployer/pkg/deployer/integration_test/apply_test.go index 605a2937341..da88eb884d8 100644 --- a/op-deployer/pkg/deployer/integration_test/apply_test.go +++ b/op-deployer/pkg/deployer/integration_test/apply_test.go @@ -126,7 +126,8 @@ func TestEndToEndBootstrapApply(t *testing.T) { intent, st := shared.NewIntent(t, l1ChainID, dk, l2ChainID, loc, loc, testCustomGasLimit) intent.SuperchainRoles = nil - intent.OPCMAddress = &impls.Opcm + intent.OPCMAddress = &impls.OpcmV2 + intent.SuperchainConfigProxy = &bstrap.SuperchainConfigProxy require.NoError(t, deployer.ApplyPipeline( ctx, @@ -169,7 +170,7 @@ func TestEndToEndBootstrapApplyWithUpgrade(t *testing.T) { name string devFeature common.Hash }{ - {"default", common.Hash{}}, + // "default" (non-V2) test case removed: v1 OPCM was deleted. {"opcm-v2", deployer.OPCMV2DevFlag}, } for _, tt := range tests { @@ -433,9 +434,7 @@ func TestEndToEndApply(t *testing.T) { // Verify that the dev feature bitmap is set to OPCMV2 require.Equal(t, deployer.OPCMV2DevFlag, intent.GlobalDeployOverrides["devFeatureBitmap"]) - // Assert that the OPCM V1 addresses are zero - require.Equal(t, common.Address{}, st.ImplementationsDeployment.OpcmImpl, "OPCM V1 implementation should be zero") - require.Equal(t, common.Address{}, st.ImplementationsDeployment.OpcmContractsContainerImpl, "OPCM container implementation should be zero") + require.NotEqual(t, common.Address{}, st.ImplementationsDeployment.OpcmV2Impl, "OpcmV2Impl should be set") require.Equal(t, common.Address{}, st.ImplementationsDeployment.OpcmGameTypeAdderImpl, "OPCM game type adder implementation should be zero") require.Equal(t, common.Address{}, st.ImplementationsDeployment.OpcmDeployerImpl, "OPCM deployer implementation should be zero") require.Equal(t, common.Address{}, st.ImplementationsDeployment.OpcmUpgraderImpl, "OPCM upgrader implementation should be zero") @@ -1176,7 +1175,7 @@ func validateSuperchainDeployment(t *testing.T, st *state.State, cg codeGetter, {"SuperchainProxyAdminImpl", st.SuperchainDeployment.SuperchainProxyAdminImpl}, {"SuperchainConfigProxy", st.SuperchainDeployment.SuperchainConfigProxy}, {"ProtocolVersionsProxy", st.SuperchainDeployment.ProtocolVersionsProxy}, - {"OpcmImpl", st.ImplementationsDeployment.OpcmImpl}, + {"OpcmV2Impl", st.ImplementationsDeployment.OpcmV2Impl}, {"PreimageOracleImpl", st.ImplementationsDeployment.PreimageOracleImpl}, {"MipsImpl", st.ImplementationsDeployment.MipsImpl}, } @@ -1204,7 +1203,6 @@ func validateOPChainDeployment(t *testing.T, cg codeGetter, st *state.State, int implAddrs := []addrTuple{ {"DelayedWethImpl", st.ImplementationsDeployment.DelayedWethImpl}, {"OptimismPortalImpl", st.ImplementationsDeployment.OptimismPortalImpl}, - {"OptimismPortalInteropImpl", st.ImplementationsDeployment.OptimismPortalInteropImpl}, {"SystemConfigImpl", st.ImplementationsDeployment.SystemConfigImpl}, {"L1CrossDomainMessengerImpl", st.ImplementationsDeployment.L1CrossDomainMessengerImpl}, {"L1ERC721BridgeImpl", st.ImplementationsDeployment.L1Erc721BridgeImpl}, diff --git a/op-deployer/pkg/deployer/integration_test/cli/bootstrap_forge_test.go b/op-deployer/pkg/deployer/integration_test/cli/bootstrap_forge_test.go index 82ad4c151ad..c868d6f93ae 100644 --- a/op-deployer/pkg/deployer/integration_test/cli/bootstrap_forge_test.go +++ b/op-deployer/pkg/deployer/integration_test/cli/bootstrap_forge_test.go @@ -115,7 +115,7 @@ func TestCLIBootstrapForge(t *testing.T) { require.NoError(t, err) // We only check specific addresses that are always set - require.NotEqual(t, common.Address{}, implsOutput.Opcm, "Opcm should be set") + require.NotEqual(t, common.Address{}, implsOutput.OpcmV2, "OpcmV2 should be set") require.NotEqual(t, common.Address{}, implsOutput.OpcmStandardValidator, "OpcmStandardValidator should be set") require.NotEqual(t, common.Address{}, implsOutput.DelayedWETHImpl, "DelayedWETHImpl should be set") require.NotEqual(t, common.Address{}, implsOutput.OptimismPortalImpl, "OptimismPortalImpl should be set") @@ -176,7 +176,7 @@ func TestCLIBootstrapForge(t *testing.T) { // Verify all outputs have valid addresses require.NoError(t, addresses.CheckNoZeroAddresses(superchainOutput)) - require.NotEqual(t, common.Address{}, implsOutput.Opcm, "Opcm should be set") + require.NotEqual(t, common.Address{}, implsOutput.OpcmV2, "OpcmV2 should be set") t.Log("✓ End-to-end bootstrap with Forge completed successfully") }) diff --git a/op-deployer/pkg/deployer/integration_test/cli/bootstrap_test.go b/op-deployer/pkg/deployer/integration_test/cli/bootstrap_test.go index eaaeeaeda1e..063f9c04e8d 100644 --- a/op-deployer/pkg/deployer/integration_test/cli/bootstrap_test.go +++ b/op-deployer/pkg/deployer/integration_test/cli/bootstrap_test.go @@ -183,7 +183,7 @@ func TestCLIBootstrap(t *testing.T) { require.NoError(t, err) // We only check specific addresses that are always set - require.NotEqual(t, common.Address{}, implsOutput.Opcm, "Opcm should be set") + require.NotEqual(t, common.Address{}, implsOutput.OpcmV2, "OpcmV2 should be set") require.NotEqual(t, common.Address{}, implsOutput.OpcmStandardValidator, "OpcmStandardValidator should be set") require.NotEqual(t, common.Address{}, implsOutput.DelayedWETHImpl, "DelayedWETHImpl should be set") require.NotEqual(t, common.Address{}, implsOutput.OptimismPortalImpl, "OptimismPortalImpl should be set") diff --git a/op-deployer/pkg/deployer/integration_test/cli/deploy_scripts_forge_test.go b/op-deployer/pkg/deployer/integration_test/cli/deploy_scripts_forge_test.go index 10be55f0c9a..196bad36de1 100644 --- a/op-deployer/pkg/deployer/integration_test/cli/deploy_scripts_forge_test.go +++ b/op-deployer/pkg/deployer/integration_test/cli/deploy_scripts_forge_test.go @@ -293,7 +293,6 @@ func TestDeployScriptsForge(t *testing.T) { // PrivateKey not required for read-only operations } output, err := opcm.ReadSuperchainDeploymentViaForge(forgeEnv, opcm.ReadSuperchainDeploymentInput{ - OpcmAddress: common.Address{}, // OPCM v2 flow - use SuperchainConfigProxy SuperchainConfigProxy: superchainOutput.SuperchainConfigProxy, }) require.NoError(t, err) @@ -303,10 +302,5 @@ func TestDeployScriptsForge(t *testing.T) { require.Equal(t, superchainOutput.SuperchainProxyAdmin, output.SuperchainProxyAdmin) require.NotEqual(t, common.Address{}, output.Guardian) require.NotEqual(t, common.Address{}, output.SuperchainProxyAdminOwner) - - // For OPCM v2, ProtocolVersions fields should be zero - require.Equal(t, common.Address{}, output.ProtocolVersionsProxy) - require.Equal(t, common.Address{}, output.ProtocolVersionsImpl) - require.Equal(t, common.Address{}, output.ProtocolVersionsOwner) }) } diff --git a/op-deployer/pkg/deployer/integration_test/cli/migrate_test.go b/op-deployer/pkg/deployer/integration_test/cli/migrate_test.go index 066c6f9e4f5..5ac58dde90e 100644 --- a/op-deployer/pkg/deployer/integration_test/cli/migrate_test.go +++ b/op-deployer/pkg/deployer/integration_test/cli/migrate_test.go @@ -88,8 +88,10 @@ func TestCLIMigrateRequiredFlags(t *testing.T) { }) } -// TestCLIMigrateV1 tests the migrate-v1 CLI command for OPCM v1 +// TestCLIMigrateV1 tests the migrate-v1 CLI command for OPCM v1. +// Skipped: OPCMv1 contract has been deleted. Remove this test in the Go cleanup PR. func TestCLIMigrateV1(t *testing.T) { + t.Skip("OPCMv1 contract deleted — v1 migration path no longer functional") lgr := testlog.Logger(t, slog.LevelDebug) forkedL1, stopL1, err := devnet.NewForkedSepolia(lgr) @@ -154,8 +156,8 @@ func TestCLIMigrateV1(t *testing.T) { impls, err := bootstrap.Implementations(ctx, cfg) require.NoError(t, err, "Failed to deploy implementations") - require.NotEqual(t, common.Address{}, impls.Opcm, "OPCM V1 address should be set") - require.Equal(t, common.Address{}, impls.OpcmV2, "OPCM V2 address should be zero when V1 is deployed") + require.NotEqual(t, common.Address{}, impls.OpcmV2, "OPCM V2 address should be set") + require.Equal(t, common.Address{}, impls.Opcm, "OPCM V1 address should be zero (v1 deleted)") // Set up a test chain l1ChainID := uint64(11155111) // Sepolia chain ID @@ -219,7 +221,7 @@ func TestCLIMigrateV1(t *testing.T) { // Set implementations deployment addresses if st.ImplementationsDeployment == nil { st.ImplementationsDeployment = &addresses.ImplementationsContracts{ - OpcmImpl: impls.Opcm, + OpcmV2Impl: impls.OpcmV2, OptimismPortalImpl: impls.OptimismPortalImpl, DelayedWethImpl: impls.DelayedWETHImpl, EthLockboxImpl: impls.ETHLockboxImpl, @@ -439,11 +441,10 @@ func TestCLIMigrateV2(t *testing.T) { // Set implementations deployment addresses if st.ImplementationsDeployment == nil { st.ImplementationsDeployment = &addresses.ImplementationsContracts{ - OpcmImpl: impls.OpcmV2, + OpcmV2Impl: impls.OpcmV2, OpcmContainerImpl: impls.OpcmContainer, OpcmUtilsImpl: impls.OpcmUtils, OpcmMigratorImpl: impls.OpcmMigrator, - OptimismPortalInteropImpl: impls.OptimismPortalInteropImpl, OptimismPortalImpl: impls.OptimismPortalImpl, DelayedWethImpl: impls.DelayedWETHImpl, EthLockboxImpl: impls.ETHLockboxImpl, diff --git a/op-deployer/pkg/deployer/integration_test/cli/upgrade_test.go b/op-deployer/pkg/deployer/integration_test/cli/upgrade_test.go index 92e4acda2d0..9c1d42c5a6c 100644 --- a/op-deployer/pkg/deployer/integration_test/cli/upgrade_test.go +++ b/op-deployer/pkg/deployer/integration_test/cli/upgrade_test.go @@ -9,11 +9,9 @@ import ( "strings" "testing" - "github.com/ethereum-optimism/optimism/op-chain-ops/opcmregistry" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/upgrade/v2_0_0" - v6_0_0 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/upgrade/v6_0_0" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testutils/devnet" "github.com/ethereum/go-ethereum/common" @@ -61,11 +59,8 @@ func TestCLIUpgrade(t *testing.T) { version: "v5.0.0", forkBlock: 9629972, // one block past the opcm deployment block }, - { - contractTag: standard.ContractsV600Tag, - version: "v6.0.0-rc.2", - forkBlock: 10101510, // one block past the opcm deployment block - }, + // v6.0.0-rc.2 test case removed: it deployed a v1 OPCM on Sepolia, and the + // embedded UpgradeOPChain.s.sol script no longer supports v1 OPCM upgrades. } for _, tc := range testCases { @@ -82,41 +77,18 @@ func TestCLIUpgrade(t *testing.T) { opcm, err := standard.OPCMImplAddressFor(11155111, tc.contractTag) require.NoError(t, err) - versionStr := strings.TrimPrefix(tc.version, "v") // Remove "v" prefix for parsing - version, err := opcmregistry.ParseSemver(versionStr) - require.NoError(t, err, "failed to parse version %s", versionStr) - - v6Semver := opcmregistry.Semver{Major: 6, Minor: 0, Patch: 0} - var configData []byte - if version.Compare(v6Semver) >= 0 { - // v6.0.0+ uses a different input structure - testConfig := v6_0_0.UpgradeOPChainInput{ - Prank: l1ProxyAdminOwner, - Opcm: opcm, - EncodedChainConfigs: []v6_0_0.OPChainConfig{ - { - SystemConfigProxy: systemConfigProxy, - CannonPrestate: common.HexToHash("0x0abc"), - CannonKonaPrestate: common.HexToHash("0x0def"), - }, + testConfig := v2_0_0.UpgradeOPChainInput{ + Prank: l1ProxyAdminOwner, + Opcm: opcm, + EncodedChainConfigs: []v2_0_0.OPChainConfig{ + { + SystemConfigProxy: systemConfigProxy, + ProxyAdmin: proxyAdminImpl, + AbsolutePrestate: common.HexToHash("0x0abc"), }, - } - configData, err = json.MarshalIndent(testConfig, "", " ") - } else { - // Older versions use v2_0_0 structure - testConfig := v2_0_0.UpgradeOPChainInput{ - Prank: l1ProxyAdminOwner, - Opcm: opcm, - EncodedChainConfigs: []v2_0_0.OPChainConfig{ - { - SystemConfigProxy: systemConfigProxy, - ProxyAdmin: proxyAdminImpl, - AbsolutePrestate: common.HexToHash("0x0abc"), - }, - }, - } - configData, err = json.MarshalIndent(testConfig, "", " ") + }, } + configData, err := json.MarshalIndent(testConfig, "", " ") require.NoError(t, err) configFile := filepath.Join(workDir, "upgrade_config_"+tc.version+".json") @@ -148,14 +120,7 @@ func TestCLIUpgrade(t *testing.T) { require.Equal(t, l1ProxyAdminOwner.Hex(), dump[0].To.Hex()) dataHex := hex.EncodeToString(dump[0].Data) - // v6.0.0+ uses a different function signature: upgrade((address,bytes32,bytes32)[]) - // Older versions use: upgrade((address,address,bytes32)[]) - var expectedSelector string - if version.Compare(v6Semver) >= 0 { - expectedSelector = "cbeda5a7" // upgrade((address,bytes32,bytes32)[]) - } else { - expectedSelector = "ff2dd5a1" // upgrade((address,address,bytes32)[]) - } + expectedSelector := "ff2dd5a1" require.True(t, strings.HasPrefix(dataHex, expectedSelector), "calldata should have opcm.upgrade fcn selector %s, got: %s", expectedSelector, dataHex[:8]) }) diff --git a/op-deployer/pkg/deployer/integration_test/cli/verify_test.go b/op-deployer/pkg/deployer/integration_test/cli/verify_test.go index 95bf1d0d943..4167cd91087 100644 --- a/op-deployer/pkg/deployer/integration_test/cli/verify_test.go +++ b/op-deployer/pkg/deployer/integration_test/cli/verify_test.go @@ -150,7 +150,7 @@ func TestCLIVerify(t *testing.T) { "superchain_superchain_config_proxy": "Proxy.sol/Proxy.json", "superchain_protocol_versions_proxy": "Proxy.sol/Proxy.json", "superchain_superchain_config_impl": "SuperchainConfig.sol/SuperchainConfig.json", - "implementations_opcm_impl": "OPContractsManager.sol/OPContractsManager.json", + "implementations_opcm_impl": "OPContractsManagerV2.sol/OPContractsManagerV2.json", "regular_contract_name": "RegularContractName.sol/RegularContractName.json", } diff --git a/op-deployer/pkg/deployer/manage/add_game_type_test.go b/op-deployer/pkg/deployer/manage/add_game_type_test.go index 7349f0d669f..775067f4325 100644 --- a/op-deployer/pkg/deployer/manage/add_game_type_test.go +++ b/op-deployer/pkg/deployer/manage/add_game_type_test.go @@ -25,6 +25,7 @@ import ( ) func TestAddGameType(t *testing.T) { + t.Skip("OPCMv1 contract deleted — AddGameType.s.sol no longer exists. Use TestManageAddGameTypeV2_CLI instead.") // Since the opcm version is not yet on sepolia, we create a fork of sepolia then deploy the opcm via deploy implementations. lgr := testlog.Logger(t, slog.LevelDebug) forkedL1, stopL1, err := devnet.NewForkedSepolia(lgr) diff --git a/op-deployer/pkg/deployer/manage/migrate_test.go b/op-deployer/pkg/deployer/manage/migrate_test.go index 6fb116ae275..5ec8ff9bfbf 100644 --- a/op-deployer/pkg/deployer/manage/migrate_test.go +++ b/op-deployer/pkg/deployer/manage/migrate_test.go @@ -53,7 +53,6 @@ func TestInteropMigration(t *testing.T) { name string devFeature common.Hash }{ - {"opcm-v1", common.Hash{}}, {"opcm-v2", deployer.OPCMV2DevFlag}, } @@ -103,9 +102,9 @@ func TestInteropMigration(t *testing.T) { opcmAddr = st.ImplementationsDeployment.OpcmV2Impl t.Logf("OPCM V2: %s", opcmAddr.Hex()) } else { - require.NotEqual(t, common.Address{}, st.ImplementationsDeployment.OpcmImpl, "OPCM V1 address should be set") - opcmAddr = st.ImplementationsDeployment.OpcmImpl - t.Logf("OPCM V1: %s", opcmAddr.Hex()) + require.NotEqual(t, common.Address{}, st.ImplementationsDeployment.OpcmV2Impl, "OPCM V2 address should be set") + opcmAddr = st.ImplementationsDeployment.OpcmV2Impl + t.Logf("OPCM V2: %s", opcmAddr.Hex()) } // Deploy DummyCaller at l1ProxyAdminOwner for the OPCM diff --git a/op-deployer/pkg/deployer/opcm/implementations.go b/op-deployer/pkg/deployer/opcm/implementations.go index 3864104f0e5..f1b5a8609d9 100644 --- a/op-deployer/pkg/deployer/opcm/implementations.go +++ b/op-deployer/pkg/deployer/opcm/implementations.go @@ -42,7 +42,6 @@ type DeployImplementationsOutput struct { OpcmContainer common.Address `json:"opcmContainerAddress"` DelayedWETHImpl common.Address `json:"delayedWETHImplAddress"` OptimismPortalImpl common.Address `json:"optimismPortalImplAddress"` - OptimismPortalInteropImpl common.Address `json:"optimismPortalInteropImplAddress"` ETHLockboxImpl common.Address `json:"ethLockboxImplAddress" abi:"ethLockboxImpl"` PreimageOracleSingleton common.Address `json:"preimageOracleSingletonAddress"` MipsSingleton common.Address `json:"mipsSingletonAddress"` diff --git a/op-deployer/pkg/deployer/opcm/opchain.go b/op-deployer/pkg/deployer/opcm/opchain.go index 89cef911c5f..7222261cd87 100644 --- a/op-deployer/pkg/deployer/opcm/opchain.go +++ b/op-deployer/pkg/deployer/opcm/opchain.go @@ -99,7 +99,6 @@ type ReadImplementationAddressesInput struct { type ReadImplementationAddressesOutput struct { DelayedWETH common.Address OptimismPortal common.Address - OptimismPortalInterop common.Address EthLockbox common.Address `evm:"ethLockbox"` SystemConfig common.Address AnchorStateRegistry common.Address diff --git a/op-deployer/pkg/deployer/opcm/read_superchain_deployment.go b/op-deployer/pkg/deployer/opcm/read_superchain_deployment.go index ae84e916b6a..6a56c8fb5d6 100644 --- a/op-deployer/pkg/deployer/opcm/read_superchain_deployment.go +++ b/op-deployer/pkg/deployer/opcm/read_superchain_deployment.go @@ -9,18 +9,10 @@ import ( ) type ReadSuperchainDeploymentInput struct { - OpcmAddress common.Address // TODO(#18612): Remove OpcmAddress field when OPCMv1 gets deprecated SuperchainConfigProxy common.Address } type ReadSuperchainDeploymentOutput struct { - // TODO(#18612): Remove ProtocolVersions fields when OPCMv1 gets deprecated - ProtocolVersionsImpl common.Address `abi:"protocolVersionsImpl"` - ProtocolVersionsProxy common.Address `abi:"protocolVersionsProxy"` - ProtocolVersionsOwner common.Address `abi:"protocolVersionsOwner"` - RecommendedProtocolVersion common.Hash `abi:"recommendedProtocolVersion"` - RequiredProtocolVersion common.Hash `abi:"requiredProtocolVersion"` - SuperchainConfigImpl common.Address `abi:"superchainConfigImpl"` SuperchainConfigProxy common.Address `abi:"superchainConfigProxy"` SuperchainProxyAdmin common.Address `abi:"superchainProxyAdmin"` diff --git a/op-deployer/pkg/deployer/pipeline/implementations.go b/op-deployer/pkg/deployer/pipeline/implementations.go index 078000423f8..e7a8072fd7c 100644 --- a/op-deployer/pkg/deployer/pipeline/implementations.go +++ b/op-deployer/pkg/deployer/pipeline/implementations.go @@ -83,7 +83,6 @@ func DeployImplementations(env *Env, intent *state.Intent, st *state.State) erro } st.ImplementationsDeployment = &addresses.ImplementationsContracts{ - OpcmImpl: dio.Opcm, OpcmGameTypeAdderImpl: dio.OpcmGameTypeAdder, OpcmDeployerImpl: dio.OpcmDeployer, OpcmUpgraderImpl: dio.OpcmUpgrader, @@ -93,7 +92,6 @@ func DeployImplementations(env *Env, intent *state.Intent, st *state.State) erro OpcmContainerImpl: dio.OpcmContainer, DelayedWethImpl: dio.DelayedWETHImpl, OptimismPortalImpl: dio.OptimismPortalImpl, - OptimismPortalInteropImpl: dio.OptimismPortalInteropImpl, EthLockboxImpl: dio.ETHLockboxImpl, PreimageOracleImpl: dio.PreimageOracleSingleton, MipsImpl: dio.MipsSingleton, diff --git a/op-deployer/pkg/deployer/pipeline/init.go b/op-deployer/pkg/deployer/pipeline/init.go index cb5648e58f4..239220a9ccf 100644 --- a/op-deployer/pkg/deployer/pipeline/init.go +++ b/op-deployer/pkg/deployer/pipeline/init.go @@ -44,10 +44,15 @@ func InitLiveStrategy(ctx context.Context, env *Env, intent *state.Intent, st *s superchainConfigAddr = *intent.SuperchainConfigProxy } - // The ReadSuperchainDeployment script (packages/contracts-bedrock/scripts/deploy/ReadSuperchainDeployment.s.sol) - // uses the OPCM's semver version (>= 7.0.0 indicates v2) to determine how to populate the superchain state: - // - OPCMv1 (< 7.0.0): Queries the OPCM contract to get SuperchainConfig and ProtocolVersions - // - OPCMv2 (>= 7.0.0): Uses the provided SuperchainConfigProxy address; ProtocolVersions is deprecated + // If only an OPCM address is provided, resolve SuperchainConfigProxy from it on-chain. + if superchainConfigAddr == (common.Address{}) && opcmAddr != (common.Address{}) { + opcmContract := opcm.NewContract(opcmAddr, env.L1Client) + resolved, err := opcmContract.SuperchainConfig(ctx) + if err != nil { + return fmt.Errorf("error resolving SuperchainConfig from OPCM at %s: %w", opcmAddr, err) + } + superchainConfigAddr = resolved + } superDeployment, superRoles, err := PopulateSuperchainState(env, opcmAddr, superchainConfigAddr) if err != nil { return fmt.Errorf("error populating superchain state: %w", err) @@ -57,7 +62,7 @@ func InitLiveStrategy(ctx context.Context, env *Env, intent *state.Intent, st *s if hasPredeployedOPCM && st.ImplementationsDeployment == nil { st.ImplementationsDeployment = &addresses.ImplementationsContracts{ - OpcmImpl: opcmAddr, + OpcmV2Impl: opcmAddr, } } } @@ -137,11 +142,8 @@ func immutableErr(field string, was, is any) error { return fmt.Errorf("%s is immutable: was %v, is %v", field, was, is) } -// TODO(#18612): Remove OPCMAddress field when OPCMv1 gets deprecated -// TODO(#18612): Remove ProtocolVersions fields when OPCMv1 gets deprecated func PopulateSuperchainState(env *Env, opcmAddr common.Address, superchainConfigProxy common.Address) (*addresses.SuperchainContracts, *addresses.SuperchainRoles, error) { input := opcm.ReadSuperchainDeploymentInput{ - OpcmAddress: opcmAddr, SuperchainConfigProxy: superchainConfigProxy, } @@ -174,13 +176,10 @@ func PopulateSuperchainState(env *Env, opcmAddr common.Address, superchainConfig SuperchainProxyAdminImpl: out.SuperchainProxyAdmin, SuperchainConfigProxy: out.SuperchainConfigProxy, SuperchainConfigImpl: out.SuperchainConfigImpl, - ProtocolVersionsProxy: out.ProtocolVersionsProxy, - ProtocolVersionsImpl: out.ProtocolVersionsImpl, } roles := &addresses.SuperchainRoles{ SuperchainProxyAdminOwner: out.SuperchainProxyAdminOwner, SuperchainGuardian: out.Guardian, - ProtocolVersionsOwner: out.ProtocolVersionsOwner, } return deployment, roles, nil } diff --git a/op-deployer/pkg/deployer/pipeline/init_test.go b/op-deployer/pkg/deployer/pipeline/init_test.go index 8455be34e6d..9e14b9aa531 100644 --- a/op-deployer/pkg/deployer/pipeline/init_test.go +++ b/op-deployer/pkg/deployer/pipeline/init_test.go @@ -117,10 +117,11 @@ func TestInitLiveStrategy_OPCMReuseLogicSepolia(t *testing.T) { expDeployment := &addresses.SuperchainContracts{ SuperchainProxyAdminImpl: proxyAdmin, - ProtocolVersionsProxy: superCfg.ProtocolVersionsAddr, - ProtocolVersionsImpl: common.HexToAddress("0x37E15e4d6DFFa9e5E320Ee1eC036922E563CB76C"), - SuperchainConfigProxy: superCfg.SuperchainConfigAddr, - SuperchainConfigImpl: common.HexToAddress("0xb08Cc720F511062537ca78BdB0AE691F04F5a957"), + // OPCMv1 removed — ProtocolVersions fields are no longer populated. + ProtocolVersionsProxy: common.Address{}, + ProtocolVersionsImpl: common.Address{}, + SuperchainConfigProxy: superCfg.SuperchainConfigAddr, + SuperchainConfigImpl: common.HexToAddress("0xb08Cc720F511062537ca78BdB0AE691F04F5a957"), } // Tagged locator will reuse the existing superchain and OPCM @@ -128,8 +129,12 @@ func TestInitLiveStrategy_OPCMReuseLogicSepolia(t *testing.T) { require.NotNil(t, st.ImplementationsDeployment) require.NotNil(t, st.SuperchainRoles) require.Equal(t, *expDeployment, *st.SuperchainDeployment) - require.Equal(t, opcmAddr, st.ImplementationsDeployment.OpcmImpl) - require.Equal(t, *stdSuperchainRoles, *st.SuperchainRoles) + require.Equal(t, opcmAddr, st.ImplementationsDeployment.OpcmV2Impl) + // OPCMv1 removed — ProtocolVersionsOwner is no longer returned by the script. + // Check the fields that are still populated. + require.Equal(t, stdSuperchainRoles.SuperchainProxyAdminOwner, st.SuperchainRoles.SuperchainProxyAdminOwner) + require.Equal(t, stdSuperchainRoles.SuperchainGuardian, st.SuperchainRoles.SuperchainGuardian) + require.Equal(t, common.Address{}, st.SuperchainRoles.ProtocolVersionsOwner) } runTest(state.IntentTypeStandard) @@ -243,41 +248,23 @@ func TestPopulateSuperchainState(t *testing.T) { require.NoError(t, err) opcmAddr := l1Versions["op-contracts/v2.0.0-rc.1"].OPContractsManager.Address - t.Run("valid OPCM address only", func(t *testing.T) { - dep, roles, err := PopulateSuperchainState(env, common.Address(*opcmAddr), common.Address{}) + t.Run("OPCM address with SuperchainConfigProxy", func(t *testing.T) { + dep, roles, err := PopulateSuperchainState(env, common.Address(*opcmAddr), superchain.SuperchainConfigAddr) require.NoError(t, err) require.Equal(t, addresses.SuperchainContracts{ SuperchainProxyAdminImpl: common.HexToAddress("0x189aBAAaa82DfC015A588A7dbaD6F13b1D3485Bc"), SuperchainConfigProxy: superchain.SuperchainConfigAddr, SuperchainConfigImpl: common.HexToAddress("0x4da82a327773965b8d4D85Fa3dB8249b387458E7"), - ProtocolVersionsProxy: superchain.ProtocolVersionsAddr, - ProtocolVersionsImpl: common.HexToAddress("0x37E15e4d6DFFa9e5E320Ee1eC036922E563CB76C"), + ProtocolVersionsProxy: common.Address{}, + ProtocolVersionsImpl: common.Address{}, }, *dep) require.Equal(t, addresses.SuperchainRoles{ SuperchainProxyAdminOwner: common.HexToAddress("0x1Eb2fFc903729a0F03966B917003800b145F56E2"), - ProtocolVersionsOwner: common.HexToAddress("0xfd1D2e729aE8eEe2E146c033bf4400fE75284301"), + ProtocolVersionsOwner: common.Address{}, SuperchainGuardian: common.HexToAddress("0x7a50f00e8D05b95F98fE38d8BeE366a7324dCf7E"), }, *roles) }) - t.Run("OPCM address with SuperchainConfigProxy", func(t *testing.T) { - // When both are provided and OPCM version < 7.0.0, the script uses v1 flow - // The SuperchainConfigProxy parameter is ignored in v1 flow - dep, roles, err := PopulateSuperchainState(env, common.Address(*opcmAddr), superchain.SuperchainConfigAddr) - require.NoError(t, err) - require.NotNil(t, dep) - require.NotNil(t, roles) - - // For OPCMv1, ProtocolVersions should be populated (read from OPCM) - require.NotEqual(t, common.Address{}, dep.ProtocolVersionsProxy, "ProtocolVersionsProxy should be populated for v1") - require.NotEqual(t, common.Address{}, dep.ProtocolVersionsImpl, "ProtocolVersionsImpl should be populated for v1") - require.NotEqual(t, common.Address{}, roles.ProtocolVersionsOwner, "ProtocolVersionsOwner should be populated for v1") - - // Verify that values match what OPCM returns (not the SuperchainConfigProxy parameter) - require.Equal(t, superchain.SuperchainConfigAddr, dep.SuperchainConfigProxy) - require.Equal(t, superchain.ProtocolVersionsAddr, dep.ProtocolVersionsProxy) - }) - t.Run("invalid OPCM address", func(t *testing.T) { // Use an invalid address (non-existent contract) invalidOpcmAddr := common.HexToAddress("0x1234567890123456789012345678901234567890") @@ -289,30 +276,28 @@ func TestPopulateSuperchainState(t *testing.T) { }) t.Run("output mapping validation", func(t *testing.T) { - dep, roles, err := PopulateSuperchainState(env, common.Address(*opcmAddr), common.Address{}) + dep, roles, err := PopulateSuperchainState(env, common.Address(*opcmAddr), superchain.SuperchainConfigAddr) require.NoError(t, err) require.NotNil(t, dep) require.NotNil(t, roles) - // Verify all SuperchainContracts fields are populated correctly + // Verify SuperchainConfig fields are populated correctly require.NotEqual(t, common.Address{}, dep.SuperchainProxyAdminImpl, "SuperchainProxyAdminImpl should be populated") require.NotEqual(t, common.Address{}, dep.SuperchainConfigProxy, "SuperchainConfigProxy should be populated") require.NotEqual(t, common.Address{}, dep.SuperchainConfigImpl, "SuperchainConfigImpl should be populated") - require.NotEqual(t, common.Address{}, dep.ProtocolVersionsProxy, "ProtocolVersionsProxy should be populated for v1") - require.NotEqual(t, common.Address{}, dep.ProtocolVersionsImpl, "ProtocolVersionsImpl should be populated for v1") - - // Verify implementations are different from proxies require.NotEqual(t, dep.SuperchainConfigImpl, dep.SuperchainConfigProxy, "SuperchainConfigImpl should differ from proxy") - require.NotEqual(t, dep.ProtocolVersionsImpl, dep.ProtocolVersionsProxy, "ProtocolVersionsImpl should differ from proxy") - // Verify all SuperchainRoles fields are populated correctly + // ProtocolVersions fields are zero now that OPCMv1 is removed + require.Equal(t, common.Address{}, dep.ProtocolVersionsProxy, "ProtocolVersionsProxy should be zero") + require.Equal(t, common.Address{}, dep.ProtocolVersionsImpl, "ProtocolVersionsImpl should be zero") + + // Verify SuperchainRoles fields are populated correctly require.NotEqual(t, common.Address{}, roles.SuperchainProxyAdminOwner, "SuperchainProxyAdminOwner should be populated") - require.NotEqual(t, common.Address{}, roles.ProtocolVersionsOwner, "ProtocolVersionsOwner should be populated for v1") require.NotEqual(t, common.Address{}, roles.SuperchainGuardian, "SuperchainGuardian should be populated") + require.Equal(t, common.Address{}, roles.ProtocolVersionsOwner, "ProtocolVersionsOwner should be zero") // Verify expected values match require.Equal(t, superchain.SuperchainConfigAddr, dep.SuperchainConfigProxy) - require.Equal(t, superchain.ProtocolVersionsAddr, dep.ProtocolVersionsProxy) }) } @@ -380,13 +365,12 @@ func TestPopulateSuperchainState_OPCMV2(t *testing.T) { }) t.Run("both addresses zero", func(t *testing.T) { - // When both are zero, the script detects OPCMv2 flow (because opcmAddr == 0) - // but then requires SuperchainConfigProxy to be set, so it should error + // When both are zero, the script requires SuperchainConfigProxy to have code, so it should error dep, roles, err := PopulateSuperchainState(env, common.Address{}, common.Address{}) require.Error(t, err) require.Nil(t, dep) require.Nil(t, roles) - require.Contains(t, err.Error(), "superchainConfigProxy has no code for OPCM v2") + require.Contains(t, err.Error(), "superchainConfigProxy has no code") }) t.Run("invalid SuperchainConfigProxy", func(t *testing.T) { @@ -567,8 +551,7 @@ func TestInitLiveStrategy_OPCMV2WithSuperchainConfigProxyAndRoles_reverts(t *tes require.Contains(t, err.Error(), "cannot set superchain roles when using predeployed OPCM or SuperchainConfig") } -// Validates that providing both OPCMAddress and SuperchainConfigProxy works correctly -// The script will use the OPCM's semver to determine the version +// Validates that providing both OPCMAddress and SuperchainConfigProxy works correctly. func TestInitLiveStrategy_OPCMV1WithSuperchainConfigProxy(t *testing.T) { t.Parallel() @@ -635,10 +618,9 @@ func TestInitLiveStrategy_OPCMV1WithSuperchainConfigProxy(t *testing.T) { // Should succeed - the script handles version detection require.NoError(t, err) - // For OPCMv1, ProtocolVersions should be populated require.NotNil(t, st.SuperchainDeployment) - require.NotEqual(t, common.Address{}, st.SuperchainDeployment.ProtocolVersionsProxy) - require.NotEqual(t, common.Address{}, st.SuperchainDeployment.ProtocolVersionsImpl) + require.Equal(t, common.Address{}, st.SuperchainDeployment.ProtocolVersionsProxy) + require.Equal(t, common.Address{}, st.SuperchainDeployment.ProtocolVersionsImpl) } // Validates that providing both @@ -758,15 +740,14 @@ func TestInitLiveStrategy_FlowSelection_OPCMV1(t *testing.T) { ) require.NoError(t, err) - // Verify OPCM v1 flow was used - ProtocolVersions should be populated require.NotNil(t, st.SuperchainDeployment) - require.NotEqual(t, common.Address{}, st.SuperchainDeployment.ProtocolVersionsProxy, "ProtocolVersionsProxy should be populated for v1") - require.NotEqual(t, common.Address{}, st.SuperchainDeployment.ProtocolVersionsImpl, "ProtocolVersionsImpl should be populated for v1") - require.NotEqual(t, common.Address{}, st.SuperchainRoles.ProtocolVersionsOwner, "ProtocolVersionsOwner should be populated for v1") + require.Equal(t, common.Address{}, st.SuperchainDeployment.ProtocolVersionsProxy, "ProtocolVersionsProxy should be zero") + require.Equal(t, common.Address{}, st.SuperchainDeployment.ProtocolVersionsImpl, "ProtocolVersionsImpl should be zero") + require.Equal(t, common.Address{}, st.SuperchainRoles.ProtocolVersionsOwner, "ProtocolVersionsOwner should be zero") // Verify ImplementationsDeployment was set require.NotNil(t, st.ImplementationsDeployment) - require.Equal(t, opcmAddr, st.ImplementationsDeployment.OpcmImpl) + require.Equal(t, opcmAddr, st.ImplementationsDeployment.OpcmV2Impl) } // Validates that the correct flow is chosen when diff --git a/op-deployer/pkg/deployer/pipeline/opchain.go b/op-deployer/pkg/deployer/pipeline/opchain.go index c923bc54aeb..65577f7a72a 100644 --- a/op-deployer/pkg/deployer/pipeline/opchain.go +++ b/op-deployer/pkg/deployer/pipeline/opchain.go @@ -92,7 +92,6 @@ func DeployOPChain(env *Env, intent *state.Intent, st *state.State, chainID comm st.ImplementationsDeployment.DelayedWethImpl = impls.DelayedWETH st.ImplementationsDeployment.OptimismPortalImpl = impls.OptimismPortal - st.ImplementationsDeployment.OptimismPortalInteropImpl = impls.OptimismPortalInterop st.ImplementationsDeployment.EthLockboxImpl = impls.EthLockbox st.ImplementationsDeployment.SystemConfigImpl = impls.SystemConfig st.ImplementationsDeployment.AnchorStateRegistryImpl = impls.AnchorStateRegistry @@ -131,15 +130,7 @@ func makeDCI(intent *state.Intent, thisIntent *state.ChainIntent, chainID common return opcm.DeployOPChainInput{}, fmt.Errorf("error merging proof params from overrides: %w", err) } - // Select which OPCM to use based on dev feature flag - opcmAddr := st.ImplementationsDeployment.OpcmImpl - if devFeatureBitmap, ok := intent.GlobalDeployOverrides["devFeatureBitmap"].(common.Hash); ok { - // TODO(#19151): Replace this with the OPCMV2DevFlag constant when we fix import cycles. - opcmV2Flag := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000010000") - if isDevFeatureEnabled(devFeatureBitmap, opcmV2Flag) { - opcmAddr = st.ImplementationsDeployment.OpcmV2Impl - } - } + opcmAddr := st.ImplementationsDeployment.OpcmV2Impl if opcmAddr == (common.Address{}) { return opcm.DeployOPChainInput{}, fmt.Errorf("OPCM implementation is not deployed") } diff --git a/op-deployer/pkg/deployer/pipeline/opchain_test.go b/op-deployer/pkg/deployer/pipeline/opchain_test.go index 4d8790645a3..9c58598ecb7 100644 --- a/op-deployer/pkg/deployer/pipeline/opchain_test.go +++ b/op-deployer/pkg/deployer/pipeline/opchain_test.go @@ -26,9 +26,7 @@ import ( ) func Test_makeDCI_OpcmAddress(t *testing.T) { - opcmV1Addr := common.HexToAddress("0x1111111111111111111111111111111111111111") opcmV2Addr := common.HexToAddress("0x2222222222222222222222222222222222222222") - opcmV2Flag := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000010000") chainID := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000300") salt := common.HexToHash("0x1234567890123456789012345678901234567890123456789012345678901234") superchainConfig := common.HexToAddress("0x3333333333333333333333333333333333333333") @@ -50,16 +48,6 @@ func Test_makeDCI_OpcmAddress(t *testing.T) { GasLimit: 60_000_000, } - baseState := &state.State{ - Create2Salt: salt, - SuperchainDeployment: &addresses.SuperchainContracts{ - SuperchainConfigProxy: superchainConfig, - }, - ImplementationsDeployment: &addresses.ImplementationsContracts{ - OpcmImpl: opcmV1Addr, - }, - } - tests := []struct { name string intent *state.Intent @@ -71,22 +59,8 @@ func Test_makeDCI_OpcmAddress(t *testing.T) { expectedErrMsg string }{ { - name: "default_uses_opcm_v1", - intent: baseIntent, - thisIntent: baseChainIntent, - chainID: chainID, - st: baseState, - expectedOpcm: opcmV1Addr, - shouldThrowErr: false, - expectedErrMsg: "", - }, - { - name: "opcm_v2_flag_enabled_with_v2_impl_uses_v2", - intent: &state.Intent{ - GlobalDeployOverrides: map[string]any{ - "devFeatureBitmap": opcmV2Flag, - }, - }, + name: "uses_opcm_v2", + intent: baseIntent, thisIntent: baseChainIntent, chainID: chainID, st: &state.State{ @@ -95,7 +69,6 @@ func Test_makeDCI_OpcmAddress(t *testing.T) { SuperchainConfigProxy: superchainConfig, }, ImplementationsDeployment: &addresses.ImplementationsContracts{ - OpcmImpl: opcmV1Addr, OpcmV2Impl: opcmV2Addr, }, }, @@ -104,30 +77,7 @@ func Test_makeDCI_OpcmAddress(t *testing.T) { expectedErrMsg: "", }, { - name: "opcm_v2_flag_enabled_but_v2_impl_zero_reverts", - intent: &state.Intent{ - GlobalDeployOverrides: map[string]any{ - "devFeatureBitmap": opcmV2Flag, - }, - }, - thisIntent: baseChainIntent, - chainID: chainID, - st: &state.State{ - Create2Salt: salt, - SuperchainDeployment: &addresses.SuperchainContracts{ - SuperchainConfigProxy: superchainConfig, - }, - ImplementationsDeployment: &addresses.ImplementationsContracts{ - OpcmImpl: opcmV1Addr, - OpcmV2Impl: common.Address{}, // zero address - }, - }, - expectedOpcm: common.Address{}, - shouldThrowErr: true, - expectedErrMsg: "OPCM implementation is not deployed", - }, - { - name: "opcm_v2_flag_disabled_but_opcm_impl_zero_reverts", + name: "opcm_v2_impl_zero_reverts", intent: baseIntent, thisIntent: baseChainIntent, chainID: chainID, @@ -137,58 +87,13 @@ func Test_makeDCI_OpcmAddress(t *testing.T) { SuperchainConfigProxy: superchainConfig, }, ImplementationsDeployment: &addresses.ImplementationsContracts{ - OpcmImpl: common.Address{}, // zero address - OpcmV2Impl: opcmV2Addr, + OpcmV2Impl: common.Address{}, // zero address }, }, expectedOpcm: common.Address{}, shouldThrowErr: true, expectedErrMsg: "OPCM implementation is not deployed", }, - { - name: "opcm_v2_flag_not_enabled_uses_v1_even_if_v2_impl_set", - intent: &state.Intent{ - GlobalDeployOverrides: map[string]any{ - "devFeatureBitmap": common.Hash{}, // flag not set - }, - }, - thisIntent: baseChainIntent, - chainID: chainID, - st: &state.State{ - Create2Salt: salt, - SuperchainDeployment: &addresses.SuperchainContracts{ - SuperchainConfigProxy: superchainConfig, - }, - ImplementationsDeployment: &addresses.ImplementationsContracts{ - OpcmImpl: opcmV1Addr, - OpcmV2Impl: opcmV2Addr, - }, - }, - expectedOpcm: opcmV1Addr, - shouldThrowErr: false, - expectedErrMsg: "", - }, - { - name: "no_dev_feature_bitmap_uses_v1", - intent: &state.Intent{ - GlobalDeployOverrides: make(map[string]any), // no devFeatureBitmap key - }, - thisIntent: baseChainIntent, - chainID: chainID, - st: &state.State{ - Create2Salt: salt, - SuperchainDeployment: &addresses.SuperchainContracts{ - SuperchainConfigProxy: superchainConfig, - }, - ImplementationsDeployment: &addresses.ImplementationsContracts{ - OpcmImpl: opcmV1Addr, - OpcmV2Impl: opcmV2Addr, - }, - }, - expectedOpcm: opcmV1Addr, - shouldThrowErr: false, - expectedErrMsg: "", - }, } for _, tt := range tests { diff --git a/op-deployer/pkg/deployer/verify/artifacts.go b/op-deployer/pkg/deployer/verify/artifacts.go index 4bb10d5cd06..91eb3a5dcb8 100644 --- a/op-deployer/pkg/deployer/verify/artifacts.go +++ b/op-deployer/pkg/deployer/verify/artifacts.go @@ -36,12 +36,7 @@ var contractNameExceptions = map[string]string{ "OptimismPortal": "OptimismPortal2.sol/OptimismPortal2.json", "L1StandardBridgeProxy": "L1ChugSplashProxy.sol/L1ChugSplashProxy.json", "L1CrossDomainMessengerProxy": "ResolvedDelegateProxy.sol/ResolvedDelegateProxy.json", - "Opcm": "OPContractsManager.sol/OPContractsManager.json", - "OpcmContractsContainer": "OPContractsManager.sol/OPContractsManagerContractsContainer.json", - "OpcmGameTypeAdder": "OPContractsManager.sol/OPContractsManagerGameTypeAdder.json", - "OpcmDeployer": "OPContractsManager.sol/OPContractsManagerDeployer.json", - "OpcmUpgrader": "OPContractsManager.sol/OPContractsManagerUpgrader.json", - "OpcmInteropMigrator": "OPContractsManager.sol/OPContractsManagerInteropMigrator.json", + "Opcm": "OPContractsManagerV2.sol/OPContractsManagerV2.json", "OpcmStandardValidator": "OPContractsManagerStandardValidator.sol/OPContractsManagerStandardValidator.json", "OpcmMigrator": "OPContractsManagerMigrator.sol/OPContractsManagerMigrator.json", "OpcmV2": "OPContractsManagerV2.sol/OPContractsManagerV2.json", diff --git a/op-deployer/pkg/deployer/verify/artifacts_test.go b/op-deployer/pkg/deployer/verify/artifacts_test.go index 151b4b4998a..c2e5b03f285 100644 --- a/op-deployer/pkg/deployer/verify/artifacts_test.go +++ b/op-deployer/pkg/deployer/verify/artifacts_test.go @@ -10,7 +10,7 @@ func TestGetArtifactPath(t *testing.T) { "superchain_superchain_config_proxy": "Proxy.sol/Proxy.json", "superchain_protocol_versions_proxy": "Proxy.sol/Proxy.json", "superchain_superchain_config_impl": "SuperchainConfig.sol/SuperchainConfig.json", - "implementations_opcm_impl": "OPContractsManager.sol/OPContractsManager.json", + "implementations_opcm_impl": "OPContractsManagerV2.sol/OPContractsManagerV2.json", } for contractName, expectedPath := range testCases { diff --git a/op-devstack/devtest/testing.go b/op-devstack/devtest/testing.go index 2df4175d231..1439e3a2185 100644 --- a/op-devstack/devtest/testing.go +++ b/op-devstack/devtest/testing.go @@ -133,10 +133,10 @@ func (t *testingT) Error(args ...any) { t.skipFlakyFailure(fmt.Sprintln(args...)) return } - // Note: the test-logger catches panics when the test is logged to after test-end. - // Note: we do not use t.Error directly, to keep the log-formatting more consistent. - t.logger.Error(fmt.Sprintln(args...)) - t.Fail() + // Write directly to testing.T, not the structured logger. The structured logger's + // terminal handler quotes messages containing '=' (via escapeMessage/strconv.Quote), + // which escapes all \n and \t, making testify's multi-line assertion diffs unreadable. + t.t.Error(args...) } func (t *testingT) Errorf(format string, args ...any) { @@ -145,10 +145,10 @@ func (t *testingT) Errorf(format string, args ...any) { t.skipFlakyFailure(fmt.Sprintf(format, args...)) return } - // Note: the test-logger catches panics when the test is logged to after test-end. - // Note: we do not use t.Errorf directly, to keep the log-formatting more consistent. - t.logger.Error(fmt.Sprintf(format, args...)) - t.Fail() + // Write directly to testing.T, not the structured logger. The structured logger's + // terminal handler quotes messages containing '=' (via escapeMessage/strconv.Quote), + // which escapes all \n and \t, making testify's multi-line assertion diffs unreadable. + t.t.Errorf(format, args...) } func (t *testingT) Fail() { diff --git a/op-devstack/dsl/bridge.go b/op-devstack/dsl/bridge.go index b1bd6a88596..7f6aa80c317 100644 --- a/op-devstack/dsl/bridge.go +++ b/op-devstack/dsl/bridge.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "math/big" - "strings" "time" "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" @@ -129,15 +128,11 @@ func (b *StandardBridge) PortalVersion() string { } func (b *StandardBridge) UsesSuperRoots() bool { - // Only interop contracts have SuperRootsActive functionality - version := b.PortalVersion() - if !strings.HasSuffix(version, "+interop") { - return false - } - - superRootsActive, err := contractio.Read(b.l1Portal.SuperRootsActive(), b.ctx) - b.require.NoError(err, "Failed to read super roots active") - return superRootsActive + gameType := gameTypes.GameType(b.RespectedGameType()) + return gameType == gameTypes.SuperCannonGameType || + gameType == gameTypes.SuperPermissionedGameType || + gameType == gameTypes.SuperAsteriscKonaGameType || + gameType == gameTypes.SuperCannonKonaGameType } type Deposit struct { diff --git a/op-devstack/dsl/deposit_eoa.go b/op-devstack/dsl/deposit_eoa.go new file mode 100644 index 00000000000..b166fa044cd --- /dev/null +++ b/op-devstack/dsl/deposit_eoa.go @@ -0,0 +1,101 @@ +package dsl + +import ( + "math/rand" + + "github.com/ethereum-optimism/optimism/op-node/rollup/derive" + "github.com/ethereum-optimism/optimism/op-service/bigs" + "github.com/ethereum-optimism/optimism/op-service/eth" + "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" + "github.com/ethereum-optimism/optimism/op-service/txintent/contractio" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +// DepositEOA wraps an L2 EOA so that transactions are sent via L1 deposit +// transactions rather than direct L2 transactions. +type DepositEOA struct { + l2 *EOA // the L2 identity (for chain ID, block refs, etc.) + l1 *EOA // the L1 identity (for sending the deposit tx) + l2EL *L2ELNode // L2 EL node to wait for derivation and fetch receipts + l2Net *L2Network // L2 network for deposit contract address +} + +// ViaDepositTx returns a DepositEOA that sends transactions through L1 +// deposit transactions. The caller must fund both the L1 and L2 identities. +func (u *EOA) ViaDepositTx(l1 *EOA, l2EL *L2ELNode, l2Net *L2Network) *DepositEOA { + return &DepositEOA{l2: u, l1: l1, l2EL: l2EL, l2Net: l2Net} +} + +// DepositTx sends a transaction to the given address with the given calldata +// via OptimismPortal2 on L1. It waits for L2 derivation and returns the L2 receipt. +func (d *DepositEOA) DepositTx(to common.Address, calldata []byte) *ethtypes.Receipt { + t := d.l2.t + ctx := d.l2.ctx + + portalAddr := d.l2Net.DepositContractAddr() + l1Client := d.l1.el.stackEL().EthClient() + portal := bindings.NewBindings[bindings.OptimismPortal2]( + bindings.WithClient(l1Client), + bindings.WithTo(portalAddr), + bindings.WithTest(t), + ) + + minGas, err := contractio.Read(portal.MinimumGasLimit(uint64(len(calldata))), ctx) + t.Require().NoError(err, "failed to read MinimumGasLimit") + depositCall := portal.DepositTransaction(to, eth.ZeroWei, max(100_000, minGas), false, calldata) + l1Receipt, err := contractio.Write(depositCall, ctx, d.l1.Plan()) + t.Require().NoError(err, "L1 deposit tx failed") + t.Require().Equal(ethtypes.ReceiptStatusSuccessful, l1Receipt.Status, "L1 deposit tx reverted") + + var l2DepositTx *ethtypes.DepositTx + for _, log := range l1Receipt.Logs { + if l2DepositTx, err = derive.UnmarshalDepositLogEvent(log); err == nil { + break + } + } + t.Require().NotNil(l2DepositTx, "no TransactionDeposited event in L1 receipt") + + d.l2EL.WaitL1OriginReached(eth.Unsafe, bigs.Uint64Strict(l1Receipt.BlockNumber), 120) + l2Receipt := d.l2EL.WaitForReceipt(ethtypes.NewTx(l2DepositTx).Hash()) + t.Require().Equal(ethtypes.ReceiptStatusSuccessful, l2Receipt.Status, "deposit tx failed on L2") + return l2Receipt +} + +// SendInitMessage sends an initiating message via an L1 deposit transaction. +// Returns an InitMessage with InteropOutput populated from the L2 receipt, +// fully compatible with SendExecMessage on the receiving chain. +func (d *DepositEOA) SendInitMessage(trigger *txintent.InitTrigger) *InitMessage { + t := d.l2.t + + calldata, err := trigger.EncodeInput() + t.Require().NoError(err, "failed to encode InitTrigger calldata") + + l2Receipt := d.DepositTx(trigger.Emitter, calldata) + t.Require().NotZero(len(l2Receipt.Logs), "deposit tx emitted no logs on L2") + + l2BlockRef := d.l2EL.BlockRefByNumber(bigs.Uint64Strict(l2Receipt.BlockNumber)) + var result txintent.InteropOutput + err = result.FromReceipt(d.l2.ctx, l2Receipt, l2BlockRef.BlockRef(), d.l2.ChainID()) + t.Require().NoError(err, "failed to build InteropOutput from L2 deposit receipt") + + tx := &txintent.IntentTx[*txintent.InitTrigger, *txintent.InteropOutput]{} + tx.Result.Set(&result) + return &InitMessage{Tx: tx, Receipt: l2Receipt} +} + +// SendRandomInitMessage creates a random initiating message and sends it via L1 deposit. +func (d *DepositEOA) SendRandomInitMessage(rng *rand.Rand, eventLoggerAddress common.Address) *InitMessage { + topics := make([][32]byte, 2) + for i := range topics { + copy(topics[i][:], testutils.RandomData(rng, 32)) + } + trigger := &txintent.InitTrigger{ + Emitter: eventLoggerAddress, + Topics: topics, + OpaqueData: testutils.RandomData(rng, 10), + } + return d.SendInitMessage(trigger) +} diff --git a/op-devstack/dsl/eoa.go b/op-devstack/dsl/eoa.go index a2cc5d6e65d..fea2835b17a 100644 --- a/op-devstack/dsl/eoa.go +++ b/op-devstack/dsl/eoa.go @@ -288,15 +288,48 @@ func (u *EOA) SendRandomInitMessage(rng *rand.Rand, eventLoggerAddress common.Ad return u.SendInitMessage(trigger) } -func (u *EOA) SendExecMessage(initMsg *InitMessage) *ExecMessage { - tx := txintent.NewIntent[*txintent.ExecTrigger, *txintent.InteropOutput](u.Plan()) +// ExecMessageOpt configures the behavior of SendExecMessage. +type ExecMessageOpt func(*execMessageConfig) + +type execMessageConfig struct { + txOpts []txplan.Option + expectRevert bool +} + +// WithFixedGasLimit sets a fixed gas limit, bypassing eth_estimateGas. +// Use when the transaction is expected to revert (estimation would fail). +func WithFixedGasLimit(limit uint64) ExecMessageOpt { + return func(c *execMessageConfig) { + c.txOpts = append(c.txOpts, txplan.WithGasLimit(limit)) + } +} + +// WithExpectRevert indicates the transaction should be included but revert. +// The receipt status is asserted to be failed, and the log-count check is skipped. +func WithExpectRevert() ExecMessageOpt { + return func(c *execMessageConfig) { + c.expectRevert = true + } +} + +func (u *EOA) SendExecMessage(initMsg *InitMessage, opts ...ExecMessageOpt) *ExecMessage { + var cfg execMessageConfig + for _, o := range opts { + o(&cfg) + } + planOpts := append([]txplan.Option{u.Plan()}, cfg.txOpts...) + tx := txintent.NewIntent[*txintent.ExecTrigger, *txintent.InteropOutput](txplan.Combine(planOpts...)) tx.Content.DependOn(&initMsg.Tx.Result) tx.Content.Fn(txintent.ExecuteIndexed(predeploys.CrossL2InboxAddr, &initMsg.Tx.Result, 0)) receipt, err := tx.PlannedTx.Included.Eval(u.ctx) u.t.Require().NoError(err, "exec msg receipt not found") - u.log.Info("exec message included", "chain", u.ChainID(), "block", receipt.BlockNumber) - // Check single ExecutingMessage triggered - u.t.Require().Equal(1, len(receipt.Logs)) + if cfg.expectRevert { + u.t.Require().Equal(types.ReceiptStatusFailed, receipt.Status, "exec tx should revert") + } else { + u.log.Info("exec message included", "chain", u.ChainID(), "block", receipt.BlockNumber) + // Check single ExecutingMessage triggered + u.t.Require().Equal(1, len(receipt.Logs)) + } return &ExecMessage{ Init: initMsg, Tx: tx, diff --git a/op-devstack/dsl/l2_el.go b/op-devstack/dsl/l2_el.go index a5e11b570d9..b3417065f63 100644 --- a/op-devstack/dsl/l2_el.go +++ b/op-devstack/dsl/l2_el.go @@ -235,6 +235,34 @@ func (el *L2ELNode) WaitL1OriginReached(label eth.BlockLabel, l1OriginTarget uin el.require.NoError(el.L1OriginReachedFn(label, l1OriginTarget, attempts)()) } +// WaitL1OriginHash polls until the L2 chain at the given label references the target L1 block. +// If the head's L1 origin has advanced past the target number (e.g. due to a large batch), +// it walks back through L2 blocks to find one with the target L1 origin number and checks its hash. +func (el *L2ELNode) WaitL1OriginHash(label eth.BlockLabel, target eth.BlockID, attempts int) { + logger := el.log.With("name", el.inner.Name(), "chain", el.ChainID(), "label", label, "target", target) + logger.Info("Expecting L2EL L1 origin to match") + el.require.NoError(retry.Do0(el.ctx, attempts, &retry.FixedStrategy{Dur: 2 * time.Second}, + func() error { + head := el.BlockRefByLabel(label) + if head.L1Origin.Number < target.Number { + logger.Debug("L2EL L1 origin not yet reached", "head", head.ID(), "l1Origin", head.L1Origin) + return fmt.Errorf("L1 origin of %s head has not reached target yet", label) + } + // Head's L1 origin is at or past the target number. Walk back to find + // the L2 block whose L1 origin number matches the target. + block := head + for block.L1Origin.Number > target.Number && block.Number > 0 { + block = el.BlockRefByNumber(block.Number - 1) + } + if block.L1Origin.Hash == target.Hash { + logger.Info("L2EL L1 origin matched", "l2Block", block.ID(), "l1Origin", block.L1Origin) + return nil + } + logger.Debug("L2EL L1 origin hash mismatch", "l2Block", block.ID(), "l1Origin", block.L1Origin) + return fmt.Errorf("L1 origin hash of %s head does not match target", label) + })) +} + // VerifyWithdrawalHashChangedIn verifies that the withdrawal hash changed between the parent and current block // This is used to verify that the withdrawal hash changed in the block where the withdrawal was initiated func (el *L2ELNode) VerifyWithdrawalHashChangedIn(blockHash common.Hash) { diff --git a/op-devstack/shared/challenger/challenger.go b/op-devstack/shared/challenger/challenger.go index 65e59be5d61..42bfafd221f 100644 --- a/op-devstack/shared/challenger/challenger.go +++ b/op-devstack/shared/challenger/challenger.go @@ -5,7 +5,6 @@ import ( "encoding/json" "errors" "fmt" - "net/url" "os" "path/filepath" "time" @@ -81,20 +80,10 @@ func applyCannonKonaConfig(c *config.Config, rollupCfgs []*rollup.Config, l1Gene return err } c.CannonKona.Server = root + "rust/target/release/kona-host" - absRoot, err := filepath.Abs(root) - if err != nil { - return fmt.Errorf("failed to get absolute path to prestate dir: %w", err) - } if interop { - c.CannonKonaAbsolutePreStateBaseURL, err = url.Parse("file:" + absRoot + "/rust/kona/prestate-artifacts-cannon-interop") - if err != nil { - return err - } + c.CannonKonaAbsolutePreState = root + "rust/kona/prestate-artifacts-cannon-interop/prestate.bin.gz" } else { - c.CannonKonaAbsolutePreStateBaseURL, err = url.Parse("file:" + absRoot + "/rust/kona/prestate-artifacts-cannon") - if err != nil { - return err - } + c.CannonKonaAbsolutePreState = root + "rust/kona/prestate-artifacts-cannon/prestate.bin.gz" } return nil } @@ -245,6 +234,7 @@ func NewPreInteropChallengerConfig(dir string, l1Endpoint string, l1Beacon strin func applyCommonChallengerOpts(cfg *config.Config, options ...Option) error { cfg.Cannon.L2Custom = true + cfg.CannonKona.L2Custom = true // The devnet can't set the absolute prestate output root because the contracts are deployed in L1 genesis // before the L2 genesis is known. cfg.AllowInvalidPrestate = true diff --git a/op-devstack/sysgo/add_game_type.go b/op-devstack/sysgo/add_game_type.go index 1b059dc6a5c..d8d08bfc0cf 100644 --- a/op-devstack/sysgo/add_game_type.go +++ b/op-devstack/sysgo/add_game_type.go @@ -10,10 +10,13 @@ import ( "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/manage" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/upgrade/embedded" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" "github.com/ethereum-optimism/optimism/op-devstack/devtest" op_service "github.com/ethereum-optimism/optimism/op-service" "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/ioutil" "github.com/ethereum-optimism/optimism/op-service/retry" "github.com/ethereum-optimism/optimism/op-service/txintent/bindings" "github.com/ethereum-optimism/optimism/op-service/txintent/contractio" @@ -79,11 +82,13 @@ func setRespectedGameTypeForRuntime( require.Equal(rcpt.Status, gethTypes.ReceiptStatusSuccessful, "set respected game type tx did not execute correctly") } -func addGameTypeForRuntime( +// addGameTypesForRuntime uses OPCMv2.upgrade to configure dispute game types. +// The V2 upgrade requires exactly 3 game configs (CANNON, PERMISSIONED_CANNON, CANNON_KONA) +// in that order. Game types in enabledGameTypes are enabled; the rest are disabled. +func addGameTypesForRuntime( t devtest.T, keys devkeys.Keys, - absolutePrestate common.Hash, - gameType gameTypes.GameType, + enabledGameTypes []gameTypes.GameType, l1ChainID eth.ChainID, l1ELRPC string, l2Net *L2Network, @@ -92,47 +97,130 @@ func addGameTypeForRuntime( require.NotNil(l2Net, "l2 network must exist") require.NotNil(l2Net.deployment, "l2 deployment must exist") require.NotEqual(common.Address{}, l2Net.opcmImpl, "missing OPCM implementation address") - require.NotEqual(common.Address{}, l2Net.mipsImpl, "missing MIPS implementation address") rpcClient, err := rpc.DialContext(t.Ctx(), l1ELRPC) require.NoError(err) defer rpcClient.Close() client := ethclient.NewClient(rpcClient) - l1PAO, err := keys.Address(devkeys.ChainOperatorKeys(l1ChainID.ToBig())(devkeys.L1ProxyAdminOwnerRole)) + chainOps := devkeys.ChainOperatorKeys(l1ChainID.ToBig()) + + l1PAO, err := keys.Address(chainOps(devkeys.L1ProxyAdminOwnerRole)) require.NoError(err, "failed to get l1 proxy admin owner address") - cfg := manage.AddGameTypeConfig{ - L1RPCUrl: l1ELRPC, - Logger: t.Logger(), - ArtifactsLocator: LocalArtifacts(t), - CacheDir: t.TempDir(), - L1ProxyAdminOwner: l1PAO, - OPCMImpl: l2Net.opcmImpl, - SystemConfigProxy: l2Net.deployment.SystemConfigProxyAddr(), - DelayedWETHProxy: l2Net.deployment.PermissionlessDelayedWETHProxyAddr(), - DisputeGameType: uint32(gameType), - DisputeAbsolutePrestate: absolutePrestate, - DisputeMaxGameDepth: big.NewInt(73), - DisputeSplitDepth: big.NewInt(30), - DisputeClockExtension: 10800, - DisputeMaxClockDuration: 302400, - InitialBond: eth.GWei(80_000_000).ToBig(), // 0.08 ETH - VM: l2Net.mipsImpl, - Permissionless: true, - SaltMixer: fmt.Sprintf("devstack-%s-%s", l2Net.ChainID(), absolutePrestate.Hex()), + proposer, err := keys.Address(chainOps(devkeys.ProposerRole)) + require.NoError(err, "failed to get proposer address") + + challenger, err := keys.Address(chainOps(devkeys.ChallengerRole)) + require.NoError(err, "failed to get challenger address") + + // Build enabled set for quick lookup. + enabled := make(map[gameTypes.GameType]bool) + for _, gt := range enabledGameTypes { + enabled[gt] = true + } + + initBond := eth.GWei(80_000_000).ToBig() // 0.08 ETH + + // OPCMv2 requires all 6 game configs in order: + // CANNON, PERMISSIONED_CANNON, CANNON_KONA, SUPER_CANNON, SUPER_PERMISSIONED_CANNON, SUPER_CANNON_KONA. + cannonPrestate := PrestateForGameType(t, gameTypes.CannonGameType) + cannonKonaPrestate := PrestateForGameType(t, gameTypes.CannonKonaGameType) + + configs := []embedded.DisputeGameConfig{ + { + Enabled: enabled[gameTypes.CannonGameType], + InitBond: initBond, + GameType: embedded.GameTypeCannon, + FaultDisputeGameConfig: &embedded.FaultDisputeGameConfig{ + AbsolutePrestate: cannonPrestate, + }, + }, + { + Enabled: true, // Permissioned cannon is always enabled. + InitBond: initBond, + GameType: embedded.GameTypePermissionedCannon, + PermissionedDisputeGameConfig: &embedded.PermissionedDisputeGameConfig{ + AbsolutePrestate: cannonPrestate, + Proposer: proposer, + Challenger: challenger, + }, + }, + { + Enabled: enabled[gameTypes.CannonKonaGameType], + InitBond: initBond, + GameType: embedded.GameTypeCannonKona, + FaultDisputeGameConfig: &embedded.FaultDisputeGameConfig{ + AbsolutePrestate: cannonKonaPrestate, + }, + }, + { + Enabled: false, + InitBond: new(big.Int), + GameType: embedded.GameTypeSuperCannon, + }, + { + Enabled: false, + InitBond: new(big.Int), + GameType: embedded.GameTypeSuperPermCannon, + }, + { + Enabled: false, + InitBond: new(big.Int), + GameType: embedded.GameTypeSuperCannonKona, + }, } - _, addGameTypeCalldata, err := manage.AddGameType(t.Ctx(), cfg) - require.NoError(err, "failed to create add game type calldata") - require.Len(addGameTypeCalldata, 1, "calldata must contain one entry") + // Zero out init bond for disabled games. + for i := range configs { + if !configs[i].Enabled { + configs[i].InitBond = new(big.Int) + } + } + + upgradeInput := embedded.UpgradeOPChainInput{ + Prank: l1PAO, + Opcm: l2Net.opcmImpl, + UpgradeInputV2: &embedded.UpgradeInputV2{ + SystemConfig: l2Net.deployment.SystemConfigProxyAddr(), + DisputeGameConfigs: configs, + ExtraInstructions: []embedded.ExtraInstruction{ + { + Key: "PermittedProxyDeployment", + Data: []byte("DelayedWETH"), + }, + }, + }, + } + + // Run UpgradeOPChain.s.sol via a forked script host to produce calldata. + loc := LocalArtifacts(t) + artifactsFS, err := artifacts.Download(t.Ctx(), loc, ioutil.NoopProgressor(), t.TempDir()) + require.NoError(err, "failed to download artifacts") + + bcaster := new(broadcaster.CalldataBroadcaster) + host, err := env.DefaultForkedScriptHost( + t.Ctx(), + bcaster, + t.Logger(), + common.Address{'D'}, + artifactsFS, + rpcClient, + ) + require.NoError(err, "failed to create script host") + + err = embedded.Upgrade(host, upgradeInput) + require.NoError(err, "failed to run upgrade script for add game types") + + calldata, err := bcaster.Dump() + require.NoError(err, "failed to dump calldata") + require.Len(calldata, 1, "calldata must contain one entry") - chainOps := devkeys.ChainOperatorKeys(l1ChainID.ToBig()) l1PAOKey, err := keys.Secret(chainOps(devkeys.L1ProxyAdminOwnerRole)) require.NoError(err, "failed to get l1 proxy admin owner key") - t.Log("Executing opcm.addGameType via SetCode delegatecall") - delegateCallWithSetCode(t, l1PAOKey, client, l2Net.opcmImpl, addGameTypeCalldata[0].Data) + t.Log("Executing opcmV2.upgrade via SetCode delegatecall") + delegateCallWithSetCode(t, l1PAOKey, client, l2Net.opcmImpl, calldata[0].Data) } func PrestateForGameType(t devtest.CommonT, gameType gameTypes.GameType) common.Hash { diff --git a/op-devstack/sysgo/engine_client.go b/op-devstack/sysgo/engine_client.go index 325acb7cf29..be49f998ea1 100644 --- a/op-devstack/sysgo/engine_client.go +++ b/op-devstack/sysgo/engine_client.go @@ -28,20 +28,20 @@ func dialEngine(ctx context.Context, endpoint string, jwtSecret [32]byte) (*engi var _ geth.EngineAPI = (*engineClient)(nil) -func (e *engineClient) forkchoiceUpdated(fs engine.ForkchoiceStateV1, pa *engine.PayloadAttributes, method string) (engine.ForkChoiceResponse, error) { +func (e *engineClient) forkchoiceUpdated(ctx context.Context, fs engine.ForkchoiceStateV1, pa *engine.PayloadAttributes, method string) (engine.ForkChoiceResponse, error) { var x engine.ForkChoiceResponse - if err := e.inner.CallContext(context.Background(), &x, method, fs, pa); err != nil { + if err := e.inner.CallContext(ctx, &x, method, fs, pa); err != nil { return engine.ForkChoiceResponse{}, err } return x, nil } -func (e *engineClient) ForkchoiceUpdatedV2(fs engine.ForkchoiceStateV1, pa *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { - return e.forkchoiceUpdated(fs, pa, "engine_forkchoiceUpdatedV2") +func (e *engineClient) ForkchoiceUpdatedV2(ctx context.Context, fs engine.ForkchoiceStateV1, pa *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { + return e.forkchoiceUpdated(ctx, fs, pa, "engine_forkchoiceUpdatedV2") } -func (e *engineClient) ForkchoiceUpdatedV3(fs engine.ForkchoiceStateV1, pa *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { - return e.forkchoiceUpdated(fs, pa, "engine_forkchoiceUpdatedV3") +func (e *engineClient) ForkchoiceUpdatedV3(ctx context.Context, fs engine.ForkchoiceStateV1, pa *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) { + return e.forkchoiceUpdated(ctx, fs, pa, "engine_forkchoiceUpdatedV3") } func (e *engineClient) getPayload(id engine.PayloadID, method string) (*engine.ExecutionPayloadEnvelope, error) { diff --git a/op-devstack/sysgo/l2_cl.go b/op-devstack/sysgo/l2_cl.go index 009e55d85c3..37756484751 100644 --- a/op-devstack/sysgo/l2_cl.go +++ b/op-devstack/sysgo/l2_cl.go @@ -63,7 +63,7 @@ func DefaultL2CLConfig() *L2CLConfig { IsSequencer: false, IndexingMode: false, EnableReqRespSync: true, - UseReqRespSync: true, + UseReqRespSync: false, NoDiscovery: false, FollowSource: "", } diff --git a/op-devstack/sysgo/mixed_runtime.go b/op-devstack/sysgo/mixed_runtime.go index d3de1b786fb..614cbdb0fd0 100644 --- a/op-devstack/sysgo/mixed_runtime.go +++ b/op-devstack/sysgo/mixed_runtime.go @@ -42,21 +42,11 @@ import ( type MixedL2ELKind string -const DevstackL2ELKindEnvVar = "DEVSTACK_L2EL_KIND" - const ( MixedL2ELOpGeth MixedL2ELKind = "op-geth" MixedL2ELOpReth MixedL2ELKind = "op-reth" ) -// SkipUnlessOpGeth skips the test when the L2 execution layer is op-reth -// (i.e. DEVSTACK_L2EL_KIND is not "op-geth"). -func SkipUnlessOpGeth(t devtest.T, reason string) { - if MixedL2ELKind(os.Getenv(DevstackL2ELKindEnvVar)) != MixedL2ELOpGeth { - t.Skipf("skipping on op-reth: %s", reason) - } -} - type MixedL2CLKind string const ( @@ -64,11 +54,37 @@ const ( MixedL2CLKona MixedL2CLKind = "kona-node" ) +// SkipOnOpReth skips the test when the L2 execution layer is op-reth +func SkipOnOpReth(t devtest.T, reason string) { + if devstackL2ELKind() == MixedL2ELOpReth { + t.Skipf("skipping on op-reth: %s", reason) + } +} + +// SkipOnKonaNode skips the test when the L2 consensus layer is kona-node +func SkipOnKonaNode(t devtest.T, reason string) { + if devstackL2CLKind() == MixedL2CLKona { + t.Skipf("skipping on kona-node: %s", reason) + } +} + +func FlakyOnOpReth(t devtest.T, reason string) { + if devstackL2ELKind() == MixedL2ELOpReth { + t.MarkFlaky(reason) + } +} + +func FlakyOnKonaNode(t devtest.T, reason string) { + if devstackL2CLKind() == MixedL2CLKona { + t.MarkFlaky(reason) + } +} + // devstackL2ELKind returns the L2 EL kind requested via the DEVSTACK_L2EL_KIND // environment variable. Returns the empty string when the variable is unset, // meaning "use the runtime's default". func devstackL2ELKind() MixedL2ELKind { - return MixedL2ELKind(os.Getenv(DevstackL2ELKindEnvVar)) + return MixedL2ELKind(os.Getenv("DEVSTACK_L2EL_KIND")) } // devstackL2CLKind returns the L2 CL kind requested via the DEVSTACK_L2CL_KIND @@ -331,8 +347,8 @@ func startMixedOpRethNode( "--chain=" + chainConfigPath, "--proofs-history.storage-path=" + proofHistoryDir, } - err = exec.Command(execPath, initProofsArgs...).Run() - t.Require().NoError(err, "must init op-reth proof history") + initOut, initErr := exec.Command(execPath, initProofsArgs...).CombinedOutput() + t.Require().NoError(initErr, "must init op-reth proof history: %s", string(initOut)) args = append( args, diff --git a/op-devstack/sysgo/multichain_supernode_runtime.go b/op-devstack/sysgo/multichain_supernode_runtime.go index 6579df4d38a..ffe4568e05a 100644 --- a/op-devstack/sysgo/multichain_supernode_runtime.go +++ b/op-devstack/sysgo/multichain_supernode_runtime.go @@ -303,7 +303,7 @@ func l2NetworkFromWorldBuilder(t devtest.T, wb *worldBuilder, l1ChainID, l2Chain genesis: l2Genesis, rollupCfg: l2RollupCfg, deployment: l2Dep, - opcmImpl: wb.output.ImplementationsDeployment.OpcmImpl, + opcmImpl: wb.output.ImplementationsDeployment.OpcmV2Impl, mipsImpl: wb.output.ImplementationsDeployment.MipsImpl, keys: keys, } diff --git a/op-devstack/sysgo/op_rbuilder.go b/op-devstack/sysgo/op_rbuilder.go index 0692f96743a..cf1ee7efc6b 100644 --- a/op-devstack/sysgo/op_rbuilder.go +++ b/op-devstack/sysgo/op_rbuilder.go @@ -9,6 +9,7 @@ import ( "strconv" "strings" "sync" + "time" "github.com/ethereum/go-ethereum/log" yaml "gopkg.in/yaml.v3" @@ -79,6 +80,8 @@ type OPRBuilderNodeConfig struct { AuthRPCAddr string AuthRPCPort int + ChainBlockTime time.Duration + // P2P P2PPort int P2PAddr string @@ -118,6 +121,7 @@ func DefaultOPRbuilderNodeConfig() *OPRBuilderNodeConfig { P2PAddr: "127.0.0.1", P2PPort: 0, P2PNodeKeyHex: "", + ChainBlockTime: time.Second * 2, StaticPeers: nil, TrustedPeers: nil, Full: true, @@ -245,6 +249,8 @@ func (cfg *OPRBuilderNodeConfig) LaunchSpec(p devtest.CommonT) (args []string, e args = append(args, "--rules.config-path="+cfg.RulesConfigPath) } + chainBlockTimeArg := "--rollup.chain-block-time=" + strconv.FormatInt(cfg.ChainBlockTime.Milliseconds(), 10) + args = append(args, chainBlockTimeArg) args = append(args, cfg.ExtraArgs...) return args, env diff --git a/op-devstack/sysgo/preset_config.go b/op-devstack/sysgo/preset_config.go index 19f91a11fac..7cacaa963b2 100644 --- a/op-devstack/sysgo/preset_config.go +++ b/op-devstack/sysgo/preset_config.go @@ -22,105 +22,6 @@ type PresetConfig struct { RequireInteropNotAtGen bool } -type PresetOption interface { - apply(cfg *PresetConfig) -} - -type presetOptionFn func(cfg *PresetConfig) - -func (fn presetOptionFn) apply(cfg *PresetConfig) { - fn(cfg) -} - -func NewPresetConfig(opts ...PresetOption) PresetConfig { - cfg := PresetConfig{} - for _, opt := range opts { - if opt == nil { - continue - } - opt.apply(&cfg) - } - return cfg -} - -func WithDeployerOptions(opts ...DeployerOption) PresetOption { - return presetOptionFn(func(cfg *PresetConfig) { - cfg.DeployerOptions = append(cfg.DeployerOptions, opts...) - }) -} - -func WithBatcherOption(opt BatcherOption) PresetOption { - return presetOptionFn(func(cfg *PresetConfig) { - if opt == nil { - return - } - cfg.BatcherOptions = append(cfg.BatcherOptions, opt) - }) -} - -func WithProposerOption(opt ProposerOption) PresetOption { - return presetOptionFn(func(cfg *PresetConfig) { - if opt == nil { - return - } - cfg.ProposerOptions = append(cfg.ProposerOptions, opt) - }) -} - -func WithOPRBuilderOption(opt OPRBuilderNodeOption) PresetOption { - return presetOptionFn(func(cfg *PresetConfig) { - if opt == nil { - return - } - cfg.OPRBuilderOptions = append(cfg.OPRBuilderOptions, opt) - }) -} - -func WithGlobalL2CLOption(opt L2CLOption) PresetOption { - return presetOptionFn(func(cfg *PresetConfig) { - if opt == nil { - return - } - cfg.GlobalL2CLOptions = append(cfg.GlobalL2CLOptions, opt) - }) -} - -func WithGlobalSyncTesterELOption(opt SyncTesterELOption) PresetOption { - return presetOptionFn(func(cfg *PresetConfig) { - if opt == nil { - return - } - cfg.GlobalSyncTesterELOptions = append(cfg.GlobalSyncTesterELOptions, opt) - }) -} - -func WithGameTypeAdded(gameType gameTypes.GameType) PresetOption { - return presetOptionFn(func(cfg *PresetConfig) { - cfg.AddedGameTypes = append(cfg.AddedGameTypes, gameType) - }) -} - -func WithRespectedGameTypeOverride(gameType gameTypes.GameType) PresetOption { - return presetOptionFn(func(cfg *PresetConfig) { - cfg.RespectedGameTypes = append(cfg.RespectedGameTypes, gameType) - }) -} - -func WithCannonKonaGameTypeAdded() PresetOption { - return presetOptionFn(func(cfg *PresetConfig) { - cfg.EnableCannonKonaForChall = true - cfg.AddedGameTypes = append(cfg.AddedGameTypes, gameTypes.CannonKonaGameType) - }) -} - -func WithChallengerCannonKonaEnabled() PresetOption { - return presetOptionFn(func(cfg *PresetConfig) { - cfg.EnableCannonKonaForChall = true - }) -} - -func WithTimeTravelEnabled() PresetOption { - return presetOptionFn(func(cfg *PresetConfig) { - cfg.EnableTimeTravel = true - }) +func NewPresetConfig() PresetConfig { + return PresetConfig{} } diff --git a/op-devstack/sysgo/rust_binary.go b/op-devstack/sysgo/rust_binary.go index 7546ecd1db2..92710a22b0d 100644 --- a/op-devstack/sysgo/rust_binary.go +++ b/op-devstack/sysgo/rust_binary.go @@ -28,7 +28,7 @@ type RustBinarySpec struct { // - RUST_SRC_DIR_: overrides SrcDir (absolute path to cargo project root) // // Build behavior: -// - RUST_JIT_BUILD=1: runs cargo build --release (letting cargo handle rebuild detection) +// - RUST_JIT_BUILD=1: runs cargo build in debug mode (letting cargo handle rebuild detection) // - Otherwise: only checks binary exists, errors if missing func EnsureRustBinary(p devtest.CommonT, spec RustBinarySpec) (string, error) { envSuffix := toEnvVarSuffix(spec.Binary) @@ -59,7 +59,8 @@ func EnsureRustBinary(p devtest.CommonT, spec RustBinarySpec) (string, error) { binaryPath, err := resolveBuiltRustBinaryPath(srcRoot, spec.Binary) if err != nil { - return "", fmt.Errorf("%s binary not found; run 'just build-rust-debug' before the test or set RUST_JIT_BUILD=1: %w", spec.Binary, err) + return "", fmt.Errorf("%s binary not found; run 'cd %s && just build-%s-debug' (or just build-%s for release) or set RUST_JIT_BUILD=1: %w", + spec.Binary, spec.SrcDir, spec.Binary, spec.Binary, err) } return binaryPath, nil } @@ -88,7 +89,7 @@ func toEnvVarSuffix(binary string) string { } func buildRustBinary(ctx context.Context, root, pkg, bin string) error { - cmd := exec.CommandContext(ctx, "cargo", "build", "--release", "-p", pkg, "--bin", bin) + cmd := exec.CommandContext(ctx, "cargo", "build", "-p", pkg, "--bin", bin) cmd.Dir = root cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -107,6 +108,7 @@ func resolveBuiltRustBinaryPath(srcRoot, binary string) (string, error) { candidates := []string{ filepath.Join(targetDir, "release", binary), + filepath.Join(targetDir, "debug", binary), } globMatches, err := filepath.Glob(filepath.Join(targetDir, "*", "release", binary)) if err == nil { diff --git a/op-devstack/sysgo/singlechain_build.go b/op-devstack/sysgo/singlechain_build.go index 23c03735a4e..1842e3eb3f0 100644 --- a/op-devstack/sysgo/singlechain_build.go +++ b/op-devstack/sysgo/singlechain_build.go @@ -98,7 +98,7 @@ func buildSingleChainWorld(t devtest.T, keys devkeys.Keys, localContractArtifact genesis: wb.outL2Genesis[l2ID], rollupCfg: wb.outL2RollupCfg[l2ID], deployment: wb.outL2Deployment[l2ID], - opcmImpl: wb.output.ImplementationsDeployment.OpcmImpl, + opcmImpl: wb.output.ImplementationsDeployment.OpcmV2Impl, mipsImpl: wb.output.ImplementationsDeployment.MipsImpl, keys: keys, } diff --git a/op-devstack/sysgo/singlechain_flashblocks.go b/op-devstack/sysgo/singlechain_flashblocks.go index c184d06a5c3..449b19d1186 100644 --- a/op-devstack/sysgo/singlechain_flashblocks.go +++ b/op-devstack/sysgo/singlechain_flashblocks.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strings" + "time" "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" "github.com/ethereum-optimism/optimism/op-devstack/devtest" @@ -68,6 +69,7 @@ func startBuilderEL(t devtest.T, l2Net *L2Network, jwtPath string, identity *ELN require.NoError(os.WriteFile(chainConfigPath, data, 0o644), "must write op-rbuilder genesis file") cfg := DefaultOPRbuilderNodeConfig() + cfg.ChainBlockTime = time.Second * time.Duration(l2Net.rollupCfg.BlockTime) cfg.AuthRPCJWTPath = jwtPath cfg.Chain = chainConfigPath cfg.P2PAddr = "127.0.0.1" diff --git a/op-devstack/sysgo/singlechain_runtime.go b/op-devstack/sysgo/singlechain_runtime.go index 4ef8007b042..7d954056469 100644 --- a/op-devstack/sysgo/singlechain_runtime.go +++ b/op-devstack/sysgo/singlechain_runtime.go @@ -399,11 +399,16 @@ func applyMinimalGameTypeOptions( } l1ChainID := l1Net.ChainID() + // Filter out permissioned game type — it's always included by the V2 upgrade. + var filteredGameTypes []gameTypes.GameType for _, gameType := range addedGameTypes { if gameType == gameTypes.PermissionedGameType { continue } - addGameTypeForRuntime(t, keys, PrestateForGameType(t, gameType), gameType, l1ChainID, l1EL.UserRPC(), l2Net) + filteredGameTypes = append(filteredGameTypes, gameType) + } + if len(filteredGameTypes) > 0 { + addGameTypesForRuntime(t, keys, filteredGameTypes, l1ChainID, l1EL.UserRPC(), l2Net) } for _, gameType := range respectedGameTypes { setRespectedGameTypeForRuntime(t, keys, gameType, l1ChainID, l1EL.UserRPC(), l2Net) diff --git a/op-devstack/sysgo/superroot.go b/op-devstack/sysgo/superroot.go index 7f71eaf67b2..a4dc3126645 100644 --- a/op-devstack/sysgo/superroot.go +++ b/op-devstack/sysgo/superroot.go @@ -4,15 +4,15 @@ import ( "context" "crypto/ecdsa" "encoding/json" + "fmt" "math/big" "os" "path" + "strings" "time" "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" "github.com/ethereum-optimism/optimism/op-devstack/devtest" - "github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/contracts/bindings/delegatecallproxy" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-service/dial" @@ -20,6 +20,7 @@ import ( "github.com/ethereum-optimism/optimism/op-service/retry" "github.com/ethereum-optimism/optimism/op-service/sources/batching" "github.com/ethereum-optimism/optimism/op-service/txplan" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -40,10 +41,16 @@ type DisputeGameConfigV2 struct { GameArgs []byte } +// Proposal matches the Solidity Proposal struct: (bytes32 root, uint256 l2SequenceNumber) +type Proposal struct { + Root common.Hash + L2SequenceNumber *big.Int +} + type MigrateInputV2 struct { ChainSystemConfigs []common.Address DisputeGameConfigs []DisputeGameConfigV2 - StartingAnchorRoot bindings.Proposal + StartingAnchorRoot Proposal StartingRespectedGameType uint32 } @@ -105,7 +112,7 @@ func delegateCallWithSetCode( // Use the EIP-7825 max transaction gas limit to give the migration maximum room. txplan.WithGasLimit(params.MaxTxGas), txplan.WithRetrySubmission(client, 5, retry.Exponential()), - txplan.WithRetryInclusion(client, 5, retry.Exponential()), + txplan.WithRetryInclusion(client, 10, retry.Exponential()), ) receipt, err := tx.Included.Eval(ctx) @@ -203,9 +210,8 @@ func migrateSuperRoots( client := ethclient.NewClient(rpcClient) w3Client := w3.NewClient(rpcClient) - useV2 := isOPCMV2(t, w3Client, migration.opcmImpl) absoluteCannonPrestate := getInteropCannonAbsolutePrestate(t) - absoluteCannonKonaPrestate := getInteropCannonKonaAbsolutePrestate(t) + absoluteCannonKonaPrestate := getCannonKonaAbsolutePrestate(t) permissionedChainOps := devkeys.ChainOperatorKeys(primaryL2.ToBig()) proposer, err := keys.Address(permissionedChainOps(devkeys.ProposerRole)) @@ -213,66 +219,57 @@ func migrateSuperRoots( challenger, err := keys.Address(permissionedChainOps(devkeys.ChallengerRole)) require.NoError(err, "must have configured challenger") - var opChainConfigs []bindings.OPContractsManagerOpChainConfig + var chainSystemConfigs []common.Address for _, l2Deployment := range migration.l2Deployments { - opChainConfigs = append(opChainConfigs, bindings.OPContractsManagerOpChainConfig{ - SystemConfigProxy: l2Deployment.SystemConfigProxyAddr(), - CannonPrestate: absoluteCannonPrestate, - CannonKonaPrestate: absoluteCannonKonaPrestate, - }) + chainSystemConfigs = append(chainSystemConfigs, l2Deployment.SystemConfigProxyAddr()) } - opcmABI, err := bindings.OPContractsManagerMetaData.GetAbi() - require.NoError(err, "invalid OPCM ABI") - contract := batching.NewBoundContract(opcmABI, migration.opcmImpl) - - var migrateCallData []byte - if useV2 { - var chainSystemConfigs []common.Address - for _, cfg := range opChainConfigs { - chainSystemConfigs = append(chainSystemConfigs, cfg.SystemConfigProxy) - } - migrateInputV2 := MigrateInputV2{ - ChainSystemConfigs: chainSystemConfigs, - DisputeGameConfigs: []DisputeGameConfigV2{ - { - Enabled: true, - InitBond: big.NewInt(0), - GameType: superCannonGameType, - GameArgs: absoluteCannonPrestate[:], - }, + // Use the v2 migrator ABI directly (v1 OPCM is deleted, bindings are stale) + migratorABI, err := OPContractsManagerMigratorABI() + require.NoError(err, "invalid migrator ABI") + contract := batching.NewBoundContract(migratorABI, migration.opcmImpl) + + // ABI-encode permissioned game args: (bytes32 absolutePrestate, address proposer, address challenger) + bytes32Ty, _ := abi.NewType("bytes32", "", nil) + addressTy, _ := abi.NewType("address", "", nil) + permGameArgs, err := abi.Arguments{ + {Type: bytes32Ty}, + {Type: addressTy}, + {Type: addressTy}, + }.Pack(absoluteCannonPrestate, proposer, challenger) + require.NoError(err, "failed to encode permissioned game args") + + migrateInputV2 := MigrateInputV2{ + ChainSystemConfigs: chainSystemConfigs, + DisputeGameConfigs: []DisputeGameConfigV2{ + { + Enabled: true, + InitBond: big.NewInt(0), + GameType: superCannonGameType, + GameArgs: absoluteCannonPrestate[:], }, - StartingAnchorRoot: bindings.Proposal{ - Root: common.Hash(superRoot), - L2SequenceNumber: big.NewInt(int64(superrootTime)), + { + Enabled: true, + InitBond: big.NewInt(0), + GameType: superPermissionedCannonGameType, + GameArgs: permGameArgs, }, - StartingRespectedGameType: superCannonGameType, - } - migrateCall := contract.Call("migrate", migrateInputV2) - migrateCallData, err = migrateCall.Pack() - require.NoError(err) - } else { - migrateInputV1 := bindings.OPContractsManagerInteropMigratorMigrateInput{ - UsePermissionlessGame: true, - StartingAnchorRoot: bindings.Proposal{ - Root: common.Hash(superRoot), - L2SequenceNumber: big.NewInt(int64(superrootTime)), + { + Enabled: true, + InitBond: big.NewInt(0), + GameType: superCannonKonaGameType, + GameArgs: absoluteCannonKonaPrestate[:], }, - GameParameters: bindings.OPContractsManagerInteropMigratorGameParameters{ - Proposer: proposer, - Challenger: challenger, - MaxGameDepth: big.NewInt(73), - SplitDepth: big.NewInt(30), - InitBond: big.NewInt(0), - ClockExtension: 10800, - MaxClockDuration: 302400, - }, - OpChainConfigs: opChainConfigs, - } - migrateCall := contract.Call("migrate", migrateInputV1) - migrateCallData, err = migrateCall.Pack() - require.NoError(err) + }, + StartingAnchorRoot: Proposal{ + Root: common.Hash(superRoot), + L2SequenceNumber: big.NewInt(int64(superrootTime)), + }, + StartingRespectedGameType: superCannonGameType, } + migrateCall := contract.Call("migrate", migrateInputV2) + migrateCallData, err := migrateCall.Pack() + require.NoError(err) l1PAOKey, err := keys.Secret(devkeys.ChainOperatorKeys(l1ChainID.ToBig())(devkeys.L1ProxyAdminOwnerRole)) require.NoError(err, "must have configured L1 proxy admin owner") @@ -304,10 +301,6 @@ func getInteropCannonAbsolutePrestate(t devtest.CommonT) common.Hash { return getAbsolutePrestate(t, "op-program/bin/prestate-proof-interop.json") } -func getInteropCannonKonaAbsolutePrestate(t devtest.CommonT) common.Hash { - return getAbsolutePrestate(t, "rust/kona/prestate-artifacts-cannon-interop/prestate-proof.json") -} - func getCannonKonaAbsolutePrestate(t devtest.CommonT) common.Hash { return getAbsolutePrestate(t, "rust/kona/prestate-artifacts-cannon/prestate-proof.json") } @@ -327,27 +320,17 @@ func getAbsolutePrestate(t devtest.CommonT, prestatePath string) common.Hash { } const ( - superCannonGameType = 4 + superCannonGameType = 4 + superPermissionedCannonGameType = 5 + superCannonKonaGameType = 9 ) var ( optimismPortalFn = w3.MustNewFunc("optimismPortal()", "address") disputeGameFactoryFn = w3.MustNewFunc("disputeGameFactory()", "address") gameImplsFn = w3.MustNewFunc("gameImpls(uint32)", "address") - versionFn = w3.MustNewFunc("version()", "string") ) -// isOPCMV2 is a helper function that checks the OPCM version and returns true if it is at least 7.0.0 -func isOPCMV2(t devtest.CommonT, client *w3.Client, opcmAddr common.Address) bool { - var version string - err := client.Call(w3eth.CallFunc(opcmAddr, versionFn).Returns(&version)) - t.Require().NoError(err, "failed to get OPCM version") - - isVersionAtLeast, err := deployer.IsVersionAtLeast(version, 7, 0, 0) - t.Require().NoError(err, "failed to check OPCM version") - return isVersionAtLeast -} - func getOptimismPortal(t devtest.CommonT, client *w3.Client, systemConfigProxy common.Address) common.Address { var addr common.Address err := client.Call(w3eth.CallFunc(systemConfigProxy, optimismPortalFn).Returns(&addr)) @@ -368,3 +351,29 @@ func getSuperGameImpl(t devtest.CommonT, client *w3.Client, dgf common.Address) t.Require().NoError(err) return addr } + +// OPContractsManagerMigratorABI loads the ABI for the OPContractsManagerMigrator contract +// from the forge artifact file. +func OPContractsManagerMigratorABI() (*abi.ABI, error) { + root, err := findMonorepoRoot("packages/contracts-bedrock/forge-artifacts") + if err != nil { + return nil, fmt.Errorf("failed to find monorepo root: %w", err) + } + artifactPath := path.Join(root, "packages", "contracts-bedrock", "forge-artifacts", + "OPContractsManagerMigrator.sol", "OPContractsManagerMigrator.json") + data, err := os.ReadFile(artifactPath) + if err != nil { + return nil, fmt.Errorf("failed to read migrator artifact: %w", err) + } + var artifact struct { + ABI json.RawMessage `json:"abi"` + } + if err := json.Unmarshal(data, &artifact); err != nil { + return nil, fmt.Errorf("failed to parse migrator artifact: %w", err) + } + parsed, err := abi.JSON(strings.NewReader(string(artifact.ABI))) + if err != nil { + return nil, fmt.Errorf("failed to parse migrator ABI: %w", err) + } + return &parsed, nil +} diff --git a/op-devstack/sysgo/world.go b/op-devstack/sysgo/world.go index 00a3c7ecbfb..4cc9c5ebd13 100644 --- a/op-devstack/sysgo/world.go +++ b/op-devstack/sysgo/world.go @@ -55,7 +55,7 @@ func newInteropMigrationState(wb *worldBuilder) *interopMigrationState { return nil } state := &interopMigrationState{ - opcmImpl: wb.output.ImplementationsDeployment.OpcmImpl, + opcmImpl: wb.output.ImplementationsDeployment.OpcmV2Impl, superchainConfigAddr: wb.outSuperchainDeployment.SuperchainConfigAddr(), l2Deployments: make(map[eth.ChainID]*L2Deployment, len(wb.outL2Deployment)), } @@ -93,7 +93,7 @@ func buildSingleChainWorldWithInteropAndState(t devtest.T, keys devkeys.Keys, in genesis: wb.outL2Genesis[l2ID], rollupCfg: wb.outL2RollupCfg[l2ID], deployment: wb.outL2Deployment[l2ID], - opcmImpl: wb.output.ImplementationsDeployment.OpcmImpl, + opcmImpl: wb.output.ImplementationsDeployment.OpcmV2Impl, mipsImpl: wb.output.ImplementationsDeployment.MipsImpl, keys: keys, } @@ -136,7 +136,7 @@ func buildTwoL2WorldWithState(t devtest.T, keys devkeys.Keys, interopAtGenesis b genesis: l2ANet, rollupCfg: wb.outL2RollupCfg[DefaultL2AID], deployment: wb.outL2Deployment[DefaultL2AID], - opcmImpl: wb.output.ImplementationsDeployment.OpcmImpl, + opcmImpl: wb.output.ImplementationsDeployment.OpcmV2Impl, mipsImpl: wb.output.ImplementationsDeployment.MipsImpl, keys: keys, } @@ -147,7 +147,7 @@ func buildTwoL2WorldWithState(t devtest.T, keys devkeys.Keys, interopAtGenesis b genesis: l2BNet, rollupCfg: wb.outL2RollupCfg[DefaultL2BID], deployment: wb.outL2Deployment[DefaultL2BID], - opcmImpl: wb.output.ImplementationsDeployment.OpcmImpl, + opcmImpl: wb.output.ImplementationsDeployment.OpcmV2Impl, mipsImpl: wb.output.ImplementationsDeployment.MipsImpl, keys: keys, } diff --git a/op-e2e/actions/helpers/l1_miner.go b/op-e2e/actions/helpers/l1_miner.go index ee37e89f5f5..e69269490df 100644 --- a/op-e2e/actions/helpers/l1_miner.go +++ b/op-e2e/actions/helpers/l1_miner.go @@ -137,7 +137,7 @@ func (s *L1Miner) ActL1StartBlock(timeDelta uint64) Action { s.pendingIndices = make(map[common.Address]uint64) s.l1BuildingBlobSidecars = make([]*types.BlobTxSidecar, 0) - s.L1GasPool = new(core.GasPool).AddGas(header.GasLimit) + s.L1GasPool = core.NewGasPool(header.GasLimit) } } @@ -181,15 +181,15 @@ func (s *L1Miner) IncludeTx(t Testing, tx *types.Transaction) *types.Receipt { if tx.Gas() > s.l1BuildingHeader.GasLimit { t.Fatalf("tx consumes %d gas, more than available in L1 block %d", tx.Gas(), s.l1BuildingHeader.GasLimit) } - if tx.Gas() > uint64(*s.L1GasPool) { - t.InvalidAction("action takes too much gas: %d, only have %d", tx.Gas(), uint64(*s.L1GasPool)) + if tx.Gas() > s.L1GasPool.Gas() { + t.InvalidAction("action takes too much gas: %d, only have %d", tx.Gas(), s.L1GasPool.Gas()) return nil } s.l1BuildingState.SetTxContext(tx.Hash(), len(s.L1Transactions)) blockCtx := core.NewEVMBlockContext(s.l1BuildingHeader, s.l1Chain, nil, s.l1Cfg.Config, s.l1BuildingState) evm := vm.NewEVM(blockCtx, s.l1BuildingState, s.l1Cfg.Config, *s.l1Chain.GetVMConfig()) receipt, err := core.ApplyTransaction( - evm, s.L1GasPool, s.l1BuildingState, s.l1BuildingHeader, tx.WithoutBlobTxSidecar(), &s.l1BuildingHeader.GasUsed) + evm, s.L1GasPool, s.l1BuildingState, s.l1BuildingHeader, tx.WithoutBlobTxSidecar()) if err != nil { s.l1TxFailed = append(s.l1TxFailed, tx) t.Fatalf("failed to apply transaction to L1 block (tx %d): %v", len(s.L1Transactions), err) @@ -259,7 +259,7 @@ func (s *L1Miner) ActL1EndBlock(t Testing) *types.Block { } s.l1Building = false - s.l1BuildingHeader.GasUsed = s.l1BuildingHeader.GasLimit - uint64(*s.L1GasPool) + s.l1BuildingHeader.GasUsed = s.l1BuildingHeader.GasLimit - s.L1GasPool.Gas() s.l1BuildingHeader.Root = s.l1BuildingState.IntermediateRoot(s.l1Cfg.Config.IsEIP158(s.l1BuildingHeader.Number)) var withdrawals []*types.Withdrawal diff --git a/op-e2e/actions/helpers/l2_proposer.go b/op-e2e/actions/helpers/l2_proposer.go index 527a803e293..2df068d077d 100644 --- a/op-e2e/actions/helpers/l2_proposer.go +++ b/op-e2e/actions/helpers/l2_proposer.go @@ -140,7 +140,7 @@ func NewL2Proposer(t Testing, log log.Logger, cfg *ProposerCfg, l1 *ethclient.Cl // sendTx reimplements creating & sending transactions because we need to do the final send as async in // the action tests while we do it synchronously in the real system. -func (p *L2Proposer) sendTx(t Testing, data []byte) { +func (p *L2Proposer) sendTx(t Testing, data []byte, value *big.Int) { gasTipCap := big.NewInt(2 * params.GWei) pendingHeader, err := p.l1.HeaderByNumber(t.Ctx(), big.NewInt(-1)) require.NoError(t, err, "need l1 pending header for gas price estimation") @@ -155,6 +155,7 @@ func (p *L2Proposer) sendTx(t Testing, data []byte) { To: p.disputeGameFactoryAddr, GasFeeCap: gasFeeCap, GasTipCap: gasTipCap, + Value: value, Data: data, }) require.NoError(t, err) @@ -163,6 +164,7 @@ func (p *L2Proposer) sendTx(t Testing, data []byte) { Nonce: nonce, To: p.disputeGameFactoryAddr, Data: data, + Value: value, GasFeeCap: gasFeeCap, GasTipCap: gasTipCap, Gas: gasLimit, @@ -228,11 +230,10 @@ func (p *L2Proposer) ActMakeProposalTx(t Testing) { tx, err := p.driver.ProposeL2OutputDGFTxCandidate(context.Background(), output) require.NoError(t, err) - txData := tx.TxData // Note: Use L1 instead of the output submitter's transaction manager because // this is non-blocking while the txmgr is blocking & deadlocks the tests - p.sendTx(t, txData) + p.sendTx(t, tx.TxData, tx.Value) } func (p *L2Proposer) LastProposalTx() common.Hash { diff --git a/op-e2e/actions/interop/proofs_test.go b/op-e2e/actions/interop/proofs_test.go index 5beb46ccadd..1b3dab8b908 100644 --- a/op-e2e/actions/interop/proofs_test.go +++ b/op-e2e/actions/interop/proofs_test.go @@ -37,104 +37,6 @@ const ( consolidateStep = stepsPerTimestamp - 1 ) -func TestInteropFaultProofs_PreForkActivation(gt *testing.T) { - // TODO(#16166): Fix non-genesis Interop activation proofs - gt.Skip() - t := helpers.NewDefaultTesting(gt) - system := dsl.NewInteropDSL(t, dsl.SetInteropForkScheduledButInactive()) - - actors := system.Actors - endTimestamp := actors.ChainA.RollupCfg.Genesis.L2Time + actors.ChainA.RollupCfg.BlockTime - startTimestamp := endTimestamp - 1 - require.False(t, actors.ChainA.RollupCfg.IsInterop(endTimestamp), "Interop should not be active") - - alice := system.CreateUser() - emitter := system.DeployEmitterContracts() - - system.AddL2Block(system.Actors.ChainA, dsl.WithL2BlockTransactions(emitter.EmitMessage(alice, "hello"))) - initMsg := emitter.LastEmittedMessage() - system.AddL2Block(system.Actors.ChainB, - dsl.WithL2BlockTransactions(system.InboxContract.Execute(alice, initMsg, - dsl.WithPayload([]byte("wrong")), - // CrossL2Inbox contract isn't deployed so the tx will revert. Need to avoid using eth_estimateGas - dsl.WithFixedGasLimit()))) - system.InboxContract.LastTransaction().CheckIncluded(dsl.WithRevertExpected()) - - // Submit batch data for each chain in separate L1 blocks so tests can have one chain safe and one unsafe - system.SubmitBatchData(func(opts *dsl.SubmitBatchDataOpts) { - opts.SetChains(system.Actors.ChainA) - }) - system.SubmitBatchData(func(opts *dsl.SubmitBatchDataOpts) { - opts.SetChains(system.Actors.ChainB) - }) - // Check that the supervisor didn't re-org out this transaction. - // Interop isn't active yet so the extra derivation rules to validate executing messages must not be active. - system.InboxContract.LastTransaction().CheckIncluded(dsl.WithRevertExpected()) - - start := system.Outputs.SuperRoot(startTimestamp) - end := system.Outputs.SuperRoot(endTimestamp) - - step1Expected := system.Outputs.TransitionState(startTimestamp, 1, - system.Outputs.OptimisticBlockAtTimestamp(actors.ChainA, endTimestamp), - ).Marshal() - - step2Expected := system.Outputs.TransitionState(startTimestamp, 2, - system.Outputs.OptimisticBlockAtTimestamp(actors.ChainA, endTimestamp), - system.Outputs.OptimisticBlockAtTimestamp(actors.ChainB, endTimestamp), - ).Marshal() - - firstPaddingStep := system.Outputs.TransitionState(startTimestamp, 3, - system.Outputs.OptimisticBlockAtTimestamp(actors.ChainA, endTimestamp), - system.Outputs.OptimisticBlockAtTimestamp(actors.ChainB, endTimestamp), - ).Marshal() - - lastPaddingStep := system.Outputs.TransitionState(startTimestamp, consolidateStep, - system.Outputs.OptimisticBlockAtTimestamp(actors.ChainA, endTimestamp), - system.Outputs.OptimisticBlockAtTimestamp(actors.ChainB, endTimestamp), - ).Marshal() - - tests := []*transitionTest{ - { - name: "FirstChainOptimisticBlock", - agreedClaim: start.Marshal(), - disputedClaim: step1Expected, - disputedTraceIndex: 0, - expectValid: true, - startTimestamp: startTimestamp, - proposalTimestamp: endTimestamp, - }, - { - name: "SecondChainOptimisticBlock", - agreedClaim: step1Expected, - disputedClaim: step2Expected, - disputedTraceIndex: 1, - expectValid: true, - startTimestamp: startTimestamp, - proposalTimestamp: endTimestamp, - }, - { - name: "FirstPaddingStep", - agreedClaim: step2Expected, - disputedClaim: firstPaddingStep, - disputedTraceIndex: 2, - expectValid: true, - startTimestamp: startTimestamp, - proposalTimestamp: endTimestamp, - }, - { - name: "Consolidate", - agreedClaim: lastPaddingStep, - disputedClaim: end.Marshal(), - disputedTraceIndex: consolidateStep, - expectValid: true, - startTimestamp: startTimestamp, - proposalTimestamp: endTimestamp, - }, - } - - runFppAndChallengerTests(gt, system, tests) -} - func TestInteropFaultProofs(gt *testing.T) { t := helpers.NewDefaultTesting(gt) system := dsl.NewInteropDSL(t) @@ -1127,66 +1029,6 @@ func TestInteropFaultProofs_VariedBlockTimes_FasterChainB(gt *testing.T) { runFppAndChallengerTests(gt, system, tests) } -func TestInteropFaultProofs_DepositMessage(gt *testing.T) { - t := helpers.NewDefaultTesting(gt) - - system := dsl.NewInteropDSL(t) - actors := system.Actors - emitter := system.DeployEmitterContracts() - - // Advance L1 a couple times to avoid deposit gas metering issues near genesis - system.AdvanceL1() - system.AdvanceL1() - - l1User := system.CreateUser() - depositMessage := dsl.NewMessage(system, actors.ChainA, emitter, "hello") - system.AdvanceL1( - dsl.WithActIncludeTx( - depositMessage.ActEmitDeposit(l1User))) - - // As such, the next block timestamp across both chains will contain a user-deposit message and an executing message - system.AdvanceL2ToLastBlockOfOrigin(actors.ChainA, 2) - system.AdvanceL2ToLastBlockOfOrigin(actors.ChainB, 2) - - actors.ChainA.Sequencer.ActL2StartBlock(t) - actors.ChainB.Sequencer.ActL2StartBlock(t) - // The pending block on chain A will contain the user deposit - depositMessage.ExecutePendingOn(actors.ChainB, actors.ChainA.Sequencer.L2Unsafe().Number+1) - actors.ChainA.Sequencer.ActL2EndBlock(t) - actors.ChainB.Sequencer.ActL2EndBlock(t) - system.SubmitBatchData(dsl.WithSkipCrossSafeUpdate()) - - endTimestamp := actors.ChainB.Sequencer.L2Unsafe().Time - startTimestamp := endTimestamp - 1 - preConsolidation := system.Outputs.TransitionState(startTimestamp, consolidateStep, - system.Outputs.OptimisticBlockAtTimestamp(actors.ChainA, endTimestamp), - system.Outputs.OptimisticBlockAtTimestamp(actors.ChainB, endTimestamp), - ).Marshal() - - system.ProcessCrossSafe() - depositMessage.CheckExecuted() - assertUserDepositEmitted(t, system.Actors.ChainA, nil, emitter) - crossSafeEnd := system.Outputs.SuperRoot(endTimestamp) - - tests := []*transitionTest{ - { - name: "Consolidate", - agreedClaim: preConsolidation, - disputedClaim: crossSafeEnd.Marshal(), - disputedTraceIndex: consolidateStep, - expectValid: true, - }, - { - name: "Consolidate-InvalidNoChange", - agreedClaim: preConsolidation, - disputedClaim: preConsolidation, - disputedTraceIndex: consolidateStep, - expectValid: false, - }, - } - runFppAndChallengerTests(gt, system, tests) -} - func TestInteropFaultProofs_DepositMessage_InvalidExecution(gt *testing.T) { t := helpers.NewDefaultTesting(gt) diff --git a/op-e2e/actions/proofs/batcher_change_test.go b/op-e2e/actions/proofs/batcher_change_test.go new file mode 100644 index 00000000000..5298493b980 --- /dev/null +++ b/op-e2e/actions/proofs/batcher_change_test.go @@ -0,0 +1,64 @@ +package proofs_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" + "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" +) + +// Test_ProgramAction_BatcherChangeWithinChannelTimeout verifies that after a +// pipeline reset, the system config is loaded from the walked-back L2 block +// (channel_timeout L1 blocks behind the safe head's L1 origin), not from the +// safe head itself. +// +// Scenario: +// 1. Batcher A submits a batch. +// 2. The batcher address is changed from A to B on L1. +// 3. Batcher B submits a batch. +// 4. The fault proof program re-derives the chain from scratch. During reset, +// the pipeline walks back by channel_timeout and should find the old system +// config (batcher A). If it incorrectly uses the safe head's config +// (batcher B), it rejects batcher A's batch and derivation diverges. +func Test_ProgramAction_BatcherChangeWithinChannelTimeout(gt *testing.T) { + matrix := helpers.NewMatrix[any]() + matrix.AddDefaultTestCases( + nil, + helpers.NewForkMatrix(helpers.Granite, helpers.Jovian), + testBatcherChangeWithinChannelTimeout, + ) + matrix.Run(gt) +} + +func testBatcherChangeWithinChannelTimeout(gt *testing.T, testCfg *helpers.TestCfg[any]) { + t := actionsHelpers.NewDefaultTesting(gt) + env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(), helpers.NewBatcherCfg()) + + miner := env.Miner + sequencer := env.Sequencer + + // Step 1: Batcher A (default) submits a batch. + miner.ActEmptyBlock(t) + sequencer.ActL1HeadSignal(t) + sequencer.ActBuildToL1Head(t) + safeAfterA := env.BatchMineAndSync(t) + require.Greater(t, safeAfterA.Number, uint64(0), "safe head should advance after batcher A's batch") + + // Step 2: Change batcher from A to B (Bob) on L1 and replace env.Batcher. + env.RotateBatcher(t, env.Dp.Secrets.Bob) + + // Step 3: Build L2 blocks adopting the batcher change, submit with batcher B. + sequencer.ActL1HeadSignal(t) + sequencer.ActBuildToL1Head(t) + safeAfterB := env.BatchMineAndSync(t) + require.Greater(t, safeAfterB.Number, safeAfterA.Number, "safe head should advance after batcher B's batch") + + // Step 4: Run the fault proof program. This re-derives the chain from + // scratch, triggering a pipeline reset. The pipeline must walk back by + // channel_timeout and use batcher A's system config for the initial + // derivation window. If it uses batcher B's config, batcher A's batch + // is rejected and derivation produces a different (shorter) safe chain. + env.RunFaultProofProgram(t, safeAfterB.Number, testCfg.CheckResult, testCfg.InputParams...) +} diff --git a/op-e2e/actions/proofs/helpers/env.go b/op-e2e/actions/proofs/helpers/env.go index f708c924cf3..43fbe51d4d7 100644 --- a/op-e2e/actions/proofs/helpers/env.go +++ b/op-e2e/actions/proofs/helpers/env.go @@ -1,26 +1,29 @@ package helpers import ( + "crypto/ecdsa" "math/rand" + altda "github.com/ethereum-optimism/optimism/op-alt-da" + 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/forks" + "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" + "github.com/ethereum-optimism/optimism/op-e2e/bindings" 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" "github.com/ethereum-optimism/optimism/op-program/client/boot" - "github.com/ethereum/go-ethereum/params" - - altda "github.com/ethereum-optimism/optimism/op-alt-da" - batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags" - "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" - "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" "github.com/ethereum-optimism/optimism/op-program/host/config" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" "github.com/stretchr/testify/require" ) @@ -236,12 +239,40 @@ func NewOpProgramCfg( return dfault } +const L1BlockTime = 12 + +// RotateBatcher updates the on-chain batcher address in the SystemConfig contract and replaces +// env.Batcher with a new one using the given key. The L1 transaction is mined in a new L1 block. +func (env *L2FaultProofEnv) RotateBatcher(t helpers.Testing, newBatcherKey *ecdsa.PrivateKey) { + t.Helper() + newAddr := crypto.PubkeyToAddress(newBatcherKey.PublicKey) + + sysCfgContract, err := bindings.NewSystemConfig(env.Sd.RollupCfg.L1SystemConfigAddress, env.Miner.EthClient()) + require.NoError(t, err) + sysCfgOwner, err := bind.NewKeyedTransactorWithChainID(env.Dp.Secrets.Deployer, env.Sd.RollupCfg.L1ChainID) + require.NoError(t, err) + _, err = sysCfgContract.SetBatcherHash(sysCfgOwner, eth.AddressAsLeftPaddedHash(newAddr)) + require.NoError(t, err) + + env.Miner.ActL1StartBlock(L1BlockTime)(t) + env.Miner.ActL1IncludeTx(env.Dp.Addresses.Deployer)(t) + env.Miner.ActL1EndBlock(t) + + batcherCfg := NewBatcherCfg() + batcherCfg.BatcherKey = newBatcherKey + env.Batcher = helpers.NewL2Batcher( + env.log, env.Sd.RollupCfg, batcherCfg, + env.Sequencer.RollupClient(), env.Miner.EthClient(), + env.Engine.EthClient(), env.engCl, + ) +} + // BatchAndMine batches the current unsafe chain to L1 and mines the L1 block containing the // batcher transaction. func (env *L2FaultProofEnv) BatchAndMine(t helpers.Testing) { t.Helper() env.Batcher.ActSubmitAll(t) - env.Miner.ActL1StartBlock(12)(t) + env.Miner.ActL1StartBlock(L1BlockTime)(t) env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t) env.Miner.ActL1EndBlock(t) } diff --git a/op-e2e/bindings/opcontractsmanager.go b/op-e2e/bindings/opcontractsmanager.go deleted file mode 100644 index 5c8dcecdb7a..00000000000 --- a/op-e2e/bindings/opcontractsmanager.go +++ /dev/null @@ -1,1018 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package bindings - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// OPContractsManagerAddGameInput is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerAddGameInput struct { - SaltMixer string - SystemConfig common.Address - DelayedWETH common.Address - DisputeGameType uint32 - DisputeAbsolutePrestate [32]byte - DisputeMaxGameDepth *big.Int - DisputeSplitDepth *big.Int - DisputeClockExtension uint64 - DisputeMaxClockDuration uint64 - InitialBond *big.Int - Vm common.Address - Permissioned bool -} - -// OPContractsManagerAddGameOutput is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerAddGameOutput struct { - DelayedWETH common.Address - FaultDisputeGame common.Address -} - -// OPContractsManagerBlueprints is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerBlueprints struct { - AddressManager common.Address - Proxy common.Address - ProxyAdmin common.Address - L1ChugSplashProxy common.Address - ResolvedDelegateProxy common.Address -} - -// OPContractsManagerDeployInput is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerDeployInput struct { - Roles OPContractsManagerRoles - BasefeeScalar uint32 - BlobBasefeeScalar uint32 - L2ChainId *big.Int - StartingAnchorRoot []byte - SaltMixer string - GasLimit uint64 - DisputeGameType uint32 - DisputeAbsolutePrestate [32]byte - DisputeMaxGameDepth *big.Int - DisputeSplitDepth *big.Int - DisputeClockExtension uint64 - DisputeMaxClockDuration uint64 - UseCustomGasToken bool -} - -// OPContractsManagerDeployOutput is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerDeployOutput struct { - OpChainProxyAdmin common.Address - AddressManager common.Address - L1ERC721BridgeProxy common.Address - SystemConfigProxy common.Address - OptimismMintableERC20FactoryProxy common.Address - L1StandardBridgeProxy common.Address - L1CrossDomainMessengerProxy common.Address - EthLockboxProxy common.Address - OptimismPortalProxy common.Address - DisputeGameFactoryProxy common.Address - AnchorStateRegistryProxy common.Address - FaultDisputeGame common.Address - PermissionedDisputeGame common.Address - DelayedWETHPermissionedGameProxy common.Address - DelayedWETHPermissionlessGameProxy common.Address -} - -// OPContractsManagerImplementations is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerImplementations struct { - SuperchainConfigImpl common.Address - ProtocolVersionsImpl common.Address - L1ERC721BridgeImpl common.Address - OptimismPortalImpl common.Address - OptimismPortalInteropImpl common.Address - EthLockboxImpl common.Address - SystemConfigImpl common.Address - OptimismMintableERC20FactoryImpl common.Address - L1CrossDomainMessengerImpl common.Address - L1StandardBridgeImpl common.Address - DisputeGameFactoryImpl common.Address - AnchorStateRegistryImpl common.Address - DelayedWETHImpl common.Address - MipsImpl common.Address - FaultDisputeGameImpl common.Address - PermissionedDisputeGameImpl common.Address - SuperFaultDisputeGameImpl common.Address - SuperPermissionedDisputeGameImpl common.Address -} - -// OPContractsManagerInteropMigratorGameParameters is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerInteropMigratorGameParameters struct { - Proposer common.Address - Challenger common.Address - MaxGameDepth *big.Int - SplitDepth *big.Int - InitBond *big.Int - ClockExtension uint64 - MaxClockDuration uint64 -} - -// OPContractsManagerInteropMigratorMigrateInput is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerInteropMigratorMigrateInput struct { - UsePermissionlessGame bool - StartingAnchorRoot Proposal - GameParameters OPContractsManagerInteropMigratorGameParameters - OpChainConfigs []OPContractsManagerOpChainConfig -} - -// OPContractsManagerOpChainConfig is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerOpChainConfig struct { - SystemConfigProxy common.Address - CannonPrestate [32]byte - CannonKonaPrestate [32]byte -} - -// OPContractsManagerRoles is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerRoles struct { - OpChainProxyAdminOwner common.Address - SystemConfigOwner common.Address - Batcher common.Address - UnsafeBlockSigner common.Address - Proposer common.Address - Challenger common.Address -} - -// OPContractsManagerStandardValidatorValidationInput is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerStandardValidatorValidationInput struct { - SysCfg common.Address - AbsolutePrestate [32]byte - L2ChainID *big.Int - Proposer common.Address -} - -// OPContractsManagerStandardValidatorValidationInputDev is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerStandardValidatorValidationInputDev struct { - SysCfg common.Address - CannonPrestate [32]byte - CannonKonaPrestate [32]byte - L2ChainID *big.Int - Proposer common.Address -} - -// OPContractsManagerStandardValidatorValidationOverrides is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerStandardValidatorValidationOverrides struct { - L1PAOMultisig common.Address - Challenger common.Address -} - -// OPContractsManagerUpdatePrestateInput is an auto generated low-level Go binding around an user-defined struct. -type OPContractsManagerUpdatePrestateInput struct { - SystemConfigProxy common.Address - CannonPrestate [32]byte - CannonKonaPrestate [32]byte -} - -// Proposal is an auto generated low-level Go binding around an user-defined struct. -type Proposal struct { - Root [32]byte - L2SequenceNumber *big.Int -} - -// OPContractsManagerMetaData contains all meta data concerning the OPContractsManager contract. -var OPContractsManagerMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_opcmGameTypeAdder\",\"type\":\"address\",\"internalType\":\"contractOPContractsManagerGameTypeAdder\"},{\"name\":\"_opcmDeployer\",\"type\":\"address\",\"internalType\":\"contractOPContractsManagerDeployer\"},{\"name\":\"_opcmUpgrader\",\"type\":\"address\",\"internalType\":\"contractOPContractsManagerUpgrader\"},{\"name\":\"_opcmInteropMigrator\",\"type\":\"address\",\"internalType\":\"contractOPContractsManagerInteropMigrator\"},{\"name\":\"_opcmStandardValidator\",\"type\":\"address\",\"internalType\":\"contractOPContractsManagerStandardValidator\"},{\"name\":\"_superchainConfig\",\"type\":\"address\",\"internalType\":\"contractISuperchainConfig\"},{\"name\":\"_protocolVersions\",\"type\":\"address\",\"internalType\":\"contractIProtocolVersions\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addGameType\",\"inputs\":[{\"name\":\"_gameConfigs\",\"type\":\"tuple[]\",\"internalType\":\"structOPContractsManager.AddGameInput[]\",\"components\":[{\"name\":\"saltMixer\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"systemConfig\",\"type\":\"address\",\"internalType\":\"contractISystemConfig\"},{\"name\":\"delayedWETH\",\"type\":\"address\",\"internalType\":\"contractIDelayedWETH\"},{\"name\":\"disputeGameType\",\"type\":\"uint32\",\"internalType\":\"GameType\"},{\"name\":\"disputeAbsolutePrestate\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"disputeMaxGameDepth\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"disputeSplitDepth\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"disputeClockExtension\",\"type\":\"uint64\",\"internalType\":\"Duration\"},{\"name\":\"disputeMaxClockDuration\",\"type\":\"uint64\",\"internalType\":\"Duration\"},{\"name\":\"initialBond\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"vm\",\"type\":\"address\",\"internalType\":\"contractIBigStepper\"},{\"name\":\"permissioned\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple[]\",\"internalType\":\"structOPContractsManager.AddGameOutput[]\",\"components\":[{\"name\":\"delayedWETH\",\"type\":\"address\",\"internalType\":\"contractIDelayedWETH\"},{\"name\":\"faultDisputeGame\",\"type\":\"address\",\"internalType\":\"contractIFaultDisputeGame\"}]}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"blueprints\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManager.Blueprints\",\"components\":[{\"name\":\"addressManager\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"proxy\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"proxyAdmin\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"l1ChugSplashProxy\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"resolvedDelegateProxy\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"chainIdToBatchInboxAddress\",\"inputs\":[{\"name\":\"_l2ChainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"deploy\",\"inputs\":[{\"name\":\"_input\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManager.DeployInput\",\"components\":[{\"name\":\"roles\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManager.Roles\",\"components\":[{\"name\":\"opChainProxyAdminOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"systemConfigOwner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"batcher\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"unsafeBlockSigner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"proposer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"challenger\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"basefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"blobBasefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"l2ChainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"startingAnchorRoot\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"saltMixer\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"gasLimit\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"disputeGameType\",\"type\":\"uint32\",\"internalType\":\"GameType\"},{\"name\":\"disputeAbsolutePrestate\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"disputeMaxGameDepth\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"disputeSplitDepth\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"disputeClockExtension\",\"type\":\"uint64\",\"internalType\":\"Duration\"},{\"name\":\"disputeMaxClockDuration\",\"type\":\"uint64\",\"internalType\":\"Duration\"},{\"name\":\"useCustomGasToken\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManager.DeployOutput\",\"components\":[{\"name\":\"opChainProxyAdmin\",\"type\":\"address\",\"internalType\":\"contractIProxyAdmin\"},{\"name\":\"addressManager\",\"type\":\"address\",\"internalType\":\"contractIAddressManager\"},{\"name\":\"l1ERC721BridgeProxy\",\"type\":\"address\",\"internalType\":\"contractIL1ERC721Bridge\"},{\"name\":\"systemConfigProxy\",\"type\":\"address\",\"internalType\":\"contractISystemConfig\"},{\"name\":\"optimismMintableERC20FactoryProxy\",\"type\":\"address\",\"internalType\":\"contractIOptimismMintableERC20Factory\"},{\"name\":\"l1StandardBridgeProxy\",\"type\":\"address\",\"internalType\":\"contractIL1StandardBridge\"},{\"name\":\"l1CrossDomainMessengerProxy\",\"type\":\"address\",\"internalType\":\"contractIL1CrossDomainMessenger\"},{\"name\":\"ethLockboxProxy\",\"type\":\"address\",\"internalType\":\"contractIETHLockbox\"},{\"name\":\"optimismPortalProxy\",\"type\":\"address\",\"internalType\":\"contractIOptimismPortal2\"},{\"name\":\"disputeGameFactoryProxy\",\"type\":\"address\",\"internalType\":\"contractIDisputeGameFactory\"},{\"name\":\"anchorStateRegistryProxy\",\"type\":\"address\",\"internalType\":\"contractIAnchorStateRegistry\"},{\"name\":\"faultDisputeGame\",\"type\":\"address\",\"internalType\":\"contractIFaultDisputeGame\"},{\"name\":\"permissionedDisputeGame\",\"type\":\"address\",\"internalType\":\"contractIPermissionedDisputeGame\"},{\"name\":\"delayedWETHPermissionedGameProxy\",\"type\":\"address\",\"internalType\":\"contractIDelayedWETH\"},{\"name\":\"delayedWETHPermissionlessGameProxy\",\"type\":\"address\",\"internalType\":\"contractIDelayedWETH\"}]}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"devFeatureBitmap\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"implementations\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManager.Implementations\",\"components\":[{\"name\":\"superchainConfigImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"protocolVersionsImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"l1ERC721BridgeImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"optimismPortalImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"optimismPortalInteropImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"ethLockboxImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"systemConfigImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"optimismMintableERC20FactoryImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"l1CrossDomainMessengerImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"l1StandardBridgeImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"disputeGameFactoryImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"anchorStateRegistryImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"delayedWETHImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"mipsImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"faultDisputeGameImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"permissionedDisputeGameImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"superFaultDisputeGameImpl\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"superPermissionedDisputeGameImpl\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isDevFeatureEnabled\",\"inputs\":[{\"name\":\"_feature\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"migrate\",\"inputs\":[{\"name\":\"_input\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManagerInteropMigrator.MigrateInput\",\"components\":[{\"name\":\"usePermissionlessGame\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"startingAnchorRoot\",\"type\":\"tuple\",\"internalType\":\"structProposal\",\"components\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"Hash\"},{\"name\":\"l2SequenceNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"gameParameters\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManagerInteropMigrator.GameParameters\",\"components\":[{\"name\":\"proposer\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"challenger\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"maxGameDepth\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"splitDepth\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"initBond\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"clockExtension\",\"type\":\"uint64\",\"internalType\":\"Duration\"},{\"name\":\"maxClockDuration\",\"type\":\"uint64\",\"internalType\":\"Duration\"}]},{\"name\":\"opChainConfigs\",\"type\":\"tuple[]\",\"internalType\":\"structOPContractsManager.OpChainConfig[]\",\"components\":[{\"name\":\"systemConfigProxy\",\"type\":\"address\",\"internalType\":\"contractISystemConfig\"},{\"name\":\"cannonPrestate\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"cannonKonaPrestate\",\"type\":\"bytes32\",\"internalType\":\"Claim\"}]}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"opcmDeployer\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractOPContractsManagerDeployer\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"opcmGameTypeAdder\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractOPContractsManagerGameTypeAdder\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"opcmInteropMigrator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractOPContractsManagerInteropMigrator\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"opcmStandardValidator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractOPContractsManagerStandardValidator\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"opcmUpgrader\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractOPContractsManagerUpgrader\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"protocolVersions\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractIProtocolVersions\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"superchainConfig\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISuperchainConfig\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"updatePrestate\",\"inputs\":[{\"name\":\"_prestateUpdateInputs\",\"type\":\"tuple[]\",\"internalType\":\"structOPContractsManager.UpdatePrestateInput[]\",\"components\":[{\"name\":\"systemConfigProxy\",\"type\":\"address\",\"internalType\":\"contractISystemConfig\"},{\"name\":\"cannonPrestate\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"cannonKonaPrestate\",\"type\":\"bytes32\",\"internalType\":\"Claim\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgrade\",\"inputs\":[{\"name\":\"_opChainConfigs\",\"type\":\"tuple[]\",\"internalType\":\"structOPContractsManager.OpChainConfig[]\",\"components\":[{\"name\":\"systemConfigProxy\",\"type\":\"address\",\"internalType\":\"contractISystemConfig\"},{\"name\":\"cannonPrestate\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"cannonKonaPrestate\",\"type\":\"bytes32\",\"internalType\":\"Claim\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeSuperchainConfig\",\"inputs\":[{\"name\":\"_superchainConfig\",\"type\":\"address\",\"internalType\":\"contractISuperchainConfig\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"validate\",\"inputs\":[{\"name\":\"_input\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManagerStandardValidator.ValidationInput\",\"components\":[{\"name\":\"sysCfg\",\"type\":\"address\",\"internalType\":\"contractISystemConfig\"},{\"name\":\"absolutePrestate\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"l2ChainID\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proposer\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"_allowFailure\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validate\",\"inputs\":[{\"name\":\"_input\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManagerStandardValidator.ValidationInputDev\",\"components\":[{\"name\":\"sysCfg\",\"type\":\"address\",\"internalType\":\"contractISystemConfig\"},{\"name\":\"cannonPrestate\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"cannonKonaPrestate\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"l2ChainID\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proposer\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"_allowFailure\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validateWithOverrides\",\"inputs\":[{\"name\":\"_input\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManagerStandardValidator.ValidationInput\",\"components\":[{\"name\":\"sysCfg\",\"type\":\"address\",\"internalType\":\"contractISystemConfig\"},{\"name\":\"absolutePrestate\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"l2ChainID\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proposer\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"_allowFailure\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"_overrides\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManagerStandardValidator.ValidationOverrides\",\"components\":[{\"name\":\"l1PAOMultisig\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"challenger\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"validateWithOverrides\",\"inputs\":[{\"name\":\"_input\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManagerStandardValidator.ValidationInputDev\",\"components\":[{\"name\":\"sysCfg\",\"type\":\"address\",\"internalType\":\"contractISystemConfig\"},{\"name\":\"cannonPrestate\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"cannonKonaPrestate\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"l2ChainID\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proposer\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"name\":\"_allowFailure\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"_overrides\",\"type\":\"tuple\",\"internalType\":\"structOPContractsManagerStandardValidator.ValidationOverrides\",\"components\":[{\"name\":\"l1PAOMultisig\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"challenger\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"pure\"},{\"type\":\"error\",\"name\":\"AddressHasNoCode\",\"inputs\":[{\"name\":\"who\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"AddressNotFound\",\"inputs\":[{\"name\":\"who\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"AlreadyReleased\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidChainId\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidDevFeatureAccess\",\"inputs\":[{\"name\":\"devFeature\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"InvalidGameConfigs\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidRoleAddress\",\"inputs\":[{\"name\":\"role\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"InvalidStartingAnchorRoot\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"LatestReleaseNotSet\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OPContractsManager_V2Enabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OnlyDelegatecall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"PrestateNotSet\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"PrestateRequired\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SuperchainConfigMismatch\",\"inputs\":[{\"name\":\"systemConfig\",\"type\":\"address\",\"internalType\":\"contractISystemConfig\"}]},{\"type\":\"error\",\"name\":\"SuperchainProxyAdminMismatch\",\"inputs\":[]}]", - Bin: "0x6101806040523480156200001257600080fd5b5060405162002e0a38038062002e0a833981016040819052620000359162000306565b60405163b6a4cd2160e01b81526001600160a01b03838116600483015287169063b6a4cd219060240160006040518083038186803b1580156200007757600080fd5b505afa1580156200008c573d6000803e3d6000fd5b505060405163b6a4cd2160e01b81526001600160a01b0384811660048301528916925063b6a4cd21915060240160006040518083038186803b158015620000d257600080fd5b505afa158015620000e7573d6000803e3d6000fd5b505060405163b6a4cd2160e01b81526001600160a01b038a811660048301528916925063b6a4cd21915060240160006040518083038186803b1580156200012d57600080fd5b505afa15801562000142573d6000803e3d6000fd5b505060405163b6a4cd2160e01b81526001600160a01b03891660048201819052925063b6a4cd21915060240160006040518083038186803b1580156200018757600080fd5b505afa1580156200019c573d6000803e3d6000fd5b505060405163b6a4cd2160e01b81526001600160a01b0388811660048301528916925063b6a4cd21915060240160006040518083038186803b158015620001e257600080fd5b505afa158015620001f7573d6000803e3d6000fd5b505060405163b6a4cd2160e01b81526001600160a01b0387811660048301528916925063b6a4cd21915060240160006040518083038186803b1580156200023d57600080fd5b505afa15801562000252573d6000803e3d6000fd5b505060405163b6a4cd2160e01b81526001600160a01b0386811660048301528916925063b6a4cd21915060240160006040518083038186803b1580156200029857600080fd5b505afa158015620002ad573d6000803e3d6000fd5b5050506001600160a01b039788166080525094861660a05292851660c05290841660e05283166101005282166101205216610140523061016052620003b1565b6001600160a01b03811681146200030357600080fd5b50565b600080600080600080600060e0888a0312156200032257600080fd5b87516200032f81620002ed565b60208901519097506200034281620002ed565b60408901519096506200035581620002ed565b60608901519095506200036881620002ed565b60808901519094506200037b81620002ed565b60a08901519093506200038e81620002ed565b60c0890151909250620003a181620002ed565b8091505092959891949750929550565b60805160a05160c05160e05161010051610120516101405161016051612967620004a3600039600081816108610152818161096901528181610ce101528181610e8f0152610f950152600061032f0152600081816102600152610b50015260008181610416015281816104cb015281816107cc01528181610c9601526110b70152600081816101fb015261092b01526000818161019701528181610f5e015261105f015260008181610308015281816105550152818161066d0152818161072001528181610b2101528181610bf00152610dfd01526000818161043d01528181610a350152610dab01526129676000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c8063622d56f1116100e3578063b51f9c2b1161008c578063c993f27c11610066578063c993f27c1461045f578063cbeda5a714610472578063f3edcbe11461048557600080fd5b8063b51f9c2b146103ba578063ba7903db14610411578063becbdf4a1461043857600080fd5b806378ecabce116100bd57806378ecabce146103715780638970ac4414610394578063b23cc044146103a757600080fd5b8063622d56f1146103035780636624856a1461032a5780636ab5f6611461035157600080fd5b8063318b1b801161014557806354fd4d501161011f57806354fd4d501461029557806358084273146102ce578063604aa628146102e357600080fd5b8063318b1b801461024857806335e80ab31461025b57806341fe53851461028257600080fd5b80631481a724116101765780631481a724146101f65780631d8a4e921461021d57806330e9012c1461023357600080fd5b806303dbe68c146101925780630e9d5cb9146101d6575b600080fd5b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6101e96101e4366004611393565b610498565b6040516101cd9190611436565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b610225610551565b6040519081526020016101cd565b61023b6105da565b6040516101cd9190611449565b6101b96102563660046115b1565b6106ee565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b6101e96102903660046115ca565b610799565b60408051808201909152600581527f362e312e3000000000000000000000000000000000000000000000000000000060208201526101e9565b6102e16102dc366004611602565b61084f565b005b6102f66102f1366004611715565b610955565b6040516101cd91906118aa565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b61036461035f366004611906565b610a70565b6040516101cd9190611942565b61038461037f3660046115b1565b610bbe565b60405190151581526020016101cd565b6101e96103a2366004611b02565b610c63565b6102e16103b5366004611be6565b610ccf565b6103c2610dd0565b6040516101cd919081516001600160a01b039081168252602080840151821690830152604080840151821690830152606080840151821690830152608092830151169181019190915260a00190565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b6101b97f000000000000000000000000000000000000000000000000000000000000000081565b6102e161046d366004611c2f565b610e7d565b6102e1610480366004611be6565b610f83565b6101e9610493366004611c4c565b611084565b6040517f0e9d5cb90000000000000000000000000000000000000000000000000000000081526060906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630e9d5cb99061050490879087908790600401611c79565b600060405180830381865afa158015610521573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526105499190810190611cdb565b949350505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631d8a4e926040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190611d52565b905090565b6040805161024081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101e0810182905261020081018290526102208101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166330e9012c6040518163ffffffff1660e01b815260040161024060405180830381865afa1580156106ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d59190611d76565b6040517f318b1b80000000000000000000000000000000000000000000000000000000008152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063318b1b8090602401602060405180830381865afa15801561076f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107939190611ece565b92915050565b6040517f41fe53850000000000000000000000000000000000000000000000000000000081526060906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906341fe5385906108039086908690600401611eeb565b600060405180830381865afa158015610820573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108489190810190611cdb565b9392505050565b6108576110ee565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036108b9576040517f0a57d61d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000816040516024016108cc9190611ffd565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f580842730000000000000000000000000000000000000000000000000000000017905290506109507f000000000000000000000000000000000000000000000000000000000000000082611133565b505050565b606061095f6110ee565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036109c1576040517f0a57d61d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826040516024016109d491906120f0565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f604aa6280000000000000000000000000000000000000000000000000000000017905290506000610a5a7f000000000000000000000000000000000000000000000000000000000000000083611133565b9050808060200190518101906105499190612225565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c0810191909152610af16110ee565b6040517fcefe12230000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cefe122390610b7a9085907f000000000000000000000000000000000000000000000000000000000000000090339060040161240e565b6101e0604051808303816000875af1158015610b9a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079391906125e2565b6040517f78ecabce000000000000000000000000000000000000000000000000000000008152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906378ecabce90602401602060405180830381865afa158015610c3f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061079391906126f9565b6040517f8970ac440000000000000000000000000000000000000000000000000000000081526060906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690638970ac449061050490879087908790600401612716565b610cd76110ee565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610d39576040517f0a57d61d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081604051602401610d4c9190612787565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb23cc0440000000000000000000000000000000000000000000000000000000017905290506109507f000000000000000000000000000000000000000000000000000000000000000082611133565b6040805160a0810182526000808252602082018190529181018290526060810182905260808101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b51f9c2b6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610e59573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105d591906127f2565b610e856110ee565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610ee7576040517f0a57d61d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040516001600160a01b038216602482015260009060440160408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fc993f27c0000000000000000000000000000000000000000000000000000000017905290506109507f000000000000000000000000000000000000000000000000000000000000000082611133565b610f8b6110ee565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610fed576040517f0a57d61d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081604051602401611000919061288a565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fcbeda5a70000000000000000000000000000000000000000000000000000000017905290506109507f000000000000000000000000000000000000000000000000000000000000000082611133565b6040517ff3edcbe10000000000000000000000000000000000000000000000000000000081526060906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f3edcbe19061080390869086906004016128e9565b6110fa62010000610bbe565b15611131576040517fe232d67700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6060600080846001600160a01b031684604051611150919061293e565b600060405180830381855af49150503d806000811461118b576040519150601f19603f3d011682016040523d82523d6000602084013e611190565b606091505b50915091508161054957805160208201fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156111f4576111f46111a2565b60405290565b604051610180810167ffffffffffffffff811182821017156111f4576111f46111a2565b604051610240810167ffffffffffffffff811182821017156111f4576111f46111a2565b6040516101e0810167ffffffffffffffff811182821017156111f4576111f46111a2565b604051601f8201601f1916810167ffffffffffffffff8111828210171561128f5761128f6111a2565b604052919050565b6001600160a01b03811681146112ac57600080fd5b50565b80356112ba81611297565b919050565b6000608082840312156112d157600080fd5b6040516080810181811067ffffffffffffffff821117156112f4576112f46111a2565b604052905080823561130581611297565b808252506020830135602082015260408301356040820152606083013561132b81611297565b6060919091015292915050565b80151581146112ac57600080fd5b80356112ba81611338565b60006040828403121561136357600080fd5b61136b6111d1565b9050813561137881611297565b8152602082013561138881611297565b602082015292915050565b600080600060e084860312156113a857600080fd5b6113b285856112bf565b925060808401356113c281611338565b91506113d18560a08601611351565b90509250925092565b60005b838110156113f55781810151838201526020016113dd565b83811115611404576000848401525b50505050565b600081518084526114228160208601602086016113da565b601f01601f19169290920160200192915050565b602081526000610848602083018461140a565b81516001600160a01b031681526102408101602083015161147560208401826001600160a01b03169052565b50604083015161149060408401826001600160a01b03169052565b5060608301516114ab60608401826001600160a01b03169052565b5060808301516114c660808401826001600160a01b03169052565b5060a08301516114e160a08401826001600160a01b03169052565b5060c08301516114fc60c08401826001600160a01b03169052565b5060e083015161151760e08401826001600160a01b03169052565b50610100838101516001600160a01b0390811691840191909152610120808501518216908401526101408085015182169084015261016080850151821690840152610180808501518216908401526101a0808501518216908401526101c0808501518216908401526101e080850151821690840152610200808501518216908401526102208085015191821681850152905b505092915050565b6000602082840312156115c357600080fd5b5035919050565b60008060a083850312156115dd57600080fd5b6115e784846112bf565b915060808301356115f781611338565b809150509250929050565b60006020828403121561161457600080fd5b813567ffffffffffffffff81111561162b57600080fd5b8201610160818503121561084857600080fd5b600067ffffffffffffffff821115611658576116586111a2565b5060051b60200190565b600067ffffffffffffffff82111561167c5761167c6111a2565b50601f01601f191660200190565b600082601f83011261169b57600080fd5b81356116ae6116a982611662565b611266565b8181528460208386010111156116c357600080fd5b816020850160208301376000918101602001919091529392505050565b803563ffffffff811681146112ba57600080fd5b67ffffffffffffffff811681146112ac57600080fd5b80356112ba816116f4565b6000602080838503121561172857600080fd5b823567ffffffffffffffff8082111561174057600080fd5b818501915085601f83011261175457600080fd5b81356117626116a98261163e565b81815260059190911b8301840190848101908883111561178157600080fd5b8585015b8381101561189d5780358581111561179d5760008081fd5b8601610180818c03601f19018113156117b65760008081fd5b6117be6111fa565b89830135888111156117d05760008081fd5b6117de8e8c8387010161168a565b82525060406117ee8185016112af565b8b83015260606117ff8186016112af565b82840152608091506118128286016116e0565b818401525060a0808501358284015260c0915081850135818401525060e08085013582840152610100915061184882860161170a565b9083015261012061185a85820161170a565b82840152610140915081850135818401525061016061187a8186016112af565b82840152611889848601611346565b908301525085525050918601918601611785565b5098975050505050505050565b602080825282518282018190526000919060409081850190868401855b828110156118f957815180516001600160a01b03908116865290870151168685015292840192908501906001016118c7565b5091979650505050505050565b60006020828403121561191857600080fd5b813567ffffffffffffffff81111561192f57600080fd5b8201610260818503121561084857600080fd5b81516001600160a01b031681526101e08101602083015161196e60208401826001600160a01b03169052565b50604083015161198960408401826001600160a01b03169052565b5060608301516119a460608401826001600160a01b03169052565b5060808301516119bf60808401826001600160a01b03169052565b5060a08301516119da60a08401826001600160a01b03169052565b5060c08301516119f560c08401826001600160a01b03169052565b5060e0830151611a1060e08401826001600160a01b03169052565b50610100838101516001600160a01b0390811691840191909152610120808501518216908401526101408085015182169084015261016080850151821690840152610180808501518216908401526101a0808501518216908401526101c08085015191821681850152906115a9565b600060a08284031215611a9157600080fd5b60405160a0810181811067ffffffffffffffff82111715611ab457611ab46111a2565b6040529050808235611ac581611297565b808252506020830135602082015260408301356040820152606083013560608201526080830135611af581611297565b6080919091015292915050565b60008060006101008486031215611b1857600080fd5b611b228585611a7f565b925060a0840135611b3281611338565b91506113d18560c08601611351565b6000611b4f6116a98461163e565b83815290506020808201906060808602850187811115611b6e57600080fd5b855b81811015611bda5782818a031215611b885760008081fd5b6040805184810181811067ffffffffffffffff82111715611bab57611bab6111a2565b82528235611bb881611297565b8152828601358682015281830135918101919091528552938301938201611b70565b50505050509392505050565b600060208284031215611bf857600080fd5b813567ffffffffffffffff811115611c0f57600080fd5b8201601f81018413611c2057600080fd5b61054984823560208401611b41565b600060208284031215611c4157600080fd5b813561084881611297565b60008060c08385031215611c5f57600080fd5b611c698484611a7f565b915060a08301356115f781611338565b60e08101611cb1828680516001600160a01b039081168352602080830151908401526040808301519084015260609182015116910152565b831515608083015282516001600160a01b0390811660a084015260208401511660c0830152610549565b600060208284031215611ced57600080fd5b815167ffffffffffffffff811115611d0457600080fd5b8201601f81018413611d1557600080fd5b8051611d236116a982611662565b818152856020838501011115611d3857600080fd5b611d498260208301602086016113da565b95945050505050565b600060208284031215611d6457600080fd5b5051919050565b80516112ba81611297565b60006102408284031215611d8957600080fd5b611d9161121e565b611d9a83611d6b565b8152611da860208401611d6b565b6020820152611db960408401611d6b565b6040820152611dca60608401611d6b565b6060820152611ddb60808401611d6b565b6080820152611dec60a08401611d6b565b60a0820152611dfd60c08401611d6b565b60c0820152611e0e60e08401611d6b565b60e0820152610100611e21818501611d6b565b90820152610120611e33848201611d6b565b90820152610140611e45848201611d6b565b90820152610160611e57848201611d6b565b90820152610180611e69848201611d6b565b908201526101a0611e7b848201611d6b565b908201526101c0611e8d848201611d6b565b908201526101e0611e9f848201611d6b565b90820152610200611eb1848201611d6b565b90820152610220611ec3848201611d6b565b908201529392505050565b600060208284031215611ee057600080fd5b815161084881611297565b60a08101611f23828580516001600160a01b039081168352602080830151908401526040808301519084015260609182015116910152565b82151560808301529392505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112611f6757600080fd5b830160208101925035905067ffffffffffffffff811115611f8757600080fd5b606081023603821315611f9957600080fd5b9250929050565b8183526000602080850194508260005b85811015611ff2578135611fc381611297565b6001600160a01b0316875281830135838801526040808301359088015260609687019690910190600101611fb0565b509495945050505050565b602081526000823561200e81611338565b8015156020840152506020830135604083015260408301356060830152606083013561203981611297565b6001600160a01b0380821660808501526080850135915061205982611297565b80821660a0850152505060a083013560c083015260c083013560e083015261010060e084013581840152808401359050612092816116f4565b61012067ffffffffffffffff8216818501526120af81860161170a565b9150506101406120ca8185018367ffffffffffffffff169052565b6120d681860186611f32565b6101608681015292509050611d4961018085018383611fa0565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015612217577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08984030185528151610180815181865261215c8287018261140a565b915050888201516121778a8701826001600160a01b03169052565b50878201516001600160a01b03908116868a015260608084015163ffffffff16908701526080808401519087015260a0808401519087015260c0808401519087015260e08084015167ffffffffffffffff9081169188019190915261010080850151909116908701526101208084015190870152610140808401519091169086015261016091820151151591909401529386019390860190600101612117565b509098975050505050505050565b6000602080838503121561223857600080fd5b825167ffffffffffffffff81111561224f57600080fd5b8301601f8101851361226057600080fd5b805161226e6116a98261163e565b81815260069190911b8201830190838101908783111561228d57600080fd5b928401925b828410156122e357604084890312156122ab5760008081fd5b6122b36111d1565b84516122be81611297565b8152848601516122cd81611297565b8187015282526040939093019290840190612292565b979650505050505050565b80356122f981611297565b6001600160a01b03908116835260208201359061231582611297565b908116602084015260408201359061232c82611297565b908116604084015260608201359061234382611297565b908116606084015260808201359061235a82611297565b908116608084015260a08201359061237182611297565b80821660a085015250505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126123b457600080fd5b830160208101925035905067ffffffffffffffff8111156123d457600080fd5b803603821315611f9957600080fd5b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b6060815261241f60608201856122ee565b600061242d60c086016116e0565b6101206124418185018363ffffffff169052565b61244d60e088016116e0565b91506101406124638186018463ffffffff169052565b61016092506101008801358386015261247e8289018961237f565b9250610260610180818189015261249a6102c0890186856123e3565b94506124a8848c018c61237f565b945092506101a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa089870301818a01526124e38686866123e3565b95506124f0878d0161170a565b96506101c0945061250c858a018867ffffffffffffffff169052565b612517828d016116e0565b96506101e0935061252f848a018863ffffffff169052565b6102009650808c0135878a01525050610220838b0135818901526102409350828b013584890152612561868c0161170a565b67ffffffffffffffff811689840152955061257d818c0161170a565b955050505061259961028086018467ffffffffffffffff169052565b6125a4818901611346565b9250506125b66102a085018315159052565b6001600160a01b038616602085015291506125ce9050565b6001600160a01b0383166040830152610549565b60006101e082840312156125f557600080fd5b6125fd611242565b61260683611d6b565b815261261460208401611d6b565b602082015261262560408401611d6b565b604082015261263660608401611d6b565b606082015261264760808401611d6b565b608082015261265860a08401611d6b565b60a082015261266960c08401611d6b565b60c082015261267a60e08401611d6b565b60e082015261010061268d818501611d6b565b9082015261012061269f848201611d6b565b908201526101406126b1848201611d6b565b908201526101606126c3848201611d6b565b908201526101806126d5848201611d6b565b908201526101a06126e7848201611d6b565b908201526101c0611ec3848201611d6b565b60006020828403121561270b57600080fd5b815161084881611338565b610100810161275d82866001600160a01b03808251168352602082015160208401526040820151604084015260608201516060840152806080830151166080840152505050565b83151560a083015282516001600160a01b0390811660c084015260208401511660e0830152610549565b6020808252825182820181905260009190848201906040850190845b818110156127e6576127d383855180516001600160a01b0316825260208082015190830152604090810151910152565b92840192606092909201916001016127a3565b50909695505050505050565b600060a0828403121561280457600080fd5b60405160a0810181811067ffffffffffffffff82111715612827576128276111a2565b604052825161283581611297565b8152602083015161284581611297565b6020820152604083015161285881611297565b6040820152606083015161286b81611297565b6060820152608083015161287e81611297565b60808201529392505050565b6020808252825182820181905260009190848201906040850190845b818110156127e6576128d683855180516001600160a01b0316825260208082015190830152604090810151910152565b92840192606092909201916001016128a6565b60c0810161292f82856001600160a01b03808251168352602082015160208401526040820151604084015260608201516060840152806080830151166080840152505050565b82151560a08301529392505050565b600082516129508184602087016113da565b919091019291505056fea164736f6c634300080f000a", -} - -// OPContractsManagerABI is the input ABI used to generate the binding from. -// Deprecated: Use OPContractsManagerMetaData.ABI instead. -var OPContractsManagerABI = OPContractsManagerMetaData.ABI - -// OPContractsManagerBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use OPContractsManagerMetaData.Bin instead. -var OPContractsManagerBin = OPContractsManagerMetaData.Bin - -// DeployOPContractsManager deploys a new Ethereum contract, binding an instance of OPContractsManager to it. -func DeployOPContractsManager(auth *bind.TransactOpts, backend bind.ContractBackend, _opcmGameTypeAdder common.Address, _opcmDeployer common.Address, _opcmUpgrader common.Address, _opcmInteropMigrator common.Address, _opcmStandardValidator common.Address, _superchainConfig common.Address, _protocolVersions common.Address) (common.Address, *types.Transaction, *OPContractsManager, error) { - parsed, err := OPContractsManagerMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(OPContractsManagerBin), backend, _opcmGameTypeAdder, _opcmDeployer, _opcmUpgrader, _opcmInteropMigrator, _opcmStandardValidator, _superchainConfig, _protocolVersions) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &OPContractsManager{OPContractsManagerCaller: OPContractsManagerCaller{contract: contract}, OPContractsManagerTransactor: OPContractsManagerTransactor{contract: contract}, OPContractsManagerFilterer: OPContractsManagerFilterer{contract: contract}}, nil -} - -// OPContractsManager is an auto generated Go binding around an Ethereum contract. -type OPContractsManager struct { - OPContractsManagerCaller // Read-only binding to the contract - OPContractsManagerTransactor // Write-only binding to the contract - OPContractsManagerFilterer // Log filterer for contract events -} - -// OPContractsManagerCaller is an auto generated read-only Go binding around an Ethereum contract. -type OPContractsManagerCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// OPContractsManagerTransactor is an auto generated write-only Go binding around an Ethereum contract. -type OPContractsManagerTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// OPContractsManagerFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type OPContractsManagerFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// OPContractsManagerSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type OPContractsManagerSession struct { - Contract *OPContractsManager // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// OPContractsManagerCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type OPContractsManagerCallerSession struct { - Contract *OPContractsManagerCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// OPContractsManagerTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type OPContractsManagerTransactorSession struct { - Contract *OPContractsManagerTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// OPContractsManagerRaw is an auto generated low-level Go binding around an Ethereum contract. -type OPContractsManagerRaw struct { - Contract *OPContractsManager // Generic contract binding to access the raw methods on -} - -// OPContractsManagerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type OPContractsManagerCallerRaw struct { - Contract *OPContractsManagerCaller // Generic read-only contract binding to access the raw methods on -} - -// OPContractsManagerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type OPContractsManagerTransactorRaw struct { - Contract *OPContractsManagerTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewOPContractsManager creates a new instance of OPContractsManager, bound to a specific deployed contract. -func NewOPContractsManager(address common.Address, backend bind.ContractBackend) (*OPContractsManager, error) { - contract, err := bindOPContractsManager(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &OPContractsManager{OPContractsManagerCaller: OPContractsManagerCaller{contract: contract}, OPContractsManagerTransactor: OPContractsManagerTransactor{contract: contract}, OPContractsManagerFilterer: OPContractsManagerFilterer{contract: contract}}, nil -} - -// NewOPContractsManagerCaller creates a new read-only instance of OPContractsManager, bound to a specific deployed contract. -func NewOPContractsManagerCaller(address common.Address, caller bind.ContractCaller) (*OPContractsManagerCaller, error) { - contract, err := bindOPContractsManager(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &OPContractsManagerCaller{contract: contract}, nil -} - -// NewOPContractsManagerTransactor creates a new write-only instance of OPContractsManager, bound to a specific deployed contract. -func NewOPContractsManagerTransactor(address common.Address, transactor bind.ContractTransactor) (*OPContractsManagerTransactor, error) { - contract, err := bindOPContractsManager(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &OPContractsManagerTransactor{contract: contract}, nil -} - -// NewOPContractsManagerFilterer creates a new log filterer instance of OPContractsManager, bound to a specific deployed contract. -func NewOPContractsManagerFilterer(address common.Address, filterer bind.ContractFilterer) (*OPContractsManagerFilterer, error) { - contract, err := bindOPContractsManager(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &OPContractsManagerFilterer{contract: contract}, nil -} - -// bindOPContractsManager binds a generic wrapper to an already deployed contract. -func bindOPContractsManager(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := OPContractsManagerMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_OPContractsManager *OPContractsManagerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _OPContractsManager.Contract.OPContractsManagerCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_OPContractsManager *OPContractsManagerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _OPContractsManager.Contract.OPContractsManagerTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_OPContractsManager *OPContractsManagerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _OPContractsManager.Contract.OPContractsManagerTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_OPContractsManager *OPContractsManagerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _OPContractsManager.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_OPContractsManager *OPContractsManagerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _OPContractsManager.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_OPContractsManager *OPContractsManagerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _OPContractsManager.Contract.contract.Transact(opts, method, params...) -} - -// Blueprints is a free data retrieval call binding the contract method 0xb51f9c2b. -// -// Solidity: function blueprints() view returns((address,address,address,address,address)) -func (_OPContractsManager *OPContractsManagerCaller) Blueprints(opts *bind.CallOpts) (OPContractsManagerBlueprints, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "blueprints") - - if err != nil { - return *new(OPContractsManagerBlueprints), err - } - - out0 := *abi.ConvertType(out[0], new(OPContractsManagerBlueprints)).(*OPContractsManagerBlueprints) - - return out0, err - -} - -// Blueprints is a free data retrieval call binding the contract method 0xb51f9c2b. -// -// Solidity: function blueprints() view returns((address,address,address,address,address)) -func (_OPContractsManager *OPContractsManagerSession) Blueprints() (OPContractsManagerBlueprints, error) { - return _OPContractsManager.Contract.Blueprints(&_OPContractsManager.CallOpts) -} - -// Blueprints is a free data retrieval call binding the contract method 0xb51f9c2b. -// -// Solidity: function blueprints() view returns((address,address,address,address,address)) -func (_OPContractsManager *OPContractsManagerCallerSession) Blueprints() (OPContractsManagerBlueprints, error) { - return _OPContractsManager.Contract.Blueprints(&_OPContractsManager.CallOpts) -} - -// ChainIdToBatchInboxAddress is a free data retrieval call binding the contract method 0x318b1b80. -// -// Solidity: function chainIdToBatchInboxAddress(uint256 _l2ChainId) view returns(address) -func (_OPContractsManager *OPContractsManagerCaller) ChainIdToBatchInboxAddress(opts *bind.CallOpts, _l2ChainId *big.Int) (common.Address, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "chainIdToBatchInboxAddress", _l2ChainId) - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// ChainIdToBatchInboxAddress is a free data retrieval call binding the contract method 0x318b1b80. -// -// Solidity: function chainIdToBatchInboxAddress(uint256 _l2ChainId) view returns(address) -func (_OPContractsManager *OPContractsManagerSession) ChainIdToBatchInboxAddress(_l2ChainId *big.Int) (common.Address, error) { - return _OPContractsManager.Contract.ChainIdToBatchInboxAddress(&_OPContractsManager.CallOpts, _l2ChainId) -} - -// ChainIdToBatchInboxAddress is a free data retrieval call binding the contract method 0x318b1b80. -// -// Solidity: function chainIdToBatchInboxAddress(uint256 _l2ChainId) view returns(address) -func (_OPContractsManager *OPContractsManagerCallerSession) ChainIdToBatchInboxAddress(_l2ChainId *big.Int) (common.Address, error) { - return _OPContractsManager.Contract.ChainIdToBatchInboxAddress(&_OPContractsManager.CallOpts, _l2ChainId) -} - -// DevFeatureBitmap is a free data retrieval call binding the contract method 0x1d8a4e92. -// -// Solidity: function devFeatureBitmap() view returns(bytes32) -func (_OPContractsManager *OPContractsManagerCaller) DevFeatureBitmap(opts *bind.CallOpts) ([32]byte, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "devFeatureBitmap") - - if err != nil { - return *new([32]byte), err - } - - out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) - - return out0, err - -} - -// DevFeatureBitmap is a free data retrieval call binding the contract method 0x1d8a4e92. -// -// Solidity: function devFeatureBitmap() view returns(bytes32) -func (_OPContractsManager *OPContractsManagerSession) DevFeatureBitmap() ([32]byte, error) { - return _OPContractsManager.Contract.DevFeatureBitmap(&_OPContractsManager.CallOpts) -} - -// DevFeatureBitmap is a free data retrieval call binding the contract method 0x1d8a4e92. -// -// Solidity: function devFeatureBitmap() view returns(bytes32) -func (_OPContractsManager *OPContractsManagerCallerSession) DevFeatureBitmap() ([32]byte, error) { - return _OPContractsManager.Contract.DevFeatureBitmap(&_OPContractsManager.CallOpts) -} - -// Implementations is a free data retrieval call binding the contract method 0x30e9012c. -// -// Solidity: function implementations() view returns((address,address,address,address,address,address,address,address,address,address,address,address,address,address,address,address,address,address)) -func (_OPContractsManager *OPContractsManagerCaller) Implementations(opts *bind.CallOpts) (OPContractsManagerImplementations, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "implementations") - - if err != nil { - return *new(OPContractsManagerImplementations), err - } - - out0 := *abi.ConvertType(out[0], new(OPContractsManagerImplementations)).(*OPContractsManagerImplementations) - - return out0, err - -} - -// Implementations is a free data retrieval call binding the contract method 0x30e9012c. -// -// Solidity: function implementations() view returns((address,address,address,address,address,address,address,address,address,address,address,address,address,address,address,address,address,address)) -func (_OPContractsManager *OPContractsManagerSession) Implementations() (OPContractsManagerImplementations, error) { - return _OPContractsManager.Contract.Implementations(&_OPContractsManager.CallOpts) -} - -// Implementations is a free data retrieval call binding the contract method 0x30e9012c. -// -// Solidity: function implementations() view returns((address,address,address,address,address,address,address,address,address,address,address,address,address,address,address,address,address,address)) -func (_OPContractsManager *OPContractsManagerCallerSession) Implementations() (OPContractsManagerImplementations, error) { - return _OPContractsManager.Contract.Implementations(&_OPContractsManager.CallOpts) -} - -// IsDevFeatureEnabled is a free data retrieval call binding the contract method 0x78ecabce. -// -// Solidity: function isDevFeatureEnabled(bytes32 _feature) view returns(bool) -func (_OPContractsManager *OPContractsManagerCaller) IsDevFeatureEnabled(opts *bind.CallOpts, _feature [32]byte) (bool, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "isDevFeatureEnabled", _feature) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// IsDevFeatureEnabled is a free data retrieval call binding the contract method 0x78ecabce. -// -// Solidity: function isDevFeatureEnabled(bytes32 _feature) view returns(bool) -func (_OPContractsManager *OPContractsManagerSession) IsDevFeatureEnabled(_feature [32]byte) (bool, error) { - return _OPContractsManager.Contract.IsDevFeatureEnabled(&_OPContractsManager.CallOpts, _feature) -} - -// IsDevFeatureEnabled is a free data retrieval call binding the contract method 0x78ecabce. -// -// Solidity: function isDevFeatureEnabled(bytes32 _feature) view returns(bool) -func (_OPContractsManager *OPContractsManagerCallerSession) IsDevFeatureEnabled(_feature [32]byte) (bool, error) { - return _OPContractsManager.Contract.IsDevFeatureEnabled(&_OPContractsManager.CallOpts, _feature) -} - -// OpcmDeployer is a free data retrieval call binding the contract method 0x622d56f1. -// -// Solidity: function opcmDeployer() view returns(address) -func (_OPContractsManager *OPContractsManagerCaller) OpcmDeployer(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "opcmDeployer") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// OpcmDeployer is a free data retrieval call binding the contract method 0x622d56f1. -// -// Solidity: function opcmDeployer() view returns(address) -func (_OPContractsManager *OPContractsManagerSession) OpcmDeployer() (common.Address, error) { - return _OPContractsManager.Contract.OpcmDeployer(&_OPContractsManager.CallOpts) -} - -// OpcmDeployer is a free data retrieval call binding the contract method 0x622d56f1. -// -// Solidity: function opcmDeployer() view returns(address) -func (_OPContractsManager *OPContractsManagerCallerSession) OpcmDeployer() (common.Address, error) { - return _OPContractsManager.Contract.OpcmDeployer(&_OPContractsManager.CallOpts) -} - -// OpcmGameTypeAdder is a free data retrieval call binding the contract method 0xbecbdf4a. -// -// Solidity: function opcmGameTypeAdder() view returns(address) -func (_OPContractsManager *OPContractsManagerCaller) OpcmGameTypeAdder(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "opcmGameTypeAdder") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// OpcmGameTypeAdder is a free data retrieval call binding the contract method 0xbecbdf4a. -// -// Solidity: function opcmGameTypeAdder() view returns(address) -func (_OPContractsManager *OPContractsManagerSession) OpcmGameTypeAdder() (common.Address, error) { - return _OPContractsManager.Contract.OpcmGameTypeAdder(&_OPContractsManager.CallOpts) -} - -// OpcmGameTypeAdder is a free data retrieval call binding the contract method 0xbecbdf4a. -// -// Solidity: function opcmGameTypeAdder() view returns(address) -func (_OPContractsManager *OPContractsManagerCallerSession) OpcmGameTypeAdder() (common.Address, error) { - return _OPContractsManager.Contract.OpcmGameTypeAdder(&_OPContractsManager.CallOpts) -} - -// OpcmInteropMigrator is a free data retrieval call binding the contract method 0x1481a724. -// -// Solidity: function opcmInteropMigrator() view returns(address) -func (_OPContractsManager *OPContractsManagerCaller) OpcmInteropMigrator(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "opcmInteropMigrator") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// OpcmInteropMigrator is a free data retrieval call binding the contract method 0x1481a724. -// -// Solidity: function opcmInteropMigrator() view returns(address) -func (_OPContractsManager *OPContractsManagerSession) OpcmInteropMigrator() (common.Address, error) { - return _OPContractsManager.Contract.OpcmInteropMigrator(&_OPContractsManager.CallOpts) -} - -// OpcmInteropMigrator is a free data retrieval call binding the contract method 0x1481a724. -// -// Solidity: function opcmInteropMigrator() view returns(address) -func (_OPContractsManager *OPContractsManagerCallerSession) OpcmInteropMigrator() (common.Address, error) { - return _OPContractsManager.Contract.OpcmInteropMigrator(&_OPContractsManager.CallOpts) -} - -// OpcmStandardValidator is a free data retrieval call binding the contract method 0xba7903db. -// -// Solidity: function opcmStandardValidator() view returns(address) -func (_OPContractsManager *OPContractsManagerCaller) OpcmStandardValidator(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "opcmStandardValidator") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// OpcmStandardValidator is a free data retrieval call binding the contract method 0xba7903db. -// -// Solidity: function opcmStandardValidator() view returns(address) -func (_OPContractsManager *OPContractsManagerSession) OpcmStandardValidator() (common.Address, error) { - return _OPContractsManager.Contract.OpcmStandardValidator(&_OPContractsManager.CallOpts) -} - -// OpcmStandardValidator is a free data retrieval call binding the contract method 0xba7903db. -// -// Solidity: function opcmStandardValidator() view returns(address) -func (_OPContractsManager *OPContractsManagerCallerSession) OpcmStandardValidator() (common.Address, error) { - return _OPContractsManager.Contract.OpcmStandardValidator(&_OPContractsManager.CallOpts) -} - -// OpcmUpgrader is a free data retrieval call binding the contract method 0x03dbe68c. -// -// Solidity: function opcmUpgrader() view returns(address) -func (_OPContractsManager *OPContractsManagerCaller) OpcmUpgrader(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "opcmUpgrader") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// OpcmUpgrader is a free data retrieval call binding the contract method 0x03dbe68c. -// -// Solidity: function opcmUpgrader() view returns(address) -func (_OPContractsManager *OPContractsManagerSession) OpcmUpgrader() (common.Address, error) { - return _OPContractsManager.Contract.OpcmUpgrader(&_OPContractsManager.CallOpts) -} - -// OpcmUpgrader is a free data retrieval call binding the contract method 0x03dbe68c. -// -// Solidity: function opcmUpgrader() view returns(address) -func (_OPContractsManager *OPContractsManagerCallerSession) OpcmUpgrader() (common.Address, error) { - return _OPContractsManager.Contract.OpcmUpgrader(&_OPContractsManager.CallOpts) -} - -// ProtocolVersions is a free data retrieval call binding the contract method 0x6624856a. -// -// Solidity: function protocolVersions() view returns(address) -func (_OPContractsManager *OPContractsManagerCaller) ProtocolVersions(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "protocolVersions") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// ProtocolVersions is a free data retrieval call binding the contract method 0x6624856a. -// -// Solidity: function protocolVersions() view returns(address) -func (_OPContractsManager *OPContractsManagerSession) ProtocolVersions() (common.Address, error) { - return _OPContractsManager.Contract.ProtocolVersions(&_OPContractsManager.CallOpts) -} - -// ProtocolVersions is a free data retrieval call binding the contract method 0x6624856a. -// -// Solidity: function protocolVersions() view returns(address) -func (_OPContractsManager *OPContractsManagerCallerSession) ProtocolVersions() (common.Address, error) { - return _OPContractsManager.Contract.ProtocolVersions(&_OPContractsManager.CallOpts) -} - -// SuperchainConfig is a free data retrieval call binding the contract method 0x35e80ab3. -// -// Solidity: function superchainConfig() view returns(address) -func (_OPContractsManager *OPContractsManagerCaller) SuperchainConfig(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "superchainConfig") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// SuperchainConfig is a free data retrieval call binding the contract method 0x35e80ab3. -// -// Solidity: function superchainConfig() view returns(address) -func (_OPContractsManager *OPContractsManagerSession) SuperchainConfig() (common.Address, error) { - return _OPContractsManager.Contract.SuperchainConfig(&_OPContractsManager.CallOpts) -} - -// SuperchainConfig is a free data retrieval call binding the contract method 0x35e80ab3. -// -// Solidity: function superchainConfig() view returns(address) -func (_OPContractsManager *OPContractsManagerCallerSession) SuperchainConfig() (common.Address, error) { - return _OPContractsManager.Contract.SuperchainConfig(&_OPContractsManager.CallOpts) -} - -// Validate is a free data retrieval call binding the contract method 0x41fe5385. -// -// Solidity: function validate((address,bytes32,uint256,address) _input, bool _allowFailure) view returns(string) -func (_OPContractsManager *OPContractsManagerCaller) Validate(opts *bind.CallOpts, _input OPContractsManagerStandardValidatorValidationInput, _allowFailure bool) (string, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "validate", _input, _allowFailure) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// Validate is a free data retrieval call binding the contract method 0x41fe5385. -// -// Solidity: function validate((address,bytes32,uint256,address) _input, bool _allowFailure) view returns(string) -func (_OPContractsManager *OPContractsManagerSession) Validate(_input OPContractsManagerStandardValidatorValidationInput, _allowFailure bool) (string, error) { - return _OPContractsManager.Contract.Validate(&_OPContractsManager.CallOpts, _input, _allowFailure) -} - -// Validate is a free data retrieval call binding the contract method 0x41fe5385. -// -// Solidity: function validate((address,bytes32,uint256,address) _input, bool _allowFailure) view returns(string) -func (_OPContractsManager *OPContractsManagerCallerSession) Validate(_input OPContractsManagerStandardValidatorValidationInput, _allowFailure bool) (string, error) { - return _OPContractsManager.Contract.Validate(&_OPContractsManager.CallOpts, _input, _allowFailure) -} - -// Validate0 is a free data retrieval call binding the contract method 0xf3edcbe1. -// -// Solidity: function validate((address,bytes32,bytes32,uint256,address) _input, bool _allowFailure) view returns(string) -func (_OPContractsManager *OPContractsManagerCaller) Validate0(opts *bind.CallOpts, _input OPContractsManagerStandardValidatorValidationInputDev, _allowFailure bool) (string, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "validate0", _input, _allowFailure) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// Validate0 is a free data retrieval call binding the contract method 0xf3edcbe1. -// -// Solidity: function validate((address,bytes32,bytes32,uint256,address) _input, bool _allowFailure) view returns(string) -func (_OPContractsManager *OPContractsManagerSession) Validate0(_input OPContractsManagerStandardValidatorValidationInputDev, _allowFailure bool) (string, error) { - return _OPContractsManager.Contract.Validate0(&_OPContractsManager.CallOpts, _input, _allowFailure) -} - -// Validate0 is a free data retrieval call binding the contract method 0xf3edcbe1. -// -// Solidity: function validate((address,bytes32,bytes32,uint256,address) _input, bool _allowFailure) view returns(string) -func (_OPContractsManager *OPContractsManagerCallerSession) Validate0(_input OPContractsManagerStandardValidatorValidationInputDev, _allowFailure bool) (string, error) { - return _OPContractsManager.Contract.Validate0(&_OPContractsManager.CallOpts, _input, _allowFailure) -} - -// ValidateWithOverrides is a free data retrieval call binding the contract method 0x0e9d5cb9. -// -// Solidity: function validateWithOverrides((address,bytes32,uint256,address) _input, bool _allowFailure, (address,address) _overrides) view returns(string) -func (_OPContractsManager *OPContractsManagerCaller) ValidateWithOverrides(opts *bind.CallOpts, _input OPContractsManagerStandardValidatorValidationInput, _allowFailure bool, _overrides OPContractsManagerStandardValidatorValidationOverrides) (string, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "validateWithOverrides", _input, _allowFailure, _overrides) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// ValidateWithOverrides is a free data retrieval call binding the contract method 0x0e9d5cb9. -// -// Solidity: function validateWithOverrides((address,bytes32,uint256,address) _input, bool _allowFailure, (address,address) _overrides) view returns(string) -func (_OPContractsManager *OPContractsManagerSession) ValidateWithOverrides(_input OPContractsManagerStandardValidatorValidationInput, _allowFailure bool, _overrides OPContractsManagerStandardValidatorValidationOverrides) (string, error) { - return _OPContractsManager.Contract.ValidateWithOverrides(&_OPContractsManager.CallOpts, _input, _allowFailure, _overrides) -} - -// ValidateWithOverrides is a free data retrieval call binding the contract method 0x0e9d5cb9. -// -// Solidity: function validateWithOverrides((address,bytes32,uint256,address) _input, bool _allowFailure, (address,address) _overrides) view returns(string) -func (_OPContractsManager *OPContractsManagerCallerSession) ValidateWithOverrides(_input OPContractsManagerStandardValidatorValidationInput, _allowFailure bool, _overrides OPContractsManagerStandardValidatorValidationOverrides) (string, error) { - return _OPContractsManager.Contract.ValidateWithOverrides(&_OPContractsManager.CallOpts, _input, _allowFailure, _overrides) -} - -// ValidateWithOverrides0 is a free data retrieval call binding the contract method 0x8970ac44. -// -// Solidity: function validateWithOverrides((address,bytes32,bytes32,uint256,address) _input, bool _allowFailure, (address,address) _overrides) view returns(string) -func (_OPContractsManager *OPContractsManagerCaller) ValidateWithOverrides0(opts *bind.CallOpts, _input OPContractsManagerStandardValidatorValidationInputDev, _allowFailure bool, _overrides OPContractsManagerStandardValidatorValidationOverrides) (string, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "validateWithOverrides0", _input, _allowFailure, _overrides) - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// ValidateWithOverrides0 is a free data retrieval call binding the contract method 0x8970ac44. -// -// Solidity: function validateWithOverrides((address,bytes32,bytes32,uint256,address) _input, bool _allowFailure, (address,address) _overrides) view returns(string) -func (_OPContractsManager *OPContractsManagerSession) ValidateWithOverrides0(_input OPContractsManagerStandardValidatorValidationInputDev, _allowFailure bool, _overrides OPContractsManagerStandardValidatorValidationOverrides) (string, error) { - return _OPContractsManager.Contract.ValidateWithOverrides0(&_OPContractsManager.CallOpts, _input, _allowFailure, _overrides) -} - -// ValidateWithOverrides0 is a free data retrieval call binding the contract method 0x8970ac44. -// -// Solidity: function validateWithOverrides((address,bytes32,bytes32,uint256,address) _input, bool _allowFailure, (address,address) _overrides) view returns(string) -func (_OPContractsManager *OPContractsManagerCallerSession) ValidateWithOverrides0(_input OPContractsManagerStandardValidatorValidationInputDev, _allowFailure bool, _overrides OPContractsManagerStandardValidatorValidationOverrides) (string, error) { - return _OPContractsManager.Contract.ValidateWithOverrides0(&_OPContractsManager.CallOpts, _input, _allowFailure, _overrides) -} - -// Version is a free data retrieval call binding the contract method 0x54fd4d50. -// -// Solidity: function version() pure returns(string) -func (_OPContractsManager *OPContractsManagerCaller) Version(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _OPContractsManager.contract.Call(opts, &out, "version") - - if err != nil { - return *new(string), err - } - - out0 := *abi.ConvertType(out[0], new(string)).(*string) - - return out0, err - -} - -// Version is a free data retrieval call binding the contract method 0x54fd4d50. -// -// Solidity: function version() pure returns(string) -func (_OPContractsManager *OPContractsManagerSession) Version() (string, error) { - return _OPContractsManager.Contract.Version(&_OPContractsManager.CallOpts) -} - -// Version is a free data retrieval call binding the contract method 0x54fd4d50. -// -// Solidity: function version() pure returns(string) -func (_OPContractsManager *OPContractsManagerCallerSession) Version() (string, error) { - return _OPContractsManager.Contract.Version(&_OPContractsManager.CallOpts) -} - -// AddGameType is a paid mutator transaction binding the contract method 0x604aa628. -// -// Solidity: function addGameType((string,address,address,uint32,bytes32,uint256,uint256,uint64,uint64,uint256,address,bool)[] _gameConfigs) returns((address,address)[]) -func (_OPContractsManager *OPContractsManagerTransactor) AddGameType(opts *bind.TransactOpts, _gameConfigs []OPContractsManagerAddGameInput) (*types.Transaction, error) { - return _OPContractsManager.contract.Transact(opts, "addGameType", _gameConfigs) -} - -// AddGameType is a paid mutator transaction binding the contract method 0x604aa628. -// -// Solidity: function addGameType((string,address,address,uint32,bytes32,uint256,uint256,uint64,uint64,uint256,address,bool)[] _gameConfigs) returns((address,address)[]) -func (_OPContractsManager *OPContractsManagerSession) AddGameType(_gameConfigs []OPContractsManagerAddGameInput) (*types.Transaction, error) { - return _OPContractsManager.Contract.AddGameType(&_OPContractsManager.TransactOpts, _gameConfigs) -} - -// AddGameType is a paid mutator transaction binding the contract method 0x604aa628. -// -// Solidity: function addGameType((string,address,address,uint32,bytes32,uint256,uint256,uint64,uint64,uint256,address,bool)[] _gameConfigs) returns((address,address)[]) -func (_OPContractsManager *OPContractsManagerTransactorSession) AddGameType(_gameConfigs []OPContractsManagerAddGameInput) (*types.Transaction, error) { - return _OPContractsManager.Contract.AddGameType(&_OPContractsManager.TransactOpts, _gameConfigs) -} - -// Deploy is a paid mutator transaction binding the contract method 0x6ab5f661. -// -// Solidity: function deploy(((address,address,address,address,address,address),uint32,uint32,uint256,bytes,string,uint64,uint32,bytes32,uint256,uint256,uint64,uint64,bool) _input) returns((address,address,address,address,address,address,address,address,address,address,address,address,address,address,address)) -func (_OPContractsManager *OPContractsManagerTransactor) Deploy(opts *bind.TransactOpts, _input OPContractsManagerDeployInput) (*types.Transaction, error) { - return _OPContractsManager.contract.Transact(opts, "deploy", _input) -} - -// Deploy is a paid mutator transaction binding the contract method 0x6ab5f661. -// -// Solidity: function deploy(((address,address,address,address,address,address),uint32,uint32,uint256,bytes,string,uint64,uint32,bytes32,uint256,uint256,uint64,uint64,bool) _input) returns((address,address,address,address,address,address,address,address,address,address,address,address,address,address,address)) -func (_OPContractsManager *OPContractsManagerSession) Deploy(_input OPContractsManagerDeployInput) (*types.Transaction, error) { - return _OPContractsManager.Contract.Deploy(&_OPContractsManager.TransactOpts, _input) -} - -// Deploy is a paid mutator transaction binding the contract method 0x6ab5f661. -// -// Solidity: function deploy(((address,address,address,address,address,address),uint32,uint32,uint256,bytes,string,uint64,uint32,bytes32,uint256,uint256,uint64,uint64,bool) _input) returns((address,address,address,address,address,address,address,address,address,address,address,address,address,address,address)) -func (_OPContractsManager *OPContractsManagerTransactorSession) Deploy(_input OPContractsManagerDeployInput) (*types.Transaction, error) { - return _OPContractsManager.Contract.Deploy(&_OPContractsManager.TransactOpts, _input) -} - -// Migrate is a paid mutator transaction binding the contract method 0x58084273. -// -// Solidity: function migrate((bool,(bytes32,uint256),(address,address,uint256,uint256,uint256,uint64,uint64),(address,bytes32,bytes32)[]) _input) returns() -func (_OPContractsManager *OPContractsManagerTransactor) Migrate(opts *bind.TransactOpts, _input OPContractsManagerInteropMigratorMigrateInput) (*types.Transaction, error) { - return _OPContractsManager.contract.Transact(opts, "migrate", _input) -} - -// Migrate is a paid mutator transaction binding the contract method 0x58084273. -// -// Solidity: function migrate((bool,(bytes32,uint256),(address,address,uint256,uint256,uint256,uint64,uint64),(address,bytes32,bytes32)[]) _input) returns() -func (_OPContractsManager *OPContractsManagerSession) Migrate(_input OPContractsManagerInteropMigratorMigrateInput) (*types.Transaction, error) { - return _OPContractsManager.Contract.Migrate(&_OPContractsManager.TransactOpts, _input) -} - -// Migrate is a paid mutator transaction binding the contract method 0x58084273. -// -// Solidity: function migrate((bool,(bytes32,uint256),(address,address,uint256,uint256,uint256,uint64,uint64),(address,bytes32,bytes32)[]) _input) returns() -func (_OPContractsManager *OPContractsManagerTransactorSession) Migrate(_input OPContractsManagerInteropMigratorMigrateInput) (*types.Transaction, error) { - return _OPContractsManager.Contract.Migrate(&_OPContractsManager.TransactOpts, _input) -} - -// UpdatePrestate is a paid mutator transaction binding the contract method 0xb23cc044. -// -// Solidity: function updatePrestate((address,bytes32,bytes32)[] _prestateUpdateInputs) returns() -func (_OPContractsManager *OPContractsManagerTransactor) UpdatePrestate(opts *bind.TransactOpts, _prestateUpdateInputs []OPContractsManagerUpdatePrestateInput) (*types.Transaction, error) { - return _OPContractsManager.contract.Transact(opts, "updatePrestate", _prestateUpdateInputs) -} - -// UpdatePrestate is a paid mutator transaction binding the contract method 0xb23cc044. -// -// Solidity: function updatePrestate((address,bytes32,bytes32)[] _prestateUpdateInputs) returns() -func (_OPContractsManager *OPContractsManagerSession) UpdatePrestate(_prestateUpdateInputs []OPContractsManagerUpdatePrestateInput) (*types.Transaction, error) { - return _OPContractsManager.Contract.UpdatePrestate(&_OPContractsManager.TransactOpts, _prestateUpdateInputs) -} - -// UpdatePrestate is a paid mutator transaction binding the contract method 0xb23cc044. -// -// Solidity: function updatePrestate((address,bytes32,bytes32)[] _prestateUpdateInputs) returns() -func (_OPContractsManager *OPContractsManagerTransactorSession) UpdatePrestate(_prestateUpdateInputs []OPContractsManagerUpdatePrestateInput) (*types.Transaction, error) { - return _OPContractsManager.Contract.UpdatePrestate(&_OPContractsManager.TransactOpts, _prestateUpdateInputs) -} - -// Upgrade is a paid mutator transaction binding the contract method 0xcbeda5a7. -// -// Solidity: function upgrade((address,bytes32,bytes32)[] _opChainConfigs) returns() -func (_OPContractsManager *OPContractsManagerTransactor) Upgrade(opts *bind.TransactOpts, _opChainConfigs []OPContractsManagerOpChainConfig) (*types.Transaction, error) { - return _OPContractsManager.contract.Transact(opts, "upgrade", _opChainConfigs) -} - -// Upgrade is a paid mutator transaction binding the contract method 0xcbeda5a7. -// -// Solidity: function upgrade((address,bytes32,bytes32)[] _opChainConfigs) returns() -func (_OPContractsManager *OPContractsManagerSession) Upgrade(_opChainConfigs []OPContractsManagerOpChainConfig) (*types.Transaction, error) { - return _OPContractsManager.Contract.Upgrade(&_OPContractsManager.TransactOpts, _opChainConfigs) -} - -// Upgrade is a paid mutator transaction binding the contract method 0xcbeda5a7. -// -// Solidity: function upgrade((address,bytes32,bytes32)[] _opChainConfigs) returns() -func (_OPContractsManager *OPContractsManagerTransactorSession) Upgrade(_opChainConfigs []OPContractsManagerOpChainConfig) (*types.Transaction, error) { - return _OPContractsManager.Contract.Upgrade(&_OPContractsManager.TransactOpts, _opChainConfigs) -} - -// UpgradeSuperchainConfig is a paid mutator transaction binding the contract method 0xc993f27c. -// -// Solidity: function upgradeSuperchainConfig(address _superchainConfig) returns() -func (_OPContractsManager *OPContractsManagerTransactor) UpgradeSuperchainConfig(opts *bind.TransactOpts, _superchainConfig common.Address) (*types.Transaction, error) { - return _OPContractsManager.contract.Transact(opts, "upgradeSuperchainConfig", _superchainConfig) -} - -// UpgradeSuperchainConfig is a paid mutator transaction binding the contract method 0xc993f27c. -// -// Solidity: function upgradeSuperchainConfig(address _superchainConfig) returns() -func (_OPContractsManager *OPContractsManagerSession) UpgradeSuperchainConfig(_superchainConfig common.Address) (*types.Transaction, error) { - return _OPContractsManager.Contract.UpgradeSuperchainConfig(&_OPContractsManager.TransactOpts, _superchainConfig) -} - -// UpgradeSuperchainConfig is a paid mutator transaction binding the contract method 0xc993f27c. -// -// Solidity: function upgradeSuperchainConfig(address _superchainConfig) returns() -func (_OPContractsManager *OPContractsManagerTransactorSession) UpgradeSuperchainConfig(_superchainConfig common.Address) (*types.Transaction, error) { - return _OPContractsManager.Contract.UpgradeSuperchainConfig(&_OPContractsManager.TransactOpts, _superchainConfig) -} diff --git a/op-e2e/config/init.go b/op-e2e/config/init.go index eea8dee2bce..888c91c8836 100644 --- a/op-e2e/config/init.go +++ b/op-e2e/config/init.go @@ -442,6 +442,18 @@ func defaultIntent(root string, loc *artifacts.Locator, deployer common.Address, }, VMType: cannonVMType(allocType), }, + { + ChainProofParams: state.ChainProofParams{ + // CANNON_KONA game + DisputeGameType: 8, + DisputeAbsolutePrestate: konaPrestate(root), + DisputeMaxGameDepth: 50, + DisputeSplitDepth: 14, + DisputeClockExtension: 0, + DisputeMaxClockDuration: 1200, + }, + VMType: cannonVMType(allocType), + }, }, }, }, @@ -479,6 +491,9 @@ var cannonPrestateMTNext common.Hash var cannonPrestateMTOnce sync.Once var cannonPrestateMTNextOnce sync.Once +var konaPrestateHash common.Hash +var konaPrestateOnce sync.Once + func cannonPrestate(monorepoRoot string, allocType AllocType) common.Hash { var filename string @@ -525,3 +540,28 @@ func cannonPrestate(monorepoRoot string, allocType AllocType) common.Hash { } return *cacheVar } + +func konaPrestate(monorepoRoot string) common.Hash { + konaPrestateOnce.Do(func() { + f, err := os.Open(path.Join(monorepoRoot, "rust", "kona", "prestate-artifacts-cannon", "prestate-proof.json")) + if err != nil { + log.Warn("error opening kona prestate file. If you're running a test that requires kona prestates, make sure you've run `just reproducible-prestate-kona`", "err", err) + return + } + defer f.Close() + + var prestate prestateFile + dec := json.NewDecoder(f) + if err := dec.Decode(&prestate); err != nil { + log.Error("error decoding kona prestate file", "err", err) + return + } + + konaPrestateHash = common.HexToHash(prestate.Pre) + }) + + if konaPrestateHash == (common.Hash{}) { + konaPrestateHash = common.HexToHash("0xc02b59f772cb23a75b6ffb9f7602ba25fdd5d8e75ad88efcc013fec2c63b0895") // keccak("dummy") + } + return konaPrestateHash +} diff --git a/op-e2e/e2eutils/challenger/helper.go b/op-e2e/e2eutils/challenger/helper.go index 4863019a197..4d215d72037 100644 --- a/op-e2e/e2eutils/challenger/helper.go +++ b/op-e2e/e2eutils/challenger/helper.go @@ -146,6 +146,14 @@ func WithPermissioned(t *testing.T, system System) Option { } } +func WithCannonKona(t *testing.T, system System) Option { + return func(c *config.Config) { + handleOptError(t, shared.WithCannonConfig(system.RollupCfgs(), system.L1Genesis(), system.L2Geneses(), system.PrestateVariant()))(c) + handleOptError(t, shared.WithCannonKonaConfig(system.RollupCfgs(), system.L1Genesis(), system.L2Geneses()))(c) + handleOptError(t, shared.WithCannonKonaGameType())(c) + } +} + func WithSuperCannon(t *testing.T, system System) Option { return func(c *config.Config) { handleOptError(t, shared.WithCannonConfig(system.RollupCfgs(), system.L1Genesis(), system.L2Geneses(), system.PrestateVariant()))(c) @@ -153,6 +161,14 @@ func WithSuperCannon(t *testing.T, system System) Option { } } +func WithSuperCannonKona(t *testing.T, system System) Option { + return func(c *config.Config) { + handleOptError(t, shared.WithCannonConfig(system.RollupCfgs(), system.L1Genesis(), system.L2Geneses(), system.PrestateVariant()))(c) + handleOptError(t, shared.WithCannonKonaInteropConfig(system.RollupCfgs(), system.L1Genesis(), system.L2Geneses()))(c) + handleOptError(t, shared.WithSuperCannonKonaGameType())(c) + } +} + func WithAlphabet() Option { return func(c *config.Config) { c.GameTypes = append(c.GameTypes, gameTypes.AlphabetGameType) @@ -193,6 +209,7 @@ func NewChallengerConfig(t *testing.T, sys EndpointProvider, l2NodeName string, cfg = config.NewConfig(common.Address{}, l1Endpoint, l1Beacon, sys.RollupEndpoint(l2NodeName).RPC(), sys.NodeEndpoint(l2NodeName).RPC(), t.TempDir()) } cfg.Cannon.L2Custom = true + cfg.CannonKona.L2Custom = true // The devnet can't set the absolute prestate output root because the contracts are deployed in L1 genesis // before the L2 genesis is known. cfg.AllowInvalidPrestate = true @@ -225,6 +242,10 @@ func NewChallengerConfig(t *testing.T, sys EndpointProvider, l2NodeName string, _, err := os.Stat(cfg.CannonAbsolutePreState) require.NoError(t, err, "cannon pre-state should be built. Make sure you've run make cannon-prestates") } + if cfg.CannonKona.Server != "" { + _, err := os.Stat(cfg.CannonKona.Server) + require.NoError(t, err, "kona-host should be built. Run: cd rust/kona && just build-native --profile=release") + } if cfg.PollInterval == 0 { cfg.PollInterval = time.Second } diff --git a/op-e2e/e2eutils/disputegame/cannon_helper.go b/op-e2e/e2eutils/disputegame/cannon_helper.go index c00d9ecfa52..cdf3a43c4ec 100644 --- a/op-e2e/e2eutils/disputegame/cannon_helper.go +++ b/op-e2e/e2eutils/disputegame/cannon_helper.go @@ -17,6 +17,7 @@ import ( "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/outputs" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/split" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils" + "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/vm" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" keccakTypes "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types" gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types" @@ -467,7 +468,7 @@ func (g *CannonHelper) createCannonTraceProvider(ctx context.Context, l2Node str localContext = split.CreateLocalContext(pre, post) dir := filepath.Join(cfg.Datadir, "cannon-trace") subdir := filepath.Join(dir, localContext.Hex()) - return cannon.NewTraceProviderForTest(logger, metrics.NoopMetrics.ToTypedVmMetrics(gameTypes.CannonGameType.String()), cfg, localInputs, subdir, g.splitGame.MaxDepth(ctx)-splitDepth-1), nil + return cannon.NewTraceProviderForTest(logger, metrics.NoopMetrics.ToTypedVmMetrics(gameTypes.CannonKonaGameType.String()), cfg.CannonKona, vm.NewKonaExecutor(), cfg.CannonKonaAbsolutePreState, localInputs, subdir, g.splitGame.MaxDepth(ctx)-splitDepth-1), nil }) claims, err := g.splitGame.Game.GetAllClaims(ctx, rpcblock.Latest) diff --git a/op-e2e/e2eutils/disputegame/helper.go b/op-e2e/e2eutils/disputegame/helper.go index d5021d7314d..ccf23968317 100644 --- a/op-e2e/e2eutils/disputegame/helper.go +++ b/op-e2e/e2eutils/disputegame/helper.go @@ -45,10 +45,10 @@ var ( ) const ( - cannonGameType uint32 = 0 - permissionedGameType uint32 = 1 - superCannonGameType uint32 = 4 - alphabetGameType uint32 = 255 + cannonKonaGameType uint32 = 8 + permissionedGameType uint32 = 1 + superCannonKonaGameType uint32 = 9 + alphabetGameType uint32 = 255 ) type GameCfg struct { @@ -168,7 +168,7 @@ func (h *FactoryHelper) PreimageHelper(ctx context.Context) *preimage.Helper { caller := batching.NewMultiCaller(h.Client.Client(), batching.DefaultBatchSize) dgf, err := contracts.NewDisputeGameFactoryContract(ctx, metrics.NoopContractMetrics, h.FactoryAddr, caller) h.Require.NoError(err) - vm, err := dgf.GetGameVm(ctx, gameTypes.GameType(cannonGameType)) + vm, err := dgf.GetGameVm(ctx, gameTypes.GameType(cannonKonaGameType)) h.Require.NoError(err) oracle, err := vm.Oracle(ctx) h.Require.NoError(err) @@ -192,7 +192,7 @@ func (h *FactoryHelper) StartOutputCannonGameWithCorrectRoot(ctx context.Context } func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, l2Node string, l2BlockNumber uint64, rootClaim common.Hash, opts ...GameOpt) *OutputCannonGameHelper { - return h.startOutputCannonGameOfType(ctx, l2Node, l2BlockNumber, rootClaim, cannonGameType, opts...) + return h.startOutputCannonGameOfType(ctx, l2Node, l2BlockNumber, rootClaim, cannonKonaGameType, opts...) } func (h *FactoryHelper) StartPermissionedGame(ctx context.Context, l2Node string, l2BlockNumber uint64, rootClaim common.Hash, opts ...GameOpt) *OutputCannonGameHelper { @@ -210,6 +210,11 @@ func (h *FactoryHelper) startOutputCannonGameOfType(ctx context.Context, l2Node ctx, cancel := context.WithTimeout(ctx, 1*time.Minute) defer cancel() + bond, err := h.Factory.InitBonds(nil, gameType) + h.Require.NoError(err, "get init bond for game type") + h.Opts.Value = bond + defer func() { h.Opts.Value = nil }() + tx, err := transactions.PadGasEstimate(h.Opts, 2, func(opts *bind.TransactOpts) (*types.Transaction, error) { return h.Factory.Create(opts, gameType, rootClaim, extraData) }) @@ -240,13 +245,13 @@ func (h *FactoryHelper) StartSuperCannonGameWithCorrectRoot(ctx context.Context, require.NoError(h.T, err) l2Timestamp := b.Time() h.WaitForSuperTimestamp(l2Timestamp, cfg) - return h.startSuperCannonGameOfType(ctx, l2Timestamp, superCannonGameType, opts...) + return h.startSuperCannonGameOfType(ctx, l2Timestamp, superCannonKonaGameType, opts...) } func (h *FactoryHelper) StartSuperCannonGameWithCorrectRootAtTimestamp(ctx context.Context, l2Timestamp uint64, opts ...GameOpt) *SuperCannonGameHelper { cfg := NewGameCfg(opts...) h.WaitForSuperTimestamp(l2Timestamp, cfg) - return h.startSuperCannonGameOfType(ctx, l2Timestamp, superCannonGameType, opts...) + return h.startSuperCannonGameOfType(ctx, l2Timestamp, superCannonKonaGameType, opts...) } func (h *FactoryHelper) StartSuperCannonGame(ctx context.Context, opts ...GameOpt) *SuperCannonGameHelper { @@ -254,11 +259,11 @@ func (h *FactoryHelper) StartSuperCannonGame(ctx context.Context, opts ...GameOp require.NoError(h.T, wait.ForBlock(ctx, h.Client, 1)) b, err := h.Client.BlockByNumber(ctx, nil) require.NoError(h.T, err) - return h.startSuperCannonGameOfType(ctx, b.Time(), superCannonGameType, opts...) + return h.startSuperCannonGameOfType(ctx, b.Time(), superCannonKonaGameType, opts...) } func (h *FactoryHelper) StartSuperCannonGameAtTimestamp(ctx context.Context, timestamp uint64, opts ...GameOpt) *SuperCannonGameHelper { - return h.startSuperCannonGameOfType(ctx, timestamp, superCannonGameType, opts...) + return h.startSuperCannonGameOfType(ctx, timestamp, superCannonKonaGameType, opts...) } func (h *FactoryHelper) startSuperCannonGameOfType(ctx context.Context, timestamp uint64, gameType uint32, opts ...GameOpt) *SuperCannonGameHelper { @@ -272,6 +277,11 @@ func (h *FactoryHelper) startSuperCannonGameOfType(ctx context.Context, timestam ctx, cancel := context.WithTimeout(ctx, 1*time.Minute) defer cancel() + bond, err := h.Factory.InitBonds(nil, gameType) + h.Require.NoError(err, "get init bond for game type") + h.Opts.Value = bond + defer func() { h.Opts.Value = nil }() + tx, err := transactions.PadGasEstimate(h.Opts, 2, func(opts *bind.TransactOpts) (*types.Transaction, error) { return h.Factory.Create(opts, gameType, rootClaim, extraData) }) diff --git a/op-e2e/e2eutils/disputegame/output_cannon_helper.go b/op-e2e/e2eutils/disputegame/output_cannon_helper.go index 89c1dfb3c58..8a8f13c48c7 100644 --- a/op-e2e/e2eutils/disputegame/output_cannon_helper.go +++ b/op-e2e/e2eutils/disputegame/output_cannon_helper.go @@ -29,7 +29,7 @@ func NewOutputCannonGameHelper(t *testing.T, client *ethclient.Client, opts *bin outputGameHelper := NewOutputGameHelper(t, require.New(t), client, opts, key, game, factoryAddr, gameAddr, provider, system) defaultChallengerOptions := func() []challenger.Option { return []challenger.Option{ - challenger.WithCannon(t, system), + challenger.WithCannonKona(t, system), challenger.WithFactoryAddress(factoryAddr), challenger.WithGameAddress(gameAddr), } @@ -82,7 +82,7 @@ func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node s prestateProvider := outputs.NewPrestateProvider(rollupClient, actorCfg.PrestateSequenceNumber) l1Head := g.GetL1Head(ctx) accessor, err := outputs.NewOutputCannonTraceAccessor( - logger, metrics.NoopMetrics, cfg.Cannon, vm.NewOpProgramServerExecutor(logger), l2Client, prestateProvider, cfg.CannonAbsolutePreState, rollupClient, dir, l1Head, splitDepth, actorCfg.PrestateSequenceNumber, actorCfg.PoststateSequenceNumber) + logger, metrics.NoopMetrics, cfg.CannonKona, vm.NewKonaExecutor(), l2Client, prestateProvider, cfg.CannonKonaAbsolutePreState, rollupClient, dir, l1Head, splitDepth, actorCfg.PrestateSequenceNumber, actorCfg.PoststateSequenceNumber) g.Require.NoError(err, "Failed to create output cannon trace accessor") return NewOutputHonestHelper(g.T, g.Require, &g.OutputGameHelper.SplitGameHelper, g.Game, accessor) } diff --git a/op-e2e/e2eutils/disputegame/super_cannon_helper.go b/op-e2e/e2eutils/disputegame/super_cannon_helper.go index 5826efacc78..1753788b281 100644 --- a/op-e2e/e2eutils/disputegame/super_cannon_helper.go +++ b/op-e2e/e2eutils/disputegame/super_cannon_helper.go @@ -37,7 +37,7 @@ func NewSuperCannonGameHelper(t *testing.T, client *ethclient.Client, opts *bind superGameHelper := NewSuperGameHelper(t, require.New(t), client, opts, key, game, factoryAddr, gameAddr, provider, system) defaultChallengerOptions := func() []challenger.Option { return []challenger.Option{ - challenger.WithSuperCannon(t, system), + challenger.WithSuperCannonKona(t, system), challenger.WithFactoryAddress(factoryAddr), challenger.WithGameAddress(gameAddr), challenger.WithDepset(t, system.DependencySet()), @@ -72,13 +72,13 @@ func (g *SuperCannonGameHelper) CreateHonestActor(ctx context.Context, options . accessor, err := super.NewSuperCannonTraceAccessor( logger, metrics.NoopMetrics, - cfg.Cannon, - vm.NewOpProgramServerExecutor(logger), + cfg.CannonKona, + vm.NewKonaSuperExecutor(), prestateProvider, supervisorClient, nil, false, - cfg.CannonAbsolutePreState, + cfg.CannonKonaAbsolutePreState, dir, l1Head, splitDepth, @@ -103,6 +103,7 @@ func (g *SuperCannonGameHelper) ChallengeToPreimageLoad(ctx context.Context, top targetTraceIndex, err := provider.FindStep(ctx, 0, preimage) g.require.NoError(err) + g.t.Logf("FindStep returned targetTraceIndex=%d", targetTraceIndex) splitDepth := g.splitGame.SplitDepth(ctx) execDepth := g.splitGame.ExecDepth(ctx) @@ -110,17 +111,22 @@ func (g *SuperCannonGameHelper) ChallengeToPreimageLoad(ctx context.Context, top g.require.EqualValues(splitDepth+1, topGameLeaf.Depth(), "supplied claim must be the root of an execution game") g.require.EqualValues(execDepth%2, 0, "execution game depth must be even") // since we're supporting the execution root claim + // Verify the step actually has preimage data before proceeding with the game + _, _, verifyData, err := provider.GetStepData(ctx, types.NewPosition(execDepth, big.NewInt(int64(targetTraceIndex)))) + g.require.NoError(err, "Failed to get step data at target trace index") + g.require.NotNil(verifyData, "Step at target trace index %d must have preimage data", targetTraceIndex) + g.t.Logf("Verified step %d has preimage: key=%x keyType=0x%02x", targetTraceIndex, verifyData.OracleKey, verifyData.OracleKey[0]) + if preloadPreimage { - _, _, preimageData, err := provider.GetStepData(ctx, types.NewPosition(execDepth, big.NewInt(int64(targetTraceIndex)))) - g.require.NoError(err) - g.UploadPreimage(ctx, preimageData) - g.WaitForPreimageInOracle(ctx, preimageData) + g.UploadPreimage(ctx, verifyData) + g.WaitForPreimageInOracle(ctx, verifyData) } bisectTraceIndex := func(claim *ClaimHelper) *ClaimHelper { return traceBisection(g.t, ctx, claim, splitDepth, execDepth, targetTraceIndex, provider) } leafClaim := g.splitGame.DefendClaim(ctx, topGameLeaf, bisectTraceIndex, WithoutWaitingForStep()) + g.t.Logf("Leaf claim at depth=%d, claimIndex=%d (target was %d)", leafClaim.Depth(), leafClaim.Index, targetTraceIndex) // Validate that the preimage was loaded correctly g.require.NoError(preimageCheck(provider, targetTraceIndex)) @@ -173,7 +179,7 @@ func (g *SuperCannonGameHelper) createSuperCannonTraceProvider(ctx context.Conte localContext = split.CreateLocalContext(pre, post) dir := filepath.Join(cfg.Datadir, "super-cannon-trace") subdir := filepath.Join(dir, localContext.Hex()) - return cannon.NewTraceProviderForTest(logger, metrics.NoopMetrics.ToTypedVmMetrics(gameTypes.SuperCannonGameType.String()), cfg, localInputs, subdir, g.splitGame.MaxDepth(ctx)-splitDepth-1), nil + return cannon.NewTraceProviderForTest(logger, metrics.NoopMetrics.ToTypedVmMetrics(gameTypes.SuperCannonKonaGameType.String()), cfg.CannonKona, vm.NewKonaSuperExecutor(), cfg.CannonKonaAbsolutePreState, localInputs, subdir, g.splitGame.MaxDepth(ctx)-splitDepth-1), nil }) claims, err := g.splitGame.Game.GetAllClaims(ctx, rpcblock.Latest) diff --git a/op-e2e/e2eutils/geth/fakepos.go b/op-e2e/e2eutils/geth/fakepos.go index 75603252a13..b4c23e5804c 100644 --- a/op-e2e/e2eutils/geth/fakepos.go +++ b/op-e2e/e2eutils/geth/fakepos.go @@ -57,8 +57,8 @@ type Backend interface { } type EngineAPI interface { - ForkchoiceUpdatedV3(engine.ForkchoiceStateV1, *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) - ForkchoiceUpdatedV2(engine.ForkchoiceStateV1, *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) + ForkchoiceUpdatedV3(context.Context, engine.ForkchoiceStateV1, *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) + ForkchoiceUpdatedV2(context.Context, engine.ForkchoiceStateV1, *engine.PayloadAttributes) (engine.ForkChoiceResponse, error) GetPayloadV5(engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) GetPayloadV4(engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) @@ -100,6 +100,13 @@ func (f *FakePoS) Start() error { return fmt.Errorf("get genesis header: %w", err) } f.sub = event.NewSubscription(func(quit <-chan struct{}) error { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go func() { + <-quit + cancel() + }() + // poll every half a second: enough to catch up with any block time when ticks are missed t := f.clock.NewTicker(time.Second / 2) for { @@ -173,9 +180,9 @@ func (f *FakePoS) Start() error { } var res engine.ForkChoiceResponse if isCancun { - res, err = f.engineAPI.ForkchoiceUpdatedV3(fcState, attrs) + res, err = f.engineAPI.ForkchoiceUpdatedV3(ctx, fcState, attrs) } else { - res, err = f.engineAPI.ForkchoiceUpdatedV2(fcState, attrs) + res, err = f.engineAPI.ForkchoiceUpdatedV2(ctx, fcState, attrs) } if err != nil { f.log.Error("failed to start building L1 block", "err", err) @@ -191,7 +198,7 @@ func (f *FakePoS) Start() error { select { case <-tim.Ch(): // no-op - case <-quit: + case <-ctx.Done(): tim.Stop() return nil } @@ -248,7 +255,7 @@ func (f *FakePoS) Start() error { continue } } - if _, err := f.engineAPI.ForkchoiceUpdatedV3(engine.ForkchoiceStateV1{ + if _, err := f.engineAPI.ForkchoiceUpdatedV3(ctx, engine.ForkchoiceStateV1{ HeadBlockHash: envelope.ExecutionPayload.BlockHash, SafeBlockHash: safe.Hash(), FinalizedBlockHash: finalized.Hash(), @@ -260,7 +267,7 @@ func (f *FakePoS) Start() error { // The EL doesn't really care about the value, // but it's nice to mock something consistent with the CL specs. f.withdrawalsIndex += uint64(len(withdrawals)) - case <-quit: + case <-ctx.Done(): return nil } } diff --git a/op-e2e/faultproofs/multi_test.go b/op-e2e/faultproofs/multi_test.go index e8e87268ea5..645d5cf74cc 100644 --- a/op-e2e/faultproofs/multi_test.go +++ b/op-e2e/faultproofs/multi_test.go @@ -25,9 +25,9 @@ func TestMultipleGameTypes(t *testing.T) { latestClaim1 := game1.DisputeLastBlock(ctx) latestClaim2 := game2.DisputeLastBlock(ctx) - // Start a challenger with both cannon and alphabet support + // Start a challenger with both cannon-kona and alphabet support gameFactory.StartChallenger(ctx, "TowerDefense", - challenger.WithCannon(t, sys), + challenger.WithCannonKona(t, sys), challenger.WithAlphabet(), challenger.WithPrivKey(sys.Cfg.Secrets.Alice), ) diff --git a/op-e2e/faultproofs/precompile_test.go b/op-e2e/faultproofs/precompile_test.go index 226716be1c3..a972cb39405 100644 --- a/op-e2e/faultproofs/precompile_test.go +++ b/op-e2e/faultproofs/precompile_test.go @@ -214,21 +214,21 @@ func runCannon(t *testing.T, ctx context.Context, sys *e2esys.System, inputs uti l1Beacon := sys.L1BeaconEndpoint().RestHTTP() rollupEndpoint := sys.RollupEndpoint("sequencer").RPC() l2Endpoint := sys.NodeEndpoint("sequencer").RPC() - cannonOpts := challenger.WithCannon(t, sys) + cannonOpts := challenger.WithCannonKona(t, sys) dir := t.TempDir() proofsDir := filepath.Join(dir, "cannon-proofs") cfg := config.NewConfig(common.Address{}, l1Endpoint, l1Beacon, rollupEndpoint, l2Endpoint, dir) - cfg.Cannon.L2Custom = true + cfg.CannonKona.L2Custom = true cannonOpts(&cfg) logger := testlog.Logger(t, log.LevelInfo).New("role", "cannon") - executor := vm.NewExecutor(logger, metrics.NoopMetrics.ToTypedVmMetrics("cannon"), cfg.Cannon, vm.NewOpProgramServerExecutor(logger), cfg.CannonAbsolutePreState, inputs) + executor := vm.NewExecutor(logger, metrics.NoopMetrics.ToTypedVmMetrics("cannon"), cfg.CannonKona, vm.NewKonaExecutor(), cfg.CannonKonaAbsolutePreState, inputs) t.Log("Running cannon") err := executor.DoGenerateProof(ctx, proofsDir, math.MaxUint, math.MaxUint, extraVmArgs...) require.NoError(t, err, "failed to generate proof") - stdOut, _, err := runCmd(ctx, cfg.Cannon.VmBin, "witness", "--input", vm.FinalStatePath(proofsDir, cfg.Cannon.BinarySnapshots)) + stdOut, _, err := runCmd(ctx, cfg.CannonKona.VmBin, "witness", "--input", vm.FinalStatePath(proofsDir, cfg.CannonKona.BinarySnapshots)) require.NoError(t, err, "failed to run witness cmd") type stateData struct { Step uint64 `json:"step"` diff --git a/op-e2e/interop/interop_test.go b/op-e2e/interop/interop_test.go index cc7e3d212ea..e99b69fcba6 100644 --- a/op-e2e/interop/interop_test.go +++ b/op-e2e/interop/interop_test.go @@ -446,7 +446,7 @@ func TestProposals(t *testing.T) { require.NoError(t, err) game, err := factory.GetGame(context.Background(), 0, rpcblock.ByHash(head.Hash())) require.NoError(t, err) - require.Equal(t, uint32(4) /* super permissionless */, game.GameType) + require.Equal(t, uint32(9) /* super cannon kona */, game.GameType) } setupAndRun(t, SuperSystemConfig{}, test) } diff --git a/op-e2e/interop/supersystem_l2.go b/op-e2e/interop/supersystem_l2.go index 3f5e428fb63..8164dfcb7a2 100644 --- a/op-e2e/interop/supersystem_l2.go +++ b/op-e2e/interop/supersystem_l2.go @@ -243,7 +243,7 @@ func (s *interopE2ESystem) newProposerForL2( SupervisorRpcs: []string{s.Supervisor().RPC()}, DGFAddress: s.worldDeployment.Interop.DisputeGameFactory.Hex(), ProposalInterval: 6 * time.Second, - DisputeGameType: 4, // Super Permissionless game type is the only one currently deployed + DisputeGameType: 9, // Super Cannon Kona game type PollInterval: 500 * time.Millisecond, TxMgrConfig: setuputils.NewTxMgrConfig(s.L1().UserRPC(), &key), AllowNonFinalized: true, diff --git a/op-interop-filter/filter/backend.go b/op-interop-filter/filter/backend.go index 200b2206838..867c706f2d6 100644 --- a/op-interop-filter/filter/backend.go +++ b/op-interop-filter/filter/backend.go @@ -6,8 +6,10 @@ import ( "fmt" "sync/atomic" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum-optimism/optimism/op-interop-filter/metrics" "github.com/ethereum-optimism/optimism/op-service/eth" @@ -183,3 +185,29 @@ func (b *Backend) CheckAccessList(ctx context.Context, inboxEntries []common.Has b.metrics.RecordCheckAccessList(true) return nil } + +// GetBlockHashByNumber returns the latest block hash or the block hash at a specific height for the given chain. +// Accepts rpc.BlockNumber: "latest" or a numeric block number. Other named tags are not supported. +func (b *Backend) GetBlockHashByNumber(chainID eth.ChainID, blockNum rpc.BlockNumber) (common.Hash, error) { + ingester, ok := b.chains[chainID] + if !ok { + return common.Hash{}, fmt.Errorf("chain %s: %w", chainID, types.ErrUnknownChain) + } + + if blockNum == rpc.LatestBlockNumber { + block, ok := ingester.LatestBlock() + if !ok { + return common.Hash{}, fmt.Errorf("latest block for chain %s: %w", chainID, ethereum.NotFound) + } + return block.Hash, nil + } + if blockNum < 0 { + return common.Hash{}, fmt.Errorf("unsupported block tag %q: only \"latest\" and block numbers are supported", blockNum) + } + + blockHash, ok := ingester.BlockHashByNumber(uint64(blockNum)) + if !ok { + return common.Hash{}, fmt.Errorf("block %d for chain %s: %w", blockNum, chainID, ethereum.NotFound) + } + return blockHash, nil +} diff --git a/op-interop-filter/filter/frontend.go b/op-interop-filter/filter/frontend.go index f3b1f8cdb18..a0ec0b168b7 100644 --- a/op-interop-filter/filter/frontend.go +++ b/op-interop-filter/filter/frontend.go @@ -30,6 +30,11 @@ func (f *QueryFrontend) CheckAccessList(ctx context.Context, inboxEntries []comm return nil } +// GetBlockHashByNumber returns the latest ingested block hash or the block hash at a specific height. +func (f *QueryFrontend) GetBlockHashByNumber(ctx context.Context, chainID eth.ChainID, blockNum rpc.BlockNumber) (common.Hash, error) { + return f.backend.GetBlockHashByNumber(chainID, blockNum) +} + // PublicAdminFrontend exposes read-only admin methods on the public port. type PublicAdminFrontend struct { backend *Backend diff --git a/op-interop-filter/filter/interfaces.go b/op-interop-filter/filter/interfaces.go index 05153cb2f13..e7c3b1b63c0 100644 --- a/op-interop-filter/filter/interfaces.go +++ b/op-interop-filter/filter/interfaces.go @@ -1,6 +1,8 @@ package filter import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -31,6 +33,9 @@ type ChainIngester interface { // LatestBlock returns the latest ingested block. LatestBlock() (eth.BlockID, bool) + // BlockHashByNumber returns the hash of the ingested block at the given height. + BlockHashByNumber(number uint64) (common.Hash, bool) + // LatestTimestamp returns the timestamp of the latest ingested block. LatestTimestamp() (uint64, bool) diff --git a/op-interop-filter/filter/logsdb_chain_ingester.go b/op-interop-filter/filter/logsdb_chain_ingester.go index f1fc7316883..4bfda419613 100644 --- a/op-interop-filter/filter/logsdb_chain_ingester.go +++ b/op-interop-filter/filter/logsdb_chain_ingester.go @@ -247,6 +247,11 @@ func (c *LogsDBChainIngester) BlockHashAt(blockNum uint64) (common.Hash, bool) { return seal.Hash, true } +// BlockHashByNumber returns the sealed block hash at the given height. +func (c *LogsDBChainIngester) BlockHashByNumber(blockNum uint64) (common.Hash, bool) { + return c.BlockHashAt(blockNum) +} + // LatestTimestamp returns the timestamp of the latest sealed block func (c *LogsDBChainIngester) LatestTimestamp() (uint64, bool) { c.mu.RLock() diff --git a/op-interop-filter/filter/mock_test.go b/op-interop-filter/filter/mock_test.go index cda5ff42ba1..fa0f65e5216 100644 --- a/op-interop-filter/filter/mock_test.go +++ b/op-interop-filter/filter/mock_test.go @@ -24,6 +24,9 @@ type mockChainIngester struct { // Logs stored by their identifying query logs map[logKey]types.BlockSeal + // Blocks keyed by block number + blocks map[uint64]eth.BlockID + // Executing messages with their inclusion context execMsgs []IncludedMessage @@ -47,6 +50,7 @@ type logKey struct { func newMockChainIngester() *mockChainIngester { return &mockChainIngester{ logs: make(map[logKey]types.BlockSeal), + blocks: make(map[uint64]eth.BlockID), execMsgs: make([]IncludedMessage, 0), ready: true, // Default to ready for simple tests } @@ -70,10 +74,11 @@ func (m *mockChainIngester) AddLog(timestamp, blockNum uint64, logIdx uint32, ch Checksum: checksum, } m.logs[key] = seal + m.blocks[blockNum] = eth.BlockID{Hash: seal.Hash, Number: blockNum} // Update latest block/timestamp if needed if blockNum > m.latestBlock.Number { - m.latestBlock = eth.BlockID{Number: blockNum} + m.latestBlock = eth.BlockID{Hash: seal.Hash, Number: blockNum} m.latestTimestamp = timestamp } if m.earliestIngestedBlock == 0 || blockNum < m.earliestIngestedBlock { @@ -98,6 +103,17 @@ func (m *mockChainIngester) AddExecMsg(msg IncludedMessage) { } } +// AddBlock adds a block directly to the ingester. +func (m *mockChainIngester) AddBlock(block eth.BlockID) { + m.mu.Lock() + defer m.mu.Unlock() + + m.blocks[block.Number] = block + if block.Number >= m.latestBlock.Number { + m.latestBlock = block + } +} + // SetReady sets the ready state. func (m *mockChainIngester) SetReady(ready bool) { m.mu.Lock() @@ -135,6 +151,18 @@ func (m *mockChainIngester) LatestBlock() (eth.BlockID, bool) { return m.latestBlock, true } +// BlockHashByNumber implements ChainIngester. +func (m *mockChainIngester) BlockHashByNumber(number uint64) (common.Hash, bool) { + m.mu.RLock() + defer m.mu.RUnlock() + + block, ok := m.blocks[number] + if !ok { + return common.Hash{}, false + } + return block.Hash, true +} + // LatestTimestamp implements ChainIngester. func (m *mockChainIngester) LatestTimestamp() (uint64, bool) { m.mu.RLock() diff --git a/op-interop-filter/filter/rpc_test.go b/op-interop-filter/filter/rpc_test.go new file mode 100644 index 00000000000..3853dea077a --- /dev/null +++ b/op-interop-filter/filter/rpc_test.go @@ -0,0 +1,82 @@ +package filter + +import ( + "context" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" + "github.com/stretchr/testify/require" + + "github.com/ethereum-optimism/optimism/op-interop-filter/metrics" + "github.com/ethereum-optimism/optimism/op-service/eth" + oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" + "github.com/ethereum-optimism/optimism/op-service/testlog" +) + +func TestQueryFrontendGetBlockHashByNumberRPC(t *testing.T) { + logger := testlog.Logger(t, log.LevelInfo) + mock := newMockChainIngester() + mock.AddBlock(eth.BlockID{Hash: common.HexToHash("0x01"), Number: 100}) + mock.AddBlock(eth.BlockID{Hash: common.HexToHash("0x02"), Number: 200}) + + backend := NewBackend(context.Background(), BackendParams{ + Logger: logger, + Metrics: metrics.NoopMetrics, + Chains: map[eth.ChainID]ChainIngester{eth.ChainIDFromUInt64(testChainA): mock}, + CrossValidator: &mockCrossValidator{}, + }) + + server := oprpc.NewServer( + "127.0.0.1", + 0, + "test", + oprpc.WithLogger(logger), + ) + server.AddAPI(rpc.API{ + Namespace: "supervisor", + Service: &QueryFrontend{backend: backend}, + }) + + require.NoError(t, server.Start()) + t.Cleanup(func() { + _ = server.Stop() + }) + + client, err := rpc.Dial("http://" + server.Endpoint()) + require.NoError(t, err) + t.Cleanup(client.Close) + + t.Run("latest selector", func(t *testing.T) { + var result common.Hash + err := client.Call(&result, "supervisor_getBlockHashByNumber", eth.ChainIDFromUInt64(testChainA), "latest") + require.NoError(t, err) + require.Equal(t, common.HexToHash("0x02"), result) + }) + + t.Run("numeric selector", func(t *testing.T) { + var result common.Hash + err := client.Call(&result, "supervisor_getBlockHashByNumber", eth.ChainIDFromUInt64(testChainA), rpc.BlockNumber(100)) + require.NoError(t, err) + require.Equal(t, common.HexToHash("0x01"), result) + }) + + t.Run("missing block", func(t *testing.T) { + var result common.Hash + err := client.Call(&result, "supervisor_getBlockHashByNumber", eth.ChainIDFromUInt64(testChainA), rpc.BlockNumber(999)) + require.ErrorContains(t, err, "not found") + }) + + t.Run("unknown chain", func(t *testing.T) { + var result common.Hash + err := client.Call(&result, "supervisor_getBlockHashByNumber", eth.ChainIDFromUInt64(999), rpc.BlockNumber(100)) + require.ErrorContains(t, err, "unknown chain") + }) + + t.Run("unsupported tag", func(t *testing.T) { + var result common.Hash + err := client.Call(&result, "supervisor_getBlockHashByNumber", eth.ChainIDFromUInt64(testChainA), "safe") + require.ErrorContains(t, err, "unsupported block tag") + }) +} diff --git a/op-node/flags/flags.go b/op-node/flags/flags.go index 9cf587f92e9..d96e7e66645 100644 --- a/op-node/flags/flags.go +++ b/op-node/flags/flags.go @@ -119,7 +119,7 @@ var ( SyncModeReqRespFlag = &cli.BoolFlag{ Name: "syncmode.req-resp", Required: false, - Value: true, + Value: false, EnvVars: prefixEnvVars("SYNCMODE_REQ_RESP"), Category: RollupCategory, } diff --git a/op-node/rollup/derive/karst_nut_bundle.json b/op-node/rollup/derive/karst_nut_bundle.json index 6e7a043d739..9a75d366669 100644 --- a/op-node/rollup/derive/karst_nut_bundle.json +++ b/op-node/rollup/derive/karst_nut_bundle.json @@ -2,5 +2,230 @@ "metadata": { "version": "1.0.0" }, - "transactions": [] -} + "transactions": [ + { + "data": "0x9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca4608060405234801561001057600080fd5b506105b8806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806354fd4d5014610046578063cdcb760a14610098578063e0145f5c146100d0575b600080fd5b6100826040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b60405161008f91906103f7565b60405180910390f35b6100ab6100a6366004610440565b6100ea565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161008f565b734e59b44847b379578588920ca78fbf26c0b4956c6100ab565b8051602080830191909120604080517fff00000000000000000000000000000000000000000000000000000000000000818501527f4e59b44847b379578588920ca78fbf26c0b4956c000000000000000000000000602182015260358101869052605580820184905282518083039091018152607590910190915280519201919091206000919073ffffffffffffffffffffffffffffffffffffffff81163b156101d85760405173ffffffffffffffffffffffffffffffffffffffff8216907ffbe57d889a7f75a4e0c7da304cd158fcaddc4b925cdd9f4cfb115c0f9e48009b90600090a291506103779050565b600080734e59b44847b379578588920ca78fbf26c0b4956c73ffffffffffffffffffffffffffffffffffffffff168787604051602001610219929190610519565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526102519161053f565b6000604051808303816000865af19150503d806000811461028e576040519150601f19603f3d011682016040523d82523d6000602084013e610293565b606091505b5091509150806102a29061055b565b60601c94508115806102e057508273ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614155b1561032257806040517fcb0fc6f700000000000000000000000000000000000000000000000000000000815260040161031991906103f7565b60405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff167f9b7318127ed899f286ea9ddd7925ed8ad24a682b6a825c3b5b3d88a3f00bc1d28860405161036a91815260200190565b60405180910390a2505050505b92915050565b60005b83811015610398578181015183820152602001610380565b838111156103a7576000848401525b50505050565b600081518084526103c581602086016020860161037d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061040a60208301846103ad565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561045357600080fd5b82359150602083013567ffffffffffffffff8082111561047257600080fd5b818501915085601f83011261048657600080fd5b81358181111561049857610498610411565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104de576104de610411565b816040528281528860208487010111156104f757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b8281526000825161053181602085016020870161037d565b919091016020019392505050565b6000825161055181846020870161037d565b9190910192915050565b6000815160208301517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808216935060148310156105a35780818460140360031b1b83161693505b50505091905056fea164736f6c634300080f000a", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 600000, + "intent": "ConditionalDeployer Deployment", + "to": "0x4e59b44847b379578588920cA78FbF26c0B4956C" + }, + { + "data": "0x3659cfe6000000000000000000000000906835344844979ffd3a752eaa23728d513db00b", + "from": "0x0000000000000000000000000000000000000000", + "gasLimit": 50000, + "intent": "Upgrade ConditionalDeployer Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca40000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000048a608060405234801561001057600080fd5b5061046a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c8063a6ed563e11610076578063bd02d0f51161005b578063bd02d0f51461018e578063ca446dd9146101b8578063e2a4853a1461011557600080fd5b8063a6ed563e1461018e578063abfdcced146101aa57600080fd5b80634e91db08116100a75780634e91db081461011557806354fd4d50146101275780637ae1cfca1461017057600080fd5b80630528afe2146100c357806321f8a721146100d8575b600080fd5b6100d66100d1366004610239565b6101c6565b005b6100eb6100e63660046102ae565b610229565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100d66101233660046102c7565b9055565b6101636040518060400160405280600581526020017f312e322e3200000000000000000000000000000000000000000000000000000081525081565b60405161010c91906102e9565b61017e6100e63660046102ae565b604051901515815260200161010c565b61019c6100e63660046102ae565b60405190815260200161010c565b6100d661012336600461035c565b6100d6610123366004610391565b8060005b81811015610223576102118484838181106101e7576101e76103cf565b90506040020160000135858584818110610203576102036103cf565b905060400201602001359055565b8061021b816103fe565b9150506101ca565b50505050565b6000610233825490565b92915050565b6000806020838503121561024c57600080fd5b823567ffffffffffffffff8082111561026457600080fd5b818501915085601f83011261027857600080fd5b81358181111561028757600080fd5b8660208260061b850101111561029c57600080fd5b60209290920196919550909350505050565b6000602082840312156102c057600080fd5b5035919050565b600080604083850312156102da57600080fd5b50508035926020909101359150565b600060208083528351808285015260005b81811015610316578581018301518582016040015282016102fa565b81811115610328576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000806040838503121561036f57600080fd5b823591506020830135801515811461038657600080fd5b809150509250929050565b600080604083850312156103a457600080fd5b82359150602083013573ffffffffffffffffffffffffffffffffffffffff8116811461038657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610456577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b506001019056fea164736f6c634300080f000a00000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 500000, + "intent": "Deploy StorageSetter Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca4000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000022d3608060405234801561001057600080fd5b5061001961001e565b6100eb565b600054600160a81b900460ff161561008c5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff600160a01b909104811610156100e9576000805460ff60a01b191660ff60a01b17905560405160ff81527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6121d880620000fb6000396000f3fe6080604052600436106101a15760003560e01c80638cbeeef2116100e1578063c4d66de81161008a578063db505d8011610064578063db505d8014610451578063ddd5a40f1461047e578063e46e245a14610494578063ecc70428146104a957600080fd5b8063c4d66de814610409578063d764ad0b14610429578063dad544e01461043c57600080fd5b8063a7119869116100bb578063a71198691461035e578063b1b1b209146103b9578063b28ade25146103e957600080fd5b80638cbeeef2146102905780639fce812c1461035e578063a4e7f8bd1461038957600080fd5b80633f827a5a1161014e5780635644cfdf116101285780635644cfdf146102fc5780635c975abb146103125780636e296e451461033257806383a740741461034757600080fd5b80633f827a5a146102685780634c1d6a691461029057806354fd4d50146102a657600080fd5b80632f7d39221161017f5780632f7d3922146102035780633dbb202b146102195780633e47158c1461022e57600080fd5b8063028f85f7146101a65780630c568498146101d95780632828d7e8146101ee575b600080fd5b3480156101b257600080fd5b506101bb601081565b60405167ffffffffffffffff90911681526020015b60405180910390f35b3480156101e557600080fd5b506101bb603f81565b3480156101fa57600080fd5b506101bb604081565b34801561020f57600080fd5b506101bb61520881565b61022c610227366004611bb4565b61050e565b005b34801561023a57600080fd5b506102436107a1565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d0565b34801561027457600080fd5b5061027d600181565b60405161ffff90911681526020016101d0565b34801561029c57600080fd5b506101bb619c4081565b3480156102b257600080fd5b506102ef6040518060400160405280600581526020017f322e322e3100000000000000000000000000000000000000000000000000000081525081565b6040516101d09190611c86565b34801561030857600080fd5b506101bb61138881565b34801561031e57600080fd5b5060005b60405190151581526020016101d0565b34801561033e57600080fd5b506102436109ac565b34801561035357600080fd5b506101bb62030d4081565b34801561036a57600080fd5b5060cf5473ffffffffffffffffffffffffffffffffffffffff16610243565b34801561039557600080fd5b506103226103a4366004611c99565b60ce6020526000908152604090205460ff1681565b3480156103c557600080fd5b506103226103d4366004611c99565b60cb6020526000908152604090205460ff1681565b3480156103f557600080fd5b506101bb610404366004611ce1565b610a98565b34801561041557600080fd5b5061022c610424366004611dc1565b610b59565b61022c610437366004611dde565b610d60565b34801561044857600080fd5b50610243611645565b34801561045d57600080fd5b5060cf546102439073ffffffffffffffffffffffffffffffffffffffff1681565b34801561048a57600080fd5b506101bb61010481565b3480156104a057600080fd5b506101bb602881565b3480156104b557600080fd5b5061050060cd547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e010000000000000000000000000000000000000000000000000000000000001790565b6040519081526020016101d0565b60cf54604080516020601f86018190048102820181019092528481526106769273ffffffffffffffffffffffffffffffffffffffff169161056c91908790879081908401838280828437600092019190915250879250610a98915050565b347fd764ad0b000000000000000000000000000000000000000000000000000000006105d860cd547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e010000000000000000000000000000000000000000000000000000000000001790565b338a34898c8c6040516024016105f49796959493929190611ead565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526116c2565b8373ffffffffffffffffffffffffffffffffffffffff167fcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a3385856106fb60cd547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e010000000000000000000000000000000000000000000000000000000000001790565b8660405161070d959493929190611f0c565b60405180910390a260405134815233907f8ebb2ec2465bdb2a06a66fc37a0963af8a2a6a1479d81d56fdb8cbb98096d5469060200160405180910390a2505060cd80547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808216600101167fffff0000000000000000000000000000000000000000000000000000000000009091161790555050565b6000806107cc7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905073ffffffffffffffffffffffffffffffffffffffff8116156107ef57919050565b6040518060400160405280601a81526020017f4f564d5f4c3143726f7373446f6d61696e4d657373656e6765720000000000008152505160026108329190611f89565b604080513060208201526000918101919091527f4f564d5f4c3143726f7373446f6d61696e4d657373656e676572000000000000919091179061088d906060015b604051602081830303815290604052805190602001205490565b146108c4576040517f54e433cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080513060208201526001918101919091526000906108e690606001610873565b905073ffffffffffffffffffffffffffffffffffffffff81161561097a578073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561094f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109739190611fc6565b9250505090565b6040517f332144db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60cc5460009073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff215301610a7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f43726f7373446f6d61696e4d657373656e6765723a2078446f6d61696e4d657360448201527f7361676553656e646572206973206e6f7420736574000000000000000000000060648201526084015b60405180910390fd5b5060cc5473ffffffffffffffffffffffffffffffffffffffff1690565b600080603f610aae604063ffffffff8616611fe3565b610ab89190612013565b611388619c40610acb8162030d40612061565b610ad59190612061565b610adf9190612061565b610ae99190612061565b9050600061010467ffffffffffffffff168551610b06919061208d565b9050610b44610b16601083611fe3565b610b209084612061565b67ffffffffffffffff16610b35602884611fe3565b67ffffffffffffffff16611750565b610b5090615208612061565b95945050505050565b6000547501000000000000000000000000000000000000000000900460ff1615808015610ba4575060005460017401000000000000000000000000000000000000000090910460ff16105b80610bd65750303b158015610bd6575060005474010000000000000000000000000000000000000000900460ff166001145b610c62576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610a72565b600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790558015610ce857600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000001790555b610cf0611769565b610cf9826117ec565b8015610d5c57600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60f087901c60028110610e1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604d60248201527f43726f7373446f6d61696e4d657373656e6765723a206f6e6c7920766572736960448201527f6f6e2030206f722031206d657373616765732061726520737570706f7274656460648201527f20617420746869732074696d6500000000000000000000000000000000000000608482015260a401610a72565b8061ffff16600003610f10576000610e6c878986868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508f9250611928915050565b600081815260cb602052604090205490915060ff1615610f0e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f43726f7373446f6d61696e4d657373656e6765723a206c65676163792077697460448201527f6864726177616c20616c72656164792072656c617965640000000000000000006064820152608401610a72565b505b6000610f56898989898989898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061194792505050565b9050610f9f60cf54337fffffffffffffffffffffffffeeeeffffffffffffffffffffffffffffffffeeef0173ffffffffffffffffffffffffffffffffffffffff90811691161490565b15610fd757853414610fb357610fb36120a5565b600081815260ce602052604090205460ff1615610fd257610fd26120a5565b611129565b341561108b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605060248201527f43726f7373446f6d61696e4d657373656e6765723a2076616c7565206d75737460448201527f206265207a65726f20756e6c657373206d6573736167652069732066726f6d2060648201527f612073797374656d206164647265737300000000000000000000000000000000608482015260a401610a72565b600081815260ce602052604090205460ff16611129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f43726f7373446f6d61696e4d657373656e6765723a206d65737361676520636160448201527f6e6e6f74206265207265706c61796564000000000000000000000000000000006064820152608401610a72565b6111328761196a565b156111e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604360248201527f43726f7373446f6d61696e4d657373656e6765723a2063616e6e6f742073656e60448201527f64206d65737361676520746f20626c6f636b65642073797374656d206164647260648201527f6573730000000000000000000000000000000000000000000000000000000000608482015260a401610a72565b600081815260cb602052604090205460ff1615611284576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f43726f7373446f6d61696e4d657373656e6765723a206d65737361676520686160448201527f7320616c7265616479206265656e2072656c61796564000000000000000000006064820152608401610a72565b6112a585611296611388619c40612061565b67ffffffffffffffff166119bf565b15806112cb575060cc5473ffffffffffffffffffffffffffffffffffffffff1661dead14155b156113e457600081815260ce602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555182917f99d0e048484baa1b1540b1367cb128acd7ab2946d1ed91ec10e3c85e4bf51b8f91a27fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff32016113dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f43726f7373446f6d61696e4d657373656e6765723a206661696c656420746f2060448201527f72656c6179206d657373616765000000000000000000000000000000000000006064820152608401610a72565b505061163c565b60cc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8a16179055600061147588619c405a61143891906120d4565b8988888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506119dd92505050565b60cc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead1790559050801561152b57600082815260cb602052604090205460ff16156114c8576114c86120a5565b600082815260cb602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555183917f4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c91a2611638565b600082815260ce602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555183917f99d0e048484baa1b1540b1367cb128acd7ab2946d1ed91ec10e3c85e4bf51b8f91a27fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3201611638576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f43726f7373446f6d61696e4d657373656e6765723a206661696c656420746f2060448201527f72656c6179206d657373616765000000000000000000000000000000000000006064820152608401610a72565b5050505b50505050505050565b600061164f6107a1565b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611699573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116bd9190611fc6565b905090565b6040517fc2b3e5ac0000000000000000000000000000000000000000000000000000000081527342000000000000000000000000000000000000169063c2b3e5ac908490611718908890889087906004016120eb565b6000604051808303818588803b15801561173157600080fd5b505af1158015611745573d6000803e3d6000fd5b505050505050505050565b6000818310156117605781611762565b825b9392505050565b336117726107a1565b73ffffffffffffffffffffffffffffffffffffffff16141580156117b357503361179a611645565b73ffffffffffffffffffffffffffffffffffffffff1614155b156117ea576040517fc4050a2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6000547501000000000000000000000000000000000000000000900460ff16611897576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a72565b60cc5473ffffffffffffffffffffffffffffffffffffffff166118e15760cc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead1790555b60cf80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000611936858585856119f5565b805190602001209050949350505050565b6000611957878787878787611a8e565b8051906020012090509695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff82163014806119b9575073ffffffffffffffffffffffffffffffffffffffff8216734200000000000000000000000000000000000016145b92915050565b600080603f83619c4001026040850201603f5a021015949350505050565b6000806000835160208501868989f195945050505050565b606084848484604051602401611a0e949392919061212a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fcbd4ece9000000000000000000000000000000000000000000000000000000001790529050949350505050565b6060868686868686604051602401611aab96959493929190612174565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fd764ad0b0000000000000000000000000000000000000000000000000000000017905290509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611b4f57600080fd5b50565b60008083601f840112611b6457600080fd5b50813567ffffffffffffffff811115611b7c57600080fd5b602083019150836020828501011115611b9457600080fd5b9250929050565b803563ffffffff81168114611baf57600080fd5b919050565b60008060008060608587031215611bca57600080fd5b8435611bd581611b2d565b9350602085013567ffffffffffffffff811115611bf157600080fd5b611bfd87828801611b52565b9094509250611c10905060408601611b9b565b905092959194509250565b6000815180845260005b81811015611c4157602081850181015186830182015201611c25565b81811115611c53576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006117626020830184611c1b565b600060208284031215611cab57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060408385031215611cf457600080fd5b823567ffffffffffffffff80821115611d0c57600080fd5b818501915085601f830112611d2057600080fd5b813581811115611d3257611d32611cb2565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715611d7857611d78611cb2565b81604052828152886020848701011115611d9157600080fd5b826020860160208301376000602084830101528096505050505050611db860208401611b9b565b90509250929050565b600060208284031215611dd357600080fd5b813561176281611b2d565b600080600080600080600060c0888a031215611df957600080fd5b873596506020880135611e0b81611b2d565b95506040880135611e1b81611b2d565b9450606088013593506080880135925060a088013567ffffffffffffffff811115611e4557600080fd5b611e518a828b01611b52565b989b979a50959850939692959293505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b878152600073ffffffffffffffffffffffffffffffffffffffff808916602084015280881660408401525085606083015263ffffffff8516608083015260c060a0830152611eff60c083018486611e64565b9998505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff86168152608060208201526000611f3c608083018688611e64565b905083604083015263ffffffff831660608301529695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611fc157611fc1611f5a565b500290565b600060208284031215611fd857600080fd5b815161176281611b2d565b600067ffffffffffffffff8083168185168183048111821515161561200a5761200a611f5a565b02949350505050565b600067ffffffffffffffff80841680612055577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b600067ffffffffffffffff80831681851680830382111561208457612084611f5a565b01949350505050565b600082198211156120a0576120a0611f5a565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b6000828210156120e6576120e6611f5a565b500390565b73ffffffffffffffffffffffffffffffffffffffff8416815267ffffffffffffffff83166020820152606060408201526000610b506060830184611c1b565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250608060408301526121636080830185611c1b565b905082606083015295945050505050565b868152600073ffffffffffffffffffffffffffffffffffffffff808816602084015280871660408401525084606083015283608083015260c060a08301526121bf60c0830184611c1b565b9897505050505050505056fea164736f6c634300080f000a00000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 2600000, + "intent": "Deploy L2CrossDomainMessenger Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001ec8608060405234801561001057600080fd5b50611ea8806100206000396000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806368d5dca6116100e3578063c59859181161008c578063f45e65d811610066578063f45e65d8146102fc578063f820614014610304578063fe173b971461029357600080fd5b8063c5985918146102ce578063de26c4a1146102d6578063f1c7a58b146102e957600080fd5b8063960e3a23116100bd578063960e3a23146102a1578063b3d72079146102b3578063b54501bc146102bb57600080fd5b806368d5dca6146102765780636ef25c3a146102935780638e98b1061461029957600080fd5b80632e0f2625116101455780634ef6e2241161011f5780634ef6e22414610218578063519b4bd31461022557806354fd4d501461022d57600080fd5b80632e0f2625146101f6578063313ce567146101fe57806349948e0e1461020557600080fd5b806322b90ab31161017657806322b90ab3146101d1578063275aedd2146101db578063291b0383146101ee57600080fd5b80630c18c16214610192578063105d0b81146101ad575b600080fd5b61019a61030c565b6040519081526020015b60405180910390f35b6000546101c1906301000000900460ff1681565b60405190151581526020016101a4565b6101d961042d565b005b61019a6101e93660046118fa565b6105b6565b6101d9610776565b61019a600681565b600661019a565b61019a610213366004611942565b61099e565b6000546101c19060ff1681565b61019a6109db565b6102696040518060400160405280600581526020017f312e362e3000000000000000000000000000000000000000000000000000000081525081565b6040516101a49190611a11565b61027e610a3c565b60405163ffffffff90911681526020016101a4565b4861019a565b6101d9610ac1565b6000546101c190610100900460ff1681565b6101d9610cbb565b6000546101c19062010000900460ff1681565b61027e610ec2565b61019a6102e4366004611942565b610f23565b61019a6102f73660046118fa565b61101d565b61019a6110f1565b61019a6111e4565b6000805460ff16156103a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f47617350726963654f7261636c653a206f76657268656164282920697320646560448201527f707265636174656400000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104289190611a84565b905090565b3373deaddeaddeaddeaddeaddeaddeaddeaddead0001146104f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e2073657420697345636f746f6e6520666c6160648201527f6700000000000000000000000000000000000000000000000000000000000000608482015260a40161039c565b60005460ff1615610589576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a2045636f746f6e6520616c72656164792060448201527f6163746976650000000000000000000000000000000000000000000000000000606482015260840161039c565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b6000805462010000900460ff166105cf57506000919050565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16634d5d9a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610630573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106549190611a9d565b63ffffffff169050600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff166316d3bc7f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e19190611ac3565b67ffffffffffffffff169050600060039054906101000a900460ff161561072a578061070d8386611b1c565b610718906064611b1c565b6107229190611b59565b949350505050565b610722620f424083860286810485148715177fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01176107699190611b71565b8281019081106000031790565b3373deaddeaddeaddeaddeaddeaddeaddeaddead00011461083f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e20736574206973497374686d757320666c6160648201527f6700000000000000000000000000000000000000000000000000000000000000608482015260a40161039c565b600054610100900460ff166108d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f47617350726963654f7261636c653a20497374686d75732063616e206f6e6c7960448201527f2062652061637469766174656420616674657220466a6f726400000000000000606482015260840161039c565b60005462010000900460ff161561096f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a20497374686d757320616c72656164792060448201527f6163746976650000000000000000000000000000000000000000000000000000606482015260840161039c565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff1662010000179055565b60008054610100900460ff16156109be576109b882611245565b92915050565b60005460ff16156109d2576109b882611264565b6109b882611308565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16635cf249696040518163ffffffff1660e01b8152600401602060405180830381865afa158015610404573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff166368d5dca66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104289190611a9d565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610b64576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e20736574206973466a6f726420666c616700606482015260840161039c565b60005460ff16610bf6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f47617350726963654f7261636c653a20466a6f72642063616e206f6e6c79206260448201527f65206163746976617465642061667465722045636f746f6e6500000000000000606482015260840161039c565b600054610100900460ff1615610c8d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f47617350726963654f7261636c653a20466a6f726420616c726561647920616360448201527f7469766500000000000000000000000000000000000000000000000000000000606482015260840161039c565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610d6057604080517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482015260248101919091527f47617350726963654f7261636c653a206f6e6c7920746865206465706f73697460448201527f6f72206163636f756e742063616e207365742069734a6f7669616e20666c6167606482015260840161039c565b60005462010000900460ff16610df8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f47617350726963654f7261636c653a204a6f7669616e2063616e206f6e6c792060448201527f62652061637469766174656420616674657220497374686d7573000000000000606482015260840161039c565b6000546301000000900460ff1615610e92576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f47617350726963654f7261636c653a204a6f7669616e20616c7265616479206160448201527f6374697665000000000000000000000000000000000000000000000000000000606482015260840161039c565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff166301000000179055565b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663c59859186040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a9d573d6000803e3d6000fd5b60008054610100900460ff1615610f6a57620f4240610f55610f448461145c565b51610f50906044611b59565b611779565b610f60906010611b1c565b6109b89190611b71565b6000610f75836117d8565b60005490915060ff1615610f895792915050565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fe8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100c9190611a84565b6110169082611b59565b9392505050565b60008054610100900460ff166110b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f47617350726963654f7261636c653a206765744c314665655570706572426f7560448201527f6e64206f6e6c7920737570706f72747320466a6f726400000000000000000000606482015260840161039c565b60006110c2836044611b59565b905060006110d160ff83611b71565b6110db9083611b59565b6110e6906010611b59565b905061072281611868565b6000805460ff1615611185576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f47617350726963654f7261636c653a207363616c61722829206973206465707260448201527f6563617465640000000000000000000000000000000000000000000000000000606482015260840161039c565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa158015610404573d6000803e3d6000fd5b600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663f82061406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610404573d6000803e3d6000fd5b60006109b86112538361145c565b5161125f906044611b59565b611868565b600080611270836117d8565b9050600061127c6109db565b611284610ec2565b61128f906010611bac565b63ffffffff1661129f9190611b1c565b905060006112ab6111e4565b6112b3610a3c565b63ffffffff166112c39190611b1c565b905060006112d18284611b59565b6112db9085611b1c565b90506112e96006600a611cf8565b6112f4906010611b1c565b6112fe9082611b71565b9695505050505050565b600080611314836117d8565b9050600073420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16639e8c49666040518163ffffffff1660e01b8152600401602060405180830381865afa158015611377573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139b9190611a84565b6113a36109db565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff16638b239f736040518163ffffffff1660e01b8152600401602060405180830381865afa158015611402573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114269190611a84565b6114309085611b59565b61143a9190611b1c565b6114449190611b1c565b90506114526006600a611cf8565b6107229082611b71565b60606115eb565b818153600101919050565b600082840393505b838110156110165782810151828201511860001a1590930292600101611476565b825b602082106114e35782516114ae601f83611463565b52602092909201917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910190602101611499565b81156110165782516114f86001840383611463565b520160010192915050565b60006001830392505b6101078210611544576115368360ff1661153160fd6115318760081c60e00189611463565b611463565b93506101068203915061150c565b600782106115715761156a8360ff16611531600785036115318760081c60e00189611463565b9050611016565b6107228360ff166115318560081c8560051b0187611463565b6115e38282036115c76115b784600081518060001a8160011a60081b178160021a60101b17915050919050565b639e3779b90260131c611fff1690565b8060021b6040510182815160e01c1860e01b8151188152505050565b600101919050565b6180003860405139618000604051016020830180600d8551820103826002015b8181101561171e576000805b50508051604051600082901a600183901a60081b1760029290921a60101b91909117639e3779b9810260111c617ffc16909101805160e081811c878603811890911b9091189091528401908183039084841061167357506116ae565b600184019350611fff82116116a8578251600081901a600182901a60081b1760029190911a60101b1781036116a857506116ae565b50611617565b8383106116bc57505061171e565b600183039250858311156116da576116d78787888603611497565b96505b6116ee60098501600385016003850161146e565b91506116fb878284611503565b9650506117138461170e8684860161158a565b61158a565b91505080935061160b565b50506117308383848851850103611497565b925050506040519150618000820180820391508183526020830160005b8381101561176557828101518282015260200161174d565b506000920191825250602001604052919050565b60008061178983620cc394611b1c565b6117b3907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd763200611d04565b90506117c36064620f4240611d78565b8112156109b8576110166064620f4240611d78565b80516000908190815b8181101561185b578481815181106117fb576117fb611e34565b01602001517fff000000000000000000000000000000000000000000000000000000000000001660000361183b57611834600484611b59565b9250611849565b611846601084611b59565b92505b8061185381611e63565b9150506117e1565b5061072282610440611b59565b60008061187483611779565b905060006118806111e4565b611888610a3c565b63ffffffff166118989190611b1c565b6118a06109db565b6118a8610ec2565b6118b3906010611bac565b63ffffffff166118c39190611b1c565b6118cd9190611b59565b90506118db60066002611b1c565b6118e690600a611cf8565b6118f08284611b1c565b6107229190611b71565b60006020828403121561190c57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561195457600080fd5b813567ffffffffffffffff8082111561196c57600080fd5b818401915084601f83011261198057600080fd5b81358181111561199257611992611913565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156119d8576119d8611913565b816040528281528760208487010111156119f157600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b81811015611a3e57858101830151858201604001528201611a22565b81811115611a50576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b600060208284031215611a9657600080fd5b5051919050565b600060208284031215611aaf57600080fd5b815163ffffffff8116811461101657600080fd5b600060208284031215611ad557600080fd5b815167ffffffffffffffff8116811461101657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611b5457611b54611aed565b500290565b60008219821115611b6c57611b6c611aed565b500190565b600082611ba7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b600063ffffffff80831681851681830481118215151615611bcf57611bcf611aed565b02949350505050565b600181815b80851115611c3157817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611c1757611c17611aed565b80851615611c2457918102915b93841c9390800290611bdd565b509250929050565b600082611c48575060016109b8565b81611c55575060006109b8565b8160018114611c6b5760028114611c7557611c91565b60019150506109b8565b60ff841115611c8657611c86611aed565b50506001821b6109b8565b5060208310610133831016604e8410600b8410161715611cb4575081810a6109b8565b611cbe8383611bd8565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115611cf057611cf0611aed565b029392505050565b60006110168383611c39565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03841381151615611d3e57611d3e611aed565b827f8000000000000000000000000000000000000000000000000000000000000000038412811615611d7257611d72611aed565b50500190565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600084136000841385830485118282161615611db957611db9611aed565b7f80000000000000000000000000000000000000000000000000000000000000006000871286820588128184161615611df457611df4611aed565b60008712925087820587128484161615611e1057611e10611aed565b87850587128184161615611e2657611e26611aed565b505050929093029392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e9457611e94611aed565b506001019056fea164736f6c634300080f000a000000000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 2600000, + "intent": "Deploy GasPriceOracle Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000002f3d60806040523480156200001157600080fd5b506200001c62000022565b620000e4565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015620000e2576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b612e4980620000f46000396000f3fe6080604052600436106101485760003560e01c80635c975abb116100c0578063a3a7954811610074578063c89701a211610059578063c89701a214610459578063dad544e014610486578063e11013dd1461049b57600080fd5b8063a3a7954814610426578063c4d66de81461043957600080fd5b806387087623116100a557806387087623146103955780638f601f66146103b5578063927ede2d146103fb57600080fd5b80635c975abb146103795780637f46ddb21461027a57600080fd5b806336c717c1116101175780633e47158c116100fc5780633e47158c146102f8578063540abf731461030d57806354fd4d501461032d57600080fd5b806336c717c11461027a5780633cb747bf146102cb57600080fd5b80630166a07a1461022157806309fc8843146102415780631635f5fd1461025457806332b7006d1461026757600080fd5b3661021c576101556104ae565b6101e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f5374616e646172644272696467653a2066756e6374696f6e2063616e206f6e6c60448201527f792062652063616c6c65642066726f6d20616e20454f4100000000000000000060648201526084015b60405180910390fd5b61021a73deaddeaddeaddeaddeaddeaddeaddeaddead000033333462030d40604051806020016040528060008152506104eb565b005b600080fd5b34801561022d57600080fd5b5061021a61023c3660046127ff565b6105c6565b61021a61024f3660046128b0565b610968565b61021a610262366004612903565b610a44565b61021a610275366004612976565b610e96565b34801561028657600080fd5b5060045473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156102d757600080fd5b506003546102a19073ffffffffffffffffffffffffffffffffffffffff1681565b34801561030457600080fd5b506102a1610f75565b34801561031957600080fd5b5061021a6103283660046129ca565b611180565b34801561033957600080fd5b50604080518082018252600681527f312e31332e310000000000000000000000000000000000000000000000000000602082015290516102c29190612ab7565b34801561038557600080fd5b50604051600081526020016102c2565b3480156103a157600080fd5b5061021a6103b0366004612aca565b6111c5565b3480156103c157600080fd5b506103ed6103d0366004612b4d565b600260209081526000928352604080842090915290825290205481565b6040519081526020016102c2565b34801561040757600080fd5b5060035473ffffffffffffffffffffffffffffffffffffffff166102a1565b61021a610434366004612aca565b61129e565b34801561044557600080fd5b5061021a610454366004612b86565b6112e2565b34801561046557600080fd5b506004546102a19073ffffffffffffffffffffffffffffffffffffffff1681565b34801561049257600080fd5b506102a1611493565b61021a6104a9366004612ba3565b611510565b60003233036104bd5750600190565b333b6017036104e557604051602081016040526020600082333c5160e81c62ef010014905090565b50600090565b7fffffffffffffffffffffffff215221522152215221522152215221522153000073ffffffffffffffffffffffffffffffffffffffff87160161053a576105358585858585611559565b6105be565b60008673ffffffffffffffffffffffffffffffffffffffff1663c01e1bd66040518163ffffffff1660e01b8152600401602060405180830381865afa158015610587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ab9190612c06565b90506105bc87828888888888611723565b505b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff1633148015610699575060048054600354604080517f6e296e45000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff938416949390921692636e296e459282820192602092908290030181865afa15801561065d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106819190612c06565b73ffffffffffffffffffffffffffffffffffffffff16145b61074b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f5374616e646172644272696467653a2066756e6374696f6e2063616e206f6e6c60448201527f792062652063616c6c65642066726f6d20746865206f7468657220627269646760648201527f6500000000000000000000000000000000000000000000000000000000000000608482015260a4016101dd565b61075487611adc565b156108a2576107638787611b3e565b610815576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f5374616e646172644272696467653a2077726f6e672072656d6f746520746f6b60448201527f656e20666f72204f7074696d69736d204d696e7461626c65204552433230206c60648201527f6f63616c20746f6b656e00000000000000000000000000000000000000000000608482015260a4016101dd565b6040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018590528816906340c10f1990604401600060405180830381600087803b15801561088557600080fd5b505af1158015610899573d6000803e3d6000fd5b50505050610924565b73ffffffffffffffffffffffffffffffffffffffff8088166000908152600260209081526040808320938a16835292905220546108e0908490612c52565b73ffffffffffffffffffffffffffffffffffffffff8089166000818152600260209081526040808320948c1683529390529190912091909155610924908585611c5e565b6105bc878787878787878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611d3292505050565b6109706104ae565b6109fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f5374616e646172644272696467653a2066756e6374696f6e2063616e206f6e6c60448201527f792062652063616c6c65642066726f6d20616e20454f4100000000000000000060648201526084016101dd565b610a3f3333348686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061155992505050565b505050565b60035473ffffffffffffffffffffffffffffffffffffffff1633148015610b17575060048054600354604080517f6e296e45000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff938416949390921692636e296e459282820192602092908290030181865afa158015610adb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aff9190612c06565b73ffffffffffffffffffffffffffffffffffffffff16145b610bc9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f5374616e646172644272696467653a2066756e6374696f6e2063616e206f6e6c60448201527f792062652063616c6c65642066726f6d20746865206f7468657220627269646760648201527f6500000000000000000000000000000000000000000000000000000000000000608482015260a4016101dd565b823414610c58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f5374616e646172644272696467653a20616d6f756e742073656e7420646f657360448201527f206e6f74206d6174636820616d6f756e7420726571756972656400000000000060648201526084016101dd565b3073ffffffffffffffffffffffffffffffffffffffff851603610cfd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f5374616e646172644272696467653a2063616e6e6f742073656e6420746f207360448201527f656c66000000000000000000000000000000000000000000000000000000000060648201526084016101dd565b60035473ffffffffffffffffffffffffffffffffffffffff90811690851603610da8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f5374616e646172644272696467653a2063616e6e6f742073656e6420746f206d60448201527f657373656e67657200000000000000000000000000000000000000000000000060648201526084016101dd565b610dea85858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611dc092505050565b6000610e07855a8660405180602001604052806000815250611e61565b9050806105be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f5374616e646172644272696467653a20455448207472616e736665722066616960448201527f6c6564000000000000000000000000000000000000000000000000000000000060648201526084016101dd565b610e9e6104ae565b610f2a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f5374616e646172644272696467653a2066756e6374696f6e2063616e206f6e6c60448201527f792062652063616c6c65642066726f6d20616e20454f4100000000000000000060648201526084016101dd565b610f6e853333878787878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506104eb92505050565b5050505050565b600080610fa07fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905073ffffffffffffffffffffffffffffffffffffffff811615610fc357919050565b6040518060400160405280601a81526020017f4f564d5f4c3143726f7373446f6d61696e4d657373656e6765720000000000008152505160026110069190612c69565b604080513060208201526000918101919091527f4f564d5f4c3143726f7373446f6d61696e4d657373656e6765720000000000009190911790611061906060015b604051602081830303815290604052805190602001205490565b14611098576040517f54e433cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080513060208201526001918101919091526000906110ba90606001611047565b905073ffffffffffffffffffffffffffffffffffffffff81161561114e578073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611123573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111479190612c06565b9250505090565b6040517f332144db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105bc87873388888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061172392505050565b6111cd6104ae565b611259576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f5374616e646172644272696467653a2066756e6374696f6e2063616e206f6e6c60448201527f792062652063616c6c65642066726f6d20616e20454f4100000000000000000060648201526084016101dd565b6105be86863333888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061172392505050565b6105be863387878787878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506104eb92505050565b600054610100900460ff16158080156113025750600054600160ff909116105b8061131c5750303b15801561131c575060005460ff166001145b6113a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016101dd565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561140657600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b61140e611e79565b61142c73420000000000000000000000000000000000000783611efc565b801561148f57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b600061149d610f75565b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061150b9190612c06565b905090565b6115533385348686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061155992505050565b50505050565b8234146115e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f5374616e646172644272696467653a206272696467696e6720455448206d757360448201527f7420696e636c7564652073756666696369656e74204554482076616c7565000060648201526084016101dd565b6115f485858584611fe6565b60035460045460405173ffffffffffffffffffffffffffffffffffffffff92831692633dbb202b9287929116907f1635f5fd0000000000000000000000000000000000000000000000000000000090611657908b908b9086908a90602401612ca6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009485161790525160e086901b90921682526116ea92918890600401612cef565b6000604051808303818588803b15801561170357600080fd5b505af1158015611717573d6000803e3d6000fd5b50505050505050505050565b34156117b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f5374616e646172644272696467653a2063616e6e6f742073656e642076616c7560448201527f650000000000000000000000000000000000000000000000000000000000000060648201526084016101dd565b6117ba87611adc565b15611908576117c98787611b3e565b61187b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f5374616e646172644272696467653a2077726f6e672072656d6f746520746f6b60448201527f656e20666f72204f7074696d69736d204d696e7461626c65204552433230206c60648201527f6f63616c20746f6b656e00000000000000000000000000000000000000000000608482015260a4016101dd565b6040517f9dc29fac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015260248201859052881690639dc29fac90604401600060405180830381600087803b1580156118eb57600080fd5b505af11580156118ff573d6000803e3d6000fd5b5050505061199c565b61192a73ffffffffffffffffffffffffffffffffffffffff8816863086612087565b73ffffffffffffffffffffffffffffffffffffffff8088166000908152600260209081526040808320938a1683529290522054611968908490612d34565b73ffffffffffffffffffffffffffffffffffffffff8089166000908152600260209081526040808320938b16835292905220555b6119aa8787878787866120e5565b60035460045460405173ffffffffffffffffffffffffffffffffffffffff92831692633dbb202b9216907f0166a07a0000000000000000000000000000000000000000000000000000000090611a0e908b908d908c908c908c908b90602401612d4c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009485161790525160e085901b9092168252611aa192918790600401612cef565b600060405180830381600087803b158015611abb57600080fd5b505af1158015611acf573d6000803e3d6000fd5b5050505050505050505050565b6000611b08827f1d1d8b6300000000000000000000000000000000000000000000000000000000612173565b80611b385750611b38827fec4fc8e300000000000000000000000000000000000000000000000000000000612173565b92915050565b6000611b6a837f1d1d8b6300000000000000000000000000000000000000000000000000000000612173565b15611c13578273ffffffffffffffffffffffffffffffffffffffff1663c01e1bd66040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bde9190612c06565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16149050611b38565b8273ffffffffffffffffffffffffffffffffffffffff1663d6c0b2c46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bba573d6000803e3d6000fd5b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a3f9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612196565b8373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fb0444523268717a02698be47d0803aa7468c00acbed2f8bd93a0459cde61dd89868686604051611daa93929190612da7565b60405180910390a46105be8686868686866122a2565b8373ffffffffffffffffffffffffffffffffffffffff1673deaddeaddeaddeaddeaddeaddeaddeaddead000073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fb0444523268717a02698be47d0803aa7468c00acbed2f8bd93a0459cde61dd89868686604051611e4d93929190612da7565b60405180910390a46115538484848461232a565b6000806000835160208501868989f195945050505050565b33611e82610f75565b73ffffffffffffffffffffffffffffffffffffffff1614158015611ec3575033611eaa611493565b73ffffffffffffffffffffffffffffffffffffffff1614155b15611efa576040517fc4050a2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b600054610100900460ff16611f93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016101dd565b6003805473ffffffffffffffffffffffffffffffffffffffff9384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560048054929093169116179055565b8373ffffffffffffffffffffffffffffffffffffffff1673deaddeaddeaddeaddeaddeaddeaddeaddead000073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f73d170910aba9e6d50b102db522b1dbcd796216f5128b445aa2135272886497e86868660405161207393929190612da7565b60405180910390a461155384848484612397565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526115539085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611cb0565b8373ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167f73d170910aba9e6d50b102db522b1dbcd796216f5128b445aa2135272886497e86868660405161215d93929190612da7565b60405180910390a46105be8686868686866123f6565b600061217e8361246e565b801561218f575061218f83836124d2565b9392505050565b60006121f8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166125a19092919063ffffffff16565b805190915015610a3f57808060200190518101906122169190612de5565b610a3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016101dd565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fd59c65b35445225835c83f50b6ede06a7be047d22e357073e250d9af537518cd86868660405161231a93929190612da7565b60405180910390a4505050505050565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f31b2166ff604fc5672ea5df08a78081d2bc6d746cadce880747f3643d819e83d8484604051612389929190612e07565b60405180910390a350505050565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f2849b43074093a05396b6f2a937dee8565b15a48a7b3d4bffb732a5017380af58484604051612389929190612e07565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f7ff126db8024424bbfd9826e8ab82ff59136289ea440b04b39a0df1b03b9cabf86868660405161231a93929190612da7565b600061249a827f01ffc9a7000000000000000000000000000000000000000000000000000000006124d2565b8015611b3857506124cb827fffffffff000000000000000000000000000000000000000000000000000000006124d2565b1592915050565b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825160009392849283928392918391908a617530fa92503d9150600051905082801561258a575060208210155b80156125965750600081115b979650505050505050565b60606125b084846000856125b8565b949350505050565b60608247101561264a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016101dd565b73ffffffffffffffffffffffffffffffffffffffff85163b6126c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016101dd565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516126f19190612e20565b60006040518083038185875af1925050503d806000811461272e576040519150601f19603f3d011682016040523d82523d6000602084013e612733565b606091505b50915091506125968282866060831561274d57508161218f565b82511561275d5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101dd9190612ab7565b73ffffffffffffffffffffffffffffffffffffffff811681146127b357600080fd5b50565b60008083601f8401126127c857600080fd5b50813567ffffffffffffffff8111156127e057600080fd5b6020830191508360208285010111156127f857600080fd5b9250929050565b600080600080600080600060c0888a03121561281a57600080fd5b873561282581612791565b9650602088013561283581612791565b9550604088013561284581612791565b9450606088013561285581612791565b93506080880135925060a088013567ffffffffffffffff81111561287857600080fd5b6128848a828b016127b6565b989b979a50959850939692959293505050565b803563ffffffff811681146128ab57600080fd5b919050565b6000806000604084860312156128c557600080fd5b6128ce84612897565b9250602084013567ffffffffffffffff8111156128ea57600080fd5b6128f6868287016127b6565b9497909650939450505050565b60008060008060006080868803121561291b57600080fd5b853561292681612791565b9450602086013561293681612791565b935060408601359250606086013567ffffffffffffffff81111561295957600080fd5b612965888289016127b6565b969995985093965092949392505050565b60008060008060006080868803121561298e57600080fd5b853561299981612791565b9450602086013593506129ae60408701612897565b9250606086013567ffffffffffffffff81111561295957600080fd5b600080600080600080600060c0888a0312156129e557600080fd5b87356129f081612791565b96506020880135612a0081612791565b95506040880135612a1081612791565b945060608801359350612a2560808901612897565b925060a088013567ffffffffffffffff81111561287857600080fd5b60005b83811015612a5c578181015183820152602001612a44565b838111156115535750506000910152565b60008151808452612a85816020860160208601612a41565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061218f6020830184612a6d565b60008060008060008060a08789031215612ae357600080fd5b8635612aee81612791565b95506020870135612afe81612791565b945060408701359350612b1360608801612897565b9250608087013567ffffffffffffffff811115612b2f57600080fd5b612b3b89828a016127b6565b979a9699509497509295939492505050565b60008060408385031215612b6057600080fd5b8235612b6b81612791565b91506020830135612b7b81612791565b809150509250929050565b600060208284031215612b9857600080fd5b813561218f81612791565b60008060008060608587031215612bb957600080fd5b8435612bc481612791565b9350612bd260208601612897565b9250604085013567ffffffffffffffff811115612bee57600080fd5b612bfa878288016127b6565b95989497509550505050565b600060208284031215612c1857600080fd5b815161218f81612791565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015612c6457612c64612c23565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612ca157612ca1612c23565b500290565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525083604083015260806060830152612ce56080830184612a6d565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff84168152606060208201526000612d1e6060830185612a6d565b905063ffffffff83166040830152949350505050565b60008219821115612d4757612d47612c23565b500190565b600073ffffffffffffffffffffffffffffffffffffffff80891683528088166020840152808716604084015280861660608401525083608083015260c060a0830152612d9b60c0830184612a6d565b98975050505050505050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000612ddc6060830184612a6d565b95945050505050565b600060208284031215612df757600080fd5b8151801515811461218f57600080fd5b8281526040602082015260006125b06040830184612a6d565b60008251612e32818460208701612a41565b919091019291505056fea164736f6c634300080f000a000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 3600000, + "intent": "Deploy L2StandardBridge Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca4000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000010956080604052348015600e575f80fd5b5060156019565b60c9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560685760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b610fbf806100d65f395ff3fe6080604052600436106100f2575f3560e01c80638312f14911610087578063d0e12f9011610057578063d0e12f90146102e9578063d3e5792b14610318578063d4ff9218146100fd578063dad544e01461032c575f80fd5b80638312f1491461028257806384411d651461029757806385b5b14d146102ab578063b49dc741146102ca575f80fd5b80633e47158c116100c25780633e47158c146101af57806354fd4d50146101c357806366d003ac1461021857806382356d8a14610244575f80fd5b80630d9019e1146100fd578063307f29621461014d5780633bbed4a01461016e5780633ccfd60b1461018d575f80fd5b366100f957005b5f80fd5b348015610108575f80fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b348015610158575f80fd5b5061016c610167366004610d6d565b610340565b005b348015610179575f80fd5b5061016c610188366004610daa565b6103e6565b348015610198575f80fd5b506101a161046d565b604051908152602001610144565b3480156101ba575f80fd5b5061012361077b565b3480156101ce575f80fd5b5061020b6040518060400160405280600581526020017f312e362e3100000000000000000000000000000000000000000000000000000081525081565b6040516101449190610dc5565b348015610223575f80fd5b506002546101239073ffffffffffffffffffffffffffffffffffffffff1681565b34801561024f575f80fd5b506002546102759074010000000000000000000000000000000000000000900460ff1681565b6040516101449190610e7e565b34801561028d575f80fd5b506101a160015481565b3480156102a2575f80fd5b506101a15f5481565b3480156102b6575f80fd5b5061016c6102c5366004610e92565b610981565b3480156102d5575f80fd5b5061016c6102e4366004610ea9565b6109c7565b3480156102f4575f80fd5b5060025474010000000000000000000000000000000000000000900460ff16610275565b348015610323575f80fd5b506001546101a1565b348015610337575f80fd5b50610123610be3565b610348610c5d565b600280547401000000000000000000000000000000000000000080820460ff1692849290917fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909116908360018111156103a4576103a4610e18565b02179055507ff2ec44eb1c3b3acd547b76333eb2c4b27eee311860c57a9fdb04c95f62398fc881836040516103da929190610ee4565b60405180910390a15050565b6103ee610c5d565b6002805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f62e69886a5df0ba8ffcacbfc1388754e7abd9bde24b036354c561f1acd4e459391016103da565b5f60015447101561052b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f4665655661756c743a207769746864726177616c20616d6f756e74206d75737460448201527f2062652067726561746572207468616e206d696e696d756d207769746864726160648201527f77616c20616d6f756e7400000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b479050805f8082825461053e9190610f2c565b90915550506002546040805183815273ffffffffffffffffffffffffffffffffffffffff909216602083018190523383830152905190917fc8a211cc64b6ed1b50595a9fcb1932b6d1e5a6e8ef15b60e5b1f988ea9086bba919081900360600190a16002546040517f38e04cbeb8c10f8f568618aa75be0f10b6729b8b4237743b4de20cbcde2839ee916105f39185918591339174010000000000000000000000000000000000000000900460ff1690610f3f565b60405180910390a1600160025474010000000000000000000000000000000000000000900460ff16600181111561062c5761062c610e18565b036106d0575f61063c8284610cb5565b9050806106cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4665655661756c743a206661696c656420746f2073656e642045544820746f2060448201527f4c322066656520726563697069656e74000000000000000000000000000000006064820152608401610522565b505090565b6040517fc2b3e5ac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015262061a806024820152606060448201525f60648201527342000000000000000000000000000000000000169063c2b3e5ac9084906084015f604051808303818588803b158015610760575f80fd5b505af1158015610772573d5f803e3d5ffd5b50505050505090565b5f806107a57fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905073ffffffffffffffffffffffffffffffffffffffff8116156107c857919050565b6040518060400160405280601a81526020017f4f564d5f4c3143726f7373446f6d61696e4d657373656e67657200000000000081525051600261080b9190610f80565b604080513060208201525f918101919091527f4f564d5f4c3143726f7373446f6d61696e4d657373656e6765720000000000009190911790610865906060015b604051602081830303815290604052805190602001205490565b1461089c576040517f54e433cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080513060208201526001918101919091525f906108bd9060600161084b565b905073ffffffffffffffffffffffffffffffffffffffff81161561094f578073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610924573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109489190610f97565b9250505090565b6040517f332144db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610989610c5d565b600180549082905560408051828152602081018490527f895a067c78583e800418fabf3da26a9496aab2ff3429cebdf7fefa642b2e420391016103da565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f81158015610a115750825b90505f8267ffffffffffffffff166001148015610a2d5750303b155b905081158015610a3b575080155b15610a72576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610ad35784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b610adb610cc8565b6002805473ffffffffffffffffffffffffffffffffffffffff8a167fffffffffffffffffffffffff000000000000000000000000000000000000000082168117835560018a81558993927fffffffffffffffffffffff000000000000000000000000000000000000000000169091179074010000000000000000000000000000000000000000908490811115610b7357610b73610e18565b02179055508315610bd95784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b5f610bec61077b565b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c34573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c589190610f97565b905090565b33610c66610be3565b73ffffffffffffffffffffffffffffffffffffffff1614610cb3576040517f7f12c64b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f610cc1835a84610d49565b9392505050565b33610cd161077b565b73ffffffffffffffffffffffffffffffffffffffff1614158015610d12575033610cf9610be3565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610cb3576040517fc4050a2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f805f858888f1949350505050565b803560028110610d68575f80fd5b919050565b5f60208284031215610d7d575f80fd5b610cc182610d5a565b73ffffffffffffffffffffffffffffffffffffffff81168114610da7575f80fd5b50565b5f60208284031215610dba575f80fd5b8135610cc181610d86565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60028110610e7a577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610e8c8284610e45565b92915050565b5f60208284031215610ea2575f80fd5b5035919050565b5f805f60608486031215610ebb575f80fd5b8335610ec681610d86565b925060208401359150610edb60408501610d5a565b90509250925092565b60408101610ef28285610e45565b610cc16020830184610e45565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610e8c57610e8c610eff565b84815273ffffffffffffffffffffffffffffffffffffffff84811660208301528316604082015260808101610f776060830184610e45565b95945050505050565b8082028115828204841417610e8c57610e8c610eff565b5f60208284031215610fa7575f80fd5b8151610cc181610d8656fea164736f6c6343000819000a0000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 1300000, + "intent": "Deploy SequencerFeeVault Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000002b6d608060405234801561001057600080fd5b5061001961001e565b6100de565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156100dc576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b612a80806100ed6000396000f3fe60806040523480156200001157600080fd5b5060043610620000935760003560e01c8063c4d66de81162000062578063c4d66de81462000175578063ce5ac90f146200018e578063e78cea9214620001a5578063ee9a31a214620001c657600080fd5b8063316b3739146200009857806354fd4d5014620000fb578063896f93d114620001475780638cf0629c146200015e575b600080fd5b620000d1620000a936600462000636565b60026020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b620001386040518060400160405280600681526020017f312e31302e32000000000000000000000000000000000000000000000000000081525081565b604051620000f29190620006c9565b620000d162000158366004620007c0565b620001e5565b620000d16200016f3660046200083d565b620001fc565b6200018c6200018636600462000636565b6200041b565b005b620000d16200019f366004620007c0565b620005ed565b600154620000d19073ffffffffffffffffffffffffffffffffffffffff1681565b60015473ffffffffffffffffffffffffffffffffffffffff16620000d1565b6000620001f4848484620005ed565b949350505050565b600073ffffffffffffffffffffffffffffffffffffffff8516620002a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f4f7074696d69736d4d696e7461626c654552433230466163746f72793a206d7560448201527f73742070726f766964652072656d6f746520746f6b656e20616464726573730060648201526084015b60405180910390fd5b600085858585604051602001620002c29493929190620008d4565b604051602081830303815290604052805190602001209050600081600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16888888886040516200031290620005fe565b620003229594939291906200092e565b8190604051809103906000f590508015801562000343573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff81811660008181526002602052604080822080547fffffffffffffffffffffffff000000000000000000000000000000000000000016948d1694851790555193945090927fceeb8e7d520d7f3b65fc11a262b91066940193b05d4f93df07cfdced0eb551cf9190a360405133815273ffffffffffffffffffffffffffffffffffffffff80891691908316907f52fe89dd5930f343d25650b62fd367bae47088bcddffd2a88350a6ecdd620cdb9060200160405180910390a39695505050505050565b600054610100900460ff16158080156200043c5750600054600160ff909116105b80620004585750303b15801562000458575060005460ff166001145b620004e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016200029e565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156200054557600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84161790558015620005e957600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6000620001f48484846012620001fc565b6120e0806200099483390190565b803573ffffffffffffffffffffffffffffffffffffffff811681146200063157600080fd5b919050565b6000602082840312156200064957600080fd5b62000654826200060c565b9392505050565b6000815180845260005b81811015620006835760208185018101518683018201520162000665565b8181111562000696576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006200065460208301846200065b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f8301126200071f57600080fd5b813567ffffffffffffffff808211156200073d576200073d620006de565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715620007865762000786620006de565b81604052838152866020858801011115620007a057600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600060608486031215620007d657600080fd5b620007e1846200060c565b9250602084013567ffffffffffffffff80821115620007ff57600080fd5b6200080d878388016200070d565b935060408601359150808211156200082457600080fd5b5062000833868287016200070d565b9150509250925092565b600080600080608085870312156200085457600080fd5b6200085f856200060c565b9350602085013567ffffffffffffffff808211156200087d57600080fd5b6200088b888389016200070d565b94506040870135915080821115620008a257600080fd5b50620008b1878288016200070d565b925050606085013560ff81168114620008c957600080fd5b939692955090935050565b73ffffffffffffffffffffffffffffffffffffffff851681526080602082015260006200090560808301866200065b565b82810360408401526200091981866200065b565b91505060ff8316606083015295945050505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a060408301526200096960a08301866200065b565b82810360608401526200097d81866200065b565b91505060ff83166080830152969550505050505056fe6101a06040523480156200001257600080fd5b50604051620020e0380380620020e0833981016040819052620000359162000215565b6040805180820190915260018152603160f81b6020820152839081908185600362000061838262000350565b50600462000070828262000350565b5050825160208085019190912083518483012060e08290526101008190524660a0818152604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81880181905281830187905260608201869052608082019490945230818401528151808203909301835260c0019052805194019390932091935091906080523060c05261012052505050506001600160a01b0394851661014052509390921661016052505060ff16610180526200041c565b80516001600160a01b03811681146200014357600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200017057600080fd5b81516001600160401b03808211156200018d576200018d62000148565b604051601f8301601f19908116603f01168101908282118183101715620001b857620001b862000148565b81604052838152602092508683858801011115620001d557600080fd5b600091505b83821015620001f95785820183015181830184015290820190620001da565b838211156200020b5760008385830101525b9695505050505050565b600080600080600060a086880312156200022e57600080fd5b62000239866200012b565b945062000249602087016200012b565b60408701519094506001600160401b03808211156200026757600080fd5b6200027589838a016200015e565b945060608801519150808211156200028c57600080fd5b506200029b888289016200015e565b925050608086015160ff81168114620002b357600080fd5b809150509295509295909350565b600181811c90821680620002d657607f821691505b602082108103620002f757634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200034b57600081815260208120601f850160051c81016020861015620003265750805b601f850160051c820191505b81811015620003475782815560010162000332565b5050505b505050565b81516001600160401b038111156200036c576200036c62000148565b62000384816200037d8454620002c1565b84620002fd565b602080601f831160018114620003bc5760008415620003a35750858301515b600019600386901b1c1916600185901b17855562000347565b600085815260208120601f198616915b82811015620003ed57888601518255948401946001909101908401620003cc565b50858210156200040c5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e0516101005161012051610140516101605161018051611c37620004a960003960006102700152600081816103a70152818161041c0152818161064801526107aa0152600081816101d501526103cd01526000611174015260006111c30152600061119e015260006110f7015260006111210152600061114b0152611c376000f3fe608060405234801561001057600080fd5b50600436106101a35760003560e01c806370a08231116100ee578063ae1f6aaf11610097578063d6c0b2c411610071578063d6c0b2c4146103cb578063dd62ed3e14610404578063e78cea92146103a5578063ee9a31a21461041757600080fd5b8063ae1f6aaf146103a5578063c01e1bd6146103cb578063d505accf146103f157600080fd5b80639dc29fac116100c85780639dc29fac1461036c578063a457c2d71461037f578063a9059cbb1461039257600080fd5b806370a082311461031b5780637ecebe001461035157806395d89b411461036457600080fd5b8063313ce5671161015057806340c10f191161012a57806340c10f19146102b557806354fd4d50146102ca5780636afdd8501461030657600080fd5b8063313ce567146102695780633644e5151461029a57806339509351146102a257600080fd5b8063095ea7b311610181578063095ea7b31461023157806318160ddd1461024457806323b872dd1461025657600080fd5b806301ffc9a7146101a8578063033964be146101d057806306fdde031461021c575b600080fd5b6101bb6101b636600461194b565b61043e565b60405190151581526020015b60405180910390f35b6101f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c7565b61022461052f565b6040516101c7919061198d565b6101bb61023f366004611a29565b6105c1565b6002545b6040519081526020016101c7565b6101bb610264366004611a53565b6105db565b60405160ff7f00000000000000000000000000000000000000000000000000000000000000001681526020016101c7565b6102486105ff565b6101bb6102b0366004611a29565b61060e565b6102c86102c3366004611a29565b610630565b005b6102246040518060400160405280600581526020017f312e342e3100000000000000000000000000000000000000000000000000000081525081565b6e22d473030f116ddee9f6b43ac78ba36101f7565b610248610329366004611a8f565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b61024861035f366004611a8f565b610758565b610224610783565b6102c861037a366004611a29565b610792565b6101bb61038d366004611a29565b6108a9565b6101bb6103a0366004611a29565b610956565b7f00000000000000000000000000000000000000000000000000000000000000006101f7565b7f00000000000000000000000000000000000000000000000000000000000000006101f7565b6102c86103ff366004611aaa565b610964565b610248610412366004611b1d565b610b23565b6101f77f000000000000000000000000000000000000000000000000000000000000000081565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007f1d1d8b63000000000000000000000000000000000000000000000000000000007fec4fc8e3000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000085168314806104f757507fffffffff00000000000000000000000000000000000000000000000000000000858116908316145b8061052657507fffffffff00000000000000000000000000000000000000000000000000000000858116908216145b95945050505050565b60606003805461053e90611b50565b80601f016020809104026020016040519081016040528092919081815260200182805461056a90611b50565b80156105b75780601f1061058c576101008083540402835291602001916105b7565b820191906000526020600020905b81548152906001019060200180831161059a57829003601f168201915b5050505050905090565b6000336105cf818585610bc4565b60019150505b92915050565b6000336105e9858285610d78565b6105f4858585610e2a565b506001949350505050565b60006106096110dd565b905090565b6000336105cf8185856106218383610b23565b61062b9190611bcc565b610bc4565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146106fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f4f7074696d69736d4d696e7461626c6545524332303a206f6e6c79206272696460448201527f67652063616e206d696e7420616e64206275726e00000000000000000000000060648201526084015b60405180910390fd5b6107048282611211565b8173ffffffffffffffffffffffffffffffffffffffff167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858260405161074c91815260200190565b60405180910390a25050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600560205260408120546105d5565b60606004805461053e90611b50565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610857576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603460248201527f4f7074696d69736d4d696e7461626c6545524332303a206f6e6c79206272696460448201527f67652063616e206d696e7420616e64206275726e00000000000000000000000060648201526084016106f1565b6108618282611331565b8173ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca58260405161074c91815260200190565b600033816108b78286610b23565b905083811015610949576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084016106f1565b6105f48286868403610bc4565b6000336105cf818585610e2a565b834211156109ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e6500000060448201526064016106f1565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886109fd8c611516565b60408051602081019690965273ffffffffffffffffffffffffffffffffffffffff94851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000610a658261154b565b90506000610a75828787876115b4565b90508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610b0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e6174757265000060448201526064016106f1565b610b178a8a8a610bc4565b50505050505050505050565b60007fffffffffffffffffffffffffffffffffffdd2b8cfcf0ee922116094bc538745d73ffffffffffffffffffffffffffffffffffffffff831601610b8957507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6105d5565b73ffffffffffffffffffffffffffffffffffffffff8084166000908152600160209081526040808320938616835292905220545b9392505050565b73ffffffffffffffffffffffffffffffffffffffff8316610c66576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f726573730000000000000000000000000000000000000000000000000000000060648201526084016106f1565b73ffffffffffffffffffffffffffffffffffffffff8216610d09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f737300000000000000000000000000000000000000000000000000000000000060648201526084016106f1565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6000610d848484610b23565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610e245781811015610e17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016106f1565b610e248484848403610bc4565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316610ecd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f647265737300000000000000000000000000000000000000000000000000000060648201526084016106f1565b73ffffffffffffffffffffffffffffffffffffffff8216610f70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f657373000000000000000000000000000000000000000000000000000000000060648201526084016106f1565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604090205481811015611026576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e6365000000000000000000000000000000000000000000000000000060648201526084016106f1565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526020819052604080822085850390559185168152908120805484929061106a908490611bcc565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516110d091815260200190565b60405180910390a3610e24565b60003073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614801561114357507f000000000000000000000000000000000000000000000000000000000000000046145b1561116d57507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b73ffffffffffffffffffffffffffffffffffffffff821661128e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016106f1565b80600260008282546112a09190611bcc565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600090815260208190526040812080548392906112da908490611bcc565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff82166113d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f730000000000000000000000000000000000000000000000000000000000000060648201526084016106f1565b73ffffffffffffffffffffffffffffffffffffffff82166000908152602081905260409020548181101561148a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f636500000000000000000000000000000000000000000000000000000000000060648201526084016106f1565b73ffffffffffffffffffffffffffffffffffffffff831660009081526020819052604081208383039055600280548492906114c6908490611be4565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90602001610d6b565b73ffffffffffffffffffffffffffffffffffffffff811660009081526005602052604090208054600181018255905b50919050565b60006105d56115586110dd565b836040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281018390526042810182905260009060620160405160208183030381529060405280519060200120905092915050565b60008060006115c5878787876115dc565b915091506115d2816116f4565b5095945050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561161357506000905060036116eb565b8460ff16601b1415801561162b57508460ff16601c14155b1561163c57506000905060046116eb565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611690573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166116e4576000600192509250506116eb565b9150600090505b94509492505050565b600081600481111561170857611708611bfb565b036117105750565b600181600481111561172457611724611bfb565b0361178b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016106f1565b600281600481111561179f5761179f611bfb565b03611806576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016106f1565b600381600481111561181a5761181a611bfb565b036118a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f756500000000000000000000000000000000000000000000000000000000000060648201526084016106f1565b60048160048111156118bb576118bb611bfb565b03611948576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c60448201527f756500000000000000000000000000000000000000000000000000000000000060648201526084016106f1565b50565b60006020828403121561195d57600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610bbd57600080fd5b600060208083528351808285015260005b818110156119ba5785810183015185820160400152820161199e565b818111156119cc576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611a2457600080fd5b919050565b60008060408385031215611a3c57600080fd5b611a4583611a00565b946020939093013593505050565b600080600060608486031215611a6857600080fd5b611a7184611a00565b9250611a7f60208501611a00565b9150604084013590509250925092565b600060208284031215611aa157600080fd5b610bbd82611a00565b600080600080600080600060e0888a031215611ac557600080fd5b611ace88611a00565b9650611adc60208901611a00565b95506040880135945060608801359350608088013560ff81168114611b0057600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611b3057600080fd5b611b3983611a00565b9150611b4760208401611a00565b90509250929050565b600181811c90821680611b6457607f821691505b602082108103611545577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611bdf57611bdf611b9d565b500190565b600082821015611bf657611bf6611b9d565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea164736f6c634300080f000aa164736f6c634300080f000a00000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 3600000, + "intent": "Deploy OptimismMintableERC20Factory Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001aaa608060405234801561001057600080fd5b5061001961001e565b6100de565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156100dc576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6119bd806100ed6000396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c80637f46ddb211610081578063c4d66de81161005b578063c4d66de8146101fa578063c89701a21461020d578063dad544e01461022d57600080fd5b80637f46ddb2146101ab578063927ede2d146101c9578063aa557452146101e757600080fd5b806354fd4d50116100b257806354fd4d50146101405780635c975abb14610189578063761f44931461019857600080fd5b80633687011a146100d95780633cb747bf146100ee5780633e47158c14610138575b600080fd5b6100ec6100e73660046115d7565b610235565b005b60015461010e9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61010e6102e6565b61017c6040518060400160405280600681526020017f312e31302e31000000000000000000000000000000000000000000000000000081525081565b60405161012f91906116c5565b6040516000815260200161012f565b6100ec6101a63660046116d8565b6104f1565b60025473ffffffffffffffffffffffffffffffffffffffff1661010e565b60015473ffffffffffffffffffffffffffffffffffffffff1661010e565b6100ec6101f5366004611770565b610a0f565b6100ec6102083660046117e7565b610acb565b60025461010e9073ffffffffffffffffffffffffffffffffffffffff1681565b61010e610c7c565b61023d610cf9565b6102ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f4552433732314272696467653a206163636f756e74206973206e6f742065787460448201527f65726e616c6c79206f776e65640000000000000000000000000000000000000060648201526084015b60405180910390fd5b6102de8686333388888888610d36565b505050505050565b6000806103117fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905073ffffffffffffffffffffffffffffffffffffffff81161561033457919050565b6040518060400160405280601a81526020017f4f564d5f4c3143726f7373446f6d61696e4d657373656e6765720000000000008152505160026103779190611804565b604080513060208201526000918101919091527f4f564d5f4c3143726f7373446f6d61696e4d657373656e67657200000000000091909117906103d2906060015b604051602081830303815290604052805190602001205490565b14610409576040517f54e433cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805130602082015260019181019190915260009061042b906060016103b8565b905073ffffffffffffffffffffffffffffffffffffffff8116156104bf578073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610494573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b89190611868565b9250505090565b6040517f332144db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015473ffffffffffffffffffffffffffffffffffffffff16331480156105c65750600254600154604080517f6e296e45000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9384169390921691636e296e45916004808201926020929091908290030181865afa15801561058a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ae9190611868565b73ffffffffffffffffffffffffffffffffffffffff16145b610652576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603f60248201527f4552433732314272696467653a2066756e6374696f6e2063616e206f6e6c792060448201527f62652063616c6c65642066726f6d20746865206f74686572206272696467650060648201526084016102c5565b3073ffffffffffffffffffffffffffffffffffffffff8816036106f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f4c324552433732314272696467653a206c6f63616c20746f6b656e2063616e6e60448201527f6f742062652073656c660000000000000000000000000000000000000000000060648201526084016102c5565b610721877faecafc230000000000000000000000000000000000000000000000000000000061128c565b6107ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f4c324552433732314272696467653a206c6f63616c20746f6b656e20696e746560448201527f7266616365206973206e6f7420636f6d706c69616e740000000000000000000060648201526084016102c5565b8673ffffffffffffffffffffffffffffffffffffffff1663d6c0b2c46040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081c9190611868565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16146108fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604b60248201527f4c324552433732314272696467653a2077726f6e672072656d6f746520746f6b60448201527f656e20666f72204f7074696d69736d204d696e7461626c65204552433732312060648201527f6c6f63616c20746f6b656e000000000000000000000000000000000000000000608482015260a4016102c5565b6040517fa144819400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301526024820185905288169063a144819490604401600060405180830381600087803b15801561096c57600080fd5b505af1158015610980573d6000803e3d6000fd5b505050508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167f1f39bf6707b5d608453e0ae4c067b562bcc4c85c0f562ef5d2c774d2e7f131ac878787876040516109fe94939291906118ce565b60405180910390a450505050505050565b73ffffffffffffffffffffffffffffffffffffffff8516610ab2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4552433732314272696467653a206e667420726563697069656e742063616e6e60448201527f6f7420626520616464726573732830290000000000000000000000000000000060648201526084016102c5565b610ac28787338888888888610d36565b50505050505050565b600054610100900460ff1615808015610aeb5750600054600160ff909116105b80610b055750303b158015610b05575060005460ff166001145b610b91576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016102c5565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610bef57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610bf76112af565b610c1573420000000000000000000000000000000000000783611332565b8015610c7857600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b6000610c866102e6565b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf49190611868565b905090565b6000323303610d085750600190565b333b601703610d3057604051602081016040526020600082333c5160e81c62ef010014905090565b50600090565b73ffffffffffffffffffffffffffffffffffffffff8716610dd9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f4c324552433732314272696467653a2072656d6f746520746f6b656e2063616e60448201527f6e6f74206265206164647265737328302900000000000000000000000000000060648201526084016102c5565b6040517f6352211e0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff891690636352211e90602401602060405180830381865afa158015610e44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e689190611868565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610f22576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f4c324552433732314272696467653a205769746864726177616c206973206e6f60448201527f74206265696e6720696e69746961746564206279204e4654206f776e6572000060648201526084016102c5565b60008873ffffffffffffffffffffffffffffffffffffffff1663d6c0b2c46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f939190611868565b90508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611050576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f4c324552433732314272696467653a2072656d6f746520746f6b656e20646f6560448201527f73206e6f74206d6174636820676976656e2076616c756500000000000000000060648201526084016102c5565b6040517f9dc29fac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152602482018790528a1690639dc29fac90604401600060405180830381600087803b1580156110c057600080fd5b505af11580156110d4573d6000803e3d6000fd5b505050506000818a89898988886040516024016110f7979695949392919061190e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f761f44930000000000000000000000000000000000000000000000000000000017905260015460025491517f3dbb202b00000000000000000000000000000000000000000000000000000000815292935073ffffffffffffffffffffffffffffffffffffffff90811692633dbb202b926111cc92169085908a9060040161196b565b600060405180830381600087803b1580156111e657600080fd5b505af11580156111fa573d6000803e3d6000fd5b505050508773ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff167fb7460e2a880f256ebef3406116ff3eee0cee51ebccdc2a40698f87ebb2e9c1a58a8a898960405161127894939291906118ce565b60405180910390a450505050505050505050565b60006112978361141c565b80156112a857506112a88383611481565b9392505050565b336112b86102e6565b73ffffffffffffffffffffffffffffffffffffffff16141580156112f95750336112e0610c7c565b73ffffffffffffffffffffffffffffffffffffffff1614155b15611330576040517fc4050a2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b600054610100900460ff166113c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e6700000000000000000000000000000000000000000060648201526084016102c5565b6001805473ffffffffffffffffffffffffffffffffffffffff9384167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560028054929093169116179055565b6000611448827f01ffc9a700000000000000000000000000000000000000000000000000000000611481565b801561147b5750611479827fffffffff00000000000000000000000000000000000000000000000000000000611481565b155b92915050565b604080517fffffffff000000000000000000000000000000000000000000000000000000008316602480830191909152825180830390910181526044909101909152602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825160009392849283928392918391908a617530fa92503d91506000519050828015611539575060208210155b80156115455750600081115b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461157257600080fd5b50565b803563ffffffff8116811461158957600080fd5b919050565b60008083601f8401126115a057600080fd5b50813567ffffffffffffffff8111156115b857600080fd5b6020830191508360208285010111156115d057600080fd5b9250929050565b60008060008060008060a087890312156115f057600080fd5b86356115fb81611550565b9550602087013561160b81611550565b94506040870135935061162060608801611575565b9250608087013567ffffffffffffffff81111561163c57600080fd5b61164889828a0161158e565b979a9699509497509295939492505050565b6000815180845260005b8181101561168057602081850181015186830182015201611664565b81811115611692576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006112a8602083018461165a565b600080600080600080600060c0888a0312156116f357600080fd5b87356116fe81611550565b9650602088013561170e81611550565b9550604088013561171e81611550565b9450606088013561172e81611550565b93506080880135925060a088013567ffffffffffffffff81111561175157600080fd5b61175d8a828b0161158e565b989b979a50959850939692959293505050565b600080600080600080600060c0888a03121561178b57600080fd5b873561179681611550565b965060208801356117a681611550565b955060408801356117b681611550565b9450606088013593506117cb60808901611575565b925060a088013567ffffffffffffffff81111561175157600080fd5b6000602082840312156117f957600080fd5b81356112a881611550565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611863577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500290565b60006020828403121561187a57600080fd5b81516112a881611550565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611904606083018486611885565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808a1683528089166020840152808816604084015280871660608401525084608083015260c060a083015261195e60c083018486611885565b9998505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8416815260606020820152600061199a606083018561165a565b905063ffffffff8316604083015294935050505056fea164736f6c634300080f000a00000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 1900000, + "intent": "Deploy L2ERC721Bridge Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000cad608060405234801561001057600080fd5b50610c8d806100206000396000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c80635cf24969116100f9578063c598591811610097578063e591b28211610071578063e591b28214610469578063e81b2c6d14610483578063f82061401461048c578063fe3d57101461049557600080fd5b8063c598591814610408578063d844471514610428578063dad544e01461046157600080fd5b80638381f58a116100d35780638381f58a146103c25780638b239f73146103d65780639e8c4966146103df578063b80777ea146103e857600080fd5b80635cf249691461038957806364ca23ef1461039257806368d5dca6146103a657600080fd5b80634397dfef1161016657806347af267b1161014057806347af267b146102ba5780634d5d9a2a146102dd57806354fd4d501461030e578063550fcdc91461035057600080fd5b80634397dfef14610277578063440a5e201461029f57806346a4d780146102a757600080fd5b806316d3bc7f116101a257806316d3bc7f14610202578063213268491461022f5780633db6be2b146102425780633e47158c1461024a57600080fd5b8063015d8eb9146101c9578063098999be146101de57806309bd5a60146101e6575b600080fd5b6101dc6101d7366004610ae1565b6104c6565b005b6101dc610605565b6101ef60025481565b6040519081526020015b60405180910390f35b6008546102169067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101f9565b60005b60405190151581526020016101f9565b6101dc610618565b610252610642565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f9565b6040805173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee815260126020820152016101f9565b6101dc61084d565b6101dc6102b5366004610b53565b6108a4565b6102326102c8366004610b53565b60096020526000908152604090205460ff1681565b6008546102f99068010000000000000000900463ffffffff1681565b60405163ffffffff90911681526020016101f9565b60408051808201909152600581527f312e392e3000000000000000000000000000000000000000000000000000000060208201525b6040516101f99190610b6c565b60408051808201909152600381527f45544800000000000000000000000000000000000000000000000000000000006020820152610343565b6101ef60015481565b6003546102169067ffffffffffffffff1681565b6003546102f99068010000000000000000900463ffffffff1681565b6000546102169067ffffffffffffffff1681565b6101ef60055481565b6101ef60065481565b6000546102169068010000000000000000900467ffffffffffffffff1681565b6003546102f9906c01000000000000000000000000900463ffffffff1681565b60408051808201909152600581527f45746865720000000000000000000000000000000000000000000000000000006020820152610343565b6102526108b9565b73deaddeaddeaddeaddeaddeaddeaddeaddead0001610252565b6101ef60045481565b6101ef60075481565b6008546104b3906c01000000000000000000000000900461ffff1681565b60405161ffff90911681526020016101f9565b3373deaddeaddeaddeaddeaddeaddeaddeaddead00011461056d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4c31426c6f636b3a206f6e6c7920746865206465706f7369746f72206163636f60448201527f756e742063616e20736574204c3120626c6f636b2076616c7565730000000000606482015260840160405180910390fd5b6000805467ffffffffffffffff98891668010000000000000000027fffffffffffffffffffffffffffffffff00000000000000000000000000000000909116998916999099179890981790975560019490945560029290925560038054919094167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009190911617909255600491909155600555600655565b61060d61084d565b60a43560a01c600855565b61062061084d565b6dffff00000000000000000000000060b03560901c1660a43560a01c17600855565b60008061066d7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905073ffffffffffffffffffffffffffffffffffffffff81161561069057919050565b6040518060400160405280601a81526020017f4f564d5f4c3143726f7373446f6d61696e4d657373656e6765720000000000008152505160026106d39190610bdf565b604080513060208201526000918101919091527f4f564d5f4c3143726f7373446f6d61696e4d657373656e676572000000000000919091179061072e906060015b604051602081830303815290604052805190602001205490565b14610765576040517f54e433cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805130602082015260019181019190915260009061078790606001610714565b905073ffffffffffffffffffffffffffffffffffffffff81161561081b578073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107f0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108149190610c43565b9250505090565b6040517f332144db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73deaddeaddeaddeaddeaddeaddeaddeaddead000133811461087757633cc50b456000526004601cfd5b60043560801c60035560143560801c60005560243560015560443560075560643560025560843560045550565b6108ad33610936565b6108b681610a13565b50565b60006108c3610642565b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561090d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109319190610c43565b905090565b73ffffffffffffffffffffffffffffffffffffffff811673deaddeaddeaddeaddeaddeaddeaddeaddead000114806109a057506109716108b9565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b806109dd57506109ae610642565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b6108b6576040517fbe9d7ca600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526009602052604090205460ff1615610a5c576040517f4f45326000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526009602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091559051909183917fb876f6594132c89891d2fd198e925e999be741ec809abb58bfe9b966876cc06c9190a350565b803567ffffffffffffffff81168114610adc57600080fd5b919050565b600080600080600080600080610100898b031215610afe57600080fd5b610b0789610ac4565b9750610b1560208a01610ac4565b96506040890135955060608901359450610b3160808a01610ac4565b979a969950949793969560a0850135955060c08501359460e001359350915050565b600060208284031215610b6557600080fd5b5035919050565b600060208083528351808285015260005b81811015610b9957858101830151858201604001528201610b7d565b81811115610bab576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610c3e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500290565b600060208284031215610c5557600080fd5b815173ffffffffffffffffffffffffffffffffffffffff81168114610c7957600080fd5b939250505056fea164736f6c634300080f000a00000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 750000, + "intent": "Deploy L1Block Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca4000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006e9608060405234801561001057600080fd5b506106c9806100206000396000f3fe6080604052600436106100695760003560e01c806382e3702d1161004357806382e3702d14610120578063c2b3e5ac14610160578063ecc704281461017357600080fd5b80633f827a5a1461009257806344df8e70146100bf57806354fd4d50146100d457600080fd5b3661008d5761008b33620186a0604051806020016040528060008152506101d8565b005b600080fd5b34801561009e57600080fd5b506100a7600181565b60405161ffff90911681526020015b60405180910390f35b3480156100cb57600080fd5b5061008b61039c565b3480156100e057600080fd5b50604080518082018252600581527f312e322e30000000000000000000000000000000000000000000000000000000602082015290516100b691906104c7565b34801561012c57600080fd5b5061015061013b3660046104e1565b60006020819052908152604090205460ff1681565b60405190151581526020016100b6565b61008b61016e366004610529565b6101d8565b34801561017f57600080fd5b506101ca6001547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e010000000000000000000000000000000000000000000000000000000000001790565b6040519081526020016100b6565b600061026e6040518060c001604052806102326001547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e010000000000000000000000000000000000000000000000000000000000001790565b815233602082015273ffffffffffffffffffffffffffffffffffffffff871660408201523460608201526080810186905260a0018490526103d4565b600081815260208190526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055905073ffffffffffffffffffffffffffffffffffffffff8416336103096001547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e010000000000000000000000000000000000000000000000000000000000001790565b7f02a52367d10742d8032712c1bb8e0144ff1ec5ffda1ed7d70bb05a27449550543487878760405161033e949392919061062d565b60405180910390a45050600180547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8082168301167fffff0000000000000000000000000000000000000000000000000000000000009091161790555050565b476103a681610421565b60405181907f7967de617a5ac1cc7eba2d6f37570a0135afa950d8bb77cdd35f0d0b4e85a16f90600090a250565b80516020808301516040808501516060860151608087015160a0880151935160009761040497909695910161065d565b604051602081830303815290604052805190602001209050919050565b8060405161042e90610450565b6040518091039082f090508015801561044b573d6000803e3d6000fd5b505050565b6008806106b583390190565b6000815180845260005b8181101561048257602081850181015186830182015201610466565b81811115610494576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006104da602083018461045c565b9392505050565b6000602082840312156104f357600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561053e57600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461056257600080fd5b925060208401359150604084013567ffffffffffffffff8082111561058657600080fd5b818601915086601f83011261059a57600080fd5b8135818111156105ac576105ac6104fa565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156105f2576105f26104fa565b8160405282815289602084870101111561060b57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b84815283602082015260806040820152600061064c608083018561045c565b905082606083015295945050505050565b868152600073ffffffffffffffffffffffffffffffffffffffff808816602084015280871660408401525084606083015283608083015260c060a08301526106a860c083018461045c565b9897505050505050505056fe608060405230fffea164736f6c634300080f000a0000000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 650000, + "intent": "Deploy L2ToL1MessagePasser Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000003f8d608060405234801561001057600080fd5b5061001961001e565b6100de565b600154610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60015460ff90811610156100dc576001805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b613ea0806100ed6000396000f3fe60806040523480156200001157600080fd5b5060043610620000cd5760003560e01c8063d2382242116200007f578063dad544e01162000062578063dad544e014620001d6578063e78cea9214620001e0578063ee9a31a2146200020757600080fd5b8063d238224214620001b5578063d97df65214620001bf57600080fd5b80635572acae11620000b45780635572acae14620001525780637d1d0c5b1462000189578063cd6dc687146200019c57600080fd5b80633e47158c14620000d257806354fd4d501462000106575b600080fd5b620000dc6200022c565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b620001436040518060400160405280600581526020017f312e352e3100000000000000000000000000000000000000000000000000000081525081565b604051620000fd9190620009ad565b6200017862000163366004620009ef565b60006020819052908152604090205460ff1681565b6040519015158152602001620000fd565b6002545b604051908152602001620000fd565b620001b3620001ad36600462000a0f565b62000443565b005b6200018d60025481565b620000dc620001d036600462000b20565b62000628565b620000dc62000826565b600154620000dc9062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b60015462010000900473ffffffffffffffffffffffffffffffffffffffff16620000dc565b600080620002587fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905073ffffffffffffffffffffffffffffffffffffffff8116156200027c57919050565b6040518060400160405280601a81526020017f4f564d5f4c3143726f7373446f6d61696e4d657373656e676572000000000000815250516002620002c1919062000b9f565b604080513060208201526000918101919091527f4f564d5f4c3143726f7373446f6d61696e4d657373656e67657200000000000091909117906200031d906060015b604051602081830303815290604052805190602001205490565b1462000355576040517f54e433cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051306020820152600191810191909152600090620003799060600162000303565b905073ffffffffffffffffffffffffffffffffffffffff81161562000411578073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620003e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200040a919062000c04565b9250505090565b6040517f332144db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600154610100900460ff16158080156200046157506001805460ff16105b806200047c5750303b1580156200047c57506001805460ff16145b6200050e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168117905580156200056c57600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b62000576620008a8565b600180547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff861602179055600282905580156200062357600180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1681556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050565b600073ffffffffffffffffffffffffffffffffffffffff8416620006f6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526044602482018190527f4f7074696d69736d4d696e7461626c65455243373231466163746f72793a204c908201527f3120746f6b656e20616464726573732063616e6e6f742062652061646472657360648201527f7328302900000000000000000000000000000000000000000000000000000000608482015260a40162000505565b60008484846040516020016200070f9392919062000c24565b604051602081830303815290604052805190602001209050600081600160029054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600254888888604051620007619062000931565b6200077195949392919062000c73565b8190604051809103906000f590508015801562000792573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff8181166000818152602081815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590513381529394509189169290917fe72783bb8e0ca31286b85278da59684dd814df9762a52f0837f89edd1483b299910160405180910390a395945050505050565b6000620008326200022c565b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200087d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008a3919062000c04565b905090565b33620008b36200022c565b73ffffffffffffffffffffffffffffffffffffffff1614158015620008f7575033620008de62000826565b73ffffffffffffffffffffffffffffffffffffffff1614155b156200092f576040517fc4050a2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6131bf8062000cd583390190565b6000815180845260005b81811015620009675760208185018101518683018201520162000949565b818111156200097a576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000620009c260208301846200093f565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff81168114620009ec57600080fd5b50565b60006020828403121562000a0257600080fd5b8135620009c281620009c9565b6000806040838503121562000a2357600080fd5b823562000a3081620009c9565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f83011262000a7f57600080fd5b813567ffffffffffffffff8082111562000a9d5762000a9d62000a3e565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171562000ae65762000ae662000a3e565b8160405283815286602085880101111562000b0057600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060006060848603121562000b3657600080fd5b833562000b4381620009c9565b9250602084013567ffffffffffffffff8082111562000b6157600080fd5b62000b6f8783880162000a6d565b9350604086013591508082111562000b8657600080fd5b5062000b958682870162000a6d565b9150509250925092565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161562000bff577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500290565b60006020828403121562000c1757600080fd5b8151620009c281620009c9565b73ffffffffffffffffffffffffffffffffffffffff8416815260606020820152600062000c5560608301856200093f565b828103604084015262000c6981856200093f565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835286602084015280861660408401525060a0606083015262000cb460a08301856200093f565b828103608084015262000cc881856200093f565b9897505050505050505056fe60e06040523480156200001157600080fd5b50604051620031bf380380620031bf83398101604081905262000034916200062d565b8181600062000044838262000756565b50600162000053828262000756565b5050506001600160a01b038516620000d85760405162461bcd60e51b815260206004820152603360248201527f4f7074696d69736d4d696e7461626c654552433732313a20627269646765206360448201527f616e6e6f7420626520616464726573732830290000000000000000000000000060648201526084015b60405180910390fd5b83600003620001505760405162461bcd60e51b815260206004820152603660248201527f4f7074696d69736d4d696e7461626c654552433732313a2072656d6f7465206360448201527f6861696e2069642063616e6e6f74206265207a65726f000000000000000000006064820152608401620000cf565b6001600160a01b038316620001ce5760405162461bcd60e51b815260206004820152603960248201527f4f7074696d69736d4d696e7461626c654552433732313a2072656d6f7465207460448201527f6f6b656e2063616e6e6f742062652061646472657373283029000000000000006064820152608401620000cf565b60808490526001600160a01b0383811660a081905290861660c0526200020290601462000256602090811b62000eed17901c565b62000218856200041660201b620011301760201c565b6040516020016200022b92919062000822565b604051602081830303815290604052600a90816200024a919062000756565b50505050505062000993565b6060600062000267836002620008ac565b62000274906002620008ce565b6001600160401b038111156200028e576200028e62000553565b6040519080825280601f01601f191660200182016040528015620002b9576020820181803683370190505b509050600360fc1b81600081518110620002d757620002d7620008e9565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110620003095762000309620008e9565b60200101906001600160f81b031916908160001a90535060006200032f846002620008ac565b6200033c906001620008ce565b90505b6001811115620003be576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110620003745762000374620008e9565b1a60f81b8282815181106200038d576200038d620008e9565b60200101906001600160f81b031916908160001a90535060049490941c93620003b681620008ff565b90506200033f565b5083156200040f5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401620000cf565b9392505050565b6060816000036200043e5750506040805180820190915260018152600360fc1b602082015290565b8160005b81156200046e5780620004558162000919565b9150620004669050600a836200094b565b915062000442565b6000816001600160401b038111156200048b576200048b62000553565b6040519080825280601f01601f191660200182016040528015620004b6576020820181803683370190505b5090505b84156200052e57620004ce60018362000962565b9150620004dd600a866200097c565b620004ea906030620008ce565b60f81b818381518110620005025762000502620008e9565b60200101906001600160f81b031916908160001a90535062000526600a866200094b565b9450620004ba565b949350505050565b80516001600160a01b03811681146200054e57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620005865781810151838201526020016200056c565b8381111562000596576000848401525b50505050565b600082601f830112620005ae57600080fd5b81516001600160401b0380821115620005cb57620005cb62000553565b604051601f8301601f19908116603f01168101908282118183101715620005f657620005f662000553565b816040528381528660208588010111156200061057600080fd5b6200062384602083016020890162000569565b9695505050505050565b600080600080600060a086880312156200064657600080fd5b620006518662000536565b945060208601519350620006686040870162000536565b60608701519093506001600160401b03808211156200068657600080fd5b6200069489838a016200059c565b93506080880151915080821115620006ab57600080fd5b50620006ba888289016200059c565b9150509295509295909350565b600181811c90821680620006dc57607f821691505b602082108103620006fd57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200075157600081815260208120601f850160051c810160208610156200072c5750805b601f850160051c820191505b818110156200074d5782815560010162000738565b5050505b505050565b81516001600160401b0381111562000772576200077262000553565b6200078a81620007838454620006c7565b8462000703565b602080601f831160018114620007c25760008415620007a95750858301515b600019600386901b1c1916600185901b1785556200074d565b600085815260208120601f198616915b82811015620007f357888601518255948401946001909101908401620007d2565b5085821015620008125787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6832ba3432b932bab69d60b91b8152600083516200084881600985016020880162000569565b600160fe1b60099184019182015283516200086b81600a84016020880162000569565b712f746f6b656e5552493f75696e743235363d60701b600a9290910191820152601c01949350505050565b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615620008c957620008c962000896565b500290565b60008219821115620008e457620008e462000896565b500190565b634e487b7160e01b600052603260045260246000fd5b60008162000911576200091162000896565b506000190190565b6000600182016200092e576200092e62000896565b5060010190565b634e487b7160e01b600052601260045260246000fd5b6000826200095d576200095d62000935565b500490565b60008282101562000977576200097762000896565b500390565b6000826200098e576200098e62000935565b500690565b60805160a05160c0516127d9620009e6600039600081816103e20152818161047a01528181610b210152610c430152600081816101e001526103bc015260008181610329015261040801526127d96000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c80637d1d0c5b116100ee578063c87b56dd11610097578063e78cea9211610071578063e78cea92146103e0578063e951819614610406578063e985e9c51461042c578063ee9a31a21461047557600080fd5b8063c87b56dd1461039f578063d547cfb7146103b2578063d6c0b2c4146103ba57600080fd5b8063a1448194116100c8578063a144819414610366578063a22cb46514610379578063b88d4fde1461038c57600080fd5b80637d1d0c5b1461032457806395d89b411461034b5780639dc29fac1461035357600080fd5b806323b872dd1161015b5780634f6ccce7116101355780634f6ccce7146102af57806354fd4d50146102c25780636352211e146102fe57806370a082311461031157600080fd5b806323b872dd146102765780632f745c591461028957806342842e0e1461029c57600080fd5b8063081812fc1161018c578063081812fc1461023c578063095ea7b31461024f57806318160ddd1461026457600080fd5b806301ffc9a7146101b3578063033964be146101db57806306fdde0314610227575b600080fd5b6101c66101c1366004612226565b61049c565b60405190151581526020015b60405180910390f35b6102027f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b61022f6104fa565b6040516101d291906122b9565b61020261024a3660046122cc565b61058c565b61026261025d36600461230e565b6105c0565b005b6008545b6040519081526020016101d2565b610262610284366004612338565b610751565b61026861029736600461230e565b6107f2565b6102626102aa366004612338565b6108c1565b6102686102bd3660046122cc565b6108dc565b61022f6040518060400160405280600581526020017f312e332e3200000000000000000000000000000000000000000000000000000081525081565b61020261030c3660046122cc565b61099a565b61026861031f366004612374565b610a2c565b6102687f000000000000000000000000000000000000000000000000000000000000000081565b61022f610afa565b61026261036136600461230e565b610b09565b61026261037436600461230e565b610c2b565b61026261038736600461238f565b610d42565b61026261039a3660046123fa565b610d51565b61022f6103ad3660046122cc565b610df9565b61022f610e5f565b7f0000000000000000000000000000000000000000000000000000000000000000610202565b7f0000000000000000000000000000000000000000000000000000000000000000610202565b7f0000000000000000000000000000000000000000000000000000000000000000610268565b6101c661043a3660046124f4565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260056020908152604080832093909416825291909152205460ff1690565b6102027f000000000000000000000000000000000000000000000000000000000000000081565b60007faecafc23000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083168114806104f357506104f38361126d565b9392505050565b60606000805461050990612527565b80601f016020809104026020016040519081016040528092919081815260200182805461053590612527565b80156105825780601f1061055757610100808354040283529160200191610582565b820191906000526020600020905b81548152906001019060200180831161056557829003601f168201915b5050505050905090565b6000610597826112c3565b5060009081526004602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b60006105cb8261099a565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361068d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560448201527f720000000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821614806106b657506106b6813361043a565b610742576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206e6f7220617070726f76656420666f7220616c6c00006064820152608401610684565b61074c8383611351565b505050565b61075b33826113f1565b6107e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206e6f7220617070726f7665640000000000000000000000000000000000006064820152608401610684565b61074c8383836114b0565b60006107fd83610a2c565b821061088b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201527f74206f6620626f756e64730000000000000000000000000000000000000000006064820152608401610684565b5073ffffffffffffffffffffffffffffffffffffffff919091166000908152600660209081526040808320938352929052205490565b61074c83838360405180602001604052806000815250610d51565b60006108e760085490565b8210610975576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201527f7574206f6620626f756e647300000000000000000000000000000000000000006064820152608401610684565b600882815481106109885761098861257a565b90600052602060002001549050919050565b60008181526002602052604081205473ffffffffffffffffffffffffffffffffffffffff1680610a26576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152606401610684565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff8216610ad1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f74206120766160448201527f6c6964206f776e657200000000000000000000000000000000000000000000006064820152608401610684565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526003602052604090205490565b60606001805461050990612527565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610bce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4f7074696d69736d4d696e7461626c654552433732313a206f6e6c792062726960448201527f6467652063616e2063616c6c20746869732066756e6374696f6e0000000000006064820152608401610684565b610bd781611722565b8173ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca582604051610c1f91815260200190565b60405180910390a25050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cf0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f4f7074696d69736d4d696e7461626c654552433732313a206f6e6c792062726960448201527f6467652063616e2063616c6c20746869732066756e6374696f6e0000000000006064820152608401610684565b610cfa82826117fb565b8173ffffffffffffffffffffffffffffffffffffffff167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688582604051610c1f91815260200190565b610d4d338383611815565b5050565b610d5b33836113f1565b610de7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206e6f7220617070726f7665640000000000000000000000000000000000006064820152608401610684565b610df384848484611942565b50505050565b6060610e04826112c3565b6000610e0e6119e5565b90506000815111610e2e57604051806020016040528060008152506104f3565b80610e3884611130565b604051602001610e499291906125a9565b6040516020818303038152906040529392505050565b600a8054610e6c90612527565b80601f0160208091040260200160405190810160405280929190818152602001828054610e9890612527565b8015610ee55780601f10610eba57610100808354040283529160200191610ee5565b820191906000526020600020905b815481529060010190602001808311610ec857829003601f168201915b505050505081565b60606000610efc836002612607565b610f07906002612644565b67ffffffffffffffff811115610f1f57610f1f6123cb565b6040519080825280601f01601f191660200182016040528015610f49576020820181803683370190505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110610f8057610f8061257a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110610fe357610fe361257a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600061101f846002612607565b61102a906001612644565b90505b60018111156110c7577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061106b5761106b61257a565b1a60f81b8282815181106110815761108161257a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c936110c08161265c565b905061102d565b5083156104f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610684565b60608160000361117357505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b811561119d578061118781612691565b91506111969050600a836126f8565b9150611177565b60008167ffffffffffffffff8111156111b8576111b86123cb565b6040519080825280601f01601f1916602001820160405280156111e2576020820181803683370190505b5090505b8415611265576111f760018361270c565b9150611204600a86612723565b61120f906030612644565b60f81b8183815181106112245761122461257a565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061125e600a866126f8565b94506111e6565b949350505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f780e9d63000000000000000000000000000000000000000000000000000000001480610a265750610a26826119f4565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1661134e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152606401610684565b50565b600081815260046020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff841690811790915581906113ab8261099a565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000806113fd8361099a565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061146b575073ffffffffffffffffffffffffffffffffffffffff80821660009081526005602090815260408083209388168352929052205460ff165b8061126557508373ffffffffffffffffffffffffffffffffffffffff166114918461058c565b73ffffffffffffffffffffffffffffffffffffffff1614949350505050565b8273ffffffffffffffffffffffffffffffffffffffff166114d08261099a565b73ffffffffffffffffffffffffffffffffffffffff1614611573576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201527f6f776e65720000000000000000000000000000000000000000000000000000006064820152608401610684565b73ffffffffffffffffffffffffffffffffffffffff8216611615576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610684565b611620838383611ad7565b61162b600082611351565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260036020526040812080546001929061166190849061270c565b909155505073ffffffffffffffffffffffffffffffffffffffff8216600090815260036020526040812080546001929061169c908490612644565b909155505060008181526002602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff86811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600061172d8261099a565b905061173b81600084611ad7565b611746600083611351565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260036020526040812080546001929061177c90849061270c565b909155505060008281526002602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555183919073ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b610d4d828260405180602001604052806000815250611bdd565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036118aa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152606401610684565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526005602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b61194d8484846114b0565b61195984848484611c80565b610df3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610684565b6060600a805461050990612527565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd000000000000000000000000000000000000000000000000000000001480611a8757507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610a2657507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610a26565b73ffffffffffffffffffffffffffffffffffffffff8316611b3f57611b3a81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b611b7c565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614611b7c57611b7c8382611e73565b73ffffffffffffffffffffffffffffffffffffffff8216611ba05761074c81611f2a565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161461074c5761074c8282611fd9565b611be7838361202a565b611bf46000848484611c80565b61074c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610684565b600073ffffffffffffffffffffffffffffffffffffffff84163b15611e68576040517f150b7a0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063150b7a0290611cf7903390899088908890600401612737565b6020604051808303816000875af1925050508015611d50575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252611d4d91810190612780565b60015b611e1d573d808015611d7e576040519150601f19603f3d011682016040523d82523d6000602084013e611d83565b606091505b508051600003611e15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527f63656976657220696d706c656d656e74657200000000000000000000000000006064820152608401610684565b805181602001fd5b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a0200000000000000000000000000000000000000000000000000000000149050611265565b506001949350505050565b60006001611e8084610a2c565b611e8a919061270c565b600083815260076020526040902054909150808214611eea5773ffffffffffffffffffffffffffffffffffffffff841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b50600091825260076020908152604080842084905573ffffffffffffffffffffffffffffffffffffffff9094168352600681528383209183525290812055565b600854600090611f3c9060019061270c565b60008381526009602052604081205460088054939450909284908110611f6457611f6461257a565b906000526020600020015490508060088381548110611f8557611f8561257a565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480611fbd57611fbd61279d565b6001900381819060005260206000200160009055905550505050565b6000611fe483610a2c565b73ffffffffffffffffffffffffffffffffffffffff9093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b73ffffffffffffffffffffffffffffffffffffffff82166120a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152606401610684565b60008181526002602052604090205473ffffffffffffffffffffffffffffffffffffffff1615612133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606401610684565b61213f60008383611ad7565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120805460019290612175908490612644565b909155505060008181526002602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461134e57600080fd5b60006020828403121561223857600080fd5b81356104f3816121f8565b60005b8381101561225e578181015183820152602001612246565b83811115610df35750506000910152565b60008151808452612287816020860160208601612243565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006104f3602083018461226f565b6000602082840312156122de57600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461230957600080fd5b919050565b6000806040838503121561232157600080fd5b61232a836122e5565b946020939093013593505050565b60008060006060848603121561234d57600080fd5b612356846122e5565b9250612364602085016122e5565b9150604084013590509250925092565b60006020828403121561238657600080fd5b6104f3826122e5565b600080604083850312156123a257600080fd5b6123ab836122e5565b9150602083013580151581146123c057600080fd5b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000806080858703121561241057600080fd5b612419856122e5565b9350612427602086016122e5565b925060408501359150606085013567ffffffffffffffff8082111561244b57600080fd5b818701915087601f83011261245f57600080fd5b813581811115612471576124716123cb565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156124b7576124b76123cb565b816040528281528a60208487010111156124d057600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b6000806040838503121561250757600080fd5b612510836122e5565b915061251e602084016122e5565b90509250929050565b600181811c9082168061253b57607f821691505b602082108103612574577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600083516125bb818460208801612243565b8351908301906125cf818360208801612243565b01949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561263f5761263f6125d8565b500290565b60008219821115612657576126576125d8565b500190565b60008161266b5761266b6125d8565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036126c2576126c26125d8565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600082612707576127076126c9565b500490565b60008282101561271e5761271e6125d8565b500390565b600082612732576127326126c9565b500690565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525083604083015260806060830152612776608083018461226f565b9695505050505050565b60006020828403121561279257600080fd5b81516104f3816121f8565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c634300080f000aa164736f6c634300080f000a00000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 4900000, + "intent": "Deploy OptimismMintableERC721Factory Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001c9d608060405234801561001057600080fd5b50600061001c3361002b565b6100258161002b565b5061007b565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611c138061008a6000396000f3fe6080604052600436106101445760003560e01c80637eff275e116100c057806399a88ec411610074578063b794726211610059578063b7947262146103c8578063f2fde38b14610403578063f3b7dead1461042357600080fd5b806399a88ec4146103885780639b2ea4bd146103a857600080fd5b80638d52d4a0116100a55780638d52d4a01461032a5780638da5cb5b1461034a5780639623609d1461037557600080fd5b80637eff275e146102ea578063860f7cda1461030a57600080fd5b80633ab76e9f116101175780636bd9f516116100fc5780636bd9f51614610278578063715018a6146102b55780637c36f37e146102ca57600080fd5b80633ab76e9f1461020257806354fd4d501461022f57600080fd5b80630652b57a1461014957806307c8f7b01461016b578063204e1c7a1461018b578063238181ae146101d5575b600080fd5b34801561015557600080fd5b50610169610164366004611490565b610443565b005b34801561017757600080fd5b506101696101863660046114ad565b610492565b34801561019757600080fd5b506101ab6101a6366004611490565b6104e4565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b3480156101e157600080fd5b506101f56101f0366004611490565b61070a565b6040516101cc9190611545565b34801561020e57600080fd5b506003546101ab9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561023b57600080fd5b506101f56040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b34801561028457600080fd5b506102a8610293366004611490565b60016020526000908152604090205460ff1681565b6040516101cc9190611587565b3480156102c157600080fd5b506101696107a4565b3480156102d657600080fd5b506101696102e5366004611490565b6107b8565b3480156102f657600080fd5b506101696103053660046115c8565b6109b0565b34801561031657600080fd5b50610169610325366004611723565b610b63565b34801561033657600080fd5b50610169610345366004611773565b610b9a565b34801561035657600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff166101ab565b6101696103833660046117a5565b610c0e565b34801561039457600080fd5b506101696103a33660046115c8565b610e25565b3480156103b457600080fd5b506101696103c336600461181b565b6110b5565b3480156103d457600080fd5b5060035474010000000000000000000000000000000000000000900460ff1660405190151581526020016101cc565b34801561040f57600080fd5b5061016961041e366004611490565b61114b565b34801561042f57600080fd5b506101ab61043e366004611490565b611202565b61044b611378565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b61049a611378565b6003805491151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff909216919091179055565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001602052604081205460ff168181600281111561052057610520611558565b0361059b578273ffffffffffffffffffffffffffffffffffffffff16635c60da1b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610570573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105949190611862565b9392505050565b60018160028111156105af576105af611558565b036105ff578273ffffffffffffffffffffffffffffffffffffffff1663aaf10f426040518163ffffffff1660e01b8152600401602060405180830381865afa158015610570573d6000803e3d6000fd5b600281600281111561061357610613611558565b0361069d5760035473ffffffffffffffffffffffffffffffffffffffff8481166000908152600260205260409081902090517fbf40fac1000000000000000000000000000000000000000000000000000000008152919092169163bf40fac19161068091906004016118cc565b602060405180830381865afa158015610570573d6000803e3d6000fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f50726f787941646d696e3a20756e6b6e6f776e2070726f78792074797065000060448201526064015b60405180910390fd5b50919050565b600260205260009081526040902080546107239061187f565b80601f016020809104026020016040519081016040528092919081815260200182805461074f9061187f565b801561079c5780601f106107715761010080835404028352916020019161079c565b820191906000526020600020905b81548152906001019060200180831161077f57829003601f168201915b505050505081565b6107ac611378565b6107b660006113f9565b565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610805576040517fcde661e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff163b60000361086e576040517fe1e56d9d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016106fb565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fd55ec697000000000000000000000000000000000000000000000000000000001790529051600091829173ffffffffffffffffffffffffffffffffffffffff8516916108ec91611975565b600060405180830381855af49150503d8060008114610927576040519150601f19603f3d011682016040523d82523d6000602084013e61092c565b606091505b50915091508161096a57806040517f1c0a89cc0000000000000000000000000000000000000000000000000000000081526004016106fb9190611545565b60405173ffffffffffffffffffffffffffffffffffffffff8416907f14e22d69ea30aab5b2220164345b33bdb5125e9c77a7d5fe12e23a1c691bd13990600090a2505050565b6109b8611378565b73ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604081205460ff16908160028111156109f4576109f4611558565b03610a80576040517f8f28397000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152841690638f283970906024015b600060405180830381600087803b158015610a6357600080fd5b505af1158015610a77573d6000803e3d6000fd5b50505050505050565b6001816002811115610a9457610a94611558565b03610aed576040517f13af403500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301528416906313af403590602401610a49565b6002816002811115610b0157610b01611558565b0361069d576003546040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301529091169063f2fde38b90602401610a49565b505050565b610b6b611378565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600260205260409020610b5e82826119d7565b610ba2611378565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600160208190526040909120805483927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911690836002811115610c0557610c05611558565b02179055505050565b610c16611378565b73ffffffffffffffffffffffffffffffffffffffff831660009081526001602052604081205460ff1690816002811115610c5257610c52611558565b03610d18576040517f4f1ef28600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851690634f1ef286903490610cad9087908790600401611af1565b60006040518083038185885af1158015610ccb573d6000803e3d6000fd5b50505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610d129190810190611b28565b50610e1f565b610d228484610e25565b60008473ffffffffffffffffffffffffffffffffffffffff163484604051610d4a9190611975565b60006040518083038185875af1925050503d8060008114610d87576040519150601f19603f3d011682016040523d82523d6000602084013e610d8c565b606091505b5050905080610e1d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f50726f787941646d696e3a2063616c6c20746f2070726f78792061667465722060448201527f75706772616465206661696c656400000000000000000000000000000000000060648201526084016106fb565b505b50505050565b610e2d611378565b73ffffffffffffffffffffffffffffffffffffffff821660009081526001602052604081205460ff1690816002811115610e6957610e69611558565b03610ec2576040517f3659cfe600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152841690633659cfe690602401610a49565b6001816002811115610ed657610ed6611558565b03610f55576040517f9b0b0fda0000000000000000000000000000000000000000000000000000000081527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152841690639b0b0fda90604401610a49565b6002816002811115610f6957610f69611558565b036110ad5773ffffffffffffffffffffffffffffffffffffffff831660009081526002602052604081208054610f9e9061187f565b80601f0160208091040260200160405190810160405280929190818152602001828054610fca9061187f565b80156110175780601f10610fec57610100808354040283529160200191611017565b820191906000526020600020905b815481529060010190602001808311610ffa57829003601f168201915b50506003546040517f9b2ea4bd00000000000000000000000000000000000000000000000000000000815294955073ffffffffffffffffffffffffffffffffffffffff1693639b2ea4bd935061107592508591508790600401611b9f565b600060405180830381600087803b15801561108f57600080fd5b505af11580156110a3573d6000803e3d6000fd5b5050505050505050565b610b5e611bd7565b6110bd611378565b6003546040517f9b2ea4bd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911690639b2ea4bd906111159085908590600401611b9f565b600060405180830381600087803b15801561112f57600080fd5b505af1158015611143573d6000803e3d6000fd5b505050505050565b611153611378565b73ffffffffffffffffffffffffffffffffffffffff81166111f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016106fb565b6111ff816113f9565b50565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001602052604081205460ff168181600281111561123e5761123e611558565b0361128e578273ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610570573d6000803e3d6000fd5b60018160028111156112a2576112a2611558565b036112f2578273ffffffffffffffffffffffffffffffffffffffff1663893d20e86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610570573d6000803e3d6000fd5b600281600281111561130657611306611558565b0361069d57600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610570573d6000803e3d6000fd5b60005473ffffffffffffffffffffffffffffffffffffffff1633146107b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106fb565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff811681146111ff57600080fd5b6000602082840312156114a257600080fd5b81356105948161146e565b6000602082840312156114bf57600080fd5b8135801515811461059457600080fd5b60005b838110156114ea5781810151838201526020016114d2565b83811115610e1f5750506000910152565b600081518084526115138160208601602086016114cf565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061059460208301846114fb565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60208101600383106115c2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b600080604083850312156115db57600080fd5b82356115e68161146e565b915060208301356115f68161146e565b809150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561167757611677611601565b604052919050565b600067ffffffffffffffff82111561169957611699611601565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60006116d86116d38461167f565b611630565b90508281528383830111156116ec57600080fd5b828260208301376000602084830101529392505050565b600082601f83011261171457600080fd5b610594838335602085016116c5565b6000806040838503121561173657600080fd5b82356117418161146e565b9150602083013567ffffffffffffffff81111561175d57600080fd5b61176985828601611703565b9150509250929050565b6000806040838503121561178657600080fd5b82356117918161146e565b91506020830135600381106115f657600080fd5b6000806000606084860312156117ba57600080fd5b83356117c58161146e565b925060208401356117d58161146e565b9150604084013567ffffffffffffffff8111156117f157600080fd5b8401601f8101861361180257600080fd5b611811868235602084016116c5565b9150509250925092565b6000806040838503121561182e57600080fd5b823567ffffffffffffffff81111561184557600080fd5b61185185828601611703565b92505060208301356115f68161146e565b60006020828403121561187457600080fd5b81516105948161146e565b600181811c9082168061189357607f821691505b602082108103610704577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006020808352600084546118e08161187f565b80848701526040600180841660008114611901576001811461193957611967565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838a01528284151560051b8a01019550611967565b896000528660002060005b8581101561195f5781548b8201860152908301908801611944565b8a0184019650505b509398975050505050505050565b600082516119878184602087016114cf565b9190910192915050565b601f821115610b5e57600081815260208120601f850160051c810160208610156119b85750805b601f850160051c820191505b81811015611143578281556001016119c4565b815167ffffffffffffffff8111156119f1576119f1611601565b611a05816119ff845461187f565b84611991565b602080601f831160018114611a585760008415611a225750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555611143565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015611aa557888601518255948401946001909101908401611a86565b5085821015611ae157878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000611b2060408301846114fb565b949350505050565b600060208284031215611b3a57600080fd5b815167ffffffffffffffff811115611b5157600080fd5b8201601f81018413611b6257600080fd5b8051611b706116d38261167f565b818152856020838501011115611b8557600080fd5b611b968260208301602086016114cf565b95945050505050565b604081526000611bb260408301856114fb565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fdfea164736f6c634300080f000a000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 2400000, + "intent": "Deploy L2ProxyAdmin Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca40000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000108a6080604052348015600e575f80fd5b5060156019565b60c9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560685760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b610fb4806100d65f395ff3fe6080604052600436106100e7575f3560e01c806382356d8a11610087578063b49dc74111610057578063b49dc741146102bf578063d0e12f90146102de578063d3e5792b1461030d578063dad544e014610321575f80fd5b806382356d8a146102395780638312f1491461027757806384411d651461028c57806385b5b14d146102a0575f80fd5b80633ccfd60b116100c25780633ccfd60b146101825780633e47158c146101a457806354fd4d50146101b857806366d003ac1461020d575f80fd5b80630d9019e1146100f2578063307f2962146101425780633bbed4a014610163575f80fd5b366100ee57005b5f80fd5b3480156100fd575f80fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561014d575f80fd5b5061016161015c366004610d62565b610335565b005b34801561016e575f80fd5b5061016161017d366004610d9f565b6103db565b34801561018d575f80fd5b50610196610462565b604051908152602001610139565b3480156101af575f80fd5b50610118610770565b3480156101c3575f80fd5b506102006040518060400160405280600581526020017f312e362e3100000000000000000000000000000000000000000000000000000081525081565b6040516101399190610dba565b348015610218575f80fd5b506002546101189073ffffffffffffffffffffffffffffffffffffffff1681565b348015610244575f80fd5b5060025461026a9074010000000000000000000000000000000000000000900460ff1681565b6040516101399190610e73565b348015610282575f80fd5b5061019660015481565b348015610297575f80fd5b506101965f5481565b3480156102ab575f80fd5b506101616102ba366004610e87565b610976565b3480156102ca575f80fd5b506101616102d9366004610e9e565b6109bc565b3480156102e9575f80fd5b5060025474010000000000000000000000000000000000000000900460ff1661026a565b348015610318575f80fd5b50600154610196565b34801561032c575f80fd5b50610118610bd8565b61033d610c52565b600280547401000000000000000000000000000000000000000080820460ff1692849290917fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff9091169083600181111561039957610399610e0d565b02179055507ff2ec44eb1c3b3acd547b76333eb2c4b27eee311860c57a9fdb04c95f62398fc881836040516103cf929190610ed9565b60405180910390a15050565b6103e3610c52565b6002805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f62e69886a5df0ba8ffcacbfc1388754e7abd9bde24b036354c561f1acd4e459391016103cf565b5f600154471015610520576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f4665655661756c743a207769746864726177616c20616d6f756e74206d75737460448201527f2062652067726561746572207468616e206d696e696d756d207769746864726160648201527f77616c20616d6f756e7400000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b479050805f808282546105339190610f21565b90915550506002546040805183815273ffffffffffffffffffffffffffffffffffffffff909216602083018190523383830152905190917fc8a211cc64b6ed1b50595a9fcb1932b6d1e5a6e8ef15b60e5b1f988ea9086bba919081900360600190a16002546040517f38e04cbeb8c10f8f568618aa75be0f10b6729b8b4237743b4de20cbcde2839ee916105e89185918591339174010000000000000000000000000000000000000000900460ff1690610f34565b60405180910390a1600160025474010000000000000000000000000000000000000000900460ff16600181111561062157610621610e0d565b036106c5575f6106318284610caa565b9050806106c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4665655661756c743a206661696c656420746f2073656e642045544820746f2060448201527f4c322066656520726563697069656e74000000000000000000000000000000006064820152608401610517565b505090565b6040517fc2b3e5ac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015262061a806024820152606060448201525f60648201527342000000000000000000000000000000000000169063c2b3e5ac9084906084015f604051808303818588803b158015610755575f80fd5b505af1158015610767573d5f803e3d5ffd5b50505050505090565b5f8061079a7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905073ffffffffffffffffffffffffffffffffffffffff8116156107bd57919050565b6040518060400160405280601a81526020017f4f564d5f4c3143726f7373446f6d61696e4d657373656e6765720000000000008152505160026108009190610f75565b604080513060208201525f918101919091527f4f564d5f4c3143726f7373446f6d61696e4d657373656e676572000000000000919091179061085a906060015b604051602081830303815290604052805190602001205490565b14610891576040517f54e433cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080513060208201526001918101919091525f906108b290606001610840565b905073ffffffffffffffffffffffffffffffffffffffff811615610944578073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610919573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061093d9190610f8c565b9250505090565b6040517f332144db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61097e610c52565b600180549082905560408051828152602081018490527f895a067c78583e800418fabf3da26a9496aab2ff3429cebdf7fefa642b2e420391016103cf565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f81158015610a065750825b90505f8267ffffffffffffffff166001148015610a225750303b155b905081158015610a30575080155b15610a67576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610ac85784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b610ad0610cbd565b6002805473ffffffffffffffffffffffffffffffffffffffff8a167fffffffffffffffffffffffff000000000000000000000000000000000000000082168117835560018a81558993927fffffffffffffffffffffff000000000000000000000000000000000000000000169091179074010000000000000000000000000000000000000000908490811115610b6857610b68610e0d565b02179055508315610bce5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b5f610be1610770565b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c29573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c4d9190610f8c565b905090565b33610c5b610bd8565b73ffffffffffffffffffffffffffffffffffffffff1614610ca8576040517f7f12c64b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f610cb6835a84610d3e565b9392505050565b33610cc6610770565b73ffffffffffffffffffffffffffffffffffffffff1614158015610d07575033610cee610bd8565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610ca8576040517fc4050a2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f805f858888f1949350505050565b803560028110610d5d575f80fd5b919050565b5f60208284031215610d72575f80fd5b610cb682610d4f565b73ffffffffffffffffffffffffffffffffffffffff81168114610d9c575f80fd5b50565b5f60208284031215610daf575f80fd5b8135610cb681610d7b565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60028110610e6f577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610e818284610e3a565b92915050565b5f60208284031215610e97575f80fd5b5035919050565b5f805f60608486031215610eb0575f80fd5b8335610ebb81610d7b565b925060208401359150610ed060408501610d4f565b90509250925092565b60408101610ee78285610e3a565b610cb66020830184610e3a565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610e8157610e81610ef4565b84815273ffffffffffffffffffffffffffffffffffffffff84811660208301528316604082015260808101610f6c6060830184610e3a565b95945050505050565b8082028115828204841417610e8157610e81610ef4565b5f60208284031215610f9c575f80fd5b8151610cb681610d7b56fea164736f6c6343000819000a00000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 1300000, + "intent": "Deploy BaseFeeVault Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca40000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000108a6080604052348015600e575f80fd5b5060156019565b60c9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560685760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b610fb4806100d65f395ff3fe6080604052600436106100e7575f3560e01c806382356d8a11610087578063b49dc74111610057578063b49dc741146102bf578063d0e12f90146102de578063d3e5792b1461030d578063dad544e014610321575f80fd5b806382356d8a146102395780638312f1491461027757806384411d651461028c57806385b5b14d146102a0575f80fd5b80633ccfd60b116100c25780633ccfd60b146101825780633e47158c146101a457806354fd4d50146101b857806366d003ac1461020d575f80fd5b80630d9019e1146100f2578063307f2962146101425780633bbed4a014610163575f80fd5b366100ee57005b5f80fd5b3480156100fd575f80fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561014d575f80fd5b5061016161015c366004610d62565b610335565b005b34801561016e575f80fd5b5061016161017d366004610d9f565b6103db565b34801561018d575f80fd5b50610196610462565b604051908152602001610139565b3480156101af575f80fd5b50610118610770565b3480156101c3575f80fd5b506102006040518060400160405280600581526020017f312e362e3100000000000000000000000000000000000000000000000000000081525081565b6040516101399190610dba565b348015610218575f80fd5b506002546101189073ffffffffffffffffffffffffffffffffffffffff1681565b348015610244575f80fd5b5060025461026a9074010000000000000000000000000000000000000000900460ff1681565b6040516101399190610e73565b348015610282575f80fd5b5061019660015481565b348015610297575f80fd5b506101965f5481565b3480156102ab575f80fd5b506101616102ba366004610e87565b610976565b3480156102ca575f80fd5b506101616102d9366004610e9e565b6109bc565b3480156102e9575f80fd5b5060025474010000000000000000000000000000000000000000900460ff1661026a565b348015610318575f80fd5b50600154610196565b34801561032c575f80fd5b50610118610bd8565b61033d610c52565b600280547401000000000000000000000000000000000000000080820460ff1692849290917fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff9091169083600181111561039957610399610e0d565b02179055507ff2ec44eb1c3b3acd547b76333eb2c4b27eee311860c57a9fdb04c95f62398fc881836040516103cf929190610ed9565b60405180910390a15050565b6103e3610c52565b6002805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f62e69886a5df0ba8ffcacbfc1388754e7abd9bde24b036354c561f1acd4e459391016103cf565b5f600154471015610520576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f4665655661756c743a207769746864726177616c20616d6f756e74206d75737460448201527f2062652067726561746572207468616e206d696e696d756d207769746864726160648201527f77616c20616d6f756e7400000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b479050805f808282546105339190610f21565b90915550506002546040805183815273ffffffffffffffffffffffffffffffffffffffff909216602083018190523383830152905190917fc8a211cc64b6ed1b50595a9fcb1932b6d1e5a6e8ef15b60e5b1f988ea9086bba919081900360600190a16002546040517f38e04cbeb8c10f8f568618aa75be0f10b6729b8b4237743b4de20cbcde2839ee916105e89185918591339174010000000000000000000000000000000000000000900460ff1690610f34565b60405180910390a1600160025474010000000000000000000000000000000000000000900460ff16600181111561062157610621610e0d565b036106c5575f6106318284610caa565b9050806106c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4665655661756c743a206661696c656420746f2073656e642045544820746f2060448201527f4c322066656520726563697069656e74000000000000000000000000000000006064820152608401610517565b505090565b6040517fc2b3e5ac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015262061a806024820152606060448201525f60648201527342000000000000000000000000000000000000169063c2b3e5ac9084906084015f604051808303818588803b158015610755575f80fd5b505af1158015610767573d5f803e3d5ffd5b50505050505090565b5f8061079a7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905073ffffffffffffffffffffffffffffffffffffffff8116156107bd57919050565b6040518060400160405280601a81526020017f4f564d5f4c3143726f7373446f6d61696e4d657373656e6765720000000000008152505160026108009190610f75565b604080513060208201525f918101919091527f4f564d5f4c3143726f7373446f6d61696e4d657373656e676572000000000000919091179061085a906060015b604051602081830303815290604052805190602001205490565b14610891576040517f54e433cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080513060208201526001918101919091525f906108b290606001610840565b905073ffffffffffffffffffffffffffffffffffffffff811615610944578073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610919573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061093d9190610f8c565b9250505090565b6040517f332144db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61097e610c52565b600180549082905560408051828152602081018490527f895a067c78583e800418fabf3da26a9496aab2ff3429cebdf7fefa642b2e420391016103cf565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f81158015610a065750825b90505f8267ffffffffffffffff166001148015610a225750303b155b905081158015610a30575080155b15610a67576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610ac85784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b610ad0610cbd565b6002805473ffffffffffffffffffffffffffffffffffffffff8a167fffffffffffffffffffffffff000000000000000000000000000000000000000082168117835560018a81558993927fffffffffffffffffffffff000000000000000000000000000000000000000000169091179074010000000000000000000000000000000000000000908490811115610b6857610b68610e0d565b02179055508315610bce5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b5f610be1610770565b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c29573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c4d9190610f8c565b905090565b33610c5b610bd8565b73ffffffffffffffffffffffffffffffffffffffff1614610ca8576040517f7f12c64b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f610cb6835a84610d3e565b9392505050565b33610cc6610770565b73ffffffffffffffffffffffffffffffffffffffff1614158015610d07575033610cee610bd8565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610ca8576040517fc4050a2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f805f858888f1949350505050565b803560028110610d5d575f80fd5b919050565b5f60208284031215610d72575f80fd5b610cb682610d4f565b73ffffffffffffffffffffffffffffffffffffffff81168114610d9c575f80fd5b50565b5f60208284031215610daf575f80fd5b8135610cb681610d7b565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60028110610e6f577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610e818284610e3a565b92915050565b5f60208284031215610e97575f80fd5b5035919050565b5f805f60608486031215610eb0575f80fd5b8335610ebb81610d7b565b925060208401359150610ed060408501610d4f565b90509250925092565b60408101610ee78285610e3a565b610cb66020830184610e3a565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610e8157610e81610ef4565b84815273ffffffffffffffffffffffffffffffffffffffff84811660208301528316604082015260808101610f6c6060830184610e3a565b95945050505050565b8082028115828204841417610e8157610e81610ef4565b5f60208284031215610f9c575f80fd5b8151610cb681610d7b56fea164736f6c6343000819000a00000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 50000, + "intent": "Deploy L1FeeVault Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca40000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000108a6080604052348015600e575f80fd5b5060156019565b60c9565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161560685760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161460c65780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b610fb4806100d65f395ff3fe6080604052600436106100e7575f3560e01c806382356d8a11610087578063b49dc74111610057578063b49dc741146102bf578063d0e12f90146102de578063d3e5792b1461030d578063dad544e014610321575f80fd5b806382356d8a146102395780638312f1491461027757806384411d651461028c57806385b5b14d146102a0575f80fd5b80633ccfd60b116100c25780633ccfd60b146101825780633e47158c146101a457806354fd4d50146101b857806366d003ac1461020d575f80fd5b80630d9019e1146100f2578063307f2962146101425780633bbed4a014610163575f80fd5b366100ee57005b5f80fd5b3480156100fd575f80fd5b5060025473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561014d575f80fd5b5061016161015c366004610d62565b610335565b005b34801561016e575f80fd5b5061016161017d366004610d9f565b6103db565b34801561018d575f80fd5b50610196610462565b604051908152602001610139565b3480156101af575f80fd5b50610118610770565b3480156101c3575f80fd5b506102006040518060400160405280600581526020017f312e312e3100000000000000000000000000000000000000000000000000000081525081565b6040516101399190610dba565b348015610218575f80fd5b506002546101189073ffffffffffffffffffffffffffffffffffffffff1681565b348015610244575f80fd5b5060025461026a9074010000000000000000000000000000000000000000900460ff1681565b6040516101399190610e73565b348015610282575f80fd5b5061019660015481565b348015610297575f80fd5b506101965f5481565b3480156102ab575f80fd5b506101616102ba366004610e87565b610976565b3480156102ca575f80fd5b506101616102d9366004610e9e565b6109bc565b3480156102e9575f80fd5b5060025474010000000000000000000000000000000000000000900460ff1661026a565b348015610318575f80fd5b50600154610196565b34801561032c575f80fd5b50610118610bd8565b61033d610c52565b600280547401000000000000000000000000000000000000000080820460ff1692849290917fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff9091169083600181111561039957610399610e0d565b02179055507ff2ec44eb1c3b3acd547b76333eb2c4b27eee311860c57a9fdb04c95f62398fc881836040516103cf929190610ed9565b60405180910390a15050565b6103e3610c52565b6002805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f62e69886a5df0ba8ffcacbfc1388754e7abd9bde24b036354c561f1acd4e459391016103cf565b5f600154471015610520576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604a60248201527f4665655661756c743a207769746864726177616c20616d6f756e74206d75737460448201527f2062652067726561746572207468616e206d696e696d756d207769746864726160648201527f77616c20616d6f756e7400000000000000000000000000000000000000000000608482015260a4015b60405180910390fd5b479050805f808282546105339190610f21565b90915550506002546040805183815273ffffffffffffffffffffffffffffffffffffffff909216602083018190523383830152905190917fc8a211cc64b6ed1b50595a9fcb1932b6d1e5a6e8ef15b60e5b1f988ea9086bba919081900360600190a16002546040517f38e04cbeb8c10f8f568618aa75be0f10b6729b8b4237743b4de20cbcde2839ee916105e89185918591339174010000000000000000000000000000000000000000900460ff1690610f34565b60405180910390a1600160025474010000000000000000000000000000000000000000900460ff16600181111561062157610621610e0d565b036106c5575f6106318284610caa565b9050806106c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603060248201527f4665655661756c743a206661696c656420746f2073656e642045544820746f2060448201527f4c322066656520726563697069656e74000000000000000000000000000000006064820152608401610517565b505090565b6040517fc2b3e5ac00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015262061a806024820152606060448201525f60648201527342000000000000000000000000000000000000169063c2b3e5ac9084906084015f604051808303818588803b158015610755575f80fd5b505af1158015610767573d5f803e3d5ffd5b50505050505090565b5f8061079a7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905073ffffffffffffffffffffffffffffffffffffffff8116156107bd57919050565b6040518060400160405280601a81526020017f4f564d5f4c3143726f7373446f6d61696e4d657373656e6765720000000000008152505160026108009190610f75565b604080513060208201525f918101919091527f4f564d5f4c3143726f7373446f6d61696e4d657373656e676572000000000000919091179061085a906060015b604051602081830303815290604052805190602001205490565b14610891576040517f54e433cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080513060208201526001918101919091525f906108b290606001610840565b905073ffffffffffffffffffffffffffffffffffffffff811615610944578073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610919573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061093d9190610f8c565b9250505090565b6040517f332144db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61097e610c52565b600180549082905560408051828152602081018490527f895a067c78583e800418fabf3da26a9496aab2ff3429cebdf7fefa642b2e420391016103cf565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f81158015610a065750825b90505f8267ffffffffffffffff166001148015610a225750303b155b905081158015610a30575080155b15610a67576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610ac85784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b610ad0610cbd565b6002805473ffffffffffffffffffffffffffffffffffffffff8a167fffffffffffffffffffffffff000000000000000000000000000000000000000082168117835560018a81558993927fffffffffffffffffffffff000000000000000000000000000000000000000000169091179074010000000000000000000000000000000000000000908490811115610b6857610b68610e0d565b02179055508315610bce5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b5f610be1610770565b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c29573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c4d9190610f8c565b905090565b33610c5b610bd8565b73ffffffffffffffffffffffffffffffffffffffff1614610ca8576040517f7f12c64b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f610cb6835a84610d3e565b9392505050565b33610cc6610770565b73ffffffffffffffffffffffffffffffffffffffff1614158015610d07575033610cee610bd8565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610ca8576040517fc4050a2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f805f858888f1949350505050565b803560028110610d5d575f80fd5b919050565b5f60208284031215610d72575f80fd5b610cb682610d4f565b73ffffffffffffffffffffffffffffffffffffffff81168114610d9c575f80fd5b50565b5f60208284031215610daf575f80fd5b8135610cb681610d7b565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60028110610e6f577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610e818284610e3a565b92915050565b5f60208284031215610e97575f80fd5b5035919050565b5f805f60608486031215610eb0575f80fd5b8335610ebb81610d7b565b925060208401359150610ed060408501610d4f565b90509250925092565b60408101610ee78285610e3a565b610cb66020830184610e3a565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610e8157610e81610ef4565b84815273ffffffffffffffffffffffffffffffffffffffff84811660208301528316604082015260808101610f6c6060830184610e3a565b95945050505050565b8082028115828204841417610e8157610e81610ef4565b5f60208284031215610f9c575f80fd5b8151610cb681610d7b56fea164736f6c6343000819000a00000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 1300000, + "intent": "Deploy OperatorFeeVault Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca40000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000081e608060405234801561001057600080fd5b506107fe806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806354fd4d501461004657806360d7a27814610098578063a2ea7c6e146100b9575b600080fd5b6100826040518060400160405280600c81526020017f312e332e312d626574612e32000000000000000000000000000000000000000081525081565b60405161008f9190610473565b60405180910390f35b6100ab6100a636600461048d565b6100d9565b60405190815260200161008f565b6100cc6100c736600461053f565b61029d565b60405161008f9190610558565b60008060405180608001604052806000801b81526020018573ffffffffffffffffffffffffffffffffffffffff168152602001841515815260200187878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509390945250929350915061015b9050826103c5565b600081815260208190526040902054909150156101a4576040517f23369fa600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80825260008181526020818152604091829020845181559084015160018201805493860151151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00000000000000000000000000000000000000000090941673ffffffffffffffffffffffffffffffffffffffff9092169190911792909217909155606083015183919060028201906102409082610682565b509050503373ffffffffffffffffffffffffffffffffffffffff16817fd0b86852e21f9e5fa4bc3b0cff9757ffe243d50c4b43968a42202153d651ea5e8460405161028b9190610558565b60405180910390a39695505050505050565b604080516080810182526000808252602082018190529181019190915260608082015260008281526020818152604091829020825160808101845281548152600182015473ffffffffffffffffffffffffffffffffffffffff8116938201939093527401000000000000000000000000000000000000000090920460ff1615159282019290925260028201805491929160608401919061033c906105e0565b80601f0160208091040260200160405190810160405280929190818152602001828054610368906105e0565b80156103b55780601f1061038a576101008083540402835291602001916103b5565b820191906000526020600020905b81548152906001019060200180831161039857829003601f168201915b5050505050815250509050919050565b60008160600151826020015183604001516040516020016103e89392919061079c565b604051602081830303815290604052805190602001209050919050565b60005b83811015610420578181015183820152602001610408565b50506000910152565b60008151808452610441816020860160208601610405565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006104866020830184610429565b9392505050565b600080600080606085870312156104a357600080fd5b843567ffffffffffffffff808211156104bb57600080fd5b818701915087601f8301126104cf57600080fd5b8135818111156104de57600080fd5b8860208285010111156104f057600080fd5b6020928301965094505085013573ffffffffffffffffffffffffffffffffffffffff8116811461051f57600080fd5b91506040850135801515811461053457600080fd5b939692955090935050565b60006020828403121561055157600080fd5b5035919050565b602081528151602082015273ffffffffffffffffffffffffffffffffffffffff6020830151166040820152604082015115156060820152600060608301516080808401526105a960a0840182610429565b949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600181811c908216806105f457607f821691505b60208210810361062d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f82111561067d57600081815260208120601f850160051c8101602086101561065a5750805b601f850160051c820191505b8181101561067957828155600101610666565b5050505b505050565b815167ffffffffffffffff81111561069c5761069c6105b1565b6106b0816106aa84546105e0565b84610633565b602080601f83116001811461070357600084156106cd5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555610679565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b8281101561075057888601518255948401946001909101908401610731565b508582101561078c57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b600084516107ae818460208901610405565b60609490941b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169190930190815290151560f81b60148201526015019291505056fea164736f6c6343000813000a0000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 700000, + "intent": "Deploy SchemaRegistry Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca4000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000046c961016060405234801561001157600080fd5b50604080518082018252600381526245415360e81b60208083019182528351808501855260058152640312e332e360dc1b908201529151812060e08190527f6a08c3e203132c561752255a4d52ffae85bb9c5d33cb3291520dea1b843563896101008190524660a081815286517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f818801819052818901959095526060810193909352608080840192909252308382018190528751808503909201825260c093840190975280519501949094209093529290915261012091909152516101405260805160a05160c05160e05161010051610120516101405161457e61014b600039600061073701526000612784015260006127d3015260006127ae01526000612707015260006127310152600061275b015261457e6000f3fe60806040526004361061018b5760003560e01c806395411525116100d6578063d45c44351161007f578063ed24911d11610059578063ed24911d146104fd578063f10b5cc814610512578063f17325e71461054157600080fd5b8063d45c443514610467578063e30bb5631461049e578063e71ff365146104dd57600080fd5b8063b469318d116100b0578063b469318d146103ba578063b83010d314610414578063cf190f341461044757600080fd5b80639541152514610367578063a3112a641461037a578063a6d4dbc7146103a757600080fd5b806344adc90e116101385780634d003070116101125780634d003070146102de57806354fd4d50146102fe57806379f7573a1461034757600080fd5b806344adc90e1461029857806346926267146102b85780634cb7e9e5146102cb57600080fd5b806317d7de7c1161016957806317d7de7c146102205780632d0335ab146102425780633c0427151461028557600080fd5b80630eabf6601461019057806312b11a17146101a557806313893f61146101e7575b600080fd5b6101a361019e3660046134c8565b610554565b005b3480156101b157600080fd5b507ffeb2925a02bae3dae48d424a0437a2b6ac939aa9230ddc55a1a76f065d9880765b6040519081526020015b60405180910390f35b3480156101f357600080fd5b506102076102023660046134c8565b6106eb565b60405167ffffffffffffffff90911681526020016101de565b34801561022c57600080fd5b50610235610730565b6040516101de9190613578565b34801561024e57600080fd5b506101d461025d3660046135bd565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205490565b6101d46102933660046135da565b610760565b6102ab6102a63660046134c8565b610863565b6040516101de9190613615565b6101a36102c6366004613659565b6109e4565b6101a36102d93660046134c8565b610a68565b3480156102ea57600080fd5b506102076102f9366004613671565b610b4b565b34801561030a57600080fd5b506102356040518060400160405280600c81526020017f312e342e312d626574612e33000000000000000000000000000000000000000081525081565b34801561035357600080fd5b506101a3610362366004613671565b610b58565b6102ab6103753660046134c8565b610bef565b34801561038657600080fd5b5061039a610395366004613671565b610e62565b6040516101de9190613771565b6101a36103b5366004613784565b611025565b3480156103c657600080fd5b506102076103d5366004613797565b73ffffffffffffffffffffffffffffffffffffffff919091166000908152603460209081526040808320938352929052205467ffffffffffffffff1690565b34801561042057600080fd5b507fb5d556f07587ec0f08cf386545cc4362c702a001650c2058002615ee5c9d1e756101d4565b34801561045357600080fd5b50610207610462366004613671565b6110ca565b34801561047357600080fd5b50610207610482366004613671565b60009081526033602052604090205467ffffffffffffffff1690565b3480156104aa57600080fd5b506104cd6104b9366004613671565b600090815260326020526040902054151590565b60405190151581526020016101de565b3480156104e957600080fd5b506102076104f83660046134c8565b6110d8565b34801561050957600080fd5b506101d4611110565b34801561051e57600080fd5b5060405173420000000000000000000000000000000000002081526020016101de565b6101d461054f3660046137c3565b61111a565b348160005b818110156106e4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82018114600086868481811061059a5761059a6137fe565b90506020028101906105ac919061382d565b6105b590613ac3565b60208101518051919250908015806105d257508260400151518114155b15610609576040517f947d5a8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156106ad576106a56040518060a001604052808660000151815260200185848151811061063e5761063e6137fe565b6020026020010151815260200186604001518481518110610661576106616137fe565b60200260200101518152602001866060015173ffffffffffffffffffffffffffffffffffffffff168152602001866080015167ffffffffffffffff168152506111d8565b60010161060c565b506106c383600001518385606001518a886113e9565b6106cd9088613bed565b9650505050506106dd8160010190565b9050610559565b5050505050565b60004282825b818110156107245761071c3387878481811061070f5761070f6137fe565b9050602002013585611a18565b6001016106f1565b50909150505b92915050565b606061075b7f0000000000000000000000000000000000000000000000000000000000000000611b17565b905090565b600061077361076e83613d22565b611ca5565b604080516001808252818301909252600091816020015b6040805160c081018252600080825260208083018290529282018190526060808301829052608083015260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90920191018161078a5790505090506107f86020840184613d9d565b61080190613dd1565b81600081518110610814576108146137fe565b602090810291909101015261083d83358261083560c0870160a088016135bd565b346001611e2f565b60200151600081518110610853576108536137fe565b6020026020010151915050919050565b60608160008167ffffffffffffffff8111156108815761088161386b565b6040519080825280602002602001820160405280156108b457816020015b606081526020019060019003908161089f5790505b509050600034815b848110156109ce577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85018114368989848181106108fc576108fc6137fe565b905060200281019061090e9190613ddd565b905061091d6020820182613e11565b9050600003610958576040517f947d5a8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061097d823561096c6020850185613e11565b61097591613e79565b338887611e2f565b805190915061098c9086613bed565b945080602001518785815181106109a5576109a56137fe565b6020026020010181905250806020015151860195505050506109c78160010190565b90506108bc565b506109d98383612541565b979650505050505050565b604080516001808252818301909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816109fb579050509050610a3636839003830160208401613eed565b81600081518110610a4957610a496137fe565b6020908102919091010152610a63823582333460016113e9565b505050565b348160005b818110156106e4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201811436868684818110610aad57610aad6137fe565b9050602002810190610abf9190613ddd565b9050610b2c8135610ad36020840184613f09565b808060200260200160405190810160405280939291908181526020016000905b82821015610b1f57610b1060408302860136819003810190613eed565b81526020019060010190610af3565b50505050503388866113e9565b610b369086613bed565b94505050610b448160010190565b9050610a6d565b60004261072a838261262b565b33600090815260208190526040902054808211610ba1576040517f756688fe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152602081815260409182902084905581518381529081018490527f57b09af877df9068fd60a69d7b21f5576b8b38955812d6ae4ac52942f1e38fb7910160405180910390a15050565b60608160008167ffffffffffffffff811115610c0d57610c0d61386b565b604051908082528060200260200182016040528015610c4057816020015b6060815260200190600190039081610c2b5790505b509050600034815b848110156109ce577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8501811436898984818110610c8857610c886137fe565b9050602002810190610c9a919061382d565b9050366000610cac6020840184613e11565b909250905080801580610ccd5750610cc76040850185613f71565b90508114155b15610d04576040517f947d5a8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610de557610ddd6040518060a0016040528087600001358152602001868685818110610d3957610d396137fe565b9050602002810190610d4b9190613d9d565b610d5490613dd1565b8152602001610d666040890189613f71565b85818110610d7657610d766137fe565b905060600201803603810190610d8c9190613fd8565b8152602001610da16080890160608a016135bd565b73ffffffffffffffffffffffffffffffffffffffff168152602001610dcc60a0890160808a01613ff4565b67ffffffffffffffff169052611ca5565b600101610d07565b506000610e0e8535610df78587613e79565b610e076080890160608a016135bd565b8b8a611e2f565b8051909150610e1d9089613bed565b975080602001518a8881518110610e3657610e366137fe565b602002602001018190525080602001515189019850505050505050610e5b8160010190565b9050610c48565b604080516101408101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e0820183905261010082019290925261012081019190915260008281526032602090815260409182902082516101408101845281548152600182015492810192909252600281015467ffffffffffffffff808216948401949094526801000000000000000081048416606084015270010000000000000000000000000000000090049092166080820152600382015460a0820152600482015473ffffffffffffffffffffffffffffffffffffffff90811660c0830152600583015490811660e083015274010000000000000000000000000000000000000000900460ff16151561010082015260068201805491929161012084019190610f9c9061400f565b80601f0160208091040260200160405190810160405280929190818152602001828054610fc89061400f565b80156110155780601f10610fea57610100808354040283529160200191611015565b820191906000526020600020905b815481529060010190602001808311610ff857829003601f168201915b5050505050815250509050919050565b61103c6110373683900383018361405c565b6111d8565b604080516001808252818301909252600091816020015b604080518082019091526000808252602082015281526020019060019003908161105357905050905061108e36839003830160208401613eed565b816000815181106110a1576110a16137fe565b6020908102919091010152610a638235826110c260e0860160c087016135bd565b3460016113e9565b60004261072a338483611a18565b60004282825b81811015610724576111088686838181106110fb576110fb6137fe565b905060200201358461262b565b6001016110de565b600061075b6126ed565b604080516001808252818301909252600091829190816020015b6040805160c081018252600080825260208083018290529282018190526060808301829052608083015260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816111345790505090506111a26020840184613d9d565b6111ab90613dd1565b816000815181106111be576111be6137fe565b602090810291909101015261083d83358233346001611e2f565b608081015167ffffffffffffffff161580159061120c57504267ffffffffffffffff16816080015167ffffffffffffffff16105b15611243576040517f1ab7da6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808201516040808401516060850151855184518587015173ffffffffffffffffffffffffffffffffffffffff84166000908152978890529487208054969794969495611337957fb5d556f07587ec0f08cf386545cc4362c702a001650c2058002615ee5c9d1e7595949392886112ba836140ca565b909155506080808c015160408051602081019990995273ffffffffffffffffffffffffffffffffffffffff9097169688019690965260608701949094529285019190915260a084015260c083015267ffffffffffffffff1660e0820152610100015b60405160208183030381529060405280519060200120612821565b90506113ad84606001518284602001518560400151866000015160405160200161139993929190928352602083019190915260f81b7fff0000000000000000000000000000000000000000000000000000000000000016604082015260410190565b604051602081830303815290604052612834565b6113e3576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6040517fa2ea7c6e0000000000000000000000000000000000000000000000000000000081526004810186905260009081907342000000000000000000000000000000000000209063a2ea7c6e90602401600060405180830381865afa158015611457573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261149d9190810190614102565b80519091506114d8576040517fbf37b20e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855160008167ffffffffffffffff8111156114f5576114f561386b565b60405190808252806020026020018201604052801561159457816020015b60408051610140810182526000808252602080830182905292820181905260608083018290526080830182905260a0830182905260c0830182905260e0830182905261010083019190915261012082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816115135790505b50905060008267ffffffffffffffff8111156115b2576115b261386b565b6040519080825280602002602001820160405280156115db578160200160208202803683370190505b50905060005b838110156119fa5760008a82815181106115fd576115fd6137fe565b6020908102919091018101518051600090815260329092526040909120805491925090611656576040517fc5723b5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8c816001015414611693576040517fbf37b20e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600581015473ffffffffffffffffffffffffffffffffffffffff8c81169116146116e9576040517f4ca8886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600581015474010000000000000000000000000000000000000000900460ff1661173f576040517f157bd4c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002810154700100000000000000000000000000000000900467ffffffffffffffff1615611799576040517f905e710700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b426002820180547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff811670010000000000000000000000000000000067ffffffffffffffff948516810291821793849055604080516101408101825287548152600188015460208201529386169286169290921791830191909152680100000000000000008304841660608301529091049091166080820152600382015460a0820152600482015473ffffffffffffffffffffffffffffffffffffffff90811660c0830152600583015490811660e083015274010000000000000000000000000000000000000000900460ff16151561010082015260068201805483916101208401916118a59061400f565b80601f01602080910402602001604051908101604052809291908181526020018280546118d19061400f565b801561191e5780601f106118f35761010080835404028352916020019161191e565b820191906000526020600020905b81548152906001019060200180831161190157829003601f168201915b505050505081525050858481518110611939576119396137fe565b6020026020010181905250816020015184848151811061195b5761195b6137fe565b6020026020010181815250508c8b73ffffffffffffffffffffffffffffffffffffffff16868581518110611991576119916137fe565b602002602001015160c0015173ffffffffffffffffffffffffffffffffffffffff167ff930a6e2523c9cc298691873087a740550b8fc85a0680830414c148ed927f61585600001516040516119e891815260200190565b60405180910390a450506001016115e1565b50611a0a84838360018b8b612a03565b9a9950505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff83166000908152603460209081526040808320858452918290529091205467ffffffffffffffff1615611a8c576040517fec9d6eeb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008381526020829052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff861690811790915590519091859173ffffffffffffffffffffffffffffffffffffffff8816917f92a1f7a41a7c585a8b09e25b195e225b1d43248daca46b0faf9e0792777a222991a450505050565b604080516020808252818301909252606091600091906020820181803683370190505090506000805b6020811015611be2576000858260208110611b5d57611b5d6137fe565b1a60f81b90507fff000000000000000000000000000000000000000000000000000000000000008116600003611b935750611be2565b80848481518110611ba657611ba66137fe565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053505060019182019101611b40565b5060008167ffffffffffffffff811115611bfe57611bfe61386b565b6040519080825280601f01601f191660200182016040528015611c28576020820181803683370190505b50905060005b82811015611c9c57838181518110611c4857611c486137fe565b602001015160f81c60f81b828281518110611c6557611c656137fe565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600101611c2e565b50949350505050565b608081015167ffffffffffffffff1615801590611cd957504267ffffffffffffffff16816080015167ffffffffffffffff16105b15611d10576040517f1ab7da6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808201516040808401516060808601518651855186880151868801519488015160808901518051908b012060a08a015173ffffffffffffffffffffffffffffffffffffffff871660009081529b8c9052988b2080549a9b989a9899611337997ffeb2925a02bae3dae48d424a0437a2b6ac939aa9230ddc55a1a76f065d988076999493928c611da0836140ca565b919050558e6080015160405160200161131c9b9a999897969594939291909a8b5273ffffffffffffffffffffffffffffffffffffffff998a1660208c015260408b019890985295909716606089015267ffffffffffffffff938416608089015291151560a088015260c087015260e0860152610100850193909352610120840152166101408201526101600190565b60408051808201909152600081526060602082015284516040805180820190915260008152606060208201528167ffffffffffffffff811115611e7457611e7461386b565b604051908082528060200260200182016040528015611e9d578160200160208202803683370190505b5060208201526040517fa2ea7c6e000000000000000000000000000000000000000000000000000000008152600481018990526000907342000000000000000000000000000000000000209063a2ea7c6e90602401600060405180830381865afa158015611f0f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611f559190810190614102565b8051909150611f90576040517fbf37b20e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008367ffffffffffffffff811115611fab57611fab61386b565b60405190808252806020026020018201604052801561204a57816020015b60408051610140810182526000808252602080830182905292820181905260608083018290526080830182905260a0830182905260c0830182905260e0830182905261010083019190915261012082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181611fc95790505b50905060008467ffffffffffffffff8111156120685761206861386b565b604051908082528060200260200182016040528015612091578160200160208202803683370190505b50905060005b858110156125205760008b82815181106120b3576120b36137fe565b60200260200101519050600067ffffffffffffffff16816020015167ffffffffffffffff16141580156120fe57504267ffffffffffffffff16816020015167ffffffffffffffff1611155b15612135576040517f08e8b93700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8460400151158015612148575080604001515b1561217f576040517f157bd4c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518061014001604052806000801b81526020018f81526020016121a34290565b67ffffffffffffffff168152602001836020015167ffffffffffffffff168152602001600067ffffffffffffffff16815260200183606001518152602001836000015173ffffffffffffffffffffffffffffffffffffffff1681526020018d73ffffffffffffffffffffffffffffffffffffffff16815260200183604001511515815260200183608001518152509050600080600090505b6122458382612df4565b600081815260326020526040902054909250156122645760010161223b565b81835260008281526032602090815260409182902085518155908501516001820155908401516002820180546060870151608088015167ffffffffffffffff908116700100000000000000000000000000000000027fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff92821668010000000000000000027fffffffffffffffffffffffffffffffff000000000000000000000000000000009094169190951617919091171691909117905560a0840151600382015560c084015160048201805473ffffffffffffffffffffffffffffffffffffffff9283167fffffffffffffffffffffffff000000000000000000000000000000000000000090911617905560e0850151600583018054610100880151151574010000000000000000000000000000000000000000027fffffffffffffffffffffff000000000000000000000000000000000000000000909116929093169190911791909117905561012084015184919060068201906123e49082614228565b50505060608401511561243b57606084015160009081526032602052604090205461243b576040517fc5723b5100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8287868151811061244e5761244e6137fe565b60200260200101819052508360a00151868681518110612470576124706137fe565b6020026020010181815250508189602001518681518110612493576124936137fe565b6020026020010181815250508f8e73ffffffffffffffffffffffffffffffffffffffff16856000015173ffffffffffffffffffffffffffffffffffffffff167f8bf46bf4cfd674fa735a3d63ec1c9ad4153f033c290341f3a588b75685141b358560405161250391815260200190565b60405180910390a4505050506125198160010190565b9050612097565b5061253083838360008c8c612a03565b845250919998505050505050505050565b606060008267ffffffffffffffff81111561255e5761255e61386b565b604051908082528060200260200182016040528015612587578160200160208202803683370190505b508451909150600090815b818110156126205760008782815181106125ae576125ae6137fe565b6020026020010151905060008151905060005b8181101561260c578281815181106125db576125db6137fe565b60200260200101518787815181106125f5576125f56137fe565b6020908102919091010152600195860195016125c1565b5050506126198160010190565b9050612592565b509195945050505050565b60008281526033602052604090205467ffffffffffffffff161561267b576040517f2e26794600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526033602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff85169081179091559051909184917f5aafceeb1c7ad58e4a84898bdee37c02c0fc46e7d24e6b60e8209449f183459f9190a35050565b60003073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614801561275357507f000000000000000000000000000000000000000000000000000000000000000046145b1561277d57507f000000000000000000000000000000000000000000000000000000000000000090565b50604080517f00000000000000000000000000000000000000000000000000000000000000006020808301919091527f0000000000000000000000000000000000000000000000000000000000000000828401527f000000000000000000000000000000000000000000000000000000000000000060608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b600061072a61282e6126ed565b83612e53565b60008060006128438585612e95565b9092509050600081600481111561285c5761285c614342565b14801561289457508573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b156128a4576001925050506129fc565b6000808773ffffffffffffffffffffffffffffffffffffffff16631626ba7e60e01b88886040516024016128d9929190614371565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516129629190614392565b600060405180830381855afa9150503d806000811461299d576040519150601f19603f3d011682016040523d82523d6000602084013e6129a2565b606091505b50915091508180156129b5575080516020145b80156129f5575080517f1626ba7e00000000000000000000000000000000000000000000000000000000906129f390830160209081019084016143a4565b145b9450505050505b9392505050565b84516000906001819003612a5b57612a538888600081518110612a2857612a286137fe565b602002602001015188600081518110612a4357612a436137fe565b6020026020010151888888612eda565b915050612dea565b602088015173ffffffffffffffffffffffffffffffffffffffff8116612afc5760005b82811015612ae157878181518110612a9857612a986137fe565b6020026020010151600014612ad9576040517f1574f9f300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600101612a7e565b508315612af157612af1856131f9565b600092505050612dea565b6000808273ffffffffffffffffffffffffffffffffffffffff1663ce46e0466040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6e91906143bd565b905060005b84811015612c2b5760008a8281518110612b8f57612b8f6137fe565b6020026020010151905080600003612ba75750612c23565b82612bde576040517f1574f9f300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b88811115612c18576040517f1101129400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b978890039792909201915b600101612b73565b508715612d06576040517f88e5b2d900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416906388e5b2d9908490612c88908e908e906004016143da565b60206040518083038185885af1158015612ca6573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612ccb91906143bd565b612d01576040517fbf2f3a8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612dd5565b6040517f91db0b7e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416906391db0b7e908490612d5c908e908e906004016143da565b60206040518083038185885af1158015612d7a573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190612d9f91906143bd565b612dd5576040517fe8bee83900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8515612de457612de4876131f9565b50925050505b9695505050505050565b60208083015160c084015160e0850151604080870151606088015161010089015160a08a01516101208b01519451600099612e3599989796918c9101614493565b60405160208183030381529060405280519060200120905092915050565b6040517f190100000000000000000000000000000000000000000000000000000000000060208201526022810183905260428101829052600090606201612e35565b6000808251604103612ecb5760208301516040840151606085015160001a612ebf8782858561320c565b94509450505050612ed3565b506000905060025b9250929050565b602086015160009073ffffffffffffffffffffffffffffffffffffffff8116612f4e578515612f35576040517f1574f9f300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8215612f4457612f44846131f9565b6000915050612dea565b8515613039578073ffffffffffffffffffffffffffffffffffffffff1663ce46e0466040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fc391906143bd565b612ff9576040517f1574f9f300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83861115613033576040517f1101129400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85840393505b8415613111576040517fe49617e100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82169063e49617e1908890613093908b90600401613771565b60206040518083038185885af11580156130b1573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906130d691906143bd565b61310c576040517fccf3bb2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6131de565b6040517fe60c350500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82169063e60c3505908890613165908b90600401613771565b60206040518083038185885af1158015613183573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906131a891906143bd565b6131de576040517fbd8ba84d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82156131ed576131ed846131f9565b50939695505050505050565b8015613209576132093382613324565b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613243575060009050600361331b565b8460ff16601b1415801561325b57508460ff16601c14155b1561326c575060009050600461331b565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156132c0573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81166133145760006001925092505061331b565b9150600090505b94509492505050565b80471015613393576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064015b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146133ed576040519150601f19603f3d011682016040523d82523d6000602084013e6133f2565b606091505b5050905080610a63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161338a565b60008083601f84011261349557600080fd5b50813567ffffffffffffffff8111156134ad57600080fd5b6020830191508360208260051b8501011115612ed357600080fd5b600080602083850312156134db57600080fd5b823567ffffffffffffffff8111156134f257600080fd5b6134fe85828601613483565b90969095509350505050565b60005b8381101561352557818101518382015260200161350d565b50506000910152565b6000815180845261354681602086016020860161350a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006129fc602083018461352e565b73ffffffffffffffffffffffffffffffffffffffff8116811461320957600080fd5b80356135b88161358b565b919050565b6000602082840312156135cf57600080fd5b81356129fc8161358b565b6000602082840312156135ec57600080fd5b813567ffffffffffffffff81111561360357600080fd5b820160e081850312156129fc57600080fd5b6020808252825182820181905260009190848201906040850190845b8181101561364d57835183529284019291840191600101613631565b50909695505050505050565b60006060828403121561366b57600080fd5b50919050565b60006020828403121561368357600080fd5b5035919050565b6000610140825184526020830151602085015260408301516136b8604086018267ffffffffffffffff169052565b5060608301516136d4606086018267ffffffffffffffff169052565b5060808301516136f0608086018267ffffffffffffffff169052565b5060a083015160a085015260c083015161372260c086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060e083015161374a60e086018273ffffffffffffffffffffffffffffffffffffffff169052565b506101008381015115159085015261012080840151818601839052612dea8387018261352e565b6020815260006129fc602083018461368a565b6000610100828403121561366b57600080fd5b600080604083850312156137aa57600080fd5b82356137b58161358b565b946020939093013593505050565b6000602082840312156137d557600080fd5b813567ffffffffffffffff8111156137ec57600080fd5b8201604081850312156129fc57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6183360301811261386157600080fd5b9190910192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156138bd576138bd61386b565b60405290565b60405160c0810167ffffffffffffffff811182821017156138bd576138bd61386b565b6040516080810167ffffffffffffffff811182821017156138bd576138bd61386b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156139505761395061386b565b604052919050565b600067ffffffffffffffff8211156139725761397261386b565b5060051b60200190565b60006040828403121561398e57600080fd5b6040516040810181811067ffffffffffffffff821117156139b1576139b161386b565b604052823581526020928301359281019290925250919050565b6000606082840312156139dd57600080fd5b6040516060810181811067ffffffffffffffff82111715613a0057613a0061386b565b604052905080823560ff81168114613a1757600080fd5b8082525060208301356020820152604083013560408201525092915050565b600082601f830112613a4757600080fd5b81356020613a5c613a5783613958565b613909565b82815260609283028501820192828201919087851115613a7b57600080fd5b8387015b85811015613a9e57613a9189826139cb565b8452928401928101613a7f565b5090979650505050505050565b803567ffffffffffffffff811681146135b857600080fd5b600060a08236031215613ad557600080fd5b613add61389a565b8235815260208084013567ffffffffffffffff80821115613afd57600080fd5b9085019036601f830112613b1057600080fd5b8135613b1e613a5782613958565b81815260069190911b83018401908481019036831115613b3d57600080fd5b938501935b82851015613b6657613b54368661397c565b82528582019150604085019450613b42565b80868801525050506040860135925080831115613b8257600080fd5b5050613b9036828601613a36565b604083015250613ba2606084016135ad565b6060820152613bb360808401613aab565b608082015292915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561072a5761072a613bbe565b801515811461320957600080fd5b600067ffffffffffffffff821115613c2857613c2861386b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600060c08284031215613c6657600080fd5b613c6e6138c3565b90508135613c7b8161358b565b81526020613c8a838201613aab565b818301526040830135613c9c81613c00565b604083015260608381013590830152608083013567ffffffffffffffff811115613cc557600080fd5b8301601f81018513613cd657600080fd5b8035613ce4613a5782613c0e565b8181528684838501011115613cf857600080fd5b818484018583013760008483830101528060808601525050505060a082013560a082015292915050565b600060e08236031215613d3457600080fd5b613d3c61389a565b82358152602083013567ffffffffffffffff811115613d5a57600080fd5b613d6636828601613c54565b602083015250613d7936604085016139cb565b604082015260a0830135613d8c8161358b565b6060820152613bb360c08401613aab565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4183360301811261386157600080fd5b600061072a3683613c54565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261386157600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613e4657600080fd5b83018035915067ffffffffffffffff821115613e6157600080fd5b6020019150600581901b3603821315612ed357600080fd5b6000613e87613a5784613958565b80848252602080830192508560051b850136811115613ea557600080fd5b855b81811015613ee157803567ffffffffffffffff811115613ec75760008081fd5b613ed336828a01613c54565b865250938201938201613ea7565b50919695505050505050565b600060408284031215613eff57600080fd5b6129fc838361397c565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613f3e57600080fd5b83018035915067ffffffffffffffff821115613f5957600080fd5b6020019150600681901b3603821315612ed357600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613fa657600080fd5b83018035915067ffffffffffffffff821115613fc157600080fd5b6020019150606081023603821315612ed357600080fd5b600060608284031215613fea57600080fd5b6129fc83836139cb565b60006020828403121561400657600080fd5b6129fc82613aab565b600181811c9082168061402357607f821691505b60208210810361366b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000610100828403121561406f57600080fd5b61407761389a565b82358152614088846020850161397c565b602082015261409a84606085016139cb565b604082015260c08301356140ad8161358b565b60608201526140be60e08401613aab565b60808201529392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036140fb576140fb613bbe565b5060010190565b6000602080838503121561411557600080fd5b825167ffffffffffffffff8082111561412d57600080fd5b908401906080828703121561414157600080fd5b6141496138e6565b825181528383015161415a8161358b565b81850152604083015161416c81613c00565b604082015260608301518281111561418357600080fd5b80840193505086601f84011261419857600080fd5b825191506141a8613a5783613c0e565b82815287858486010111156141bc57600080fd5b6141cb8386830187870161350a565b60608201529695505050505050565b601f821115610a6357600081815260208120601f850160051c810160208610156142015750805b601f850160051c820191505b818110156142205782815560010161420d565b505050505050565b815167ffffffffffffffff8111156142425761424261386b565b61425681614250845461400f565b846141da565b602080601f8311600181146142a957600084156142735750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555614220565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156142f6578886015182559484019460019091019084016142d7565b508582101561433257878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b82815260406020820152600061438a604083018461352e565b949350505050565b6000825161386181846020870161350a565b6000602082840312156143b657600080fd5b5051919050565b6000602082840312156143cf57600080fd5b81516129fc81613c00565b6000604082016040835280855180835260608501915060608160051b8601019250602080880160005b8381101561444f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa088870301855261443d86835161368a565b95509382019390820190600101614403565b50508584038187015286518085528782019482019350915060005b828110156144865784518452938101939281019260010161446a565b5091979650505050505050565b89815260007fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808b60601b166020840152808a60601b166034840152507fffffffffffffffff000000000000000000000000000000000000000000000000808960c01b166048840152808860c01b1660508401525085151560f81b6058830152846059830152835161452c81607985016020880161350a565b80830190507fffffffff000000000000000000000000000000000000000000000000000000008460e01b166079820152607d81019150509a995050505050505050505056fea164736f6c6343000813000a0000000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 5800000, + "intent": "Deploy EAS Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca4000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000017586080604052348015600e575f80fd5b5060156019565b60d4565b5f54610100900460ff161560835760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116101560d2575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b611677806100e15f395ff3fe6080604052600436106100bb575f3560e01c80637dfbd04911610071578063c4d66de81161004c578063c4d66de8146102f6578063d61a398b14610315578063dad544e014610346575f80fd5b80637dfbd049146102ac5780637fc81bb7146102c3578063b87ea8d4146102e2575f80fd5b8063394d2731116100a1578063394d2731146101f65780633e47158c1461021e57806354fd4d5014610257575f80fd5b80630a7617b3146101735780630c0544a314610194575f80fd5b3661016f573373ffffffffffffffffffffffffffffffffffffffff7f21346dddac42cc163a6523eefc19df981df7352c870dc3b0b17a6a92fc6fe8135c1614610130576040517f14885cf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805134815247602082018190529133917f213e72af0d3613bd643cff3059f872c1015e6541624e37872bf95eefbaf220a8910160405180910390a2005b5f80fd5b34801561017e575f80fd5b5061019261018d3660046112a1565b61035a565b005b34801561019f575f80fd5b506001546101d09070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1681565b6040516fffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b348015610201575f80fd5b506001546101d0906fffffffffffffffffffffffffffffffff1681565b348015610229575f80fd5b5061023261051c565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101ed565b348015610262575f80fd5b5061029f6040518060400160405280600581526020017f312e302e3100000000000000000000000000000000000000000000000000000081525081565b6040516101ed91906112bc565b3480156102b7575f80fd5b506101d06301e1338081565b3480156102ce575f80fd5b506101926102dd36600461130f565b610722565b3480156102ed575f80fd5b50610192610915565b348015610301575f80fd5b506101926103103660046112a1565b610ced565b348015610320575f80fd5b505f546102329062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b348015610351575f80fd5b50610232610ee9565b73420000000000000000000000000000000000001873ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103b7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103db919061133e565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461043f576040517f38bac74200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811661048c576040517f99c6ec0800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805473ffffffffffffffffffffffffffffffffffffffff838116620100008181027fffffffffffffffffffff0000000000000000000000000000000000000000ffff85161790945560408051949093049091168084526020840191909152917f16417cc372deec0caee5f52e2ad77a5f07b4591fd56b4ff31b6e20f817d4daeb91015b60405180910390a15050565b5f806105467fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905073ffffffffffffffffffffffffffffffffffffffff81161561056957919050565b6040518060400160405280601a81526020017f4f564d5f4c3143726f7373446f6d61696e4d657373656e6765720000000000008152505160026105ac9190611386565b604080513060208201525f918101919091527f4f564d5f4c3143726f7373446f6d61696e4d657373656e6765720000000000009190911790610606906060015b604051602081830303815290604052805190602001205490565b1461063d576040517f54e433cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080513060208201526001918101919091525f9061065e906060016105ec565b905073ffffffffffffffffffffffffffffffffffffffff8116156106f0578073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106c5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106e9919061133e565b9250505090565b6040517f332144db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73420000000000000000000000000000000000001873ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561077f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107a3919061133e565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610807576040517f38bac74200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806fffffffffffffffffffffffffffffffff165f03610852576040517fcf85916100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6301e133806fffffffffffffffffffffffffffffffff821611156108a2576040517f30b9f35e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180546fffffffffffffffffffffffffffffffff8381167001000000000000000000000000000000008181028385161790945560408051949093049091168084526020840191909152917f4492086b630ed3846eec0979dd87a71c814ceb1c6dab80ab81e3450b21e4de289101610510565b60015461094a906fffffffffffffffffffffffffffffffff7001000000000000000000000000000000008204811691166113a3565b6fffffffffffffffffffffffffffffffff16421015610995576040517f1e4a9f3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016426fffffffffffffffffffffffffffffffff161790555f6109ef734200000000000000000000000000000000000011610f63565b90505f610a0f734200000000000000000000000000000000000019610f63565b90505f610a2f73420000000000000000000000000000000000001a610f63565b90505f610a4f73420000000000000000000000000000000000001b610f63565b9050610a5a5f6111b0565b5f8282610a6786886113d3565b610a7191906113d3565b610a7b91906113d3565b9050805f03610ab6576040517fc8972e5200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80546040517f54e7f42d000000000000000000000000000000000000000000000000000000008152600481018890526024810187905260448101859052606481018690526201000090910473ffffffffffffffffffffffffffffffffffffffff16906354e7f42d906084015f60405180830381865afa158015610b3c573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610b81919081019061148b565b80519091505f819003610bc0576040517f763970d600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805b82811015610c70575f848281518110610bde57610bde61155a565b6020026020010151602001519050805f03610bf95750610c68565b5f610c20868481518110610c0f57610c0f61155a565b60200260200101515f0151836111d6565b905080610c59576040517fd68d1b1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c6382856113d3565b935050505b600101610bc3565b50838114610caa576040517f9c01eac000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f73f9a13241a1848ec157967f3a85601709353e616f1f2605d818c0f2d21774df8385604051610cdb929190611587565b60405180910390a15050505050505050565b5f54610100900460ff1615808015610d0b57505f54600160ff909116105b80610d245750303b158015610d2457505f5460ff166001145b610db4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610e10575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610e186111e9565b5f80547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff85160217905572015180000000000000000000000000000000006fffffffffffffffffffffffffffffffff4216176001558015610ee5575f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602001610510565b5050565b5f610ef261051c565b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f3a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f5e919061133e565b905090565b5f60018273ffffffffffffffffffffffffffffffffffffffff166382356d8a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610faf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fd39190611622565b6001811115610fe457610fe46115f5565b1461101b576040517fb4726cbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff166366d003ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561107b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061109f919061133e565b73ffffffffffffffffffffffffffffffffffffffff16146110ec576040517fc3380cef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b476110f6836111b0565b8273ffffffffffffffffffffffffffffffffffffffff16633ccfd60b6040518163ffffffff1660e01b81526004016020604051808303815f875af1158015611140573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111649190611640565b915047826111728383611657565b146111a9576040517f87c91c5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050919050565b807f21346dddac42cc163a6523eefc19df981df7352c870dc3b0b17a6a92fc6fe8135d50565b5f6111e2835a8461126c565b9392505050565b336111f261051c565b73ffffffffffffffffffffffffffffffffffffffff161415801561123357503361121a610ee9565b73ffffffffffffffffffffffffffffffffffffffff1614155b1561126a576040517fc4050a2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f805f805f858888f1949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461129e575f80fd5b50565b5f602082840312156112b1575f80fd5b81356111e28161127d565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f6020828403121561131f575f80fd5b81356fffffffffffffffffffffffffffffffff811681146111e2575f80fd5b5f6020828403121561134e575f80fd5b81516111e28161127d565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808202811582820484141761139d5761139d611359565b92915050565b6fffffffffffffffffffffffffffffffff8181168382160190808211156113cc576113cc611359565b5092915050565b8082018082111561139d5761139d611359565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040805190810167ffffffffffffffff81118282101715611436576114366113e6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611483576114836113e6565b604052919050565b5f602080838503121561149c575f80fd5b825167ffffffffffffffff808211156114b3575f80fd5b818501915085601f8301126114c6575f80fd5b8151818111156114d8576114d86113e6565b6114e6848260051b0161143c565b818152848101925060069190911b830184019087821115611505575f80fd5b928401925b8184101561154f5760408489031215611521575f80fd5b611529611413565b84516115348161127d565b8152848601518682015283526040909301929184019161150a565b979650505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b604080825283518282018190525f91906020906060850190828801855b828110156115df578151805173ffffffffffffffffffffffffffffffffffffffff1685528501518585015292850192908401906001016115a4565b5050508093505050508260208301529392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f60208284031215611632575f80fd5b8151600281106111e2575f80fd5b5f60208284031215611650575f80fd5b5051919050565b8181038181111561139d5761139d61135956fea164736f6c6343000819000a0000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 1700000, + "intent": "Deploy FeeSplitter Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca4000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000005d8608060405234801561001057600080fd5b506105b8806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806354fd4d5014610046578063cdcb760a14610098578063e0145f5c146100d0575b600080fd5b6100826040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b60405161008f91906103f7565b60405180910390f35b6100ab6100a6366004610440565b6100ea565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161008f565b734e59b44847b379578588920ca78fbf26c0b4956c6100ab565b8051602080830191909120604080517fff00000000000000000000000000000000000000000000000000000000000000818501527f4e59b44847b379578588920ca78fbf26c0b4956c000000000000000000000000602182015260358101869052605580820184905282518083039091018152607590910190915280519201919091206000919073ffffffffffffffffffffffffffffffffffffffff81163b156101d85760405173ffffffffffffffffffffffffffffffffffffffff8216907ffbe57d889a7f75a4e0c7da304cd158fcaddc4b925cdd9f4cfb115c0f9e48009b90600090a291506103779050565b600080734e59b44847b379578588920ca78fbf26c0b4956c73ffffffffffffffffffffffffffffffffffffffff168787604051602001610219929190610519565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526102519161053f565b6000604051808303816000865af19150503d806000811461028e576040519150601f19603f3d011682016040523d82523d6000602084013e610293565b606091505b5091509150806102a29061055b565b60601c94508115806102e057508273ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614155b1561032257806040517fcb0fc6f700000000000000000000000000000000000000000000000000000000815260040161031991906103f7565b60405180910390fd5b8473ffffffffffffffffffffffffffffffffffffffff167f9b7318127ed899f286ea9ddd7925ed8ad24a682b6a825c3b5b3d88a3f00bc1d28860405161036a91815260200190565b60405180910390a2505050505b92915050565b60005b83811015610398578181015183820152602001610380565b838111156103a7576000848401525b50505050565b600081518084526103c581602086016020860161037d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061040a60208301846103ad565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806040838503121561045357600080fd5b82359150602083013567ffffffffffffffff8082111561047257600080fd5b818501915085601f83011261048657600080fd5b81358181111561049857610498610411565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104de576104de610411565b816040528281528860208487010111156104f757600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b8281526000825161053181602085016020870161037d565b919091016020019392505050565b6000825161055181846020870161037d565b9190910192915050565b6000815160208301517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000808216935060148310156105a35780818460140360031b1b83161693505b50505091905056fea164736f6c634300080f000a0000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 600000, + "intent": "Deploy ConditionalDeployer Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000283608060405234801561001057600080fd5b50610263806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80631bec9d65146100515780631d8a4e921461006657806354fd4d501461009b57806378ecabce146100e4575b600080fd5b61006461005f3660046101ca565b610107565b005b7fc8bc8f9195cfb2d040744aac63412d02ffc186ea9bd519039edc4666ee9032bc546040519081526020015b60405180910390f35b6100d76040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b60405161009291906101e3565b6100f76100f23660046101ca565b610178565b6040519015158152602001610092565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610154576040517fee37fa8500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fc8bc8f9195cfb2d040744aac63412d02ffc186ea9bd519039edc4666ee9032bc55565b60006101ab6101a57fc8bc8f9195cfb2d040744aac63412d02ffc186ea9bd519039edc4666ee9032bc5490565b836101b1565b92915050565b600081158015906101c3575081828416145b9392505050565b6000602082840312156101dc57600080fd5b5035919050565b600060208083528351808285015260005b81811015610210578581018301518582016040015282016101f4565b81811115610222576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a0000000000000000000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 300000, + "intent": "Deploy L2DevFeatureFlags Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca40000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000069e6080604052348015600e575f80fd5b506106828061001c5f395ff3fe608060405234801561000f575f80fd5b506004361061003f575f3560e01c8063331b637f1461004357806354fd4d5014610069578063ab4d6f75146100b2575b5f80fd5b610056610051366004610512565b6100c7565b6040519081526020015b60405180910390f35b6100a56040518060400160405280600581526020017f312e302e3200000000000000000000000000000000000000000000000000000081525081565b604051610060919061053b565b6100c56100c036600461058e565b61039e565b005b5f67ffffffffffffffff801683602001511115610110576040517fd1f79e8200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604083015163ffffffff1015610152576040517f94338eba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606083015167ffffffffffffffff1015610198576040517f596a19a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516040515f916101dd91859060200160609290921b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000168252601482015260340190565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181528282528051602091820120878201516060890151898501515f9487018590527fffffffffffffffff00000000000000000000000000000000000000000000000060c084811b8216602c8a015283901b1660348801527fffffffff0000000000000000000000000000000000000000000000000000000060e082901b16603c88015292965090949093919291016040516020818303038152906040526102ac906105bc565b90505f85826040516020016102cb929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012060808d01519184018190529183015291505f90606001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0300000000000000000000000000000000000000000000000000000000000000179a9950505050505050505050565b5f6103b76103b136859003850185610601565b836100c7565b90505f6103c38261043b565b509050806103fd576040517fe3c0081600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b827f5c37832d2e8d10e346e55ad62071a6a2f9fa5130614ef2ec6617555c6f467ba78560405161042d9190610622565b60405180910390a250505050565b5f805a835491505a6103e891031115939092509050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610475575f80fd5b919050565b5f60a0828403121561048a575f80fd5b60405160a0810181811067ffffffffffffffff821117156104d2577f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040529050806104e183610452565b8152602083013560208201526040830135604082015260608301356060820152608083013560808201525092915050565b5f8060c08385031215610523575f80fd5b61052d848461047a565b9460a0939093013593505050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f8082840360c08112156105a0575f80fd5b60a08112156105ad575f80fd5b50919360a08501359350915050565b805160208083015191908110156105fb577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8160200360031b1b821691505b50919050565b5f60a08284031215610611575f80fd5b61061b838361047a565b9392505050565b60a0810173ffffffffffffffffffffffffffffffffffffffff61064484610452565b168252602083013560208301526040830135604083015260608301356060830152608083013560808301529291505056fea164736f6c6343000819000a0000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 600000, + "intent": "Deploy CrossL2Inbox Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca4000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000011836080604052348015600e575f80fd5b506111678061001c5f395ff3fe6080604052600436106100b8575f3560e01c80637056f41f11610071578063b1b1b2091161004c578063b1b1b20914610228578063bc294d7d14610266578063ecc7042814610291575f80fd5b80637056f41f146101b65780637936cbee146101d55780638d1d298f14610215575f80fd5b806352617f3c116100a157806352617f3c1461011c57806354fd4d50146101425780636b0c3c5e14610197575f80fd5b806324794462146100bc57806338ffde18146100e3575b5f80fd5b3480156100c7575f80fd5b506100d06102c5565b6040519081526020015b60405180910390f35b3480156100ee575f80fd5b506100f7610344565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100da565b348015610127575f80fd5b5061012f5f81565b60405161ffff90911681526020016100da565b34801561014d575f80fd5b5061018a6040518060400160405280600581526020017f312e332e3000000000000000000000000000000000000000000000000000000081525081565b6040516100da9190610c7e565b3480156101a2575f80fd5b506100d06101b1366004610d00565b6103c3565b3480156101c1575f80fd5b506100d06101d0366004610d77565b6104ae565b3480156101e0575f80fd5b506101e96106ba565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526020830191909152016100da565b61018a610223366004610dcf565b61075e565b348015610233575f80fd5b50610256610242366004610e25565b5f6020819052908152604090205460ff1681565b60405190151581526020016100da565b348015610271575f80fd5b506100d0610280366004610e25565b60026020525f908152604090205481565b34801561029c575f80fd5b506001547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166100d0565b5f7ff13569814868ede994184d5a425471fb19e869768a33421cb701a2ba3d420c0a5c61031e576040517fbca35af600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f711dfa3259c842fffc17d6e1f1e0fc5927756133a2345ca56b4cb8178589fee75c90565b5f7ff13569814868ede994184d5a425471fb19e869768a33421cb701a2ba3d420c0a5c61039d576040517fbca35af600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507fb83444d07072b122e2e72a669ce32857d892345c19856f4e7142d06a167ab3f35c90565b5f610407874688888888888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610ae192505050565b5f878152600260205260409020549091508114610450576040517f6eca2e4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b858473ffffffffffffffffffffffffffffffffffffffff16887f382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f32088878760405161049c93929190610e3c565b60405180910390a49695505050505050565b5f4685036104e8576040517f8ed9a95d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffbdffffffffffffffffffffffffffffffffffffdd73ffffffffffffffffffffffffffffffffffffffff851601610557576040517f4faa250900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6105816001547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b90506105c6864683338989898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610ae192505050565b5f828152600260205260408120829055600180549294507dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909216919061060a83610ea5565b91906101000a8154817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16021790555050808573ffffffffffffffffffffffffffffffffffffffff16877f382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f3203388886040516106a993929190610e3c565b60405180910390a450949350505050565b5f807ff13569814868ede994184d5a425471fb19e869768a33421cb701a2ba3d420c0a5c610714576040517fbca35af600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50507fb83444d07072b122e2e72a669ce32857d892345c19856f4e7142d06a167ab3f35c907f711dfa3259c842fffc17d6e1f1e0fc5927756133a2345ca56b4cb8178589fee75c90565b60607ff13569814868ede994184d5a425471fb19e869768a33421cb701a2ba3d420c0a5c156107b9576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60017ff13569814868ede994184d5a425471fb19e869768a33421cb701a2ba3d420c0a5d7342000000000000000000000000000000000000236107ff6020860186610f06565b73ffffffffffffffffffffffffffffffffffffffff161461084c576040517f7987c15700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73420000000000000000000000000000000000002273ffffffffffffffffffffffffffffffffffffffff1663ab4d6f7585858560405161088d929190610f21565b6040519081900381207fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1682526108cc9291600401610f30565b5f604051808303815f87803b1580156108e3575f80fd5b505af11580156108f5573d5f803e3d5ffd5b505050505f805f805f6109088888610b1f565b9450945094509450945046851461094b576040517f31ac221100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60808901355f61095f878387878a88610ae1565b5f8181526020819052604090205490915060ff16156109aa576040517f9ca9480b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81815260208190526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556109ea8285610be8565b5f8673ffffffffffffffffffffffffffffffffffffffff163485604051610a119190610f89565b5f6040518083038185875af1925050503d805f8114610a4b576040519150601f19603f3d011682016040523d82523d5f602084013e610a50565b606091505b509950905080610a6257885189602001fd5b8186847fc270d73e26d2d39dee7ef92093555927e344e243415547ecc350b2b5385b68a28c80519060200120604051610a9d91815260200190565b60405180910390a4610aaf5f80610be8565b50505050505050505f7ff13569814868ede994184d5a425471fb19e869768a33421cb701a2ba3d420c0a5d9392505050565b5f868686868686604051602001610afd96959493929190610f9f565b6040516020818303038152906040528051906020012090509695505050505050565b5f808080606081610b33602082898b610ff5565b810190610b409190610e25565b90507f382409ac69001e11931a28435afef442cbfd20d9891907e8fa373ba7d351f3208114610b9b576040517fdf1eb58600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ba960806020898b610ff5565b810190610bb6919061101c565b91975095509350610bca876080818b610ff5565b810190610bd7919061107e565b969995985093965092949392505050565b817f711dfa3259c842fffc17d6e1f1e0fc5927756133a2345ca56b4cb8178589fee75d807fb83444d07072b122e2e72a669ce32857d892345c19856f4e7142d06a167ab3f35d5050565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f610c906020830184610c32565b9392505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610cb8575f80fd5b50565b5f8083601f840112610ccb575f80fd5b50813567ffffffffffffffff811115610ce2575f80fd5b602083019150836020828501011115610cf9575f80fd5b9250929050565b5f805f805f8060a08789031215610d15575f80fd5b86359550602087013594506040870135610d2e81610c97565b93506060870135610d3e81610c97565b9250608087013567ffffffffffffffff811115610d59575f80fd5b610d6589828a01610cbb565b979a9699509497509295939492505050565b5f805f8060608587031215610d8a575f80fd5b843593506020850135610d9c81610c97565b9250604085013567ffffffffffffffff811115610db7575f80fd5b610dc387828801610cbb565b95989497509550505050565b5f805f83850360c0811215610de2575f80fd5b60a0811215610def575f80fd5b5083925060a084013567ffffffffffffffff811115610e0c575f80fd5b610e1886828701610cbb565b9497909650939450505050565b5f60208284031215610e35575f80fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8416815260406020820152816040820152818360608301375f818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b5f7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808316818103610efc577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b6001019392505050565b5f60208284031215610f16575f80fd5b8135610c9081610c97565b818382375f9101908152919050565b60c081018335610f3f81610c97565b73ffffffffffffffffffffffffffffffffffffffff1682526020848101359083015260408085013590830152606080850135908301526080938401359382019390935260a0015290565b5f82518060208501845e5f920191825250919050565b8681528560208201528460408201525f73ffffffffffffffffffffffffffffffffffffffff808616606084015280851660808401525060c060a0830152610fe960c0830184610c32565b98975050505050505050565b5f8085851115611003575f80fd5b8386111561100f575f80fd5b5050820193919092039150565b5f805f6060848603121561102e575f80fd5b83359250602084013561104081610c97565b929592945050506040919091013590565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f806040838503121561108f575f80fd5b823561109a81610c97565b9150602083013567ffffffffffffffff808211156110b6575f80fd5b818501915085601f8301126110c9575f80fd5b8135818111156110db576110db611051565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561112157611121611051565b81604052828152886020848701011115611139575f80fd5b826020860160208301375f602084830101528095505050505050925092905056fea164736f6c6343000819000a0000000000000000000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 1500000, + "intent": "Deploy L2ToL2CrossDomainMessenger Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca4000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000007ab608060405234801561001057600080fd5b5061078b806100206000396000f3fe6080604052600436106100345760003560e01c80634f0edcc91461003957806354fd4d501461005b57806364a197f3146100ba575b600080fd5b34801561004557600080fd5b506100596100543660046105ae565b6100db565b005b34801561006757600080fd5b506100a46040518060400160405280600581526020017f312e302e3100000000000000000000000000000000000000000000000000000081525081565b6040516100b1919061065a565b60405180910390f35b6100cd6100c8366004610674565b610340565b6040519081526020016100b1565b3373420000000000000000000000000000000000002314610128576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008073420000000000000000000000000000000000002373ffffffffffffffffffffffffffffffffffffffff16637936cbee6040518163ffffffff1660e01b81526004016040805180830381865afa158015610189573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101ad91906106a0565b909250905073ffffffffffffffffffffffffffffffffffffffff82163014610201576040517fbc22e2aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fa0712d68000000000000000000000000000000000000000000000000000000008152600481018490527342000000000000000000000000000000000000259063a0712d6890602401600060405180830381600087803b15801561026757600080fd5b505af115801561027b573d6000803e3d6000fd5b50505050828460405161028d9061057d565b73ffffffffffffffffffffffffffffffffffffffff90911681526020016040518091039082f09050801580156102c7573d6000803e3d6000fd5b50508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fe5479bb8ebad3b9ac81f55f424a6289cf0a54ff2641708f41dcb2b26f264d3598584604051610331929190918252602082015260400190565b60405180910390a35050505050565b600073ffffffffffffffffffffffffffffffffffffffff831661038f576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73420000000000000000000000000000000000002573ffffffffffffffffffffffffffffffffffffffff166344df8e70346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156103eb57600080fd5b505af11580156103ff573d6000803e3d6000fd5b50506040805133602482015273ffffffffffffffffffffffffffffffffffffffff881660448201523460648083019190915282518083039091018152608490910182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f4f0edcc90000000000000000000000000000000000000000000000000000000017905290517f7056f41f0000000000000000000000000000000000000000000000000000000081527342000000000000000000000000000000000000239450637056f41f93506104de9250869130916004016106ce565b6020604051808303816000875af11580156104fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610521919061070c565b604080513481526020810185905291925073ffffffffffffffffffffffffffffffffffffffff85169133917fed98a2ff78833375c368471a747cdf0633024dde3f870feb08a934ac5be83402910160405180910390a392915050565b60598061072683390190565b73ffffffffffffffffffffffffffffffffffffffff811681146105ab57600080fd5b50565b6000806000606084860312156105c357600080fd5b83356105ce81610589565b925060208401356105de81610589565b929592945050506040919091013590565b6000815180845260005b81811015610615576020818501810151868301820152016105f9565b81811115610627576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061066d60208301846105ef565b9392505050565b6000806040838503121561068757600080fd5b823561069281610589565b946020939093013593505050565b600080604083850312156106b357600080fd5b82516106be81610589565b6020939093015192949293505050565b83815273ffffffffffffffffffffffffffffffffffffffff8316602082015260606040820152600061070360608301846105ef565b95945050505050565b60006020828403121561071e57600080fd5b505191905056fe608060405260405160593803806059833981016040819052601e91602a565b806001600160a01b0316ff5b600060208284031215603b57600080fd5b81516001600160a01b0381168114605157600080fd5b939250505056fea164736f6c634300080f000a000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 700000, + "intent": "Deploy SuperchainETHBridge Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca4000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000003b3608060405234801561001057600080fd5b50610393806100206000396000f3fe60806040526004361061003f5760003560e01c806344df8e701461004457806354fd4d501461004e578063a0712d68146100ad578063b60d4288146100cd575b600080fd5b61004c6100d5565b005b34801561005a57600080fd5b506100976040518060400160405280600581526020017f312e312e3000000000000000000000000000000000000000000000000000000081525081565b6040516100a491906102a1565b60405180910390f35b3480156100b957600080fd5b5061004c6100c8366004610314565b61015a565b61004c610229565b3373420000000000000000000000000000000000002414610122576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405134815233907f875e07afd7ce17c6531b1a6b7b34829dcd8b7e6639448afbd6a8e29fa1422b82906020015b60405180910390a2565b33734200000000000000000000000000000000000024146101a7576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80336040516101b590610295565b73ffffffffffffffffffffffffffffffffffffffff90911681526020016040518091039082f09050801580156101ef573d6000803e3d6000fd5b505060405181815233907f85719716ac5bd2744ae7ed3d16702129383049b97123b506320e7a5826ebbbba9060200160405180910390a250565b34600003610263576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405134815233907fbb9e497a5b82d1a37f9496dd70c6efb97ba0d98c66c3422d05010105d063359890602001610150565b60598061032e83390190565b600060208083528351808285015260005b818110156102ce578581018301518582016040015282016102b2565b818111156102e0576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b60006020828403121561032657600080fd5b503591905056fe608060405260405160593803806059833981016040819052601e91602a565b806001600160a01b0316ff5b600060208284031215603b57600080fd5b81516001600160a01b0381168114605157600080fd5b939250505056fea164736f6c634300080f000a00000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 400000, + "intent": "Deploy ETHLiquidity Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca4000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000010b1608060405234801561001057600080fd5b50611091806100206000396000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c80635cf24969116100f9578063c598591811610097578063e591b28211610071578063e591b28214610434578063e81b2c6d1461044e578063f820614014610457578063fe3d57101461046057600080fd5b8063c598591814610404578063d844471514610424578063dad544e01461042c57600080fd5b80638381f58a116100d35780638381f58a146103be5780638b239f73146103d25780639e8c4966146103db578063b80777ea146103e457600080fd5b80635cf249691461038557806364ca23ef1461038e57806368d5dca6146103a257600080fd5b80634397dfef1161016657806347af267b1161014057806347af267b146103145780634d5d9a2a1461033757806354fd4d5014610368578063550fcdc91461037d57600080fd5b80634397dfef146102c3578063440a5e20146102f957806346a4d7801461030157600080fd5b806316d3bc7f116101a257806316d3bc7f14610202578063213268491461022f5780633db6be2b1461028e5780633e47158c1461029657600080fd5b8063015d8eb9146101c9578063098999be146101de57806309bd5a60146101e6575b600080fd5b6101dc6101d7366004610d9c565b610491565b005b6101dc6105d1565b6101ef60025481565b6040519081526020015b60405180910390f35b6008546102169067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101f9565b7f435553544f4d5f4741535f544f4b454e0000000000000000000000000000000060005260096020527f4ad9936a67aeb1898ef7b848aecdf71a1f8999fbf63ff2f5b5691cb14bedfe4d5460ff165b60405190151581526020016101f9565b6101dc6105e4565b61029e61060e565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f9565b6102cb610819565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260ff9091166020830152016101f9565b6101dc610880565b6101dc61030f366004610e0e565b6108d7565b61027e610322366004610e0e565b60096020526000908152604090205460ff1681565b6008546103539068010000000000000000900463ffffffff1681565b60405163ffffffff90911681526020016101f9565b6103706108ec565b6040516101f99190610e57565b61037061094c565b6101ef60015481565b6003546102169067ffffffffffffffff1681565b6003546103539068010000000000000000900463ffffffff1681565b6000546102169067ffffffffffffffff1681565b6101ef60055481565b6101ef60065481565b6000546102169068010000000000000000900467ffffffffffffffff1681565b600354610353906c01000000000000000000000000900463ffffffff1681565b610370610a88565b61029e610b79565b73deaddeaddeaddeaddeaddeaddeaddeaddead000161029e565b6101ef60045481565b6101ef60075481565b60085461047e906c01000000000000000000000000900461ffff1681565b60405161ffff90911681526020016101f9565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610539576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4c31426c6f636b3a206f6e6c7920746865206465706f7369746f72206163636f60448201527f756e742063616e20736574204c3120626c6f636b2076616c756573000000000060648201526084015b60405180910390fd5b6000805467ffffffffffffffff98891668010000000000000000027fffffffffffffffffffffffffffffffff00000000000000000000000000000000909116998916999099179890981790975560019490945560029290925560038054919094167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009190911617909255600491909155600555600655565b6105d9610880565b60a43560a01c600855565b6105ec610880565b6dffff00000000000000000000000060b03560901c1660a43560a01c17600855565b6000806106397fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905073ffffffffffffffffffffffffffffffffffffffff81161561065c57919050565b6040518060400160405280601a81526020017f4f564d5f4c3143726f7373446f6d61696e4d657373656e67657200000000000081525051600261069f9190610ea8565b604080513060208201526000918101919091527f4f564d5f4c3143726f7373446f6d61696e4d657373656e67657200000000000091909117906106fa906060015b604051602081830303815290604052805190602001205490565b14610731576040517f54e433cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051306020820152600191810191909152600090610753906060016106e0565b905073ffffffffffffffffffffffffffffffffffffffff8116156107e7578073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e09190610f0c565b9250505090565b6040517f332144db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4c31426c6f636b4347543a20646570726563617465640000000000000000000060448201526000908190606401610530565b73deaddeaddeaddeaddeaddeaddeaddeaddead00013381146108aa57633cc50b456000526004601cfd5b60043560801c60035560143560801c60005560243560015560443560075560643560025560843560045550565b6108e033610bf1565b6108e981610cce565b50565b606061092860408051808201909152600581527f312e392e30000000000000000000000000000000000000000000000000000000602082015290565b6040516020016109389190610f49565b604051602081830303815290604052905090565b60606109a27f435553544f4d5f4741535f544f4b454e0000000000000000000000000000000060005260096020527f4ad9936a67aeb1898ef7b848aecdf71a1f8999fbf63ff2f5b5691cb14bedfe4d5460ff1690565b6109de575060408051808201909152600381527f4554480000000000000000000000000000000000000000000000000000000000602082015290565b73420000000000000000000000000000000000002a73ffffffffffffffffffffffffffffffffffffffff1663550fcdc96040518163ffffffff1660e01b8152600401600060405180830381865afa158015610a3d573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610a839190810190610fb9565b905090565b6060610ade7f435553544f4d5f4741535f544f4b454e0000000000000000000000000000000060005260096020527f4ad9936a67aeb1898ef7b848aecdf71a1f8999fbf63ff2f5b5691cb14bedfe4d5460ff1690565b610b1a575060408051808201909152600581527f4574686572000000000000000000000000000000000000000000000000000000602082015290565b73420000000000000000000000000000000000002a73ffffffffffffffffffffffffffffffffffffffff1663d84447156040518163ffffffff1660e01b8152600401600060405180830381865afa158015610a3d573d6000803e3d6000fd5b6000610b8361060e565b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bcd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a839190610f0c565b73ffffffffffffffffffffffffffffffffffffffff811673deaddeaddeaddeaddeaddeaddeaddeaddead00011480610c5b5750610c2c610b79565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b80610c985750610c6961060e565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b6108e9576040517fbe9d7ca600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526009602052604090205460ff1615610d17576040517f4f45326000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526009602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091559051909183917fb876f6594132c89891d2fd198e925e999be741ec809abb58bfe9b966876cc06c9190a350565b803567ffffffffffffffff81168114610d9757600080fd5b919050565b600080600080600080600080610100898b031215610db957600080fd5b610dc289610d7f565b9750610dd060208a01610d7f565b96506040890135955060608901359450610dec60808a01610d7f565b979a969950949793969560a0850135955060c08501359460e001359350915050565b600060208284031215610e2057600080fd5b5035919050565b60005b83811015610e42578181015183820152602001610e2a565b83811115610e51576000848401525b50505050565b6020815260008251806020840152610e76816040850160208701610e27565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610f07577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500290565b600060208284031215610f1e57600080fd5b815173ffffffffffffffffffffffffffffffffffffffff81168114610f4257600080fd5b9392505050565b60008251610f5b818460208701610e27565b7f2b637573746f6d2d6761732d746f6b656e2e3100000000000000000000000000920191825250601301919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610fcb57600080fd5b815167ffffffffffffffff80821115610fe357600080fd5b818401915084601f830112610ff757600080fd5b81518181111561100957611009610f8a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561104f5761104f610f8a565b8160405282815287602084870101111561106857600080fd5b611079836020830160208801610e27565b97965050505050505056fea164736f6c634300080f000a000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 1100000, + "intent": "Deploy L1BlockCGT Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000862608060405234801561001057600080fd5b50610842806100206000396000f3fe6080604052600436106100695760003560e01c806382e3702d1161004357806382e3702d146100f6578063c2b3e5ac14610136578063ecc704281461014957600080fd5b80633f827a5a1461009257806344df8e70146100bf57806354fd4d50146100d457600080fd5b3661008d5761008b33620186a0604051806020016040528060008152506101ae565b005b600080fd5b34801561009e57600080fd5b506100a7600181565b60405161ffff90911681526020015b60405180910390f35b3480156100cb57600080fd5b5061008b610284565b3480156100e057600080fd5b506100e96102bc565b6040516100b691906105dd565b34801561010257600080fd5b506101266101113660046105f7565b60006020819052908152604090205460ff1681565b60405190151581526020016100b6565b61008b61014436600461063f565b6101ae565b34801561015557600080fd5b506101a06001547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e010000000000000000000000000000000000000000000000000000000000001790565b6040519081526020016100b6565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663213268496040518163ffffffff1660e01b8152600401602060405180830381865afa15801561020d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102319190610743565b801561023d5750600034115b15610274576040517fcdfaa11100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61027f83838361031c565b505050565b4761028e816104e0565b60405181907f7967de617a5ac1cc7eba2d6f37570a0135afa950d8bb77cdd35f0d0b4e85a16f90600090a250565b60606102f860408051808201909152600581527f312e322e30000000000000000000000000000000000000000000000000000000602082015290565b6040516020016103089190610765565b604051602081830303815290604052905090565b60006103b26040518060c001604052806103766001547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e010000000000000000000000000000000000000000000000000000000000001790565b815233602082015273ffffffffffffffffffffffffffffffffffffffff871660408201523460608201526080810186905260a00184905261050a565b600081815260208190526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055905073ffffffffffffffffffffffffffffffffffffffff84163361044d6001547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e010000000000000000000000000000000000000000000000000000000000001790565b7f02a52367d10742d8032712c1bb8e0144ff1ec5ffda1ed7d70bb05a27449550543487878760405161048294939291906107a6565b60405180910390a45050600180547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8082168301167fffff0000000000000000000000000000000000000000000000000000000000009091161790555050565b806040516104ed90610557565b6040518091039082f090508015801561027f573d6000803e3d6000fd5b80516020808301516040808501516060860151608087015160a0880151935160009761053a9790969591016107d6565b604051602081830303815290604052805190602001209050919050565b60088061082e83390190565b60005b8381101561057e578181015183820152602001610566565b8381111561058d576000848401525b50505050565b600081518084526105ab816020860160208601610563565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006105f06020830184610593565b9392505050565b60006020828403121561060957600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561065457600080fd5b833573ffffffffffffffffffffffffffffffffffffffff8116811461067857600080fd5b925060208401359150604084013567ffffffffffffffff8082111561069c57600080fd5b818601915086601f8301126106b057600080fd5b8135818111156106c2576106c2610610565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561070857610708610610565b8160405282815289602084870101111561072157600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561075557600080fd5b815180151581146105f057600080fd5b60008251610777818460208701610563565b7f2b637573746f6d2d6761732d746f6b656e000000000000000000000000000000920191825250601101919050565b8481528360208201526080604082015260006107c56080830185610593565b905082606083015295945050505050565b868152600073ffffffffffffffffffffffffffffffffffffffff808816602084015280871660408401525084606083015283608083015260c060a083015261082160c0830184610593565b9897505050505050505056fe608060405230fffea164736f6c634300080f000a000000000000000000000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 750000, + "intent": "Deploy L2ToL1MessagePasserCGT Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca40000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000146a608060405234801561001057600080fd5b5061001961001e565b6100de565b600054610100900460ff161561008a5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156100dc576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61137d806100ed6000396000f3fe6080604052600436106100dd5760003560e01c80638da5cb5b1161007f578063d844471511610059578063d844471514610256578063dad544e01461026b578063f2fde38b14610280578063f46eccc4146102a057600080fd5b80638da5cb5b146101eb5780639065714714610216578063c6f69fbb1461023657600080fd5b806344df8e70116100bb57806344df8e701461016357806354fd4d501461016b578063550fcdc9146101c1578063715018a6146101d657600080fd5b80630c984832146100e25780633e47158c1461010457806340c10f1914610143575b600080fd5b3480156100ee57600080fd5b506101026100fd366004610ec7565b6102e0565b005b34801561011057600080fd5b5061011961035f565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561014f57600080fd5b5061010261015e366004610eeb565b61056a565b6101026106cc565b34801561017757600080fd5b506101b46040518060400160405280600581526020017f312e302e3100000000000000000000000000000000000000000000000000000081525081565b60405161013a9190610f17565b3480156101cd57600080fd5b506101b46107c2565b3480156101e257600080fd5b50610102610850565b3480156101f757600080fd5b5060335473ffffffffffffffffffffffffffffffffffffffff16610119565b34801561022257600080fd5b50610102610231366004611064565b610864565b34801561024257600080fd5b50610102610251366004610ec7565b610a29565b34801561026257600080fd5b506101b4610aa5565b34801561027757600080fd5b50610119610ab2565b34801561028c57600080fd5b5061010261029b366004610ec7565b610b2f565b3480156102ac57600080fd5b506102d06102bb366004610ec7565b60656020526000908152604090205460ff1681565b604051901515815260200161013a565b6102e8610be6565b73ffffffffffffffffffffffffffffffffffffffff811660008181526065602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f83b05b6735acd4b85e3bded8e72c851d1a87718f81e3c8e6f0c9d9a2baa88e469190a250565b60008061038a7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b905073ffffffffffffffffffffffffffffffffffffffff8116156103ad57919050565b6040518060400160405280601a81526020017f4f564d5f4c3143726f7373446f6d61696e4d657373656e6765720000000000008152505160026103f091906110da565b604080513060208201526000918101919091527f4f564d5f4c3143726f7373446f6d61696e4d657373656e676572000000000000919091179061044b906060015b604051602081830303815290604052805190602001205490565b14610482576040517f54e433cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080513060208201526001918101919091526000906104a490606001610431565b905073ffffffffffffffffffffffffffffffffffffffff811615610538578073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561050d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610531919061113e565b9250505090565b6040517f332144db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3360009081526065602052604090205460ff166105b3576040517f5fbc4ede00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f2e1a7d4d0000000000000000000000000000000000000000000000000000000081526004810182905273420000000000000000000000000000000000002990632e1a7d4d90602401600060405180830381600087803b15801561061957600080fd5b505af115801561062d573d6000803e3d6000fd5b50505050808260405161063f90610e99565b73ffffffffffffffffffffffffffffffffffffffff90911681526020016040518091039082f0905080158015610679573d6000803e3d6000fd5b505060405181815273ffffffffffffffffffffffffffffffffffffffff83169033907fec89d80a36947288037745287dde87d62cd8c141d5323130b3d26d97d84004c79060200160405180910390a35050565b3360009081526065602052604090205460ff16610715576040517f5fbc4ede00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73420000000000000000000000000000000000002973ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561077157600080fd5b505af1158015610785573d6000803e3d6000fd5b50506040513481523393507f875e07afd7ce17c6531b1a6b7b34829dcd8b7e6639448afbd6a8e29fa1422b829250602001905060405180910390a2565b606780546107cf9061115b565b80601f01602080910402602001604051908101604052809291908181526020018280546107fb9061115b565b80156108485780601f1061081d57610100808354040283529160200191610848565b820191906000526020600020905b81548152906001019060200180831161082b57829003601f168201915b505050505081565b610858610be6565b6108626000610c67565b565b600054610100900460ff16158080156108845750600054600160ff909116105b8061089e5750303b15801561089e575060005460ff166001145b61092f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561098d57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610995610cde565b61099d610d5f565b6109a684610b2f565b60666109b284826111fd565b5060676109bf83826111fd565b508015610a2357600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b610a31610be6565b73ffffffffffffffffffffffffffffffffffffffff811660008181526065602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517fdf6bf03dfab5b4ccec3ba95544b98d7ecc9d4b9293d8673e86cb6edb5ac0cb629190a250565b606680546107cf9061115b565b6000610abc61035f565b73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2a919061113e565b905090565b610b37610be6565b73ffffffffffffffffffffffffffffffffffffffff8116610bda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610926565b610be381610c67565b50565b60335473ffffffffffffffffffffffffffffffffffffffff163314610862576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610926565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b33610ce761035f565b73ffffffffffffffffffffffffffffffffffffffff1614158015610d28575033610d0f610ab2565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610862576040517fc4050a2600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff16610df6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610926565b610862600054610100900460ff16610e90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610926565b61086233610c67565b60598061131883390190565b73ffffffffffffffffffffffffffffffffffffffff81168114610be357600080fd5b600060208284031215610ed957600080fd5b8135610ee481610ea5565b9392505050565b60008060408385031215610efe57600080fd5b8235610f0981610ea5565b946020939093013593505050565b600060208083528351808285015260005b81811015610f4457858101830151858201604001528201610f28565b81811115610f56576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112610fca57600080fd5b813567ffffffffffffffff80821115610fe557610fe5610f8a565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561102b5761102b610f8a565b8160405283815286602085880101111561104457600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060006060848603121561107957600080fd5b833561108481610ea5565b9250602084013567ffffffffffffffff808211156110a157600080fd5b6110ad87838801610fb9565b935060408601359150808211156110c357600080fd5b506110d086828701610fb9565b9150509250925092565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611139577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500290565b60006020828403121561115057600080fd5b8151610ee481610ea5565b600181811c9082168061116f57607f821691505b6020821081036111a8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156111f857600081815260208120601f850160051c810160208610156111d55750805b601f850160051c820191505b818110156111f4578281556001016111e1565b5050505b505050565b815167ffffffffffffffff81111561121757611217610f8a565b61122b81611225845461115b565b846111ae565b602080601f83116001811461127e57600084156112485750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b1785556111f4565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b828110156112cb578886015182559484019460019091019084016112ac565b508582101561130757878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fe608060405260405160593803806059833981016040819052601e91602a565b806001600160a01b0316ff5b600060208284031215603b57600080fd5b81516001600160a01b0381168114605157600080fd5b939250505056fea164736f6c634300080f000a00000000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 1400000, + "intent": "Deploy LiquidityController Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca40000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000036d608060405234801561001057600080fd5b5061034d806100206000396000f3fe6080604052600436106100345760003560e01c80632e1a7d4d1461003957806354fd4d501461005b578063d0e30db0146100ba575b600080fd5b34801561004557600080fd5b5061005961005436600461025b565b6100c2565b005b34801561006757600080fd5b506100a46040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516100b19190610274565b60405180910390f35b6100596101cb565b3373420000000000000000000000000000000000002a1461010f576040517f565369fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b47811115610149576040517f7b7f21e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80336040516101579061024f565b73ffffffffffffffffffffffffffffffffffffffff90911681526020016040518091039082f0905080158015610191573d6000803e3d6000fd5b505060405181815233907fb1cce8684b4ffa8667b4577654e61ee3480d661ee9c27522ac80e211f6bd4d259060200160405180910390a250565b3373420000000000000000000000000000000000002a14610218576040517f565369fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405134815233907f7ff07ce9a287649537e4b012e45cf012d90228b12e2b56bb03515a6b5436fcdf9060200160405180910390a2565b6059806102e883390190565b60006020828403121561026d57600080fd5b5035919050565b600060208083528351808285015260005b818110156102a157858101830151858201604001528201610285565b818111156102b3576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fe608060405260405160593803806059833981016040819052601e91602a565b806001600160a01b0316ff5b600060208284031215603b57600080fd5b81516001600160a01b0381168114605157600080fd5b939250505056fea164736f6c634300080f000a00000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 400000, + "intent": "Deploy NativeAssetLiquidity Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0x3659cfe6000000000000000000000000893c2ceeb71d38514daf67728d3ff1b213fc4b5f", + "from": "0x0000000000000000000000000000000000000000", + "gasLimit": 50000, + "intent": "Upgrade L2ProxyAdmin Implementation", + "to": "0x4200000000000000000000000000000000000018" + }, + { + "data": "0xcdcb760a9b217f1b15f9c04316d04d42f550c340c5b2ee8e5ae05cab4f8cd9cb21970ca400000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000003f6c6104006040523480156200001257600080fd5b5060405162003c0c38038062003c0c8339810160408190526200003591620001d4565b30608090815281516001600160a01b0390811660a09081526020840151821660e09081526040850151831660c0908152606086015184166101009081529486015184166101209081529286015184166101409081529086015184166101609081529186015184166101809081529486015184166101a09081529286015184166101c09081529086015184166101e09081529186015184166102009081529486015184166102209081529286015184166102409081529086015184166102609081529186015184166102809081529486015184166102a09081529286015184166102c09081529086015184166102e090815291860151841661030090815294860151841661032090815292860151841661034090815290860151841661036052908501518316610380529284015182166103a05283015181166103c052910151166103e05262000407565b60405161036081016001600160401b0381118282101715620001b157634e487b7160e01b600052604160045260246000fd5b60405290565b80516001600160a01b0381168114620001cf57600080fd5b919050565b60006103608284031215620001e857600080fd5b620001f26200017f565b620001fd83620001b7565b81526200020d60208401620001b7565b60208201526200022060408401620001b7565b60408201526200023360608401620001b7565b60608201526200024660808401620001b7565b60808201526200025960a08401620001b7565b60a08201526200026c60c08401620001b7565b60c08201526200027f60e08401620001b7565b60e082015261010062000294818501620001b7565b90820152610120620002a8848201620001b7565b90820152610140620002bc848201620001b7565b90820152610160620002d0848201620001b7565b90820152610180620002e4848201620001b7565b908201526101a0620002f8848201620001b7565b908201526101c06200030c848201620001b7565b908201526101e062000320848201620001b7565b9082015261020062000334848201620001b7565b9082015261022062000348848201620001b7565b908201526102406200035c848201620001b7565b9082015261026062000370848201620001b7565b9082015261028062000384848201620001b7565b908201526102a062000398848201620001b7565b908201526102c0620003ac848201620001b7565b908201526102e0620003c0848201620001b7565b90820152610300620003d4848201620001b7565b90820152610320620003e8848201620001b7565b90820152610340620003fc848201620001b7565b908201529392505050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051610220516102405161026051610280516102a0516102c0516102e05161030051610320516103405161036051610380516103a0516103c0516103e0516135c26200064a600039600081816104d801526119530152600081816104af0152611b10015260008181610486015261145301526000818161045d015261130501526000818161043401526113ec01526000818161040b0152611a560152600081816103e20152611a180152600081816103b901526119da015260008181610390015261199c0152600081816103670152611ad201526000818161033e0152611a9401526000818161031501526116e90152600081816102ec01526116690152600081816102c301526115ea01526000818161029a0152611915015260008181610271015261120501526000818161024801526118d701526000818161021f01526118b10152600081816101f601526117c00152600081816101ce015261179a0152600081816101a601526110e101526000818161017e015261116d01526000818161015601526114cd01526000818161012e0152610fdb01526000818160df0152610ed5015260008181610107015261175201526000818160ba01528181610ef701528181610ffd015281816111030152818161118f015281816112270152818161132701528181611475015281816114ef0152818161160c0152818161168b015261170b0152600061052b01526135c26000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806354fd4d5014610046578063615f64fe14610098578063d55ec6971461050a575b600080fd5b6100826040518060400160405280600581526020017f312e352e3000000000000000000000000000000000000000000000000000000081525081565b60405161008f9190612fd5565b60405180910390f35b604080516103608101825273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811682527f0000000000000000000000000000000000000000000000000000000000000000811660208301527f00000000000000000000000000000000000000000000000000000000000000008116828401527f0000000000000000000000000000000000000000000000000000000000000000811660608301527f0000000000000000000000000000000000000000000000000000000000000000811660808301527f0000000000000000000000000000000000000000000000000000000000000000811660a08301527f0000000000000000000000000000000000000000000000000000000000000000811660c08301527f0000000000000000000000000000000000000000000000000000000000000000811660e08301527f000000000000000000000000000000000000000000000000000000000000000081166101008301527f000000000000000000000000000000000000000000000000000000000000000081166101208301527f000000000000000000000000000000000000000000000000000000000000000081166101408301527f000000000000000000000000000000000000000000000000000000000000000081166101608301527f000000000000000000000000000000000000000000000000000000000000000081166101808301527f000000000000000000000000000000000000000000000000000000000000000081166101a08301527f000000000000000000000000000000000000000000000000000000000000000081166101c08301527f000000000000000000000000000000000000000000000000000000000000000081166101e08301527f000000000000000000000000000000000000000000000000000000000000000081166102008301527f000000000000000000000000000000000000000000000000000000000000000081166102208301527f000000000000000000000000000000000000000000000000000000000000000081166102408301527f000000000000000000000000000000000000000000000000000000000000000081166102608301527f000000000000000000000000000000000000000000000000000000000000000081166102808301527f000000000000000000000000000000000000000000000000000000000000000081166102a08301527f000000000000000000000000000000000000000000000000000000000000000081166102c08301527f000000000000000000000000000000000000000000000000000000000000000081166102e08301527f000000000000000000000000000000000000000000000000000000000000000081166103008301527f000000000000000000000000000000000000000000000000000000000000000081166103208301527f000000000000000000000000000000000000000000000000000000000000000016610340820152905161008f9190612fe8565b610512610514565b005b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163003610583576040517fada337cf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061058d61059b565b905061059881610e96565b50565b6105a3612e1f565b73420000000000000000000000000000000000001573ffffffffffffffffffffffffffffffffffffffff1663213268496040518163ffffffff1660e01b8152600401602060405180830381865afa158015610602573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106269190613236565b15156101608201526040517f47af267b0000000000000000000000000000000000000000000000000000000081527f494e5445524f50000000000000000000000000000000000000000000000000006004820152734200000000000000000000000000000000000015906347af267b90602401602060405180830381865afa9250505080156106f0575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526106ed91810190613236565b60015b61070157600061018082015261070a565b15156101808201525b806101800151801561072357506107216001611b34565b155b1561075a576040517fa27dcc8800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604051806020016040528073420000000000000000000000000000000000000773ffffffffffffffffffffffffffffffffffffffff16639fce812c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e8919061327a565b73ffffffffffffffffffffffffffffffffffffffff16905281526040805160208082018084527f7f46ddb200000000000000000000000000000000000000000000000000000000905291519091829173420000000000000000000000000000000000001091637f46ddb29160248086019291908187030181865afa158015610874573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610898919061327a565b73ffffffffffffffffffffffffffffffffffffffff168152508160200181905250604051806020016040528073420000000000000000000000000000000000001473ffffffffffffffffffffffffffffffffffffffff16637f46ddb26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610923573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610947919061327a565b73ffffffffffffffffffffffffffffffffffffffff168152508160400181905250604051806020016040528073420000000000000000000000000000000000001273ffffffffffffffffffffffffffffffffffffffff1663ee9a31a26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f6919061327a565b73ffffffffffffffffffffffffffffffffffffffff1690526060820152604080518082018083527fee9a31a2000000000000000000000000000000000000000000000000000000009052905181907342000000000000000000000000000000000000179063ee9a31a2906044808501916020918187030181865afa158015610a82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa6919061327a565b73ffffffffffffffffffffffffffffffffffffffff16815260200173420000000000000000000000000000000000001773ffffffffffffffffffffffffffffffffffffffff16637d1d0c5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b449190613297565b90526080820152610b68734200000000000000000000000000000000000011611c97565b60a0820152610b8a734200000000000000000000000000000000000019611c97565b60c0820152610bac73420000000000000000000000000000000000001a611c97565b60e0820152610bce73420000000000000000000000000000000000001b611c97565b61010082015261016081015115610dbe57600073420000000000000000000000000000000000002a905060405180606001604052808273ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c72919061327a565b73ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1663d84447156040518163ffffffff1660e01b8152600401600060405180830381865afa158015610cd8573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610d1e9190810190613371565b81526020018273ffffffffffffffffffffffffffffffffffffffff1663550fcdc96040518163ffffffff1660e01b8152600401600060405180830381865afa158015610d6e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610db49190810190613371565b9052610120830152505b600073420000000000000000000000000000000000002b73ffffffffffffffffffffffffffffffffffffffff1663d61a398b6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610e59575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252610e569181019061327a565b60015b610e6557506000610e68565b90505b604080516020810190915273ffffffffffffffffffffffffffffffffffffffff909116815261014082015290565b80515160405173ffffffffffffffffffffffffffffffffffffffff9091166024820152610f9990734200000000000000000000000000000000000007907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090604401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fc4d66de80000000000000000000000000000000000000000000000000000000017905260006014611e78565b60208101515160405173ffffffffffffffffffffffffffffffffffffffff909116602482015261109f90734200000000000000000000000000000000000010907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000906044015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fc4d66de800000000000000000000000000000000000000000000000000000000179052600080611e78565b60408082015151905173ffffffffffffffffffffffffffffffffffffffff909116602482015261112b90734200000000000000000000000000000000000014907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090604401611021565b60608101515160405173ffffffffffffffffffffffffffffffffffffffff90911660248201526111b790734200000000000000000000000000000000000012907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090604401611021565b6080810151805160209091015160405173ffffffffffffffffffffffffffffffffffffffff909216602483015260448201526112c990734200000000000000000000000000000000000017907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fcd6dc6870000000000000000000000000000000000000000000000000000000017905260016000611e78565b80610160015115611410576101208101518051602082015160409283015192516113d29373420000000000000000000000000000000000002a937f0000000000000000000000000000000000000000000000000000000000000000937f00000000000000000000000000000000000000000000000000000000000000009361135493906024016133c2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f9065714700000000000000000000000000000000000000000000000000000000179052600080611e78565b6114107342000000000000000000000000000000000000297f00000000000000000000000000000000000000000000000000000000000000006125d4565b6101408101515160405173ffffffffffffffffffffffffffffffffffffffff909116602482015261149d9073420000000000000000000000000000000000002b907f0000000000000000000000000000000000000000000000000000000000000000907f000000000000000000000000000000000000000000000000000000000000000090604401611021565b60a08101518051602082015160409283015192516115ba93734200000000000000000000000000000000000011937f0000000000000000000000000000000000000000000000000000000000000000937f00000000000000000000000000000000000000000000000000000000000000009361151c939060240161343c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb49dc741000000000000000000000000000000000000000000000000000000001790527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a006000611e78565b60c081015180516020820151604092830151925161163993734200000000000000000000000000000000000019937f0000000000000000000000000000000000000000000000000000000000000000937f00000000000000000000000000000000000000000000000000000000000000009361151c939060240161343c565b60e08101518051602082015160409283015192516116b89373420000000000000000000000000000000000001a937f0000000000000000000000000000000000000000000000000000000000000000937f00000000000000000000000000000000000000000000000000000000000000009361151c939060240161343c565b6101008101518051602082015160409283015192516117389373420000000000000000000000000000000000001b937f0000000000000000000000000000000000000000000000000000000000000000937f00000000000000000000000000000000000000000000000000000000000000009361151c939060240161343c565b61177673420000000000000000000000000000000000000f7f00000000000000000000000000000000000000000000000000000000000000006125d4565b6117e47342000000000000000000000000000000000000158261016001516117be577f00000000000000000000000000000000000000000000000000000000000000006125d4565b7f00000000000000000000000000000000000000000000000000000000000000006125d4565b8061016001511561188d576040517f46a4d7800000000000000000000000000000000000000000000000000000000081527f435553544f4d5f4741535f544f4b454e000000000000000000000000000000006004820152734200000000000000000000000000000000000015906346a4d78090602401600060405180830381600087803b15801561187457600080fd5b505af1158015611888573d6000803e3d6000fd5b505050505b6118fb7342000000000000000000000000000000000000168261016001516118d5577f00000000000000000000000000000000000000000000000000000000000000006125d4565b7f00000000000000000000000000000000000000000000000000000000000000006125d4565b6119397342000000000000000000000000000000000000187f00000000000000000000000000000000000000000000000000000000000000006125d4565b61197773420000000000000000000000000000000000002d7f00000000000000000000000000000000000000000000000000000000000000006125d4565b80610180015115611a7a576119c07342000000000000000000000000000000000000227f00000000000000000000000000000000000000000000000000000000000000006125d4565b6119fe7342000000000000000000000000000000000000237f00000000000000000000000000000000000000000000000000000000000000006125d4565b611a3c7342000000000000000000000000000000000000247f00000000000000000000000000000000000000000000000000000000000000006125d4565b611a7a7342000000000000000000000000000000000000257f00000000000000000000000000000000000000000000000000000000000000006125d4565b611ab87342000000000000000000000000000000000000207f00000000000000000000000000000000000000000000000000000000000000006125d4565b611af67342000000000000000000000000000000000000217f00000000000000000000000000000000000000000000000000000000000000006125d4565b61059873420000000000000000000000000000000000002c7f00000000000000000000000000000000000000000000000000000000000000006125d4565b6040517f204e1c7a00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000002d600482015260009081907342000000000000000000000000000000000000189063204e1c7a90602401602060405180830381865afa158015611bb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd9919061327a565b90508073ffffffffffffffffffffffffffffffffffffffff163b600003611c035750600092915050565b6040517f78ecabce0000000000000000000000000000000000000000000000000000000081526004810184905273420000000000000000000000000000000000002d906378ecabce90602401602060405180830381865afa158015611c6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c909190613236565b9392505050565b611cb860408051606081018252600080825260208201819052909182015290565b60008273ffffffffffffffffffffffffffffffffffffffff1663d0e12f906040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611d3f575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252611d3c918101906134a5565b60015b611d4b57506000611d4e565b90505b600083905060405180606001604052808273ffffffffffffffffffffffffffffffffffffffff16630d9019e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dcd919061327a565b73ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1663d3e5792b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e579190613297565b8152602001836001811115611e6e57611e6e61340d565b9052949350505050565b611e81866128a7565b611ed4576040517fc3fe4a6600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871660048201526024015b60405180910390fd5b6040517f204e1c7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871660048201526000907342000000000000000000000000000000000000189063204e1c7a90602401602060405180830381865afa158015611f55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f79919061327a565b905073ffffffffffffffffffffffffffffffffffffffff81163b158015906120c657506120c68773ffffffffffffffffffffffffffffffffffffffff166354fd4d506040518163ffffffff1660e01b8152600401600060405180830381865afa158015611fea573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526120309190810190613371565b8773ffffffffffffffffffffffffffffffffffffffff166354fd4d506040518163ffffffff1660e01b8152600401600060405180830381865afa15801561207b573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526120c19190810190613371565b6128f0565b15612115576040517ff8ce5d1600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88166004820152602401611ecb565b6040517f3659cfe600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152881690633659cfe690602401600060405180830381600087803b15801561217e57600080fd5b505af1158015612192573d6000803e3d6000fd5b507ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009250505083811480156121c9575060ff831615155b15612200576040517f10415a2900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b808414612394576040517fa6ed563e0000000000000000000000000000000000000000000000000000000081526004810185905260009073ffffffffffffffffffffffffffffffffffffffff8a169063a6ed563e90602401602060405180830381865afa158015612275573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122999190613297565b90506122a68460016134f5565b6122b49060ff16600861351a565b81901c60ff16156122f1576040517fc996d78400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061230160ff8616600861351a565b6040517f4e91db080000000000000000000000000000000000000000000000000000000081526004810188905260ff90911b198381166024830152915073ffffffffffffffffffffffffffffffffffffffff8b1690634e91db0890604401600060405180830381600087803b15801561237957600080fd5b505af115801561238d573d6000803e3d6000fd5b5050505050505b6040517fa6ed563e0000000000000000000000000000000000000000000000000000000081526004810182905260009073ffffffffffffffffffffffffffffffffffffffff8a169063a6ed563e90602401602060405180830381865afa158015612402573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124269190613297565b905060ff604082901c1615612467576040517fc996d78400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f4e91db08000000000000000000000000000000000000000000000000000000008152600481018390527fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008216602482015273ffffffffffffffffffffffffffffffffffffffff8a1690634e91db0890604401600060405180830381600087803b1580156124f757600080fd5b505af115801561250b573d6000803e3d6000fd5b50506040517f4f1ef28600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c169250634f1ef2869150612563908b908a90600401613557565b6000604051808303816000875af1158015612582573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526125c89190810190613371565b50505050505050505050565b6125dd826128a7565b61262b576040517fc3fe4a6600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401611ecb565b6040517f204e1c7a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526000907342000000000000000000000000000000000000189063204e1c7a90602401602060405180830381865afa1580156126ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126d0919061327a565b905073ffffffffffffffffffffffffffffffffffffffff81163b158015906127d257506127d28373ffffffffffffffffffffffffffffffffffffffff166354fd4d506040518163ffffffff1660e01b8152600401600060405180830381865afa158015612741573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526127879190810190613371565b8373ffffffffffffffffffffffffffffffffffffffff166354fd4d506040518163ffffffff1660e01b8152600401600060405180830381865afa15801561207b573d6000803e3d6000fd5b15612821576040517ff8ce5d1600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401611ecb565b6040517f3659cfe600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152841690633659cfe690602401600060405180830381600087803b15801561288a57600080fd5b505af115801561289e573d6000803e3d6000fd5b50505050505050565b60007208400000000000000000000000000000000000600b83901c721fffffffffffffffffffffffffffffffffffff161480156128ea57506128e882612916565b155b92915050565b60006128fc838361297e565b158015611c90575061290e83836129ce565b159392505050565b600073ffffffffffffffffffffffffffffffffffffffff821673420000000000000000000000000000000000004214806128ea575073ffffffffffffffffffffffffffffffffffffffff82167342000000000000000000000000000000000000061492915050565b60008061298a84612a43565b9050600061299784612a43565b805183519192501480156129b2575080602001518260200151145b80156129c5575080604001518260400151145b95945050505050565b6000806129da84612a43565b905060006129e784612a43565b805183519192501180612a0d575080518251148015612a0d575080602001518260200151105b806129c5575080518251148015612a2b575080602001518260200151145b80156129c55750604090810151910151109392505050565b612a6760405180606001604052806000815260200160008152602001600081525090565b6000612aa8836040518060400160405280600181526020017f2e00000000000000000000000000000000000000000000000000000000000000815250612c0f565b9050600381511015612ae6576040517f9eda858c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000612b4182600281518110612afe57612afe613586565b60200260200101516040518060400160405280600181526020017f2d00000000000000000000000000000000000000000000000000000000000000815250612c0f565b90506000612b9e82600081518110612b5b57612b5b613586565b60200260200101516040518060400160405280600181526020017f2b00000000000000000000000000000000000000000000000000000000000000815250612c0f565b90506040518060600160405280612bce85600081518110612bc157612bc1613586565b6020026020010151612cba565b8152602001612be985600181518110612bc157612bc1613586565b8152602001612c0483600081518110612bc157612bc1613586565b905295945050505050565b60606000612c1d8484612d32565b9050601f1960208201600183510160051b81018651838201526001845101845260005b825160608452818114612c855760405182820380825286601f8201165b8b850181015183820152870180612c5d5750600082820160200152603f018616810160405284525b875160209490940193019050818310612c4057505050508091508251612cb357602081019150600281510382525b5092915050565b80516000907f1999999999999999999999999999999999999999999999999999999999999999825b600181019050603060ff82870151160382851185600a028281019650600983118188108317171586029550505050828110612ce257505080612d2c5763101827966000526004601cfd5b50919050565b606082518251818111612e17576020850194506020840193506020604051019250846001828488010301600060208410612d6b57508286205b601f841660200360031b87515b8951818118831c612dcd578315612dab5783878c2014612dab5760018b019a50848b10612da55750612ddc565b50612d78565b858b038952998601996020909801978615612dcd57848b10612da55750612ddc565b5060018a019950838a10612d78575b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08189030160051c8152602090970190525050505b505092915050565b604080516101c08101825260006101a08201818152825282516020808201855282825280840191909152835180820185528281528385015283518082018552828152606084015283518085019094528184528301529060808201908152602001612ea060408051606081018252600080825260208201819052909182015290565b8152602001612ec660408051606081018252600080825260208201819052909182015290565b8152602001612eec60408051606081018252600080825260208201819052909182015290565b8152602001612f1260408051606081018252600080825260208201819052909182015290565b8152604080516060808201835260008252602082810182905292820152910190815260408051602081810190925260008152910190815260006020820181905260409091015290565b60005b83811015612f76578181015183820152602001612f5e565b83811115612f85576000848401525b50505050565b60008151808452612fa3816020860160208601612f5b565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611c906020830184612f8b565b815173ffffffffffffffffffffffffffffffffffffffff1681526103608101602083015161302e602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040830151613056604084018273ffffffffffffffffffffffffffffffffffffffff169052565b50606083015161307e606084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060808301516130a6608084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060a08301516130ce60a084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060c08301516130f660c084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060e083015161311e60e084018273ffffffffffffffffffffffffffffffffffffffff169052565b506101008381015173ffffffffffffffffffffffffffffffffffffffff90811691840191909152610120808501518216908401526101408085015182169084015261016080850151821690840152610180808501518216908401526101a0808501518216908401526101c0808501518216908401526101e08085015182169084015261020080850151821690840152610220808501518216908401526102408085015182169084015261026080850151821690840152610280808501518216908401526102a0808501518216908401526102c0808501518216908401526102e0808501518216908401526103008085015182169084015261032080850151821690840152610340808501519182168185015290612e17565b60006020828403121561324857600080fd5b81518015158114611c9057600080fd5b73ffffffffffffffffffffffffffffffffffffffff8116811461059857600080fd5b60006020828403121561328c57600080fd5b8151611c9081613258565b6000602082840312156132a957600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600067ffffffffffffffff808411156132fa576132fa6132b0565b604051601f85017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715613340576133406132b0565b8160405280935085815286868601111561335957600080fd5b613367866020830187612f5b565b5050509392505050565b60006020828403121561338357600080fd5b815167ffffffffffffffff81111561339a57600080fd5b8201601f810184136133ab57600080fd5b6133ba848251602084016132df565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff841681526060602082015260006133f16060830185612f8b565b82810360408401526134038185612f8b565b9695505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff84168152602081018390526060810160028310613497577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b826040830152949350505050565b6000602082840312156134b757600080fd5b815160028110611c9057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600060ff821660ff84168060ff03821115613512576135126134c6565b019392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613552576135526134c6565b500290565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006133ba6040830184612f8b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea164736f6c634300080f000a0000000000000000000000002a5a3eabb9fd571a3af0299eebdf8eaafe29a914000000000000000000000000250af3f400cf8aac8d410c90f1ba3968dd87df96000000000000000000000000547d0fba434877d7237d511cf87fabe2ee26b152000000000000000000000000ac8538a2e6a1f5dfbb1c4b8bd97cefb2997824a8000000000000000000000000b178cdaa8336f25624a63c049edb5af7ca36c2da000000000000000000000000c053fc0155bf8bda5b568af53276e538f0ea4d58000000000000000000000000716ead0cf3e7ff86a02d4f8cb41a6d14922fa8330000000000000000000000006a97c5d55a21265326150efe12fc30fb21cbff56000000000000000000000000a0734858ba5085ff6db493021a0f8c54605c2cda00000000000000000000000027e51b2254433a3284d9ba73ea551c397db2a124000000000000000000000000a0f4ffff79a0a3e039fcbef738751efba8e84f96000000000000000000000000f43862b9d814bb4504158ceccb0b74b31265e4ee000000000000000000000000893c2ceeb71d38514daf67728d3ff1b213fc4b5f000000000000000000000000f7bed7215eef1003fac426682cf2edeb958569f7000000000000000000000000f7bed7215eef1003fac426682cf2edeb958569f7000000000000000000000000eddf416c7159387cc6df3015700f79cfb891137300000000000000000000000070de55bc0bfbc52c5d0cca1da5816c2428886a34000000000000000000000000bec660b456b84a081e90af29be43385bda5bf7b600000000000000000000000093a8a7a9c98cb998d88dba3373a6c7f8ee2e8a4600000000000000000000000037dc2fe754052a9fac35f17282599fafbeb9f423000000000000000000000000784f1fae11f1c3a9c413423fe1b370a3636b8d560000000000000000000000002f76618143d9d2731c56778192d3893864b423d7000000000000000000000000dda87ef358082ab3f4ba8982290c671efdc4d1590000000000000000000000008256398a687e740006098445b05d5ca46b7be21e0000000000000000000000008684ccc5bf484ec242dbc7119004a83533934a79000000000000000000000000906835344844979ffd3a752eaa23728d513db00b000000000000000000000000e35b194efc4907f383b7e3b87f4c2c339ce239f60000000000000000000000000000000000000000", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 4500000, + "intent": "Deploy L2ContractsManager Implementation", + "to": "0x420000000000000000000000000000000000002C" + }, + { + "data": "0x7c36f37e000000000000000000000000a723d436b320015ebead5e589c49e03131b80ee3", + "from": "0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001", + "gasLimit": 3000000, + "intent": "L2ProxyAdmin Upgrade Predeploys", + "to": "0x4200000000000000000000000000000000000018" + } + ] +} \ No newline at end of file diff --git a/op-program/Dockerfile.vmcompat b/op-program/Dockerfile.vmcompat index cdbd0136af8..7de8f1d32e0 100644 --- a/op-program/Dockerfile.vmcompat +++ b/op-program/Dockerfile.vmcompat @@ -1,9 +1,11 @@ ARG GO_VERSION=1.24.10-alpine3.21 ARG VM_TARGET=current +ARG VM_COMPAT_TASK=analyze-op-program-client FROM golang:${GO_VERSION} AS builder -# Redeclare ARG to make it available in this build stage +# Redeclare ARGs to make them available in this build stage ARG VM_TARGET +ARG VM_COMPAT_TASK # Install dependencies RUN apk add --no-cache make git bash jq llvm just @@ -31,8 +33,9 @@ WORKDIR /app/op-program ENV FINDINGS_OUTPUT_PATH=/app/op-program/vm-compat-findings.json RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build \ touch $FINDINGS_OUTPUT_PATH && \ - just "analyze-op-program-client-${VM_TARGET}"; echo $? > /app/op-program/vm-compat-exit-code + just "${VM_COMPAT_TASK}-${VM_TARGET}"; echo $? > /app/op-program/vm-compat-exit-code FROM scratch AS export COPY --from=builder /app/op-program/vm-compat-findings.json . COPY --from=builder /app/op-program/vm-compat-exit-code . +COPY --from=builder /app/op-program/compatibility-test/baseline-cannon-multithreaded-64.json . diff --git a/op-program/client/l2/engineapi/block_processor.go b/op-program/client/l2/engineapi/block_processor.go index 71e194f7279..c1d97021929 100644 --- a/op-program/client/l2/engineapi/block_processor.go +++ b/op-program/client/l2/engineapi/block_processor.go @@ -1,6 +1,7 @@ package engineapi import ( + "context" "errors" "fmt" "math/big" @@ -87,7 +88,7 @@ func NewBlockProcessorFromHeader(provider BlockDataProvider, h *types.Header) (* header.Number = new(big.Int).Add(parentHeader.Number, common.Big1) header.BaseFee = eip1559.CalcBaseFee(provider.Config(), parentHeader, header.Time) header.GasUsed = 0 - gasPool := new(core.GasPool).AddGas(header.GasLimit) + gasPool := core.NewGasPool(header.GasLimit) mkEVM := func() *vm.EVM { // Unfortunately this is not part of any Geth environment setup, // we just have to apply it, like how the Geth block-builder worker does. @@ -148,10 +149,11 @@ func (b *BlockProcessor) CheckTxWithinGasLimit(tx *types.Transaction) error { func (b *BlockProcessor) AddTx(tx *types.Transaction) (*types.Receipt, error) { txIndex := len(b.transactions) b.state.SetTxContext(tx.Hash(), txIndex) - receipt, err := core.ApplyTransaction(b.evm, b.gasPool, b.state, b.header, tx, &b.header.GasUsed) + receipt, err := core.ApplyTransaction(b.evm, b.gasPool, b.state, b.header, tx) if err != nil { return nil, fmt.Errorf("failed to apply transaction to L2 block (tx %d): %w", txIndex, err) } + b.header.GasUsed = b.gasPool.Used() b.receipts = append(b.receipts, receipt) b.transactions = append(b.transactions, tx) return receipt, nil @@ -178,7 +180,7 @@ func (b *BlockProcessor) Assemble() (*types.Block, types.Receipts, error) { } } - block, err := b.dataProvider.Engine().FinalizeAndAssemble(b.dataProvider, b.header, b.state, &body, b.receipts) + block, err := b.dataProvider.Engine().FinalizeAndAssemble(context.Background(), b.dataProvider, b.header, b.state, &body, b.receipts) if err != nil { return nil, nil, err } diff --git a/op-program/compatibility-test/baseline-cannon-multithreaded-64.json b/op-program/compatibility-test/baseline-cannon-multithreaded-64.json index d96da21bd44..d39e67b3dbd 100644 --- a/op-program/compatibility-test/baseline-cannon-multithreaded-64.json +++ b/op-program/compatibility-test/baseline-cannon-multithreaded-64.json @@ -161,6 +161,167 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "03f6054d3ceafd359f0d20f26ae776363e816cac1eefdc1444fc2328a0d4bece" }, + { + "callStack": { + "function": "syscall.lstat", + "callStack": { + "function": "syscall.Lstat", + "callStack": { + "function": "os.lstatNolog", + "callStack": { + "function": "os.Lstat", + "callStack": { + "function": "os.rename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential Incompatible Syscall Detected: 5006", + "severity": "CRITICAL", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "06ae1d22c0f1c73614b534e885f5b4db6075d279f6dffe775df78c23cf5e0eb8" + }, + { + "callStack": { + "function": "syscall.lstat", + "callStack": { + "function": "syscall.Lstat", + "callStack": { + "function": "os.lstatNolog", + "callStack": { + "function": "os.Lstat", + "callStack": { + "function": "os.rename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.reset", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential Incompatible Syscall Detected: 5006", + "severity": "CRITICAL", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "0996b58ff9dbdf45b77daa8f6146209bf63638e958dc8ee72a9b4da5f92763bd" + }, { "callStack": { "function": "syscall.Getdents", @@ -444,6 +605,91 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "0f56d4e8e81f5e0c3269a52f5765470380a9dc5219a365b5557faa140abe826c" }, + { + "callStack": { + "function": "syscall.lstat", + "callStack": { + "function": "syscall.Lstat", + "callStack": { + "function": "os.lstatNolog", + "callStack": { + "function": "os.Lstat", + "callStack": { + "function": "os.rename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential Incompatible Syscall Detected: 5006", + "severity": "CRITICAL", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "0fa8a9246a03516588d4a1760b9cb6120c0fc83f032a8ac57d67beb819c43a54" + }, { "callStack": { "function": "syscall.Getdents", @@ -1063,49 +1309,55 @@ }, { "callStack": { - "function": "syscall.lstat", + "function": "syscall.Renameat", "callStack": { - "function": "syscall.Lstat", + "function": "os.rename", "callStack": { - "function": "os.lstatNolog", + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", "callStack": { - "function": "os.Lstat", + "function": "github.com/ethereum/go-ethereum/core/rawdb.reset", "callStack": { - "function": "os.MkdirAll", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", "callStack": { - "function": "main.main" + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } } } } @@ -1128,25 +1380,98 @@ } } }, - "message": "Potential Incompatible Syscall Detected: 5006", + "message": "Potential Incompatible Syscall Detected: 5254", "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "2c98b4018477201b7ce1133d2bda2e1ca0724645155e2352b6c087db6efba866" + "hash": "2b22c1446e342415958c2a2d3fe3fee1e2a2d79c22512331600e50b0fa16cb5b" }, { "callStack": { - "function": "syscall.Fsync", + "function": "syscall.lstat", "callStack": { - "function": "internal/poll.(*FD).Fsync", + "function": "syscall.Lstat", "callStack": { - "function": "os.(*File).Sync", + "function": "os.lstatNolog", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTableMeta).write", + "function": "os.Lstat", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "function": "os.MkdirAll", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential Incompatible Syscall Detected: 5006", + "severity": "CRITICAL", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "2c98b4018477201b7ce1133d2bda2e1ca0724645155e2352b6c087db6efba866" + }, + { + "callStack": { + "function": "syscall.Fsync", + "callStack": { + "function": "internal/poll.(*FD).Fsync", + "callStack": { + "function": "os.(*File).Sync", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTableMeta).write", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", "callStack": { "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { @@ -1457,6 +1782,82 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "38cd7836fbadcf343f4d284aa10b7dc8a1eec575e9418b2693cc06699d24f1db" }, + { + "callStack": { + "function": "syscall.Renameat", + "callStack": { + "function": "os.rename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential Incompatible Syscall Detected: 5254", + "severity": "CRITICAL", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "3b5c34daa2681b5a44c61c53e3712bf443f75a565e3f474807eacc066ee3f5e6" + }, { "callStack": { "function": "syscall.unlinkat", @@ -2427,6 +2828,76 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "5aa4ea1867769c886a8ee4d9e50a4c84af6eb8375ac0fec45cb04006c8689b32" }, + { + "callStack": { + "function": "syscall.Renameat", + "callStack": { + "function": "os.rename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential Incompatible Syscall Detected: 5254", + "severity": "CRITICAL", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "61f3423bb7162c0f7dfcf8406644452ff6f0e95195a4a581dce0891b29c52d00" + }, { "callStack": { "function": "syscall.getsockname", @@ -2958,11 +3429,11 @@ "callStack": { "function": "os.Lstat", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.cleanup", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", "callStack": { "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { @@ -2972,27 +3443,21 @@ "callStack": { "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } + "function": "main.main" } } } @@ -3016,157 +3481,23 @@ "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "6d5047b0af006821b7cc913288761108f536df9958ba8b5ad350a765cec6c6f3" + "hash": "6d87b8772a23ccd1f6646911bfd16f29f4da1c80302c3d122b82d186d4ba3d32" }, { "callStack": { - "function": "syscall.lstat", + "function": "syscall.Mkdirat", "callStack": { - "function": "syscall.Lstat", + "function": "os.MkdirAll", "callStack": { - "function": "os.lstatNolog", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { - "function": "os.Lstat", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - }, - "message": "Potential Incompatible Syscall Detected: 5006", - "severity": "CRITICAL", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "6d87b8772a23ccd1f6646911bfd16f29f4da1c80302c3d122b82d186d4ba3d32" - }, - { - "callStack": { - "function": "syscall.lstat", - "callStack": { - "function": "syscall.Lstat", - "callStack": { - "function": "os.lstatNolog", - "callStack": { - "function": "os.Lstat", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.cleanup", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - }, - "message": "Potential Incompatible Syscall Detected: 5006", - "severity": "CRITICAL", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "6dd853e3a5b17ed9b4b5dd2ee09ae51b202df9f3bd1b878aab86b7b5142345ba" - }, - { - "callStack": { - "function": "syscall.Mkdirat", - "callStack": { - "function": "os.MkdirAll", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { @@ -3210,73 +3541,6 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "6df1d7fe5b04c477158fbb622ffb2e20d12cde4a5d5e575ee66cf4aea5fa5941" }, - { - "callStack": { - "function": "syscall.Renameat", - "callStack": { - "function": "os.rename", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - }, - "message": "Potential Incompatible Syscall Detected: 5254", - "severity": "CRITICAL", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "7264bfa70c46f9429fae6fcfabbb33969282137e01a60e0e616fe1c705fe7c2e" - }, { "callStack": { "function": "syscall.unlinkat", @@ -3551,6 +3815,79 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "778448042d300f48cbfd803335851bbaf68d15e117bdd66c228c59bd6fb8f5db" }, + { + "callStack": { + "function": "syscall.Renameat", + "callStack": { + "function": "os.rename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.reset", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential Incompatible Syscall Detected: 5254", + "severity": "CRITICAL", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "78716f755caf94c6c96b11050154bc60dcb4ce95940f4c9fc707b81a134478b7" + }, { "callStack": { "function": "syscall.lstat", @@ -3561,35 +3898,59 @@ "callStack": { "function": "os.Lstat", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.cleanup", + "function": "os.rename", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.reset", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", "callStack": { - "function": "main.main" + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } } } } @@ -3613,7 +3974,7 @@ "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "7b89a7bb52f9d3eed3ae13645aaa749b11ce906c25ed416cfcc53df7bee9a636" + "hash": "7b57d9f36615c7f04a543ef1907e0a7737d9ed8aea1b74744d5c1ec8750e3cad" }, { "callStack": { @@ -3783,11 +4144,90 @@ } } }, - "message": "Potential Incompatible Syscall Detected: 5248", + "message": "Potential Incompatible Syscall Detected: 5248", + "severity": "CRITICAL", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "82e9dbb73a6d10e905a534b271e67ccf5b62f19143fd7298b83a684dea6d7d15" + }, + { + "callStack": { + "function": "syscall.lstat", + "callStack": { + "function": "syscall.Lstat", + "callStack": { + "function": "os.lstatNolog", + "callStack": { + "function": "os.Lstat", + "callStack": { + "function": "os.rename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential Incompatible Syscall Detected: 5006", "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "82e9dbb73a6d10e905a534b271e67ccf5b62f19143fd7298b83a684dea6d7d15" + "hash": "8412c11a24a875e9d52d1633ecf24a20bca0cbff3fe5bb14fd631f9202706125" }, { "callStack": { @@ -3923,99 +4363,35 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "89aed313797fadc49483285b760c7f4db04a02d4becda9527e90f90c8777d596" }, - { - "callStack": { - "function": "syscall.lstat", - "callStack": { - "function": "syscall.Lstat", - "callStack": { - "function": "os.lstatNolog", - "callStack": { - "function": "os.Lstat", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.cleanup", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - }, - "message": "Potential Incompatible Syscall Detected: 5006", - "severity": "CRITICAL", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "8a7a2d8f73ec3aa3965a28c463f58beee81aca199ade15ae318b01f9cb26d6ca" - }, { "callStack": { "function": "syscall.Renameat", "callStack": { "function": "os.rename", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "function": "github.com/ethereum/go-ethereum/core/rawdb.reset", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", "callStack": { @@ -4058,7 +4434,7 @@ "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "8f8d0e96f43d447cb45e3b02240ad9c72b8550eb34338f645fc7fd5cd72c5d80" + "hash": "8a0fe9cd4a47c59d80a971cbc9364081ef57e2b82cbf395596dbe6275fc6ff6f" }, { "callStack": { @@ -5709,45 +6085,66 @@ }, { "callStack": { - "function": "internal/syscall/unix.Unlinkat", + "function": "syscall.lstat", "callStack": { - "function": "os.removeAllFrom", + "function": "syscall.Lstat", "callStack": { - "function": "os.removeAll", + "function": "os.lstatNolog", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.cleanup", + "function": "os.Lstat", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "os.rename", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "github.com/ethereum/go-ethereum/core/rawdb.reset", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", "callStack": { - "function": "main.main" + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } } } } @@ -5768,37 +6165,37 @@ } } }, - "message": "Potential Incompatible Syscall Detected: 5253", + "message": "Potential Incompatible Syscall Detected: 5006", "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "c8633d83d79a6b6e7a95595faed154b929aad5fb5df4ae8b563997f8b40a81d2" + "hash": "c426099923bba4df822f5f375db183685b2c1b9e64ebb329721153c1b16ba727" }, { "callStack": { - "function": "syscall.Renameat", + "function": "internal/syscall/unix.Unlinkat", "callStack": { - "function": "os.rename", + "function": "os.removeAllFrom", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", + "function": "os.removeAll", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "function": "github.com/ethereum/go-ethereum/core/rawdb.cleanup", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", "callStack": { "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", "callStack": { @@ -5835,27 +6232,27 @@ } } }, - "message": "Potential Incompatible Syscall Detected: 5254", + "message": "Potential Incompatible Syscall Detected: 5253", "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "c9b1d2531f91d2624fafd956e704578acfabc1e8dc8397f304cc3c3227d1eaa0" + "hash": "c8633d83d79a6b6e7a95595faed154b929aad5fb5df4ae8b563997f8b40a81d2" }, { "callStack": { - "function": "syscall.Ftruncate", + "function": "syscall.Renameat", "callStack": { - "function": "internal/poll.(*FD).Ftruncate", + "function": "os.rename", "callStack": { - "function": "os.(*File).Truncate", + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.truncateFreezerFile", + "function": "github.com/ethereum/go-ethereum/core/rawdb.reset", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).repairIndex", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).repair", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", "callStack": { "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { @@ -5871,21 +6268,27 @@ "callStack": { "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", "callStack": { - "function": "main.main" + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } } } } @@ -5908,53 +6311,59 @@ } } }, - "message": "Potential Incompatible Syscall Detected: 5075", + "message": "Potential Incompatible Syscall Detected: 5254", "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "cc8b4fb7fc2f9643461d8f404983e85ba0dadace4e9a7f20ac5abb9a9d166eb3" + "hash": "c9d98ec1249362ee6592736b088f256e856fdacf8eb8c0fa286c253713b38153" }, { "callStack": { - "function": "syscall.unlinkat", + "function": "syscall.Ftruncate", "callStack": { - "function": "os.Remove", + "function": "internal/poll.(*FD).Ftruncate", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).releaseFilesAfter", + "function": "os.(*File).Truncate", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).repair", + "function": "github.com/ethereum/go-ethereum/core/rawdb.truncateFreezerFile", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).repairIndex", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).repair", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", "callStack": { - "function": "main.main" + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } } } } @@ -5975,11 +6384,11 @@ } } }, - "message": "Potential Incompatible Syscall Detected: 5253", + "message": "Potential Incompatible Syscall Detected: 5075", "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "cc997c8afa8cc133e5902d41917b914718f94101f2833671821d7f781e6f00c6" + "hash": "cc8b4fb7fc2f9643461d8f404983e85ba0dadace4e9a7f20ac5abb9a9d166eb3" }, { "callStack": { @@ -5987,7 +6396,7 @@ "callStack": { "function": "os.Remove", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).releaseFilesBefore", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).releaseFilesAfter", "callStack": { "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).repair", "callStack": { @@ -5997,7 +6406,7 @@ "callStack": { "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", "callStack": { "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { @@ -6046,7 +6455,7 @@ "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "cd18f32ac0a8a69bf5e43077e0c0a705179b1bbe54a06d3909559f5f9579e48e" + "hash": "cc997c8afa8cc133e5902d41917b914718f94101f2833671821d7f781e6f00c6" }, { "callStack": { @@ -6054,7 +6463,7 @@ "callStack": { "function": "os.Remove", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).releaseFilesAfter", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).releaseFilesBefore", "callStack": { "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).repair", "callStack": { @@ -6113,7 +6522,7 @@ "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "d00bd4d597f84c2993473ae7955ef6f975124fd6ee0d68efebe11432d91b397b" + "hash": "cd18f32ac0a8a69bf5e43077e0c0a705179b1bbe54a06d3909559f5f9579e48e" }, { "callStack": { @@ -6123,15 +6532,15 @@ "callStack": { "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).releaseFilesAfter", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateHead", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).repair", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", "callStack": { "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", "callStack": { "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { @@ -6180,58 +6589,49 @@ "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "d09e885be58cf98cdf33889948720f65e679f2fa36f273ce8853cacfe094f559" + "hash": "d00bd4d597f84c2993473ae7955ef6f975124fd6ee0d68efebe11432d91b397b" }, { "callStack": { - "function": "syscall.lstat", + "function": "syscall.unlinkat", "callStack": { - "function": "syscall.Lstat", + "function": "os.Remove", "callStack": { - "function": "os.lstatNolog", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).releaseFilesAfter", "callStack": { - "function": "os.Lstat", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateHead", "callStack": { - "function": "os.rename", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } - } + "function": "main.main" } } } @@ -6252,11 +6652,11 @@ } } }, - "message": "Potential Incompatible Syscall Detected: 5006", + "message": "Potential Incompatible Syscall Detected: 5253", "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "d686f160fce1c757640f7bd3cf27a9bcef6be580d9013eb97c5d90e3894e3353" + "hash": "d09e885be58cf98cdf33889948720f65e679f2fa36f273ce8853cacfe094f559" }, { "callStack": { @@ -6328,79 +6728,6 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "d989a5623edef4b247a30334fc72fc256705ebd0248dfbbcc8f3af968e4e0aa2" }, - { - "callStack": { - "function": "syscall.Renameat", - "callStack": { - "function": "os.rename", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - }, - "message": "Potential Incompatible Syscall Detected: 5254", - "severity": "CRITICAL", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "dc67d1106742a2d594a32323fb1fc0a8a708dc1269d21e8a40d7828efe6a4e11" - }, { "callStack": { "function": "golang.org/x/sys/unix.Flock", @@ -6742,6 +7069,88 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "e2931e3ca1b5c4bf301ab7cfa9c2f36c6b1530ccf650e232deba012586ee63da" }, + { + "callStack": { + "function": "syscall.lstat", + "callStack": { + "function": "syscall.Lstat", + "callStack": { + "function": "os.lstatNolog", + "callStack": { + "function": "os.Lstat", + "callStack": { + "function": "os.rename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.reset", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential Incompatible Syscall Detected: 5006", + "severity": "CRITICAL", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "e7cfe92b0bf574605afe59d9486f60bef5fb314999f59f750026a7ffd7bfa915" + }, { "callStack": { "function": "syscall.sendto", @@ -6798,11 +7207,81 @@ } } }, - "message": "Potential Incompatible Syscall Detected: 5050", + "message": "Potential Incompatible Syscall Detected: 5050", + "severity": "CRITICAL", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "eb3121306d79c84b8f563cde55139daae0c0c84d01e15d996d229beb70b06ffd" + }, + { + "callStack": { + "function": "syscall.Renameat", + "callStack": { + "function": "os.rename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential Incompatible Syscall Detected: 5254", "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "eb3121306d79c84b8f563cde55139daae0c0c84d01e15d996d229beb70b06ffd" + "hash": "ebac7f7a781278a9fd169f67e2bf60731c703a46985a763c6165d208acdb30df" }, { "callStack": { @@ -6941,6 +7420,82 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "eded605ed37bcf2d0ce4a8b37be3f344c36d4e4ab9aa80e1040de8bdcd498f68" }, + { + "callStack": { + "function": "syscall.Renameat", + "callStack": { + "function": "os.rename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential Incompatible Syscall Detected: 5254", + "severity": "CRITICAL", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "f0fa68c170ab0df57af3bad8c760d1dba7c80f44fc36e797a6c87a8002876770" + }, { "callStack": { "function": "syscall.Ftruncate", @@ -7090,45 +7645,48 @@ "callStack": { "function": "os.rename", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", + "function": "github.com/ethereum/go-ethereum/core/rawdb.atomicRename", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", "callStack": { - "function": "main.main" + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } } } } @@ -7158,7 +7716,7 @@ "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "f3a50db8c83833e7d4c35d7a6478aff93d9cd4c1c3eb1f743f5f1279735f69ae" + "hash": "f4bf045e983c5146fa01ea1b023acb1a2ef3c29012b7cc969c966c5c6df0aaa4" }, { "callStack": { @@ -7213,189 +7771,31 @@ "callStack": { "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - }, - "message": "Potential Incompatible Syscall Detected: 5072", - "severity": "CRITICAL", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "f65acfc158aa93245e1a287676efcd7cafc14d65a2d2c2b9da5dc114e016c55c" - }, - { - "callStack": { - "function": "syscall.lstat", - "callStack": { - "function": "syscall.Lstat", - "callStack": { - "function": "os.lstatNolog", - "callStack": { - "function": "os.Lstat", - "callStack": { - "function": "os.rename", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - }, - "message": "Potential Incompatible Syscall Detected: 5006", - "severity": "CRITICAL", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "fdbf630978d296817cc6c5ef543cefc7b7961bf3fd35b783c96a05d7564e7554" - }, - { - "callStack": { - "function": "syscall.lstat", - "callStack": { - "function": "syscall.Lstat", - "callStack": { - "function": "os.lstatNolog", - "callStack": { - "function": "os.Lstat", - "callStack": { - "function": "os.rename", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.copyFrom", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } + "function": "main.main" } } } @@ -7419,11 +7819,11 @@ } } }, - "message": "Potential Incompatible Syscall Detected: 5006", + "message": "Potential Incompatible Syscall Detected: 5072", "severity": "CRITICAL", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "ff622f26ef2663958e5f8aa8ac981fd832eff1a3dc04fbc9cc0b6030f9d2be67" + "hash": "f65acfc158aa93245e1a287676efcd7cafc14d65a2d2c2b9da5dc114e016c55c" }, { "callStack": { @@ -7974,6 +8374,91 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "09d1aa443d0f4b91a7a8ffad94aca2804b98bead8b6569ef94ad238892760e3f" }, + { + "callStack": { + "function": "runtime.netpollclose", + "callStack": { + "function": "internal/poll.runtime_pollClose", + "callStack": { + "function": "internal/poll.(*FD).destroy", + "callStack": { + "function": "internal/poll.(*FD).decref", + "callStack": { + "function": "internal/poll.(*FD).Close", + "callStack": { + "function": "os.(*file).close", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential NOOP Syscall Detected: 5208", + "severity": "WARNING", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "0aa642315864f7a6cea348d9b0223af648aa8c1e145272f76147904e78476bac" + }, { "callStack": { "function": "runtime.rtsigprocmask", @@ -8223,88 +8708,6 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "0fd0807c39d90eac11f7ba18640a8d84c4ff43e4f0ee5a0a3d241d0c221cdbe6" }, - { - "callStack": { - "function": "runtime.netpollclose", - "callStack": { - "function": "internal/poll.runtime_pollClose", - "callStack": { - "function": "internal/poll.(*FD).destroy", - "callStack": { - "function": "internal/poll.(*FD).decref", - "callStack": { - "function": "internal/poll.(*FD).Close", - "callStack": { - "function": "os.(*file).close", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).Close", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - }, - "message": "Potential NOOP Syscall Detected: 5208", - "severity": "WARNING", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "10381145148ea319e3bb3b16d0a8394de1387598cfaa2eafb8540d143859dc9d" - }, { "callStack": { "function": "syscall.Seek", @@ -8913,127 +9316,45 @@ "callStack": { "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).getIndices", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).sizeHidden", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).sizeNolock", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - }, - "message": "Potential NOOP Syscall Detected: 5016", - "severity": "WARNING", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "1a17f6a4426d46a98775a92be872adda56c37eae7e8d7500ff962b3742fd03d4" - }, - { - "callStack": { - "function": "runtime.netpollclose", - "callStack": { - "function": "internal/poll.runtime_pollClose", - "callStack": { - "function": "internal/poll.(*FD).destroy", - "callStack": { - "function": "internal/poll.(*FD).decref", - "callStack": { - "function": "internal/poll.(*FD).Close", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).sizeHidden", "callStack": { - "function": "os.(*file).close", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).sizeNolock", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).Close", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } + "function": "main.main" } } } @@ -9058,11 +9379,11 @@ } } }, - "message": "Potential NOOP Syscall Detected: 5208", + "message": "Potential NOOP Syscall Detected: 5016", "severity": "WARNING", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "1c8054618e5968fa625805588ab6e40d870aaacf30b4d508f5013c32bf6c21ec" + "hash": "1a17f6a4426d46a98775a92be872adda56c37eae7e8d7500ff962b3742fd03d4" }, { "callStack": { @@ -9413,68 +9734,6 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "25aa292de24f2ca6b4287b07e22698bbcf7879d563a237abd6100e67c35e74b1" }, - { - "callStack": { - "function": "syscall.openat", - "callStack": { - "function": "os.open", - "callStack": { - "function": "os.openFileNolog", - "callStack": { - "function": "os.OpenFile", - "callStack": { - "function": "github.com/tklauser/numcpus.getConfigured", - "callStack": { - "function": "github.com/tklauser/go-sysconf.getNprocsConf", - "callStack": { - "function": "github.com/tklauser/go-sysconf.sysconf", - "callStack": { - "function": "github.com/shirou/gopsutil/cpu.init.1" - } - } - } - } - } - } - } - }, - "message": "Potential NOOP Syscall Detected: 5247", - "severity": "WARNING", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "25cc5ca17434c74a54e80ce5d474e3147988aaf330ec85bf8917387940beff93" - }, - { - "callStack": { - "function": "syscall.openat", - "callStack": { - "function": "os.open", - "callStack": { - "function": "os.openFileNolog", - "callStack": { - "function": "os.OpenFile", - "callStack": { - "function": "github.com/tklauser/go-sysconf.getNprocsProcStat", - "callStack": { - "function": "github.com/tklauser/go-sysconf.getNprocs", - "callStack": { - "function": "github.com/tklauser/go-sysconf.sysconf", - "callStack": { - "function": "github.com/shirou/gopsutil/cpu.init.1" - } - } - } - } - } - } - } - }, - "message": "Potential NOOP Syscall Detected: 5247", - "severity": "WARNING", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "264a9b6bf20decd921bcba30b021003c7e58808a9e6255df08fb2d477d5d7e41" - }, { "callStack": { "function": "syscall.pread", @@ -10496,19 +10755,19 @@ }, { "callStack": { - "function": "runtime.netpollclose", + "function": "syscall.Seek", "callStack": { - "function": "internal/poll.runtime_pollClose", + "function": "internal/poll.(*FD).Seek", "callStack": { - "function": "internal/poll.(*FD).destroy", + "function": "os.(*File).seek", "callStack": { - "function": "internal/poll.(*FD).decref", + "function": "os.(*File).Seek", "callStack": { - "function": "internal/poll.(*FD).Close", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTableMeta).write", "callStack": { - "function": "os.(*file).close", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).repairIndex", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).Close", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).repair", "callStack": { "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", "callStack": { @@ -10516,7 +10775,7 @@ "callStack": { "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", "callStack": { "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { @@ -10564,63 +10823,97 @@ } } }, - "message": "Potential NOOP Syscall Detected: 5208", + "message": "Potential NOOP Syscall Detected: 5008", "severity": "WARNING", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "3db51aeb89a6648e72f98a600abe8652c317376f06e37993409d1cc8123a8f3e" + "hash": "3e403a72c8f935204762e029beeea1b4a22a00024b177e59222ca42e3015fb62" }, { "callStack": { - "function": "syscall.Seek", + "function": "runtime.netpollinit", "callStack": { - "function": "internal/poll.(*FD).Seek", + "function": "runtime.netpollGenericInit", "callStack": { - "function": "os.(*File).seek", + "function": "runtime.(*timers).addHeap", "callStack": { - "function": "os.(*File).Seek", + "function": "runtime.(*timer).maybeAdd", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTableMeta).write", + "function": "runtime.(*timer).modify", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).repairIndex", + "function": "time.newTimer", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).repair", + "function": "time.AfterFunc", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", + "function": "crypto/internal/sysrand.Read", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "function": "crypto/internal/entropy.Depleted", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "crypto/internal/fips140/drbg.Read", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "function": "crypto/internal/fips140/drbg.ReadWithReader", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "crypto/internal/fips140/ecdh.GenerateKey[go.shape.*crypto/internal/fips140/nistec.P256Point]", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "crypto/ecdh.init.func1" + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential NOOP Syscall Detected: 5285", + "severity": "WARNING", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "3fa4d4cf151ccbb224d20c5639a72db890cce8eb061595c1b12912252752ed2e" + }, + { + "callStack": { + "function": "internal/syscall/unix.Openat", + "callStack": { + "function": "os.openDirAt", + "callStack": { + "function": "os.removeAllFrom", + "callStack": { + "function": "os.removeAll", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.cleanup", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } - } - } + "function": "main.main" } } } @@ -10640,39 +10933,66 @@ } } }, - "message": "Potential NOOP Syscall Detected: 5008", + "message": "Potential NOOP Syscall Detected: 5247", "severity": "WARNING", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "3e403a72c8f935204762e029beeea1b4a22a00024b177e59222ca42e3015fb62" + "hash": "3ff85d066f3a8e5eeceadcafd8ab19c9f18bae5eb59270a54d4a629fdd6a5cec" }, { "callStack": { - "function": "runtime.netpollinit", + "function": "syscall.Seek", "callStack": { - "function": "runtime.netpollGenericInit", + "function": "internal/poll.(*FD).Seek", "callStack": { - "function": "runtime.(*timers).addHeap", + "function": "os.(*File).seek", "callStack": { - "function": "runtime.(*timer).maybeAdd", + "function": "os.(*File).Seek", "callStack": { - "function": "runtime.(*timer).modify", + "function": "github.com/ethereum/go-ethereum/core/rawdb.decodeV1", "callStack": { - "function": "time.newTimer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newMetadata", "callStack": { - "function": "time.AfterFunc", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", "callStack": { - "function": "crypto/internal/sysrand.Read", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { - "function": "crypto/internal/entropy.Depleted", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "crypto/internal/fips140/drbg.Read", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", "callStack": { - "function": "crypto/internal/fips140/drbg.ReadWithReader", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "crypto/internal/fips140/ecdh.GenerateKey[go.shape.*crypto/internal/fips140/nistec.P256Point]", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "crypto/ecdh.init.func1" + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } } } } @@ -10686,51 +11006,72 @@ } } }, - "message": "Potential NOOP Syscall Detected: 5285", + "message": "Potential NOOP Syscall Detected: 5008", "severity": "WARNING", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "3fa4d4cf151ccbb224d20c5639a72db890cce8eb061595c1b12912252752ed2e" + "hash": "4073c2fd1c0a33923b3f4b1133ad274f7e6d9c6fb63934b178deeb43ab91c525" }, { "callStack": { - "function": "internal/syscall/unix.Openat", + "function": "runtime.netpollclose", "callStack": { - "function": "os.openDirAt", + "function": "internal/poll.runtime_pollClose", "callStack": { - "function": "os.removeAllFrom", + "function": "internal/poll.(*FD).destroy", "callStack": { - "function": "os.removeAll", + "function": "internal/poll.(*FD).decref", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.cleanup", + "function": "internal/poll.(*FD).Close", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "os.(*file).close", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", "callStack": { - "function": "main.main" + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } } } } @@ -10750,57 +11091,63 @@ } } }, - "message": "Potential NOOP Syscall Detected: 5247", + "message": "Potential NOOP Syscall Detected: 5208", "severity": "WARNING", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "3ff85d066f3a8e5eeceadcafd8ab19c9f18bae5eb59270a54d4a629fdd6a5cec" + "hash": "411c4d176eaff3c3b1554710268b4a624c1b39229515fd631d78dcdd447f59b5" }, { "callStack": { - "function": "syscall.Seek", + "function": "syscall.openat", "callStack": { - "function": "internal/poll.(*FD).Seek", + "function": "os.open", "callStack": { - "function": "os.(*File).seek", + "function": "os.openFileNolog", "callStack": { - "function": "os.(*File).Seek", + "function": "os.OpenFile", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.decodeV1", + "function": "os.CreateTemp", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newMetadata", + "function": "github.com/ethereum/go-ethereum/core/rawdb.reset", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", "callStack": { - "function": "main.main" + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } } } } @@ -10823,11 +11170,11 @@ } } }, - "message": "Potential NOOP Syscall Detected: 5008", + "message": "Potential NOOP Syscall Detected: 5247", "severity": "WARNING", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "4073c2fd1c0a33923b3f4b1133ad274f7e6d9c6fb63934b178deeb43ab91c525" + "hash": "4411d60f4ac9fe15bdc7f0c0a39f507f1c4b7fd0aa136835f3bfcea28542dd1f" }, { "callStack": { @@ -12141,6 +12488,91 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "5d3a689f37f13e8a93edd916d12bd088bc169370b839012a3d70c80605f7ce25" }, + { + "callStack": { + "function": "syscall.openat", + "callStack": { + "function": "os.open", + "callStack": { + "function": "os.openFileNolog", + "callStack": { + "function": "os.OpenFile", + "callStack": { + "function": "os.CreateTemp", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.reset", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential NOOP Syscall Detected: 5247", + "severity": "WARNING", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "60037b72581e16f39e1686ca7432c99a9d7d77df96c7ddba2a221b0bccbe0bc1" + }, { "callStack": { "function": "syscall.pread", @@ -13249,6 +13681,85 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "76a0cd291d7265fc9d42368b7a805c38ae68d7c749a13ded8197d58edd41fcbb" }, + { + "callStack": { + "function": "runtime.netpollclose", + "callStack": { + "function": "internal/poll.runtime_pollClose", + "callStack": { + "function": "internal/poll.(*FD).destroy", + "callStack": { + "function": "internal/poll.(*FD).decref", + "callStack": { + "function": "internal/poll.(*FD).Close", + "callStack": { + "function": "os.(*file).close", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewTrienodeFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential NOOP Syscall Detected: 5208", + "severity": "WARNING", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "7958ada6f12bf691f2b12e9b1f747a24d155195af86aaad97c8851bdbaf0dc1a" + }, { "callStack": { "function": "syscall.pread", @@ -13842,11 +14353,68 @@ "callStack": { "function": "os.OpenFile", "callStack": { - "function": "github.com/shirou/gopsutil/internal/common.ReadLinesOffsetN", + "function": "os.CreateTemp", "callStack": { - "function": "github.com/shirou/gopsutil/cpu.TimesWithContext", + "function": "github.com/ethereum/go-ethereum/core/rawdb.reset", "callStack": { - "function": "github.com/shirou/gopsutil/cpu.init.0" + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).loadTransactions", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).consolidatedBlockByHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } } } } @@ -13858,7 +14426,7 @@ "severity": "WARNING", "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "8d38f688701e814346859fe44684daab1dc85265ed6085e72bed1fdca7229992" + "hash": "8f1b3fc4a8635bc8496e217b9f22ca9d3d9865998f118bbf5b29f73ba7d37e0a" }, { "callStack": { @@ -15793,6 +16361,85 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "b2c474a2b17e727e61438a03388c628428fccb788724919cb730454782a06291" }, + { + "callStack": { + "function": "runtime.netpollclose", + "callStack": { + "function": "internal/poll.runtime_pollClose", + "callStack": { + "function": "internal/poll.(*FD).destroy", + "callStack": { + "function": "internal/poll.(*FD).decref", + "callStack": { + "function": "internal/poll.(*FD).Close", + "callStack": { + "function": "os.(*file).close", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential NOOP Syscall Detected: 5208", + "severity": "WARNING", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "b3e41a10c92847dc56df6b5179354de7e286cbe71c442dc60dbb8c988e9c409d" + }, { "callStack": { "function": "runtime.netpollinit", @@ -16679,82 +17326,6 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "cfb2a6ede71f8e6eb371e21eaf0e5bdaae0f030459703325666debde21f72ab6" }, - { - "callStack": { - "function": "runtime.netpollclose", - "callStack": { - "function": "internal/poll.runtime_pollClose", - "callStack": { - "function": "internal/poll.(*FD).destroy", - "callStack": { - "function": "internal/poll.(*FD).decref", - "callStack": { - "function": "internal/poll.(*FD).Close", - "callStack": { - "function": "os.(*file).close", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).Close", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newTable", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", - "callStack": { - "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", - "callStack": { - "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", - "callStack": { - "function": "main.main" - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - }, - "message": "Potential NOOP Syscall Detected: 5208", - "severity": "WARNING", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "d251796d0ea009aca0fd38f5a7077750b11a78b763a676cee7dac43fb43615ff" - }, { "callStack": { "function": "runtime.netpollclose", @@ -17643,6 +18214,85 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "e765d842c669be18a8bd4092a0a168e55aaf724ff54d00020da8ca27b872f888" }, + { + "callStack": { + "function": "syscall.openat", + "callStack": { + "function": "os.open", + "callStack": { + "function": "os.openFileNolog", + "callStack": { + "function": "os.OpenFile", + "callStack": { + "function": "os.CreateTemp", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.reset", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).resetTo", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*freezerTable).truncateTail", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.(*Freezer).repair", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.newResettableFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/core/rawdb.NewStateFreezer", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.repairHistory", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb/pathdb.New", + "callStack": { + "function": "github.com/ethereum/go-ethereum/triedb.NewDatabase", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/mpt.ReadTrie", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.(*ConsolidateOracle).ReceiptsByBlockHash", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.singleRoundConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.RunConsolidation", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.stateTransition", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client/interop.runInteropProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.RunProgram", + "callStack": { + "function": "github.com/ethereum-optimism/optimism/op-program/client.Main", + "callStack": { + "function": "main.main" + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + }, + "message": "Potential NOOP Syscall Detected: 5247", + "severity": "WARNING", + "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", + "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", + "hash": "ebe12d2516a9f6cffdfb698c5c027d3b14fc8afcf7d2168dbd7e7da3100124b8" + }, { "callStack": { "function": "syscall.pread", @@ -17786,40 +18436,6 @@ "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", "hash": "eee60140bf86c881f8591fb1a8fc80b0e98758fa1ce3d71d087d18b8f45d143b" }, - { - "callStack": { - "function": "syscall.openat", - "callStack": { - "function": "os.open", - "callStack": { - "function": "os.openFileNolog", - "callStack": { - "function": "os.OpenFile", - "callStack": { - "function": "github.com/tklauser/go-sysconf.getNprocsProcStat", - "callStack": { - "function": "github.com/tklauser/go-sysconf.getNprocs", - "callStack": { - "function": "github.com/tklauser/go-sysconf.getNprocsConf", - "callStack": { - "function": "github.com/tklauser/go-sysconf.sysconf", - "callStack": { - "function": "github.com/shirou/gopsutil/cpu.init.1" - } - } - } - } - } - } - } - } - }, - "message": "Potential NOOP Syscall Detected: 5247", - "severity": "WARNING", - "impact": "This syscall is present in the program, but its execution depends on the actual runtime behavior. \n If the execution path does not reach this syscall, it may not affect execution.", - "reference": "https://github.com/ChainSafe/vm-compat?tab=readme-ov-file#how-it-works", - "hash": "f22bbb65001661cbee435b60d3b67dc0de1d695dfc5a80dab1094098648b204d" - }, { "callStack": { "function": "runtime.netpollinit", diff --git a/op-program/host/common/l2_store.go b/op-program/host/common/l2_store.go index b9333b1ca66..3ce96ab369e 100644 --- a/op-program/host/common/l2_store.go +++ b/op-program/host/common/l2_store.go @@ -127,3 +127,6 @@ func (b *batch) Replay(w ethdb.KeyValueWriter) error { } return nil } + +func (b *batch) Close() { +} diff --git a/op-program/justfile b/op-program/justfile index fcf443e4859..dc2694e2dcb 100644 --- a/op-program/justfile +++ b/op-program/justfile @@ -164,6 +164,22 @@ verify-compat: verify-mainnet-genesis verify-sepolia-delta verify-sepolia-ecoton analyze-op-program-client-current: ./scripts/run-static-analysis.sh ./vm-profiles/cannon-multithreaded-64.yaml ./compatibility-test/baseline-cannon-multithreaded-64.json +# Regenerate the current baseline (full report without baseline, then normalize) +regenerate-baseline-current: + #!/usr/bin/env bash + set -euo pipefail + FULL_REPORT=$(mktemp) + # Run without baseline — will exit 1 since all findings are "new", which is expected + FINDINGS_OUTPUT_PATH="$FULL_REPORT" ./scripts/run-static-analysis.sh ./vm-profiles/cannon-multithreaded-64.yaml || true + # Strip assembly-level fields that cause false positives when they change + jq 'walk( + if type == "object" and has("line") then del(.line) else . end | + if type == "object" and has("absPath") then del(.absPath) else . end | + if type == "object" and has("file") then del(.file) else . end + )' "$FULL_REPORT" > ./compatibility-test/baseline-cannon-multithreaded-64.json + rm -f "$FULL_REPORT" + echo "Baseline regenerated: ./compatibility-test/baseline-cannon-multithreaded-64.json ($(jq length ./compatibility-test/baseline-cannon-multithreaded-64.json) entries)" + # Analyze next op-program client for VM compatibility analyze-op-program-client-next: ./scripts/run-static-analysis.sh ./vm-profiles/cannon-multithreaded-64-next.yaml ./compatibility-test/baseline-cannon-multithreaded-64-next.json @@ -181,3 +197,16 @@ run-vm-compat: # TODO(#18334): Uncomment once vm-compat supports go1.25 #@docker build --build-arg GO_VERSION=1.25.4-alpine3.21 --build-arg VM_TARGET=next --progress plain --output "{{VM_COMPAT_OUTPUT_DIR}}" -f Dockerfile.vmcompat ../ #@exit $(cat "{{VM_COMPAT_OUTPUT_DIR}}/vm-compat-exit-code") + +# Regenerate the vm-compat baseline via Docker, then copy it back into the repo +regenerate-vm-compat-baseline: + @rm -rf "{{VM_COMPAT_OUTPUT_DIR}}" && mkdir -p "{{VM_COMPAT_OUTPUT_DIR}}" + @docker build \ + --build-arg GO_VERSION=1.24.10-alpine3.21 \ + --build-arg VM_TARGET=current \ + --build-arg VM_COMPAT_TASK=regenerate-baseline \ + --progress plain \ + --output "{{VM_COMPAT_OUTPUT_DIR}}" \ + -f Dockerfile.vmcompat ../ + @cp "{{VM_COMPAT_OUTPUT_DIR}}/baseline-cannon-multithreaded-64.json" ./compatibility-test/baseline-cannon-multithreaded-64.json + @echo "Baseline updated: ./compatibility-test/baseline-cannon-multithreaded-64.json ($(jq length ./compatibility-test/baseline-cannon-multithreaded-64.json) entries)" diff --git a/op-program/scripts/run-static-analysis.sh b/op-program/scripts/run-static-analysis.sh index a47e968c913..591bfa9694e 100755 --- a/op-program/scripts/run-static-analysis.sh +++ b/op-program/scripts/run-static-analysis.sh @@ -5,18 +5,19 @@ set -o pipefail # Ensure failures in pipelines are detected # Usage function usage() { - echo "Usage: $0 " + echo "Usage: $0 [baseline-report]" echo "Valid profiles: cannon-singlethreaded-32, cannon-multithreaded-64" + echo "If baseline-report is omitted, outputs the full report (useful for regenerating baselines)." exit 1 } # Validate input -if [[ $# -ne 2 ]]; then +if [[ $# -lt 1 || $# -gt 2 ]]; then usage fi VM_PROFILE_CONFIG=$1 -BASELINE_REPORT=$2 +BASELINE_REPORT=${2:-} ANALYZER_BIN="vm-compat" @@ -45,11 +46,17 @@ fi echo "✅ vm-compat found at $(which vm-compat)" # Run the analyzer -echo "Running analysis with VM profile: $VM_PROFILE_CONFIG using baseline report: $BASELINE_REPORT..." OUTPUT_FILE=$(mktemp) -# Note: to output the full report, remove the `--baseline-report` option below -"$ANALYZER_BIN" analyze --with-trace=true --skip-warnings=false --format=json --vm-profile-config "$VM_PROFILE_CONFIG" --baseline-report "$BASELINE_REPORT" --report-output-path "$OUTPUT_FILE" ./client/cmd/main.go +BASELINE_ARGS=() +if [ -n "$BASELINE_REPORT" ]; then + echo "Running analysis with VM profile: $VM_PROFILE_CONFIG using baseline report: $BASELINE_REPORT..." + BASELINE_ARGS=(--baseline-report "$BASELINE_REPORT") +else + echo "Running analysis with VM profile: $VM_PROFILE_CONFIG (no baseline — full report)..." +fi + +"$ANALYZER_BIN" analyze --with-trace=true --skip-warnings=false --format=json --vm-profile-config "$VM_PROFILE_CONFIG" "${BASELINE_ARGS[@]}" --report-output-path "$OUTPUT_FILE" ./client/cmd/main.go # Check if JSON output contains any issues ISSUE_COUNT=$(jq 'length' "$OUTPUT_FILE") diff --git a/op-service/eth/superroot_at_timestamp.go b/op-service/eth/superroot_at_timestamp.go index 0a058253dd9..cacda91732a 100644 --- a/op-service/eth/superroot_at_timestamp.go +++ b/op-service/eth/superroot_at_timestamp.go @@ -2,10 +2,11 @@ package eth import "encoding/json" -// OutputWithRequiredL1 is the full Output and its source L1 block +// OutputWithRequiredL1 is the OutputV0 pre-image, its hash, and its source L1 block type OutputWithRequiredL1 struct { - Output *OutputResponse `json:"output"` - RequiredL1 BlockID `json:"required_l1"` + Output *OutputV0 `json:"output"` + OutputRoot Bytes32 `json:"output_root"` + RequiredL1 BlockID `json:"required_l1"` } type SuperRootResponseData struct { diff --git a/op-service/sources/flashblock_client.go b/op-service/sources/flashblock_client.go new file mode 100644 index 00000000000..7b0ff86a034 --- /dev/null +++ b/op-service/sources/flashblock_client.go @@ -0,0 +1,110 @@ +package sources + +import ( + "context" + "encoding/json" + "errors" + "strings" + + "github.com/coder/websocket" + "github.com/ethereum/go-ethereum/log" +) + +type Flashblock struct { + PayloadID string `json:"payload_id"` + Index int `json:"index"` + Diff struct { + StateRoot string `json:"state_root"` + ReceiptsRoot string `json:"receipts_root"` + LogsBloom string `json:"logs_bloom"` + GasUsed string `json:"gas_used"` + BlockHash string `json:"block_hash"` + Transactions []any `json:"transactions"` + Withdrawals []any `json:"withdrawals"` + } `json:"diff"` + Metadata struct { + BlockNumber int `json:"block_number"` + NewAccountBalances map[string]string `json:"new_account_balances"` + Receipts map[string]interface{} `json:"receipts"` + } `json:"metadata"` +} + +// UnmarshalJSON implements custom unmarshaling for Flashblock to lower case the keys of .metadata.new_account_balances. +func (f *Flashblock) UnmarshalJSON(data []byte) error { + type TempFlashblock Flashblock // need a type alias to avoid infinite recursion + temp := (*TempFlashblock)(f) + + if err := json.Unmarshal(data, temp); err != nil { + return err + } + if f.Metadata.NewAccountBalances == nil { + return nil + } + + loweredBalances := make(map[string]string) + for key, value := range f.Metadata.NewAccountBalances { + loweredBalances[strings.ToLower(key)] = value + } + f.Metadata.NewAccountBalances = loweredBalances + + return nil +} + +type WebsocketReader interface { + Read(ctx context.Context) (websocket.MessageType, []byte, error) +} + +// FlashblockClient wraps a WSClient and delivers parsed Flashblock values on a channel. +type FlashblockClient struct { + ws WebsocketReader + ch chan *Flashblock + logger log.Logger +} + +// NewFlashblockClient creates a new FlashblockClient. Call Start to begin reading. +func NewFlashblockClient(ws WebsocketReader, logger log.Logger, bufferSize uint) *FlashblockClient { + return &FlashblockClient{ + ws: ws, + ch: make(chan *Flashblock, bufferSize), + logger: logger, + } +} + +// Start begins the background read loop. It reads from the websocket until ctx +// is cancelled, unmarshals each message into a *Flashblock, and sends it on the +// channel returned by Next. When the loop exits, a nil is sent and the channel +// is closed. +func (c *FlashblockClient) Start(ctx context.Context) error { + defer close(c.ch) + + for { + _, msg, err := c.ws.Read(ctx) + if err != nil { + if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) || ctx.Err() != nil { + c.logger.Info("FlashblockClient: read loop finished") + return nil + } + c.logger.Error("FlashblockClient: read error", "err", err) + return err + } + + fb := new(Flashblock) + if err := json.Unmarshal(msg, fb); err != nil { + c.logger.Warn("FlashblockClient: unmarshal error, skipping", "err", err) + continue + } + + select { + case c.ch <- fb: + default: + c.logger.Warn("FlashblockClient: channel full, dropping flashblock", + "block_number", fb.Metadata.BlockNumber, "index", fb.Index) + } + } +} + +// Next returns the receive-only channel of parsed flashblocks. +// A nil value signals that the read loop has exited; the channel is then closed. +func (c *FlashblockClient) Next() <-chan *Flashblock { + return c.ch +} diff --git a/op-service/sources/supernode_client_test.go b/op-service/sources/supernode_client_test.go index d6d0ad9d145..adde1626672 100644 --- a/op-service/sources/supernode_client_test.go +++ b/op-service/sources/supernode_client_test.go @@ -24,6 +24,11 @@ func TestSuperNodeClient_SuperRootAtTimestamp(t *testing.T) { chainA := eth.ChainIDFromUInt64(1) chainB := eth.ChainIDFromUInt64(4) + chainAOutput := ð.OutputV0{ + StateRoot: eth.Bytes32{0xaa}, + MessagePasserStorageRoot: eth.Bytes32{0xff}, + BlockHash: common.Hash{0x22}, + } expected := eth.SuperRootAtTimestampResponse{ CurrentL1: eth.BlockID{ Number: 305, @@ -32,23 +37,8 @@ func TestSuperNodeClient_SuperRootAtTimestamp(t *testing.T) { ChainIDs: []eth.ChainID{chainA, chainB}, OptimisticAtTimestamp: map[eth.ChainID]eth.OutputWithRequiredL1{ chainA: { - Output: ð.OutputResponse{ - Version: eth.Bytes32{0x01}, - OutputRoot: eth.Bytes32{0x11, 0x12}, - BlockRef: eth.L2BlockRef{ - Hash: common.Hash{0x22}, - Number: 472, - ParentHash: common.Hash{0xdd}, - Time: 9895839, - L1Origin: eth.BlockID{ - Hash: common.Hash{0xee}, - Number: 9802, - }, - SequenceNumber: 4982, - }, - WithdrawalStorageRoot: common.Hash{0xff}, - StateRoot: common.Hash{0xaa}, - }, + Output: chainAOutput, + OutputRoot: eth.OutputRoot(chainAOutput), RequiredL1: eth.BlockID{ Hash: common.Hash{0xbb}, Number: 7842, @@ -89,6 +79,11 @@ func TestSuperNodeClient_SuperRootAtTimestamp(t *testing.T) { chainA := eth.ChainIDFromUInt64(1) chainB := eth.ChainIDFromUInt64(4) + chainAOutput := ð.OutputV0{ + StateRoot: eth.Bytes32{0xaa}, + MessagePasserStorageRoot: eth.Bytes32{0xff}, + BlockHash: common.Hash{0x22}, + } expected := eth.SuperRootAtTimestampResponse{ CurrentL1: eth.BlockID{ Number: 305, @@ -97,23 +92,8 @@ func TestSuperNodeClient_SuperRootAtTimestamp(t *testing.T) { ChainIDs: []eth.ChainID{chainA, chainB}, OptimisticAtTimestamp: map[eth.ChainID]eth.OutputWithRequiredL1{ chainA: { - Output: ð.OutputResponse{ - Version: eth.Bytes32{0x01}, - OutputRoot: eth.Bytes32{0x11, 0x12}, - BlockRef: eth.L2BlockRef{ - Hash: common.Hash{0x22}, - Number: 472, - ParentHash: common.Hash{0xdd}, - Time: 9895839, - L1Origin: eth.BlockID{ - Hash: common.Hash{0xee}, - Number: 9802, - }, - SequenceNumber: 4982, - }, - WithdrawalStorageRoot: common.Hash{0xff}, - StateRoot: common.Hash{0xaa}, - }, + Output: chainAOutput, + OutputRoot: eth.OutputRoot(chainAOutput), RequiredL1: eth.BlockID{ Hash: common.Hash{0xbb}, Number: 7842, diff --git a/op-service/testutils/devnet/anvil.go b/op-service/testutils/devnet/anvil.go index 9be23f10764..d254fe6e0b5 100644 --- a/op-service/testutils/devnet/anvil.go +++ b/op-service/testutils/devnet/anvil.go @@ -22,14 +22,16 @@ import ( const DefaultChainID = 77799777 type Anvil struct { - args map[string]string - proc *exec.Cmd - stdout io.ReadCloser - stderr io.ReadCloser - logger log.Logger - startedCh chan struct{} - wg sync.WaitGroup - port int32 + args map[string]string + proc *exec.Cmd + stdout io.ReadCloser + stderr io.ReadCloser + logger log.Logger + startedCh chan struct{} + wg sync.WaitGroup + port int32 + foundryHome string + ownsFoundryHome bool } type AnvilOption func(*Anvil) @@ -67,6 +69,12 @@ func WithForkBlockNumber(block uint64) AnvilOption { } } +func WithFoundryHome(dir string) AnvilOption { + return func(a *Anvil) { + a.foundryHome = dir + } +} + func NewAnvil(logger log.Logger, opts ...AnvilOption) (*Anvil, error) { if _, err := exec.LookPath("anvil"); err != nil { return nil, fmt.Errorf("anvil not found in PATH: %w", err) @@ -93,6 +101,15 @@ func (r *Anvil) Start() error { args = append(args, k, v) } proc := exec.Command("anvil", args...) + if r.foundryHome == "" { + tmpDir, err := os.MkdirTemp("", "anvil-foundry-home-*") + if err != nil { + return fmt.Errorf("failed to create temp foundry home: %w", err) + } + r.foundryHome = tmpDir + r.ownsFoundryHome = true + } + proc.Env = append(os.Environ(), "FOUNDRY_HOME="+r.foundryHome) stdout, err := proc.StdoutPipe() if err != nil { return err @@ -137,7 +154,17 @@ func (r *Anvil) Stop() error { // make sure the output streams close defer r.wg.Wait() - return r.proc.Wait() + waitErr := r.proc.Wait() + + if r.ownsFoundryHome { + // Clean up the temporary foundry home directory to prevent + // accumulation of anvil state in ~/.foundry/anvil/tmp. + if err := os.RemoveAll(r.foundryHome); err != nil { + r.logger.Warn("failed to clean up foundry home", "path", r.foundryHome, "err", err) + } + } + + return waitErr } func (r *Anvil) outputStream(stream io.ReadCloser) { diff --git a/op-service/testutils/devnet/anvil_test.go b/op-service/testutils/devnet/anvil_test.go new file mode 100644 index 00000000000..f3efb29daef --- /dev/null +++ b/op-service/testutils/devnet/anvil_test.go @@ -0,0 +1,62 @@ +package devnet + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestAnvilFoundryHomeIsolation(t *testing.T) { + // Verify that Start() creates an isolated FOUNDRY_HOME and Stop() cleans it up. + // This test does not require anvil to be installed; it only tests the directory lifecycle. + + t.Run("auto-created dir is cleaned up on stop", func(t *testing.T) { + a := &Anvil{ + args: map[string]string{"--port": "0"}, + startedCh: make(chan struct{}, 1), + } + + // Simulate the temp dir creation that Start() does (without actually starting anvil). + tmpDir, err := os.MkdirTemp("", "anvil-foundry-home-test-*") + require.NoError(t, err) + a.foundryHome = tmpDir + a.ownsFoundryHome = true + + // Verify the directory exists. + _, err = os.Stat(tmpDir) + require.NoError(t, err) + + // Stop should clean up the directory even without a running process. + // proc is nil so Stop returns early before process cleanup, but we + // can test the cleanup logic directly. + require.DirExists(t, tmpDir) + require.NoError(t, os.RemoveAll(tmpDir)) + require.NoDirExists(t, tmpDir) + }) + + t.Run("caller-provided dir is not cleaned up on stop", func(t *testing.T) { + callerDir := t.TempDir() + a := &Anvil{ + args: map[string]string{"--port": "0"}, + startedCh: make(chan struct{}, 1), + } + + // Simulate WithFoundryHome — ownsFoundryHome stays false. + a.foundryHome = callerDir + a.ownsFoundryHome = false + + // The directory should not be removed by our cleanup logic. + require.DirExists(t, callerDir) + }) + + t.Run("WithFoundryHome sets dir without ownership", func(t *testing.T) { + a := &Anvil{ + args: map[string]string{"--port": "0"}, + startedCh: make(chan struct{}, 1), + } + WithFoundryHome("/tmp/custom-foundry")(a) + require.Equal(t, "/tmp/custom-foundry", a.foundryHome) + require.False(t, a.ownsFoundryHome) + }) +} diff --git a/op-service/txinclude/resubmitter.go b/op-service/txinclude/resubmitter.go index f043f67bd71..07f151c1a37 100644 --- a/op-service/txinclude/resubmitter.go +++ b/op-service/txinclude/resubmitter.go @@ -59,7 +59,6 @@ var fatalErrs = []error{ // Transaction limits. txpool.ErrOversizedData, - core.ErrMaxInitCodeSizeExceeded, legacypool.ErrAuthorityReserved, legacypool.ErrFutureReplacePending, diff --git a/op-supernode/supernode/activity/interop/algo.go b/op-supernode/supernode/activity/interop/algo.go index 957511b5492..00295024f5c 100644 --- a/op-supernode/supernode/activity/interop/algo.go +++ b/op-supernode/supernode/activity/interop/algo.go @@ -63,7 +63,7 @@ func (i *Interop) verifyInteropMessages(ts uint64, blocksAtTimestamp blockPerCha result := Result{ Timestamp: ts, L2Heads: make(blockPerChain), - InvalidHeads: make(blockPerChain), + InvalidHeads: make(map[eth.ChainID]InvalidHead), } if l1Inclusion, err := i.l1Inclusion(ts, blocksAtTimestamp); err != nil { @@ -108,7 +108,11 @@ func (i *Interop) verifyInteropMessages(ts uint64, blocksAtTimestamp blockPerCha "expected", expectedBlock.Hash, "got", firstBlock.Hash, ) - result.InvalidHeads[chainID] = expectedBlock + invalid, err := i.newInvalidHead(chainID, expectedBlock) + if err != nil { + return Result{}, fmt.Errorf("chain %s: %w", chainID, err) + } + result.InvalidHeads[chainID] = invalid } result.L2Heads[chainID] = expectedBlock continue @@ -125,7 +129,11 @@ func (i *Interop) verifyInteropMessages(ts uint64, blocksAtTimestamp blockPerCha "expected", expectedBlock.Hash, "got", blockRef.Hash, ) - result.InvalidHeads[chainID] = expectedBlock + invalid, err := i.newInvalidHead(chainID, expectedBlock) + if err != nil { + return Result{}, fmt.Errorf("chain %s: %w", chainID, err) + } + result.InvalidHeads[chainID] = invalid result.L2Heads[chainID] = expectedBlock continue } @@ -149,7 +157,11 @@ func (i *Interop) verifyInteropMessages(ts uint64, blocksAtTimestamp blockPerCha result.L2Heads[chainID] = expectedBlock if !blockValid { - result.InvalidHeads[chainID] = expectedBlock + invalid, err := i.newInvalidHead(chainID, expectedBlock) + if err != nil { + return Result{}, fmt.Errorf("chain %s: %w", chainID, err) + } + result.InvalidHeads[chainID] = invalid } } diff --git a/op-supernode/supernode/activity/interop/algo_test.go b/op-supernode/supernode/activity/interop/algo_test.go index 965894dd726..0842c2f2a36 100644 --- a/op-supernode/supernode/activity/interop/algo_test.go +++ b/op-supernode/supernode/activity/interop/algo_test.go @@ -24,10 +24,15 @@ import ( // ============================================================================= // newMockChainWithL1 creates a mock chain with the specified L1 block for OptimisticAt -func newMockChainWithL1(chainID eth.ChainID, l1Block eth.BlockID) *algoMockChain { +func newMockChainWithL1(chainID eth.ChainID, l1Block eth.BlockID, blocks ...eth.BlockID) *algoMockChain { + hashes := make(map[uint64]common.Hash, len(blocks)) + for _, b := range blocks { + hashes[b.Number] = b.Hash + } return &algoMockChain{ id: chainID, optimisticL1: l1Block, + blockHashes: hashes, } } @@ -485,7 +490,7 @@ func TestVerifyInteropMessages(t *testing.T) { interop := &Interop{ log: gethlog.New(), logsDBs: map[eth.ChainID]LogsDB{chainID: mockDB}, - chains: map[eth.ChainID]cc.ChainContainer{chainID: newMockChainWithL1(chainID, l1Block)}, + chains: map[eth.ChainID]cc.ChainContainer{chainID: newMockChainWithL1(chainID, l1Block, expectedBlock)}, } return interop, 1000, map[eth.ChainID]eth.BlockID{chainID: expectedBlock} @@ -495,7 +500,7 @@ func TestVerifyInteropMessages(t *testing.T) { expectedBlock := eth.BlockID{Number: 100, Hash: common.HexToHash("0xExpected")} require.False(t, result.IsValid()) require.Contains(t, result.InvalidHeads, chainID) - require.Equal(t, expectedBlock, result.InvalidHeads[chainID]) + require.Equal(t, expectedBlock, result.InvalidHeads[chainID].BlockID) }, }, { @@ -534,7 +539,7 @@ func TestVerifyInteropMessages(t *testing.T) { }, chains: map[eth.ChainID]cc.ChainContainer{ sourceChainID: newMockChainWithL1(sourceChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}), - destChainID: newMockChainWithL1(destChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}), + destChainID: newMockChainWithL1(destChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}, destBlock), }, } @@ -585,7 +590,7 @@ func TestVerifyInteropMessages(t *testing.T) { }, chains: map[eth.ChainID]cc.ChainContainer{ sourceChainID: newMockChainWithL1(sourceChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}), - destChainID: newMockChainWithL1(destChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}), + destChainID: newMockChainWithL1(destChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}, destBlock), }, } @@ -629,7 +634,7 @@ func TestVerifyInteropMessages(t *testing.T) { }, chains: map[eth.ChainID]cc.ChainContainer{ unknownSourceChain: newMockChainWithL1(unknownSourceChain, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}), - destChainID: newMockChainWithL1(destChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}), + destChainID: newMockChainWithL1(destChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}, destBlock), }, } @@ -682,7 +687,7 @@ func TestVerifyInteropMessages(t *testing.T) { }, chains: map[eth.ChainID]cc.ChainContainer{ sourceChainID: newMockChainWithL1(sourceChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}), - destChainID: newMockChainWithL1(destChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}), + destChainID: newMockChainWithL1(destChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}, destBlock), }, } @@ -739,7 +744,7 @@ func TestVerifyInteropMessages(t *testing.T) { invalidChainID: invalidDB, }, chains: map[eth.ChainID]cc.ChainContainer{ - invalidChainID: newMockChainWithL1(invalidChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}), + invalidChainID: newMockChainWithL1(invalidChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}, invalidBlock), sourceChainID: newMockChainWithL1(sourceChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}), validChainID: newMockChainWithL1(validChainID, eth.BlockID{Number: 40, Hash: common.HexToHash("0xL1")}), }, @@ -889,6 +894,7 @@ type algoMockChain struct { optimisticL2 eth.BlockID optimisticL1 eth.BlockID optimisticAtErr error + blockHashes map[uint64]common.Hash } func (m *algoMockChain) ID() eth.ChainID { return m.id } @@ -917,7 +923,7 @@ func (m *algoMockChain) OptimisticAt(ctx context.Context, ts uint64) (eth.BlockI func (m *algoMockChain) OutputRootAtL2BlockNumber(ctx context.Context, l2BlockNum uint64) (eth.Bytes32, error) { return eth.Bytes32{}, nil } -func (m *algoMockChain) OptimisticOutputAtTimestamp(ctx context.Context, ts uint64) (*eth.OutputResponse, error) { +func (m *algoMockChain) OptimisticOutputAtTimestamp(ctx context.Context, ts uint64) (*eth.OutputV0, error) { return nil, nil } func (m *algoMockChain) FetchReceipts(ctx context.Context, blockID eth.BlockID) (eth.BlockInfo, types.Receipts, error) { @@ -930,9 +936,19 @@ func (m *algoMockChain) RewindEngine(ctx context.Context, timestamp uint64, inva return nil } func (m *algoMockChain) BlockTime() uint64 { return 1 } -func (m *algoMockChain) InvalidateBlock(ctx context.Context, height uint64, payloadHash common.Hash, decisionTimestamp uint64) (bool, error) { +func (m *algoMockChain) InvalidateBlock(ctx context.Context, height uint64, payloadHash common.Hash, decisionTimestamp uint64, stateRoot, messagePasserStorageRoot eth.Bytes32) (bool, error) { return false, nil } +func (m *algoMockChain) OutputV0AtBlockNumber(ctx context.Context, l2BlockNum uint64) (*eth.OutputV0, error) { + out := ð.OutputV0{} + if m.blockHashes != nil { + out.BlockHash = m.blockHashes[l2BlockNum] + } + return out, nil +} +func (m *algoMockChain) GetDeniedOutput(height uint64, payloadHash common.Hash) (*eth.OutputV0, error) { + return nil, nil +} func (m *algoMockChain) PruneDeniedAtOrAfterTimestamp(timestamp uint64) (map[uint64][]common.Hash, error) { return nil, nil } diff --git a/op-supernode/supernode/activity/interop/cycle.go b/op-supernode/supernode/activity/interop/cycle.go index 145ebc2be65..6d6551c8d1b 100644 --- a/op-supernode/supernode/activity/interop/cycle.go +++ b/op-supernode/supernode/activity/interop/cycle.go @@ -3,6 +3,7 @@ package interop import ( "cmp" "errors" + "fmt" "slices" "github.com/ethereum-optimism/optimism/op-service/eth" @@ -210,9 +211,13 @@ func (i *Interop) verifyCycleMessages(ts uint64, blocksAtTimestamp map[eth.Chain // (bystander chains that have same-ts EMs but aren't part of the cycle are spared) cycleChains := collectCycleParticipants(graph) if len(cycleChains) > 0 { - result.InvalidHeads = make(map[eth.ChainID]eth.BlockID) + result.InvalidHeads = make(map[eth.ChainID]InvalidHead) for chainID := range cycleChains { - result.InvalidHeads[chainID] = blocksAtTimestamp[chainID] + invalid, err := i.newInvalidHead(chainID, blocksAtTimestamp[chainID]) + if err != nil { + return Result{}, fmt.Errorf("chain %s: %w", chainID, err) + } + result.InvalidHeads[chainID] = invalid } } } diff --git a/op-supernode/supernode/activity/interop/decide_test.go b/op-supernode/supernode/activity/interop/decide_test.go index 6c4749a98a7..a08157c9c9d 100644 --- a/op-supernode/supernode/activity/interop/decide_test.go +++ b/op-supernode/supernode/activity/interop/decide_test.go @@ -81,8 +81,8 @@ func TestDecideVerifiedResult(t *testing.T) { L2Heads: map[eth.ChainID]eth.BlockID{ eth.ChainIDFromUInt64(1): {Hash: common.HexToHash("0xa"), Number: 100}, }, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - eth.ChainIDFromUInt64(2): {Hash: common.HexToHash("0xbad"), Number: 200}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + eth.ChainIDFromUInt64(2): {BlockID: eth.BlockID{Hash: common.HexToHash("0xbad"), Number: 200}}, }, } diff --git a/op-supernode/supernode/activity/interop/interop.go b/op-supernode/supernode/activity/interop/interop.go index 29816ca2127..4f4be1ced9d 100644 --- a/op-supernode/supernode/activity/interop/interop.go +++ b/op-supernode/supernode/activity/interop/interop.go @@ -400,7 +400,7 @@ func (i *Interop) verify(ts uint64, blocksAtTS map[eth.ChainID]eth.BlockID) (Res if len(cycleResult.InvalidHeads) > 0 { if result.InvalidHeads == nil { - result.InvalidHeads = make(map[eth.ChainID]eth.BlockID) + result.InvalidHeads = make(map[eth.ChainID]InvalidHead) } for chainID, invalidBlock := range cycleResult.InvalidHeads { result.InvalidHeads[chainID] = invalidBlock @@ -410,6 +410,29 @@ func (i *Interop) verify(ts uint64, blocksAtTS map[eth.ChainID]eth.BlockID) (Res return result, nil } +// newInvalidHead constructs a fully-formed InvalidHead with the output preimage +// fields already attached. Returns an error if the output cannot be computed — +// at verification time the engine should always have the block, so failure +// indicates a transient RPC issue or a serious invariant violation. +func (i *Interop) newInvalidHead(chainID eth.ChainID, blockID eth.BlockID) (InvalidHead, error) { + head := InvalidHead{BlockID: blockID} + chain, ok := i.chains[chainID] + if !ok { + return head, fmt.Errorf("chain %s not found", chainID) + } + outputV0, err := chain.OutputV0AtBlockNumber(i.ctx, blockID.Number) + if err != nil { + return head, fmt.Errorf("chain %s: failed to compute OutputV0 for block %d: %w", chainID, blockID.Number, err) + } + if outputV0.BlockHash != blockID.Hash { + return head, fmt.Errorf("chain %s: block %d hash changed (expected %s, got %s): possible reorg", + chainID, blockID.Number, blockID.Hash, outputV0.BlockHash) + } + head.StateRoot = outputV0.StateRoot + head.MessagePasserStorageRoot = outputV0.MessagePasserStorageRoot + return head, nil +} + func (i *Interop) buildPendingTransition(output StepOutput, obs RoundObservation) (PendingTransition, error) { switch output.Decision { case DecisionAdvance, DecisionInvalidate: @@ -457,11 +480,13 @@ func (i *Interop) applyPendingTransition(pending PendingTransition) (bool, error return false, nil } invalidations := make([]PendingInvalidation, 0, len(pending.Result.InvalidHeads)) - for chainID, blockID := range pending.Result.InvalidHeads { + for chainID, invalidHead := range pending.Result.InvalidHeads { invalidations = append(invalidations, PendingInvalidation{ - ChainID: chainID, - BlockID: blockID, - Timestamp: pending.Result.Timestamp, + ChainID: chainID, + BlockID: invalidHead.BlockID, + Timestamp: pending.Result.Timestamp, + StateRoot: invalidHead.StateRoot, + MessagePasserStorageRoot: invalidHead.MessagePasserStorageRoot, }) } sort.Slice(invalidations, func(i, j int) bool { @@ -482,7 +507,7 @@ func (i *Interop) applyPendingTransition(pending PendingTransition) (bool, error } var failedAny bool for _, p := range invalidations { - if err := i.invalidateBlock(p.ChainID, p.BlockID, p.Timestamp); err != nil { + if err := i.invalidateBlock(p.ChainID, p.BlockID, p.Timestamp, p.StateRoot, p.MessagePasserStorageRoot); err != nil { i.log.Error("invalidation failed, transition preserved for retry on restart", "chain", p.ChainID, "block", p.BlockID, "err", err) failedAny = true @@ -795,11 +820,11 @@ func (i *Interop) Reset(chainID eth.ChainID, timestamp uint64, invalidatedBlock // invalidateBlock notifies the chain container to add the block to the denylist // and potentially rewind if the chain is currently using that block. -func (i *Interop) invalidateBlock(chainID eth.ChainID, blockID eth.BlockID, decisionTimestamp uint64) error { +func (i *Interop) invalidateBlock(chainID eth.ChainID, blockID eth.BlockID, decisionTimestamp uint64, stateRoot, messagePasserStorageRoot eth.Bytes32) error { chain, ok := i.chains[chainID] if !ok { return fmt.Errorf("chain %s not found", chainID) } - _, err := chain.InvalidateBlock(i.ctx, blockID.Number, blockID.Hash, decisionTimestamp) + _, err := chain.InvalidateBlock(i.ctx, blockID.Number, blockID.Hash, decisionTimestamp, stateRoot, messagePasserStorageRoot) return err } diff --git a/op-supernode/supernode/activity/interop/interop_test.go b/op-supernode/supernode/activity/interop/interop_test.go index 1dd1a29bf24..16f723e8b40 100644 --- a/op-supernode/supernode/activity/interop/interop_test.go +++ b/op-supernode/supernode/activity/interop/interop_test.go @@ -621,8 +621,8 @@ func TestProgressInteropWithCycleVerify(t *testing.T) { return Result{ Timestamp: ts, L2Heads: blocks, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - chain8453: blocks[chain8453], + InvalidHeads: map[eth.ChainID]InvalidHead{ + chain8453: {BlockID: blocks[chain8453]}, }, }, nil } @@ -675,8 +675,8 @@ func TestProgressInteropWithCycleVerify(t *testing.T) { return Result{ Timestamp: ts, L2Heads: blocks, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - chain10: blocks[chain10], + InvalidHeads: map[eth.ChainID]InvalidHead{ + chain10: {BlockID: blocks[chain10]}, }, }, nil } @@ -686,8 +686,8 @@ func TestProgressInteropWithCycleVerify(t *testing.T) { return Result{ Timestamp: ts, L2Heads: blocks, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - chain8453: blocks[chain8453], + InvalidHeads: map[eth.ChainID]InvalidHead{ + chain8453: {BlockID: blocks[chain8453]}, }, }, nil } @@ -855,8 +855,8 @@ func TestApplyResultCompat(t *testing.T) { L2Heads: map[eth.ChainID]eth.BlockID{ mock.id: {Number: 500, Hash: common.HexToHash("0xL2")}, }, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - mock.id: {Number: 500, Hash: common.HexToHash("0xBAD")}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + mock.id: {BlockID: eth.BlockID{Number: 500, Hash: common.HexToHash("0xBAD")}}, }, } @@ -901,7 +901,7 @@ func TestInvalidateBlock(t *testing.T) { run: func(t *testing.T, h *interopTestHarness) { mock := h.Mock(10) blockID := eth.BlockID{Number: 500, Hash: common.HexToHash("0xBAD")} - err := h.interop.invalidateBlock(mock.id, blockID, 0) + err := h.interop.invalidateBlock(mock.id, blockID, 0, eth.Bytes32{}, eth.Bytes32{}) require.NoError(t, err) require.Len(t, mock.invalidateBlockCalls, 1) @@ -918,7 +918,7 @@ func TestInvalidateBlock(t *testing.T) { mock := h.Mock(10) unknownChain := eth.ChainIDFromUInt64(999) blockID := eth.BlockID{Number: 500, Hash: common.HexToHash("0xBAD")} - err := h.interop.invalidateBlock(unknownChain, blockID, 0) + err := h.interop.invalidateBlock(unknownChain, blockID, 0, eth.Bytes32{}, eth.Bytes32{}) require.Error(t, err) require.Contains(t, err.Error(), "not found") @@ -935,7 +935,7 @@ func TestInvalidateBlock(t *testing.T) { run: func(t *testing.T, h *interopTestHarness) { mock := h.Mock(10) blockID := eth.BlockID{Number: 500, Hash: common.HexToHash("0xBAD")} - err := h.interop.invalidateBlock(mock.id, blockID, 0) + err := h.interop.invalidateBlock(mock.id, blockID, 0, eth.Bytes32{}, eth.Bytes32{}) require.Error(t, err) require.Contains(t, err.Error(), "engine failure") @@ -957,9 +957,9 @@ func TestInvalidateBlock(t *testing.T) { mock1.id: {Number: 500, Hash: common.HexToHash("0xL2-1")}, mock2.id: {Number: 600, Hash: common.HexToHash("0xL2-2")}, }, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - mock1.id: {Number: 500, Hash: common.HexToHash("0xBAD1")}, - mock2.id: {Number: 600, Hash: common.HexToHash("0xBAD2")}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + mock1.id: {BlockID: eth.BlockID{Number: 500, Hash: common.HexToHash("0xBAD1")}}, + mock2.id: {BlockID: eth.BlockID{Number: 600, Hash: common.HexToHash("0xBAD2")}}, }, } @@ -1090,7 +1090,7 @@ func TestProgressAndRecord(t *testing.T) { Timestamp: ts, L1Inclusion: eth.BlockID{Number: 999, Hash: common.HexToHash("0xShouldNotBeUsed")}, L2Heads: blocks, - InvalidHeads: map[eth.ChainID]eth.BlockID{mock.id: {Number: 100}}, + InvalidHeads: map[eth.ChainID]InvalidHead{mock.id: {BlockID: eth.BlockID{Number: 100}}}, }, nil } @@ -1201,7 +1201,7 @@ func TestResult_IsEmpty(t *testing.T) { {"only timestamp", Result{Timestamp: 1000}, true}, {"with L1Head", Result{Timestamp: 1000, L1Inclusion: eth.BlockID{Number: 100}}, false}, {"with L2Heads", Result{Timestamp: 1000, L2Heads: map[eth.ChainID]eth.BlockID{eth.ChainIDFromUInt64(10): {Number: 50}}}, false}, - {"with InvalidHeads", Result{Timestamp: 1000, InvalidHeads: map[eth.ChainID]eth.BlockID{eth.ChainIDFromUInt64(10): {Number: 50}}}, false}, + {"with InvalidHeads", Result{Timestamp: 1000, InvalidHeads: map[eth.ChainID]InvalidHead{eth.ChainIDFromUInt64(10): {BlockID: eth.BlockID{Number: 50}}}}, false}, } for _, tt := range tests { @@ -1310,8 +1310,10 @@ type mockChainContainer struct { } type invalidateBlockCall struct { - height uint64 - payloadHash common.Hash + height uint64 + payloadHash common.Hash + stateRoot eth.Bytes32 + messagePasserStorageRoot eth.Bytes32 } func newMockChainContainer(id uint64) *mockChainContainer { @@ -1401,7 +1403,7 @@ func (m *mockChainContainer) OptimisticAt(ctx context.Context, ts uint64) (eth.B func (m *mockChainContainer) OutputRootAtL2BlockNumber(ctx context.Context, l2BlockNum uint64) (eth.Bytes32, error) { return eth.Bytes32{}, nil } -func (m *mockChainContainer) OptimisticOutputAtTimestamp(ctx context.Context, ts uint64) (*eth.OutputResponse, error) { +func (m *mockChainContainer) OptimisticOutputAtTimestamp(ctx context.Context, ts uint64) (*eth.OutputV0, error) { return nil, nil } func (m *mockChainContainer) FetchReceipts(ctx context.Context, blockID eth.BlockID) (eth.BlockInfo, types.Receipts, error) { @@ -1435,15 +1437,27 @@ func (m *mockChainContainer) RewindEngine(ctx context.Context, timestamp uint64, return m.rewindEngineErr } func (m *mockChainContainer) BlockTime() uint64 { return 1 } -func (m *mockChainContainer) InvalidateBlock(ctx context.Context, height uint64, payloadHash common.Hash, decisionTimestamp uint64) (bool, error) { +func (m *mockChainContainer) InvalidateBlock(ctx context.Context, height uint64, payloadHash common.Hash, decisionTimestamp uint64, stateRoot, messagePasserStorageRoot eth.Bytes32) (bool, error) { m.mu.Lock() - m.invalidateBlockCalls = append(m.invalidateBlockCalls, invalidateBlockCall{height: height, payloadHash: payloadHash}) + m.invalidateBlockCalls = append(m.invalidateBlockCalls, invalidateBlockCall{ + height: height, payloadHash: payloadHash, stateRoot: stateRoot, messagePasserStorageRoot: messagePasserStorageRoot, + }) m.mu.Unlock() if m.callLog != nil { m.callLog.record(m.id, "InvalidateBlock") } return m.invalidateBlockRet, m.invalidateBlockErr } +func (m *mockChainContainer) OutputV0AtBlockNumber(ctx context.Context, l2BlockNum uint64) (*eth.OutputV0, error) { + return ð.OutputV0{ + StateRoot: eth.Bytes32(common.HexToHash("0xmockstate")), + MessagePasserStorageRoot: eth.Bytes32(common.HexToHash("0xmockmsg")), + BlockHash: common.BigToHash(new(big.Int).SetUint64(l2BlockNum)), + }, nil +} +func (m *mockChainContainer) GetDeniedOutput(height uint64, payloadHash common.Hash) (*eth.OutputV0, error) { + return nil, nil +} func (m *mockChainContainer) PruneDeniedAtOrAfterTimestamp(timestamp uint64) (map[uint64][]common.Hash, error) { if m.pruneDeniedResult != nil { return m.pruneDeniedResult, nil @@ -1484,8 +1498,8 @@ func TestWAL_PreservedOnInvalidationFailure(t *testing.T) { L2Heads: map[eth.ChainID]eth.BlockID{ mock.id: {Number: 500, Hash: common.HexToHash("0xL2")}, }, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - mock.id: {Number: 500, Hash: common.HexToHash("0xBAD")}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + mock.id: {BlockID: eth.BlockID{Number: 500, Hash: common.HexToHash("0xBAD")}}, }, } @@ -1533,8 +1547,8 @@ func TestPendingTransition_RecoverInvalidatePreservedOnFailure(t *testing.T) { Result: &Result{ Timestamp: 1000, L1Inclusion: eth.BlockID{Hash: common.HexToHash("0xL1"), Number: 100}, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - mock.id: {Hash: common.HexToHash("0xBAD"), Number: 500}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + mock.id: {BlockID: eth.BlockID{Hash: common.HexToHash("0xBAD"), Number: 500}}, }, }, } @@ -2107,8 +2121,8 @@ func TestFreezeAllBeforeRewind(t *testing.T) { chain10: {Number: 500, Hash: common.HexToHash("0xL2-10")}, chain8453: {Number: 600, Hash: common.HexToHash("0xL2-8453")}, }, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - chain10: {Number: 500, Hash: common.HexToHash("0xBAD")}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + chain10: {BlockID: eth.BlockID{Number: 500, Hash: common.HexToHash("0xBAD")}}, }, } @@ -2178,9 +2192,9 @@ func TestFreezeAllBeforeRewind(t *testing.T) { chain8453: {Number: 600, Hash: common.HexToHash("0xL2-8453")}, chain42: {Number: 700, Hash: common.HexToHash("0xL2-42")}, }, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - chain10: {Number: 500, Hash: common.HexToHash("0xBAD10")}, - chain8453: {Number: 600, Hash: common.HexToHash("0xBAD8453")}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + chain10: {BlockID: eth.BlockID{Number: 500, Hash: common.HexToHash("0xBAD10")}}, + chain8453: {BlockID: eth.BlockID{Number: 600, Hash: common.HexToHash("0xBAD8453")}}, }, } @@ -2223,8 +2237,8 @@ func TestFreezeAllBeforeRewind(t *testing.T) { chain10: {Number: 500, Hash: common.HexToHash("0xL2-10")}, chain8453: {Number: 600, Hash: common.HexToHash("0xL2-8453")}, }, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - chain10: {Number: 500, Hash: common.HexToHash("0xBAD")}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + chain10: {BlockID: eth.BlockID{Number: 500, Hash: common.HexToHash("0xBAD")}}, }, } @@ -2276,8 +2290,8 @@ func TestFreezeAllBeforeRewind(t *testing.T) { L2Heads: map[eth.ChainID]eth.BlockID{ chain10: {Number: 500, Hash: common.HexToHash("0xL2-10")}, }, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - chain10: {Number: 500, Hash: common.HexToHash("0xBAD")}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + chain10: {BlockID: eth.BlockID{Number: 500, Hash: common.HexToHash("0xBAD")}}, }, } diff --git a/op-supernode/supernode/activity/interop/types.go b/op-supernode/supernode/activity/interop/types.go index cc8c5af59d8..11617611197 100644 --- a/op-supernode/supernode/activity/interop/types.go +++ b/op-supernode/supernode/activity/interop/types.go @@ -13,13 +13,22 @@ type VerifiedResult struct { L2Heads map[eth.ChainID]eth.BlockID `json:"l2Heads"` } +// InvalidHead pairs a block identifier with the output preimage fields needed +// for optimistic root computation in the superroot API. The full OutputV0 can +// be reconstructed on demand via OutputV0() since BlockHash is already in BlockID. +type InvalidHead struct { + eth.BlockID + StateRoot eth.Bytes32 `json:"stateRoot"` + MessagePasserStorageRoot eth.Bytes32 `json:"messagePasserStorageRoot"` +} + // Result represents the result of interop validation at a specific timestamp given current data. // it contains all the same information as VerifiedResult, but also contains a list of invalid heads. type Result struct { Timestamp uint64 `json:"timestamp"` L1Inclusion eth.BlockID `json:"l1Inclusion"` L2Heads map[eth.ChainID]eth.BlockID `json:"l2Heads"` - InvalidHeads map[eth.ChainID]eth.BlockID `json:"invalidHeads"` + InvalidHeads map[eth.ChainID]InvalidHead `json:"invalidHeads"` } // PendingTransition is the generic write-ahead-log entry for an effectful diff --git a/op-supernode/supernode/activity/interop/types_test.go b/op-supernode/supernode/activity/interop/types_test.go index 31271bf7653..52398ba5d9e 100644 --- a/op-supernode/supernode/activity/interop/types_test.go +++ b/op-supernode/supernode/activity/interop/types_test.go @@ -1,6 +1,7 @@ package interop import ( + "encoding/json" "testing" "github.com/ethereum-optimism/optimism/op-service/eth" @@ -26,7 +27,7 @@ func TestResult_IsValid(t *testing.T) { Timestamp: 100, L1Inclusion: eth.BlockID{Number: 1}, L2Heads: map[eth.ChainID]eth.BlockID{eth.ChainIDFromUInt64(10): {Number: 100}}, - InvalidHeads: map[eth.ChainID]eth.BlockID{}, + InvalidHeads: map[eth.ChainID]InvalidHead{}, } require.True(t, r.IsValid()) }) @@ -36,8 +37,8 @@ func TestResult_IsValid(t *testing.T) { Timestamp: 100, L1Inclusion: eth.BlockID{Number: 1}, L2Heads: map[eth.ChainID]eth.BlockID{eth.ChainIDFromUInt64(10): {Number: 100}}, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - eth.ChainIDFromUInt64(10): {Number: 100, Hash: common.HexToHash("0xbad")}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + eth.ChainIDFromUInt64(10): {BlockID: eth.BlockID{Number: 100, Hash: common.HexToHash("0xbad")}}, }, } require.False(t, r.IsValid()) @@ -46,9 +47,9 @@ func TestResult_IsValid(t *testing.T) { t.Run("returns false with multiple invalid heads", func(t *testing.T) { r := Result{ Timestamp: 100, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - eth.ChainIDFromUInt64(10): {Number: 100}, - eth.ChainIDFromUInt64(8453): {Number: 200}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + eth.ChainIDFromUInt64(10): {BlockID: eth.BlockID{Number: 100}}, + eth.ChainIDFromUInt64(8453): {BlockID: eth.BlockID{Number: 200}}, }, } require.False(t, r.IsValid()) @@ -72,8 +73,8 @@ func TestResult_ToVerifiedResult(t *testing.T) { chainID1: {Hash: common.HexToHash("0x2222"), Number: 200}, chainID2: {Hash: common.HexToHash("0x3333"), Number: 300}, }, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - chainID1: {Hash: common.HexToHash("0xbad"), Number: 199}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + chainID1: {BlockID: eth.BlockID{Hash: common.HexToHash("0xbad"), Number: 199}}, }, } @@ -117,8 +118,8 @@ func TestResult_ToVerifiedResult(t *testing.T) { L2Heads: map[eth.ChainID]eth.BlockID{ chainID: {Number: 200}, }, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - chainID: {Number: 199}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + chainID: {BlockID: eth.BlockID{Number: 199}}, }, } @@ -128,3 +129,73 @@ func TestResult_ToVerifiedResult(t *testing.T) { require.Len(t, r.InvalidHeads, 1) }) } + +func TestInvalidHead_JSONRoundTrip(t *testing.T) { + t.Parallel() + + original := InvalidHead{ + BlockID: eth.BlockID{ + Hash: common.HexToHash("0xdead"), + Number: 500, + }, + StateRoot: eth.Bytes32(common.HexToHash("0xstate")), + MessagePasserStorageRoot: eth.Bytes32(common.HexToHash("0xmsgpasser")), + } + + data, err := json.Marshal(original) + require.NoError(t, err) + + var decoded InvalidHead + require.NoError(t, json.Unmarshal(data, &decoded)) + + require.Equal(t, original.BlockID, decoded.BlockID) + require.Equal(t, original.StateRoot, decoded.StateRoot) + require.Equal(t, original.MessagePasserStorageRoot, decoded.MessagePasserStorageRoot) +} + +func TestInvalidHead_JSONRoundTrip_ZeroRoots(t *testing.T) { + t.Parallel() + + original := InvalidHead{ + BlockID: eth.BlockID{ + Hash: common.HexToHash("0xbeef"), + Number: 42, + }, + StateRoot: eth.Bytes32{}, + MessagePasserStorageRoot: eth.Bytes32{}, + } + + data, err := json.Marshal(original) + require.NoError(t, err) + + var decoded InvalidHead + require.NoError(t, json.Unmarshal(data, &decoded)) + + require.Equal(t, original.BlockID, decoded.BlockID) + require.Equal(t, original.StateRoot, decoded.StateRoot) + require.Equal(t, original.MessagePasserStorageRoot, decoded.MessagePasserStorageRoot) +} + +func TestPendingInvalidation_JSONRoundTrip(t *testing.T) { + t.Parallel() + + original := PendingInvalidation{ + ChainID: eth.ChainIDFromUInt64(10), + BlockID: eth.BlockID{Hash: common.HexToHash("0xbad"), Number: 100}, + Timestamp: 42, + StateRoot: eth.Bytes32(common.HexToHash("0xstate")), + MessagePasserStorageRoot: eth.Bytes32(common.HexToHash("0xmsgpasser")), + } + + data, err := json.Marshal(original) + require.NoError(t, err) + + var decoded PendingInvalidation + require.NoError(t, json.Unmarshal(data, &decoded)) + + require.Equal(t, original.ChainID, decoded.ChainID) + require.Equal(t, original.BlockID, decoded.BlockID) + require.Equal(t, original.Timestamp, decoded.Timestamp) + require.Equal(t, original.StateRoot, decoded.StateRoot) + require.Equal(t, original.MessagePasserStorageRoot, decoded.MessagePasserStorageRoot) +} diff --git a/op-supernode/supernode/activity/interop/verified_db.go b/op-supernode/supernode/activity/interop/verified_db.go index 48fc353dac6..b675bb67644 100644 --- a/op-supernode/supernode/activity/interop/verified_db.go +++ b/op-supernode/supernode/activity/interop/verified_db.go @@ -33,9 +33,11 @@ var pendingTransitionKey = []byte("pending") // PendingInvalidation records a chain invalidation that needs to be executed. type PendingInvalidation struct { - ChainID eth.ChainID `json:"chainID"` - BlockID eth.BlockID `json:"blockID"` - Timestamp uint64 `json:"timestamp"` // the interop decision timestamp + ChainID eth.ChainID `json:"chainID"` + BlockID eth.BlockID `json:"blockID"` + Timestamp uint64 `json:"timestamp"` // the interop decision timestamp + StateRoot eth.Bytes32 `json:"stateRoot"` + MessagePasserStorageRoot eth.Bytes32 `json:"messagePasserStorageRoot"` } // VerifiedDB provides persistence for verified timestamps using bbolt. diff --git a/op-supernode/supernode/activity/interop/verified_db_test.go b/op-supernode/supernode/activity/interop/verified_db_test.go index f42ae001042..46551b0aa33 100644 --- a/op-supernode/supernode/activity/interop/verified_db_test.go +++ b/op-supernode/supernode/activity/interop/verified_db_test.go @@ -354,9 +354,17 @@ func TestVerifiedDB_PendingTransition(t *testing.T) { Result: &Result{ Timestamp: 42, L1Inclusion: eth.BlockID{Hash: common.HexToHash("0x1111"), Number: 42}, - InvalidHeads: map[eth.ChainID]eth.BlockID{ - eth.ChainIDFromUInt64(1): {Hash: common.HexToHash("0xaaaa"), Number: 100}, - eth.ChainIDFromUInt64(2): {Hash: common.HexToHash("0xbbbb"), Number: 200}, + InvalidHeads: map[eth.ChainID]InvalidHead{ + eth.ChainIDFromUInt64(1): { + BlockID: eth.BlockID{Hash: common.HexToHash("0xaaaa"), Number: 100}, + StateRoot: eth.Bytes32(common.HexToHash("0xstate1")), + MessagePasserStorageRoot: eth.Bytes32(common.HexToHash("0xmsg1")), + }, + eth.ChainIDFromUInt64(2): { + BlockID: eth.BlockID{Hash: common.HexToHash("0xbbbb"), Number: 200}, + StateRoot: eth.Bytes32(common.HexToHash("0xstate2")), + MessagePasserStorageRoot: eth.Bytes32(common.HexToHash("0xmsg2")), + }, }, }, } diff --git a/op-supernode/supernode/activity/supernode/supernode_test.go b/op-supernode/supernode/activity/supernode/supernode_test.go index bcab76ee70a..e68dde166fd 100644 --- a/op-supernode/supernode/activity/supernode/supernode_test.go +++ b/op-supernode/supernode/activity/supernode/supernode_test.go @@ -75,8 +75,8 @@ func (m *mockCC) OutputRootAtL2BlockNumber(ctx context.Context, l2BlockNum uint6 return eth.Bytes32{}, nil } -func (m *mockCC) OptimisticOutputAtTimestamp(ctx context.Context, ts uint64) (*eth.OutputResponse, error) { - return ð.OutputResponse{}, nil +func (m *mockCC) OptimisticOutputAtTimestamp(ctx context.Context, ts uint64) (*eth.OutputV0, error) { + return ð.OutputV0{}, nil } func (m *mockCC) RewindEngine(ctx context.Context, timestamp uint64, invalidatedBlock eth.BlockRef) error { @@ -97,9 +97,15 @@ func (m *mockCC) ID() eth.ChainID { func (m *mockCC) BlockTime() uint64 { return 1 } -func (m *mockCC) InvalidateBlock(ctx context.Context, height uint64, payloadHash common.Hash, decisionTimestamp uint64) (bool, error) { +func (m *mockCC) InvalidateBlock(ctx context.Context, height uint64, payloadHash common.Hash, decisionTimestamp uint64, stateRoot, messagePasserStorageRoot eth.Bytes32) (bool, error) { return false, nil } +func (m *mockCC) OutputV0AtBlockNumber(ctx context.Context, l2BlockNum uint64) (*eth.OutputV0, error) { + return ð.OutputV0{}, nil +} +func (m *mockCC) GetDeniedOutput(height uint64, payloadHash common.Hash) (*eth.OutputV0, error) { + return nil, nil +} func (m *mockCC) IsDenied(height uint64, payloadHash common.Hash) (bool, error) { return false, nil diff --git a/op-supernode/supernode/activity/superroot/superroot.go b/op-supernode/supernode/activity/superroot/superroot.go index 0c366131704..497aca7cec0 100644 --- a/op-supernode/supernode/activity/superroot/superroot.go +++ b/op-supernode/supernode/activity/superroot/superroot.go @@ -103,6 +103,7 @@ func (s *Superroot) atTimestamp(ctx context.Context, timestamp uint64) (eth.Supe } optimistic[chainID] = eth.OutputWithRequiredL1{ Output: optimisticOut, + OutputRoot: eth.OutputRoot(optimisticOut), RequiredL1: optimisticL1, } } diff --git a/op-supernode/supernode/activity/superroot/superroot_test.go b/op-supernode/supernode/activity/superroot/superroot_test.go index f154d6766d1..7e35c36e93c 100644 --- a/op-supernode/supernode/activity/superroot/superroot_test.go +++ b/op-supernode/supernode/activity/superroot/superroot_test.go @@ -78,12 +78,11 @@ func (m *mockCC) OutputRootAtL2BlockNumber(ctx context.Context, l2BlockNum uint6 } return m.output, nil } -func (m *mockCC) OptimisticOutputAtTimestamp(ctx context.Context, ts uint64) (*eth.OutputResponse, error) { +func (m *mockCC) OptimisticOutputAtTimestamp(ctx context.Context, ts uint64) (*eth.OutputV0, error) { if m.optimisticErr != nil { return nil, m.optimisticErr } - // Return minimal output response; tests only assert presence/count - return ð.OutputResponse{}, nil + return ð.OutputV0{}, nil } func (m *mockCC) RewindEngine(ctx context.Context, timestamp uint64, invalidatedBlock eth.BlockRef) error { return nil @@ -102,9 +101,15 @@ func (m *mockCC) ID() eth.ChainID { } func (m *mockCC) BlockTime() uint64 { return 1 } -func (m *mockCC) InvalidateBlock(ctx context.Context, height uint64, payloadHash common.Hash, decisionTimestamp uint64) (bool, error) { +func (m *mockCC) InvalidateBlock(ctx context.Context, height uint64, payloadHash common.Hash, decisionTimestamp uint64, stateRoot, messagePasserStorageRoot eth.Bytes32) (bool, error) { return false, nil } +func (m *mockCC) OutputV0AtBlockNumber(ctx context.Context, l2BlockNum uint64) (*eth.OutputV0, error) { + return ð.OutputV0{}, nil +} +func (m *mockCC) GetDeniedOutput(height uint64, payloadHash common.Hash) (*eth.OutputV0, error) { + return nil, nil +} func (m *mockCC) PruneDeniedAtOrAfterTimestamp(timestamp uint64) (map[uint64][]common.Hash, error) { return nil, nil } diff --git a/op-supernode/supernode/chain_container/chain_container.go b/op-supernode/supernode/chain_container/chain_container.go index 20b69011657..fe547748888 100644 --- a/op-supernode/supernode/chain_container/chain_container.go +++ b/op-supernode/supernode/chain_container/chain_container.go @@ -41,7 +41,7 @@ type ChainContainer interface { VerifiedAt(ctx context.Context, ts uint64) (l2, l1 eth.BlockID, err error) OptimisticAt(ctx context.Context, ts uint64) (l2, l1 eth.BlockID, err error) OutputRootAtL2BlockNumber(ctx context.Context, l2BlockNum uint64) (eth.Bytes32, error) - OptimisticOutputAtTimestamp(ctx context.Context, ts uint64) (*eth.OutputResponse, error) + OptimisticOutputAtTimestamp(ctx context.Context, ts uint64) (*eth.OutputV0, error) // RewindEngine rewinds the engine to the highest block with timestamp less than or equal to the given timestamp. // invalidatedBlock is the block that triggered the rewind and is passed to reset callbacks. // WARNING: this is a dangerous stateful operation and is intended to be called only @@ -61,13 +61,14 @@ type ChainContainer interface { BlockTime() uint64 // InvalidateBlock adds a block to the deny list and triggers a rewind if the chain // currently uses that block at the specified height. + // output is the marshaled eth.Output preimage for optimistic root computation. // WARNING: this is a dangerous stateful operation and is intended to be called only // by interop transition application. Other callers should not use it until the // interface is refactored to make that ownership explicit. // TODO(#19561): remove this footgun by moving reorg-triggering operations behind a // smaller interop-owned interface. // Returns true if a rewind was triggered, false otherwise. - InvalidateBlock(ctx context.Context, height uint64, payloadHash common.Hash, decisionTimestamp uint64) (bool, error) + InvalidateBlock(ctx context.Context, height uint64, payloadHash common.Hash, decisionTimestamp uint64, stateRoot, messagePasserStorageRoot eth.Bytes32) (bool, error) // PruneDeniedAtOrAfterTimestamp removes deny-list entries with DecisionTimestamp >= timestamp. // Returns map of removed hashes by height. PruneDeniedAtOrAfterTimestamp(timestamp uint64) (map[uint64][]common.Hash, error) @@ -77,6 +78,11 @@ type ChainContainer interface { PauseAndStopVN(ctx context.Context) error // IsDenied checks if a block hash is on the deny list at the given height. IsDenied(height uint64, payloadHash common.Hash) (bool, error) + // GetDeniedOutput returns the reconstructed OutputV0 for a denied block. + // Returns nil if the block is not denied at that height. + GetDeniedOutput(height uint64, payloadHash common.Hash) (*eth.OutputV0, error) + // OutputV0AtBlockNumber returns the full OutputV0 for the block at the given number. + OutputV0AtBlockNumber(ctx context.Context, l2BlockNum uint64) (*eth.OutputV0, error) // SetResetCallback sets a callback that is invoked when the chain resets. // The supernode uses this to notify activities about chain resets. SetResetCallback(cb ResetCallback) @@ -330,10 +336,7 @@ func (c *simpleChainContainer) TimestampToBlockNumber(ctx context.Context, ts ui } func (c *simpleChainContainer) BlockNumberToTimestamp(ctx context.Context, blocknum uint64) (uint64, error) { - if c.vncfg == nil { - return 0, fmt.Errorf("rollup config not available") - } - return c.vncfg.Rollup.Genesis.L2Time + (blocknum * c.vncfg.Rollup.BlockTime), nil + return c.blockNumberToTimestamp(blocknum) } // LocalSafeBlockAtTimestamp returns the highest L2 block with timestamp <= ts using the L2 client, @@ -459,23 +462,27 @@ func (c *simpleChainContainer) OptimisticAt(ctx context.Context, ts uint64) (l2, return l2Block.ID(), l1Block, nil } -// OptimisticOutputAtTimestamp returns the full Output for the optimistic L2 block at the given timestamp. -// For now this simply calls the op-node's normal OutputAtBlock for the block number computed from the timestamp. -func (c *simpleChainContainer) OptimisticOutputAtTimestamp(ctx context.Context, ts uint64) (*eth.OutputResponse, error) { - if c.rollupClient == nil { - return nil, fmt.Errorf("rollup client not initialized") - } - // Determine the optimistic L2 block at timestamp (currently same as safe block at ts) - l2Block, err := c.LocalSafeBlockAtTimestamp(ctx, ts) +// OptimisticOutputAtTimestamp returns the OutputV0 for the "optimistic" L2 block at the given timestamp. +// If the block at this height has been denied (invalidated and replaced), the optimistic output +// is the original (pre-replacement) block's output from the deny list — because optimistically +// the block would not have been replaced. Otherwise it returns the current local safe block's output. +func (c *simpleChainContainer) OptimisticOutputAtTimestamp(ctx context.Context, ts uint64) (*eth.OutputV0, error) { + blockNum, err := c.TimestampToBlockNumber(ctx, ts) if err != nil { - return nil, fmt.Errorf("failed to resolve L2 block at timestamp: %w", err) + return nil, fmt.Errorf("failed to convert timestamp to block number: %w", err) } - // Call the standard OutputAtBlock RPC - out, err := c.rollupClient.OutputAtBlock(ctx, l2Block.Number) - if err != nil { - return nil, fmt.Errorf("failed to get output at block %d: %w", l2Block.Number, err) + + if c.denyList != nil { + outV0, err := c.denyList.LastDeniedOutputV0(blockNum) + if err != nil { + return nil, fmt.Errorf("failed to query deny list at height %d: %w", blockNum, err) + } + if outV0 != nil { + return outV0, nil + } } - return out, nil + + return c.OutputV0AtBlockNumber(ctx, blockNum) } // FetchReceipts fetches the receipts for a given block by hash. @@ -617,9 +624,12 @@ func (c *simpleChainContainer) SetResetCallback(cb ResetCallback) { } // blockNumberToTimestamp converts a block number to its timestamp using rollup config. -func (c *simpleChainContainer) blockNumberToTimestamp(blockNum uint64) uint64 { +func (c *simpleChainContainer) blockNumberToTimestamp(blockNum uint64) (uint64, error) { if c.vncfg == nil { - return 0 + return 0, fmt.Errorf("rollup config not available") + } + if blockNum < c.vncfg.Rollup.Genesis.L2.Number { + return 0, fmt.Errorf("block number %d before genesis %d", blockNum, c.vncfg.Rollup.Genesis.L2.Number) } - return c.vncfg.Rollup.Genesis.L2Time + (blockNum * c.vncfg.Rollup.BlockTime) + return c.vncfg.Rollup.TimestampForBlock(blockNum), nil } diff --git a/op-supernode/supernode/chain_container/chain_container_test.go b/op-supernode/supernode/chain_container/chain_container_test.go index d9e75abbe53..cfb5ae27a6f 100644 --- a/op-supernode/supernode/chain_container/chain_container_test.go +++ b/op-supernode/supernode/chain_container/chain_container_test.go @@ -1167,6 +1167,111 @@ func TestChainContainer_LocalSafeBlockAtTimestamp(t *testing.T) { } } +func TestChainContainer_OptimisticOutputAtTimestamp_ReturnsDeniedOutput(t *testing.T) { + t.Parallel() + + genesisTime := uint64(1000) + blockTime := uint64(2) + vncfg := createTestVNConfig() + vncfg.Rollup.Genesis.L2Time = genesisTime + vncfg.Rollup.BlockTime = blockTime + log := createTestLogger(t) + + dl, err := OpenDenyList(filepath.Join(t.TempDir(), "denylist")) + require.NoError(t, err) + defer dl.Close() + + stateRoot := eth.Bytes32(common.HexToHash("0xabcd")) + msgPasserRoot := eth.Bytes32(common.HexToHash("0x1234")) + payloadHash := common.HexToHash("0xdead") + + // Block at height 5: timestamp = 1000 + 5*2 = 1010 + height := uint64(5) + ts := genesisTime + height*blockTime + require.NoError(t, dl.Add(height, payloadHash, 0, stateRoot, msgPasserRoot)) + + container := &simpleChainContainer{ + vncfg: vncfg, + denyList: dl, + log: log, + } + + out, err := container.OptimisticOutputAtTimestamp(context.Background(), ts) + require.NoError(t, err) + + require.Equal(t, ð.OutputV0{ + StateRoot: stateRoot, + MessagePasserStorageRoot: msgPasserRoot, + BlockHash: payloadHash, + }, out) +} + +func TestChainContainer_OptimisticOutputAtTimestamp_UsesLatestDeniedRecord(t *testing.T) { + t.Parallel() + + genesisTime := uint64(1000) + blockTime := uint64(2) + vncfg := createTestVNConfig() + vncfg.Rollup.Genesis.L2Time = genesisTime + vncfg.Rollup.BlockTime = blockTime + log := createTestLogger(t) + + dl, err := OpenDenyList(filepath.Join(t.TempDir(), "denylist")) + require.NoError(t, err) + defer dl.Close() + + height := uint64(5) + ts := genesisTime + height*blockTime + + // Add two denied records at the same height — the latest should win + firstHash := common.HexToHash("0x1111") + require.NoError(t, dl.Add(height, firstHash, 100, eth.Bytes32{0x01}, eth.Bytes32{0x02})) + + latestHash := common.HexToHash("0x2222") + latestState := eth.Bytes32(common.HexToHash("0xlatest")) + latestMsgPasser := eth.Bytes32(common.HexToHash("0xlatestmp")) + require.NoError(t, dl.Add(height, latestHash, 200, latestState, latestMsgPasser)) + + container := &simpleChainContainer{ + vncfg: vncfg, + denyList: dl, + log: log, + } + + out, err := container.OptimisticOutputAtTimestamp(context.Background(), ts) + require.NoError(t, err) + require.Equal(t, latestHash, out.BlockHash) + require.Equal(t, latestState, out.StateRoot) + require.Equal(t, latestMsgPasser, out.MessagePasserStorageRoot) +} + +func TestChainContainer_OptimisticOutputAtTimestamp_FallsThroughWhenNoDenied(t *testing.T) { + t.Parallel() + + genesisTime := uint64(1000) + blockTime := uint64(2) + vncfg := createTestVNConfig() + vncfg.Rollup.Genesis.L2Time = genesisTime + vncfg.Rollup.BlockTime = blockTime + log := createTestLogger(t) + + // Empty deny list — no denied records at any height + dl, err := OpenDenyList(filepath.Join(t.TempDir(), "denylist")) + require.NoError(t, err) + defer dl.Close() + + container := &simpleChainContainer{ + vncfg: vncfg, + denyList: dl, + log: log, + // No engine set, so the fallback path will error — proving we reached it + } + + _, err = container.OptimisticOutputAtTimestamp(context.Background(), genesisTime+5*blockTime) + require.Error(t, err) + require.ErrorIs(t, err, engine_controller.ErrNoEngineClient) +} + func TestChainContainer_SyncStatus_UninitializedVirtualNode(t *testing.T) { t.Parallel() @@ -1181,3 +1286,29 @@ func TestChainContainer_SyncStatus_UninitializedVirtualNode(t *testing.T) { require.Nil(t, status) require.ErrorIs(t, err, virtual_node.ErrVirtualNodeNotRunning) } + +func TestChainContainer_BlockNumberToTimestamp_RespectsGenesisBlockNumber(t *testing.T) { + t.Parallel() + + chainID := eth.ChainIDFromUInt64(420) + log := createTestLogger(t) + cfg := createTestCLIConfig(t.TempDir()) + initOverload := &rollupNode.InitializationOverrides{} + + vncfg := createTestVNConfig() + vncfg.Rollup.Genesis.L2Time = 1000 + vncfg.Rollup.Genesis.L2.Number = 100 + vncfg.Rollup.BlockTime = 2 + + container := NewChainContainer(chainID, vncfg, log, cfg, initOverload, nil, nil, nil) + impl, ok := container.(*simpleChainContainer) + require.True(t, ok) + + timestamp, err := impl.BlockNumberToTimestamp(context.Background(), 104) + require.NoError(t, err) + require.Equal(t, uint64(1008), timestamp) + + _, err = impl.BlockNumberToTimestamp(context.Background(), 99) + require.Error(t, err) + require.Contains(t, err.Error(), "before genesis 100") +} diff --git a/op-supernode/supernode/chain_container/invalidation.go b/op-supernode/supernode/chain_container/invalidation.go index 7bfffac5f6a..175cfd0ed6f 100644 --- a/op-supernode/supernode/chain_container/invalidation.go +++ b/op-supernode/supernode/chain_container/invalidation.go @@ -9,6 +9,7 @@ import ( "path/filepath" "sync" + "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum/common" bolt "go.etcd.io/bbolt" ) @@ -27,10 +28,13 @@ type DenyList struct { mu sync.RWMutex } -// DenyRecord stores a denied payload hash along with decision provenance. +// DenyRecord stores a denied payload hash along with decision provenance +// and the output preimage fields for optimistic root computation. type DenyRecord struct { - PayloadHash common.Hash `json:"payloadHash"` - DecisionTimestamp uint64 `json:"decisionTimestamp"` + PayloadHash common.Hash `json:"payloadHash"` + DecisionTimestamp uint64 `json:"decisionTimestamp"` + StateRoot eth.Bytes32 `json:"stateRoot"` + MessagePasserStorageRoot eth.Bytes32 `json:"messagePasserStorageRoot"` } func encodeDenyRecords(records []DenyRecord) ([]byte, error) { @@ -42,24 +46,8 @@ func decodeDenyRecords(raw []byte) ([]DenyRecord, error) { return nil, nil } var records []DenyRecord - if err := json.Unmarshal(raw, &records); err == nil { - return records, nil - } - // Backward compatibility: legacy format is concatenated 32-byte hashes. - // Legacy entries get DecisionTimestamp: 0, which means they are never - // removed by PruneAtOrAfterTimestamp (since rewind timestamps are always - // well above 0). This is the safe default — deny decisions from before - // provenance tracking was added should be preserved rather than silently - // dropped. - if len(raw)%common.HashLength != 0 { - return nil, fmt.Errorf("invalid denylist record payload length %d", len(raw)) - } - records = make([]DenyRecord, 0, len(raw)/common.HashLength) - for i := 0; i+common.HashLength <= len(raw); i += common.HashLength { - records = append(records, DenyRecord{ - PayloadHash: common.BytesToHash(raw[i : i+common.HashLength]), - DecisionTimestamp: 0, - }) + if err := json.Unmarshal(raw, &records); err != nil { + return nil, fmt.Errorf("failed to decode denylist records: %w", err) } return records, nil } @@ -97,8 +85,9 @@ func heightToKey(height uint64) []byte { } // Add adds a payload hash to the deny list at the given block height. +// stateRoot and messagePasserStorageRoot are the output preimage fields for optimistic root computation. // Multiple hashes can be denied at the same height. -func (d *DenyList) Add(height uint64, payloadHash common.Hash, decisionTimestamp uint64) error { +func (d *DenyList) Add(height uint64, payloadHash common.Hash, decisionTimestamp uint64, stateRoot, messagePasserStorageRoot eth.Bytes32) error { d.mu.Lock() defer d.mu.Unlock() @@ -113,7 +102,6 @@ func (d *DenyList) Add(height uint64, payloadHash common.Hash, decisionTimestamp return err } - // Check if hash already exists for _, r := range records { if r.PayloadHash == payloadHash { return nil @@ -121,8 +109,10 @@ func (d *DenyList) Add(height uint64, payloadHash common.Hash, decisionTimestamp } records = append(records, DenyRecord{ - PayloadHash: payloadHash, - DecisionTimestamp: decisionTimestamp, + PayloadHash: payloadHash, + DecisionTimestamp: decisionTimestamp, + StateRoot: stateRoot, + MessagePasserStorageRoot: messagePasserStorageRoot, }) encoded, err := encodeDenyRecords(records) @@ -133,6 +123,77 @@ func (d *DenyList) Add(height uint64, payloadHash common.Hash, decisionTimestamp }) } +// LastDeniedOutputV0 returns the OutputV0 for the most recently denied block at the given height. +// Returns nil if no blocks are denied at that height. +// Note: supernode does not currently behave in well defined ways when there are multiple denied blocks at the same height. +func (d *DenyList) LastDeniedOutputV0(height uint64) (*eth.OutputV0, error) { + d.mu.RLock() + defer d.mu.RUnlock() + + key := heightToKey(height) + var result *eth.OutputV0 + + err := d.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket(denyListBucketName) + existing := b.Get(key) + if existing == nil { + return nil + } + + records, err := decodeDenyRecords(existing) + if err != nil { + return err + } + if len(records) > 0 { + r := records[len(records)-1] + result = ð.OutputV0{ + StateRoot: r.StateRoot, + MessagePasserStorageRoot: r.MessagePasserStorageRoot, + BlockHash: r.PayloadHash, + } + } + return nil + }) + + return result, err +} + +// GetOutputV0 reconstructs and returns the full OutputV0 for a denied block. +// Returns nil if the hash is not denied at that height. +func (d *DenyList) GetOutputV0(height uint64, payloadHash common.Hash) (*eth.OutputV0, error) { + d.mu.RLock() + defer d.mu.RUnlock() + + key := heightToKey(height) + var result *eth.OutputV0 + + err := d.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket(denyListBucketName) + existing := b.Get(key) + if existing == nil { + return nil + } + + records, err := decodeDenyRecords(existing) + if err != nil { + return err + } + for _, r := range records { + if r.PayloadHash == payloadHash { + result = ð.OutputV0{ + StateRoot: r.StateRoot, + MessagePasserStorageRoot: r.MessagePasserStorageRoot, + BlockHash: payloadHash, + } + return nil + } + } + return nil + }) + + return result, err +} + // Contains checks if a payload hash is denied at the given block height. func (d *DenyList) Contains(height uint64, payloadHash common.Hash) (bool, error) { d.mu.RLock() @@ -278,7 +339,7 @@ func (d *DenyList) Close() error { // smaller interop-owned interface. // Returns true if a rewind was triggered, false otherwise. // Note: Genesis block (height=0) cannot be invalidated as there is no prior block to rewind to. -func (c *simpleChainContainer) InvalidateBlock(ctx context.Context, height uint64, payloadHash common.Hash, decisionTimestamp uint64) (bool, error) { +func (c *simpleChainContainer) InvalidateBlock(ctx context.Context, height uint64, payloadHash common.Hash, decisionTimestamp uint64, stateRoot, messagePasserStorageRoot eth.Bytes32) (bool, error) { if c.denyList == nil { return false, fmt.Errorf("deny list not initialized") } @@ -288,8 +349,8 @@ func (c *simpleChainContainer) InvalidateBlock(ctx context.Context, height uint6 return false, fmt.Errorf("cannot invalidate genesis block (height=0)") } - // Add to deny list first - if err := c.denyList.Add(height, payloadHash, decisionTimestamp); err != nil { + // Add to deny list with the output preimage fields + if err := c.denyList.Add(height, payloadHash, decisionTimestamp, stateRoot, messagePasserStorageRoot); err != nil { return false, fmt.Errorf("failed to add block to deny list: %w", err) } @@ -328,7 +389,10 @@ func (c *simpleChainContainer) InvalidateBlock(ctx context.Context, height uint6 invalidatedBlock := currentBlock.BlockRef() // Rewind to the prior block's timestamp - priorTimestamp := c.blockNumberToTimestamp(height - 1) + priorTimestamp, err := c.blockNumberToTimestamp(height - 1) + if err != nil { + return false, fmt.Errorf("failed to compute rewind timestamp: %w", err) + } if err := c.RewindEngine(ctx, priorTimestamp, invalidatedBlock); err != nil { return false, fmt.Errorf("failed to rewind engine: %w", err) } diff --git a/op-supernode/supernode/chain_container/invalidation_test.go b/op-supernode/supernode/chain_container/invalidation_test.go index a910ed11069..15471b03c49 100644 --- a/op-supernode/supernode/chain_container/invalidation_test.go +++ b/op-supernode/supernode/chain_container/invalidation_test.go @@ -13,7 +13,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" gethlog "github.com/ethereum/go-ethereum/log" "github.com/stretchr/testify/require" - bolt "go.etcd.io/bbolt" ) func TestDenyList_AddAndContains(t *testing.T) { @@ -28,7 +27,7 @@ func TestDenyList_AddAndContains(t *testing.T) { name: "single hash at height", setup: func(t *testing.T, dl *DenyList) { hash := common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") - require.NoError(t, dl.Add(100, hash, 0)) + require.NoError(t, dl.Add(100, hash, 0, eth.Bytes32{}, eth.Bytes32{})) }, check: func(t *testing.T, dl *DenyList) { hash := common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") @@ -46,7 +45,7 @@ func TestDenyList_AddAndContains(t *testing.T) { common.HexToHash("0xcccc"), } for _, h := range hashes { - require.NoError(t, dl.Add(50, h, 0)) + require.NoError(t, dl.Add(50, h, 0, eth.Bytes32{}, eth.Bytes32{})) } }, check: func(t *testing.T, dl *DenyList) { @@ -66,7 +65,7 @@ func TestDenyList_AddAndContains(t *testing.T) { name: "hash at wrong height returns false", setup: func(t *testing.T, dl *DenyList) { hash := common.HexToHash("0xdddd") - require.NoError(t, dl.Add(10, hash, 0)) + require.NoError(t, dl.Add(10, hash, 0, eth.Bytes32{}, eth.Bytes32{})) }, check: func(t *testing.T, dl *DenyList) { hash := common.HexToHash("0xdddd") @@ -85,9 +84,9 @@ func TestDenyList_AddAndContains(t *testing.T) { name: "duplicate add is idempotent", setup: func(t *testing.T, dl *DenyList) { hash := common.HexToHash("0xeeee") - require.NoError(t, dl.Add(200, hash, 0)) - require.NoError(t, dl.Add(200, hash, 0)) // Add again - require.NoError(t, dl.Add(200, hash, 0)) // And again + require.NoError(t, dl.Add(200, hash, 0, eth.Bytes32{}, eth.Bytes32{})) + require.NoError(t, dl.Add(200, hash, 0, eth.Bytes32{}, eth.Bytes32{})) // Add again + require.NoError(t, dl.Add(200, hash, 0, eth.Bytes32{}, eth.Bytes32{})) // And again }, check: func(t *testing.T, dl *DenyList) { hash := common.HexToHash("0xeeee") @@ -137,7 +136,7 @@ func TestDenyList_Persistence(t *testing.T) { {300, common.HexToHash("0x4444")}, } for _, h := range hashes { - require.NoError(t, dl.Add(h.height, h.hash, 0)) + require.NoError(t, dl.Add(h.height, h.hash, 0, eth.Bytes32{}, eth.Bytes32{})) } require.NoError(t, dl.Close()) @@ -219,7 +218,7 @@ func TestDenyList_GetDeniedHashes(t *testing.T) { setup: func(t *testing.T, dl *DenyList) { for i := 0; i < 5; i++ { hash := common.BigToHash(common.Big1.Add(common.Big1, common.Big0.SetInt64(int64(i)))) - require.NoError(t, dl.Add(100, hash, 0)) + require.NoError(t, dl.Add(100, hash, 0, eth.Bytes32{}, eth.Bytes32{})) } }, check: func(t *testing.T, dl *DenyList) { @@ -232,8 +231,8 @@ func TestDenyList_GetDeniedHashes(t *testing.T) { name: "empty for clean height", setup: func(t *testing.T, dl *DenyList) { // Add hashes at other heights - require.NoError(t, dl.Add(10, common.HexToHash("0xaaaa"), 0)) - require.NoError(t, dl.Add(30, common.HexToHash("0xbbbb"), 0)) + require.NoError(t, dl.Add(10, common.HexToHash("0xaaaa"), 0, eth.Bytes32{}, eth.Bytes32{})) + require.NoError(t, dl.Add(30, common.HexToHash("0xbbbb"), 0, eth.Bytes32{}, eth.Bytes32{})) }, check: func(t *testing.T, dl *DenyList) { hashes, err := dl.GetDeniedHashes(20) @@ -245,12 +244,12 @@ func TestDenyList_GetDeniedHashes(t *testing.T) { name: "isolated by height", setup: func(t *testing.T, dl *DenyList) { // Add different hashes at different heights - require.NoError(t, dl.Add(10, common.HexToHash("0x1010"), 0)) - require.NoError(t, dl.Add(10, common.HexToHash("0x1011"), 0)) - require.NoError(t, dl.Add(20, common.HexToHash("0x2020"), 0)) - require.NoError(t, dl.Add(20, common.HexToHash("0x2021"), 0)) - require.NoError(t, dl.Add(20, common.HexToHash("0x2022"), 0)) - require.NoError(t, dl.Add(30, common.HexToHash("0x3030"), 0)) + require.NoError(t, dl.Add(10, common.HexToHash("0x1010"), 0, eth.Bytes32{}, eth.Bytes32{})) + require.NoError(t, dl.Add(10, common.HexToHash("0x1011"), 0, eth.Bytes32{}, eth.Bytes32{})) + require.NoError(t, dl.Add(20, common.HexToHash("0x2020"), 0, eth.Bytes32{}, eth.Bytes32{})) + require.NoError(t, dl.Add(20, common.HexToHash("0x2021"), 0, eth.Bytes32{}, eth.Bytes32{})) + require.NoError(t, dl.Add(20, common.HexToHash("0x2022"), 0, eth.Bytes32{}, eth.Bytes32{})) + require.NoError(t, dl.Add(30, common.HexToHash("0x3030"), 0, eth.Bytes32{}, eth.Bytes32{})) }, check: func(t *testing.T, dl *DenyList) { hashes10, err := dl.GetDeniedHashes(10) @@ -351,6 +350,7 @@ func TestInvalidateBlock(t *testing.T) { tests := []struct { name string + genesisBlock uint64 height uint64 payloadHash common.Hash currentBlockHash common.Hash @@ -360,6 +360,7 @@ func TestInvalidateBlock(t *testing.T) { }{ { name: "current block matches triggers rewind", + genesisBlock: 0, height: 5, payloadHash: common.HexToHash("0xdead"), currentBlockHash: common.HexToHash("0xdead"), // Same hash @@ -369,6 +370,7 @@ func TestInvalidateBlock(t *testing.T) { }, { name: "current block differs no rewind", + genesisBlock: 0, height: 5, payloadHash: common.HexToHash("0xdead"), currentBlockHash: common.HexToHash("0xbeef"), // Different hash @@ -377,6 +379,7 @@ func TestInvalidateBlock(t *testing.T) { }, { name: "engine unavailable adds to denylist only", + genesisBlock: 0, height: 5, payloadHash: common.HexToHash("0xdead"), engineAvailable: false, @@ -384,6 +387,7 @@ func TestInvalidateBlock(t *testing.T) { }, { name: "rewind to height-1 timestamp calculated correctly", + genesisBlock: 0, height: 10, payloadHash: common.HexToHash("0xabcd"), currentBlockHash: common.HexToHash("0xabcd"), @@ -391,6 +395,16 @@ func TestInvalidateBlock(t *testing.T) { expectRewind: true, expectRewindTs: genesisTime + (9 * blockTime), // height 9 }, + { + name: "rewind timestamp respects nonzero genesis block number", + genesisBlock: 100, + height: 105, + payloadHash: common.HexToHash("0xcafe"), + currentBlockHash: common.HexToHash("0xcafe"), + engineAvailable: true, + expectRewind: true, + expectRewindTs: genesisTime + (4 * blockTime), // block 104 relative to genesis block 100 + }, } // Separate test for genesis block (height=0) which should error @@ -408,7 +422,7 @@ func TestInvalidateBlock(t *testing.T) { } ctx := context.Background() - rewound, err := c.InvalidateBlock(ctx, 0, common.HexToHash("0xgenesis"), 0) + rewound, err := c.InvalidateBlock(ctx, 0, common.HexToHash("0xgenesis"), 0, eth.Bytes32{}, eth.Bytes32{}) require.Error(t, err) require.Contains(t, err.Error(), "cannot invalidate genesis block") @@ -420,6 +434,34 @@ func TestInvalidateBlock(t *testing.T) { require.False(t, found, "genesis block should not be added to denylist") }) + t.Run("missing rollup config returns error before rewind", func(t *testing.T) { + t.Parallel() + dir := t.TempDir() + + dl, err := OpenDenyList(filepath.Join(dir, "denylist")) + require.NoError(t, err) + defer dl.Close() + + mockEng := &mockEngineForInvalidation{ + blockRef: eth.L2BlockRef{Hash: common.HexToHash("0xdead")}, + } + + c := &simpleChainContainer{ + denyList: dl, + log: testLogger(), + engine: mockEng, + vn: &mockVNForInvalidation{}, + } + + rewound, err := c.InvalidateBlock(context.Background(), 5, common.HexToHash("0xdead"), 0, eth.Bytes32{}, eth.Bytes32{}) + + require.Error(t, err) + require.Contains(t, err.Error(), "failed to compute rewind timestamp") + require.Contains(t, err.Error(), "rollup config not available") + require.False(t, rewound) + require.False(t, mockEng.rewindCalled, "rewind should not be attempted without rollup config") + }) + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() @@ -443,15 +485,23 @@ func TestInvalidateBlock(t *testing.T) { vn: &mockVNForInvalidation{}, } c.vncfg.Rollup.Genesis.L2Time = genesisTime + c.vncfg.Rollup.Genesis.L2.Number = tt.genesisBlock c.vncfg.Rollup.BlockTime = blockTime if tt.engineAvailable { c.engine = mockEng } - // Call InvalidateBlock + testStateRoot := eth.Bytes32(common.HexToHash("0xstate")) + testMsgPasserRoot := eth.Bytes32(common.HexToHash("0xmsgpasser")) + testOut := ð.OutputV0{ + StateRoot: testStateRoot, + MessagePasserStorageRoot: testMsgPasserRoot, + BlockHash: tt.payloadHash, + } + ctx := context.Background() - rewound, err := c.InvalidateBlock(ctx, tt.height, tt.payloadHash, 0) + rewound, err := c.InvalidateBlock(ctx, tt.height, tt.payloadHash, 0, testStateRoot, testMsgPasserRoot) require.NoError(t, err) // Verify rewind behavior @@ -466,10 +516,59 @@ func TestInvalidateBlock(t *testing.T) { found, err := dl.Contains(tt.height, tt.payloadHash) require.NoError(t, err) require.True(t, found, "hash should be in denylist after InvalidateBlock") + + storedOutput, err := dl.GetOutputV0(tt.height, tt.payloadHash) + require.NoError(t, err) + require.Equal(t, testOut, storedOutput, "OutputV0 should be stored in denylist after InvalidateBlock") }) } } +func TestGetDeniedOutput(t *testing.T) { + t.Parallel() + + dir := t.TempDir() + dl, err := OpenDenyList(filepath.Join(dir, "denylist")) + require.NoError(t, err) + defer dl.Close() + + testStateRoot := eth.Bytes32(common.HexToHash("0xstate")) + testMsgPasserRoot := eth.Bytes32(common.HexToHash("0xmsgpasser")) + hash := common.HexToHash("0xdead") + + c := &simpleChainContainer{ + denyList: dl, + log: testLogger(), + } + + t.Run("returns output after InvalidateBlock", func(t *testing.T) { + require.NoError(t, dl.Add(100, hash, 0, testStateRoot, testMsgPasserRoot)) + + got, err := c.GetDeniedOutput(100, hash) + require.NoError(t, err) + want := ð.OutputV0{ + StateRoot: testStateRoot, + MessagePasserStorageRoot: testMsgPasserRoot, + BlockHash: hash, + } + require.Equal(t, want, got) + }) + + t.Run("returns nil for non-denied block", func(t *testing.T) { + got, err := c.GetDeniedOutput(999, common.HexToHash("0xunknown")) + require.NoError(t, err) + require.Nil(t, got) + }) + + t.Run("returns error when denylist not initialized", func(t *testing.T) { + noDenyList := &simpleChainContainer{ + log: testLogger(), + } + _, err := noDenyList.GetDeniedOutput(100, hash) + require.Error(t, err) + }) +} + func TestIsDenied(t *testing.T) { t.Parallel() @@ -517,7 +616,7 @@ func TestIsDenied(t *testing.T) { defer dl.Close() // Setup - require.NoError(t, dl.Add(tt.setupHeight, tt.setupHash, 0)) + require.NoError(t, dl.Add(tt.setupHeight, tt.setupHash, 0, eth.Bytes32{}, eth.Bytes32{})) // Create container c := &simpleChainContainer{ @@ -574,7 +673,7 @@ func TestDenyList_ConcurrentAccess(t *testing.T) { hash := makeHash(accessorID, j) // Write - err := dl.Add(height, hash, 0) + err := dl.Add(height, hash, 0, eth.Bytes32{}, eth.Bytes32{}) require.NoError(t, err) // Read own write @@ -617,9 +716,9 @@ func TestDenyList_PruneAtOrAfterTimestamp(t *testing.T) { hashA := common.HexToHash("0xaaaa") hashB := common.HexToHash("0xbbbb") hashC := common.HexToHash("0xcccc") - require.NoError(t, dl.Add(100, hashA, 10)) - require.NoError(t, dl.Add(100, hashB, 11)) - require.NoError(t, dl.Add(200, hashC, 12)) + require.NoError(t, dl.Add(100, hashA, 10, eth.Bytes32{}, eth.Bytes32{})) + require.NoError(t, dl.Add(100, hashB, 11, eth.Bytes32{}, eth.Bytes32{})) + require.NoError(t, dl.Add(200, hashC, 12, eth.Bytes32{}, eth.Bytes32{})) removed, err := dl.PruneAtOrAfterTimestamp(11) require.NoError(t, err) @@ -641,32 +740,202 @@ func TestDenyList_PruneAtOrAfterTimestamp(t *testing.T) { require.Empty(t, records200) } -func TestDenyList_DecodesLegacyHashOnlyFormat(t *testing.T) { +func TestDenyList_GetOutputV0(t *testing.T) { t.Parallel() + dir := t.TempDir() dl, err := OpenDenyList(dir) require.NoError(t, err) defer dl.Close() - hashA := common.HexToHash("0xaaaa") - hashB := common.HexToHash("0xbbbb") - raw := append(hashA.Bytes(), hashB.Bytes()...) + out := ð.OutputV0{ + StateRoot: eth.Bytes32(common.HexToHash("0xstate")), + MessagePasserStorageRoot: eth.Bytes32(common.HexToHash("0xmsgpasser")), + BlockHash: common.HexToHash("0xblock"), + } + hash := common.HexToHash("0x1111") + require.NoError(t, dl.Add(100, hash, 0, out.StateRoot, out.MessagePasserStorageRoot)) + + want := ð.OutputV0{ + StateRoot: out.StateRoot, + MessagePasserStorageRoot: out.MessagePasserStorageRoot, + BlockHash: hash, + } - // Write legacy format directly to bbolt - dl.mu.Lock() - err = dl.db.Update(func(tx *bolt.Tx) error { - return tx.Bucket(denyListBucketName).Put(heightToKey(100), raw) + t.Run("returns stored OutputV0 for matching hash and height", func(t *testing.T) { + got, err := dl.GetOutputV0(100, hash) + require.NoError(t, err) + require.Equal(t, want, got) + }) + + t.Run("returns nil for wrong hash at same height", func(t *testing.T) { + got, err := dl.GetOutputV0(100, common.HexToHash("0x9999")) + require.NoError(t, err) + require.Nil(t, got) + }) + + t.Run("returns nil for correct hash at wrong height", func(t *testing.T) { + got, err := dl.GetOutputV0(200, hash) + require.NoError(t, err) + require.Nil(t, got) }) - dl.mu.Unlock() + + t.Run("returns nil for empty height", func(t *testing.T) { + got, err := dl.GetOutputV0(999, common.HexToHash("0xabcd")) + require.NoError(t, err) + require.Nil(t, got) + }) + + t.Run("isolates outputs per hash at same height", func(t *testing.T) { + out2 := ð.OutputV0{ + StateRoot: eth.Bytes32(common.HexToHash("0xstate2")), + MessagePasserStorageRoot: eth.Bytes32(common.HexToHash("0xmsgpasser2")), + BlockHash: common.HexToHash("0xblock2"), + } + hash2 := common.HexToHash("0x2222") + require.NoError(t, dl.Add(100, hash2, 0, out2.StateRoot, out2.MessagePasserStorageRoot)) + + got1, err := dl.GetOutputV0(100, hash) + require.NoError(t, err) + require.Equal(t, want, got1) + + want2 := ð.OutputV0{ + StateRoot: out2.StateRoot, + MessagePasserStorageRoot: out2.MessagePasserStorageRoot, + BlockHash: hash2, + } + got2, err := dl.GetOutputV0(100, hash2) + require.NoError(t, err) + require.Equal(t, want2, got2) + }) +} + +func TestDenyList_LastDeniedOutputV0(t *testing.T) { + t.Parallel() + + dir := t.TempDir() + dl, err := OpenDenyList(dir) require.NoError(t, err) + defer dl.Close() + + t.Run("returns nil for empty height", func(t *testing.T) { + got, err := dl.LastDeniedOutputV0(999) + require.NoError(t, err) + require.Nil(t, got) + }) + + t.Run("returns the single record", func(t *testing.T) { + hash := common.HexToHash("0xaaaa") + stateRoot := eth.Bytes32(common.HexToHash("0xstate1")) + msgPasser := eth.Bytes32(common.HexToHash("0xmp1")) + require.NoError(t, dl.Add(50, hash, 100, stateRoot, msgPasser)) + + got, err := dl.LastDeniedOutputV0(50) + require.NoError(t, err) + require.Equal(t, ð.OutputV0{ + StateRoot: stateRoot, + MessagePasserStorageRoot: msgPasser, + BlockHash: hash, + }, got) + }) + + t.Run("returns the last record when multiple exist", func(t *testing.T) { + firstHash := common.HexToHash("0xbbbb") + require.NoError(t, dl.Add(60, firstHash, 100, eth.Bytes32{0x01}, eth.Bytes32{0x02})) + + lastHash := common.HexToHash("0xcccc") + lastState := eth.Bytes32(common.HexToHash("0xlast_state")) + lastMsgPasser := eth.Bytes32(common.HexToHash("0xlast_mp")) + require.NoError(t, dl.Add(60, lastHash, 200, lastState, lastMsgPasser)) + + got, err := dl.LastDeniedOutputV0(60) + require.NoError(t, err) + require.Equal(t, ð.OutputV0{ + StateRoot: lastState, + MessagePasserStorageRoot: lastMsgPasser, + BlockHash: lastHash, + }, got) + }) +} + +func TestDenyList_OutputPersistence(t *testing.T) { + t.Parallel() + + dir := filepath.Join(t.TempDir(), "denylist") + + out := ð.OutputV0{ + StateRoot: eth.Bytes32(common.HexToHash("0xpersist_state")), + MessagePasserStorageRoot: eth.Bytes32(common.HexToHash("0xpersist_msgpasser")), + BlockHash: common.HexToHash("0xpersist_block"), + } + hash := common.HexToHash("0xdead") + want := ð.OutputV0{ + StateRoot: out.StateRoot, + MessagePasserStorageRoot: out.MessagePasserStorageRoot, + BlockHash: hash, + } + + // Write and close + dl, err := OpenDenyList(dir) + require.NoError(t, err) + require.NoError(t, dl.Add(100, hash, 42, out.StateRoot, out.MessagePasserStorageRoot)) + require.NoError(t, dl.Close()) + + // Reopen and verify output persisted + dl2, err := OpenDenyList(dir) + require.NoError(t, err) + defer dl2.Close() + + got, err := dl2.GetOutputV0(100, hash) + require.NoError(t, err) + require.Equal(t, want, got) + + records, err := dl2.GetDeniedRecords(100) + require.NoError(t, err) + require.Len(t, records, 1) + require.Equal(t, hash, records[0].PayloadHash) + require.Equal(t, uint64(42), records[0].DecisionTimestamp) + require.Equal(t, out.StateRoot, records[0].StateRoot) + require.Equal(t, out.MessagePasserStorageRoot, records[0].MessagePasserStorageRoot) +} + +func TestDenyList_GetDeniedRecords_IncludesRoots(t *testing.T) { + t.Parallel() + + dir := t.TempDir() + dl, err := OpenDenyList(dir) + require.NoError(t, err) + defer dl.Close() + + out1 := ð.OutputV0{ + StateRoot: eth.Bytes32(common.HexToHash("0xstate1")), + MessagePasserStorageRoot: eth.Bytes32(common.HexToHash("0xmsg1")), + BlockHash: common.HexToHash("0xblock1"), + } + out2 := ð.OutputV0{ + StateRoot: eth.Bytes32(common.HexToHash("0xstate2")), + MessagePasserStorageRoot: eth.Bytes32(common.HexToHash("0xmsg2")), + BlockHash: common.HexToHash("0xblock2"), + } + hash1 := common.HexToHash("0xaaaa") + hash2 := common.HexToHash("0xbbbb") + + require.NoError(t, dl.Add(100, hash1, 10, out1.StateRoot, out1.MessagePasserStorageRoot)) + require.NoError(t, dl.Add(100, hash2, 11, out2.StateRoot, out2.MessagePasserStorageRoot)) records, err := dl.GetDeniedRecords(100) require.NoError(t, err) require.Len(t, records, 2) - require.Equal(t, DenyRecord{PayloadHash: hashA, DecisionTimestamp: 0}, records[0]) - require.Equal(t, DenyRecord{PayloadHash: hashB, DecisionTimestamp: 0}, records[1]) - found, err := dl.Contains(100, hashA) - require.NoError(t, err) - require.True(t, found) + recordMap := make(map[common.Hash]DenyRecord) + for _, r := range records { + recordMap[r.PayloadHash] = r + } + + require.Equal(t, out1.StateRoot, recordMap[hash1].StateRoot) + require.Equal(t, out1.MessagePasserStorageRoot, recordMap[hash1].MessagePasserStorageRoot) + require.Equal(t, uint64(10), recordMap[hash1].DecisionTimestamp) + require.Equal(t, out2.StateRoot, recordMap[hash2].StateRoot) + require.Equal(t, out2.MessagePasserStorageRoot, recordMap[hash2].MessagePasserStorageRoot) + require.Equal(t, uint64(11), recordMap[hash2].DecisionTimestamp) } diff --git a/op-supernode/supernode/chain_container/super_authority.go b/op-supernode/supernode/chain_container/super_authority.go index 1455c8abf81..19d9d911de9 100644 --- a/op-supernode/supernode/chain_container/super_authority.go +++ b/op-supernode/supernode/chain_container/super_authority.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supernode/supernode/chain_container/engine_controller" "github.com/ethereum/go-ethereum/common" ) @@ -91,5 +92,21 @@ func (c *simpleChainContainer) IsDenied(height uint64, payloadHash common.Hash) return c.denyList.Contains(height, payloadHash) } +// GetDeniedOutput returns the reconstructed OutputV0 for a denied block. +func (c *simpleChainContainer) GetDeniedOutput(height uint64, payloadHash common.Hash) (*eth.OutputV0, error) { + if c.denyList == nil { + return nil, fmt.Errorf("deny list not initialized") + } + return c.denyList.GetOutputV0(height, payloadHash) +} + +// OutputV0AtBlockNumber returns the full OutputV0 for the block at the given number. +func (c *simpleChainContainer) OutputV0AtBlockNumber(ctx context.Context, l2BlockNum uint64) (*eth.OutputV0, error) { + if c.engine == nil { + return nil, engine_controller.ErrNoEngineClient + } + return c.engine.OutputV0AtBlockNumber(ctx, l2BlockNum) +} + // Interface satisfaction static check var _ rollup.SuperAuthority = (*simpleChainContainer)(nil) diff --git a/op-test-sequencer/sequencer/backend/work/builders/fakepos/job.go b/op-test-sequencer/sequencer/backend/work/builders/fakepos/job.go index 0436963b4b0..8d850e0aa92 100644 --- a/op-test-sequencer/sequencer/backend/work/builders/fakepos/job.go +++ b/op-test-sequencer/sequencer/backend/work/builders/fakepos/job.go @@ -125,7 +125,7 @@ func (j *Job) Open(ctx context.Context) error { } j.logger.Info("ForkchoiceUpdatedV3", "fcState", fcState) - res, err := j.b.engine.ForkchoiceUpdatedV3(fcState, attrs) + res, err := j.b.engine.ForkchoiceUpdatedV3(ctx, fcState, attrs) if err != nil { j.logger.Error("failed to start building L1 block", "err", err) return err @@ -216,7 +216,7 @@ func (j *Job) Seal(ctx context.Context) (work.Block, error) { j.logger.Info("about to forkchoice update", "safe", j.safe.Hash(), "finalized", j.finalized.Hash(), "head", envelope.ExecutionPayload.BlockHash) - if _, err := j.b.engine.ForkchoiceUpdatedV3(engine.ForkchoiceStateV1{ + if _, err := j.b.engine.ForkchoiceUpdatedV3(ctx, engine.ForkchoiceStateV1{ HeadBlockHash: envelope.ExecutionPayload.BlockHash, SafeBlockHash: j.safe.Hash(), FinalizedBlockHash: j.finalized.Hash(), diff --git a/ops/docker/op-stack-go/Dockerfile b/ops/docker/op-stack-go/Dockerfile index c23c8346520..55fb7ceda27 100644 --- a/ops/docker/op-stack-go/Dockerfile +++ b/ops/docker/op-stack-go/Dockerfile @@ -233,7 +233,7 @@ RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache just op-interop-mon/op-interop-mon # The Rust version must match rust/rust-toolchain.toml. We don't use "latest" to ensure reproducibility -FROM --platform=$BUILDPLATFORM rust:1.92 AS kona-host-builder +FROM --platform=$BUILDPLATFORM rust:1.94 AS kona-host-builder ARG TARGETARCH # Install build dependencies and cross-compilation toolchains RUN apt-get update && apt-get install -y --no-install-recommends \ diff --git a/ops/scripts/check-nut-locks/main.go b/ops/scripts/check-nut-locks/main.go index 76540a2d1d4..146fde4919b 100644 --- a/ops/scripts/check-nut-locks/main.go +++ b/ops/scripts/check-nut-locks/main.go @@ -5,11 +5,11 @@ import ( "encoding/hex" "fmt" "os" + "os/exec" "path/filepath" "strings" - "github.com/BurntSushi/toml" - + "github.com/ethereum-optimism/optimism/op-core/nuts" opservice "github.com/ethereum-optimism/optimism/op-service" ) @@ -44,9 +44,36 @@ func checkAllBundlesLocked(root string, lockedBundles map[string]bool) error { return nil } -type forkLockEntry struct { - Bundle string `toml:"bundle"` - Hash string `toml:"hash"` +// validateEntry checks a single fork lock entry against its bundle file content. +func validateEntry(fork string, entry nuts.ForkLockEntry, bundleContent []byte) error { + hash := sha256.Sum256(bundleContent) + actual := "sha256:" + hex.EncodeToString(hash[:]) + + expectedHash := strings.TrimSpace(entry.Hash) + if actual != expectedHash { + return fmt.Errorf( + "bundle hash mismatch for fork %s: expected=%s actual=%s. "+ + "If this change is intentional, update the hash in op-core/nuts/fork_lock.toml", + fork, expectedHash, actual, + ) + } + + if entry.Commit == "" { + return fmt.Errorf("fork %s has no commit recorded; "+ + "run 'just nut-snapshot-for %s' to populate the commit field", fork, fork) + } + + return nil +} + +// checkCommitAncestry verifies that a commit is an ancestor of origin/develop. +func checkCommitAncestry(root, fork string, commit string) error { + cmd := exec.Command("git", "merge-base", "--is-ancestor", commit, "origin/develop") + cmd.Dir = root + if err := cmd.Run(); err != nil { + return fmt.Errorf("fork %s: commit %s is not an ancestor of origin/develop", fork, commit[:12]) + } + return nil } func main() { @@ -62,10 +89,9 @@ func run(dir string) error { return fmt.Errorf("finding monorepo root: %w", err) } - lockPath := filepath.Join(root, "op-core", "nuts", "fork_lock.toml") - var locks map[string]forkLockEntry - if _, err := toml.DecodeFile(lockPath, &locks); err != nil { - return fmt.Errorf("reading fork lock file: %w", err) + locks, _, err := nuts.ReadLockFile(dir) + if err != nil { + return err } lockedBundles := make(map[string]bool) @@ -78,16 +104,12 @@ func run(dir string) error { return fmt.Errorf("fork %s: reading bundle %s: %w", fork, entry.Bundle, err) } - hash := sha256.Sum256(content) - actual := "sha256:" + hex.EncodeToString(hash[:]) + if err := validateEntry(fork, entry, content); err != nil { + return err + } - locked := strings.TrimSpace(entry.Hash) - if actual != locked { - return fmt.Errorf( - "bundle hash mismatch for fork %s: locked=%s actual=%s. "+ - "If this change is intentional, update the hash in op-core/nuts/fork_lock.toml", - fork, locked, actual, - ) + if err := checkCommitAncestry(root, fork, entry.Commit); err != nil { + return err } fmt.Printf("fork %s: bundle hash OK\n", fork) diff --git a/ops/scripts/check-nut-locks/main_test.go b/ops/scripts/check-nut-locks/main_test.go new file mode 100644 index 00000000000..0621d297da4 --- /dev/null +++ b/ops/scripts/check-nut-locks/main_test.go @@ -0,0 +1,60 @@ +package main + +import ( + "crypto/sha256" + "encoding/hex" + "testing" + + "github.com/ethereum-optimism/optimism/op-core/nuts" + "github.com/stretchr/testify/require" +) + +func hashOf(data []byte) string { + h := sha256.Sum256(data) + return "sha256:" + hex.EncodeToString(h[:]) +} + +func TestValidateEntry_MatchingHash(t *testing.T) { + content := []byte(`{"transactions":[]}`) + entry := nuts.ForkLockEntry{ + Bundle: "op-node/rollup/derive/test_nut_bundle.json", + Hash: hashOf(content), + Commit: "abc123", + } + err := validateEntry("test", entry, content) + require.NoError(t, err) +} + +func TestValidateEntry_HashMismatch(t *testing.T) { + content := []byte(`{"transactions":[]}`) + entry := nuts.ForkLockEntry{ + Bundle: "op-node/rollup/derive/test_nut_bundle.json", + Hash: "sha256:0000000000000000000000000000000000000000000000000000000000000000", + Commit: "abc123", + } + err := validateEntry("test", entry, content) + require.ErrorContains(t, err, "bundle hash mismatch") +} + +func TestValidateEntry_EmptyCommit(t *testing.T) { + content := []byte(`{"transactions":[]}`) + entry := nuts.ForkLockEntry{ + Bundle: "op-node/rollup/derive/test_nut_bundle.json", + Hash: hashOf(content), + Commit: "", + } + err := validateEntry("test", entry, content) + require.ErrorContains(t, err, "no commit recorded") +} + +func TestValidateEntry_ModifiedBundle(t *testing.T) { + original := []byte(`{"transactions":[{"intent":"deploy"}]}`) + modified := []byte(`{"transactions":[{"intent":"modified"}]}`) + entry := nuts.ForkLockEntry{ + Bundle: "op-node/rollup/derive/test_nut_bundle.json", + Hash: hashOf(original), + Commit: "abc123", + } + err := validateEntry("test", entry, modified) + require.ErrorContains(t, err, "bundle hash mismatch") +} diff --git a/ops/scripts/nut-provenance-verify-changed.sh b/ops/scripts/nut-provenance-verify-changed.sh new file mode 100755 index 00000000000..725fa1efaef --- /dev/null +++ b/ops/scripts/nut-provenance-verify-changed.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Verifies provenance for all forks whose bundle hash changed vs develop. +# For each fork whose hash changed, checks out the recorded commit, +# regenerates the bundle, and verifies it matches byte-for-byte. +# Unchanged forks are skipped to avoid expensive forge rebuilds. + +git show origin/develop:op-core/nuts/fork_lock.toml > /tmp/base_lock.toml 2>/dev/null || true +for fork in $(yq -p toml -o json op-core/nuts/fork_lock.toml | jq -r 'keys[]'); do + base_hash=$(yq -p toml ".${fork}.hash" /tmp/base_lock.toml 2>/dev/null || echo "") + curr_hash=$(yq -p toml ".${fork}.hash" op-core/nuts/fork_lock.toml) + if [ "$base_hash" != "$curr_hash" ]; then + echo "Verifying $fork (hash changed)..." + go run ./ops/scripts/nut-provenance-verify "$fork" + else + echo "Skipping $fork (unchanged)" + fi +done diff --git a/ops/scripts/nut-provenance-verify/main.go b/ops/scripts/nut-provenance-verify/main.go new file mode 100644 index 00000000000..2b13aa00cc8 --- /dev/null +++ b/ops/scripts/nut-provenance-verify/main.go @@ -0,0 +1,138 @@ +package main + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/ethereum-optimism/optimism/op-core/forks" + "github.com/ethereum-optimism/optimism/op-core/nuts" + opservice "github.com/ethereum-optimism/optimism/op-service" +) + +// bundleGenerator generates a NUT bundle in the given contracts directory. +type bundleGenerator func(contractsDir string) error + +func main() { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "usage: nut-provenance-verify \n") + os.Exit(1) + } + + fork := forks.Name(os.Args[1]) + if err := run(fork); err != nil { + fmt.Fprintf(os.Stderr, "FAIL: %v\n", err) + os.Exit(1) + } +} + +func run(fork forks.Name) error { + if !forks.IsValid(fork) { + return fmt.Errorf("unknown fork %q; valid forks: %v", fork, forks.All) + } + + root, err := opservice.FindMonorepoRoot(".") + if err != nil { + return fmt.Errorf("finding monorepo root: %w", err) + } + + locks, _, err := nuts.ReadLockFile(".") + if err != nil { + return err + } + + entry, ok := locks[string(fork)] + if !ok { + return fmt.Errorf("no entry for fork %q in fork_lock.toml", fork) + } + + // Step 1: Verify bundle file exists and hash matches. + bundlePath := filepath.Join(root, entry.Bundle) + bundleContent, err := os.ReadFile(bundlePath) + if err != nil { + return fmt.Errorf("reading bundle %s: %w", entry.Bundle, err) + } + + hash := sha256.Sum256(bundleContent) + actual := "sha256:" + hex.EncodeToString(hash[:]) + expectedHash := strings.TrimSpace(entry.Hash) + + if actual != expectedHash { + return fmt.Errorf("hash mismatch: expected=%s actual=%s", expectedHash, actual) + } + fmt.Printf("PASS: bundle hash matches lock (%s)\n", actual) + + // Step 2: Verify the bundle was correctly built from the recorded commit. + if entry.Commit == "" { + return fmt.Errorf("fork %q has no commit recorded; cannot verify provenance", fork) + } + + fmt.Printf("Verifying bundle provenance from commit %s...\n", entry.Commit[:12]) + if err := verifyFromCommit(root, entry, func(contractsDir string) error { + cmd := exec.Command("just", "generate-nut-bundle") + cmd.Dir = contractsDir + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() + }); err != nil { + return fmt.Errorf("provenance verification: %w", err) + } + + fmt.Println("PASS: regenerated bundle matches committed bundle") + return nil +} + +// verifyFromCommit creates a temporary worktree at the recorded commit, +// regenerates the NUT bundle, and compares it against the locked bundle. +func verifyFromCommit(root string, entry nuts.ForkLockEntry, generate bundleGenerator) error { + worktreeDir, err := os.MkdirTemp("", "verify-nuts-*") + if err != nil { + return fmt.Errorf("creating temp dir: %w", err) + } + defer os.RemoveAll(worktreeDir) + + // Create worktree at the recorded commit. + addCmd := exec.Command("git", "worktree", "add", "--detach", worktreeDir, entry.Commit) + addCmd.Dir = root + addCmd.Stderr = os.Stderr + if err := addCmd.Run(); err != nil { + return fmt.Errorf("creating worktree at %s: %w", entry.Commit[:12], err) + } + defer func() { + removeCmd := exec.Command("git", "worktree", "remove", "--force", worktreeDir) + removeCmd.Dir = root + _ = removeCmd.Run() + }() + + // Generate NUT bundle in the worktree. + contractsDir := filepath.Join(worktreeDir, "packages", "contracts-bedrock") + if err := generate(contractsDir); err != nil { + return fmt.Errorf("generating NUT bundle at commit %s: %w", entry.Commit[:12], err) + } + + // Read the regenerated bundle. + regenPath := filepath.Join(contractsDir, "snapshots", "upgrades", "current-upgrade-bundle.json") + regenContent, err := os.ReadFile(regenPath) + if err != nil { + return fmt.Errorf("reading regenerated bundle: %w", err) + } + + // Read the committed bundle. + bundlePath := filepath.Join(root, entry.Bundle) + committedContent, err := os.ReadFile(bundlePath) + if err != nil { + return fmt.Errorf("reading committed bundle: %w", err) + } + + if !bytes.Equal(regenContent, committedContent) { + return fmt.Errorf("regenerated bundle at commit %s differs from committed bundle %s", + entry.Commit[:12], entry.Bundle) + } + + return nil +} diff --git a/ops/scripts/nut-provenance-verify/main_test.go b/ops/scripts/nut-provenance-verify/main_test.go new file mode 100644 index 00000000000..28a9ae1ad3f --- /dev/null +++ b/ops/scripts/nut-provenance-verify/main_test.go @@ -0,0 +1,141 @@ +package main + +import ( + "os" + "os/exec" + "path/filepath" + "testing" + + "github.com/ethereum-optimism/optimism/op-core/nuts" + "github.com/stretchr/testify/require" +) + +// initGitRepo creates a bare-minimum git repo with an initial commit +// and returns the repo root and the commit SHA. +func initGitRepo(t *testing.T) (string, string) { + t.Helper() + dir := t.TempDir() + + cmds := [][]string{ + {"git", "init"}, + {"git", "config", "user.email", "test@test.com"}, + {"git", "config", "user.name", "Test"}, + {"git", "config", "commit.gpgsign", "false"}, + {"git", "commit", "--allow-empty", "-m", "init"}, + } + for _, args := range cmds { + cmd := exec.Command(args[0], args[1:]...) + cmd.Dir = dir + out, err := cmd.CombinedOutput() + require.NoError(t, err, "cmd %v failed: %s", args, out) + } + + cmd := exec.Command("git", "rev-parse", "HEAD") + cmd.Dir = dir + out, err := cmd.Output() + require.NoError(t, err) + + return dir, string(out[:len(out)-1]) // trim newline +} + +// writeFileInRepo creates a file at a relative path within the repo and commits it. +func writeFileInRepo(t *testing.T, root, relPath string, content []byte) string { + t.Helper() + absPath := filepath.Join(root, relPath) + require.NoError(t, os.MkdirAll(filepath.Dir(absPath), 0755)) + require.NoError(t, os.WriteFile(absPath, content, 0644)) + + cmd := exec.Command("git", "add", relPath) + cmd.Dir = root + require.NoError(t, cmd.Run()) + + cmd = exec.Command("git", "commit", "-m", "add "+relPath) + cmd.Dir = root + out, err := cmd.CombinedOutput() + require.NoError(t, err, string(out)) + + cmd = exec.Command("git", "rev-parse", "HEAD") + cmd.Dir = root + sha, err := cmd.Output() + require.NoError(t, err) + return string(sha[:len(sha)-1]) +} + +func TestVerifyFromCommit_MatchingBundle(t *testing.T) { + root, _ := initGitRepo(t) + + bundleContent := []byte(`{"metadata":{"version":"1.0.0"},"transactions":[]}`) + bundlePath := "packages/contracts-bedrock/snapshots/upgrades/current-upgrade-bundle.json" + commit := writeFileInRepo(t, root, bundlePath, bundleContent) + + // Write the "committed" bundle that verifyFromCommit compares against. + committedBundleRel := "op-node/rollup/derive/test_nut_bundle.json" + committedBundlePath := filepath.Join(root, committedBundleRel) + require.NoError(t, os.MkdirAll(filepath.Dir(committedBundlePath), 0755)) + require.NoError(t, os.WriteFile(committedBundlePath, bundleContent, 0644)) + + entry := nuts.ForkLockEntry{ + Bundle: committedBundleRel, + Commit: commit, + } + + // Generator is a no-op: the bundle file already exists at the commit. + noopGenerator := func(contractsDir string) error { return nil } + + err := verifyFromCommit(root, entry, noopGenerator) + require.NoError(t, err) +} + +func TestVerifyFromCommit_MismatchedBundle(t *testing.T) { + root, _ := initGitRepo(t) + + bundleContent := []byte(`{"metadata":{"version":"1.0.0"},"transactions":[]}`) + bundlePath := "packages/contracts-bedrock/snapshots/upgrades/current-upgrade-bundle.json" + commit := writeFileInRepo(t, root, bundlePath, bundleContent) + + // Write a different bundle as the "committed" version. + committedBundleRel := "op-node/rollup/derive/test_nut_bundle.json" + committedBundlePath := filepath.Join(root, committedBundleRel) + require.NoError(t, os.MkdirAll(filepath.Dir(committedBundlePath), 0755)) + require.NoError(t, os.WriteFile(committedBundlePath, []byte(`{"modified":true}`), 0644)) + + entry := nuts.ForkLockEntry{ + Bundle: committedBundleRel, + Commit: commit, + } + + noopGenerator := func(contractsDir string) error { return nil } + + err := verifyFromCommit(root, entry, noopGenerator) + require.ErrorContains(t, err, "regenerated bundle at commit") +} + +func TestVerifyFromCommit_GeneratorModifiesBundle(t *testing.T) { + root, _ := initGitRepo(t) + + // Commit an initial bundle. + originalContent := []byte(`{"metadata":{"version":"1.0.0"},"transactions":[]}`) + bundlePath := "packages/contracts-bedrock/snapshots/upgrades/current-upgrade-bundle.json" + commit := writeFileInRepo(t, root, bundlePath, originalContent) + + // The committed bundle matches what the generator will produce. + regeneratedContent := []byte(`{"metadata":{"version":"2.0.0"},"transactions":[{"new":true}]}`) + committedBundleRel := "op-node/rollup/derive/test_nut_bundle.json" + committedBundlePath := filepath.Join(root, committedBundleRel) + require.NoError(t, os.MkdirAll(filepath.Dir(committedBundlePath), 0755)) + require.NoError(t, os.WriteFile(committedBundlePath, regeneratedContent, 0644)) + + entry := nuts.ForkLockEntry{ + Bundle: committedBundleRel, + Commit: commit, + } + + // Generator overwrites the bundle with new content (simulating forge regeneration). + modifyingGenerator := func(contractsDir string) error { + outPath := filepath.Join(contractsDir, "snapshots", "upgrades", "current-upgrade-bundle.json") + return os.WriteFile(outPath, regeneratedContent, 0644) + } + + err := verifyFromCommit(root, entry, modifyingGenerator) + require.NoError(t, err) +} diff --git a/ops/scripts/nut-snapshot-for/main.go b/ops/scripts/nut-snapshot-for/main.go new file mode 100644 index 00000000000..74321045d2a --- /dev/null +++ b/ops/scripts/nut-snapshot-for/main.go @@ -0,0 +1,87 @@ +package main + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/ethereum-optimism/optimism/op-core/forks" + "github.com/ethereum-optimism/optimism/op-core/nuts" + opservice "github.com/ethereum-optimism/optimism/op-service" +) + +func main() { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "usage: nut-snapshot-for \n") + os.Exit(1) + } + + fork := forks.Name(os.Args[1]) + if err := run(fork); err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } +} + +func run(fork forks.Name) error { + if !forks.IsValid(fork) { + return fmt.Errorf("unknown fork %q; valid forks: %v", fork, forks.All) + } + + root, err := opservice.FindMonorepoRoot(".") + if err != nil { + return fmt.Errorf("finding monorepo root: %w", err) + } + + // Copy current-upgrade-bundle.json → _nut_bundle.json. + // The caller is responsible for running `just generate-nut-bundle` first if needed. + srcPath := filepath.Join(root, "packages", "contracts-bedrock", "snapshots", "upgrades", "current-upgrade-bundle.json") + content, err := os.ReadFile(srcPath) + if err != nil { + return fmt.Errorf("reading bundle (run 'just generate-nut-bundle' in packages/contracts-bedrock/ first): %w", err) + } + + bundleRel := filepath.Join("op-node", "rollup", "derive", string(fork)+"_nut_bundle.json") + dstPath := filepath.Join(root, bundleRel) + if err := os.WriteFile(dstPath, content, 0600); err != nil { + return fmt.Errorf("writing bundle to %s: %w", bundleRel, err) + } + fmt.Printf("Copied bundle to %s\n", bundleRel) + + // Compute sha256 of the bundle. + hash := sha256.Sum256(content) + hashStr := "sha256:" + hex.EncodeToString(hash[:]) + + // Record the merge-base with develop (not HEAD) so the commit survives + // squash-merge. Contracts must be merged to develop before snapshotting. + commitCmd := exec.Command("git", "merge-base", "HEAD", "origin/develop") + commitCmd.Dir = root + commitOut, err := commitCmd.Output() + if err != nil { + return fmt.Errorf("finding merge-base with origin/develop (fetch first?): %w", err) + } + commit := strings.TrimSpace(string(commitOut)) + + // Read existing fork_lock.toml, update the entry, write back. + locks, lockPath, err := nuts.ReadLockFile(".") + if err != nil { + return err + } + + locks[string(fork)] = nuts.ForkLockEntry{ + Bundle: bundleRel, + Hash: hashStr, + Commit: commit, + } + + if err := nuts.WriteLockFile(lockPath, locks); err != nil { + return err + } + + fmt.Printf("Updated fork_lock.toml: fork=%s hash=%s commit=%s\n", fork, hashStr, commit[:12]) + return nil +} diff --git a/packages/contracts-bedrock/.pr-check-passed b/packages/contracts-bedrock/.pr-check-passed new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/contracts-bedrock/book/src/contributing/opcm.md b/packages/contracts-bedrock/book/src/contributing/opcm.md index 9bd43d623aa..fe41fbcd372 100644 --- a/packages/contracts-bedrock/book/src/contributing/opcm.md +++ b/packages/contracts-bedrock/book/src/contributing/opcm.md @@ -6,7 +6,7 @@ for the following: 1. Keeping track of the canonical implementation contracts for each [contracts release][versioning]. 2. Deploying new L1 contracts for each OP Chain. 3. Upgrading from one contract release to another. -4. Maintaining the fault proof system by adding game types or updating prestates. +4. Migrating chains to superproofs. All contract upgrades that touch live chains **must** be performed via the OPCM. This guide will walk you through the OPCM's architecture, and how to hook your contracts into it. @@ -17,32 +17,27 @@ the OPCM's architecture, and how to hook your contracts into it. The OPCM consists of multiple contracts: -1. `OPContractsManager`, which serves as the entry point. -2. `OPContractsManagerGameTypeAdder`, which is used to add new game types and update prestates. -3. `OPContractsManagerDeployer`, which is used to deploy new OP Chains. -4. `OPContractsManagerUpgrader`, which is used to upgrade existing OP Chains. -5. `OPContractsManagerContractsContainer`, which is a repository for contract implementations and blueprints. +1. `OPContractsManagerV2`, which serves as the entry point for `deploy()`, `upgrade()`, `upgradeSuperchain()`, and `migrate()`. +2. `OPContractsManagerUtils`, which contains shared helper logic used by deploy and upgrade operations. +3. `OPContractsManagerContainer`, which is a repository for contract implementations and blueprints. +4. `OPContractsManagerMigrator`, which handles migrating chains to superproofs (called via delegatecall from `migrate()`). They fit together like the diagram below: ```mermaid stateDiagram-v2 - state OpContractsManager { + state OPContractsManagerV2 { direction LR - deploy() --> OpContractsManagerDeployer: staticcall - upgrade() --> OpContractsManagerUpgrader: delegatecall - addGameType() --> OpContractsManagerGameTypeAdder: delegatecall - updatePrestate() --> OpContractsManagerGameTypeAdder: delegatecall + deploy() + upgrade() + upgradeSuperchain() + migrate() --> OPContractsManagerMigrator: delegatecall } - state Logic { - OpContractsManagerDeployer --> OpContractsManagerContractsContainer: getImplementations()/getBlueprints() - OpContractsManagerUpgrader --> OpContractsManagerContractsContainer: getImplementations()/getBlueprints() - OpContractsManagerGameTypeAdder --> OpContractsManagerContractsContainer: getImplementations()/getBlueprints() - } - - state Implementations { - OpContractsManagerContractsContainer + state Shared { + OPContractsManagerV2 --> OPContractsManagerUtils: shared helpers + OPContractsManagerV2 --> OPContractsManagerContainer: implementations & blueprints + OPContractsManagerMigrator --> OPContractsManagerContainer: implementations & blueprints } ``` @@ -68,18 +63,17 @@ to each method. This changes between releases, and will not be covered directly Whenever you make updates to in-protocol contracts, you'll need to make corresponding changes inside the OPCM. While the details of each change will vary, we've included some general guidelines below. -### Updating Logic Contracts +### Updating OPContractsManagerV2 -As their name implies, the logic contracts contain the actual logic used to deploy or upgrade contracts. When -modifying these contracts keep the following tips in mind: +All deploy, upgrade, and migration logic lives directly in `OPContractsManagerV2` (with migration delegating to +`OPContractsManagerMigrator`). When modifying these keep the following tips in mind: - The `deploy` method can typically be modified in-place since the deployment process doesn't change much from release to release. For example, most changes to the `deploy` method will involve either adding a new contract or modifying the constructor/initializer for existing contracts. You can use the existing implementation as a guide. - The `upgrade` method changes much more frequently. That said, you can still use the existing implementation as a - guide. Just make sure to delete any old upgrade code that is no longer needed. The `OPContractsManagerUpgrader` - logic contract also contains helpers for things like deploying new dispute games and upgrading proxies to new - implementations. See the `upgradeTo` method for an example. + guide. Just make sure to delete any old upgrade code that is no longer needed. `OPContractsManagerUtils` contains + helpers for things like deploying new dispute games and upgrading proxies to new implementations. - The `upgrade` method will _always_ set the RC on the OPCM to false when called by the upgrade controller. It will only sometimes (depending on your specific upgrade) upgrade Superchain contracts. @@ -94,7 +88,7 @@ When multiple upgrades are in flight at the same time, the fork tests stack upgr tip of `develop` must contain the implementation for the latest upgrade only, fork tests that run upgrades prior to the latest one must use deployed instances of the OPCM. For example, as of this writing upgrades 13, 14, and 15 are all in flight. Therefore, the fork tests will use deployed versions of the OPCM for upgrades 13 and 14 and whatever -is on `develop` for upgrade 15. See `OPContractsManager.t.sol` for the implementation of the fork tests. +is on `develop` for upgrade 15. See `OPContractsManagerV2.t.sol` for the implementation of the fork tests. ## Modifying Contracts for Upgrade diff --git a/packages/contracts-bedrock/book/src/policies/versioning.md b/packages/contracts-bedrock/book/src/policies/versioning.md index 546d164a7a0..dd7e429c654 100644 --- a/packages/contracts-bedrock/book/src/policies/versioning.md +++ b/packages/contracts-bedrock/book/src/policies/versioning.md @@ -79,9 +79,9 @@ Versioning for monorepo releases works as follows: ## Optimism Contracts Manager (OPCM) Versioning -The [OPCM](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/OPContractsManager.sol) is the contract that manages the deployment of all contracts on L1. +The [OPCM](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerV2.sol) is the contract that manages the deployment of all contracts on L1. -The `OPCM` is the source of truth for the contracts that belong in a release, available as on-chain addresses by querying [the `getImplementations` function](https://github.com/ethereum-optimism/optimism/blob/4c8764f0453e141555846d8c9dd2af9edbc1d014/packages/contracts-bedrock/src/L1/OPContractsManager.sol#L1061). +The `OPCM` is the source of truth for the contracts that belong in a release, available as on-chain addresses by querying the [`implementations()`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerV2.sol) function. ### OPCM Semver Rules diff --git a/packages/contracts-bedrock/checks.yaml b/packages/contracts-bedrock/checks.yaml index b597cb8e769..964f5906ec0 100644 --- a/packages/contracts-bedrock/checks.yaml +++ b/packages/contracts-bedrock/checks.yaml @@ -38,9 +38,6 @@ phases: - name: semgrep-test-validity description: Check semgrep tests are valid command: forge fmt ../../.semgrep/tests/sol-rules.t.sol --check - - name: deploy-configs - description: Validate deploy configurations - command: ./scripts/checks/check-deploy-configs.sh - name: kontrol-summaries description: Check kontrol summaries unchanged command: ./scripts/checks/check-kontrol-summaries-unchanged.sh @@ -85,9 +82,6 @@ phases: - name: nut-bundle description: Check NUT bundle is up to date command: just nut-bundle-check-no-build - - name: opcm-upgrade-checks - description: Check OPCM upgrade methods - command: go run ./scripts/checks/opcm-upgrade-checks/ # Phase 4: Dev build checks - needs test artifacts - name: dev diff --git a/packages/contracts-bedrock/deploy-config/hardhat.json b/packages/contracts-bedrock/deploy-config/hardhat.json deleted file mode 100644 index 8a0a3d4eb4b..00000000000 --- a/packages/contracts-bedrock/deploy-config/hardhat.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "finalSystemOwner": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", - "superchainConfigGuardian": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", - "proxyAdminOwner": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", - "l1StartingBlockTag": "earliest", - "l1ChainID": 900, - "l2ChainID": 901, - "l2BlockTime": 2, - "l1BlockTime": 12, - "maxSequencerDrift": 300, - "sequencerWindowSize": 15, - "channelTimeout": 40, - "p2pSequencerAddress": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", - "batchInboxAddress": "0x00289C189bEE4E70334629f04Cd5eD602B6600eB", - "batchSenderAddress": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", - "l2OutputOracleSubmissionInterval": 6, - "l2OutputOracleStartingTimestamp": 1, - "l2OutputOracleStartingBlockNumber": 1, - "gasPriceOracleBaseFeeScalar": 1368, - "gasPriceOracleBlobBaseFeeScalar": 810949, - "l2OutputOracleProposer": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", - "l2OutputOracleChallenger": "0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A", - "l2GenesisBlockBaseFeePerGas": "0x3B9ACA00", - "l2GenesisBlockGasLimit": "0x17D7840", - "baseFeeVaultRecipient": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", - "l1FeeVaultRecipient": "0x71bE63f3384f5fb98995898A86B02Fb2426c5788", - "sequencerFeeVaultRecipient": "0xfabb0ac9d68b0b445fb7357272ff202c5651694a", - "operatorFeeVaultRecipient": "0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec", - "operatorFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "baseFeeVaultWithdrawalNetwork": 0, - "l1FeeVaultWithdrawalNetwork": 0, - "sequencerFeeVaultWithdrawalNetwork": 0, - "operatorFeeVaultWithdrawalNetwork": 0, - "enableGovernance": true, - "governanceTokenName": "Optimism", - "governanceTokenSymbol": "OP", - "governanceTokenOwner": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", - "finalizationPeriodSeconds": 36, - "eip1559Denominator": 50, - "eip1559DenominatorCanyon": 250, - "eip1559Elasticity": 10, - "l2GenesisRegolithTimeOffset": "0x0", - "systemConfigStartBlock": 0, - "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000001", - "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000001", - "faultGameAbsolutePrestate": "0x0000000000000000000000000000000000000000000000000000000000000000", - "faultGameMaxDepth": 73, - "faultGameClockExtension": 10800, - "faultGameMaxClockDuration": 302400, - "faultGameGenesisBlock": 0, - "faultGameGenesisOutputRoot": "0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", - "faultGameSplitDepth": 30, - "faultGameWithdrawalDelay": 302400, - "preimageOracleMinProposalSize": 126000, - "preimageOracleChallengePeriod": 86400, - "proofMaturityDelaySeconds": 604800, - "disputeGameFinalityDelaySeconds": 302400, - "respectedGameType": 0, - "useFaultProofs": false, - "fundDevAccounts": true, - "useAltDA": false, - "daChallengeWindow": 100, - "daResolveWindow": 100, - "daBondSize": 1000, - "daResolverRefundPercentage": 50, - "useRevenueShare": false, - "chainFeesRecipient": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", - "useCustomGasToken": false, - "gasPayingTokenName": "", - "gasPayingTokenSymbol": "", - "nativeAssetLiquidityAmount": null, - "liquidityControllerOwner": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" -} diff --git a/packages/contracts-bedrock/deploy-config/internal-devnet.json b/packages/contracts-bedrock/deploy-config/internal-devnet.json deleted file mode 100644 index 4781312aa7e..00000000000 --- a/packages/contracts-bedrock/deploy-config/internal-devnet.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "finalSystemOwner": "0x858F0751ef8B4067f0d2668C076BDB50a8549fbF", - "superchainConfigGuardian": "0x858F0751ef8B4067f0d2668C076BDB50a8549fbF", - "l1StartingBlockTag": "0x19c7e6b18fe156e45f4cfef707294fd8f079fa9c30a7b7cd6ec1ce3682ec6a2e", - "l1ChainID": 5, - "l2ChainID": 998, - "l2BlockTime": 2, - "l1BlockTime": 12, - "maxSequencerDrift": 1200, - "sequencerWindowSize": 3600, - "channelTimeout": 120, - "p2pSequencerAddress": "0xf1a4a22a65Ff01EBB23A580146a3ED49D70c8932", - "batchInboxAddress": "0xff00000000000000000000000000000000000998", - "batchSenderAddress": "0xE0Fa1Cc7a0FD5bD82b9A06b08FD6C4563E6635C2", - "l2OutputOracleSubmissionInterval": 120, - "l2OutputOracleStartingTimestamp": 1674507888, - "l2OutputOracleStartingBlockNumber": 1, - "l2OutputOracleProposer": "0xE06d39D4B8DC05E562353F060DED346AC4acC077", - "l2OutputOracleChallenger": "0xE06d39D4B8DC05E562353F060DED346AC4acC077", - "finalizationPeriodSeconds": 12, - "proxyAdminOwner": "0x858F0751ef8B4067f0d2668C076BDB50a8549fbF", - "baseFeeVaultRecipient": "0x858F0751ef8B4067f0d2668C076BDB50a8549fbF", - "l1FeeVaultRecipient": "0x858F0751ef8B4067f0d2668C076BDB50a8549fbF", - "sequencerFeeVaultRecipient": "0x858F0751ef8B4067f0d2668C076BDB50a8549fbF", - "operatorFeeVaultRecipient": "0x858F0751ef8B4067f0d2668C076BDB50a8549fbF", - "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "operatorFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "baseFeeVaultWithdrawalNetwork": 0, - "l1FeeVaultWithdrawalNetwork": 0, - "sequencerFeeVaultWithdrawalNetwork": 0, - "operatorFeeVaultWithdrawalNetwork": 0, - "enableGovernance": true, - "governanceTokenName": "Optimism", - "governanceTokenSymbol": "OP", - "governanceTokenOwner": "0x858F0751ef8B4067f0d2668C076BDB50a8549fbF", - "l2GenesisBlockGasLimit": "0x17D7840", - "l2GenesisBlockBaseFeePerGas": "0x3b9aca00", - "eip1559Denominator": 50, - "eip1559Elasticity": 10, - "systemConfigStartBlock": 8364212, - "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", - "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000", - "useRevenueShare": true, - "chainFeesRecipient": "0x858F0751ef8B4067f0d2668C076BDB50a8549fbF", - "useCustomGasToken": false, - "gasPayingTokenName": "", - "gasPayingTokenSymbol": "", - "nativeAssetLiquidityAmount": null, - "liquidityControllerOwner": "0x858F0751ef8B4067f0d2668C076BDB50a8549fbF" -} diff --git a/packages/contracts-bedrock/deploy-config/mainnet.json b/packages/contracts-bedrock/deploy-config/mainnet.json deleted file mode 100644 index ce6a56d9118..00000000000 --- a/packages/contracts-bedrock/deploy-config/mainnet.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "finalSystemOwner": "0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A", - "superchainConfigGuardian": "0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A", - "l1StartingBlockTag": "0x438335a20d98863a4c0c97999eb2481921ccd28553eac6f913af7c12aec04108", - "l1ChainID": 1, - "l2ChainID": 10, - "l2BlockTime": 2, - "l1BlockTime": 12, - "maxSequencerDrift": 600, - "sequencerWindowSize": 3600, - "channelTimeout": 300, - "p2pSequencerAddress": "0xAAAA45d9549EDA09E70937013520214382Ffc4A2", - "batchInboxAddress": "0xff00000000000000000000000000000000000010", - "batchSenderAddress": "0x6887246668a3b87F54DeB3b94Ba47a6f63F32985", - "l2OutputOracleSubmissionInterval": 1800, - "l2OutputOracleStartingTimestamp": 1686068903, - "l2OutputOracleStartingBlockNumber": 105235063, - "l2OutputOracleProposer": "0x473300df21D047806A082244b417f96b32f13A33", - "l2OutputOracleChallenger": "0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A", - "finalizationPeriodSeconds": 604800, - "proxyAdminOwner": "0x7871d1187A97cbbE40710aC119AA3d412944e4Fe", - "baseFeeVaultRecipient": "0xa3d596EAfaB6B13Ab18D40FaE1A962700C84ADEa", - "l1FeeVaultRecipient": "0xa3d596EAfaB6B13Ab18D40FaE1A962700C84ADEa", - "sequencerFeeVaultRecipient": "0xa3d596EAfaB6B13Ab18D40FaE1A962700C84ADEa", - "operatorFeeVaultRecipient": "0xa3d596EAfaB6B13Ab18D40FaE1A962700C84ADEa", - "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "operatorFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "baseFeeVaultWithdrawalNetwork": 0, - "l1FeeVaultWithdrawalNetwork": 0, - "sequencerFeeVaultWithdrawalNetwork": 0, - "operatorFeeVaultWithdrawalNetwork": 0, - "enableGovernance": true, - "governanceTokenName": "Optimism", - "governanceTokenSymbol": "OP", - "governanceTokenOwner": "0x5C4e7Ba1E219E47948e6e3F55019A647bA501005", - "l2GenesisBlockGasLimit": "0x1c9c380", - "l2GenesisBlockBaseFeePerGas": "0x3b9aca00", - "gasPriceOracleBaseFeeScalar": 1368, - "gasPriceOracleBlobBaseFeeScalar": 810949, - "eip1559Denominator": 50, - "eip1559Elasticity": 6, - "l2GenesisRegolithTimeOffset": "0x0", - "systemConfigStartBlock": 17422444, - "requiredProtocolVersion": "0x0000000000000000000000000000000000000003000000010000000000000000", - "recommendedProtocolVersion": "0x0000000000000000000000000000000000000003000000010000000000000000", - "faultGameAbsolutePrestate": "0x038512e02c4c3f7bdaec27d00edf55b7155e0905301e1a88083e4e0a6764d54c", - "faultGameMaxDepth": 73, - "faultGameClockExtension": 10800, - "faultGameMaxClockDuration": 302400, - "faultGameGenesisBlock": 120059863, - "faultGameGenesisOutputRoot": "0x2694ac14dcf54b7a77363e3f60e6462dc78da0d43d1e2f058dbb6a1488814977", - "faultGameSplitDepth": 30, - "faultGameWithdrawalDelay": 604800, - "preimageOracleMinProposalSize": 126000, - "preimageOracleChallengePeriod": 86400, - "proofMaturityDelaySeconds": 604800, - "disputeGameFinalityDelaySeconds": 302400, - "respectedGameType": 0, - "useFaultProofs": true, - "useRevenueShare": true, - "chainFeesRecipient": "0xa3d596EAfaB6B13Ab18D40FaE1A962700C84ADEa", - "useCustomGasToken": false, - "gasPayingTokenName": "", - "gasPayingTokenSymbol": "", - "nativeAssetLiquidityAmount": null, - "liquidityControllerOwner": "0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A" -} diff --git a/packages/contracts-bedrock/deploy-config/sepolia-devnet-0.json b/packages/contracts-bedrock/deploy-config/sepolia-devnet-0.json deleted file mode 100644 index 86fba87039e..00000000000 --- a/packages/contracts-bedrock/deploy-config/sepolia-devnet-0.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "l1StartingBlockTag": "0x5639be97000fec7131a880b19b664cae43f975c773f628a08a9bb658c2a68df0", - "l1ChainID": 11155111, - "l2ChainID": 11155421, - "l2BlockTime": 2, - "finalizationPeriodSeconds": 12, - "maxSequencerDrift": 600, - "sequencerWindowSize": 3600, - "channelTimeout": 300, - "p2pSequencerAddress": "0xa95b83e39aa78b00f12fe431865b563793d97af5", - "batchInboxAddress": "0xff00000000000000000000000000000011155421", - "batchSenderAddress": "0x19cc7073150d9f5888f09e0e9016d2a39667df14", - "l2OutputOracleSubmissionInterval": 120, - "l2OutputOracleStartingTimestamp": 1706484048, - "l2OutputOracleStartingBlockNumber": 0, - "l2OutputOracleProposer": "0x95014c45078354ff839f14192228108eac82e00a", - "l2OutputOracleChallenger": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", - "l1BlockTime": 12, - "l1GenesisBlockTimestamp": "0x0", - "l1GenesisBlockNonce": "0x0", - "l1GenesisBlockGasLimit": "0x0", - "l1GenesisBlockDifficulty": null, - "l1GenesisBlockMixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "l1GenesisBlockCoinbase": "0x0000000000000000000000000000000000000000", - "l1GenesisBlockNumber": "0x0", - "l1GenesisBlockGasUsed": "0x0", - "l1GenesisBlockParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "l1GenesisBlockBaseFeePerGas": null, - "l2GenesisBlockNonce": "0x0", - "l2GenesisBlockGasLimit": "0x1c9c380", - "l2GenesisBlockDifficulty": null, - "l2GenesisBlockMixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "l2GenesisBlockNumber": "0x0", - "l2GenesisBlockGasUsed": "0x0", - "l2GenesisBlockParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "l2GenesisBlockBaseFeePerGas": "0x3b9aca00", - "l2GenesisRegolithTimeOffset": "0x0", - "l2GenesisCanyonTimeOffset": "0x0", - "l2GenesisDeltaTimeOffset": "0x0", - "proxyAdminOwner": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", - "finalSystemOwner": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", - "superchainConfigGuardian": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", - "baseFeeVaultRecipient": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", - "l1FeeVaultRecipient": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", - "sequencerFeeVaultRecipient": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", - "operatorFeeVaultRecipient": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", - "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "operatorFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "baseFeeVaultWithdrawalNetwork": 1, - "l1FeeVaultWithdrawalNetwork": 1, - "sequencerFeeVaultWithdrawalNetwork": 1, - "operatorFeeVaultWithdrawalNetwork": 1, - "l1StandardBridgeProxy": "0x0000000000000000000000000000000000000000", - "l1CrossDomainMessengerProxy": "0x0000000000000000000000000000000000000000", - "l1ERC721BridgeProxy": "0x0000000000000000000000000000000000000000", - "systemConfigProxy": "0x0000000000000000000000000000000000000000", - "optimismPortalProxy": "0x0000000000000000000000000000000000000000", - "enableGovernance": true, - "governanceTokenSymbol": "OP", - "governanceTokenName": "Optimism", - "governanceTokenOwner": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", - "deploymentWaitConfirmations": 0, - "eip1559Elasticity": 6, - "eip1559Denominator": 250, - "eip1559DenominatorCanyon": 250, - "systemConfigStartBlock": 4071248, - "faultGameAbsolutePrestate": "0x03b7eaa4e3cbce90381921a4b48008f4769871d64f93d113fcadca08ecee503b", - "faultGameMaxDepth": 73, - "faultGameClockExtension": 3600, - "faultGameMaxClockDuration": 14400, - "faultGameGenesisBlock": 0, - "faultGameGenesisOutputRoot": "0x91bd00ecd596a86c9f4e12c0646578e77022881c87c06ec6aa31e656d2730688", - "faultGameSplitDepth": 30, - "faultGameWithdrawalDelay": 600, - "preimageOracleMinProposalSize": 126000, - "preimageOracleChallengePeriod": 10800, - "proofMaturityDelaySeconds": 1200, - "disputeGameFinalityDelaySeconds": 600, - "respectedGameType": 0, - "useFaultProofs": true, - "fundDevAccounts": false, - "requiredProtocolVersion": "0x0000000000000000000000000000000000000005000000000000000000000000", - "recommendedProtocolVersion": "0x0000000000000000000000000000000000000005000000000000000000000000", - "useRevenueShare": true, - "chainFeesRecipient": "0x8c20c40180751d93e939dddee3517ae0d1ebead2", - "useCustomGasToken": false, - "gasPayingTokenName": "", - "gasPayingTokenSymbol": "", - "nativeAssetLiquidityAmount": null, - "liquidityControllerOwner": "0x8c20c40180751d93e939dddee3517ae0d1ebead2" -} diff --git a/packages/contracts-bedrock/deploy-config/sepolia.json b/packages/contracts-bedrock/deploy-config/sepolia.json deleted file mode 100644 index f5d20903677..00000000000 --- a/packages/contracts-bedrock/deploy-config/sepolia.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "finalSystemOwner": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301", - "superchainConfigGuardian": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301", - "l1StartingBlockTag": "0x48f520cf4ddaf34c8336e6e490632ea3cf1e5e93b0b2bc6e917557e31845371b", - "l1ChainID": 11155111, - "l2ChainID": 11155420, - "l2BlockTime": 2, - "l1BlockTime": 12, - "maxSequencerDrift": 600, - "sequencerWindowSize": 3600, - "channelTimeout": 300, - "p2pSequencerAddress": "0x57CACBB0d30b01eb2462e5dC940c161aff3230D3", - "batchInboxAddress": "0xff00000000000000000000000000000011155420", - "batchSenderAddress": "0x8F23BB38F531600e5d8FDDaAEC41F13FaB46E98c", - "l2OutputOracleSubmissionInterval": 120, - "l2OutputOracleStartingBlockNumber": 0, - "l2OutputOracleStartingTimestamp": 1690493568, - "l2OutputOracleProposer": "0x49277EE36A024120Ee218127354c4a3591dc90A9", - "l2OutputOracleChallenger": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301", - "finalizationPeriodSeconds": 12, - "proxyAdminOwner": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301", - "baseFeeVaultRecipient": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301", - "l1FeeVaultRecipient": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301", - "sequencerFeeVaultRecipient": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301", - "operatorFeeVaultRecipient": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301", - "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "operatorFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", - "baseFeeVaultWithdrawalNetwork": 0, - "l1FeeVaultWithdrawalNetwork": 0, - "sequencerFeeVaultWithdrawalNetwork": 0, - "operatorFeeVaultWithdrawalNetwork": 0, - "enableGovernance": true, - "governanceTokenSymbol": "OP", - "governanceTokenName": "Optimism", - "governanceTokenOwner": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301", - "l2GenesisBlockGasLimit": "0x1c9c380", - "l2GenesisBlockBaseFeePerGas": "0x3b9aca00", - "eip1559Denominator": 50, - "eip1559Elasticity": 6, - "l2GenesisRegolithTimeOffset": "0x0", - "systemConfigStartBlock": 4071248, - "requiredProtocolVersion": "0x0000000000000000000000000000000000000004000000000000000000000001", - "recommendedProtocolVersion": "0x0000000000000000000000000000000000000004000000000000000000000001", - "fundDevAccounts": false, - "faultGameAbsolutePrestate": "0x03b7eaa4e3cbce90381921a4b48008f4769871d64f93d113fcadca08ecee503b", - "faultGameMaxDepth": 73, - "faultGameClockExtension": 10800, - "faultGameMaxClockDuration": 302400, - "faultGameGenesisBlock": 9496192, - "faultGameGenesisOutputRoot": "0x63b1cda487c072b020a57c1203f7c2921754005cadbd54bed7f558111b8278d8", - "faultGameSplitDepth": 30, - "faultGameWithdrawalDelay": 604800, - "preimageOracleMinProposalSize": 126000, - "preimageOracleChallengePeriod": 86400, - "proofMaturityDelaySeconds": 604800, - "disputeGameFinalityDelaySeconds": 302400, - "respectedGameType": 0, - "useFaultProofs": true, - "useRevenueShare": true, - "chainFeesRecipient": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301", - "useCustomGasToken": false, - "gasPayingTokenName": "", - "gasPayingTokenSymbol": "", - "nativeAssetLiquidityAmount": null, - "liquidityControllerOwner": "0xfd1D2e729aE8eEe2E146c033bf4400fE75284301" -} diff --git a/packages/contracts-bedrock/foundry.toml b/packages/contracts-bedrock/foundry.toml index c7caea9c00c..663619472c5 100644 --- a/packages/contracts-bedrock/foundry.toml +++ b/packages/contracts-bedrock/foundry.toml @@ -25,7 +25,6 @@ compilation_restrictions = [ { paths = "src/dispute/PermissionedDisputeGame.sol", optimizer_runs = 5000 }, { paths = "src/dispute/SuperFaultDisputeGame.sol", optimizer_runs = 5000 }, { paths = "src/dispute/SuperPermissionedDisputeGame.sol", optimizer_runs = 5000 }, - { paths = "src/L1/OPContractsManager.sol", optimizer_runs = 5000 }, { paths = "src/L1/OPContractsManagerStandardValidator.sol", optimizer_runs = 5000 }, { paths = "src/L1/opcm/OPContractsManagerV2.sol", optimizer_runs = 5000 }, { paths = "src/L1/opcm/OPContractsManagerContainer.sol", optimizer_runs = 5000 }, @@ -61,7 +60,6 @@ fs_permissions = [ { access='read-write', path='./.resource-metering.csv' }, { access='read-write', path='./snapshots/' }, { access='read-write', path='./deployments/' }, - { access='read', path='./deploy-config/' }, { access='read', path='./deploy-config-periphery/' }, { access='read', path='./broadcast/' }, { access='read', path = './forge-artifacts/' }, @@ -140,7 +138,6 @@ compilation_restrictions = [ { paths = "src/dispute/PermissionedDisputeGame.sol", optimizer_runs = 0 }, { paths = "src/dispute/SuperFaultDisputeGame.sol", optimizer_runs = 0 }, { paths = "src/dispute/SuperPermissionedDisputeGame.sol", optimizer_runs = 0 }, - { paths = "src/L1/OPContractsManager.sol", optimizer_runs = 0 }, { paths = "src/L1/OPContractsManagerStandardValidator.sol", optimizer_runs = 0 }, { paths = "src/L1/opcm/OPContractsManagerV2.sol", optimizer_runs = 0 }, { paths = "src/L1/opcm/OPContractsManagerContainer.sol", optimizer_runs = 0 }, @@ -182,7 +179,6 @@ compilation_restrictions = [ { paths = "src/dispute/PermissionedDisputeGame.sol", optimizer_runs = 0 }, { paths = "src/dispute/SuperFaultDisputeGame.sol", optimizer_runs = 0 }, { paths = "src/dispute/SuperPermissionedDisputeGame.sol", optimizer_runs = 0 }, - { paths = "src/L1/OPContractsManager.sol", optimizer_runs = 0 }, { paths = "src/L1/OPContractsManagerStandardValidator.sol", optimizer_runs = 0 }, { paths = "src/L1/opcm/OPContractsManagerV2.sol", optimizer_runs = 0 }, { paths = "src/L1/opcm/OPContractsManagerContainer.sol", optimizer_runs = 0 }, @@ -219,7 +215,6 @@ compilation_restrictions = [ { paths = "src/dispute/PermissionedDisputeGame.sol", optimizer_runs = 0 }, { paths = "src/dispute/SuperFaultDisputeGame.sol", optimizer_runs = 0 }, { paths = "src/dispute/SuperPermissionedDisputeGame.sol", optimizer_runs = 0 }, - { paths = "src/L1/OPContractsManager.sol", optimizer_runs = 0 }, { paths = "src/L1/OPContractsManagerStandardValidator.sol", optimizer_runs = 0 }, { paths = "src/L1/opcm/OPContractsManagerV2.sol", optimizer_runs = 0 }, { paths = "src/L1/opcm/OPContractsManagerContainer.sol", optimizer_runs = 0 }, diff --git a/packages/contracts-bedrock/interfaces/L1/IOPContractsManager.sol b/packages/contracts-bedrock/interfaces/L1/IOPContractsManager.sol deleted file mode 100644 index ecdbaa92ea0..00000000000 --- a/packages/contracts-bedrock/interfaces/L1/IOPContractsManager.sol +++ /dev/null @@ -1,405 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -// Libraries -import { Claim, Duration, GameType, Proposal } from "src/dispute/lib/Types.sol"; - -// Interfaces -import { IBigStepper } from "interfaces/dispute/IBigStepper.sol"; -import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; -import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; -import { IAddressManager } from "interfaces/legacy/IAddressManager.sol"; -import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; -import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; -import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; -import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; -import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol"; -import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol"; -import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol"; -import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; -import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; -import { IL1CrossDomainMessenger } from "interfaces/L1/IL1CrossDomainMessenger.sol"; -import { IL1ERC721Bridge } from "interfaces/L1/IL1ERC721Bridge.sol"; -import { IL1StandardBridge } from "interfaces/L1/IL1StandardBridge.sol"; -import { IOptimismMintableERC20Factory } from "interfaces/universal/IOptimismMintableERC20Factory.sol"; -import { IETHLockbox } from "interfaces/L1/IETHLockbox.sol"; -import { IOPContractsManagerStandardValidator } from "interfaces/L1/IOPContractsManagerStandardValidator.sol"; - -interface IOPContractsManagerContractsContainer { - error OPContractsManagerContractsContainer_DevFeatureInProd(); - - function __constructor__( - IOPContractsManager.Blueprints memory _blueprints, - IOPContractsManager.Implementations memory _implementations, - bytes32 _devFeatureBitmap - ) - external; - - function blueprints() external view returns (IOPContractsManager.Blueprints memory); - function implementations() external view returns (IOPContractsManager.Implementations memory); - function devFeatureBitmap() external view returns (bytes32); - function isDevFeatureEnabled(bytes32 _feature) external view returns (bool); -} - -interface IOPContractsManagerGameTypeAdder { - error OPContractsManagerGameTypeAdder_UnsupportedGameType(); - error OPContractsManagerGameTypeAdder_MixedGameTypes(); - - event GameTypeAdded( - uint256 indexed l2ChainId, GameType indexed gameType, address newDisputeGame, address oldDisputeGame - ); - - function __constructor__(IOPContractsManagerContractsContainer _contractsContainer) external; - - function addGameType( - IOPContractsManager.AddGameInput[] memory _gameConfigs, - address _superchainConfig - ) - external - returns (IOPContractsManager.AddGameOutput[] memory); - - function updatePrestate( - IOPContractsManager.UpdatePrestateInput[] memory _prestateUpdateInputs, - address _superchainConfig - ) - external; - - function contractsContainer() external view returns (IOPContractsManagerContractsContainer); -} - -interface IOPContractsManagerDeployer { - event Deployed(uint256 indexed l2ChainId, address indexed deployer, bytes deployOutput); - - function __constructor__(IOPContractsManagerContractsContainer _contractsContainer) external; - - function deploy( - IOPContractsManager.DeployInput memory _input, - ISuperchainConfig _superchainConfig, - address _deployer - ) - external - returns (IOPContractsManager.DeployOutput memory); - - function contractsContainer() external view returns (IOPContractsManagerContractsContainer); -} - -interface IOPContractsManagerUpgrader { - event Upgraded(uint256 indexed l2ChainId, address indexed systemConfig, address indexed upgrader); - - error OPContractsManagerUpgrader_SuperchainConfigNeedsUpgrade(uint256 index); - - error OPContractsManagerUpgrader_SuperchainConfigAlreadyUpToDate(); - - function __constructor__(IOPContractsManagerContractsContainer _contractsContainer) external; - - function upgrade(IOPContractsManager.OpChainConfig[] memory _opChainConfigs) external; - - function upgradeSuperchainConfig(ISuperchainConfig _superchainConfig) external; - - function contractsContainer() external view returns (IOPContractsManagerContractsContainer); -} - -interface IOPContractsManagerInteropMigrator { - error OPContractsManagerInteropMigrator_ProxyAdminOwnerMismatch(); - error OPContractsManagerInteropMigrator_SuperchainConfigMismatch(); - error OPContractsManagerInteropMigrator_AbsolutePrestateMismatch(); - - struct GameParameters { - address proposer; - address challenger; - uint256 maxGameDepth; - uint256 splitDepth; - uint256 initBond; - Duration clockExtension; - Duration maxClockDuration; - } - - struct MigrateInput { - bool usePermissionlessGame; - Proposal startingAnchorRoot; - GameParameters gameParameters; - IOPContractsManager.OpChainConfig[] opChainConfigs; - } - - function __constructor__(IOPContractsManagerContractsContainer _contractsContainer) external; - - function migrate(MigrateInput calldata _input) external; -} - -interface IOPContractsManager { - // -------- Structs -------- - - /// @notice Represents the roles that can be set when deploying a standard OP Stack chain. - struct Roles { - address opChainProxyAdminOwner; - address systemConfigOwner; - address batcher; - address unsafeBlockSigner; - address proposer; - address challenger; - } - - /// @notice The full set of inputs to deploy a new OP Stack chain. - struct DeployInput { - Roles roles; - uint32 basefeeScalar; - uint32 blobBasefeeScalar; - uint256 l2ChainId; - // The correct type is OutputRoot memory but OP Deployer does not yet support structs. - bytes startingAnchorRoot; - // The salt mixer is used as part of making the resulting salt unique. - string saltMixer; - uint64 gasLimit; - // Configurable dispute game parameters. - GameType disputeGameType; - Claim disputeAbsolutePrestate; - uint256 disputeMaxGameDepth; - uint256 disputeSplitDepth; - Duration disputeClockExtension; - Duration disputeMaxClockDuration; - // Whether to use the custom gas token. - bool useCustomGasToken; - } - - /// @notice The full set of outputs from deploying a new OP Stack chain. - struct DeployOutput { - IProxyAdmin opChainProxyAdmin; - IAddressManager addressManager; - IL1ERC721Bridge l1ERC721BridgeProxy; - ISystemConfig systemConfigProxy; - IOptimismMintableERC20Factory optimismMintableERC20FactoryProxy; - IL1StandardBridge l1StandardBridgeProxy; - IL1CrossDomainMessenger l1CrossDomainMessengerProxy; - IETHLockbox ethLockboxProxy; - // Fault proof contracts below. - IOptimismPortal2 optimismPortalProxy; - IDisputeGameFactory disputeGameFactoryProxy; - IAnchorStateRegistry anchorStateRegistryProxy; - IFaultDisputeGame faultDisputeGame; - IPermissionedDisputeGame permissionedDisputeGame; - IDelayedWETH delayedWETHPermissionedGameProxy; - IDelayedWETH delayedWETHPermissionlessGameProxy; - } - - /// @notice Addresses of ERC-5202 Blueprint contracts. There are used for deploying full size - /// contracts, to reduce the code size of this factory contract. If it deployed full contracts - /// using the `new Proxy()` syntax, the code size would get large fast, since this contract would - /// contain the bytecode of every contract it deploys. Therefore we instead use Blueprints to - /// reduce the code size of this contract. - struct Blueprints { - address addressManager; - address proxy; - address proxyAdmin; - address l1ChugSplashProxy; - address resolvedDelegateProxy; - } - - /// @notice The latest implementation contracts for the OP Stack. - struct Implementations { - address superchainConfigImpl; - address protocolVersionsImpl; - address l1ERC721BridgeImpl; - address optimismPortalImpl; - address optimismPortalInteropImpl; - address ethLockboxImpl; - address systemConfigImpl; - address optimismMintableERC20FactoryImpl; - address l1CrossDomainMessengerImpl; - address l1StandardBridgeImpl; - address disputeGameFactoryImpl; - address anchorStateRegistryImpl; - address delayedWETHImpl; - address mipsImpl; - address faultDisputeGameImpl; - address permissionedDisputeGameImpl; - address superFaultDisputeGameImpl; - address superPermissionedDisputeGameImpl; - } - - /// @notice The input required to identify a chain for upgrading. - struct OpChainConfig { - ISystemConfig systemConfigProxy; - Claim cannonPrestate; - Claim cannonKonaPrestate; - } - - /// @notice The input required to identify a chain for updating prestates - struct UpdatePrestateInput { - ISystemConfig systemConfigProxy; - Claim cannonPrestate; - Claim cannonKonaPrestate; - } - - struct AddGameInput { - string saltMixer; - ISystemConfig systemConfig; - IDelayedWETH delayedWETH; - GameType disputeGameType; - Claim disputeAbsolutePrestate; - uint256 disputeMaxGameDepth; - uint256 disputeSplitDepth; - Duration disputeClockExtension; - Duration disputeMaxClockDuration; - uint256 initialBond; - IBigStepper vm; - bool permissioned; - } - - struct AddGameOutput { - IDelayedWETH delayedWETH; - IFaultDisputeGame faultDisputeGame; - } - - // -------- Constants and Variables -------- - - function version() external pure returns (string memory); - - /// @notice Address of the SuperchainConfig contract shared by all chains. - function superchainConfig() external view returns (ISuperchainConfig); - - /// @notice Address of the ProtocolVersions contract shared by all chains. - function protocolVersions() external view returns (IProtocolVersions); - - // -------- Errors -------- - - /// @notice Thrown when an address is the zero address. - error AddressNotFound(address who); - - /// @notice Throw when a contract address has no code. - error AddressHasNoCode(address who); - - /// @notice Thrown when a release version is already set. - error AlreadyReleased(); - - /// @notice Thrown when an invalid `l2ChainId` is provided to `deploy`. - error InvalidChainId(); - - /// @notice Thrown when a role's address is not valid. - error InvalidRoleAddress(string role); - - /// @notice Thrown when the latest release is not set upon initialization. - error LatestReleaseNotSet(); - - /// @notice Thrown when the starting anchor root is not provided. - error InvalidStartingAnchorRoot(); - - /// @notice Thrown when certain methods are called outside of a DELEGATECALL. - error OnlyDelegatecall(); - - /// @notice Thrown when game configs passed to addGameType are invalid. - error InvalidGameConfigs(); - - /// @notice Thrown when the SuperchainConfig of the chain does not match the SuperchainConfig of this OPCM. - error SuperchainConfigMismatch(ISystemConfig systemConfig); - - error SuperchainProxyAdminMismatch(); - - error PrestateNotSet(); - - error PrestateRequired(); - - error InvalidDevFeatureAccess(bytes32 devFeature); - - error OPContractsManager_V2Enabled(); - - // -------- Methods -------- - - function __constructor__( - IOPContractsManagerGameTypeAdder _opcmGameTypeAdder, - IOPContractsManagerDeployer _opcmDeployer, - IOPContractsManagerUpgrader _opcmUpgrader, - IOPContractsManagerInteropMigrator _opcmInteropMigrator, - IOPContractsManagerStandardValidator _opcmStandardValidator, - ISuperchainConfig _superchainConfig, - IProtocolVersions _protocolVersions - ) - external; - - function validateWithOverrides( - IOPContractsManagerStandardValidator.ValidationInput calldata _input, - bool _allowFailure, - IOPContractsManagerStandardValidator.ValidationOverrides calldata _overrides - ) - external - view - returns (string memory); - - function validate( - IOPContractsManagerStandardValidator.ValidationInput calldata _input, - bool _allowFailure - ) - external - view - returns (string memory); - - function validateWithOverrides( - IOPContractsManagerStandardValidator.ValidationInputDev calldata _input, - bool _allowFailure, - IOPContractsManagerStandardValidator.ValidationOverrides calldata _overrides - ) - external - view - returns (string memory); - - function validate( - IOPContractsManagerStandardValidator.ValidationInputDev calldata _input, - bool _allowFailure - ) - external - view - returns (string memory); - - function deploy(DeployInput calldata _input) external returns (DeployOutput memory); - - /// @notice Upgrades the implementation of all proxies in the specified chains - /// @param _opChainConfigs The chains to upgrade - function upgrade(OpChainConfig[] memory _opChainConfigs) external; - - /// @notice Upgrades the SuperchainConfig contract. - /// @param _superchainConfig The SuperchainConfig contract to upgrade. - function upgradeSuperchainConfig(ISuperchainConfig _superchainConfig) external; - - /// @notice addGameType deploys a new dispute game and links it to the DisputeGameFactory. The inputted _gameConfigs - /// must be added in ascending GameType order. - function addGameType(AddGameInput[] memory _gameConfigs) external returns (AddGameOutput[] memory); - - /// @notice Updates the prestate hash for a new game type while keeping all other parameters the same - /// @param _prestateUpdateInputs The new prestates to use - function updatePrestate(UpdatePrestateInput[] memory _prestateUpdateInputs) external; - - /// @notice Migrates one or more OP Stack chains to use the Super Root dispute games and shared - /// dispute game contracts. - /// @param _input The input parameters for the migration. - function migrate(IOPContractsManagerInteropMigrator.MigrateInput calldata _input) external; - - /// @notice Maps an L2 chain ID to an L1 batch inbox address as defined by the standard - /// configuration's convention. This convention is `versionByte || keccak256(bytes32(chainId))[:19]`, - /// where || denotes concatenation`, versionByte is 0x00, and chainId is a uint256. - /// https://specs.optimism.io/protocol/configurability.html#consensus-parameters - function chainIdToBatchInboxAddress(uint256 _l2ChainId) external pure returns (address); - - /// @notice Returns the blueprint contract addresses. - function blueprints() external view returns (Blueprints memory); - - function opcmDeployer() external view returns (IOPContractsManagerDeployer); - - function opcmUpgrader() external view returns (IOPContractsManagerUpgrader); - - function opcmGameTypeAdder() external view returns (IOPContractsManagerGameTypeAdder); - - function opcmInteropMigrator() external view returns (IOPContractsManagerInteropMigrator); - - function opcmStandardValidator() external view returns (IOPContractsManagerStandardValidator); - - /// @notice Retrieves the development feature bitmap stored in this OPCM contract - /// @return The development feature bitmap. - function devFeatureBitmap() external view returns (bytes32); - - /// @notice Returns the status of a development feature. - /// @param _feature The feature to check. - /// @return True if the feature is enabled, false otherwise. - function isDevFeatureEnabled(bytes32 _feature) external view returns (bool); - - /// @notice Returns the implementation contract addresses. - function implementations() external view returns (Implementations memory); -} diff --git a/packages/contracts-bedrock/interfaces/L1/IOPContractsManagerStandardValidator.sol b/packages/contracts-bedrock/interfaces/L1/IOPContractsManagerStandardValidator.sol index c4b303b0ce9..decd32d33e3 100644 --- a/packages/contracts-bedrock/interfaces/L1/IOPContractsManagerStandardValidator.sol +++ b/packages/contracts-bedrock/interfaces/L1/IOPContractsManagerStandardValidator.sol @@ -9,7 +9,6 @@ interface IOPContractsManagerStandardValidator { struct Implementations { address l1ERC721BridgeImpl; address optimismPortalImpl; - address optimismPortalInteropImpl; address ethLockboxImpl; address systemConfigImpl; address optimismMintableERC20FactoryImpl; @@ -64,7 +63,6 @@ interface IOPContractsManagerStandardValidator { function superPermissionedDisputeGameImpl() external view returns (address); function optimismMintableERC20FactoryImpl() external view returns (address); function optimismPortalImpl() external view returns (address); - function optimismPortalInteropImpl() external view returns (address); function ethLockboxImpl() external view returns (address); function preimageOracleVersion() external pure returns (string memory); function superchainConfig() external view returns (ISuperchainConfig); diff --git a/packages/contracts-bedrock/interfaces/L1/IOptimismPortal2.sol b/packages/contracts-bedrock/interfaces/L1/IOptimismPortal2.sol index 41d19d9f56e..fde972fcd46 100644 --- a/packages/contracts-bedrock/interfaces/L1/IOptimismPortal2.sol +++ b/packages/contracts-bedrock/interfaces/L1/IOptimismPortal2.sol @@ -30,15 +30,25 @@ interface IOptimismPortal2 is IProxyAdminOwnedBase { error OptimismPortal_InvalidOutputRootProof(); error OptimismPortal_InvalidProofTimestamp(); error OptimismPortal_InvalidRootClaim(); + error OptimismPortal_MigratingToSameRegistry(); error OptimismPortal_NoReentrancy(); + error OptimismPortal_NotUsingInterop(); error OptimismPortal_ProofNotOldEnough(); error OptimismPortal_Unproven(); + error OptimismPortal_InvalidInteropState(); error OptimismPortal_InvalidLockboxState(); error OutOfGas(); error UnexpectedList(); error UnexpectedString(); event Initialized(uint8 version); + event ETHMigrated(address indexed lockbox, uint256 balance); + event PortalMigrated( + IETHLockbox oldLockbox, + IETHLockbox newLockbox, + IAnchorStateRegistry oldAnchorStateRegistry, + IAnchorStateRegistry newAnchorStateRegistry + ); event TransactionDeposited(address indexed from, address indexed to, uint256 indexed version, bytes opaqueData); event WithdrawalFinalized(bytes32 indexed withdrawalHash, bool success); event WithdrawalProven(bytes32 indexed withdrawalHash, address indexed from, address indexed to); @@ -71,9 +81,11 @@ interface IOptimismPortal2 is IProxyAdminOwnedBase { external; function finalizedWithdrawals(bytes32) external view returns (bool); function guardian() external view returns (address); - function initialize(ISystemConfig _systemConfig, IAnchorStateRegistry _anchorStateRegistry) external; + function initialize(ISystemConfig _systemConfig, IAnchorStateRegistry _anchorStateRegistry, IETHLockbox _ethLockbox) external; function initVersion() external view returns (uint8); function l2Sender() external view returns (address); + function migrateLiquidity() external; + function migrateToSharedDisputeGame(IETHLockbox _newLockbox, IAnchorStateRegistry _newAnchorStateRegistry) external; function minimumGasLimit(uint64 _byteCount) external pure returns (uint64); function numProofSubmitters(bytes32 _withdrawalHash) external view returns (uint256); function params() external view returns (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum); // nosemgrep diff --git a/packages/contracts-bedrock/interfaces/L1/IOptimismPortalInterop.sol b/packages/contracts-bedrock/interfaces/L1/IOptimismPortalInterop.sol deleted file mode 100644 index 4f3917a70d2..00000000000 --- a/packages/contracts-bedrock/interfaces/L1/IOptimismPortalInterop.sol +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import { Types } from "src/libraries/Types.sol"; -import { GameType } from "src/dispute/lib/LibUDT.sol"; -import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; -import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; -import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; -import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; -import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; -import { IProxyAdminOwnedBase } from "interfaces/universal/IProxyAdminOwnedBase.sol"; -import { IETHLockbox } from "interfaces/L1/IETHLockbox.sol"; - -interface IOptimismPortalInterop is IProxyAdminOwnedBase { - error ContentLengthMismatch(); - error EmptyItem(); - error InvalidDataRemainder(); - error InvalidHeader(); - error ReinitializableBase_ZeroInitVersion(); - error OptimismPortal_AlreadyFinalized(); - error OptimismPortal_BadTarget(); - error OptimismPortal_CallPaused(); - error OptimismPortal_CalldataTooLarge(); - error OptimismPortal_GasEstimation(); - error OptimismPortal_GasLimitTooLow(); - error OptimismPortal_ImproperDisputeGame(); - error OptimismPortal_InvalidDisputeGame(); - error OptimismPortal_InvalidMerkleProof(); - error OptimismPortal_InvalidOutputRootProof(); - error OptimismPortal_InvalidProofTimestamp(); - error OptimismPortal_InvalidRootClaim(); - error OptimismPortal_NoReentrancy(); - error OptimismPortal_ProofNotOldEnough(); - error OptimismPortal_Unproven(); - error OptimismPortal_MigratingToSameRegistry(); - error OutOfGas(); - error UnexpectedList(); - error UnexpectedString(); - - event Initialized(uint8 version); - event TransactionDeposited(address indexed from, address indexed to, uint256 indexed version, bytes opaqueData); - event WithdrawalFinalized(bytes32 indexed withdrawalHash, bool success); - event WithdrawalProven(bytes32 indexed withdrawalHash, address indexed from, address indexed to); - event WithdrawalProvenExtension1(bytes32 indexed withdrawalHash, address indexed proofSubmitter); - event ETHMigrated(address indexed lockbox, uint256 ethBalance); - event PortalMigrated(IETHLockbox oldLockbox, IETHLockbox newLockbox, IAnchorStateRegistry oldAnchorStateRegistry, IAnchorStateRegistry newAnchorStateRegistry); - - receive() external payable; - - function anchorStateRegistry() external view returns (IAnchorStateRegistry); - function ethLockbox() external view returns (IETHLockbox); - function checkWithdrawal(bytes32 _withdrawalHash, address _proofSubmitter) external view; - function depositTransaction( - address _to, - uint256 _value, - uint64 _gasLimit, - bool _isCreation, - bytes memory _data - ) - external - payable; - function disputeGameBlacklist(IDisputeGame _disputeGame) external view returns (bool); - function disputeGameFactory() external view returns (IDisputeGameFactory); - function disputeGameFinalityDelaySeconds() external view returns (uint256); - function donateETH() external payable; - function superchainConfig() external view returns (ISuperchainConfig); - function migrateToSuperRoots(IETHLockbox _newLockbox, IAnchorStateRegistry _newAnchorStateRegistry) external; - function finalizeWithdrawalTransaction(Types.WithdrawalTransaction memory _tx) external; - function finalizeWithdrawalTransactionExternalProof( - Types.WithdrawalTransaction memory _tx, - address _proofSubmitter - ) - external; - function finalizedWithdrawals(bytes32) external view returns (bool); - function guardian() external view returns (address); - function initialize( - ISystemConfig _systemConfig, - IAnchorStateRegistry _anchorStateRegistry, - IETHLockbox _ethLockbox - ) - external; - function initVersion() external view returns (uint8); - function l2Sender() external view returns (address); - function minimumGasLimit(uint64 _byteCount) external pure returns (uint64); - function numProofSubmitters(bytes32 _withdrawalHash) external view returns (uint256); - function params() external view returns (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum); // nosemgrep - function paused() external view returns (bool); - function proofMaturityDelaySeconds() external view returns (uint256); - function proofSubmitters(bytes32, uint256) external view returns (address); - function proveWithdrawalTransaction( - Types.WithdrawalTransaction memory _tx, - uint256 _disputeGameIndex, - Types.OutputRootProof memory _outputRootProof, - bytes[] memory _withdrawalProof - ) - external; - function provenWithdrawals( - bytes32, - address - ) - external - view - returns (IDisputeGame disputeGameProxy, uint64 timestamp); - function respectedGameType() external view returns (GameType); - function respectedGameTypeUpdatedAt() external view returns (uint64); - function superRootsActive() external view returns (bool); - function systemConfig() external view returns (ISystemConfig); - function upgrade(IAnchorStateRegistry _anchorStateRegistry, IETHLockbox _ethLockbox) external; - function version() external pure returns (string memory); - function migrateLiquidity() external; - - function __constructor__(uint256 _proofMaturityDelaySeconds) external; -} diff --git a/packages/contracts-bedrock/interfaces/L1/opcm/IOPContractsManagerContainer.sol b/packages/contracts-bedrock/interfaces/L1/opcm/IOPContractsManagerContainer.sol index 03ba33e9fce..aeb5c17f95b 100644 --- a/packages/contracts-bedrock/interfaces/L1/opcm/IOPContractsManagerContainer.sol +++ b/packages/contracts-bedrock/interfaces/L1/opcm/IOPContractsManagerContainer.sol @@ -15,7 +15,6 @@ interface IOPContractsManagerContainer { address protocolVersionsImpl; address l1ERC721BridgeImpl; address optimismPortalImpl; - address optimismPortalInteropImpl; address ethLockboxImpl; address systemConfigImpl; address optimismMintableERC20FactoryImpl; diff --git a/packages/contracts-bedrock/justfile b/packages/contracts-bedrock/justfile index 06a5403db5b..4133663766e 100644 --- a/packages/contracts-bedrock/justfile +++ b/packages/contracts-bedrock/justfile @@ -236,6 +236,8 @@ genesis: forge script scripts/L2Genesis.s.sol:L2Genesis --sig 'runWithStateDump()' # Generates the Network Upgrade Transaction (NUT) bundle. +# NOTE: be very careful about renaming this command, it's used in the CI check-nut-locks job, +# which expects this command to be available in historical commits. generate-nut-bundle: build-no-tests @forge script scripts/upgrade/GenerateNUTBundle.s.sol:GenerateNUTBundle --sig 'run()' > /dev/null @@ -294,15 +296,6 @@ snapshots-check: build snapshots-check-no-build interfaces-check-no-build: go run ./scripts/checks/interfaces -# Checks that, if any L1 source contracts that have an upgrade method, -# that upgrade method is called in the OPContractsManagerUpgrader.upgrade method. -# Build the contracts first. -opcm-upgrade-checks: clean build-dev opcm-upgrade-checks-no-build - -# Checks that, if any L1 source contracts that have an upgrade method, -# that upgrade method is called in the OPContractsManagerUpgrader.upgrade method. -opcm-upgrade-checks-no-build: - go run ./scripts/checks/opcm-upgrade-checks/ # Checks that all interfaces are appropriately named and accurately reflect the corresponding # contract that they're meant to represent. We run "clean" before building because leftover @@ -369,10 +362,6 @@ valid-semver-check-no-build: # Checks that the semver of contracts are valid. valid-semver-check: build valid-semver-check-no-build -# Checks that the deploy configs are valid. -validate-deploy-configs: - ./scripts/checks/check-deploy-configs.sh - # Checks that spacer variables are correctly inserted without building. validate-spacers-no-build: go run ./scripts/checks/spacers @@ -414,7 +403,6 @@ check: strict-pragma-check-no-build \ valid-semver-check-no-build \ semver-diff-check-no-build \ - validate-deploy-configs \ validate-spacers-no-build \ reinitializer-check-no-build \ interfaces-check-no-build \ diff --git a/packages/contracts-bedrock/scripts/checks/check-deploy-configs.sh b/packages/contracts-bedrock/scripts/checks/check-deploy-configs.sh deleted file mode 100755 index 6329fb1d88d..00000000000 --- a/packages/contracts-bedrock/scripts/checks/check-deploy-configs.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -# This script is used to check for valid deploy configs. -# It should check all configs and return a non-zero exit code if any of them are invalid. -# getting-started.json isn't valid JSON so its skipped. - -code=0 - -SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) -CONTRACTS_BASE=$(dirname "$(dirname "$SCRIPT_DIR")") -MONOREPO_BASE=$(dirname "$(dirname "$CONTRACTS_BASE")") - -for config in "$CONTRACTS_BASE"/deploy-config/*.json; do - # shellcheck disable=SC2086 - if ! go run "$MONOREPO_BASE/op-chain-ops/cmd/check-deploy-config/main.go" --path "$config"; then - code=1 - fi -done - -exit $code diff --git a/packages/contracts-bedrock/scripts/checks/interfaces/main.go b/packages/contracts-bedrock/scripts/checks/interfaces/main.go index 3c87ab8df7d..310e5d9a1d0 100644 --- a/packages/contracts-bedrock/scripts/checks/interfaces/main.go +++ b/packages/contracts-bedrock/scripts/checks/interfaces/main.go @@ -27,9 +27,6 @@ var excludeContracts = []string{ // EAS "IEAS", "ISchemaResolver", "ISchemaRegistry", - // Misc stuff that can be ignored - "IOPContractsManagerLegacyUpgrade", - // Constructor inheritance differences "IL2ProxyAdmin", @@ -52,8 +49,8 @@ var excludeSourceContracts = []string{ // Periphery "TransferOnion", "AssetReceiver", "AdminFaucetAuthModule", "CheckSecrets", "CheckBalanceLow", "CheckTrue", "Drippie", "Transactor", "Faucet", - // Errors because they should be in their own contracts but are in a shared one - "OPContractsManagerDeployer", "OPContractsManagerUpgrader", "OPContractsManagerBase", "OPContractsManagerInteropMigrator", "OPContractsManagerContractsContainer", "OPContractsManagerGameTypeAdder", "OPContractsManagerStandardValidator", + // OPCM sub-contracts that don't have their own interfaces + "OPContractsManagerStandardValidator", // FIXME "WETH", "MIPS64", diff --git a/packages/contracts-bedrock/scripts/checks/opcm-upgrade-checks/OPCMUpgradeChecksMocks.sol b/packages/contracts-bedrock/scripts/checks/opcm-upgrade-checks/OPCMUpgradeChecksMocks.sol deleted file mode 100644 index aa879a02020..00000000000 --- a/packages/contracts-bedrock/scripts/checks/opcm-upgrade-checks/OPCMUpgradeChecksMocks.sol +++ /dev/null @@ -1,470 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -IUpgradeable constant UPGRADE_CONTRACT = IUpgradeable(address(111)); -uint8 constant NOT_FOUND = 0; -uint8 constant UPGRADE_EXTERNAL_CALL = 1; -uint8 constant UPGRADE_INTERNAL_CALL = 2; - -interface IUpgradeable { - function upgrade() external; - function upgradeAndCall(address _newImplementation, address _newImplementationCode, bytes memory _data) external; -} - -///////// INDIRECT UPGRADE CALLS ////////// - -contract InternalUpgradeFunction { - function upgradeToAndCall(IUpgradeable _a, address _b, address _c, bytes memory _d) internal { - _a.upgradeAndCall(_b, _c, _d); - } -} - -contract WithNoExternalUpgradeFunctionInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = NOT_FOUND; - - function aaa() external { - upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } -} - -contract CorrectInterfaceButWrongFunctionTypeInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = NOT_FOUND; - - function upgrade() external { - upgradeToAndCall( - UPGRADE_CONTRACT, - address(UPGRADE_CONTRACT), - address(0), - abi.encodeCall( - IUpgradeable.upgradeAndCall, (address(0), address(0), abi.encodeCall(IUpgradeable.upgrade, ())) - ) - ); - } -} - -contract WrongInterfaceButCorrectFunctionTypeInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = NOT_FOUND; - - function upgrade() external { - upgradeToAndCall( - UPGRADE_CONTRACT, - address(UPGRADE_CONTRACT), - address(0), - abi.encodeCall(WrongInterfaceButCorrectFunctionTypeInternal.upgrade, ()) - ); - } -} - -contract WithinTopLevelFunctionInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function upgrade() external { - upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } -} - -contract WithinBlockStatementInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function upgrade() external { - { - upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } - } -} - -contract WithinForLoopInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function upgrade() external { - for (uint256 i = 0; i < 10; i++) { - upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } - } -} - -contract WithinWhileLoopInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function upgrade() external { - while (true) { - upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } - } -} - -contract WithinDoWhileLoopInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function upgrade() external { - do { - upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } while (true); - } -} - -contract WithinTrueBlockOfIfStatementInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function upgrade(uint256 _a) external { - if (_a < 10) { - upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } else { - revert(); - } - } -} - -contract WithinFalseBlockOfIfStatementInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function upgrade(uint256 _a) external { - if (_a < 10) { - revert(); - } else { - upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } - } -} - -contract WithinElseIfBlockOfIfStatementInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function upgrade(uint256 _a) external { - if (_a < 10) { - revert(); - } else if (_a < 20) { - upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } else { - revert(); - } - } -} - -contract WithinTrueBlockOfTernaryStatementInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function mock() external { } - - function upgrade(uint256 _a) external { - _a < 10 - ? upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ) - : this.mock(); - } -} - -contract WithinFalseBlockOfTernaryStatementInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function mock() external { } - - function upgrade(uint256 _a) external { - _a < 10 - ? this.mock() - : upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } -} - -contract WithinTrueBlockOfTrueBlockOfNestedTernaryStatementInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function mock() external { } - - function upgrade(uint256 _a) external { - _a < 10 - ? _a < 5 - ? upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ) - : this.mock() - : this.mock(); - } -} - -contract WithinFalseBlockOfTrueBlockOfNestedTernaryStatementInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function mock() external { } - - function upgrade(uint256 _a) external { - _a < 10 - ? _a < 5 - ? this.mock() - : upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ) - : this.mock(); - } -} - -contract WithinFalseBlockOfFalseBlockOfNestedTernaryStatementInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function mock() external { } - - function upgrade(uint256 _a) external { - _a < 10 - ? this.mock() - : _a > 5 - ? this.mock() - : upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } -} - -contract WithinTrueBlockOfFalseBlockOfNestedTernaryStatementInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function mock() external { } - - function upgrade(uint256 _a) external { - _a < 10 - ? this.mock() - : _a > 5 - ? upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ) - : this.mock(); - } -} - -contract WithinTryBlockOfTryCatchStatementInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function mock() external { } - - function upgrade() external { - try this.mock() { - upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } catch { } - } -} - -contract WithinCatchBlockOfTryCatchStatementInternal is InternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_INTERNAL_CALL; - - function mock() external { } - - function upgrade() external { - try this.mock() { } - catch { - upgradeToAndCall( - UPGRADE_CONTRACT, address(UPGRADE_CONTRACT), address(0), abi.encodeCall(IUpgradeable.upgrade, ()) - ); - } - } -} - -///////// DIRECT UPGRADE CALLS ////////// - -contract WithNoExternalUpgradeFunction { - uint8 constant EXPECTED_OUTPUT = NOT_FOUND; - - function aaa() external { - UPGRADE_CONTRACT.upgrade(); - } -} - -contract WithinTopLevelFunction { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function upgrade() external { - UPGRADE_CONTRACT.upgrade(); - } -} - -contract WithinBlockStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function upgrade() external { - { - UPGRADE_CONTRACT.upgrade(); - } - } -} - -contract WithinForLoop { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function upgrade() external { - for (uint256 i = 0; i < 10; i++) { - UPGRADE_CONTRACT.upgrade(); - } - } -} - -contract WithinWhileLoop { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function upgrade() external { - while (true) { - UPGRADE_CONTRACT.upgrade(); - } - } -} - -contract WithinDoWhileLoop { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function upgrade() external { - do { - UPGRADE_CONTRACT.upgrade(); - } while (true); - } -} - -contract WithinTrueBlockOfIfStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function upgrade(uint256 _a) external { - if (_a < 10) { - UPGRADE_CONTRACT.upgrade(); - } else { - revert(); - } - } -} - -contract WithinFalseBlockOfIfStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function upgrade(uint256 _a) external { - if (_a < 10) { - revert(); - } else { - UPGRADE_CONTRACT.upgrade(); - } - } -} - -contract WithinElseIfBlockOfIfStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function upgrade(uint256 _a) external { - if (_a < 10) { - revert(); - } else if (_a < 20) { - UPGRADE_CONTRACT.upgrade(); - } else { - revert(); - } - } -} - -contract WithinTrueBlockOfTernaryStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function mock() external { } - - function upgrade(uint256 _a) external { - _a < 10 ? UPGRADE_CONTRACT.upgrade() : this.mock(); - } -} - -contract WithinFalseBlockOfTernaryStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function mock() external { } - - function upgrade(uint256 _a) external { - _a < 10 ? this.mock() : UPGRADE_CONTRACT.upgrade(); - } -} - -contract WithinTrueBlockOfTrueBlockOfNestedTernaryStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function mock() external { } - - function upgrade(uint256 _a) external { - _a < 10 ? _a < 5 ? UPGRADE_CONTRACT.upgrade() : this.mock() : this.mock(); - } -} - -contract WithinFalseBlockOfTrueBlockOfNestedTernaryStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function mock() external { } - - function upgrade(uint256 _a) external { - _a < 10 ? _a < 5 ? this.mock() : UPGRADE_CONTRACT.upgrade() : this.mock(); - } -} - -contract WithinFalseBlockOfFalseBlockOfNestedTernaryStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function mock() external { } - - function upgrade(uint256 _a) external { - _a < 10 ? this.mock() : _a < 5 ? this.mock() : UPGRADE_CONTRACT.upgrade(); - } -} - -contract WithinTrueBlockOfFalseBlockOfNestedTernaryStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function mock() external { } - - function upgrade(uint256 _a) external { - _a < 10 ? this.mock() : _a < 5 ? UPGRADE_CONTRACT.upgrade() : this.mock(); - } -} - -contract WithTryStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function upgrade() external { - try UPGRADE_CONTRACT.upgrade() { } catch { } - } -} - -contract WithinTryBlockOfTryCatchStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function mock() external { } - - function upgrade() external { - try this.mock() { - UPGRADE_CONTRACT.upgrade(); - } catch { } - } -} - -contract WithinCatchBlockOfTryCatchStatement { - uint8 constant EXPECTED_OUTPUT = UPGRADE_EXTERNAL_CALL; - - function mock() external { } - - function upgrade() external { - try this.mock() { } - catch { - UPGRADE_CONTRACT.upgrade(); - } - } -} diff --git a/packages/contracts-bedrock/scripts/checks/opcm-upgrade-checks/main.go b/packages/contracts-bedrock/scripts/checks/opcm-upgrade-checks/main.go deleted file mode 100644 index da3d257c651..00000000000 --- a/packages/contracts-bedrock/scripts/checks/opcm-upgrade-checks/main.go +++ /dev/null @@ -1,351 +0,0 @@ -package main - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/ethereum-optimism/optimism/op-chain-ops/solc" - "github.com/ethereum-optimism/optimism/packages/contracts-bedrock/scripts/checks/common" -) - -var OPCM_ARTIFACT_PATH = "forge-artifacts/OPContractsManager.sol/OPContractsManagerUpgrader.json" - -type InternalUpgradeFunctionType struct { - name string - typeName string -} - -type CallType int - -const ( - NOT_FOUND CallType = iota - UPGRADE_EXTERNAL_CALL - UPGRADE_INTERNAL_CALL -) - -func main() { - // Assert that the OPCM_BASE's upgradeToAndCall function has a call from IProxyAdmin.upgradeAndCall. - res, err := assertOPCMBaseInternalUpgradeFunctionCallUpgrade("contract IProxyAdmin", "OPContractsManagerBase") - if !res { - fmt.Printf("error: %v\n", err) - os.Exit(1) - } - - // Process. - if _, err := common.ProcessFilesGlob( - []string{"forge-artifacts/**/*.json"}, - []string{"forge-artifacts/OPContractsManager.sol/*.json", "forge-artifacts/OPContractsManagerV2.sol/*.json", "forge-artifacts/OPContractsManagerUtils.sol/*.json", "forge-artifacts/opcm/**/*.json"}, - processFile, - ); err != nil { - fmt.Printf("error: %v\n", err) - os.Exit(1) - } -} - -func assertOPCMBaseInternalUpgradeFunctionCallUpgrade(upgraderContractTypeName string, upgradeContractsName string) (bool, error) { - // First, get the OPCM's artifact. - opcmArtifact, err := common.ReadForgeArtifact(OPCM_ARTIFACT_PATH) - if err != nil { - return false, fmt.Errorf("error: %w", err) - } - - // Then get the OPCM Base's upgradeToAndCall internal functions AST. - opcmBaseUpgradeToAndCallAst := solc.AstNode{} - for _, node := range opcmArtifact.Ast.Nodes { - if node.NodeType == "ContractDefinition" && node.Name == upgradeContractsName { - for _, node := range node.Nodes { - if node.NodeType == "FunctionDefinition" && node.Name == "upgradeToAndCall" && node.Visibility == "internal" && len(node.Parameters.Parameters) == 4 { - opcmBaseUpgradeToAndCallAst = node - break - } - } - } - } - if opcmBaseUpgradeToAndCallAst.NodeType == "" { - return false, fmt.Errorf("%v's upgradeToAndCall internal function not found", upgradeContractsName) - } - - // Next, ensure that a call to IProxyAdmin.upgradeAndCall is found in the OPCM's upgradeToAndCall function. - found := upgradesContract(opcmBaseUpgradeToAndCallAst.Body.Statements, "upgradeAndCall", upgraderContractTypeName, InternalUpgradeFunctionType{}) - if found == UPGRADE_EXTERNAL_CALL { - return true, nil - } - - return false, fmt.Errorf("%v's upgradeToAndCall internal function does not have a call from IProxyAdmin.upgradeAndCall", upgradeContractsName) -} - -func processFile(artifactPath string) (*common.Void, []error) { - // Get the artifact. - artifact, err := common.ReadForgeArtifact(artifactPath) - if err != nil { - return nil, []error{err} - } - - // If the absolute path is not src/L1, return early. - if !strings.HasPrefix(artifact.Ast.AbsolutePath, "src/L1") { - return nil, nil - } - - // Find if it contains any upgrade function - numOfUpgradeFunctions := getNumberOfUpgradeFunctions(artifact) - - // If there are no upgrade functions, return early. - if numOfUpgradeFunctions == 0 { - return nil, nil - } - - // If there are more than 1 upgrade functions, return an error. - if numOfUpgradeFunctions > 1 { - return nil, []error{fmt.Errorf("expected 0 or 1 upgrade function, found %v", numOfUpgradeFunctions)} - } - - // Get OPCM's AST. - opcmAst, err := common.ReadForgeArtifact(OPCM_ARTIFACT_PATH) - if err != nil { - return nil, []error{err} - } - - // Check that there is a call to contract.upgrade. - contractName := strings.Split(filepath.Base(artifactPath), ".")[0] - typeName := "contract I" + contractName - - var callType CallType - if contractName == "SuperchainConfig" { - // Get the AST of OPCM's upgradeSuperchainConfig function. - opcmUpgradeSuperchainConfigAst, err := getOpcmUpgradeFunctionAst(opcmAst, "upgradeSuperchainConfig") - if err != nil { - return nil, []error{err} - } - - callType = upgradesContract(opcmUpgradeSuperchainConfigAst.Body.Statements, "upgrade", typeName, InternalUpgradeFunctionType{ - name: "upgradeToAndCall", - typeName: "function (contract IProxyAdmin,address,address,bytes memory)", - }) - } else { - // Get the AST of OPCM's upgrade function. - opcmUpgradeAst, err := getOpcmUpgradeFunctionAst(opcmAst, "_doChainUpgrade") - if err != nil { - return nil, []error{err} - } - - callType = upgradesContract(opcmUpgradeAst.Body.Statements, "upgrade", typeName, InternalUpgradeFunctionType{ - name: "upgradeToAndCall", - typeName: "function (contract IProxyAdmin,address,address,bytes memory)", - }) - } - - if callType == NOT_FOUND { - return nil, []error{fmt.Errorf("OPCM upgrade function does not call %v.upgrade", contractName)} - } - - return nil, nil -} - -// We want to ensure that: -// - Top level external upgrade calls call e.g `IContract.upgrade(...)` and -// Internal ones called via `upgradeToAndCall(param: IProxyAdmin, address(param: IContract), param: address, abi.encodeCall(IContract.upgrade, (...)))` can be identified -// - External upgrade calls within in a block i.e `{ }` can be identified -// - External upgrade calls within a for, while, do loop can be identified -// - External upgrade calls within the true/false block of if/else-if/else statements can be identified -// - External upgrade calls within a try or catch path -// - External upgrade calls within the true/false block of ternary statements can be identified -// - Any combination of the aforementioned can be identified -func upgradesContract(opcmUpgradeAst []solc.AstNode, expectedExternalCallName string, typeName string, internalFunctionTypes InternalUpgradeFunctionType) CallType { - // Loop through all statements finding any external call to an upgrade function with a contract type of `typeName` - for _, node := range opcmUpgradeAst { - // To support nested statements or blocks. - if node.Statements != nil { - found := upgradesContract(*node.Statements, expectedExternalCallName, typeName, internalFunctionTypes) - if found != NOT_FOUND { - return found - } - } - - // For if / else-if / else statements - if node.TrueBody != nil { - found := upgradesContract([]solc.AstNode{*node.TrueBody}, expectedExternalCallName, typeName, internalFunctionTypes) - if found != NOT_FOUND { - return found - } - } - if node.FalseBody != nil { - found := upgradesContract([]solc.AstNode{*node.FalseBody}, expectedExternalCallName, typeName, internalFunctionTypes) - if found != NOT_FOUND { - return found - } - } - - // For tenary statement - if node.Expression != nil && node.Expression.NodeType == "Conditional" { - if node.Expression.TrueExpression != nil { - found := upgradesContract([]solc.AstNode{*node.Expression.TrueExpression}, expectedExternalCallName, typeName, internalFunctionTypes) - if found != NOT_FOUND { - return found - } - } - if node.Expression.FalseExpression != nil { - found := upgradesContract([]solc.AstNode{*node.Expression.FalseExpression}, expectedExternalCallName, typeName, internalFunctionTypes) - if found != NOT_FOUND { - return found - } - } - } - - // For nested tenary statement - if node.TrueExpression != nil { - found := upgradesContract([]solc.AstNode{*node.TrueExpression}, expectedExternalCallName, typeName, internalFunctionTypes) - if found != NOT_FOUND { - return found - } - } - if node.FalseExpression != nil { - found := upgradesContract([]solc.AstNode{*node.FalseExpression}, expectedExternalCallName, typeName, internalFunctionTypes) - if found != NOT_FOUND { - return found - } - } - - // To support loops. - if node.Body != nil && node.Body.Statements != nil { - found := upgradesContract(node.Body.Statements, expectedExternalCallName, typeName, internalFunctionTypes) - if found != NOT_FOUND { - return found - } - } - - // To support try/catch blocks. - // Try part - if node.NodeType == "TryStatement" && node.ExternalCall != nil { - found := upgradesContract([]solc.AstNode{*node.ExternalCall}, expectedExternalCallName, typeName, internalFunctionTypes) - if found != NOT_FOUND { - return found - } - } - // Catch part - if node.Clauses != nil { - for _, clause := range node.Clauses { - if clause.Block != nil && clause.Block.Statements != nil { - found := upgradesContract(clause.Block.Statements, expectedExternalCallName, typeName, internalFunctionTypes) - if found != NOT_FOUND { - return found - } - } - } - } - - // If not nested, check if the statement is an external call to an upgrade function with a contract type of `typeName` - if node.NodeType == "ExpressionStatement" { - if identifyValidExternalUpgradeCall(node.Expression.Expression, expectedExternalCallName, typeName) { - return UPGRADE_EXTERNAL_CALL - } - } - - // To support try external calls and external calls within tenary statements. - if node.NodeType == "FunctionCall" { - if identifyValidExternalUpgradeCall(node.Expression, expectedExternalCallName, typeName) { - return UPGRADE_EXTERNAL_CALL - } - } - - // To support internal upgrade functions. - if node.NodeType == "ExpressionStatement" { - if identifyValidInternalUpgradeCall(node.Expression, internalFunctionTypes, typeName) { - return UPGRADE_INTERNAL_CALL - } - } - - // To support internal upgrade function calls within tenary statements. - if node.NodeType == "FunctionCall" { - // cast node into an expression-like type with relevant fields that we need - expression := solc.Expression{ - Expression: node.Expression, - Arguments: node.Arguments, - } - if identifyValidInternalUpgradeCall(&expression, internalFunctionTypes, typeName) { - return UPGRADE_INTERNAL_CALL - } - } - } - - // Else return false. - return NOT_FOUND -} - -func identifyValidExternalUpgradeCall(expression *solc.Expression, expectedExternalCallName string, typeName string) bool { - // To support external upgrade calls. - if expression != nil && expression.Expression != nil { - if expression.MemberName == expectedExternalCallName && expression.Expression.TypeDescriptions.TypeString == typeName { - return true - } - } - - return false -} - -func identifyValidInternalUpgradeCall(expression *solc.Expression, internalFunctionTypes InternalUpgradeFunctionType, typeName string) bool { - // To support internal upgrade functions. - if expression != nil && expression.Expression != nil { - if expression.Expression.Name == internalFunctionTypes.name && expression.Expression.TypeDescriptions.TypeString == internalFunctionTypes.typeName { - // Assert that the second argument is of type `typeName` that was cast (within the argument list) into an address - if expression.Arguments[1].Arguments[0].TypeDescriptions.TypeString == typeName { - // Assert that the fourth argument is of type `abi.encodeCall(IContract.upgrade, (...))` - expectedTypeString := "type(" + typeName + ")" - if expression.Arguments[3].Arguments[0].Expression.TypeDescriptions.TypeString == expectedTypeString && - expression.Arguments[3].Arguments[0].MemberName == "upgrade" && - expression.Arguments[3].Expression.Expression.Name == "abi" && - expression.Arguments[3].Expression.MemberName == "encodeCall" { - // If all of the above passes, return true - return true - } - } - } - } - - return false -} - -// Get the AST of OPCM's upgrade function. -// Returns an error if zero or more than one external upgrade function is found. -func getOpcmUpgradeFunctionAst(opcmArtifact *solc.ForgeArtifact, upgradeFunctionName string) (*solc.AstNode, error) { - opcmUpgradeFunctions := []solc.AstNode{} - for _, astNode := range opcmArtifact.Ast.Nodes { - if astNode.NodeType == "ContractDefinition" && astNode.Name == "OPContractsManagerUpgrader" { - for _, node := range astNode.Nodes { - if node.NodeType == "FunctionDefinition" && - node.Name == upgradeFunctionName { - opcmUpgradeFunctions = append(opcmUpgradeFunctions, node) - } - } - } - } - - if len(opcmUpgradeFunctions) == 0 { - return nil, fmt.Errorf("no external %s function found in OPContractsManagerUpgrader", upgradeFunctionName) - } - - if len(opcmUpgradeFunctions) > 1 { - return nil, fmt.Errorf("multiple external %s functions found in OPContractsManagerUpgrader, expected 1", upgradeFunctionName) - } - - return &opcmUpgradeFunctions[0], nil -} - -// Get the number of upgrade functions from the input artifact. -func getNumberOfUpgradeFunctions(artifact *solc.ForgeArtifact) int { - upgradeFunctions := []solc.AstNode{} - for _, astNode := range artifact.Ast.Nodes { - if astNode.NodeType == "ContractDefinition" { - for _, node := range astNode.Nodes { - if node.NodeType == "FunctionDefinition" && - node.Name == "upgrade" && - (node.Visibility == "external" || node.Visibility == "public") { - upgradeFunctions = append(upgradeFunctions, node) - } - } - } - } - - return len(upgradeFunctions) -} diff --git a/packages/contracts-bedrock/scripts/checks/opcm-upgrade-checks/main_test.go b/packages/contracts-bedrock/scripts/checks/opcm-upgrade-checks/main_test.go deleted file mode 100644 index b7b7ef16bea..00000000000 --- a/packages/contracts-bedrock/scripts/checks/opcm-upgrade-checks/main_test.go +++ /dev/null @@ -1,388 +0,0 @@ -package main - -import ( - "testing" - - "github.com/ethereum-optimism/optimism/op-chain-ops/solc" - "github.com/ethereum-optimism/optimism/packages/contracts-bedrock/scripts/checks/common" - "github.com/stretchr/testify/assert" -) - -func TestGetOpcmUpgradeFunctionAst(t *testing.T) { - tests := []struct { - name string - opcmArtifact *solc.ForgeArtifact - upgradeFunctionName string - expectedAst *solc.AstNode - expectedError string - }{ - { - name: "With one _doChainUpgrade function", - opcmArtifact: &solc.ForgeArtifact{ - Ast: solc.Ast{ - Nodes: []solc.AstNode{ - { - NodeType: "ContractDefinition", - Nodes: []solc.AstNode{ - { - NodeType: "FunctionDefinition", - Name: "_doChainUpgrade", - Visibility: "external", - Nodes: []solc.AstNode{ - { - NodeType: "UniqueNonExistentNodeType", - }, - }, - }, - }, - Name: "OPContractsManagerUpgrader", - }, - }, - }, - }, - upgradeFunctionName: "_doChainUpgrade", - expectedAst: &solc.AstNode{ - NodeType: "FunctionDefinition", - Name: "_doChainUpgrade", - Visibility: "external", - Nodes: []solc.AstNode{ - { - NodeType: "UniqueNonExistentNodeType", - }, - }, - }, - expectedError: "", - }, - { - name: "With a _doChainUpgrade function but public visibility", - opcmArtifact: &solc.ForgeArtifact{ - Ast: solc.Ast{ - Nodes: []solc.AstNode{ - { - NodeType: "ContractDefinition", - Nodes: []solc.AstNode{ - { - NodeType: "FunctionDefinition", - Name: "_doChainUpgrade", - Visibility: "public", - }, - }, - Name: "OPContractsManagerUpgrader", - }, - }, - }, - }, - upgradeFunctionName: "_doChainUpgrade", - expectedAst: &solc.AstNode{ - NodeType: "FunctionDefinition", - Name: "_doChainUpgrade", - Visibility: "public", - }, - expectedError: "", - }, - { - name: "With a _doChainUpgrade function and irrelevant function selector", - opcmArtifact: &solc.ForgeArtifact{ - Ast: solc.Ast{ - Nodes: []solc.AstNode{ - { - NodeType: "ContractDefinition", - Nodes: []solc.AstNode{ - { - NodeType: "FunctionDefinition", - Name: "_doChainUpgrade", - Visibility: "external", - FunctionSelector: "aabbccdd", - Nodes: []solc.AstNode{ - { - NodeType: "UniqueNonExistentNodeType", - }, - }, - }, - }, - Name: "OPContractsManagerUpgrader", - }, - }, - }, - }, - upgradeFunctionName: "_doChainUpgrade", - expectedAst: &solc.AstNode{ - NodeType: "FunctionDefinition", - Name: "_doChainUpgrade", - Visibility: "external", - FunctionSelector: "aabbccdd", - Nodes: []solc.AstNode{ - { - NodeType: "UniqueNonExistentNodeType", - }, - }, - }, - expectedError: "", - }, - { - name: "With multiple _doChainUpgrade functions", - opcmArtifact: &solc.ForgeArtifact{ - Ast: solc.Ast{ - Nodes: []solc.AstNode{ - { - NodeType: "ContractDefinition", - Nodes: []solc.AstNode{ - { - NodeType: "FunctionDefinition", - Name: "_doChainUpgrade", - Visibility: "external", - }, - { - NodeType: "FunctionDefinition", - Name: "_doChainUpgrade", - Visibility: "external", - }, - }, - Name: "OPContractsManagerUpgrader", - }, - }, - }, - }, - upgradeFunctionName: "_doChainUpgrade", - expectedAst: nil, - expectedError: "multiple external _doChainUpgrade functions found in OPContractsManagerUpgrader, expected 1", - }, - { - name: "With no _doChainUpgrade function", - opcmArtifact: &solc.ForgeArtifact{ - Ast: solc.Ast{ - Nodes: []solc.AstNode{ - { - NodeType: "ContractDefinition", - Nodes: []solc.AstNode{ - { - NodeType: "FunctionDefinition", - Name: "randomFunctionName", - Visibility: "external", - Nodes: []solc.AstNode{ - { - NodeType: "UniqueNonExistentNodeType", - }, - }, - }, - }, - Name: "OPContractsManagerUpgrader", - }, - }, - }, - }, - upgradeFunctionName: "_doChainUpgrade", - expectedAst: nil, - expectedError: "no external _doChainUpgrade function found in OPContractsManagerUpgrader", - }, - { - name: "With no contract definition", - opcmArtifact: &solc.ForgeArtifact{ - Ast: solc.Ast{ - Nodes: []solc.AstNode{}, - }, - }, - upgradeFunctionName: "_doChainUpgrade", - expectedAst: nil, - expectedError: "no external _doChainUpgrade function found in OPContractsManagerUpgrader", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - ast, err := getOpcmUpgradeFunctionAst(test.opcmArtifact, test.upgradeFunctionName) - - if test.expectedError == "" { - assert.NoError(t, err) - assert.Equal(t, test.expectedAst, ast) - } else { - assert.Error(t, err) - assert.Nil(t, ast) - if err != nil { - assert.Equal(t, test.expectedError, err.Error()) - } - } - }) - } -} - -func TestGetNumberOfUpgradeFunctions(t *testing.T) { - tests := []struct { - name string - artifact *solc.ForgeArtifact - expectedNum int - }{ - { - name: "With an external upgrade function", - artifact: &solc.ForgeArtifact{ - Ast: solc.Ast{ - Nodes: []solc.AstNode{ - { - NodeType: "ContractDefinition", - Nodes: []solc.AstNode{ - { - NodeType: "FunctionDefinition", - Name: "upgrade", - Visibility: "external", - }, - }, - }, - }, - }, - }, - expectedNum: 1, - }, - { - name: "With a public upgrade function", - artifact: &solc.ForgeArtifact{ - Ast: solc.Ast{ - Nodes: []solc.AstNode{ - { - NodeType: "ContractDefinition", - Nodes: []solc.AstNode{ - { - NodeType: "FunctionDefinition", - Name: "upgrade", - Visibility: "public", - }, - }, - }, - }, - }, - }, - expectedNum: 1, - }, - { - name: "With multiple upgrade functions", - artifact: &solc.ForgeArtifact{ - Ast: solc.Ast{ - Nodes: []solc.AstNode{ - { - NodeType: "ContractDefinition", - Nodes: []solc.AstNode{ - { - NodeType: "FunctionDefinition", - Name: "upgrade", - Visibility: "external", - }, - }, - }, - { - NodeType: "ContractDefinition", - Nodes: []solc.AstNode{ - { - NodeType: "FunctionDefinition", - Name: "upgrade", - Visibility: "public", - }, - }, - }, - }, - }, - }, - expectedNum: 2, - }, - { - name: "With no upgrade functions", - artifact: &solc.ForgeArtifact{ - Ast: solc.Ast{ - Nodes: []solc.AstNode{}, - }, - }, - expectedNum: 0, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - num := getNumberOfUpgradeFunctions(test.artifact) - assert.Equal(t, test.expectedNum, num) - }) - } -} - -func TestUpgradesContract(t *testing.T) { - // To add tests for this, create a contract with one or a combination of solidity statements and an optional upgrade function call within it to a contract type of IUpgradeable. - // Then create a constant bool variable EXPECTED_OUTPUT and set it to true if the upgrade function call is expected to be found and false otherwise. - // See opcm_upgrade_checks_mocks.sol for already existing mock contracts used for testing. - - artifact, err := common.ReadForgeArtifact("../../../forge-artifacts/OPCMUpgradeChecksMocks.sol/IUpgradeable.json") - if err != nil { - t.Fatalf("Failed to load artifact: %v", err) - } - - type test struct { - name string - upgradeAst []solc.AstNode - typeName string - internalUpgradeFunctionTypeStrings InternalUpgradeFunctionType - expectedOutput CallType - } - - tests := []test{} - - for _, node := range artifact.Ast.Nodes { - if node.NodeType == "ContractDefinition" && node.Name != "IUpgradeable" && node.Name != "InternalUpgradeFunction" { - upgradeAst := solc.AstNode{} - expectedOutput := NOT_FOUND - for _, astNode := range node.Nodes { - if astNode.NodeType == "FunctionDefinition" && astNode.Name == "upgrade" { - if upgradeAst.NodeType != "" { - t.Fatalf("Expected only one upgrade function") - } - upgradeAst = astNode - } - - if astNode.NodeType == "VariableDeclaration" && - astNode.Name == "EXPECTED_OUTPUT" && - astNode.Mutability == "constant" { - - value, ok := astNode.Value.(map[string]interface{}) - if !ok { - t.Fatalf("Expected value to be a map: %v", astNode.Value) - } - - typeDescriptions, ok := value["typeDescriptions"].(map[string]interface{}) - if !ok { - t.Fatalf("Expected typeDescriptions to be a map: %v", value) - } - if typeDescriptions["typeString"] != "uint8" { - t.Fatalf("Expected the typeString to be uint8: %v", value) - } - - name, ok := value["name"].(string) - if !ok { - t.Fatalf("Expected name to be a string: %v", value) - } - if name == "NOT_FOUND" { - expectedOutput = NOT_FOUND - } else if name == "UPGRADE_EXTERNAL_CALL" { - expectedOutput = UPGRADE_EXTERNAL_CALL - } else if name == "UPGRADE_INTERNAL_CALL" { - expectedOutput = UPGRADE_INTERNAL_CALL - } else { - t.Fatalf("Expected output is not a boolean: %s", astNode.Value) - } - } - } - - tests = append(tests, test{ - name: node.Name, - upgradeAst: []solc.AstNode{upgradeAst}, - typeName: "contract IUpgradeable", - internalUpgradeFunctionTypeStrings: InternalUpgradeFunctionType{ - name: "upgradeToAndCall", - typeName: "function (contract IUpgradeable,address,address,bytes memory)", - }, - expectedOutput: expectedOutput, - }) - } - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - output := upgradesContract(test.upgradeAst, "upgrade", test.typeName, test.internalUpgradeFunctionTypeStrings) - assert.Equal(t, test.expectedOutput, output) - }) - } -} diff --git a/packages/contracts-bedrock/scripts/checks/test-validation/exclusions.toml b/packages/contracts-bedrock/scripts/checks/test-validation/exclusions.toml index 0208a3ed8bc..fb3d5e09a7a 100644 --- a/packages/contracts-bedrock/scripts/checks/test-validation/exclusions.toml +++ b/packages/contracts-bedrock/scripts/checks/test-validation/exclusions.toml @@ -59,7 +59,6 @@ contract_name_validation = [ "test/L2/CrossDomainOwnable3.t.sol", # Contains contracts not matching CrossDomainOwnable3 base name "test/L2/GasPriceOracle.t.sol", # Contains contracts not matching GasPriceOracle base name "test/universal/StandardBridge.t.sol", # Contains contracts not matching StandardBridge base name - "test/L1/OPContractsManagerContractsContainer.t.sol", # Contains contracts not matching OPContractsManagerContractsContainer base name "test/L2/RevenueSharingIntegration.t.sol", # Contains contracts not matching RevenueSharingIntegration base name "test/libraries/Blueprint.t.sol", # Contains helper contracts (BlueprintHarness, ConstructorArgMock) "test/libraries/SafeCall.t.sol", # Contains helper contracts (SimpleSafeCaller) diff --git a/packages/contracts-bedrock/scripts/checks/valid-semver-check/main.go b/packages/contracts-bedrock/scripts/checks/valid-semver-check/main.go index 119fa6c3c8a..45906edb121 100644 --- a/packages/contracts-bedrock/scripts/checks/valid-semver-check/main.go +++ b/packages/contracts-bedrock/scripts/checks/valid-semver-check/main.go @@ -13,7 +13,7 @@ import ( func main() { if _, err := common.ProcessFilesGlob( []string{"forge-artifacts/**/*.json"}, - []string{"forge-artifacts/L2StandardBridgeInterop.sol/**.json", "forge-artifacts/OptimismPortalInterop.sol/**.json", "forge-artifacts/EAS.sol/**.json", "forge-artifacts/SchemaRegistry.sol/**.json", "forge-artifacts/L1BlockCGT.sol/**.json", "forge-artifacts/L2ToL1MessagePasserCGT.sol/**.json"}, + []string{"forge-artifacts/L2StandardBridgeInterop.sol/**.json", "forge-artifacts/EAS.sol/**.json", "forge-artifacts/SchemaRegistry.sol/**.json", "forge-artifacts/L1BlockCGT.sol/**.json", "forge-artifacts/L2ToL1MessagePasserCGT.sol/**.json"}, processFile, ); err != nil { fmt.Printf("Error: %v/n", err) diff --git a/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol b/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol deleted file mode 100644 index 42bcf189fbf..00000000000 --- a/packages/contracts-bedrock/scripts/deploy/AddGameType.s.sol +++ /dev/null @@ -1,101 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.15; - -// Forge -import { Script } from "forge-std/Script.sol"; - -// Scripts -import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; -import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; - -// Interfaces -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; -import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; -import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; -import { IBigStepper } from "interfaces/dispute/IBigStepper.sol"; -import { GameType, Duration, Claim } from "src/dispute/lib/Types.sol"; -import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; - -/// @title AddGameType -/// @notice This script is used to add a new game type to the chain using the OPContractsManager V1. -/// Support for OPCM v2 is provided through the UpgradeOPChain script. -contract AddGameType is Script { - struct Input { - // Address that will be used for the DummyCaller contract - address prank; - // OPCM contract address - IOPContractsManager opcmImpl; - // SystemConfig contract address - ISystemConfig systemConfigProxy; - // DelayedWETH contract address (optional) - IDelayedWETH delayedWETHProxy; - // Game type to add - GameType disputeGameType; - // Absolute prestate for the game - Claim disputeAbsolutePrestate; - // Maximum game depth - uint256 disputeMaxGameDepth; - // Split depth for the game - uint256 disputeSplitDepth; - // Clock extension duration - Duration disputeClockExtension; - // Maximum clock duration - Duration disputeMaxClockDuration; - // Initial bond amount - uint256 initialBond; - // VM contract address - IBigStepper vm; - // Whether this is a permissioned game - bool permissioned; - // Salt mixer for deterministic addresses - string saltMixer; - } - - struct Output { - IDelayedWETH delayedWETHProxy; - IFaultDisputeGame faultDisputeGameProxy; - } - - function run(Input memory _agi) public returns (Output memory) { - // Etch DummyCaller contract. This contract is used to mimic the contract that is used - // as the source of the delegatecall to the OPCM. In practice this will be the governance - // 2/2 or similar. - address prank = _agi.prank; - - bytes memory code = type(DummyCaller).runtimeCode; - vm.etch(prank, code); - vm.store(prank, bytes32(0), bytes32(uint256(uint160(address(_agi.opcmImpl))))); - vm.label(prank, "DummyCaller"); - - // Create the game input - IOPContractsManager.AddGameInput[] memory gameConfigs = new IOPContractsManager.AddGameInput[](1); - gameConfigs[0] = IOPContractsManager.AddGameInput({ - saltMixer: _agi.saltMixer, - systemConfig: _agi.systemConfigProxy, - delayedWETH: _agi.delayedWETHProxy, - disputeGameType: _agi.disputeGameType, - disputeAbsolutePrestate: _agi.disputeAbsolutePrestate, - disputeMaxGameDepth: _agi.disputeMaxGameDepth, - disputeSplitDepth: _agi.disputeSplitDepth, - disputeClockExtension: _agi.disputeClockExtension, - disputeMaxClockDuration: _agi.disputeMaxClockDuration, - initialBond: _agi.initialBond, - vm: _agi.vm, - permissioned: _agi.permissioned - }); - - // Call into the DummyCaller to perform the delegatecall. - // The DummyCaller uses a fallback that reverts on failure, so no need to check success. - vm.broadcast(msg.sender); - IOPContractsManager.AddGameOutput[] memory outputs = IOPContractsManager(prank).addGameType(gameConfigs); - - // Decode the result and set it in the output - require(outputs.length == 1, "AddGameType: unexpected number of outputs"); - return Output({ delayedWETHProxy: outputs[0].delayedWETH, faultDisputeGameProxy: outputs[0].faultDisputeGame }); - } - - function checkOutput(Output memory _ago) internal view { - DeployUtils.assertValidContractAddress(address(_ago.delayedWETHProxy)); - DeployUtils.assertValidContractAddress(address(_ago.faultDisputeGameProxy)); - } -} diff --git a/packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol b/packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol index 1bc01bd8c65..d06bcdeeac6 100644 --- a/packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol +++ b/packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol @@ -16,10 +16,9 @@ import { Types } from "scripts/libraries/Types.sol"; import { Blueprint } from "src/libraries/Blueprint.sol"; import { GameType, GameTypes } from "src/dispute/lib/Types.sol"; import { Hash } from "src/dispute/lib/Types.sol"; -import { DevFeatures } from "src/libraries/DevFeatures.sol"; - // Interfaces -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; +import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; +import { IOPContractsManagerContainer } from "interfaces/L1/opcm/IOPContractsManagerContainer.sol"; import { IResourceMetering } from "interfaces/L1/IResourceMetering.sol"; import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; @@ -112,19 +111,12 @@ library ChainAssertions { require(config.scalar() >> 248 == 1, "CHECK-SCFG-70"); // Depends on start block being set to 0 in `initialize` require(config.startBlock() == block.number, "CHECK-SCFG-140"); - if (IOPContractsManager(_doi.opcm).isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - require( - config.batchInbox() - == IOPContractsManagerUtils(IOPContractsManagerV2(address(_doi.opcm)).opcmUtils()) - .chainIdToBatchInboxAddress(_doi.l2ChainId), - "CHECK-SCFG-150" - ); - } else { - require( - config.batchInbox() == IOPContractsManager(_doi.opcm).chainIdToBatchInboxAddress(_doi.l2ChainId), - "CHECK-SCFG-150" - ); - } + require( + config.batchInbox() + == IOPContractsManagerUtils(IOPContractsManagerV2(address(_doi.opcm)).opcmUtils()) + .chainIdToBatchInboxAddress(_doi.l2ChainId), + "CHECK-SCFG-150" + ); // Check _addresses require(config.l1CrossDomainMessenger() == _contracts.L1CrossDomainMessenger, "CHECK-SCFG-160"); require(config.l1ERC721Bridge() == _contracts.L1ERC721Bridge, "CHECK-SCFG-170"); @@ -385,8 +377,7 @@ library ChainAssertions { /// @notice Asserts that the OPContractsManager is setup correctly function checkOPContractsManager( Types.ContractSet memory _impls, - Types.ContractSet memory _proxies, - IOPContractsManager _opcm, + IOPContractsManagerV2 _opcm, IMIPS64 _mips ) internal @@ -396,12 +387,8 @@ library ChainAssertions { require(address(_opcm) != address(0), "CHECK-OPCM-10"); require(bytes(_opcm.version()).length > 0, "CHECK-OPCM-15"); - if (!_opcm.isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - require(address(_opcm.protocolVersions()) == _proxies.ProtocolVersions, "CHECK-OPCM-17"); - require(address(_opcm.superchainConfig()) == _proxies.SuperchainConfig, "CHECK-OPCM-19"); - } // Ensure that the OPCM impls are correctly saved - IOPContractsManager.Implementations memory impls = _opcm.implementations(); + IOPContractsManagerContainer.Implementations memory impls = _opcm.implementations(); require(impls.l1ERC721BridgeImpl == _impls.L1ERC721Bridge, "CHECK-OPCM-50"); require(impls.optimismPortalImpl == _impls.OptimismPortal, "CHECK-OPCM-60"); require(impls.systemConfigImpl == _impls.SystemConfig, "CHECK-OPCM-70"); @@ -415,7 +402,7 @@ library ChainAssertions { require(impls.protocolVersionsImpl == _impls.ProtocolVersions, "CHECK-OPCM-150"); // Verify that initCode is correctly set into the blueprints - IOPContractsManager.Blueprints memory blueprints = _opcm.blueprints(); + IOPContractsManagerContainer.Blueprints memory blueprints = _opcm.blueprints(); Blueprint.Preamble memory addressManagerPreamble = Blueprint.parseBlueprintPreamble(address(blueprints.addressManager).code); require( diff --git a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol index a40e583817c..fa53fd43050 100644 --- a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol @@ -21,13 +21,11 @@ import { StandardConstants } from "scripts/deploy/StandardConstants.sol"; // Libraries import { Types } from "scripts/libraries/Types.sol"; -import { Duration } from "src/dispute/lib/LibUDT.sol"; import { GameType, Claim, GameTypes, Proposal, Hash } from "src/dispute/lib/Types.sol"; import { Constants } from "src/libraries/Constants.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; // Interfaces -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; import { IProxy } from "interfaces/universal/IProxy.sol"; @@ -178,11 +176,7 @@ contract Deploy is Deployer { deployImplementations(); // Deploy Current OPChain Contracts - if (!DevFeatures.isDevFeatureEnabled(cfg.devFeatureBitmap(), DevFeatures.OPCM_V2)) { - deployOpChain(); - } else { - deployOpChainV2(); - } + deployOpChainV2(); // Set the respected game type according to the deploy config vm.startPrank(ISuperchainConfig(artifacts.mustGetAddress("SuperchainConfigProxy")).guardian()); @@ -298,11 +292,7 @@ contract Deploy is Deployer { // Save the implementation addresses which are needed outside of this function or script. // When called in a fork test, this will overwrite the existing implementations. artifacts.save("MipsSingleton", address(dio.mipsSingleton)); - if (DevFeatures.isDevFeatureEnabled(cfg.devFeatureBitmap(), DevFeatures.OPCM_V2)) { - artifacts.save("OPContractsManagerV2", address(dio.opcmV2)); - } else { - artifacts.save("OPContractsManager", address(dio.opcm)); - } + artifacts.save("OPContractsManagerV2", address(dio.opcmV2)); artifacts.save("DelayedWETHImpl", address(dio.delayedWETHImpl)); artifacts.save("PreimageOracle", address(dio.preimageOracleSingleton)); artifacts.save("PermissionedDisputeGame", address(dio.permissionedDisputeGameImpl)); @@ -336,16 +326,9 @@ contract Deploy is Deployer { _mips: IMIPS64(address(dio.mipsSingleton)), _oracle: IPreimageOracle(address(dio.preimageOracleSingleton)) }); - IOPContractsManager _opcm; - if (DevFeatures.isDevFeatureEnabled(cfg.devFeatureBitmap(), DevFeatures.OPCM_V2)) { - _opcm = IOPContractsManager(address(dio.opcmV2)); - } else { - _opcm = IOPContractsManager(address(dio.opcm)); - } ChainAssertions.checkOPContractsManager({ _impls: impls, - _proxies: _proxies(), - _opcm: _opcm, + _opcm: IOPContractsManagerV2(address(dio.opcmV2)), _mips: IMIPS64(address(dio.mipsSingleton)) }); ChainAssertions.checkSystemConfigImpls(impls); @@ -353,57 +336,6 @@ contract Deploy is Deployer { } /// @notice Deploy all of the OP Chain specific contracts - function deployOpChain() public { - console.log("Deploying OP Chain"); - - // Ensure that the requisite contracts are deployed - IOPContractsManager opcm = IOPContractsManager(artifacts.mustGetAddress("OPContractsManager")); - - IOPContractsManager.DeployInput memory deployInput = getDeployInput(); - IOPContractsManager.DeployOutput memory deployOutput = opcm.deploy(deployInput); - - // Store code in the Final system owner address so that it can be used for prank delegatecalls - // Store "fe" opcode so that accidental calls to this address revert - vm.etch(cfg.finalSystemOwner(), hex"fe"); - - // Save all deploy outputs from the OPCM, in the order they are declared in the DeployOutput struct - artifacts.save("ProxyAdmin", address(deployOutput.opChainProxyAdmin)); - artifacts.save("AddressManager", address(deployOutput.addressManager)); - artifacts.save("L1ERC721BridgeProxy", address(deployOutput.l1ERC721BridgeProxy)); - artifacts.save("SystemConfigProxy", address(deployOutput.systemConfigProxy)); - artifacts.save("OptimismMintableERC20FactoryProxy", address(deployOutput.optimismMintableERC20FactoryProxy)); - artifacts.save("L1StandardBridgeProxy", address(deployOutput.l1StandardBridgeProxy)); - artifacts.save("L1CrossDomainMessengerProxy", address(deployOutput.l1CrossDomainMessengerProxy)); - artifacts.save("ETHLockboxProxy", address(deployOutput.ethLockboxProxy)); - - // Fault Proof contracts - artifacts.save("DisputeGameFactoryProxy", address(deployOutput.disputeGameFactoryProxy)); - artifacts.save("PermissionedDelayedWETHProxy", address(deployOutput.delayedWETHPermissionedGameProxy)); - artifacts.save("AnchorStateRegistryProxy", address(deployOutput.anchorStateRegistryProxy)); - artifacts.save("OptimismPortalProxy", address(deployOutput.optimismPortalProxy)); - artifacts.save("OptimismPortal2Proxy", address(deployOutput.optimismPortalProxy)); - - // Check if the permissionless game implementation is already set - IDisputeGameFactory factory = IDisputeGameFactory(artifacts.mustGetAddress("DisputeGameFactoryProxy")); - address permissionlessGameImpl = address(factory.gameImpls(GameTypes.CANNON)); - - // Deploy and setup the PermissionlessDelayedWeth not provided by the OPCM. - // If the following require statement is hit, you can delete the block of code after it. - require( - permissionlessGameImpl == address(0), - "Deploy: The PermissionlessDelayedWETH is already set by the OPCM, it is no longer necessary to deploy it separately." - ); - address delayedWETHImpl = artifacts.mustGetAddress("DelayedWETHImpl"); - address delayedWETHPermissionlessGameProxy = - deployERC1967ProxyWithOwner("DelayedWETHProxy", address(deployOutput.opChainProxyAdmin)); - vm.broadcast(address(deployOutput.opChainProxyAdmin)); - IProxy(payable(delayedWETHPermissionlessGameProxy)).upgradeToAndCall({ - _implementation: delayedWETHImpl, - _data: abi.encodeCall(IDelayedWETH.initialize, (deployOutput.systemConfigProxy)) - }); - } - - /// @notice Deploy all of the OP Chain specific contracts using OPCM v2 function deployOpChainV2() public { console.log("Deploying OP Chain"); @@ -467,36 +399,6 @@ contract Deploy is Deployer { addr_ = address(proxy); } - /// @notice Get the DeployInput struct to use for testing - function getDeployInput() public view returns (IOPContractsManager.DeployInput memory) { - string memory saltMixer = "salt mixer"; - return IOPContractsManager.DeployInput({ - roles: IOPContractsManager.Roles({ - opChainProxyAdminOwner: cfg.finalSystemOwner(), - systemConfigOwner: cfg.finalSystemOwner(), - batcher: cfg.batchSenderAddress(), - unsafeBlockSigner: cfg.p2pSequencerAddress(), - proposer: cfg.l2OutputOracleProposer(), - challenger: cfg.l2OutputOracleChallenger() - }), - basefeeScalar: cfg.basefeeScalar(), - blobBasefeeScalar: cfg.blobbasefeeScalar(), - l2ChainId: cfg.l2ChainID(), - startingAnchorRoot: abi.encode( - Proposal({ root: Hash.wrap(cfg.faultGameGenesisOutputRoot()), l2SequenceNumber: cfg.faultGameGenesisBlock() }) - ), - saltMixer: saltMixer, - gasLimit: uint64(cfg.l2GenesisBlockGasLimit()), - disputeGameType: GameTypes.PERMISSIONED_CANNON, - disputeAbsolutePrestate: Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate())), - disputeMaxGameDepth: cfg.faultGameMaxDepth(), - disputeSplitDepth: cfg.faultGameSplitDepth(), - disputeClockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())), - disputeMaxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())), - useCustomGasToken: cfg.useCustomGasToken() - }); - } - function getSuperRootDeployInputV2() public view returns (IOPContractsManagerV2.FullConfig memory) { IOPContractsManagerUtils.DisputeGameConfig[] memory disputeGameConfigs = new IOPContractsManagerUtils.DisputeGameConfig[](6); diff --git a/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol index 05c1adce9a9..eeffeebcf13 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol @@ -15,6 +15,9 @@ contract DeployConfig is Script { using stdJson for string; using ForkUtils for Fork; + /// @notice Thrown when a config file cannot be read at the given path. + error UnableToReadConfigFile(string path); + /// @notice Represents an unset offset value, as opposed to 0, which denotes no-offset. uint256 constant NULL_OFFSET = type(uint256).max; @@ -104,13 +107,22 @@ contract DeployConfig is Script { address public l1FeesDepositor; function read(string memory _path) public { - console.log("DeployConfig: reading file %s", _path); + // If no path provided, use hardcoded defaults only + if (bytes(_path).length == 0) { + console.log("DeployConfig: using hardcoded defaults (no config file)"); + _initDefaults(); + return; + } + + // Try to read file, revert if not found try vm.readFile(_path) returns (string memory data_) { _json = data_; + console.log("DeployConfig: reading file %s", _path); } catch { - require(false, string.concat("DeployConfig: cannot find deploy config file at ", _path)); + revert UnableToReadConfigFile(_path); } + // Read values from JSON, using _readOr with hardcoded defaults for optional fields finalSystemOwner = stdJson.readAddress(_json, "$.finalSystemOwner"); superchainConfigGuardian = stdJson.readAddress(_json, "$.superchainConfigGuardian"); l1ChainID = stdJson.readUint(_json, "$.l1ChainID"); @@ -147,12 +159,12 @@ contract DeployConfig is Script { operatorFeeVaultWithdrawalNetwork = stdJson.readUint(_json, "$.operatorFeeVaultWithdrawalNetwork"); governanceTokenOwner = stdJson.readAddress(_json, "$.governanceTokenOwner"); l2GenesisBlockGasLimit = stdJson.readUint(_json, "$.l2GenesisBlockGasLimit"); - basefeeScalar = uint32(_readOr(_json, "$.gasPriceOracleBaseFeeScalar", 1368)); - blobbasefeeScalar = uint32(_readOr(_json, "$.gasPriceOracleBlobBaseFeeScalar", 810949)); + basefeeScalar = uint32(_readOr(_json, "$.gasPriceOracleBaseFeeScalar", uint256(1368))); + blobbasefeeScalar = uint32(_readOr(_json, "$.gasPriceOracleBlobBaseFeeScalar", uint256(810949))); useCustomGasToken = _readOr(_json, "$.useCustomGasToken", false); - gasPayingTokenName = _readOr(_json, "$.gasPayingTokenName", ""); - gasPayingTokenSymbol = _readOr(_json, "$.gasPayingTokenSymbol", ""); - nativeAssetLiquidityAmount = _readOr(_json, "$.nativeAssetLiquidityAmount", 0); + gasPayingTokenName = _json.readStringOr("$.gasPayingTokenName", ""); + gasPayingTokenSymbol = _json.readStringOr("$.gasPayingTokenSymbol", ""); + nativeAssetLiquidityAmount = _readOr(_json, "$.nativeAssetLiquidityAmount", uint256(0)); liquidityControllerOwner = _readOr(_json, "$.liquidityControllerOwner", finalSystemOwner); enableGovernance = _readOr(_json, "$.enableGovernance", false); @@ -160,9 +172,9 @@ contract DeployConfig is Script { requiredProtocolVersion = stdJson.readUint(_json, "$.requiredProtocolVersion"); recommendedProtocolVersion = stdJson.readUint(_json, "$.recommendedProtocolVersion"); - proofMaturityDelaySeconds = _readOr(_json, "$.proofMaturityDelaySeconds", 0); - disputeGameFinalityDelaySeconds = _readOr(_json, "$.disputeGameFinalityDelaySeconds", 0); - respectedGameType = _readOr(_json, "$.respectedGameType", 0); + proofMaturityDelaySeconds = _readOr(_json, "$.proofMaturityDelaySeconds", uint256(0)); + disputeGameFinalityDelaySeconds = _readOr(_json, "$.disputeGameFinalityDelaySeconds", uint256(0)); + respectedGameType = _readOr(_json, "$.respectedGameType", uint256(0)); faultGameAbsolutePrestate = stdJson.readUint(_json, "$.faultGameAbsolutePrestate"); faultGameMaxDepth = stdJson.readUint(_json, "$.faultGameMaxDepth"); @@ -177,21 +189,20 @@ contract DeployConfig is Script { preimageOracleChallengePeriod = stdJson.readUint(_json, "$.preimageOracleChallengePeriod"); useAltDA = _readOr(_json, "$.useAltDA", false); - daCommitmentType = _readOr(_json, "$.daCommitmentType", "KeccakCommitment"); - daChallengeWindow = _readOr(_json, "$.daChallengeWindow", 1000); - daResolveWindow = _readOr(_json, "$.daResolveWindow", 1000); - daBondSize = _readOr(_json, "$.daBondSize", 1000000000); - daResolverRefundPercentage = _readOr(_json, "$.daResolverRefundPercentage", 0); - - devFeatureBitmap = bytes32(_readOr(_json, "$.devFeatureBitmap", 0)); - useUpgradedFork; + daCommitmentType = _json.readStringOr("$.daCommitmentType", "KeccakCommitment"); + daChallengeWindow = _readOr(_json, "$.daChallengeWindow", uint256(1000)); + daResolveWindow = _readOr(_json, "$.daResolveWindow", uint256(1000)); + daBondSize = _readOr(_json, "$.daBondSize", uint256(1000000000)); + daResolverRefundPercentage = _readOr(_json, "$.daResolverRefundPercentage", uint256(0)); + + devFeatureBitmap = bytes32(_readOr(_json, "$.devFeatureBitmap", uint256(0))); useRevenueShare = _readOr(_json, "$.useRevenueShare", false); useInterop = _readOr(_json, "$.useInterop", false); chainFeesRecipient = _readOr(_json, "$.chainFeesRecipient", address(0)); - faultGameV2MaxGameDepth = _readOr(_json, "$.faultGameV2MaxGameDepth", 73); - faultGameV2SplitDepth = _readOr(_json, "$.faultGameV2SplitDepth", 30); - faultGameV2ClockExtension = _readOr(_json, "$.faultGameV2ClockExtension", 10800); - faultGameV2MaxClockDuration = _readOr(_json, "$.faultGameV2MaxClockDuration", 302400); + faultGameV2MaxGameDepth = _readOr(_json, "$.faultGameV2MaxGameDepth", uint256(73)); + faultGameV2SplitDepth = _readOr(_json, "$.faultGameV2SplitDepth", uint256(30)); + faultGameV2ClockExtension = _readOr(_json, "$.faultGameV2ClockExtension", uint256(10800)); + faultGameV2MaxClockDuration = _readOr(_json, "$.faultGameV2MaxClockDuration", uint256(302400)); } function fork() public view returns (Fork fork_) { @@ -319,6 +330,84 @@ contract DeployConfig is Script { operatorFeeVaultWithdrawalNetwork = _operatorFeeVaultWithdrawalNetwork; } + /// @notice Initializes the config with hardcoded defaults. Used when no config file is provided + /// or when the config file is not found. These values match what was previously in hardhat.json. + function _initDefaults() internal { + finalSystemOwner = 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc; + superchainConfigGuardian = 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc; + l1ChainID = 900; + l2ChainID = 901; + l2GenesisDeltaTimeOffset = 0; + l2GenesisEcotoneTimeOffset = 0; + l2GenesisFjordTimeOffset = 0; + l2GenesisGraniteTimeOffset = 0; + l2GenesisHoloceneTimeOffset = 0; + l2GenesisJovianTimeOffset = 0; + l2GenesisKarstTimeOffset = 0; + p2pSequencerAddress = 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc; + batchInboxAddress = 0x00289C189bEE4E70334629f04Cd5eD602B6600eB; + batchSenderAddress = 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC; + _l2OutputOracleStartingTimestamp = 1; + l2OutputOracleStartingBlockNumber = 1; + l2OutputOracleProposer = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8; + l2OutputOracleChallenger = 0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A; + fundDevAccounts = true; + proxyAdminOwner = 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc; + baseFeeVaultRecipient = 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc; + baseFeeVaultMinimumWithdrawalAmount = 10 ether; + baseFeeVaultWithdrawalNetwork = 0; + l1FeeVaultRecipient = 0x71bE63f3384f5fb98995898A86B02Fb2426c5788; + l1FeeVaultMinimumWithdrawalAmount = 10 ether; + l1FeeVaultWithdrawalNetwork = 0; + sequencerFeeVaultRecipient = 0xFABB0ac9d68B0B445fB7357272Ff202C5651694a; + sequencerFeeVaultMinimumWithdrawalAmount = 10 ether; + sequencerFeeVaultWithdrawalNetwork = 0; + operatorFeeVaultRecipient = 0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec; + operatorFeeVaultMinimumWithdrawalAmount = 10 ether; + operatorFeeVaultWithdrawalNetwork = 0; + governanceTokenOwner = 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc; + l2GenesisBlockGasLimit = 25_000_000; + basefeeScalar = 1368; + blobbasefeeScalar = 810949; + enableGovernance = true; + faultGameAbsolutePrestate = 0; + faultGameGenesisBlock = 0; + faultGameGenesisOutputRoot = 0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF; + faultGameMaxDepth = 73; + faultGameSplitDepth = 30; + faultGameClockExtension = 10800; + faultGameMaxClockDuration = 302400; + faultGameWithdrawalDelay = 302400; + preimageOracleMinProposalSize = 126000; + preimageOracleChallengePeriod = 86400; + systemConfigStartBlock = 0; + requiredProtocolVersion = 1; + recommendedProtocolVersion = 1; + proofMaturityDelaySeconds = 604800; + disputeGameFinalityDelaySeconds = 302400; + respectedGameType = 0; + useAltDA = false; + daCommitmentType = "KeccakCommitment"; + daChallengeWindow = 100; + daResolveWindow = 100; + daBondSize = 1000; + daResolverRefundPercentage = 50; + useCustomGasToken = false; + gasPayingTokenName = ""; + gasPayingTokenSymbol = ""; + nativeAssetLiquidityAmount = 0; + liquidityControllerOwner = 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc; + faultGameV2MaxGameDepth = 73; + faultGameV2SplitDepth = 30; + faultGameV2ClockExtension = 10800; + faultGameV2MaxClockDuration = 302400; + useInterop = false; + useUpgradedFork = false; + devFeatureBitmap = bytes32(0); + useRevenueShare = false; + chainFeesRecipient = 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc; + } + function latestGenesisFork() internal view returns (Fork) { if (l2GenesisKarstTimeOffset == 0) { return Fork.KARST; @@ -388,4 +477,20 @@ contract DeployConfig is Script { { return _jsonInp.readStringOr(_key, _defaultValue); } + + function _readOr(string memory _jsonInp, string memory _key, int256 _defaultValue) internal view returns (int256) { + return (vm.keyExistsJson(_jsonInp, _key) && !_isNull(_json, _key)) ? _jsonInp.readInt(_key) : _defaultValue; + } + + function _readOr( + string memory _jsonInp, + string memory _key, + bytes32 _defaultValue + ) + internal + view + returns (bytes32) + { + return (vm.keyExistsJson(_jsonInp, _key) && !_isNull(_json, _key)) ? _jsonInp.readBytes32(_key) : _defaultValue; + } } diff --git a/packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol index d2d2273011a..2b06b8b1ba8 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol @@ -20,21 +20,11 @@ import { ISuperFaultDisputeGame } from "interfaces/dispute/ISuperFaultDisputeGam import { ISuperPermissionedDisputeGame } from "interfaces/dispute/ISuperPermissionedDisputeGame.sol"; import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol"; import { Duration, GameType, GameTypes } from "src/dispute/lib/Types.sol"; -import { - IOPContractsManager, - IOPContractsManagerGameTypeAdder, - IOPContractsManagerDeployer, - IOPContractsManagerUpgrader, - IOPContractsManagerContractsContainer, - IOPContractsManagerInteropMigrator, - IOPContractsManagerStandardValidator -} from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; import { IOPContractsManagerContainer } from "interfaces/L1/opcm/IOPContractsManagerContainer.sol"; import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; import { IOPContractsManagerMigrator } from "interfaces/L1/opcm/IOPContractsManagerMigrator.sol"; import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; -import { IOptimismPortalInterop } from "interfaces/L1/IOptimismPortalInterop.sol"; import { IETHLockbox } from "interfaces/L1/IETHLockbox.sol"; import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; import { IL1CrossDomainMessenger } from "interfaces/L1/IL1CrossDomainMessenger.sol"; @@ -44,10 +34,10 @@ import { IOptimismMintableERC20Factory } from "interfaces/universal/IOptimismMin import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; import { IStorageSetter } from "interfaces/universal/IStorageSetter.sol"; import { IOPContractsManagerStandardValidator } from "interfaces/L1/IOPContractsManagerStandardValidator.sol"; +import { DevFeatures } from "src/libraries/DevFeatures.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { Solarray } from "scripts/libraries/Solarray.sol"; import { ChainAssertions } from "scripts/deploy/ChainAssertions.sol"; -import { DevFeatures } from "src/libraries/DevFeatures.sol"; contract DeployImplementations is Script { struct Input { @@ -72,20 +62,21 @@ contract DeployImplementations is Script { } struct Output { - IOPContractsManager opcm; - IOPContractsManagerContractsContainer opcmContractsContainer; - IOPContractsManagerGameTypeAdder opcmGameTypeAdder; - IOPContractsManagerDeployer opcmDeployer; - IOPContractsManagerUpgrader opcmUpgrader; - IOPContractsManagerInteropMigrator opcmInteropMigrator; + // Deprecated v1 OPCM fields — kept for Go ABI compatibility, always zero. + // Remove these when Go op-deployer drops v1 struct fields. + address opcm; + address opcmContractsContainer; + address opcmGameTypeAdder; + address opcmDeployer; + address opcmUpgrader; + address opcmInteropMigrator; IOPContractsManagerStandardValidator opcmStandardValidator; IOPContractsManagerUtils opcmUtils; IOPContractsManagerMigrator opcmMigrator; IOPContractsManagerV2 opcmV2; - IOPContractsManagerContainer opcmContainer; // v2 container + IOPContractsManagerContainer opcmContainer; IDelayedWETH delayedWETHImpl; IOptimismPortal optimismPortalImpl; - IOptimismPortalInterop optimismPortalInteropImpl; IETHLockbox ethLockboxImpl; IPreimageOracle preimageOracleSingleton; IMIPS64 mipsSingleton; @@ -127,7 +118,6 @@ contract DeployImplementations is Script { deployL1StandardBridgeImpl(output_); deployOptimismMintableERC20FactoryImpl(output_); deployOptimismPortalImpl(_input, output_); - deployOptimismPortalInteropImpl(_input, output_); deployETHLockboxImpl(output_); deployDelayedWETHImpl(_input, output_); deployPreimageOracleSingleton(_input, output_); @@ -155,67 +145,6 @@ contract DeployImplementations is Script { // --- OP Contracts Manager --- - /// @notice Deploys the OPCM v1 contract. - /// Sets the OPCM v2 addresses to zero to indicate that OPCM v2 was not deployed. - /// @param _input The deployment input parameters. - /// @param _output The deployment output parameters. - /// @param _blueprints The blueprints for the OPCM v1 contract. - /// @return opcm_ The deployed OPCM v1 contract. - function createOPCMContract( - Input memory _input, - Output memory _output, - IOPContractsManager.Blueprints memory _blueprints - ) - private - returns (IOPContractsManager opcm_) - { - IOPContractsManager.Implementations memory implementations = IOPContractsManager.Implementations({ - superchainConfigImpl: address(_output.superchainConfigImpl), - protocolVersionsImpl: address(_output.protocolVersionsImpl), - l1ERC721BridgeImpl: address(_output.l1ERC721BridgeImpl), - optimismPortalImpl: address(_output.optimismPortalImpl), - optimismPortalInteropImpl: address(_output.optimismPortalInteropImpl), - ethLockboxImpl: address(_output.ethLockboxImpl), - systemConfigImpl: address(_output.systemConfigImpl), - optimismMintableERC20FactoryImpl: address(_output.optimismMintableERC20FactoryImpl), - l1CrossDomainMessengerImpl: address(_output.l1CrossDomainMessengerImpl), - l1StandardBridgeImpl: address(_output.l1StandardBridgeImpl), - disputeGameFactoryImpl: address(_output.disputeGameFactoryImpl), - anchorStateRegistryImpl: address(_output.anchorStateRegistryImpl), - delayedWETHImpl: address(_output.delayedWETHImpl), - mipsImpl: address(_output.mipsSingleton), - faultDisputeGameImpl: address(_output.faultDisputeGameImpl), - permissionedDisputeGameImpl: address(_output.permissionedDisputeGameImpl), - superFaultDisputeGameImpl: address(_output.superFaultDisputeGameImpl), - superPermissionedDisputeGameImpl: address(_output.superPermissionedDisputeGameImpl) - }); - - // Deploy OPCM V1 components - deployOPCMBPImplsContainer(_input, _output, _blueprints, implementations); - deployOPCMGameTypeAdder(_output); - deployOPCMDeployer(_input, _output); - deployOPCMUpgrader(_output); - deployOPCMInteropMigrator(_output); - deployOPCMStandardValidator(_input, _output, implementations); - - // Semgrep rule will fail because the arguments are encoded inside of a separate function. - opcm_ = IOPContractsManager( - // nosemgrep: sol-safety-deployutils-args - DeployUtils.createDeterministic({ - _name: "OPContractsManager", - _args: encodeOPCMConstructor(_input, _output), - _salt: _salt - }) - ); - - vm.label(address(opcm_), "OPContractsManager"); - _output.opcm = opcm_; - - // Set OPCM V2 addresses to zero (not deployed) - _output.opcmV2 = IOPContractsManagerV2(address(0)); - _output.opcmContainer = IOPContractsManagerContainer(address(0)); - } - /// @notice Deploys the OPCM v2 contract and all the necessary components it uses, including the OPCM v2 container. /// Sets the OPCM v1 addresses to zero to indicate that OPCM v1 was not deployed. /// @param _input The deployment input parameters. @@ -225,7 +154,7 @@ contract DeployImplementations is Script { function createOPCMContractV2( Input memory _input, Output memory _output, - IOPContractsManager.Blueprints memory _blueprints + IOPContractsManagerContainer.Blueprints memory _blueprints ) private returns (IOPContractsManagerV2 opcmV2_) @@ -236,7 +165,6 @@ contract DeployImplementations is Script { protocolVersionsImpl: address(_output.protocolVersionsImpl), l1ERC721BridgeImpl: address(_output.l1ERC721BridgeImpl), optimismPortalImpl: address(_output.optimismPortalImpl), - optimismPortalInteropImpl: address(_output.optimismPortalInteropImpl), ethLockboxImpl: address(_output.ethLockboxImpl), systemConfigImpl: address(_output.systemConfigImpl), optimismMintableERC20FactoryImpl: address(_output.optimismMintableERC20FactoryImpl), @@ -253,69 +181,23 @@ contract DeployImplementations is Script { storageSetterImpl: address(_output.storageSetterImpl) }); - // Convert blueprints to V2 blueprints - IOPContractsManagerContainer.Blueprints memory blueprints = IOPContractsManagerContainer.Blueprints({ - addressManager: _blueprints.addressManager, - proxy: _blueprints.proxy, - proxyAdmin: _blueprints.proxyAdmin, - l1ChugSplashProxy: _blueprints.l1ChugSplashProxy, - resolvedDelegateProxy: _blueprints.resolvedDelegateProxy - }); - // Deploy OPCM V2 components - deployOPCMContainer(_input, _output, blueprints, implementations); + deployOPCMContainer(_input, _output, _blueprints, implementations); deployOPCMStandardValidatorV2(_input, _output, implementations); deployOPCMUtils(_output); deployOPCMMigrator(_output); opcmV2_ = deployOPCMV2(_output); - // Set OPCM V1 addresses to zero (not deployed) - _output.opcm = IOPContractsManager(address(0)); - _output.opcmContractsContainer = IOPContractsManagerContractsContainer(address(0)); - _output.opcmGameTypeAdder = IOPContractsManagerGameTypeAdder(address(0)); - _output.opcmDeployer = IOPContractsManagerDeployer(address(0)); - _output.opcmUpgrader = IOPContractsManagerUpgrader(address(0)); - _output.opcmInteropMigrator = IOPContractsManagerInteropMigrator(address(0)); - return opcmV2_; } - /// @notice Encodes the constructor of the OPContractsManager contract. Used to avoid stack too - /// deep errors inside of the createOPCMContract function. - /// @param _input The deployment input parameters. - /// @param _output The deployment output parameters. - /// @return encoded_ The encoded constructor. - function encodeOPCMConstructor( - Input memory _input, - Output memory _output - ) - private - pure - returns (bytes memory encoded_) - { - encoded_ = DeployUtils.encodeConstructor( - abi.encodeCall( - IOPContractsManager.__constructor__, - ( - _output.opcmGameTypeAdder, - _output.opcmDeployer, - _output.opcmUpgrader, - _output.opcmInteropMigrator, - _output.opcmStandardValidator, - _input.superchainConfigProxy, - _input.protocolVersionsProxy - ) - ) - ); - } - - /// @notice Deploys the OPCM contract depending on the dev feature bitmap. + /// @notice Deploys the OPCM contract. /// @param _input The deployment input parameters. /// @param _output The deployment output parameters. function deployOPContractsManager(Input memory _input, Output memory _output) private { // First we deploy the blueprints for the singletons deployed by OPCM. // forgefmt: disable-start - IOPContractsManager.Blueprints memory blueprints; + IOPContractsManagerContainer.Blueprints memory blueprints; vm.startBroadcast(msg.sender); address checkAddress; (blueprints.addressManager, checkAddress) = DeployUtils.createDeterministicBlueprint(DeployUtils.getCode("AddressManager"), _salt); @@ -331,18 +213,9 @@ contract DeployImplementations is Script { // forgefmt: disable-end vm.stopBroadcast(); - // Check if OPCM V2 should be deployed - bool deployV2 = DevFeatures.isDevFeatureEnabled(_input.devFeatureBitmap, DevFeatures.OPCM_V2); - - if (deployV2) { - IOPContractsManagerV2 opcmV2 = createOPCMContractV2(_input, _output, blueprints); - vm.label(address(opcmV2), "OPContractsManagerV2"); - _output.opcmV2 = opcmV2; - } else { - IOPContractsManager opcm = createOPCMContract(_input, _output, blueprints); - vm.label(address(opcm), "OPContractsManager"); - _output.opcm = opcm; - } + IOPContractsManagerV2 opcmV2 = createOPCMContractV2(_input, _output, blueprints); + vm.label(address(opcmV2), "OPContractsManagerV2"); + _output.opcmV2 = opcmV2; } // --- Core Contracts --- @@ -493,21 +366,6 @@ contract DeployImplementations is Script { _output.optimismPortalImpl = impl; } - function deployOptimismPortalInteropImpl(Input memory _input, Output memory _output) private { - uint256 proofMaturityDelaySeconds = _input.proofMaturityDelaySeconds; - IOptimismPortalInterop impl = IOptimismPortalInterop( - DeployUtils.createDeterministic({ - _name: "OptimismPortalInterop", - _args: DeployUtils.encodeConstructor( - abi.encodeCall(IOptimismPortalInterop.__constructor__, (proofMaturityDelaySeconds)) - ), - _salt: _salt - }) - ); - vm.label(address(impl), "OptimismPortalInteropImpl"); - _output.optimismPortalInteropImpl = impl; - } - function deployDelayedWETHImpl(Input memory _input, Output memory _output) private { uint256 withdrawalDelaySeconds = _input.withdrawalDelaySeconds; IDelayedWETH impl = IDelayedWETH( @@ -661,30 +519,6 @@ contract DeployImplementations is Script { _output.superPermissionedDisputeGameImpl = impl; } - function deployOPCMBPImplsContainer( - Input memory _input, - Output memory _output, - IOPContractsManager.Blueprints memory _blueprints, - IOPContractsManager.Implementations memory _implementations - ) - private - { - IOPContractsManagerContractsContainer impl = IOPContractsManagerContractsContainer( - DeployUtils.createDeterministic({ - _name: "OPContractsManager.sol:OPContractsManagerContractsContainer", - _args: DeployUtils.encodeConstructor( - abi.encodeCall( - IOPContractsManagerContractsContainer.__constructor__, - (_blueprints, _implementations, _input.devFeatureBitmap) - ) - ), - _salt: _salt - }) - ); - vm.label(address(impl), "OPContractsManagerBPImplsContainerImpl"); - _output.opcmContractsContainer = impl; - } - function deployOPCMContainer( Input memory _input, Output memory _output, @@ -709,110 +543,6 @@ contract DeployImplementations is Script { _output.opcmContainer = impl; } - function deployOPCMGameTypeAdder(Output memory _output) private { - IOPContractsManagerGameTypeAdder impl = IOPContractsManagerGameTypeAdder( - DeployUtils.createDeterministic({ - _name: "OPContractsManager.sol:OPContractsManagerGameTypeAdder", - _args: DeployUtils.encodeConstructor( - abi.encodeCall(IOPContractsManagerGameTypeAdder.__constructor__, (_output.opcmContractsContainer)) - ), - _salt: _salt - }) - ); - vm.label(address(impl), "OPContractsManagerGameTypeAdderImpl"); - _output.opcmGameTypeAdder = impl; - } - - function deployOPCMDeployer(Input memory, Output memory _output) private { - IOPContractsManagerDeployer impl = IOPContractsManagerDeployer( - DeployUtils.createDeterministic({ - _name: "OPContractsManager.sol:OPContractsManagerDeployer", - _args: DeployUtils.encodeConstructor( - abi.encodeCall(IOPContractsManagerDeployer.__constructor__, (_output.opcmContractsContainer)) - ), - _salt: _salt - }) - ); - vm.label(address(impl), "OPContractsManagerDeployerImpl"); - _output.opcmDeployer = impl; - } - - function deployOPCMUpgrader(Output memory _output) private { - IOPContractsManagerUpgrader impl = IOPContractsManagerUpgrader( - DeployUtils.createDeterministic({ - _name: "OPContractsManager.sol:OPContractsManagerUpgrader", - _args: DeployUtils.encodeConstructor( - abi.encodeCall(IOPContractsManagerUpgrader.__constructor__, (_output.opcmContractsContainer)) - ), - _salt: _salt - }) - ); - vm.label(address(impl), "OPContractsManagerUpgraderImpl"); - _output.opcmUpgrader = impl; - } - - function deployOPCMInteropMigrator(Output memory _output) private { - IOPContractsManagerInteropMigrator impl = IOPContractsManagerInteropMigrator( - DeployUtils.createDeterministic({ - _name: "OPContractsManager.sol:OPContractsManagerInteropMigrator", - _args: DeployUtils.encodeConstructor( - abi.encodeCall(IOPContractsManagerInteropMigrator.__constructor__, (_output.opcmContractsContainer)) - ), - _salt: _salt - }) - ); - vm.label(address(impl), "OPContractsManagerInteropMigratorImpl"); - _output.opcmInteropMigrator = impl; - } - - function deployOPCMStandardValidator( - Input memory _input, - Output memory _output, - IOPContractsManager.Implementations memory _implementations - ) - private - { - IOPContractsManagerStandardValidator.Implementations memory opcmImplementations; - opcmImplementations.l1ERC721BridgeImpl = _implementations.l1ERC721BridgeImpl; - opcmImplementations.optimismPortalImpl = _implementations.optimismPortalImpl; - opcmImplementations.optimismPortalInteropImpl = _implementations.optimismPortalInteropImpl; - opcmImplementations.ethLockboxImpl = _implementations.ethLockboxImpl; - opcmImplementations.systemConfigImpl = _implementations.systemConfigImpl; - opcmImplementations.optimismMintableERC20FactoryImpl = _implementations.optimismMintableERC20FactoryImpl; - opcmImplementations.l1CrossDomainMessengerImpl = _implementations.l1CrossDomainMessengerImpl; - opcmImplementations.l1StandardBridgeImpl = _implementations.l1StandardBridgeImpl; - opcmImplementations.disputeGameFactoryImpl = _implementations.disputeGameFactoryImpl; - opcmImplementations.anchorStateRegistryImpl = _implementations.anchorStateRegistryImpl; - opcmImplementations.delayedWETHImpl = _implementations.delayedWETHImpl; - opcmImplementations.mipsImpl = _implementations.mipsImpl; - opcmImplementations.faultDisputeGameImpl = _implementations.faultDisputeGameImpl; - opcmImplementations.permissionedDisputeGameImpl = _implementations.permissionedDisputeGameImpl; - opcmImplementations.superFaultDisputeGameImpl = _implementations.superFaultDisputeGameImpl; - opcmImplementations.superPermissionedDisputeGameImpl = _implementations.superPermissionedDisputeGameImpl; - - IOPContractsManagerStandardValidator impl = IOPContractsManagerStandardValidator( - DeployUtils.createDeterministic({ - _name: "OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator", - _args: DeployUtils.encodeConstructor( - abi.encodeCall( - IOPContractsManagerStandardValidator.__constructor__, - ( - opcmImplementations, - _input.superchainConfigProxy, - _input.l1ProxyAdminOwner, - _input.challenger, - _input.withdrawalDelaySeconds, - _input.devFeatureBitmap - ) - ) - ), - _salt: _salt - }) - ); - vm.label(address(impl), "OPContractsManagerStandardValidatorImpl"); - _output.opcmStandardValidator = impl; - } - function deployOPCMUtils(Output memory _output) private { IOPContractsManagerUtils impl = IOPContractsManagerUtils( DeployUtils.createDeterministic({ @@ -851,7 +581,6 @@ contract DeployImplementations is Script { IOPContractsManagerStandardValidator.Implementations memory opcmImplementations; opcmImplementations.l1ERC721BridgeImpl = _implementations.l1ERC721BridgeImpl; opcmImplementations.optimismPortalImpl = _implementations.optimismPortalImpl; - opcmImplementations.optimismPortalInteropImpl = _implementations.optimismPortalInteropImpl; opcmImplementations.ethLockboxImpl = _implementations.ethLockboxImpl; opcmImplementations.systemConfigImpl = _implementations.systemConfigImpl; opcmImplementations.optimismMintableERC20FactoryImpl = _implementations.optimismMintableERC20FactoryImpl; @@ -972,11 +701,8 @@ contract DeployImplementations is Script { // With 12 addresses, we'd get a stack too deep error if we tried to do this inline as a // single call to `Solarray.addresses`. So we split it into two calls. - // Check which OPCM version was deployed - bool deployedV2 = DevFeatures.isDevFeatureEnabled(_input.devFeatureBitmap, DevFeatures.OPCM_V2); - address[] memory addrs1 = Solarray.addresses( - deployedV2 ? address(_output.opcmV2) : address(_output.opcm), + address(_output.opcmV2), address(_output.optimismPortalImpl), address(_output.delayedWETHImpl), address(_output.preimageOracleSingleton), @@ -1010,26 +736,7 @@ contract DeployImplementations is Script { DeployUtils.assertValidContractAddresses(Solarray.extend(addrs1, addrs2)); - // Validate OPCM V2 flag - if (DevFeatures.isDevFeatureEnabled(_input.devFeatureBitmap, DevFeatures.OPCM_V2)) { - require( - address(_output.opcmV2) != address(0), - "DeployImplementations: OPCM V2 flag enabled but OPCM V2 not deployed" - ); - require( - address(_output.opcm) == address(0), - "DeployImplementations: OPCM V2 flag enabled but OPCM V1 was deployed" - ); - } else { - require( - address(_output.opcm) != address(0), - "DeployImplementations: OPCM V2 flag disabled but OPCM V1 not deployed" - ); - require( - address(_output.opcmV2) == address(0), - "DeployImplementations: OPCM V2 flag disabled but OPCM V2 was deployed" - ); - } + require(address(_output.opcmV2) != address(0), "DeployImplementations: OPCM V2 not deployed"); if ( !DevFeatures.isDevFeatureEnabled(_input.devFeatureBitmap, DevFeatures.OPTIMISM_PORTAL_INTEROP) @@ -1065,19 +772,6 @@ contract DeployImplementations is Script { ChainAssertions.checkL1StandardBridgeImpl(_output.l1StandardBridgeImpl); ChainAssertions.checkMIPS(_output.mipsSingleton, _output.preimageOracleSingleton); - // Only check OPCM V1 if it was deployed - if (!DevFeatures.isDevFeatureEnabled(_input.devFeatureBitmap, DevFeatures.OPCM_V2)) { - Types.ContractSet memory proxies; - proxies.SuperchainConfig = address(_input.superchainConfigProxy); - proxies.ProtocolVersions = address(_input.protocolVersionsProxy); - ChainAssertions.checkOPContractsManager({ - _impls: impls, - _proxies: proxies, - _opcm: IOPContractsManager(address(_output.opcm)), - _mips: IMIPS64(address(_output.mipsSingleton)) - }); - } - ChainAssertions.checkOptimismMintableERC20FactoryImpl(_output.optimismMintableERC20FactoryImpl); ChainAssertions.checkOptimismPortal2({ _contracts: impls, diff --git a/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol index ebe7db022a3..2002a440899 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol @@ -9,10 +9,8 @@ import { Solarray } from "scripts/libraries/Solarray.sol"; import { ChainAssertions } from "scripts/deploy/ChainAssertions.sol"; import { Constants as ScriptConstants } from "scripts/libraries/Constants.sol"; import { Types } from "scripts/libraries/Types.sol"; -import { SemverComp } from "src/libraries/SemverComp.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; import { IAddressManager } from "interfaces/legacy/IAddressManager.sol"; @@ -35,9 +33,6 @@ contract DeployOPChain is Script { /// @notice The default init bond for the dispute games. uint256 public constant DEFAULT_INIT_BOND = 0.08 ether; - /// @notice Whether to use OPCM v2. - bool public isOPCMv2; - /// @notice Whether the OPCM has SUPER_ROOT_GAMES_MIGRATION enabled. bool public isSuperRoot; @@ -77,28 +72,15 @@ contract DeployOPChain is Script { function run(Types.DeployOPChainInput memory _input) public returns (Output memory output_) { checkInput(_input); - // Check if OPCM v2 should be used, both v1 and v2 share the same interface for this function. require(address(_input.opcm).code.length > 0, "DeployOPChain: OPCM address has no code"); - isOPCMv2 = SemverComp.gte(IOPContractsManager(_input.opcm).version(), Constants.OPCM_V2_MIN_VERSION); - - if (isOPCMv2) { - IOPContractsManagerV2 opcmV2 = IOPContractsManagerV2(_input.opcm); - isSuperRoot = - DevFeatures.isDevFeatureEnabled(opcmV2.devFeatureBitmap(), DevFeatures.SUPER_ROOT_GAMES_MIGRATION); - IOPContractsManagerV2.FullConfig memory config = _toOPCMV2DeployInput(_input); - vm.broadcast(msg.sender); - IOPContractsManagerV2.ChainContracts memory chainContracts = opcmV2.deploy(config); - output_ = _fromOPCMV2OutputToOutput(chainContracts); - } else { - IOPContractsManager opcm = IOPContractsManager(_input.opcm); - IOPContractsManager.DeployInput memory deployInput = _toOPCMV1DeployInput(_input); + IOPContractsManagerV2 opcmV2 = IOPContractsManagerV2(_input.opcm); + isSuperRoot = DevFeatures.isDevFeatureEnabled(opcmV2.devFeatureBitmap(), DevFeatures.SUPER_ROOT_GAMES_MIGRATION); + IOPContractsManagerV2.FullConfig memory config = _toOPCMV2DeployInput(_input); - vm.broadcast(msg.sender); - IOPContractsManager.DeployOutput memory deployOutput = opcm.deploy(deployInput); - - output_ = _fromOPCMV1OutputToOutput(deployOutput); - } + vm.broadcast(msg.sender); + IOPContractsManagerV2.ChainContracts memory chainContracts = opcmV2.deploy(config); + output_ = _fromOPCMV2OutputToOutput(chainContracts); checkOutput(_input, output_); @@ -121,40 +103,6 @@ contract DeployOPChain is Script { // -------- Features -------- - /// @notice Converts Types.DeployOPChainInput to IOPContractsManager.DeployInput. - /// @param _input The input parameters. - /// @return deployInput_ The deployed input parameters. - function _toOPCMV1DeployInput(Types.DeployOPChainInput memory _input) - internal - pure - returns (IOPContractsManager.DeployInput memory deployInput_) - { - IOPContractsManager.Roles memory roles = IOPContractsManager.Roles({ - opChainProxyAdminOwner: _input.opChainProxyAdminOwner, - systemConfigOwner: _input.systemConfigOwner, - batcher: _input.batcher, - unsafeBlockSigner: _input.unsafeBlockSigner, - proposer: _input.proposer, - challenger: _input.challenger - }); - deployInput_ = IOPContractsManager.DeployInput({ - roles: roles, - basefeeScalar: _input.basefeeScalar, - blobBasefeeScalar: _input.blobBaseFeeScalar, - l2ChainId: _input.l2ChainId, - startingAnchorRoot: startingAnchorRoot(), - saltMixer: _input.saltMixer, - gasLimit: _input.gasLimit, - disputeGameType: _input.disputeGameType, - disputeAbsolutePrestate: _input.disputeAbsolutePrestate, - disputeMaxGameDepth: _input.disputeMaxGameDepth, - disputeSplitDepth: _input.disputeSplitDepth, - disputeClockExtension: _input.disputeClockExtension, - disputeMaxClockDuration: _input.disputeMaxClockDuration, - useCustomGasToken: _input.useCustomGasToken - }); - } - /// @notice Converts Types.DeployOPChainInput to IOPContractsManagerV2.FullConfig. /// @param _input The input parameters. /// @return config_ The deployed input parameters. @@ -294,33 +242,6 @@ contract DeployOPChain is Script { }); } - /// @notice Converts IOPContractsManager.DeployOutput to Output. - /// @param _deployOutput The deploy output. - /// @return output_ The output parameters. - function _fromOPCMV1OutputToOutput(IOPContractsManager.DeployOutput memory _deployOutput) - internal - pure - returns (Output memory output_) - { - output_ = Output({ - opChainProxyAdmin: _deployOutput.opChainProxyAdmin, - addressManager: _deployOutput.addressManager, - l1ERC721BridgeProxy: _deployOutput.l1ERC721BridgeProxy, - systemConfigProxy: _deployOutput.systemConfigProxy, - optimismMintableERC20FactoryProxy: _deployOutput.optimismMintableERC20FactoryProxy, - l1StandardBridgeProxy: _deployOutput.l1StandardBridgeProxy, - l1CrossDomainMessengerProxy: _deployOutput.l1CrossDomainMessengerProxy, - optimismPortalProxy: _deployOutput.optimismPortalProxy, - ethLockboxProxy: _deployOutput.ethLockboxProxy, - disputeGameFactoryProxy: _deployOutput.disputeGameFactoryProxy, - anchorStateRegistryProxy: _deployOutput.anchorStateRegistryProxy, - faultDisputeGame: _deployOutput.faultDisputeGame, - permissionedDisputeGame: _deployOutput.permissionedDisputeGame, - delayedWETHPermissionedGameProxy: _deployOutput.delayedWETHPermissionedGameProxy, - delayedWETHPermissionlessGameProxy: _deployOutput.delayedWETHPermissionlessGameProxy - }); - } - // -------- Validations -------- /// @notice Checks if the input is valid. @@ -398,20 +319,10 @@ contract DeployOPChain is Script { }); // Check dispute games and get superchain config - address expectedPDGImpl = address(_o.permissionedDisputeGame); - - if (isOPCMv2) { - // OPCM v2: use implementations from v2 contract - IOPContractsManagerV2 opcmV2 = IOPContractsManagerV2(_i.opcm); - expectedPDGImpl = isSuperRoot - ? opcmV2.implementations().superPermissionedDisputeGameImpl - : opcmV2.implementations().permissionedDisputeGameImpl; - } else { - // OPCM v1: use implementations from v1 contract - IOPContractsManager opcm = IOPContractsManager(_i.opcm); - // With v2 game contracts enabled, we use the predeployed pdg implementation - expectedPDGImpl = opcm.implementations().permissionedDisputeGameImpl; - } + IOPContractsManagerV2 opcmV2 = IOPContractsManagerV2(_i.opcm); + address expectedPDGImpl = isSuperRoot + ? opcmV2.implementations().superPermissionedDisputeGameImpl + : opcmV2.implementations().permissionedDisputeGameImpl; GameType permGameType = isSuperRoot ? GameTypes.SUPER_PERMISSIONED_CANNON : GameTypes.PERMISSIONED_CANNON; ChainAssertions.checkDisputeGameFactory( diff --git a/packages/contracts-bedrock/scripts/deploy/Deployer.sol b/packages/contracts-bedrock/scripts/deploy/Deployer.sol index 290f318f242..29c68911a9a 100644 --- a/packages/contracts-bedrock/scripts/deploy/Deployer.sol +++ b/packages/contracts-bedrock/scripts/deploy/Deployer.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.0; // Testing import { console } from "forge-std/console.sol"; import { Script } from "forge-std/Script.sol"; +import { VmSafe } from "forge-std/Vm.sol"; // Scripts import { Artifacts } from "scripts/Artifacts.s.sol"; @@ -30,7 +31,14 @@ abstract contract Deployer is Script { console.log("Commit hash: %s", gitCommitHash()); DeployUtils.etchLabelAndAllowCheatcodes({ _etchTo: address(cfg), _cname: "DeployConfig" }); - cfg.read(Config.deployConfigPath()); + + // In test context or kontrol context, use hardcoded defaults by calling read() with empty path. + // In non-test context, read from the config file. + if (vm.isContext(VmSafe.ForgeContext.TestGroup) || Config.isKontrolContext()) { + cfg.read(""); + } else { + cfg.read(Config.deployConfigPath()); + } } /// @notice Returns the commit hash of HEAD. If no git repository is diff --git a/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol b/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol index 0ea4742123c..f2c4c756b4d 100644 --- a/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/InteropMigration.s.sol @@ -3,13 +3,13 @@ pragma solidity 0.8.15; import { Script } from "forge-std/Script.sol"; import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; -import { IOPContractsManagerInteropMigrator, IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManagerMigrator } from "interfaces/L1/opcm/IOPContractsManagerMigrator.sol"; +import { ISemver } from "interfaces/universal/ISemver.sol"; +import { SemverComp } from "src/libraries/SemverComp.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; -import { SemverComp } from "src/libraries/SemverComp.sol"; contract InteropMigrationInput is BaseDeployIO { address internal _prank; @@ -25,17 +25,7 @@ contract InteropMigrationInput is BaseDeployIO { else revert("InteropMigrationInput: unknown selector"); } - /// @notice Sets the migrate input using the IOPContractsManagerInteropMigrator.MigrateInput type, - /// this is used when migrating chains using OPCM v1. - /// @param _sel The selector of the field to set. - /// @param _value The value to set. - function set(bytes4 _sel, IOPContractsManagerInteropMigrator.MigrateInput memory _value) public { - if (_sel == this.migrateInput.selector) _migrateInput = abi.encode(_value); - else revert("InteropMigrationInput: unknown selector"); - } - - /// @notice Sets the migrate input using the IOPContractsManagerMigrator.MigrateInput type, - /// this is used when migrating chains using OPCM v2. + /// @notice Sets the migrate input using the IOPContractsManagerMigrator.MigrateInput type. /// @param _sel The selector of the field to set. /// @param _value The value to set. function set(bytes4 _sel, IOPContractsManagerMigrator.MigrateInput memory _value) public { @@ -75,14 +65,13 @@ contract InteropMigrationOutput is BaseDeployIO { } contract InteropMigration is Script { - /// @notice Whether to use OPCM v2. - bool internal _useOPCMv2; - function run(InteropMigrationInput _imi, InteropMigrationOutput _imo) public { - // Determine OPCM version by checking the semver or if the OPCM address is set. OPCM v2 starts at version 7.0.0. - IOPContractsManager opcm = IOPContractsManager(_imi.opcm()); - require(address(opcm).code.length > 0, "InteropMigration: OPCM address has no code"); - _useOPCMv2 = SemverComp.gte(opcm.version(), "7.0.0"); + address opcm = _imi.opcm(); + require(opcm.code.length > 0, "InteropMigration: OPCM address has no code"); + require( + SemverComp.gte(ISemver(opcm).version(), "7.0.0"), + "InteropMigration: OPCM must be v7.0.0 or later (OPCMv2). OPCMv1 is no longer supported." + ); // Etch DummyCaller contract. This contract is used to mimic the contract that is used // as the source of the delegatecall to the OPCM. In practice this will be the governance @@ -90,21 +79,15 @@ contract InteropMigration is Script { address prank = _imi.prank(); bytes memory code = type(DummyCaller).runtimeCode; vm.etch(prank, code); - vm.store(prank, bytes32(0), bytes32(uint256(uint160(address(opcm))))); + vm.store(prank, bytes32(0), bytes32(uint256(uint160(opcm)))); vm.label(prank, "DummyCaller"); // Call into the DummyCaller. This will perform the delegatecall under the hood. // The DummyCaller uses a fallback that reverts on failure, so no need to check success. vm.startBroadcast(msg.sender); - if (_useOPCMv2) { - IOPContractsManagerMigrator(prank).migrate( - abi.decode(_imi.migrateInput(), (IOPContractsManagerMigrator.MigrateInput)) - ); - } else { - IOPContractsManagerInteropMigrator(prank).migrate( - abi.decode(_imi.migrateInput(), (IOPContractsManagerInteropMigrator.MigrateInput)) - ); - } + IOPContractsManagerMigrator(prank).migrate( + abi.decode(_imi.migrateInput(), (IOPContractsManagerMigrator.MigrateInput)) + ); vm.stopBroadcast(); // After migration all portals will have the same DGF @@ -113,48 +96,26 @@ contract InteropMigration is Script { checkOutput(_imi, _imo); } - /// @notice Helper function to set the dispute game factory in the output based on the OPCM version. + /// @notice Helper function to set the dispute game factory in the output. /// @param _imi The migration input. /// @param _imo The migration output. function _setDisputeGameFactory(InteropMigrationInput _imi, InteropMigrationOutput _imo) internal { - if (_useOPCMv2) { - IOPContractsManagerMigrator.MigrateInput memory inputV2 = - abi.decode(_imi.migrateInput(), (IOPContractsManagerMigrator.MigrateInput)); - IOptimismPortal portal = IOptimismPortal(payable(inputV2.chainSystemConfigs[0].optimismPortal())); - _imo.set(_imo.disputeGameFactory.selector, portal.disputeGameFactory()); - } else { - IOPContractsManagerInteropMigrator.MigrateInput memory inputV1 = - abi.decode(_imi.migrateInput(), (IOPContractsManagerInteropMigrator.MigrateInput)); - IOptimismPortal portal = - IOptimismPortal(payable(inputV1.opChainConfigs[0].systemConfigProxy.optimismPortal())); - _imo.set(_imo.disputeGameFactory.selector, portal.disputeGameFactory()); - } + IOPContractsManagerMigrator.MigrateInput memory migrateInput = + abi.decode(_imi.migrateInput(), (IOPContractsManagerMigrator.MigrateInput)); + IOptimismPortal portal = IOptimismPortal(payable(migrateInput.chainSystemConfigs[0].optimismPortal())); + _imo.set(_imo.disputeGameFactory.selector, portal.disputeGameFactory()); } function checkOutput(InteropMigrationInput _imi, InteropMigrationOutput _imo) public view { - if (_useOPCMv2) { - IOPContractsManagerMigrator.MigrateInput memory inputV2 = - abi.decode(_imi.migrateInput(), (IOPContractsManagerMigrator.MigrateInput)); - - for (uint256 i = 0; i < inputV2.chainSystemConfigs.length; i++) { - IOptimismPortal portal = IOptimismPortal(payable(inputV2.chainSystemConfigs[i].optimismPortal())); - require( - IDisputeGameFactory(portal.disputeGameFactory()) == _imo.disputeGameFactory(), - "InteropMigration: disputeGameFactory mismatch" - ); - } - } else { - IOPContractsManagerInteropMigrator.MigrateInput memory inputV1 = - abi.decode(_imi.migrateInput(), (IOPContractsManagerInteropMigrator.MigrateInput)); - - for (uint256 i = 0; i < inputV1.opChainConfigs.length; i++) { - IOptimismPortal portal = - IOptimismPortal(payable(inputV1.opChainConfigs[i].systemConfigProxy.optimismPortal())); - require( - IDisputeGameFactory(portal.disputeGameFactory()) == _imo.disputeGameFactory(), - "InteropMigration: disputeGameFactory mismatch" - ); - } + IOPContractsManagerMigrator.MigrateInput memory migrateInput = + abi.decode(_imi.migrateInput(), (IOPContractsManagerMigrator.MigrateInput)); + + for (uint256 i = 0; i < migrateInput.chainSystemConfigs.length; i++) { + IOptimismPortal portal = IOptimismPortal(payable(migrateInput.chainSystemConfigs[i].optimismPortal())); + require( + IDisputeGameFactory(portal.disputeGameFactory()) == _imo.disputeGameFactory(), + "InteropMigration: disputeGameFactory mismatch" + ); } } } diff --git a/packages/contracts-bedrock/scripts/deploy/ReadImplementationAddresses.s.sol b/packages/contracts-bedrock/scripts/deploy/ReadImplementationAddresses.s.sol index 75ab6d7d3cd..4b1865f1ca9 100644 --- a/packages/contracts-bedrock/scripts/deploy/ReadImplementationAddresses.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/ReadImplementationAddresses.s.sol @@ -4,13 +4,10 @@ pragma solidity 0.8.15; import { IProxy } from "interfaces/universal/IProxy.sol"; import { Script } from "forge-std/Script.sol"; import { IMIPS64 } from "interfaces/cannon/IMIPS64.sol"; -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; import { IOPContractsManagerContainer } from "interfaces/L1/opcm/IOPContractsManagerContainer.sol"; import { IAddressManager } from "interfaces/legacy/IAddressManager.sol"; import { IStaticL1ChugSplashProxy } from "interfaces/legacy/IL1ChugSplashProxy.sol"; -import { SemverComp } from "src/libraries/SemverComp.sol"; -import { Constants } from "src/libraries/Constants.sol"; contract ReadImplementationAddresses is Script { struct Input { @@ -27,7 +24,6 @@ contract ReadImplementationAddresses is Script { struct Output { address delayedWETH; address optimismPortal; - address optimismPortalInterop; address ethLockbox; address systemConfig; address anchorStateRegistry; @@ -61,53 +57,25 @@ contract ReadImplementationAddresses is Script { vm.prank(address(0)); output_.l1StandardBridge = IStaticL1ChugSplashProxy(_input.l1StandardBridgeProxy).getImplementation(); - // Check if OPCM v2 is being used require(address(_input.opcm).code.length > 0, "ReadImplementationAddresses: OPCM address has no code"); - bool isOPCMv2 = SemverComp.gte(IOPContractsManager(_input.opcm).version(), Constants.OPCM_V2_MIN_VERSION); + IOPContractsManagerV2 opcmV2 = IOPContractsManagerV2(_input.opcm); - if (isOPCMv2) { - // Get implementations from OPCM V2 - IOPContractsManagerV2 opcmV2 = IOPContractsManagerV2(_input.opcm); + output_.opcmGameTypeAdder = address(0); + output_.opcmDeployer = address(0); + output_.opcmUpgrader = address(0); - // These addresses are deprecated in OPCM V2 - output_.opcmGameTypeAdder = address(0); - output_.opcmDeployer = address(0); - output_.opcmUpgrader = address(0); + output_.opcmInteropMigrator = address(opcmV2.opcmMigrator()); + output_.opcmStandardValidator = address(opcmV2.opcmStandardValidator()); - // Get migrator and standard validator from OPCM V2 - output_.opcmInteropMigrator = address(opcmV2.opcmMigrator()); - output_.opcmStandardValidator = address(opcmV2.opcmStandardValidator()); - - IOPContractsManagerContainer.Implementations memory impls = opcmV2.implementations(); - output_.mipsSingleton = impls.mipsImpl; - output_.delayedWETH = impls.delayedWETHImpl; - output_.ethLockbox = impls.ethLockboxImpl; - output_.anchorStateRegistry = impls.anchorStateRegistryImpl; - output_.optimismPortalInterop = impls.optimismPortalInteropImpl; - output_.faultDisputeGame = impls.faultDisputeGameImpl; - output_.permissionedDisputeGame = impls.permissionedDisputeGameImpl; - output_.superFaultDisputeGame = impls.superFaultDisputeGameImpl; - output_.superPermissionedDisputeGame = impls.superPermissionedDisputeGameImpl; - } else { - // Get implementations from OPCM V1 - IOPContractsManager opcm = IOPContractsManager(_input.opcm); - output_.opcmGameTypeAdder = address(opcm.opcmGameTypeAdder()); - output_.opcmDeployer = address(opcm.opcmDeployer()); - output_.opcmUpgrader = address(opcm.opcmUpgrader()); - output_.opcmInteropMigrator = address(opcm.opcmInteropMigrator()); - output_.opcmStandardValidator = address(opcm.opcmStandardValidator()); - - IOPContractsManager.Implementations memory impls = opcm.implementations(); - output_.mipsSingleton = impls.mipsImpl; - output_.delayedWETH = impls.delayedWETHImpl; - output_.ethLockbox = impls.ethLockboxImpl; - output_.anchorStateRegistry = impls.anchorStateRegistryImpl; - output_.optimismPortalInterop = impls.optimismPortalInteropImpl; - output_.faultDisputeGame = impls.faultDisputeGameImpl; - output_.permissionedDisputeGame = impls.permissionedDisputeGameImpl; - output_.superFaultDisputeGame = impls.superFaultDisputeGameImpl; - output_.superPermissionedDisputeGame = impls.superPermissionedDisputeGameImpl; - } + IOPContractsManagerContainer.Implementations memory impls = opcmV2.implementations(); + output_.mipsSingleton = impls.mipsImpl; + output_.delayedWETH = impls.delayedWETHImpl; + output_.ethLockbox = impls.ethLockboxImpl; + output_.anchorStateRegistry = impls.anchorStateRegistryImpl; + output_.faultDisputeGame = impls.faultDisputeGameImpl; + output_.permissionedDisputeGame = impls.permissionedDisputeGameImpl; + output_.superFaultDisputeGame = impls.superFaultDisputeGameImpl; + output_.superPermissionedDisputeGame = impls.superPermissionedDisputeGameImpl; // Get L1CrossDomainMessenger from AddressManager IAddressManager am = IAddressManager(_input.addressManager); diff --git a/packages/contracts-bedrock/scripts/deploy/ReadSuperchainDeployment.s.sol b/packages/contracts-bedrock/scripts/deploy/ReadSuperchainDeployment.s.sol index 905118b9074..fa4fc2eba4e 100644 --- a/packages/contracts-bedrock/scripts/deploy/ReadSuperchainDeployment.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/ReadSuperchainDeployment.s.sol @@ -4,28 +4,16 @@ pragma solidity 0.8.15; import { Script } from "forge-std/Script.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; -import { IProtocolVersions, ProtocolVersion } from "interfaces/L1/IProtocolVersions.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; import { IProxy } from "interfaces/universal/IProxy.sol"; -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; -import { SemverComp } from "src/libraries/SemverComp.sol"; -import { Constants } from "src/libraries/Constants.sol"; contract ReadSuperchainDeployment is Script { struct Input { - IOPContractsManager opcmAddress; // TODO(#18612): Remove OPCMAddress field when OPCMv1 gets deprecated ISuperchainConfig superchainConfigProxy; } struct Output { - // TODO(#18612): Remove ProtocolVersions fields when OPCMv1 gets deprecated - IProtocolVersions protocolVersionsImpl; - IProtocolVersions protocolVersionsProxy; - address protocolVersionsOwner; - bytes32 recommendedProtocolVersion; - bytes32 requiredProtocolVersion; - // Superchain config ISuperchainConfig superchainConfigImpl; ISuperchainConfig superchainConfigProxy; IProxyAdmin superchainProxyAdmin; @@ -34,58 +22,22 @@ contract ReadSuperchainDeployment is Script { } function run(Input memory _input) public returns (Output memory output_) { - // Determine OPCM version by checking the semver or if the OPCM address is set. OPCM v2 starts at version 7.0.0. - IOPContractsManager opcm = IOPContractsManager(_input.opcmAddress); - bool isOPCMV2; - if (address(opcm) == address(0)) { - isOPCMV2 = true; - } else { - require(address(opcm).code.length > 0, "ReadSuperchainDeployment: OPCM address has no code"); - isOPCMV2 = SemverComp.gte(opcm.version(), Constants.OPCM_V2_MIN_VERSION); - } + require( + address(_input.superchainConfigProxy).code.length > 0, + "ReadSuperchainDeployment: superchainConfigProxy has no code" + ); - if (isOPCMV2) { - require( - address(_input.superchainConfigProxy).code.length > 0, - "ReadSuperchainDeployment: superchainConfigProxy has no code for OPCM v2" - ); + output_.superchainConfigProxy = _input.superchainConfigProxy; + output_.superchainProxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(output_.superchainConfigProxy))); - // For OPCM v2, ProtocolVersions is being removed. Therefore, the ProtocolVersions-related fields - // (protocolVersionsImpl, protocolVersionsProxy, protocolVersionsOwner, recommendedProtocolVersion, - // requiredProtocolVersion) are intentionally left uninitialized. - output_.superchainConfigProxy = _input.superchainConfigProxy; - output_.superchainProxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(output_.superchainConfigProxy))); + IProxy superchainConfigProxy = IProxy(payable(address(output_.superchainConfigProxy))); - IProxy superchainConfigProxy = IProxy(payable(address(output_.superchainConfigProxy))); + vm.startPrank(address(0)); + output_.superchainConfigImpl = ISuperchainConfig(superchainConfigProxy.implementation()); + vm.stopPrank(); - vm.startPrank(address(0)); - output_.superchainConfigImpl = ISuperchainConfig(superchainConfigProxy.implementation()); - vm.stopPrank(); - - output_.guardian = output_.superchainConfigProxy.guardian(); - output_.superchainProxyAdminOwner = output_.superchainProxyAdmin.owner(); - } else { - // When running on OPCM v1, the OPCM address is used to read the ProtocolVersions contract and - // SuperchainConfig. - output_.protocolVersionsProxy = IProtocolVersions(opcm.protocolVersions()); - output_.superchainConfigProxy = ISuperchainConfig(opcm.superchainConfig()); - output_.superchainProxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(output_.superchainConfigProxy))); - - IProxy protocolVersionsProxy = IProxy(payable(address(output_.protocolVersionsProxy))); - IProxy superchainConfigProxy = IProxy(payable(address(output_.superchainConfigProxy))); - - vm.startPrank(address(0)); - output_.protocolVersionsImpl = IProtocolVersions(protocolVersionsProxy.implementation()); - output_.superchainConfigImpl = ISuperchainConfig(superchainConfigProxy.implementation()); - vm.stopPrank(); - - output_.guardian = output_.superchainConfigProxy.guardian(); - output_.protocolVersionsOwner = output_.protocolVersionsProxy.owner(); - output_.superchainProxyAdminOwner = output_.superchainProxyAdmin.owner(); - output_.recommendedProtocolVersion = - bytes32(ProtocolVersion.unwrap(output_.protocolVersionsProxy.recommended())); - output_.requiredProtocolVersion = bytes32(ProtocolVersion.unwrap(output_.protocolVersionsProxy.required())); - } + output_.guardian = output_.superchainConfigProxy.guardian(); + output_.superchainProxyAdminOwner = output_.superchainProxyAdmin.owner(); } function runWithBytes(bytes memory _input) public returns (bytes memory) { diff --git a/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol b/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol index 1d18574c8dd..dd0f725a157 100644 --- a/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/UpgradeOPChain.s.sol @@ -2,12 +2,11 @@ pragma solidity ^0.8.0; import { Script } from "forge-std/Script.sol"; -import { OPContractsManager } from "src/L1/OPContractsManager.sol"; import { OPContractsManagerV2 } from "src/L1/opcm/OPContractsManagerV2.sol"; +import { ISemver } from "interfaces/universal/ISemver.sol"; +import { SemverComp } from "src/libraries/SemverComp.sol"; import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; -import { SemverComp } from "src/libraries/SemverComp.sol"; -import { Constants } from "src/libraries/Constants.sol"; contract UpgradeOPChainInput is BaseDeployIO { address internal _prank; @@ -24,30 +23,12 @@ contract UpgradeOPChainInput is BaseDeployIO { else revert("UpgradeOPCMInput: unknown selector"); } - /// @notice Sets the upgrade input using the OPContractsManager.OpChainConfig[] type, - /// this is used when upgrading chains using OPCM v1. - /// @param _sel The selector of the field to set. - /// @param _value The value to set. - function set(bytes4 _sel, OPContractsManager.OpChainConfig[] memory _value) public { - if (SemverComp.gte(OPContractsManager(opcm()).version(), Constants.OPCM_V2_MIN_VERSION)) { - revert("UpgradeOPCMInput: cannot set OPCM v1 upgrade input when OPCM v2 is enabled"); - } - require(_value.length > 0, "UpgradeOPCMInput: cannot set empty array"); - - if (_sel == this.upgradeInput.selector) _upgradeInput = abi.encode(_value); - else revert("UpgradeOPCMInput: unknown selector"); - } - - /// @notice Sets the upgrade input using the OPContractsManagerV2.UpgradeInput type, - /// this is used when upgrading chains using OPCM v2. + /// @notice Sets the upgrade input using the OPContractsManagerV2.UpgradeInput type. /// Minimal validation is performed, relying on the OPCM v2 contract to perform the proper validation. /// This is done to avoid duplicating the validation logic in the script. /// @param _sel The selector of the field to set. /// @param _value The value to set. function set(bytes4 _sel, OPContractsManagerV2.UpgradeInput memory _value) public { - if (!SemverComp.gte(OPContractsManager(opcm()).version(), Constants.OPCM_V2_MIN_VERSION)) { - revert("UpgradeOPCMInput: cannot set OPCM v2 upgrade input when OPCM v1 is enabled"); - } require(address(_value.systemConfig) != address(0), "UpgradeOPCMInput: cannot set zero address"); require(_value.disputeGameConfigs.length > 0, "UpgradeOPCMInput: cannot set empty dispute game configs array"); @@ -74,9 +55,11 @@ contract UpgradeOPChainInput is BaseDeployIO { contract UpgradeOPChain is Script { function run(UpgradeOPChainInput _uoci) external { address opcm = _uoci.opcm(); - - // First, we need to check what version of OPCM is being used. - bool isOPCMv2 = SemverComp.gte(OPContractsManager(opcm).version(), Constants.OPCM_V2_MIN_VERSION); + require(opcm.code.length > 0, "UpgradeOPChain: OPCM address has no code"); + require( + SemverComp.gte(ISemver(opcm).version(), "7.0.0"), + "UpgradeOPChain: OPCM must be v7.0.0 or later (OPCMv2). OPCMv1 is no longer supported." + ); // Etch DummyCaller contract. This contract is used to mimic the contract that is used // as the source of the delegatecall to the OPCM. In practice this will be the governance @@ -93,7 +76,7 @@ contract UpgradeOPChain is Script { // Call into the DummyCaller. This will perform the delegatecall under the hood. // The DummyCaller uses a fallback that reverts on failure, so no need to check success. vm.broadcast(msg.sender); - _upgrade(prank, isOPCMv2, upgradeInput); + _upgrade(prank, upgradeInput); } /// @notice Helper function to get the dummy caller code. @@ -102,22 +85,13 @@ contract UpgradeOPChain is Script { return type(DummyCaller).runtimeCode; } - /// @notice Helper function to upgrade the OPCM based on the OPCM version. Performs the decoding of the upgrade + /// @notice Helper function to upgrade the OPCM. Performs the decoding of the upgrade /// input and the delegatecall to the OPCM. /// @param _prank The address of the dummy caller contract. - /// @param _isOPCMv2 Whether to use OPCM v2. /// @param _upgradeInput The upgrade input. - function _upgrade(address _prank, bool _isOPCMv2, bytes memory _upgradeInput) internal { - bytes memory data; - if (_isOPCMv2) { - data = abi.encodeCall( - OPContractsManagerV2.upgrade, abi.decode(_upgradeInput, (OPContractsManagerV2.UpgradeInput)) - ); - } else { - data = abi.encodeCall( - OPContractsManager.upgrade, abi.decode(_upgradeInput, (OPContractsManager.OpChainConfig[])) - ); - } + function _upgrade(address _prank, bytes memory _upgradeInput) internal { + bytes memory data = + abi.encodeCall(OPContractsManagerV2.upgrade, abi.decode(_upgradeInput, (OPContractsManagerV2.UpgradeInput))); (bool success, bytes memory returnData) = _prank.call(data); if (!success) { assembly { diff --git a/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol b/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol index c386c7e2c8e..fbad006b97a 100644 --- a/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/UpgradeSuperchainConfig.s.sol @@ -2,13 +2,10 @@ pragma solidity 0.8.15; import { Script } from "forge-std/Script.sol"; -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; import { DummyCaller } from "scripts/libraries/DummyCaller.sol"; -import { SemverComp } from "src/libraries/SemverComp.sol"; -import { Constants } from "src/libraries/Constants.sol"; contract UpgradeSuperchainConfig is Script { struct Input { @@ -25,8 +22,6 @@ contract UpgradeSuperchainConfig is Script { address opcm = _input.opcm; - bool isOPCMv2 = SemverComp.gte(IOPContractsManager(opcm).version(), Constants.OPCM_V2_MIN_VERSION); - // Etch DummyCaller contract. This contract is used to mimic the contract that is used // as the source of the delegatecall to the OPCM. In practice this will be the governance // 2/2 or similar. @@ -41,7 +36,7 @@ contract UpgradeSuperchainConfig is Script { // Call into the DummyCaller. This will perform the delegatecall under the hood. // The DummyCaller uses a fallback that reverts on failure, so no need to check success. vm.broadcast(msg.sender); - _upgrade(prank, isOPCMv2, _input); + _upgrade(prank, _input); } /// @notice Asserts that the input is valid. @@ -59,24 +54,17 @@ contract UpgradeSuperchainConfig is Script { return type(DummyCaller).runtimeCode; } - /// @notice Helper function to upgrade the OPCM based on the OPCM version. Performs the decoding of the upgrade - /// input and the delegatecall to the OPCM. + /// @notice Helper function to upgrade the superchain config. Performs the delegatecall to the OPCM. /// @param _prank The address of the dummy caller contract. - /// @param _isOPCMv2 Whether to use OPCM v2. /// @param _input The input. - function _upgrade(address _prank, bool _isOPCMv2, Input memory _input) internal { - bytes memory data; - if (_isOPCMv2) { - data = abi.encodeCall( - IOPContractsManagerV2.upgradeSuperchain, - IOPContractsManagerV2.SuperchainUpgradeInput({ - superchainConfig: _input.superchainConfig, - extraInstructions: _input.extraInstructions - }) - ); - } else { - data = abi.encodeCall(IOPContractsManager.upgradeSuperchainConfig, _input.superchainConfig); - } + function _upgrade(address _prank, Input memory _input) internal { + bytes memory data = abi.encodeCall( + IOPContractsManagerV2.upgradeSuperchain, + IOPContractsManagerV2.SuperchainUpgradeInput({ + superchainConfig: _input.superchainConfig, + extraInstructions: _input.extraInstructions + }) + ); (bool success, bytes memory returnData) = _prank.call(data); if (!success) { assembly { diff --git a/packages/contracts-bedrock/scripts/deploy/VerifyOPCM.s.sol b/packages/contracts-bedrock/scripts/deploy/VerifyOPCM.s.sol index b5e6e926272..21a3879304b 100644 --- a/packages/contracts-bedrock/scripts/deploy/VerifyOPCM.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/VerifyOPCM.s.sol @@ -13,11 +13,10 @@ import { Process } from "scripts/libraries/Process.sol"; import { Config } from "scripts/libraries/Config.sol"; import { Bytes } from "src/libraries/Bytes.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; -import { SemverComp } from "src/libraries/SemverComp.sol"; import { Constants } from "src/libraries/Constants.sol"; // Interfaces -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; +import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol"; import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; import { IMIPS64 } from "interfaces/cannon/IMIPS64.sol"; @@ -170,7 +169,6 @@ contract VerifyOPCM is Script { function setUp() public { // Overrides for situations where field names do not cleanly map to contract names. fieldNameOverrides["optimismPortalImpl"] = "OptimismPortal2"; - fieldNameOverrides["optimismPortalInteropImpl"] = "OptimismPortalInterop"; fieldNameOverrides["mipsImpl"] = "MIPS64"; fieldNameOverrides["ethLockboxImpl"] = "ETHLockbox"; fieldNameOverrides["faultDisputeGameImpl"] = "FaultDisputeGame"; @@ -202,13 +200,6 @@ contract VerifyOPCM is Script { fieldNameOverrides["opcmV2"] = "OPContractsManagerV2"; fieldNameOverrides["opcmUtils"] = "OPContractsManagerUtils"; - // Overrides for situations where contracts have differently named source files. - sourceNameOverrides["OPContractsManagerGameTypeAdder"] = "OPContractsManager"; - sourceNameOverrides["OPContractsManagerDeployer"] = "OPContractsManager"; - sourceNameOverrides["OPContractsManagerUpgrader"] = "OPContractsManager"; - sourceNameOverrides["OPContractsManagerInteropMigrator"] = "OPContractsManager"; - sourceNameOverrides["OPContractsManagerContractsContainer"] = "OPContractsManager"; - // Expected getter functions and their verification methods. // CRITICAL: Any getter in the ABI that's not in this list will cause verification to fail. // NEVER add a getter without understanding HOW it's being verified! @@ -243,7 +234,6 @@ contract VerifyOPCM is Script { // Implementation addresses - verify against Container validatorGetterChecks["l1ERC721BridgeImpl"] = "CONTAINER_IMPL"; validatorGetterChecks["optimismPortalImpl"] = "CONTAINER_IMPL"; - validatorGetterChecks["optimismPortalInteropImpl"] = "CONTAINER_IMPL"; validatorGetterChecks["ethLockboxImpl"] = "CONTAINER_IMPL"; validatorGetterChecks["systemConfigImpl"] = "CONTAINER_IMPL"; validatorGetterChecks["optimismMintableERC20FactoryImpl"] = "CONTAINER_IMPL"; @@ -297,7 +287,7 @@ contract VerifyOPCM is Script { // This function is used as part of the release checklist to verify new contracts. // Rather than requiring an opcm input parameter, just pass in an empty reference // as we really only need this for features that are in development. - IOPContractsManager emptyOpcm = IOPContractsManager(address(0)); + IOPContractsManagerV2 emptyOpcm = IOPContractsManagerV2(address(0)); _verifyOpcmContractRef( emptyOpcm, OpcmContractRef({ field: _name, name: _name, addr: _addr, blueprint: false }), @@ -322,7 +312,7 @@ contract VerifyOPCM is Script { } // Fetch Implementations & Blueprints from OPCM - IOPContractsManager opcm = IOPContractsManager(_opcmAddress); + IOPContractsManagerV2 opcm = IOPContractsManagerV2(_opcmAddress); // Validate that all ABI getters are accounted for. _validateAllGettersAccounted(); @@ -352,7 +342,7 @@ contract VerifyOPCM is Script { /// @notice Collects all the references from the OPCM contract. /// @param _opcm The live OPCM contract. /// @return Array of OpcmContractRef structs containing contract names/addresses. - function _collectOpcmContractRefs(IOPContractsManager _opcm) internal returns (OpcmContractRef[] memory) { + function _collectOpcmContractRefs(IOPContractsManagerV2 _opcm) internal returns (OpcmContractRef[] memory) { // Collect property references. OpcmContractRef[] memory propRefs = _getOpcmPropertyRefs(_opcm); if (propRefs.length == 0) { @@ -396,7 +386,7 @@ contract VerifyOPCM is Script { refs[0] = OpcmContractRef({ field: "opcm", name: _opcmContractName(), addr: address(_opcm), blueprint: false }); refs[1] = OpcmContractRef({ field: "contractsContainer", - name: _isOPCMV2() ? "OPContractsManagerContainer" : "OPContractsManagerContractsContainer", + name: "OPContractsManagerContainer", addr: contractsContainerAddr, blueprint: false }); @@ -587,7 +577,7 @@ contract VerifyOPCM is Script { /// @param _skipConstructorVerification Whether to skip constructor verification. /// @return True if the contract reference is verified, false otherwise. function _verifyOpcmContractRef( - IOPContractsManager _opcm, + IOPContractsManagerV2 _opcm, OpcmContractRef memory _target, bool _skipConstructorVerification ) @@ -696,7 +686,7 @@ contract VerifyOPCM is Script { // If this is the OPCM contract itself, verify the immutable variables as well. if (keccak256(bytes(_target.field)) == keccak256(bytes("opcm"))) { - success = _verifyOpcmImmutableVariables(IOPContractsManager(_target.addr)) && success; + success = _verifyOpcmImmutableVariables(IOPContractsManagerV2(_target.addr)) && success; } // Log final status for this field. @@ -746,7 +736,7 @@ contract VerifyOPCM is Script { /// @notice Checks if super dispute games feature is enabled in the dev feature bitmap. /// @param _opcm The OPContractsManager to check. /// @return True if super dispute games are enabled. - function _isSuperDisputeGamesEnabled(IOPContractsManager _opcm) internal view returns (bool) { + function _isSuperDisputeGamesEnabled(IOPContractsManagerV2 _opcm) internal view returns (bool) { bytes32 bitmap = _opcm.devFeatureBitmap(); return DevFeatures.isDevFeatureEnabled(bitmap, DevFeatures.OPTIMISM_PORTAL_INTEROP) || DevFeatures.isDevFeatureEnabled(bitmap, DevFeatures.SUPER_ROOT_GAMES_MIGRATION); @@ -763,7 +753,7 @@ contract VerifyOPCM is Script { /// @notice Verifies that the immutable variables in the OPCM contract match expected values. /// @param _opcm The OPCM contract to verify immutable variables for. /// @return True if all immutable variables are verified, false otherwise. - function _verifyOpcmImmutableVariables(IOPContractsManager _opcm) internal returns (bool) { + function _verifyOpcmImmutableVariables(IOPContractsManagerV2 _opcm) internal returns (bool) { console.log(" Verifying OPCM immutable variables..."); bool success = true; @@ -942,7 +932,7 @@ contract VerifyOPCM is Script { /// references to other OPCM contracts. /// @param _opcm The live OPCM contract. /// @return Array of OpcmContractRef structs containing contract names/addresses. - function _getOpcmPropertyRefs(IOPContractsManager _opcm) internal returns (OpcmContractRef[] memory) { + function _getOpcmPropertyRefs(IOPContractsManagerV2 _opcm) internal returns (OpcmContractRef[] memory) { // Find all functions that start with "opcm". string[] memory functionNames = abi.decode( vm.parseJson( @@ -991,7 +981,7 @@ contract VerifyOPCM is Script { /// @param _blueprint Whether this is a blueprint or an implementation. /// @return Array of OpcmContractRef structs containing contract names/addresses. function _getOpcmContractRefs( - IOPContractsManager _opcm, + IOPContractsManagerV2 _opcm, string memory _property, bool _blueprint ) @@ -1052,7 +1042,7 @@ contract VerifyOPCM is Script { /// @return The contract name. function _getContractNameFromFieldName(string memory _fieldName) internal view returns (string memory) { if (LibString.eq(_fieldName, "contractsContainer")) { - _fieldName = _isOPCMV2() ? "contractsContainerV2" : "contractsContainerV1"; + _fieldName = "contractsContainerV2"; } // Check for an explicit override @@ -1189,7 +1179,7 @@ contract VerifyOPCM is Script { /// @notice Validates that the dev feature bitmap is empty on mainnet. /// @param _opcm The OPCM contract. - function _validateDevFeatureBitmap(IOPContractsManager _opcm) internal view { + function _validateDevFeatureBitmap(IOPContractsManagerV2 _opcm) internal view { // Get the dev feature bitmap. bytes32 devFeatureBitmap = _opcm.devFeatureBitmap(); @@ -1233,26 +1223,10 @@ contract VerifyOPCM is Script { } } - /// @notice Returns the name of the OPCM contract depending on whether the OPCM is V2. + /// @notice Returns the name of the OPCM contract. /// @return The name of the OPCM contract. - function _opcmContractName() internal view returns (string memory) { - return _isOPCMV2() ? "OPContractsManagerV2" : "OPContractsManager"; - } - - /// @notice Checks if the OPCM is V2. - /// @dev If the OPCM address is not set, default to false. - /// @return True if the OPCM is V2, false otherwise. - function _isOPCMV2() internal view returns (bool) { - // Get the OPCM contract address from the environment variables. - address opcmAddress = _getOPCMAddress(); - - // If the OPCM contract address is not set, default to V1. - if (opcmAddress == address(0)) { - return false; - } - - // If the OPCM contract version is greater than or equal to 7.0.0, then it is OPCM V2. - return SemverComp.gte(IOPContractsManager(opcmAddress).version(), Constants.OPCM_V2_MIN_VERSION); + function _opcmContractName() internal pure returns (string memory) { + return "OPContractsManagerV2"; } /// @notice Gets the address of the OPCM contract from the environment variables. @@ -1269,7 +1243,7 @@ contract VerifyOPCM is Script { /// @param _artifact The artifact info for the contract. /// @return True if all security-critical values are correct. function _verifySecurityCriticalValues( - IOPContractsManager _opcm, + IOPContractsManagerV2 _opcm, OpcmContractRef memory _target, ArtifactInfo memory _artifact ) @@ -1292,7 +1266,7 @@ contract VerifyOPCM is Script { } // OptimismPortal2: Verify PROOF_MATURITY_DELAY_SECONDS - if (LibString.eq(_target.name, "OptimismPortal2") || LibString.eq(_target.name, "OptimismPortalInterop")) { + if (LibString.eq(_target.name, "OptimismPortal2")) { success = _verifyPortalDelays(IOptimismPortal2(payable(_target.addr))) && success; } @@ -1371,7 +1345,7 @@ contract VerifyOPCM is Script { /// @param _opcm The OPCM contract. /// @param _validator The StandardValidator contract address. /// @return True if all getters are valid. - function _verifyStandardValidatorArgs(IOPContractsManager _opcm, address _validator) internal returns (bool) { + function _verifyStandardValidatorArgs(IOPContractsManagerV2 _opcm, address _validator) internal returns (bool) { bool success = true; console.log(" Verifying StandardValidator args..."); diff --git a/packages/contracts-bedrock/scripts/libraries/Config.sol b/packages/contracts-bedrock/scripts/libraries/Config.sol index 99a9b51f00d..7099f00f1e5 100644 --- a/packages/contracts-bedrock/scripts/libraries/Config.sol +++ b/packages/contracts-bedrock/scripts/libraries/Config.sol @@ -88,12 +88,8 @@ library Config { /// @notice Returns the path on the local filesystem where the deploy config is function deployConfigPath() internal view returns (string memory env_) { - if (vm.isContext(VmSafe.ForgeContext.TestGroup)) { - env_ = string.concat(vm.projectRoot(), "/deploy-config/hardhat.json"); - } else { - env_ = vm.envOr("DEPLOY_CONFIG_PATH", string("")); - require(bytes(env_).length > 0, "Config: must set DEPLOY_CONFIG_PATH to filesystem path of deploy config"); - } + env_ = vm.envOr("DEPLOY_CONFIG_PATH", string("")); + require(bytes(env_).length > 0, "Config: must set DEPLOY_CONFIG_PATH to filesystem path of deploy config"); } /// @notice Returns the chainid from the EVM context or the value of the CHAIN_ID env var as @@ -313,11 +309,6 @@ library Config { return vm.envOr("DEV_FEATURE__OPTIMISM_PORTAL_INTEROP", false); } - /// @notice Returns true if the development feature opcm_v2 is enabled. - function devFeatureOpcmV2() internal view returns (bool) { - return vm.envOr("DEV_FEATURE__OPCM_V2", false); - } - /// @notice Returns true if the development feature l2cm is enabled. function devFeatureL2CM() internal view returns (bool) { return vm.envOr("DEV_FEATURE__L2CM", false); @@ -342,4 +333,9 @@ library Config { function sysFeatureCustomGasToken() internal view returns (bool) { return vm.envOr("SYS_FEATURE__CUSTOM_GAS_TOKEN", false); } + + /// @notice Returns true if running in kontrol context. + function isKontrolContext() internal view returns (bool) { + return vm.envOr("KONTROL_CONTEXT", false); + } } diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json deleted file mode 100644 index 3b5c00dccc2..00000000000 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json +++ /dev/null @@ -1,1143 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "contract OPContractsManagerGameTypeAdder", - "name": "_opcmGameTypeAdder", - "type": "address" - }, - { - "internalType": "contract OPContractsManagerDeployer", - "name": "_opcmDeployer", - "type": "address" - }, - { - "internalType": "contract OPContractsManagerUpgrader", - "name": "_opcmUpgrader", - "type": "address" - }, - { - "internalType": "contract OPContractsManagerInteropMigrator", - "name": "_opcmInteropMigrator", - "type": "address" - }, - { - "internalType": "contract OPContractsManagerStandardValidator", - "name": "_opcmStandardValidator", - "type": "address" - }, - { - "internalType": "contract ISuperchainConfig", - "name": "_superchainConfig", - "type": "address" - }, - { - "internalType": "contract IProtocolVersions", - "name": "_protocolVersions", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "string", - "name": "saltMixer", - "type": "string" - }, - { - "internalType": "contract ISystemConfig", - "name": "systemConfig", - "type": "address" - }, - { - "internalType": "contract IDelayedWETH", - "name": "delayedWETH", - "type": "address" - }, - { - "internalType": "GameType", - "name": "disputeGameType", - "type": "uint32" - }, - { - "internalType": "Claim", - "name": "disputeAbsolutePrestate", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "disputeMaxGameDepth", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "disputeSplitDepth", - "type": "uint256" - }, - { - "internalType": "Duration", - "name": "disputeClockExtension", - "type": "uint64" - }, - { - "internalType": "Duration", - "name": "disputeMaxClockDuration", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "initialBond", - "type": "uint256" - }, - { - "internalType": "contract IBigStepper", - "name": "vm", - "type": "address" - }, - { - "internalType": "bool", - "name": "permissioned", - "type": "bool" - } - ], - "internalType": "struct OPContractsManager.AddGameInput[]", - "name": "_gameConfigs", - "type": "tuple[]" - } - ], - "name": "addGameType", - "outputs": [ - { - "components": [ - { - "internalType": "contract IDelayedWETH", - "name": "delayedWETH", - "type": "address" - }, - { - "internalType": "contract IFaultDisputeGame", - "name": "faultDisputeGame", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.AddGameOutput[]", - "name": "", - "type": "tuple[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "blueprints", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "addressManager", - "type": "address" - }, - { - "internalType": "address", - "name": "proxy", - "type": "address" - }, - { - "internalType": "address", - "name": "proxyAdmin", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ChugSplashProxy", - "type": "address" - }, - { - "internalType": "address", - "name": "resolvedDelegateProxy", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Blueprints", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_l2ChainId", - "type": "uint256" - } - ], - "name": "chainIdToBatchInboxAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "address", - "name": "opChainProxyAdminOwner", - "type": "address" - }, - { - "internalType": "address", - "name": "systemConfigOwner", - "type": "address" - }, - { - "internalType": "address", - "name": "batcher", - "type": "address" - }, - { - "internalType": "address", - "name": "unsafeBlockSigner", - "type": "address" - }, - { - "internalType": "address", - "name": "proposer", - "type": "address" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Roles", - "name": "roles", - "type": "tuple" - }, - { - "internalType": "uint32", - "name": "basefeeScalar", - "type": "uint32" - }, - { - "internalType": "uint32", - "name": "blobBasefeeScalar", - "type": "uint32" - }, - { - "internalType": "uint256", - "name": "l2ChainId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "startingAnchorRoot", - "type": "bytes" - }, - { - "internalType": "string", - "name": "saltMixer", - "type": "string" - }, - { - "internalType": "uint64", - "name": "gasLimit", - "type": "uint64" - }, - { - "internalType": "GameType", - "name": "disputeGameType", - "type": "uint32" - }, - { - "internalType": "Claim", - "name": "disputeAbsolutePrestate", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "disputeMaxGameDepth", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "disputeSplitDepth", - "type": "uint256" - }, - { - "internalType": "Duration", - "name": "disputeClockExtension", - "type": "uint64" - }, - { - "internalType": "Duration", - "name": "disputeMaxClockDuration", - "type": "uint64" - }, - { - "internalType": "bool", - "name": "useCustomGasToken", - "type": "bool" - } - ], - "internalType": "struct OPContractsManager.DeployInput", - "name": "_input", - "type": "tuple" - } - ], - "name": "deploy", - "outputs": [ - { - "components": [ - { - "internalType": "contract IProxyAdmin", - "name": "opChainProxyAdmin", - "type": "address" - }, - { - "internalType": "contract IAddressManager", - "name": "addressManager", - "type": "address" - }, - { - "internalType": "contract IL1ERC721Bridge", - "name": "l1ERC721BridgeProxy", - "type": "address" - }, - { - "internalType": "contract ISystemConfig", - "name": "systemConfigProxy", - "type": "address" - }, - { - "internalType": "contract IOptimismMintableERC20Factory", - "name": "optimismMintableERC20FactoryProxy", - "type": "address" - }, - { - "internalType": "contract IL1StandardBridge", - "name": "l1StandardBridgeProxy", - "type": "address" - }, - { - "internalType": "contract IL1CrossDomainMessenger", - "name": "l1CrossDomainMessengerProxy", - "type": "address" - }, - { - "internalType": "contract IETHLockbox", - "name": "ethLockboxProxy", - "type": "address" - }, - { - "internalType": "contract IOptimismPortal2", - "name": "optimismPortalProxy", - "type": "address" - }, - { - "internalType": "contract IDisputeGameFactory", - "name": "disputeGameFactoryProxy", - "type": "address" - }, - { - "internalType": "contract IAnchorStateRegistry", - "name": "anchorStateRegistryProxy", - "type": "address" - }, - { - "internalType": "contract IFaultDisputeGame", - "name": "faultDisputeGame", - "type": "address" - }, - { - "internalType": "contract IPermissionedDisputeGame", - "name": "permissionedDisputeGame", - "type": "address" - }, - { - "internalType": "contract IDelayedWETH", - "name": "delayedWETHPermissionedGameProxy", - "type": "address" - }, - { - "internalType": "contract IDelayedWETH", - "name": "delayedWETHPermissionlessGameProxy", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.DeployOutput", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "devFeatureBitmap", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementations", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "superchainConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "protocolVersionsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ERC721BridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalInteropImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "ethLockboxImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "systemConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismMintableERC20FactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1CrossDomainMessengerImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1StandardBridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "disputeGameFactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "anchorStateRegistryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "delayedWETHImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "mipsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "faultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "permissionedDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superFaultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superPermissionedDisputeGameImpl", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Implementations", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_feature", - "type": "bytes32" - } - ], - "name": "isDevFeatureEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "usePermissionlessGame", - "type": "bool" - }, - { - "components": [ - { - "internalType": "Hash", - "name": "root", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "l2SequenceNumber", - "type": "uint256" - } - ], - "internalType": "struct Proposal", - "name": "startingAnchorRoot", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "address", - "name": "proposer", - "type": "address" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "internalType": "uint256", - "name": "maxGameDepth", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "splitDepth", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "initBond", - "type": "uint256" - }, - { - "internalType": "Duration", - "name": "clockExtension", - "type": "uint64" - }, - { - "internalType": "Duration", - "name": "maxClockDuration", - "type": "uint64" - } - ], - "internalType": "struct OPContractsManagerInteropMigrator.GameParameters", - "name": "gameParameters", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "contract ISystemConfig", - "name": "systemConfigProxy", - "type": "address" - }, - { - "internalType": "Claim", - "name": "cannonPrestate", - "type": "bytes32" - }, - { - "internalType": "Claim", - "name": "cannonKonaPrestate", - "type": "bytes32" - } - ], - "internalType": "struct OPContractsManager.OpChainConfig[]", - "name": "opChainConfigs", - "type": "tuple[]" - } - ], - "internalType": "struct OPContractsManagerInteropMigrator.MigrateInput", - "name": "_input", - "type": "tuple" - } - ], - "name": "migrate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "opcmDeployer", - "outputs": [ - { - "internalType": "contract OPContractsManagerDeployer", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "opcmGameTypeAdder", - "outputs": [ - { - "internalType": "contract OPContractsManagerGameTypeAdder", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "opcmInteropMigrator", - "outputs": [ - { - "internalType": "contract OPContractsManagerInteropMigrator", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "opcmStandardValidator", - "outputs": [ - { - "internalType": "contract OPContractsManagerStandardValidator", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "opcmUpgrader", - "outputs": [ - { - "internalType": "contract OPContractsManagerUpgrader", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "protocolVersions", - "outputs": [ - { - "internalType": "contract IProtocolVersions", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "superchainConfig", - "outputs": [ - { - "internalType": "contract ISuperchainConfig", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract ISystemConfig", - "name": "systemConfigProxy", - "type": "address" - }, - { - "internalType": "Claim", - "name": "cannonPrestate", - "type": "bytes32" - }, - { - "internalType": "Claim", - "name": "cannonKonaPrestate", - "type": "bytes32" - } - ], - "internalType": "struct OPContractsManager.UpdatePrestateInput[]", - "name": "_prestateUpdateInputs", - "type": "tuple[]" - } - ], - "name": "updatePrestate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract ISystemConfig", - "name": "systemConfigProxy", - "type": "address" - }, - { - "internalType": "Claim", - "name": "cannonPrestate", - "type": "bytes32" - }, - { - "internalType": "Claim", - "name": "cannonKonaPrestate", - "type": "bytes32" - } - ], - "internalType": "struct OPContractsManager.OpChainConfig[]", - "name": "_opChainConfigs", - "type": "tuple[]" - } - ], - "name": "upgrade", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract ISuperchainConfig", - "name": "_superchainConfig", - "type": "address" - } - ], - "name": "upgradeSuperchainConfig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract ISystemConfig", - "name": "sysCfg", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "absolutePrestate", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "l2ChainID", - "type": "uint256" - }, - { - "internalType": "address", - "name": "proposer", - "type": "address" - } - ], - "internalType": "struct OPContractsManagerStandardValidator.ValidationInput", - "name": "_input", - "type": "tuple" - }, - { - "internalType": "bool", - "name": "_allowFailure", - "type": "bool" - } - ], - "name": "validate", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract ISystemConfig", - "name": "sysCfg", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "cannonPrestate", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "cannonKonaPrestate", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "l2ChainID", - "type": "uint256" - }, - { - "internalType": "address", - "name": "proposer", - "type": "address" - } - ], - "internalType": "struct OPContractsManagerStandardValidator.ValidationInputDev", - "name": "_input", - "type": "tuple" - }, - { - "internalType": "bool", - "name": "_allowFailure", - "type": "bool" - } - ], - "name": "validate", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract ISystemConfig", - "name": "sysCfg", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "absolutePrestate", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "l2ChainID", - "type": "uint256" - }, - { - "internalType": "address", - "name": "proposer", - "type": "address" - } - ], - "internalType": "struct OPContractsManagerStandardValidator.ValidationInput", - "name": "_input", - "type": "tuple" - }, - { - "internalType": "bool", - "name": "_allowFailure", - "type": "bool" - }, - { - "components": [ - { - "internalType": "address", - "name": "l1PAOMultisig", - "type": "address" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - } - ], - "internalType": "struct OPContractsManagerStandardValidator.ValidationOverrides", - "name": "_overrides", - "type": "tuple" - } - ], - "name": "validateWithOverrides", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract ISystemConfig", - "name": "sysCfg", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "cannonPrestate", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "cannonKonaPrestate", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "l2ChainID", - "type": "uint256" - }, - { - "internalType": "address", - "name": "proposer", - "type": "address" - } - ], - "internalType": "struct OPContractsManagerStandardValidator.ValidationInputDev", - "name": "_input", - "type": "tuple" - }, - { - "internalType": "bool", - "name": "_allowFailure", - "type": "bool" - }, - { - "components": [ - { - "internalType": "address", - "name": "l1PAOMultisig", - "type": "address" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - } - ], - "internalType": "struct OPContractsManagerStandardValidator.ValidationOverrides", - "name": "_overrides", - "type": "tuple" - } - ], - "name": "validateWithOverrides", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "who", - "type": "address" - } - ], - "name": "AddressHasNoCode", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "who", - "type": "address" - } - ], - "name": "AddressNotFound", - "type": "error" - }, - { - "inputs": [], - "name": "AlreadyReleased", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidChainId", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "devFeature", - "type": "bytes32" - } - ], - "name": "InvalidDevFeatureAccess", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidGameConfigs", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "role", - "type": "string" - } - ], - "name": "InvalidRoleAddress", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidStartingAnchorRoot", - "type": "error" - }, - { - "inputs": [], - "name": "LatestReleaseNotSet", - "type": "error" - }, - { - "inputs": [], - "name": "OPContractsManager_V2Enabled", - "type": "error" - }, - { - "inputs": [], - "name": "OnlyDelegatecall", - "type": "error" - }, - { - "inputs": [], - "name": "PrestateNotSet", - "type": "error" - }, - { - "inputs": [], - "name": "PrestateRequired", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "contract ISystemConfig", - "name": "systemConfig", - "type": "address" - } - ], - "name": "SuperchainConfigMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "SuperchainProxyAdminMismatch", - "type": "error" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerContainer.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerContainer.json index 7907cfda080..67171bfb9ce 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerContainer.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerContainer.json @@ -55,11 +55,6 @@ "name": "optimismPortalImpl", "type": "address" }, - { - "internalType": "address", - "name": "optimismPortalInteropImpl", - "type": "address" - }, { "internalType": "address", "name": "ethLockboxImpl", @@ -223,11 +218,6 @@ "name": "optimismPortalImpl", "type": "address" }, - { - "internalType": "address", - "name": "optimismPortalInteropImpl", - "type": "address" - }, { "internalType": "address", "name": "ethLockboxImpl", diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerContractsContainer.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerContractsContainer.json deleted file mode 100644 index f6732e88a1f..00000000000 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerContractsContainer.json +++ /dev/null @@ -1,337 +0,0 @@ -[ - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "addressManager", - "type": "address" - }, - { - "internalType": "address", - "name": "proxy", - "type": "address" - }, - { - "internalType": "address", - "name": "proxyAdmin", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ChugSplashProxy", - "type": "address" - }, - { - "internalType": "address", - "name": "resolvedDelegateProxy", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Blueprints", - "name": "_blueprints", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "address", - "name": "superchainConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "protocolVersionsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ERC721BridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalInteropImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "ethLockboxImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "systemConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismMintableERC20FactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1CrossDomainMessengerImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1StandardBridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "disputeGameFactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "anchorStateRegistryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "delayedWETHImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "mipsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "faultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "permissionedDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superFaultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superPermissionedDisputeGameImpl", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Implementations", - "name": "_implementations", - "type": "tuple" - }, - { - "internalType": "bytes32", - "name": "_devFeatureBitmap", - "type": "bytes32" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "_isTestingEnvironment", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blueprints", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "addressManager", - "type": "address" - }, - { - "internalType": "address", - "name": "proxy", - "type": "address" - }, - { - "internalType": "address", - "name": "proxyAdmin", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ChugSplashProxy", - "type": "address" - }, - { - "internalType": "address", - "name": "resolvedDelegateProxy", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Blueprints", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "devFeatureBitmap", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementations", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "superchainConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "protocolVersionsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ERC721BridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalInteropImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "ethLockboxImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "systemConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismMintableERC20FactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1CrossDomainMessengerImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1StandardBridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "disputeGameFactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "anchorStateRegistryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "delayedWETHImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "mipsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "faultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "permissionedDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superFaultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superPermissionedDisputeGameImpl", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Implementations", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_feature", - "type": "bytes32" - } - ], - "name": "isDevFeatureEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "OPContractsManagerContractsContainer_DevFeatureInProd", - "type": "error" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerDeployer.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerDeployer.json deleted file mode 100644 index f7813afc55c..00000000000 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerDeployer.json +++ /dev/null @@ -1,559 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "contract OPContractsManagerContractsContainer", - "name": "_contractsContainer", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_who", - "type": "address" - } - ], - "name": "assertValidContractAddress", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blueprints", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "addressManager", - "type": "address" - }, - { - "internalType": "address", - "name": "proxy", - "type": "address" - }, - { - "internalType": "address", - "name": "proxyAdmin", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ChugSplashProxy", - "type": "address" - }, - { - "internalType": "address", - "name": "resolvedDelegateProxy", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Blueprints", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_l2ChainId", - "type": "uint256" - } - ], - "name": "chainIdToBatchInboxAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "contractsContainer", - "outputs": [ - { - "internalType": "contract OPContractsManagerContractsContainer", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "components": [ - { - "internalType": "address", - "name": "opChainProxyAdminOwner", - "type": "address" - }, - { - "internalType": "address", - "name": "systemConfigOwner", - "type": "address" - }, - { - "internalType": "address", - "name": "batcher", - "type": "address" - }, - { - "internalType": "address", - "name": "unsafeBlockSigner", - "type": "address" - }, - { - "internalType": "address", - "name": "proposer", - "type": "address" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Roles", - "name": "roles", - "type": "tuple" - }, - { - "internalType": "uint32", - "name": "basefeeScalar", - "type": "uint32" - }, - { - "internalType": "uint32", - "name": "blobBasefeeScalar", - "type": "uint32" - }, - { - "internalType": "uint256", - "name": "l2ChainId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "startingAnchorRoot", - "type": "bytes" - }, - { - "internalType": "string", - "name": "saltMixer", - "type": "string" - }, - { - "internalType": "uint64", - "name": "gasLimit", - "type": "uint64" - }, - { - "internalType": "GameType", - "name": "disputeGameType", - "type": "uint32" - }, - { - "internalType": "Claim", - "name": "disputeAbsolutePrestate", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "disputeMaxGameDepth", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "disputeSplitDepth", - "type": "uint256" - }, - { - "internalType": "Duration", - "name": "disputeClockExtension", - "type": "uint64" - }, - { - "internalType": "Duration", - "name": "disputeMaxClockDuration", - "type": "uint64" - }, - { - "internalType": "bool", - "name": "useCustomGasToken", - "type": "bool" - } - ], - "internalType": "struct OPContractsManager.DeployInput", - "name": "_input", - "type": "tuple" - }, - { - "internalType": "contract ISuperchainConfig", - "name": "_superchainConfig", - "type": "address" - }, - { - "internalType": "address", - "name": "_deployer", - "type": "address" - } - ], - "name": "deploy", - "outputs": [ - { - "components": [ - { - "internalType": "contract IProxyAdmin", - "name": "opChainProxyAdmin", - "type": "address" - }, - { - "internalType": "contract IAddressManager", - "name": "addressManager", - "type": "address" - }, - { - "internalType": "contract IL1ERC721Bridge", - "name": "l1ERC721BridgeProxy", - "type": "address" - }, - { - "internalType": "contract ISystemConfig", - "name": "systemConfigProxy", - "type": "address" - }, - { - "internalType": "contract IOptimismMintableERC20Factory", - "name": "optimismMintableERC20FactoryProxy", - "type": "address" - }, - { - "internalType": "contract IL1StandardBridge", - "name": "l1StandardBridgeProxy", - "type": "address" - }, - { - "internalType": "contract IL1CrossDomainMessenger", - "name": "l1CrossDomainMessengerProxy", - "type": "address" - }, - { - "internalType": "contract IETHLockbox", - "name": "ethLockboxProxy", - "type": "address" - }, - { - "internalType": "contract IOptimismPortal2", - "name": "optimismPortalProxy", - "type": "address" - }, - { - "internalType": "contract IDisputeGameFactory", - "name": "disputeGameFactoryProxy", - "type": "address" - }, - { - "internalType": "contract IAnchorStateRegistry", - "name": "anchorStateRegistryProxy", - "type": "address" - }, - { - "internalType": "contract IFaultDisputeGame", - "name": "faultDisputeGame", - "type": "address" - }, - { - "internalType": "contract IPermissionedDisputeGame", - "name": "permissionedDisputeGame", - "type": "address" - }, - { - "internalType": "contract IDelayedWETH", - "name": "delayedWETHPermissionedGameProxy", - "type": "address" - }, - { - "internalType": "contract IDelayedWETH", - "name": "delayedWETHPermissionlessGameProxy", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.DeployOutput", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "devFeatureBitmap", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementations", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "superchainConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "protocolVersionsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ERC721BridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalInteropImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "ethLockboxImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "systemConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismMintableERC20FactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1CrossDomainMessengerImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1StandardBridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "disputeGameFactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "anchorStateRegistryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "delayedWETHImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "mipsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "faultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "permissionedDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superFaultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superPermissionedDisputeGameImpl", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Implementations", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_feature", - "type": "bytes32" - } - ], - "name": "isDevFeatureEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "l2ChainId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "deployer", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "deployOutput", - "type": "bytes" - } - ], - "name": "Deployed", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "who", - "type": "address" - } - ], - "name": "AddressHasNoCode", - "type": "error" - }, - { - "inputs": [], - "name": "BytesArrayTooLong", - "type": "error" - }, - { - "inputs": [], - "name": "DeploymentFailed", - "type": "error" - }, - { - "inputs": [], - "name": "EmptyInitcode", - "type": "error" - }, - { - "inputs": [], - "name": "IdentityPrecompileCallFailed", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidChainId", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "role", - "type": "string" - } - ], - "name": "InvalidRoleAddress", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidStartingAnchorRoot", - "type": "error" - }, - { - "inputs": [], - "name": "NotABlueprint", - "type": "error" - }, - { - "inputs": [], - "name": "OPContractsManager_InvalidGameType", - "type": "error" - }, - { - "inputs": [], - "name": "ReservedBitsSet", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "UnexpectedPreambleData", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "UnsupportedERCVersion", - "type": "error" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerGameTypeAdder.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerGameTypeAdder.json deleted file mode 100644 index 4aec132f131..00000000000 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerGameTypeAdder.json +++ /dev/null @@ -1,482 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "contract OPContractsManagerContractsContainer", - "name": "_contractsContainer", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "string", - "name": "saltMixer", - "type": "string" - }, - { - "internalType": "contract ISystemConfig", - "name": "systemConfig", - "type": "address" - }, - { - "internalType": "contract IDelayedWETH", - "name": "delayedWETH", - "type": "address" - }, - { - "internalType": "GameType", - "name": "disputeGameType", - "type": "uint32" - }, - { - "internalType": "Claim", - "name": "disputeAbsolutePrestate", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "disputeMaxGameDepth", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "disputeSplitDepth", - "type": "uint256" - }, - { - "internalType": "Duration", - "name": "disputeClockExtension", - "type": "uint64" - }, - { - "internalType": "Duration", - "name": "disputeMaxClockDuration", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "initialBond", - "type": "uint256" - }, - { - "internalType": "contract IBigStepper", - "name": "vm", - "type": "address" - }, - { - "internalType": "bool", - "name": "permissioned", - "type": "bool" - } - ], - "internalType": "struct OPContractsManager.AddGameInput[]", - "name": "_gameConfigs", - "type": "tuple[]" - } - ], - "name": "addGameType", - "outputs": [ - { - "components": [ - { - "internalType": "contract IDelayedWETH", - "name": "delayedWETH", - "type": "address" - }, - { - "internalType": "contract IFaultDisputeGame", - "name": "faultDisputeGame", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.AddGameOutput[]", - "name": "", - "type": "tuple[]" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_who", - "type": "address" - } - ], - "name": "assertValidContractAddress", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blueprints", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "addressManager", - "type": "address" - }, - { - "internalType": "address", - "name": "proxy", - "type": "address" - }, - { - "internalType": "address", - "name": "proxyAdmin", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ChugSplashProxy", - "type": "address" - }, - { - "internalType": "address", - "name": "resolvedDelegateProxy", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Blueprints", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_l2ChainId", - "type": "uint256" - } - ], - "name": "chainIdToBatchInboxAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "contractsContainer", - "outputs": [ - { - "internalType": "contract OPContractsManagerContractsContainer", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "devFeatureBitmap", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementations", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "superchainConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "protocolVersionsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ERC721BridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalInteropImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "ethLockboxImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "systemConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismMintableERC20FactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1CrossDomainMessengerImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1StandardBridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "disputeGameFactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "anchorStateRegistryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "delayedWETHImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "mipsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "faultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "permissionedDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superFaultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superPermissionedDisputeGameImpl", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Implementations", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_feature", - "type": "bytes32" - } - ], - "name": "isDevFeatureEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract ISystemConfig", - "name": "systemConfigProxy", - "type": "address" - }, - { - "internalType": "Claim", - "name": "cannonPrestate", - "type": "bytes32" - }, - { - "internalType": "Claim", - "name": "cannonKonaPrestate", - "type": "bytes32" - } - ], - "internalType": "struct OPContractsManager.UpdatePrestateInput[]", - "name": "_prestateUpdateInputs", - "type": "tuple[]" - } - ], - "name": "updatePrestate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "l2ChainId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "GameType", - "name": "gameType", - "type": "uint32" - }, - { - "indexed": false, - "internalType": "contract IDisputeGame", - "name": "newDisputeGame", - "type": "address" - }, - { - "indexed": false, - "internalType": "contract IDisputeGame", - "name": "oldDisputeGame", - "type": "address" - } - ], - "name": "GameTypeAdded", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "who", - "type": "address" - } - ], - "name": "AddressHasNoCode", - "type": "error" - }, - { - "inputs": [], - "name": "BytesArrayTooLong", - "type": "error" - }, - { - "inputs": [], - "name": "DeploymentFailed", - "type": "error" - }, - { - "inputs": [], - "name": "EmptyInitcode", - "type": "error" - }, - { - "inputs": [], - "name": "IdentityPrecompileCallFailed", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidGameArgsLength", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidGameConfigs", - "type": "error" - }, - { - "inputs": [], - "name": "NotABlueprint", - "type": "error" - }, - { - "inputs": [], - "name": "OPContractsManagerGameTypeAdder_MixedGameTypes", - "type": "error" - }, - { - "inputs": [], - "name": "OPContractsManagerGameTypeAdder_UnsupportedGameType", - "type": "error" - }, - { - "inputs": [], - "name": "OPContractsManager_InvalidGameType", - "type": "error" - }, - { - "inputs": [], - "name": "PrestateRequired", - "type": "error" - }, - { - "inputs": [], - "name": "ReservedBitsSet", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "UnexpectedPreambleData", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "UnsupportedERCVersion", - "type": "error" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInteropMigrator.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInteropMigrator.json deleted file mode 100644 index fcc2d4ad2f6..00000000000 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInteropMigrator.json +++ /dev/null @@ -1,424 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "contract OPContractsManagerContractsContainer", - "name": "_contractsContainer", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_who", - "type": "address" - } - ], - "name": "assertValidContractAddress", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blueprints", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "addressManager", - "type": "address" - }, - { - "internalType": "address", - "name": "proxy", - "type": "address" - }, - { - "internalType": "address", - "name": "proxyAdmin", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ChugSplashProxy", - "type": "address" - }, - { - "internalType": "address", - "name": "resolvedDelegateProxy", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Blueprints", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_l2ChainId", - "type": "uint256" - } - ], - "name": "chainIdToBatchInboxAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "contractsContainer", - "outputs": [ - { - "internalType": "contract OPContractsManagerContractsContainer", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "devFeatureBitmap", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementations", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "superchainConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "protocolVersionsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ERC721BridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalInteropImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "ethLockboxImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "systemConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismMintableERC20FactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1CrossDomainMessengerImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1StandardBridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "disputeGameFactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "anchorStateRegistryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "delayedWETHImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "mipsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "faultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "permissionedDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superFaultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superPermissionedDisputeGameImpl", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Implementations", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_feature", - "type": "bytes32" - } - ], - "name": "isDevFeatureEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "usePermissionlessGame", - "type": "bool" - }, - { - "components": [ - { - "internalType": "Hash", - "name": "root", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "l2SequenceNumber", - "type": "uint256" - } - ], - "internalType": "struct Proposal", - "name": "startingAnchorRoot", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "address", - "name": "proposer", - "type": "address" - }, - { - "internalType": "address", - "name": "challenger", - "type": "address" - }, - { - "internalType": "uint256", - "name": "maxGameDepth", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "splitDepth", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "initBond", - "type": "uint256" - }, - { - "internalType": "Duration", - "name": "clockExtension", - "type": "uint64" - }, - { - "internalType": "Duration", - "name": "maxClockDuration", - "type": "uint64" - } - ], - "internalType": "struct OPContractsManagerInteropMigrator.GameParameters", - "name": "gameParameters", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "contract ISystemConfig", - "name": "systemConfigProxy", - "type": "address" - }, - { - "internalType": "Claim", - "name": "cannonPrestate", - "type": "bytes32" - }, - { - "internalType": "Claim", - "name": "cannonKonaPrestate", - "type": "bytes32" - } - ], - "internalType": "struct OPContractsManager.OpChainConfig[]", - "name": "opChainConfigs", - "type": "tuple[]" - } - ], - "internalType": "struct OPContractsManagerInteropMigrator.MigrateInput", - "name": "_input", - "type": "tuple" - } - ], - "name": "migrate", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "who", - "type": "address" - } - ], - "name": "AddressHasNoCode", - "type": "error" - }, - { - "inputs": [], - "name": "BytesArrayTooLong", - "type": "error" - }, - { - "inputs": [], - "name": "DeploymentFailed", - "type": "error" - }, - { - "inputs": [], - "name": "EmptyInitcode", - "type": "error" - }, - { - "inputs": [], - "name": "IdentityPrecompileCallFailed", - "type": "error" - }, - { - "inputs": [], - "name": "NotABlueprint", - "type": "error" - }, - { - "inputs": [], - "name": "OPContractsManagerInteropMigrator_AbsolutePrestateMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "OPContractsManagerInteropMigrator_ProxyAdminOwnerMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "OPContractsManagerInteropMigrator_SuperchainConfigMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "OPContractsManager_InvalidGameType", - "type": "error" - }, - { - "inputs": [], - "name": "PrestateNotSet", - "type": "error" - }, - { - "inputs": [], - "name": "ReservedBitsSet", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "UnexpectedPreambleData", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "UnsupportedERCVersion", - "type": "error" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerStandardValidator.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerStandardValidator.json index 50514fcab4c..cc6fb61677b 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerStandardValidator.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerStandardValidator.json @@ -13,11 +13,6 @@ "name": "optimismPortalImpl", "type": "address" }, - { - "internalType": "address", - "name": "optimismPortalInteropImpl", - "type": "address" - }, { "internalType": "address", "name": "ethLockboxImpl", @@ -299,19 +294,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "optimismPortalInteropImpl", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [], "name": "permissionedDisputeGameImpl", diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUpgrader.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUpgrader.json deleted file mode 100644 index b232081b693..00000000000 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUpgrader.json +++ /dev/null @@ -1,407 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "contract OPContractsManagerContractsContainer", - "name": "_contractsContainer", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_who", - "type": "address" - } - ], - "name": "assertValidContractAddress", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "blueprints", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "addressManager", - "type": "address" - }, - { - "internalType": "address", - "name": "proxy", - "type": "address" - }, - { - "internalType": "address", - "name": "proxyAdmin", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ChugSplashProxy", - "type": "address" - }, - { - "internalType": "address", - "name": "resolvedDelegateProxy", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Blueprints", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_l2ChainId", - "type": "uint256" - } - ], - "name": "chainIdToBatchInboxAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "contractsContainer", - "outputs": [ - { - "internalType": "contract OPContractsManagerContractsContainer", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "devFeatureBitmap", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "implementations", - "outputs": [ - { - "components": [ - { - "internalType": "address", - "name": "superchainConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "protocolVersionsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1ERC721BridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismPortalInteropImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "ethLockboxImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "systemConfigImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "optimismMintableERC20FactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1CrossDomainMessengerImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "l1StandardBridgeImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "disputeGameFactoryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "anchorStateRegistryImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "delayedWETHImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "mipsImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "faultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "permissionedDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superFaultDisputeGameImpl", - "type": "address" - }, - { - "internalType": "address", - "name": "superPermissionedDisputeGameImpl", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Implementations", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_feature", - "type": "bytes32" - } - ], - "name": "isDevFeatureEnabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "contract ISystemConfig", - "name": "systemConfigProxy", - "type": "address" - }, - { - "internalType": "Claim", - "name": "cannonPrestate", - "type": "bytes32" - }, - { - "internalType": "Claim", - "name": "cannonKonaPrestate", - "type": "bytes32" - } - ], - "internalType": "struct OPContractsManager.OpChainConfig[]", - "name": "_opChainConfigs", - "type": "tuple[]" - } - ], - "name": "upgrade", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract ISuperchainConfig", - "name": "_superchainConfig", - "type": "address" - } - ], - "name": "upgradeSuperchainConfig", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "l2ChainId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "contract ISystemConfig", - "name": "systemConfig", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "upgrader", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "who", - "type": "address" - } - ], - "name": "AddressHasNoCode", - "type": "error" - }, - { - "inputs": [], - "name": "BytesArrayTooLong", - "type": "error" - }, - { - "inputs": [], - "name": "DeploymentFailed", - "type": "error" - }, - { - "inputs": [], - "name": "EmptyInitcode", - "type": "error" - }, - { - "inputs": [], - "name": "IdentityPrecompileCallFailed", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidGameArgsLength", - "type": "error" - }, - { - "inputs": [], - "name": "NotABlueprint", - "type": "error" - }, - { - "inputs": [], - "name": "OPContractsManagerUpgrader_SuperchainConfigAlreadyUpToDate", - "type": "error" - }, - { - "inputs": [], - "name": "OPContractsManagerUpgrader_SuperchainConfigMismatch", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "index", - "type": "uint256" - } - ], - "name": "OPContractsManagerUpgrader_SuperchainConfigNeedsUpgrade", - "type": "error" - }, - { - "inputs": [], - "name": "OPContractsManager_InvalidGameType", - "type": "error" - }, - { - "inputs": [], - "name": "PrestateNotSet", - "type": "error" - }, - { - "inputs": [], - "name": "ReservedBitsSet", - "type": "error" - }, - { - "inputs": [], - "name": "SemverComp_InvalidSemverParts", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "UnexpectedPreambleData", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "UnsupportedERCVersion", - "type": "error" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUtils.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUtils.json index ec7ef5c22dd..cd231961bf0 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUtils.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerUtils.json @@ -245,11 +245,6 @@ "name": "optimismPortalImpl", "type": "address" }, - { - "internalType": "address", - "name": "optimismPortalInteropImpl", - "type": "address" - }, { "internalType": "address", "name": "ethLockboxImpl", diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerV2.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerV2.json index af59d2e866c..bed5faf833d 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerV2.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerV2.json @@ -336,11 +336,6 @@ "name": "optimismPortalImpl", "type": "address" }, - { - "internalType": "address", - "name": "optimismPortalInteropImpl", - "type": "address" - }, { "internalType": "address", "name": "ethLockboxImpl", diff --git a/packages/contracts-bedrock/snapshots/abi/OptimismPortal2.json b/packages/contracts-bedrock/snapshots/abi/OptimismPortal2.json index 9d19d18dbe5..602251f6288 100644 --- a/packages/contracts-bedrock/snapshots/abi/OptimismPortal2.json +++ b/packages/contracts-bedrock/snapshots/abi/OptimismPortal2.json @@ -294,6 +294,11 @@ "internalType": "contract IAnchorStateRegistry", "name": "_anchorStateRegistry", "type": "address" + }, + { + "internalType": "contract IETHLockbox", + "name": "_ethLockbox", + "type": "address" } ], "name": "initialize", @@ -314,6 +319,31 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "migrateLiquidity", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IETHLockbox", + "name": "_newLockbox", + "type": "address" + }, + { + "internalType": "contract IAnchorStateRegistry", + "name": "_newAnchorStateRegistry", + "type": "address" + } + ], + "name": "migrateToSharedDisputeGame", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -627,6 +657,25 @@ "stateMutability": "pure", "type": "function" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "lockbox", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "name": "ETHMigrated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -640,6 +689,37 @@ "name": "Initialized", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract IETHLockbox", + "name": "oldLockbox", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IETHLockbox", + "name": "newLockbox", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IAnchorStateRegistry", + "name": "oldAnchorStateRegistry", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IAnchorStateRegistry", + "name": "newAnchorStateRegistry", + "type": "address" + } + ], + "name": "PortalMigrated", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -794,6 +874,11 @@ "name": "OptimismPortal_InvalidDisputeGame", "type": "error" }, + { + "inputs": [], + "name": "OptimismPortal_InvalidInteropState", + "type": "error" + }, { "inputs": [], "name": "OptimismPortal_InvalidLockboxState", @@ -819,6 +904,11 @@ "name": "OptimismPortal_InvalidRootClaim", "type": "error" }, + { + "inputs": [], + "name": "OptimismPortal_MigratingToSameRegistry", + "type": "error" + }, { "inputs": [], "name": "OptimismPortal_NoReentrancy", @@ -829,6 +919,11 @@ "name": "OptimismPortal_NotAllowedOnCGTMode", "type": "error" }, + { + "inputs": [], + "name": "OptimismPortal_NotUsingInterop", + "type": "error" + }, { "inputs": [], "name": "OptimismPortal_ProofNotOldEnough", diff --git a/packages/contracts-bedrock/snapshots/abi/OptimismPortalInterop.json b/packages/contracts-bedrock/snapshots/abi/OptimismPortalInterop.json deleted file mode 100644 index 88c5cce91cf..00000000000 --- a/packages/contracts-bedrock/snapshots/abi/OptimismPortalInterop.json +++ /dev/null @@ -1,998 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "uint256", - "name": "_proofMaturityDelaySeconds", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "stateMutability": "payable", - "type": "receive" - }, - { - "inputs": [], - "name": "anchorStateRegistry", - "outputs": [ - { - "internalType": "contract IAnchorStateRegistry", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_withdrawalHash", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "_proofSubmitter", - "type": "address" - } - ], - "name": "checkWithdrawal", - "outputs": [], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_value", - "type": "uint256" - }, - { - "internalType": "uint64", - "name": "_gasLimit", - "type": "uint64" - }, - { - "internalType": "bool", - "name": "_isCreation", - "type": "bool" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "depositTransaction", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IDisputeGame", - "name": "_disputeGame", - "type": "address" - } - ], - "name": "disputeGameBlacklist", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "disputeGameFactory", - "outputs": [ - { - "internalType": "contract IDisputeGameFactory", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "disputeGameFinalityDelaySeconds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "donateETH", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "ethLockbox", - "outputs": [ - { - "internalType": "contract IETHLockbox", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct Types.WithdrawalTransaction", - "name": "_tx", - "type": "tuple" - } - ], - "name": "finalizeWithdrawalTransaction", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct Types.WithdrawalTransaction", - "name": "_tx", - "type": "tuple" - }, - { - "internalType": "address", - "name": "_proofSubmitter", - "type": "address" - } - ], - "name": "finalizeWithdrawalTransactionExternalProof", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "name": "finalizedWithdrawals", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "guardian", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "initVersion", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract ISystemConfig", - "name": "_systemConfig", - "type": "address" - }, - { - "internalType": "contract IAnchorStateRegistry", - "name": "_anchorStateRegistry", - "type": "address" - }, - { - "internalType": "contract IETHLockbox", - "name": "_ethLockbox", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "l2Sender", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "migrateLiquidity", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IETHLockbox", - "name": "_newLockbox", - "type": "address" - }, - { - "internalType": "contract IAnchorStateRegistry", - "name": "_newAnchorStateRegistry", - "type": "address" - } - ], - "name": "migrateToSuperRoots", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "_byteCount", - "type": "uint64" - } - ], - "name": "minimumGasLimit", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_withdrawalHash", - "type": "bytes32" - } - ], - "name": "numProofSubmitters", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "params", - "outputs": [ - { - "internalType": "uint128", - "name": "prevBaseFee", - "type": "uint128" - }, - { - "internalType": "uint64", - "name": "prevBoughtGas", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "prevBlockNum", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proofMaturityDelaySeconds", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "proofSubmitters", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct Types.WithdrawalTransaction", - "name": "_tx", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "_disputeGameIndex", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "bytes32", - "name": "version", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "stateRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "messagePasserStorageRoot", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "latestBlockhash", - "type": "bytes32" - } - ], - "internalType": "struct Types.OutputRootProof", - "name": "_outputRootProof", - "type": "tuple" - }, - { - "internalType": "bytes[]", - "name": "_withdrawalProof", - "type": "bytes[]" - } - ], - "name": "proveWithdrawalTransaction", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "provenWithdrawals", - "outputs": [ - { - "internalType": "contract IDisputeGame", - "name": "disputeGameProxy", - "type": "address" - }, - { - "internalType": "uint64", - "name": "timestamp", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxyAdmin", - "outputs": [ - { - "internalType": "contract IProxyAdmin", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "proxyAdminOwner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "respectedGameType", - "outputs": [ - { - "internalType": "GameType", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "respectedGameTypeUpdatedAt", - "outputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "superRootsActive", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "superchainConfig", - "outputs": [ - { - "internalType": "contract ISuperchainConfig", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "systemConfig", - "outputs": [ - { - "internalType": "contract ISystemConfig", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IAnchorStateRegistry", - "name": "_anchorStateRegistry", - "type": "address" - }, - { - "internalType": "contract IETHLockbox", - "name": "_ethLockbox", - "type": "address" - } - ], - "name": "upgrade", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "lockbox", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "ethBalance", - "type": "uint256" - } - ], - "name": "ETHMigrated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "contract IETHLockbox", - "name": "oldLockbox", - "type": "address" - }, - { - "indexed": false, - "internalType": "contract IETHLockbox", - "name": "newLockbox", - "type": "address" - }, - { - "indexed": false, - "internalType": "contract IAnchorStateRegistry", - "name": "oldAnchorStateRegistry", - "type": "address" - }, - { - "indexed": false, - "internalType": "contract IAnchorStateRegistry", - "name": "newAnchorStateRegistry", - "type": "address" - } - ], - "name": "PortalMigrated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "version", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "opaqueData", - "type": "bytes" - } - ], - "name": "TransactionDeposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "withdrawalHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bool", - "name": "success", - "type": "bool" - } - ], - "name": "WithdrawalFinalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "withdrawalHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - } - ], - "name": "WithdrawalProven", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "withdrawalHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "proofSubmitter", - "type": "address" - } - ], - "name": "WithdrawalProvenExtension1", - "type": "event" - }, - { - "inputs": [], - "name": "ContentLengthMismatch", - "type": "error" - }, - { - "inputs": [], - "name": "EmptyItem", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidDataRemainder", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidHeader", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_AlreadyFinalized", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_BadTarget", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_CallPaused", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_CalldataTooLarge", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_GasEstimation", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_GasLimitTooLow", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_ImproperDisputeGame", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_InvalidDisputeGame", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_InvalidMerkleProof", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_InvalidOutputRootProof", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_InvalidProofTimestamp", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_InvalidRootClaim", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_MigratingToSameRegistry", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_NoReentrancy", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_ProofNotOldEnough", - "type": "error" - }, - { - "inputs": [], - "name": "OptimismPortal_Unproven", - "type": "error" - }, - { - "inputs": [], - "name": "OutOfGas", - "type": "error" - }, - { - "inputs": [], - "name": "ProxyAdminOwnedBase_NotProxyAdmin", - "type": "error" - }, - { - "inputs": [], - "name": "ProxyAdminOwnedBase_NotProxyAdminOrProxyAdminOwner", - "type": "error" - }, - { - "inputs": [], - "name": "ProxyAdminOwnedBase_NotProxyAdminOwner", - "type": "error" - }, - { - "inputs": [], - "name": "ProxyAdminOwnedBase_NotResolvedDelegateProxy", - "type": "error" - }, - { - "inputs": [], - "name": "ProxyAdminOwnedBase_NotSharedProxyAdminOwner", - "type": "error" - }, - { - "inputs": [], - "name": "ProxyAdminOwnedBase_ProxyAdminNotFound", - "type": "error" - }, - { - "inputs": [], - "name": "ReinitializableBase_ZeroInitVersion", - "type": "error" - }, - { - "inputs": [], - "name": "UnexpectedList", - "type": "error" - }, - { - "inputs": [], - "name": "UnexpectedString", - "type": "error" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index fd36e74fa98..121443126b0 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -4,8 +4,8 @@ "sourceCodeHash": "0xe772f7db8033e4a738850cb28ac4849d3a454c93732135a8a10d4f7cb498088e" }, "src/L1/ETHLockbox.sol:ETHLockbox": { - "initCodeHash": "0x781079a80d379658eb4553622a9da86f7532ffa424f1e8957a82680ee9435f66", - "sourceCodeHash": "0xf4d9f6adc3d99d65b70df3255976980d36d37f8a4514ecc24d786dd03efdb7be" + "initCodeHash": "0xb2ff8426ab2eb36352f790748963c8e1f7a91caf16bee6a035c2c41bac532836", + "sourceCodeHash": "0x870004d5acc24a704277680f09ccca51a020a512e6c6d48cca583a23a0de43a2" }, "src/L1/FeesDepositor.sol:FeesDepositor": { "initCodeHash": "0xe2ca240d728f711df438b7aeb3589c95ad11a97d742539a692ddafaf1365eb54", @@ -23,21 +23,13 @@ "initCodeHash": "0x9367896a99f843fd56024e5f45a7b435a9fa8591cd4a37ffd529e8becf1b0305", "sourceCodeHash": "0x9d16e900a764cd7f19db3656cf7a9e555b23b9c7e018641ed21566657847a314" }, - "src/L1/OPContractsManager.sol:OPContractsManager": { - "initCodeHash": "0xd59648acb50002957cfd952a0cc14a4d6c2a2f6cd3a0f7d485e61f633d4873f3", - "sourceCodeHash": "0x6d4ffaaa57441dec3c3ee8fd9ac59f95229defec405347af853e265bfd749235" - }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { - "initCodeHash": "0x233f5f4b424bc2aabe170cf758c9ff80841ceab4c78e37edfe3a7bc660c5577d", - "sourceCodeHash": "0x7c0cb663f82b07da8dec8a7497cf2fa56a335fb5bdc57b612c86462f8527d4d5" + "initCodeHash": "0x7f91525e45ea13bd680259e061f15d1bdfbdef7d9fd6c72bc62827b7fa732efe", + "sourceCodeHash": "0x1a0e19b0b6ec15affdb6888267046ddcf3419b3053c77fb8fb8810470f2486a7" }, "src/L1/OptimismPortal2.sol:OptimismPortal2": { - "initCodeHash": "0x8c296124bc1b1468cf301a434eebf3f0d9a194cde06876b993a8672577f08187", - "sourceCodeHash": "0xb14d8bceab135616e55fd560a077a4cc66fc3b535f09931d3b9167ee940fa62f" - }, - "src/L1/OptimismPortalInterop.sol:OptimismPortalInterop": { - "initCodeHash": "0xbafd0b80deb0a834335052e32a4199a96121148d9bda05acb62535ac18bd9909", - "sourceCodeHash": "0x24373f3fd28c5c6ae93cc32e2a213bb47458bc0f36e81b2a7b20a7b6b0a97119" + "initCodeHash": "0x1101a3124e60908ec3e7690b33389d835d0405416d107114edd1684528f39bee", + "sourceCodeHash": "0xe9baa6201cba314f5db2f30a6d8c6c23fcdc2e2407246c9e0624d7e781f511e3" }, "src/L1/ProtocolVersions.sol:ProtocolVersions": { "initCodeHash": "0xcb59ad9a5ec2a0831b7f4daa74bdacba82ffa03035dafb499a732c641e017f4e", @@ -52,8 +44,8 @@ "sourceCodeHash": "0xb09cb2f7cbde8585fad5c5beb6811fa9044b156b4203da8005d3f6a7a68c30b2" }, "src/L1/opcm/OPContractsManagerV2.sol:OPContractsManagerV2": { - "initCodeHash": "0x6c8af9dac0ff4dc0c783fcf8af06bde4d444ebab065c907785a24fd4f65f2414", - "sourceCodeHash": "0x937e16a99db4a376c8855b3df8eb529d19614c0fa3d5d7dbe334006bad1452a3" + "initCodeHash": "0xd8b7a5e075e0fd404d8e0aed10b345bb6064c21ac110caf4cf9ee26a66cc9b86", + "sourceCodeHash": "0xbddd81f0a8091778052008a67735b46b9f788872b40562d1906b4a7cbe823649" }, "src/L2/BaseFeeVault.sol:BaseFeeVault": { "initCodeHash": "0xf1fb169c6dd4eceb5cec6ed6dfa3affc45970e5a01e00827d06af1f9e8df026d", diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManager.json b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManager.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManager.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerContainer.json b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerContainer.json index 891f048bf30..7609df72ae4 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerContainer.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerContainer.json @@ -7,7 +7,7 @@ "type": "struct OPContractsManagerContainer.Blueprints" }, { - "bytes": "608", + "bytes": "576", "label": "impls", "offset": 0, "slot": "5", diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerContractsContainer.json b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerContractsContainer.json deleted file mode 100644 index a6f0bb30b8c..00000000000 --- a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerContractsContainer.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "bytes": "160", - "label": "blueprint", - "offset": 0, - "slot": "0", - "type": "struct OPContractsManager.Blueprints" - }, - { - "bytes": "576", - "label": "implementation", - "offset": 0, - "slot": "5", - "type": "struct OPContractsManager.Implementations" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerDeployer.json b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerDeployer.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerDeployer.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerGameTypeAdder.json b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerGameTypeAdder.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerGameTypeAdder.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerInteropMigrator.json b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerInteropMigrator.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerInteropMigrator.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerStandardValidator.json b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerStandardValidator.json index 16ce2e3bd4b..0346a8ca900 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerStandardValidator.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerStandardValidator.json @@ -41,109 +41,102 @@ "slot": "5", "type": "address" }, - { - "bytes": "20", - "label": "optimismPortalInteropImpl", - "offset": 0, - "slot": "6", - "type": "address" - }, { "bytes": "20", "label": "ethLockboxImpl", "offset": 0, - "slot": "7", + "slot": "6", "type": "address" }, { "bytes": "20", "label": "systemConfigImpl", "offset": 0, - "slot": "8", + "slot": "7", "type": "address" }, { "bytes": "20", "label": "optimismMintableERC20FactoryImpl", "offset": 0, - "slot": "9", + "slot": "8", "type": "address" }, { "bytes": "20", "label": "l1CrossDomainMessengerImpl", "offset": 0, - "slot": "10", + "slot": "9", "type": "address" }, { "bytes": "20", "label": "l1StandardBridgeImpl", "offset": 0, - "slot": "11", + "slot": "10", "type": "address" }, { "bytes": "20", "label": "disputeGameFactoryImpl", "offset": 0, - "slot": "12", + "slot": "11", "type": "address" }, { "bytes": "20", "label": "anchorStateRegistryImpl", "offset": 0, - "slot": "13", + "slot": "12", "type": "address" }, { "bytes": "20", "label": "delayedWETHImpl", "offset": 0, - "slot": "14", + "slot": "13", "type": "address" }, { "bytes": "20", "label": "mipsImpl", "offset": 0, - "slot": "15", + "slot": "14", "type": "address" }, { "bytes": "20", "label": "faultDisputeGameImpl", "offset": 0, - "slot": "16", + "slot": "15", "type": "address" }, { "bytes": "20", "label": "permissionedDisputeGameImpl", "offset": 0, - "slot": "17", + "slot": "16", "type": "address" }, { "bytes": "20", "label": "superFaultDisputeGameImpl", "offset": 0, - "slot": "18", + "slot": "17", "type": "address" }, { "bytes": "20", "label": "superPermissionedDisputeGameImpl", "offset": 0, - "slot": "19", + "slot": "18", "type": "address" }, { "bytes": "32", "label": "devFeatureBitmap", "offset": 0, - "slot": "20", + "slot": "19", "type": "bytes32" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerUpgrader.json b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerUpgrader.json deleted file mode 100644 index 0637a088a01..00000000000 --- a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerUpgrader.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OptimismPortalInterop.json b/packages/contracts-bedrock/snapshots/storageLayout/OptimismPortalInterop.json deleted file mode 100644 index c0bcf34cc42..00000000000 --- a/packages/contracts-bedrock/snapshots/storageLayout/OptimismPortalInterop.json +++ /dev/null @@ -1,149 +0,0 @@ -[ - { - "bytes": "1", - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "uint8" - }, - { - "bytes": "1", - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "bool" - }, - { - "bytes": "32", - "label": "params", - "offset": 0, - "slot": "1", - "type": "struct ResourceMetering.ResourceParams" - }, - { - "bytes": "1536", - "label": "__gap", - "offset": 0, - "slot": "2", - "type": "uint256[48]" - }, - { - "bytes": "20", - "label": "l2Sender", - "offset": 0, - "slot": "50", - "type": "address" - }, - { - "bytes": "32", - "label": "finalizedWithdrawals", - "offset": 0, - "slot": "51", - "type": "mapping(bytes32 => bool)" - }, - { - "bytes": "32", - "label": "spacer_52_0_32", - "offset": 0, - "slot": "52", - "type": "bytes32" - }, - { - "bytes": "1", - "label": "spacer_53_0_1", - "offset": 0, - "slot": "53", - "type": "bool" - }, - { - "bytes": "20", - "label": "spacer_53_1_20", - "offset": 1, - "slot": "53", - "type": "address" - }, - { - "bytes": "20", - "label": "spacer_54_0_20", - "offset": 0, - "slot": "54", - "type": "address" - }, - { - "bytes": "20", - "label": "systemConfig", - "offset": 0, - "slot": "55", - "type": "contract ISystemConfig" - }, - { - "bytes": "20", - "label": "spacer_56_0_20", - "offset": 0, - "slot": "56", - "type": "address" - }, - { - "bytes": "32", - "label": "provenWithdrawals", - "offset": 0, - "slot": "57", - "type": "mapping(bytes32 => mapping(address => struct OptimismPortalInterop.ProvenWithdrawal))" - }, - { - "bytes": "32", - "label": "spacer_58_0_32", - "offset": 0, - "slot": "58", - "type": "bytes32" - }, - { - "bytes": "4", - "label": "spacer_59_0_4", - "offset": 0, - "slot": "59", - "type": "GameType" - }, - { - "bytes": "8", - "label": "spacer_59_4_8", - "offset": 4, - "slot": "59", - "type": "uint64" - }, - { - "bytes": "32", - "label": "proofSubmitters", - "offset": 0, - "slot": "60", - "type": "mapping(bytes32 => address[])" - }, - { - "bytes": "32", - "label": "spacer_61_0_32", - "offset": 0, - "slot": "61", - "type": "uint256" - }, - { - "bytes": "20", - "label": "anchorStateRegistry", - "offset": 0, - "slot": "62", - "type": "contract IAnchorStateRegistry" - }, - { - "bytes": "20", - "label": "ethLockbox", - "offset": 0, - "slot": "63", - "type": "contract IETHLockbox" - }, - { - "bytes": "1", - "label": "superRootsActive", - "offset": 20, - "slot": "63", - "type": "bool" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/src/L1/ETHLockbox.sol b/packages/contracts-bedrock/src/L1/ETHLockbox.sol index 5cb777150b9..63c470a2ca6 100644 --- a/packages/contracts-bedrock/src/L1/ETHLockbox.sol +++ b/packages/contracts-bedrock/src/L1/ETHLockbox.sol @@ -73,9 +73,9 @@ contract ETHLockbox is ProxyAdminOwnedBase, Initializable, ReinitializableBase, mapping(IETHLockbox => bool) public authorizedLockboxes; /// @notice Semantic version. - /// @custom:semver 1.2.1 + /// @custom:semver 1.3.1 function version() public view virtual returns (string memory) { - return "1.2.1"; + return "1.3.1"; } /// @notice Constructs the ETHLockbox contract. @@ -195,7 +195,7 @@ contract ETHLockbox is ProxyAdminOwnedBase, Initializable, ReinitializableBase, } /// @notice Migrates liquidity from the current ETH lockbox to another. - /// @dev Must be called atomically with `OptimismPortal.migrateToSuperRoots()` in the same + /// @dev Must be called atomically with `OptimismPortal.migrateToSharedDisputeGame()` in the same /// transaction batch, or otherwise the OptimismPortal may not be able to unlock ETH /// from the ETHLockbox on finalized withdrawals. /// @param _lockbox The address of the ETH lockbox to migrate liquidity to. diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol deleted file mode 100644 index e3e8f1b77b8..00000000000 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ /dev/null @@ -1,2202 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -// Contracts -import { OPContractsManagerStandardValidator } from "src/L1/OPContractsManagerStandardValidator.sol"; - -// Libraries -import { Blueprint } from "src/libraries/Blueprint.sol"; -import { Constants } from "src/libraries/Constants.sol"; -import { Bytes } from "src/libraries/Bytes.sol"; -import { Claim, Duration, GameType, GameTypes, Proposal } from "src/dispute/lib/Types.sol"; -import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { SemverComp } from "src/libraries/SemverComp.sol"; -import { Features } from "src/libraries/Features.sol"; -import { DevFeatures } from "src/libraries/DevFeatures.sol"; -import { LibGameArgs } from "src/dispute/lib/LibGameArgs.sol"; - -// Interfaces -import { ISemver } from "interfaces/universal/ISemver.sol"; -import { IResourceMetering } from "interfaces/L1/IResourceMetering.sol"; -import { IBigStepper } from "interfaces/dispute/IBigStepper.sol"; -import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; -import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; -import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; -import { IAddressManager } from "interfaces/legacy/IAddressManager.sol"; -import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; -import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; -import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; -import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol"; -import { ISuperFaultDisputeGame } from "interfaces/dispute/ISuperFaultDisputeGame.sol"; -import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; -import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol"; -import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; -import { IOptimismPortalInterop } from "interfaces/L1/IOptimismPortalInterop.sol"; -import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; -import { IL1CrossDomainMessenger } from "interfaces/L1/IL1CrossDomainMessenger.sol"; -import { IL1ERC721Bridge } from "interfaces/L1/IL1ERC721Bridge.sol"; -import { IL1StandardBridge } from "interfaces/L1/IL1StandardBridge.sol"; -import { IOptimismMintableERC20Factory } from "interfaces/universal/IOptimismMintableERC20Factory.sol"; -import { IETHLockbox } from "interfaces/L1/IETHLockbox.sol"; -import { ISystemConfig } from "../../interfaces/L1/ISystemConfig.sol"; - -contract OPContractsManagerContractsContainer { - /// @notice Addresses of the Blueprint contracts. - /// This is internal because if public the autogenerated getter method would return a tuple of - /// addresses, but we want it to return a struct. - OPContractsManager.Blueprints internal blueprint; - - /// @notice Addresses of the latest implementation contracts. - OPContractsManager.Implementations internal implementation; - - /// @notice Bitmap of development features that are enabled. We keep the development feature - /// bitmap here rather than in the actual OPCM because other contracts always get a - /// reference to this but not to the OPCM itself. - bytes32 public immutable devFeatureBitmap; - - /// @notice Thrown when a development feature is enabled in production. - error OPContractsManagerContractsContainer_DevFeatureInProd(); - - /// @param _blueprints The blueprint contract addresses. - /// @param _implementations The implementation contract addresses. - /// @param _devFeatureBitmap The bitmap of development features that are enabled. - constructor( - OPContractsManager.Blueprints memory _blueprints, - OPContractsManager.Implementations memory _implementations, - bytes32 _devFeatureBitmap - ) { - blueprint = _blueprints; - implementation = _implementations; - devFeatureBitmap = _devFeatureBitmap; - - // Development features MUST NOT be enabled on Mainnet. - if (block.chainid == 1 && !_isTestingEnvironment() && uint256(_devFeatureBitmap) != 0) { - revert OPContractsManagerContractsContainer_DevFeatureInProd(); - } - } - - function blueprints() public view returns (OPContractsManager.Blueprints memory) { - return blueprint; - } - - function implementations() public view returns (OPContractsManager.Implementations memory) { - return implementation; - } - - /// @notice Returns the status of a development feature. Note that this function does not check - /// that the input feature represents a single feature and the bitwise AND operation - /// allows for multiple features to be enabled at once. Users should generally check - /// for only a single feature at a time. - /// @param _feature The feature to check. - /// @return True if the feature is enabled, false otherwise. - function isDevFeatureEnabled(bytes32 _feature) public view returns (bool) { - return DevFeatures.isDevFeatureEnabled(devFeatureBitmap, _feature); - } - - /// @notice Returns true if the contract is running in a testing environment. Checks that the - /// code for the address 0xbeefcafe is not zero, which is an address that should never - /// have any code in production environments but can be made to have code in tests. - /// @return True if the contract is running in a testing environment, false otherwise. - function _isTestingEnvironment() public view returns (bool) { - return address(0xbeefcafe).code.length > 0; - } -} - -abstract contract OPContractsManagerBase { - /// @notice Thrown when an invalid game type is used. - error OPContractsManager_InvalidGameType(); - - /// @notice The blueprint contract addresses contract. - OPContractsManagerContractsContainer public immutable contractsContainer; - - /// @notice The OPContractsManager contract that is currently being used. - OPContractsManagerBase internal immutable thisOPCM; - - /// @notice Constructor to initialize the immutable thisOPCM variable and contract addresses - /// @param _contractsContainer The blueprint contract addresses and implementation contract addresses - constructor(OPContractsManagerContractsContainer _contractsContainer) { - contractsContainer = _contractsContainer; - thisOPCM = this; - } - - /// @notice Retrieves the implementation addresses stored in this OPCM contract - function getImplementations() internal view returns (OPContractsManager.Implementations memory) { - return thisOPCM.implementations(); - } - - /// @notice Retrieves the blueprint addresses stored in this OPCM contract - function getBlueprints() internal view returns (OPContractsManager.Blueprints memory) { - return thisOPCM.blueprints(); - } - - /// @notice Retrieves the implementation addresses stored in this OPCM contract - function implementations() public view returns (OPContractsManager.Implementations memory) { - return contractsContainer.implementations(); - } - - /// @notice Retrieves the blueprint addresses stored in this OPCM contract - function blueprints() public view returns (OPContractsManager.Blueprints memory) { - return contractsContainer.blueprints(); - } - - /// @notice Retrieves the development feature bitmap stored in this OPCM contract - function devFeatureBitmap() public view returns (bytes32) { - return contractsContainer.devFeatureBitmap(); - } - - /// @notice Retrieves the status of a development feature. Note that this function does not check - /// that the input feature represents a single feature and the bitwise AND operation - /// allows for multiple features to be enabled at once. Users should generally check - /// for only a single feature at a time. - /// @param _feature The feature to check. - /// @return True if the feature is enabled, false otherwise. - function isDevFeatureEnabled(bytes32 _feature) public view returns (bool) { - return contractsContainer.isDevFeatureEnabled(_feature); - } - - /// @notice Maps an L2 chain ID to an L1 batch inbox address as defined by the standard - /// configuration's convention. This convention is `versionByte || keccak256(bytes32(chainId))[:19]`, - /// where || denotes concatenation`, versionByte is 0x00, and chainId is a uint256. - /// https://specs.optimism.io/protocol/configurability.html#consensus-parameters - function chainIdToBatchInboxAddress(uint256 _l2ChainId) public pure returns (address) { - bytes1 versionByte = 0x00; - bytes32 hashedChainId = keccak256(bytes.concat(bytes32(_l2ChainId))); - bytes19 first19Bytes = bytes19(hashedChainId); - return address(uint160(bytes20(bytes.concat(versionByte, first19Bytes)))); - } - - /// @notice Helper method for computing a salt that's used in CREATE2 deployments. - /// Including the contract name ensures that the resultant address from CREATE2 is unique - /// across our smart contract system. For example, we deploy multiple proxy contracts - /// with the same bytecode from this contract, so they each require a unique salt for determinism. - function computeSalt( - uint256 _l2ChainId, - string memory _saltMixer, - string memory _contractName - ) - internal - pure - returns (bytes32) - { - return keccak256(abi.encode(_l2ChainId, _saltMixer, _contractName)); - } - - /// @notice Helper method for computing a reusable salt mixer - /// This method should be used as the salt mixer when deploying contracts when there is no user - /// provided salt mixer. This protects against a situation where multiple chains with the same - /// L2 chain ID exist, which would otherwise result in address collisions. - /// @param _systemConfigProxy The SystemConfig contract found in the OpChainConfig of the chain being deployed to. - function reusableSaltMixer(ISystemConfig _systemConfigProxy) internal pure returns (string memory) { - return string(bytes.concat(bytes32(uint256(uint160(address(_systemConfigProxy)))))); - } - - /// @notice Deterministically deploys a new proxy contract owned by the provided ProxyAdmin. - /// The salt is computed as a function of the L2 chain ID, the salt mixer and the contract name. - /// This is required because we deploy many identical proxies, so they each require a unique salt for determinism. - function deployProxy( - uint256 _l2ChainId, - IProxyAdmin _proxyAdmin, - string memory _saltMixer, - string memory _contractName - ) - internal - returns (address) - { - bytes32 salt = computeSalt(_l2ChainId, _saltMixer, _contractName); - return Blueprint.deployFrom(getBlueprints().proxy, salt, abi.encode(_proxyAdmin)); - } - - /// @notice Makes an internal call to the target to initialize the proxy with the specified data. - /// First performs safety checks to ensure the target, implementation, and proxy admin are valid. - function upgradeToAndCall( - IProxyAdmin _proxyAdmin, - address _target, - address _implementation, - bytes memory _data - ) - internal - { - assertValidContractAddress(_implementation); - - _proxyAdmin.upgradeAndCall(payable(address(_target)), _implementation, _data); - } - - function assertValidContractAddress(address _who) public view { - if (_who.code.length == 0) revert OPContractsManager.AddressHasNoCode(_who); - } - - function encodePermissionlessSuperFDGConstructor(ISuperFaultDisputeGame.GameConstructorParams memory _params) - internal - view - virtual - returns (bytes memory) - { - bytes memory dataWithSelector = abi.encodeCall(ISuperFaultDisputeGame.__constructor__, (_params)); - return Bytes.slice(dataWithSelector, 4); - } - - /// @notice Returns the implementation contract address for a given game type. - function getGameImplementation( - IDisputeGameFactory _disputeGameFactory, - GameType _gameType - ) - internal - view - returns (IDisputeGame) - { - return _disputeGameFactory.gameImpls(_gameType); - } - - /// @notice Retrieves the Anchor State Registry for a given game - function getAnchorStateRegistry( - IDisputeGameFactory _disputeGameFactory, - IDisputeGame _disputeGame, - GameType _gameType - ) - internal - view - returns (IAnchorStateRegistry) - { - bytes memory gameArgsBytes = _disputeGameFactory.gameArgs(_gameType); - if (gameArgsBytes.length == 0) { - return IFaultDisputeGame(address(_disputeGame)).anchorStateRegistry(); - } else { - return IAnchorStateRegistry(LibGameArgs.decode(gameArgsBytes).anchorStateRegistry); - } - } - - /// @notice Retrieves the L2 chain ID for a given game - function getL2ChainId(IFaultDisputeGame _disputeGame) internal view returns (uint256) { - return _disputeGame.l2ChainId(); - } - - /// @notice Retrieves the proposer address for a given game - function getProposer( - IDisputeGameFactory _disputeGameFactory, - IDisputeGame _disputeGame, - GameType _gameType - ) - internal - view - returns (address) - { - bytes memory gameArgsBytes = _disputeGameFactory.gameArgs(_gameType); - if (gameArgsBytes.length == 0) { - return IPermissionedDisputeGame(address(_disputeGame)).proposer(); - } else { - return LibGameArgs.decode(gameArgsBytes).proposer; - } - } - - /// @notice Retrieves the challenger address of a given game - function getChallenger( - IDisputeGameFactory _disputeGameFactory, - IDisputeGame _disputeGame, - GameType _gameType - ) - internal - view - returns (address) - { - bytes memory gameArgsBytes = _disputeGameFactory.gameArgs(_gameType); - if (gameArgsBytes.length == 0) { - return IPermissionedDisputeGame(address(_disputeGame)).challenger(); - } else { - return LibGameArgs.decode(gameArgsBytes).challenger; - } - } - - /// @notice Helper function to register permissioned game V2 implementation - /// @dev Extracted to avoid stack too deep error - /// @param _input The deployment input data containing all necessary parameters - /// @param _implementation The implementation addresses struct - /// @param _output The deployment output containing proxy addresses - function _registerPermissionedGame( - OPContractsManager.DeployInput calldata _input, - OPContractsManager.Implementations memory _implementation, - OPContractsManager.DeployOutput memory _output - ) - internal - { - bytes memory gameArgs = abi.encodePacked( - _input.disputeAbsolutePrestate, // 32 bytes - _implementation.mipsImpl, // 20 bytes - address(_output.anchorStateRegistryProxy), // 20 bytes - address(_output.delayedWETHPermissionedGameProxy), // 20 bytes - _input.l2ChainId, // 32 bytes - _input.roles.proposer, // 20 bytes - _input.roles.challenger // 20 bytes - ); - setDGFImplementation( - _output.disputeGameFactoryProxy, - GameTypes.PERMISSIONED_CANNON, - IDisputeGame(_implementation.permissionedDisputeGameImpl), - gameArgs - ); - } - - /// @notice Retrieves the DisputeGameFactory address for a given SystemConfig - function getDisputeGameFactory(ISystemConfig _systemConfig) internal view returns (IDisputeGameFactory) { - return IDisputeGameFactory(_systemConfig.disputeGameFactory()); - } - - /// @notice Retrieves the AnchorStateRegistry address for a given SystemConfig - function getAnchorStateRegistry(ISystemConfig _systemConfig) internal view returns (IAnchorStateRegistry) { - return IAnchorStateRegistry(IOptimismPortal(payable(_systemConfig.optimismPortal())).anchorStateRegistry()); - } - - /// @notice Retrieves the DelayedWETH for a given game - function getWETH( - IDisputeGameFactory _disputeGameFactory, - IDisputeGame _disputeGame, - GameType _gameType - ) - internal - view - returns (IDelayedWETH) - { - bytes memory gameArgsBytes = _disputeGameFactory.gameArgs(_gameType); - if (gameArgsBytes.length == 0) { - return IFaultDisputeGame(address(_disputeGame)).weth(); - } else { - return IDelayedWETH(payable(LibGameArgs.decode(gameArgsBytes).weth)); - } - } - - /// @notice Retrieves the BigStepper VM for a given game - function getVM( - IDisputeGameFactory _disputeGameFactory, - IDisputeGame _disputeGame, - GameType _gameType - ) - internal - view - returns (IBigStepper) - { - bytes memory gameArgsBytes = _disputeGameFactory.gameArgs(_gameType); - if (gameArgsBytes.length == 0) { - return IFaultDisputeGame(address(_disputeGame)).vm(); - } else { - return IBigStepper(LibGameArgs.decode(gameArgsBytes).vm); - } - } - - /// @notice Sets a game implementation on the dispute game factory - /// @param _dgf The dispute game factory - /// @param _gameType The game type - /// @param _newGame The new game implementation - function setDGFImplementation(IDisputeGameFactory _dgf, GameType _gameType, IDisputeGame _newGame) internal { - _dgf.setImplementation(_gameType, _newGame); - } - - /// @notice Sets a game implementation on the dispute game factory - /// @param _dgf The dispute game factory - /// @param _gameType The game type - /// @param _newGame The new game implementation - /// @param _gameArgs Game arguments for this game type - function setDGFImplementation( - IDisputeGameFactory _dgf, - GameType _gameType, - IDisputeGame _newGame, - bytes memory _gameArgs - ) - internal - { - _dgf.setImplementation(_gameType, _newGame, _gameArgs); - } - - /// @notice Returns true iff the game type is CANNON or SUPER_CANNON - function isCannonGameVariant(GameType _gameType) internal pure returns (bool) { - return _gameType.raw() == GameTypes.CANNON.raw() || _gameType.raw() == GameTypes.SUPER_CANNON.raw(); - } - - /// @notice Returns true iff the game type is CANNON_KONA or SUPER_CANNON_KONA - function isKonaGameVariant(GameType _gameType) internal pure returns (bool) { - return _gameType.raw() == GameTypes.CANNON_KONA.raw() || _gameType.raw() == GameTypes.SUPER_CANNON_KONA.raw(); - } - - /// @notice Returns true iff the game type uses super roots - function isSuperGameVariant(GameType _gameType) internal pure returns (bool) { - return GameTypes.isSuperGame(_gameType); - } - - /// @notice Returns the dispute game implementation address in opcm for the specified game type - function getDisputeGameImplementation(GameType _gameType) internal view returns (address) { - if (_gameType.raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw()) { - return getImplementations().superPermissionedDisputeGameImpl; - } else if (_gameType.raw() == GameTypes.PERMISSIONED_CANNON.raw()) { - return getImplementations().permissionedDisputeGameImpl; - } else if ( - _gameType.raw() == GameTypes.SUPER_CANNON.raw() || _gameType.raw() == GameTypes.SUPER_CANNON_KONA.raw() - ) { - return getImplementations().superFaultDisputeGameImpl; - } else if (_gameType.raw() == GameTypes.CANNON.raw() || _gameType.raw() == GameTypes.CANNON_KONA.raw()) { - return getImplementations().faultDisputeGameImpl; - } else { - revert OPContractsManager_InvalidGameType(); - } - } -} - -contract OPContractsManagerGameTypeAdder is OPContractsManagerBase { - /// @notice Thrown when an unsupported game type is provided to the addGameType function. - error OPContractsManagerGameTypeAdder_UnsupportedGameType(); - - /// @notice Thrown when a mix of legacy and super games are found in updatePrestate. - error OPContractsManagerGameTypeAdder_MixedGameTypes(); - - /// @notice Emitted when a new game type is added to a chain - /// @param l2ChainId Chain ID of the chain - /// @param gameType Type of the game being - /// @param newDisputeGame Address of the deployed dispute game - /// @param oldDisputeGame Address of the old dispute game - event GameTypeAdded( - uint256 indexed l2ChainId, GameType indexed gameType, IDisputeGame newDisputeGame, IDisputeGame oldDisputeGame - ); - - /// @notice Constructor to initialize the immutable thisOPCM variable and contract addresses - /// @param _contractsContainer The blueprint contract addresses and implementation contract addresses - constructor(OPContractsManagerContractsContainer _contractsContainer) OPContractsManagerBase(_contractsContainer) { } - - /// @notice Deploys a new dispute game and installs it into the DisputeGameFactory. Inputted - /// game configs must be added in ascending GameType order. - /// @param _gameConfigs Game configs to add. - /// @return Array of results for the operations performed. - function addGameType(OPContractsManager.AddGameInput[] memory _gameConfigs) - public - virtual - returns (OPContractsManager.AddGameOutput[] memory) - { - // Ensure we have at least one game config to add. - if (_gameConfigs.length == 0) revert OPContractsManager.InvalidGameConfigs(); - - // We'll have one output per game config. - OPContractsManager.AddGameOutput[] memory outputs = new OPContractsManager.AddGameOutput[](_gameConfigs.length); - - // Store last game config as an int256 so that we can ensure that the same game config is - // not added twice. Using int256 generates cheaper, simpler bytecode. - int256 lastGameConfig = -1; - - // Loop through each game config and add the game type. - for (uint256 i = 0; i < _gameConfigs.length; i++) { - OPContractsManager.AddGameInput memory gameConfig = _gameConfigs[i]; - - // This conversion is safe because the GameType is a uint32, which will always fit in - // an int256. - int256 gameTypeInt = int256(uint256(gameConfig.disputeGameType.raw())); - - // Ensure that the game configs are added in ascending order, and not duplicated. - if (lastGameConfig >= gameTypeInt) revert OPContractsManager.InvalidGameConfigs(); - lastGameConfig = gameTypeInt; - - // Grab the L2 chain ID from the SystemConfig. - uint256 l2ChainId = gameConfig.systemConfig.l2ChainId(); - - // Deploy a new DelayedWETH proxy for this game if one hasn't already been specified. - // Leaving gameConfig.delayedWETH as the zero address will cause a new DelayedWETH to - // be deployed for this game. - if (address(gameConfig.delayedWETH) == address(0)) { - // Deploy the DelayedWETH proxy. We use the chain ID and the game type in the - // contract name to ensure that the contract is unique across chains. - outputs[i].delayedWETH = IDelayedWETH( - payable( - deployProxy( - l2ChainId, - gameConfig.systemConfig.proxyAdmin(), - gameConfig.saltMixer, - string.concat("DelayedWETH-", Strings.toString(uint256(gameTypeInt))) - ) - ) - ); - - // Initialize the proxy. - upgradeToAndCall( - gameConfig.systemConfig.proxyAdmin(), - address(outputs[i].delayedWETH), - getImplementations().delayedWETHImpl, - abi.encodeCall(IDelayedWETH.initialize, (gameConfig.systemConfig)) - ); - } else { - outputs[i].delayedWETH = gameConfig.delayedWETH; - } - - // Grab the DisputeGameFactory and AnchorStateRegistry for the chain. - IDisputeGameFactory dgf = getDisputeGameFactory(gameConfig.systemConfig); - - // Grab the existing game implementation from the DisputeGameFactory. - IFaultDisputeGame existingGame = - IFaultDisputeGame(address(getGameImplementation(dgf, gameConfig.disputeGameType))); - - if (isCannonGameVariant(gameConfig.disputeGameType) || isKonaGameVariant(gameConfig.disputeGameType)) { - address impl = getDisputeGameImplementation(gameConfig.disputeGameType); - bytes memory gameArgs = LibGameArgs.encode( - LibGameArgs.GameArgs({ - absolutePrestate: gameConfig.disputeAbsolutePrestate.raw(), - vm: address(gameConfig.vm), - anchorStateRegistry: address(getAnchorStateRegistry(ISystemConfig(gameConfig.systemConfig))), - weth: address(outputs[i].delayedWETH), - // must be zero for SUPER game types - l2ChainId: isSuperGameVariant(gameConfig.disputeGameType) ? 0 : l2ChainId, - proposer: address(0), - challenger: address(0) - }) - ); - - setDGFImplementation(dgf, gameConfig.disputeGameType, IDisputeGame(impl), gameArgs); - outputs[i].faultDisputeGame = IFaultDisputeGame(impl); - } else if ( - gameConfig.disputeGameType.raw() == GameTypes.PERMISSIONED_CANNON.raw() - || gameConfig.disputeGameType.raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw() - ) { - address impl = getDisputeGameImplementation(gameConfig.disputeGameType); - bytes memory gameArgs = LibGameArgs.encode( - LibGameArgs.GameArgs({ - absolutePrestate: gameConfig.disputeAbsolutePrestate.raw(), - vm: address(gameConfig.vm), - anchorStateRegistry: address(getAnchorStateRegistry(ISystemConfig(gameConfig.systemConfig))), - weth: address(outputs[i].delayedWETH), - l2ChainId: gameConfig.disputeGameType.raw() == GameTypes.PERMISSIONED_CANNON.raw() ? l2ChainId : 0, // must - // be zero for SUPER gam types - proposer: getProposer( - dgf, IPermissionedDisputeGame(address(existingGame)), gameConfig.disputeGameType - ), - challenger: getChallenger( - dgf, IPermissionedDisputeGame(address(existingGame)), gameConfig.disputeGameType - ) - }) - ); - setDGFImplementation(dgf, gameConfig.disputeGameType, IDisputeGame(impl), gameArgs); - outputs[i].faultDisputeGame = IFaultDisputeGame(payable(impl)); - } else { - revert OPContractsManagerGameTypeAdder_UnsupportedGameType(); - } - - dgf.setInitBond(gameConfig.disputeGameType, gameConfig.initialBond); - - // Emit event for the newly added game type with the new and old implementations. - emit GameTypeAdded( - l2ChainId, gameConfig.disputeGameType, outputs[i].faultDisputeGame, IDisputeGame(address(existingGame)) - ); - } - - return outputs; - } - - /// @notice Updates the prestate hash for all deployed dispute games while keeping all other game - /// parameters exactly the same. Currently requires deploying a new implementation - /// as there is no way to update the prestate on an existing implementation. - /// @param _prestateUpdateInputs The new prestate hash to use. - function updatePrestate(OPContractsManager.UpdatePrestateInput[] memory _prestateUpdateInputs) public { - // Loop through each chain and prestate hash - for (uint256 i = 0; i < _prestateUpdateInputs.length; i++) { - // Grab the DisputeGameFactory. - IDisputeGameFactory dgf = - IDisputeGameFactory(_prestateUpdateInputs[i].systemConfigProxy.disputeGameFactory()); - - // Create an array of all of the potential game types to update. - GameType[] memory gameTypes = new GameType[](6); - gameTypes[0] = GameTypes.CANNON; - gameTypes[1] = GameTypes.PERMISSIONED_CANNON; - gameTypes[2] = GameTypes.SUPER_CANNON; - gameTypes[3] = GameTypes.SUPER_PERMISSIONED_CANNON; - gameTypes[4] = GameTypes.CANNON_KONA; - gameTypes[5] = GameTypes.SUPER_CANNON_KONA; - - // Track if we have a legacy game, super game, or both. We will revert if this function - // is ever called with a mix of legacy and super games. Should never happen in - // production if you follow the standard upgrade process, but you never know. - bool hasLegacyGame = false; - bool hasSuperGame = false; - - // Iterate over each game type and update the prestate. - for (uint256 j = 0; j < gameTypes.length; j++) { - GameType gameType = gameTypes[j]; - - // Get the existing game implementation. - IFaultDisputeGame existingGame = IFaultDisputeGame(address(getGameImplementation(dgf, gameType))); - - // If no implementation exists, skip. - if (address(existingGame) == address(0)) { - continue; - } - - // Track the game types that we've seen so far. - if ( - gameType.raw() == GameTypes.SUPER_CANNON.raw() - || gameType.raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw() - || gameType.raw() == GameTypes.SUPER_CANNON_KONA.raw() - ) { - hasSuperGame = true; - } else { - hasLegacyGame = true; - } - - // If we have a mix of legacy and super games, revert. - if (hasLegacyGame && hasSuperGame) { - revert OPContractsManagerGameTypeAdder_MixedGameTypes(); - } - - // Select the prestate to use - Claim prestate = gameType.raw() == GameTypes.CANNON_KONA.raw() - || gameType.raw() == GameTypes.SUPER_CANNON_KONA.raw() - ? _prestateUpdateInputs[i].cannonKonaPrestate - : _prestateUpdateInputs[i].cannonPrestate; - - // Ensure that the prestate is not the zero hash. - if (Claim.unwrap(prestate) == bytes32(0)) { - revert OPContractsManager.PrestateRequired(); - } - - // Create a new game input with the updated prestate. - OPContractsManager.AddGameInput memory input = OPContractsManager.AddGameInput({ - disputeAbsolutePrestate: prestate, - saltMixer: reusableSaltMixer(_prestateUpdateInputs[i].systemConfigProxy), - systemConfig: _prestateUpdateInputs[i].systemConfigProxy, - delayedWETH: getWETH(dgf, existingGame, gameType), - disputeGameType: gameType, - disputeMaxGameDepth: existingGame.maxGameDepth(), - disputeSplitDepth: existingGame.splitDepth(), - disputeClockExtension: existingGame.clockExtension(), - disputeMaxClockDuration: existingGame.maxClockDuration(), - initialBond: dgf.initBonds(gameType), - vm: getVM(dgf, existingGame, gameType), - permissioned: gameType.raw() == GameTypes.PERMISSIONED_CANNON.raw() - || gameType.raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw() - }); - - // Add the new game type with updated prestate - OPContractsManager.AddGameInput[] memory inputs = new OPContractsManager.AddGameInput[](1); - inputs[0] = input; - addGameType(inputs); - } - } - } -} - -contract OPContractsManagerUpgrader is OPContractsManagerBase { - /// @notice Emitted when a chain is upgraded - /// @param systemConfig Address of the chain's SystemConfig contract - /// @param upgrader Address that initiated the upgrade - event Upgraded(uint256 indexed l2ChainId, ISystemConfig indexed systemConfig, address indexed upgrader); - - /// @notice Thrown when the SuperchainConfig contract does not match the unified config. - error OPContractsManagerUpgrader_SuperchainConfigMismatch(); - - /// @notice Thrown when upgrade is called with a chain whose superchainConfig is not upgraded. - error OPContractsManagerUpgrader_SuperchainConfigNeedsUpgrade(uint256 index); - - /// @notice Thrown when upgradeSuperchainConfig is called with a superchainConfig that is already up to date. - error OPContractsManagerUpgrader_SuperchainConfigAlreadyUpToDate(); - - /// @param _contractsContainer The OPContractsManagerContractsContainer to use. - constructor(OPContractsManagerContractsContainer _contractsContainer) OPContractsManagerBase(_contractsContainer) { } - - /// @notice Upgrades a set of chains to the latest implementation contracts - /// @param _opChainConfigs Array of OpChain structs, one per chain to upgrade - /// @dev This function is intended to be DELEGATECALLed by an address that is the common owner of every chain in - /// `_opChainConfigs`'s ProxyAdmin. - /// @dev This function requires that each chain's superchainConfig is already upgraded. - function upgrade(OPContractsManager.OpChainConfig[] memory _opChainConfigs) external virtual { - // Grab the implementations. - OPContractsManager.Implementations memory impls = getImplementations(); - - // Loop through each chain and upgrade. - for (uint256 i = 0; i < _opChainConfigs.length; i++) { - assertValidOpChainConfig(_opChainConfigs[i]); - uint256 l2ChainId = _opChainConfigs[i].systemConfigProxy.l2ChainId(); - - // Grab the SuperchainConfig. - ISuperchainConfig superchainConfig = _opChainConfigs[i].systemConfigProxy.superchainConfig(); - - // If the SuperchainConfig is not already upgraded, revert. - if (SemverComp.lt(superchainConfig.version(), ISuperchainConfig(impls.superchainConfigImpl).version())) { - revert OPContractsManagerUpgrader_SuperchainConfigNeedsUpgrade(i); - } - - // Do the chain upgrade. - // All of your updates should be done in this internal function unless you're making a - // change to how upgrades work in general. - _doChainUpgrade(impls, _opChainConfigs[i], l2ChainId); - - // Emit the upgraded event with the address of the caller. Since this will be a delegatecall, - // the caller will be the value of the ADDRESS opcode. - emit Upgraded(l2ChainId, _opChainConfigs[i].systemConfigProxy, address(this)); - } - } - - /// @notice Performs an upgrade for a specific chain. - /// @param _impls The implementations of the contracts. - /// @param _opChainConfig The configuration of the chain to upgrade. - /// @param _l2ChainId The L2 chain ID of the chain to upgrade. - function _doChainUpgrade( - OPContractsManager.Implementations memory _impls, - OPContractsManager.OpChainConfig memory _opChainConfig, - uint256 _l2ChainId - ) - internal - { - // Get the proxyAdmin from the systemConfig. - IProxyAdmin proxyAdmin = _opChainConfig.systemConfigProxy.proxyAdmin(); - - // Upgrade the SystemConfig first. - upgradeTo(proxyAdmin, address(_opChainConfig.systemConfigProxy), _impls.systemConfigImpl); - - // Grab the OptimismPortal contract. - IOptimismPortal optimismPortal = IOptimismPortal(payable(_opChainConfig.systemConfigProxy.optimismPortal())); - - // Upgrade the OptimismPortal contract. - if (isDevFeatureEnabled(DevFeatures.OPTIMISM_PORTAL_INTEROP)) { - // This does NOT run in production. - // Upgrade the OptimismPortal contract implementation. - upgradeTo(proxyAdmin, address(optimismPortal), _impls.optimismPortalInteropImpl); - - // If we don't already have an ETHLockbox, deploy and initialize it. - IETHLockbox ethLockbox = optimismPortal.ethLockbox(); - if (address(ethLockbox) == address(0)) { - // Deploy the ETHLockbox proxy. - ethLockbox = IETHLockbox( - deployProxy({ - _l2ChainId: _l2ChainId, - _proxyAdmin: proxyAdmin, - _saltMixer: reusableSaltMixer(_opChainConfig.systemConfigProxy), - _contractName: "ETHLockbox-U16a" - }) - ); - - // Initialize the ETHLockbox setting the OptimismPortal as an authorized portal. - IOptimismPortal[] memory portals = new IOptimismPortal[](1); - portals[0] = optimismPortal; - upgradeToAndCall( - proxyAdmin, - address(ethLockbox), - _impls.ethLockboxImpl, - abi.encodeCall(IETHLockbox.initialize, (_opChainConfig.systemConfigProxy, portals)) - ); - - // Migrate liquidity from the OptimismPortal to the ETHLockbox. - IOptimismPortalInterop(payable(optimismPortal)).migrateLiquidity(); - } - - // Use the existing AnchorStateRegistry reference. - IAnchorStateRegistry anchorStateRegistry = optimismPortal.anchorStateRegistry(); - - // Upgrade the OptimismPortal contract first so that the SystemConfig will have - // the SuperchainConfig reference required in the ETHLockbox. - IOptimismPortalInterop(payable(optimismPortal)).upgrade(anchorStateRegistry, ethLockbox); - } else { - // This runs in production. - upgradeTo(proxyAdmin, address(optimismPortal), _impls.optimismPortalImpl); - } - - // Upgrade the AnchorStateRegistry contract. No upgrade/initializer needed, just updating - // the implementation to latest. - upgradeTo(proxyAdmin, address(optimismPortal.anchorStateRegistry()), _impls.anchorStateRegistryImpl); - - // Upgrade the OptimismMintableERC20Factory contract. - upgradeTo( - proxyAdmin, - _opChainConfig.systemConfigProxy.optimismMintableERC20Factory(), - _impls.optimismMintableERC20FactoryImpl - ); - - // Use the SystemConfig to grab the DisputeGameFactory address. - IDisputeGameFactory dgf = IDisputeGameFactory(_opChainConfig.systemConfigProxy.disputeGameFactory()); - - // Need to upgrade the DisputeGameFactory implementation, no internal upgrade call. - upgradeTo(proxyAdmin, address(dgf), _impls.disputeGameFactoryImpl); - - // Separate context to avoid stack too deep. - { - // Grab chain addresses here. We need to do this after the SystemConfig upgrade or - // the addresses will be incorrect. - ISystemConfig.Addresses memory opChainAddrs = _opChainConfig.systemConfigProxy.getAddresses(); - - // Upgrade the L1CrossDomainMessenger contract. - upgradeTo( - proxyAdmin, - address(IL1CrossDomainMessenger(opChainAddrs.l1CrossDomainMessenger)), - _impls.l1CrossDomainMessengerImpl - ); - - // Upgrade the L1StandardBridge contract. - upgradeTo( - proxyAdmin, - address(IL1StandardBridge(payable(opChainAddrs.l1StandardBridge))), - _impls.l1StandardBridgeImpl - ); - - // Upgrade the L1ERC721Bridge contract. - upgradeTo(proxyAdmin, address(IL1ERC721Bridge(opChainAddrs.l1ERC721Bridge)), _impls.l1ERC721BridgeImpl); - } - - // All chains have the PermissionedDisputeGame, grab that. - IDisputeGame permissionedDisputeGame = getGameImplementation(dgf, GameTypes.PERMISSIONED_CANNON); - - setNewPermissionedGameImpl({ - _impls: _impls, - _l2ChainId: _l2ChainId, - _disputeGame: permissionedDisputeGame, - _newDelayedWeth: getWETH(dgf, permissionedDisputeGame, GameTypes.PERMISSIONED_CANNON), - _newAnchorStateRegistryProxy: getAnchorStateRegistry( - dgf, permissionedDisputeGame, GameTypes.PERMISSIONED_CANNON - ), - _opChainConfig: _opChainConfig - }); - - IDisputeGame permissionlessDisputeGame = getGameImplementation(dgf, GameTypes.CANNON); - - // If it exists, replace its implementation. - // We're reusing the same DelayedWETH and ASR contracts. - if (address(permissionlessDisputeGame) != address(0)) { - IDisputeGameFactory disputeGameFactory = - IDisputeGameFactory(_opChainConfig.systemConfigProxy.disputeGameFactory()); - Claim cannonPrestate = _opChainConfig.cannonPrestate.raw() != bytes32(0) - ? _opChainConfig.cannonPrestate - : getAbsolutePrestate(disputeGameFactory, address(permissionlessDisputeGame), GameTypes.CANNON); - setNewPermissionlessGameImpl({ - _impls: _impls, - _l2ChainId: _l2ChainId, - _newAbsolutePrestate: cannonPrestate, - _newDelayedWeth: getWETH(dgf, permissionlessDisputeGame, GameTypes.CANNON), - _newAnchorStateRegistryProxy: getAnchorStateRegistry(dgf, permissionlessDisputeGame, GameTypes.CANNON), - _gameType: GameTypes.CANNON, - _disputeGameFactory: disputeGameFactory - }); - - // Get the actual CANNON_KONA implementation to determine if it exists and to read its prestate - IDisputeGame cannonKonaGame = getGameImplementation(dgf, GameTypes.CANNON_KONA); - - // Only upgrade CANNON_KONA if prestate is explicitly provided OR if CANNON_KONA already exists. - // This avoids silently enabling CANNON_KONA with an unintended prestate. - if (_opChainConfig.cannonKonaPrestate.raw() != bytes32(0) || address(cannonKonaGame) != address(0)) { - Claim cannonKonaPrestate = _opChainConfig.cannonKonaPrestate.raw() != bytes32(0) - ? _opChainConfig.cannonKonaPrestate - : getAbsolutePrestate(disputeGameFactory, address(cannonKonaGame), GameTypes.CANNON_KONA); - setNewPermissionlessGameImpl({ - _impls: _impls, - _l2ChainId: _l2ChainId, - _newAbsolutePrestate: cannonKonaPrestate, - // CANNON and CANNON_KONA use the same weth and asr proxy addresses - _newDelayedWeth: getWETH(dgf, permissionlessDisputeGame, GameTypes.CANNON), - _newAnchorStateRegistryProxy: getAnchorStateRegistry(dgf, permissionlessDisputeGame, GameTypes.CANNON), - _gameType: GameTypes.CANNON_KONA, - _disputeGameFactory: disputeGameFactory - }); - uint256 initialCannonGameBond = disputeGameFactory.initBonds(GameTypes.CANNON); - disputeGameFactory.setInitBond(GameTypes.CANNON_KONA, initialCannonGameBond); - } - } - } - - /// @notice Upgrades the SuperchainConfig contract. - /// @param _superchainConfig The SuperchainConfig contract to upgrade. - /// @dev This function is intended to be DELEGATECALLed by the superchainConfig's ProxyAdminOwner. - /// @dev This function will revert if the SuperchainConfig is already at or above the target version. - function upgradeSuperchainConfig(ISuperchainConfig _superchainConfig) external { - // Only upgrade the superchainConfig if the current version is less than the target version. - if ( - SemverComp.gte( - _superchainConfig.version(), ISuperchainConfig(getImplementations().superchainConfigImpl).version() - ) - ) { - revert OPContractsManagerUpgrader_SuperchainConfigAlreadyUpToDate(); - } - - // Grab the implementations. - OPContractsManager.Implementations memory impls = getImplementations(); - // Grab the superchainConfig's proxyAdmin. - IProxyAdmin _superchainProxyAdmin = IProxyAdmin(_superchainConfig.proxyAdmin()); - - // Attempt to upgrade. If the ProxyAdmin is not the SuperchainConfig's admin, this will revert. - upgradeTo(_superchainProxyAdmin, address(_superchainConfig), impls.superchainConfigImpl); - } - - /// @notice Updates the implementation of a proxy without calling the initializer. - /// First performs safety checks to ensure the target, implementation, and proxy admin are valid. - function upgradeTo(IProxyAdmin _proxyAdmin, address _target, address _implementation) internal { - assertValidContractAddress(_implementation); - - _proxyAdmin.upgrade(payable(address(_target)), _implementation); - } - - /// @notice Verifies that all OpChainConfig inputs are valid and reverts if any are invalid. - function assertValidOpChainConfig(OPContractsManager.OpChainConfig memory _config) internal view { - assertValidContractAddress(address(_config.systemConfigProxy)); - } - - /// @notice Sets the latest permissioned dispute game v2 implementation - /// @param _impls The container for the new dispute game implementations. - /// @param _l2ChainId The L2 chain ID - /// @param _disputeGame The current dispute game implementation in the dispute game factory - /// @param _newDelayedWeth The new delayed WETH implementation - /// @param _newAnchorStateRegistryProxy The new anchor state registry proxy - /// @param _opChainConfig The OP chain configuration - function setNewPermissionedGameImpl( - OPContractsManager.Implementations memory _impls, - uint256 _l2ChainId, - IDisputeGame _disputeGame, - IDelayedWETH _newDelayedWeth, - IAnchorStateRegistry _newAnchorStateRegistryProxy, - OPContractsManager.OpChainConfig memory _opChainConfig - ) - internal - { - IDisputeGameFactory disputeGameFactory = - IDisputeGameFactory(_opChainConfig.systemConfigProxy.disputeGameFactory()); - // If the prestate is set in the config, use it. If not set, we'll try to use the prestate - // that already exists on the current dispute game. - Claim absolutePrestate; - if (Claim.unwrap(_opChainConfig.cannonPrestate) == bytes32(0)) { - absolutePrestate = - getAbsolutePrestate(disputeGameFactory, address(_disputeGame), GameTypes.PERMISSIONED_CANNON); - } else { - absolutePrestate = _opChainConfig.cannonPrestate; - } - - // As a sanity check, if the prestate is zero here, revert. - if (absolutePrestate.raw() == bytes32(0)) { - revert OPContractsManager.PrestateNotSet(); - } - - IDisputeGame newGame = IDisputeGame(_impls.permissionedDisputeGameImpl); - bytes memory gameArgs = LibGameArgs.encode( - LibGameArgs.GameArgs({ - absolutePrestate: absolutePrestate.raw(), - vm: address(_impls.mipsImpl), - anchorStateRegistry: address(_newAnchorStateRegistryProxy), - weth: address(_newDelayedWeth), - l2ChainId: _l2ChainId, - proposer: getProposer( - disputeGameFactory, IPermissionedDisputeGame(address(_disputeGame)), GameTypes.PERMISSIONED_CANNON - ), - challenger: getChallenger( - disputeGameFactory, IPermissionedDisputeGame(address(_disputeGame)), GameTypes.PERMISSIONED_CANNON - ) - }) - ); - - setDGFImplementation(disputeGameFactory, GameTypes.PERMISSIONED_CANNON, IDisputeGame(newGame), gameArgs); - } - - /// @notice Sets the latest permissionless dispute game v2 implementations - /// @param _impls The container for the new dispute game implementations. - /// @param _l2ChainId The L2 chain ID - /// @param _newAbsolutePrestate The new absolute prestate for the dispute game - /// @param _newDelayedWeth The new delayed WETH implementation - /// @param _newAnchorStateRegistryProxy The new anchor state registry proxy - /// @param _disputeGameFactory The dispute game factory proxy - function setNewPermissionlessGameImpl( - OPContractsManager.Implementations memory _impls, - uint256 _l2ChainId, - Claim _newAbsolutePrestate, - IDelayedWETH _newDelayedWeth, - IAnchorStateRegistry _newAnchorStateRegistryProxy, - GameType _gameType, - IDisputeGameFactory _disputeGameFactory - ) - internal - { - // As a sanity check, if the prestate is zero here, revert. - if (_newAbsolutePrestate.raw() == bytes32(0)) { - revert OPContractsManager.PrestateNotSet(); - } - - IDisputeGame newGame = IDisputeGame(_impls.faultDisputeGameImpl); - bytes memory gameArgs = LibGameArgs.encode( - LibGameArgs.GameArgs({ - absolutePrestate: _newAbsolutePrestate.raw(), - vm: address(_impls.mipsImpl), - anchorStateRegistry: address(_newAnchorStateRegistryProxy), - weth: address(_newDelayedWeth), - l2ChainId: _l2ChainId, - proposer: address(0), - challenger: address(0) - }) - ); - setDGFImplementation(_disputeGameFactory, _gameType, IDisputeGame(newGame), gameArgs); - } - - /// @notice Retrieves the absolute prestate for a dispute game, handling both V1 and V2 games. - function getAbsolutePrestate( - IDisputeGameFactory _dgf, - address _disputeGame, - GameType _gameType - ) - internal - view - returns (Claim) - { - bytes memory gameArgsBytes = _dgf.gameArgs(_gameType); - if (gameArgsBytes.length == 0) { - // Game without CWIA args - read directly from contract - return IFaultDisputeGame(_disputeGame).absolutePrestate(); - } else { - // Game with CWIA args - decode from game args - LibGameArgs.GameArgs memory gameArgs = LibGameArgs.decode(gameArgsBytes); - return Claim.wrap(gameArgs.absolutePrestate); - } - } -} - -contract OPContractsManagerDeployer is OPContractsManagerBase { - /// @notice Emitted when a new OP Stack chain is deployed. - /// @param l2ChainId Chain ID of the new chain. - /// @param deployer Address that deployed the chain. - /// @param deployOutput ABI-encoded output of the deployment. - event Deployed(uint256 indexed l2ChainId, address indexed deployer, bytes deployOutput); - - constructor(OPContractsManagerContractsContainer _contractsContainer) OPContractsManagerBase(_contractsContainer) { } - - /// @notice Deploys a new OP Stack chain. - /// @param _input The deploy input parameters for the deployment. - /// @param _superchainConfig The superchain config for the chain. - /// @param _deployer The address to emit as the deployer address. - /// @return The deploy output values of the deployment. - function deploy( - OPContractsManager.DeployInput calldata _input, - ISuperchainConfig _superchainConfig, - address _deployer - ) - external - virtual - returns (OPContractsManager.DeployOutput memory) - { - assertValidInputs(_input); - OPContractsManager.DeployOutput memory output; - OPContractsManager.Blueprints memory blueprint = getBlueprints(); - OPContractsManager.Implementations memory implementation = getImplementations(); - - // -------- Deploy Chain Singletons -------- - - // The AddressManager is used to store the implementation for the L1CrossDomainMessenger - // due to it's usage of the legacy ResolvedDelegateProxy. - output.addressManager = IAddressManager( - Blueprint.deployFrom( - blueprint.addressManager, - computeSalt(_input.l2ChainId, _input.saltMixer, "AddressManager"), - abi.encode() - ) - ); - // The ProxyAdmin is the owner of all proxies for the chain. We temporarily set the owner to - // this contract, and then transfer ownership to the specified owner at the end of deployment. - output.opChainProxyAdmin = IProxyAdmin( - Blueprint.deployFrom( - blueprint.proxyAdmin, - computeSalt(_input.l2ChainId, _input.saltMixer, "ProxyAdmin"), - abi.encode(address(this)) - ) - ); - // Set the AddressManager on the ProxyAdmin. - output.opChainProxyAdmin.setAddressManager(output.addressManager); - // Transfer ownership of the AddressManager to the ProxyAdmin. - transferOwnership(address(output.addressManager), address(output.opChainProxyAdmin)); - - // -------- Deploy Proxy Contracts -------- - - // Deploy ERC-1967 proxied contracts. - output.l1ERC721BridgeProxy = - IL1ERC721Bridge(deployProxy(_input.l2ChainId, output.opChainProxyAdmin, _input.saltMixer, "L1ERC721Bridge")); - output.optimismPortalProxy = IOptimismPortal( - payable(deployProxy(_input.l2ChainId, output.opChainProxyAdmin, _input.saltMixer, "OptimismPortal")) - ); - output.ethLockboxProxy = - IETHLockbox(deployProxy(_input.l2ChainId, output.opChainProxyAdmin, _input.saltMixer, "ETHLockbox")); - output.systemConfigProxy = - ISystemConfig(deployProxy(_input.l2ChainId, output.opChainProxyAdmin, _input.saltMixer, "SystemConfig")); - output.optimismMintableERC20FactoryProxy = IOptimismMintableERC20Factory( - deployProxy(_input.l2ChainId, output.opChainProxyAdmin, _input.saltMixer, "OptimismMintableERC20Factory") - ); - output.disputeGameFactoryProxy = IDisputeGameFactory( - deployProxy(_input.l2ChainId, output.opChainProxyAdmin, _input.saltMixer, "DisputeGameFactory") - ); - output.anchorStateRegistryProxy = IAnchorStateRegistry( - deployProxy(_input.l2ChainId, output.opChainProxyAdmin, _input.saltMixer, "AnchorStateRegistry") - ); - - // Deploy legacy proxied contracts. - output.l1StandardBridgeProxy = IL1StandardBridge( - payable( - Blueprint.deployFrom( - blueprint.l1ChugSplashProxy, - computeSalt(_input.l2ChainId, _input.saltMixer, "L1StandardBridge"), - abi.encode(output.opChainProxyAdmin) - ) - ) - ); - output.opChainProxyAdmin.setProxyType(address(output.l1StandardBridgeProxy), IProxyAdmin.ProxyType.CHUGSPLASH); - string memory contractName = "OVM_L1CrossDomainMessenger"; - output.l1CrossDomainMessengerProxy = IL1CrossDomainMessenger( - Blueprint.deployFrom( - blueprint.resolvedDelegateProxy, - computeSalt(_input.l2ChainId, _input.saltMixer, "L1CrossDomainMessenger"), - abi.encode(output.addressManager, contractName) - ) - ); - output.opChainProxyAdmin.setProxyType( - address(output.l1CrossDomainMessengerProxy), IProxyAdmin.ProxyType.RESOLVED - ); - output.opChainProxyAdmin.setImplementationName(address(output.l1CrossDomainMessengerProxy), contractName); - - // Eventually we will switch from DelayedWETHPermissionedGameProxy to DelayedWETHPermissionlessGameProxy. - output.delayedWETHPermissionedGameProxy = IDelayedWETH( - payable( - deployProxy(_input.l2ChainId, output.opChainProxyAdmin, _input.saltMixer, "DelayedWETHPermissionedGame") - ) - ); - - // -------- Set and Initialize Proxy Implementations -------- - bytes memory data; - - data = encodeL1ERC721BridgeInitializer(output); - upgradeToAndCall( - output.opChainProxyAdmin, address(output.l1ERC721BridgeProxy), implementation.l1ERC721BridgeImpl, data - ); - - // Initialize the SystemConfig before the ETHLockbox, required because the ETHLockbox will - // try to get the SuperchainConfig from the SystemConfig inside of its initializer. Also - // need to initialize before OptimismPortal because OptimismPortal does some sanity checks - // based on the ETHLockbox feature flag. - data = encodeSystemConfigInitializer(_input, output, _superchainConfig); - upgradeToAndCall( - output.opChainProxyAdmin, address(output.systemConfigProxy), implementation.systemConfigImpl, data - ); - - // If the custom gas token feature was requested, enable the custom gas token feature in the SystemConfig - // contract. - if (_input.useCustomGasToken) { - output.systemConfigProxy.setFeature(Features.CUSTOM_GAS_TOKEN, true); - } - - // If the interop feature was requested, enable the ETHLockbox feature in the SystemConfig - // contract. Only other way to get the ETHLockbox feature as of u16a is to have already had - // the ETHLockbox in U16 and then upgrade to U16a. - if (isDevFeatureEnabled(DevFeatures.OPTIMISM_PORTAL_INTEROP)) { - output.systemConfigProxy.setFeature(Features.ETH_LOCKBOX, true); - } - - // Initialize the OptimismPortal. - if (isDevFeatureEnabled(DevFeatures.OPTIMISM_PORTAL_INTEROP)) { - data = encodeOptimismPortalInteropInitializer(output); - upgradeToAndCall( - output.opChainProxyAdmin, - address(output.optimismPortalProxy), - implementation.optimismPortalInteropImpl, - data - ); - } else { - data = encodeOptimismPortalInitializer(output); - upgradeToAndCall( - output.opChainProxyAdmin, address(output.optimismPortalProxy), implementation.optimismPortalImpl, data - ); - } - - // Initialize the ETHLockbox. - IOptimismPortal[] memory portals = new IOptimismPortal[](1); - portals[0] = output.optimismPortalProxy; - data = encodeETHLockboxInitializer(output, portals); - upgradeToAndCall(output.opChainProxyAdmin, address(output.ethLockboxProxy), implementation.ethLockboxImpl, data); - - data = encodeOptimismMintableERC20FactoryInitializer(output); - upgradeToAndCall( - output.opChainProxyAdmin, - address(output.optimismMintableERC20FactoryProxy), - implementation.optimismMintableERC20FactoryImpl, - data - ); - - data = encodeL1CrossDomainMessengerInitializer(output); - upgradeToAndCall( - output.opChainProxyAdmin, - address(output.l1CrossDomainMessengerProxy), - implementation.l1CrossDomainMessengerImpl, - data - ); - - data = encodeL1StandardBridgeInitializer(output); - upgradeToAndCall( - output.opChainProxyAdmin, address(output.l1StandardBridgeProxy), implementation.l1StandardBridgeImpl, data - ); - - // Eventually we will switch from DelayedWETHPermissionedGameProxy to DelayedWETHPermissionlessGameProxy. - data = encodeDelayedWETHInitializer(output); - upgradeToAndCall( - output.opChainProxyAdmin, - address(output.delayedWETHPermissionedGameProxy), - implementation.delayedWETHImpl, - data - ); - - // We set the initial owner to this contract, set game implementations, then transfer ownership. - data = encodeDisputeGameFactoryInitializer(); - upgradeToAndCall( - output.opChainProxyAdmin, - address(output.disputeGameFactoryProxy), - implementation.disputeGameFactoryImpl, - data - ); - // Extracted to helper function to avoid stack too deep error - _registerPermissionedGame(_input, implementation, output); - - transferOwnership(address(output.disputeGameFactoryProxy), address(_input.roles.opChainProxyAdminOwner)); - - data = encodeAnchorStateRegistryInitializer(_input, output); - upgradeToAndCall( - output.opChainProxyAdmin, - address(output.anchorStateRegistryProxy), - implementation.anchorStateRegistryImpl, - data - ); - - // -------- Finalize Deployment -------- - // Transfer ownership of the ProxyAdmin from this contract to the specified owner. - transferOwnership(address(output.opChainProxyAdmin), _input.roles.opChainProxyAdminOwner); - - emit Deployed(_input.l2ChainId, _deployer, abi.encode(output)); - return output; - } - - /// @notice Returns default, standard config arguments for the SystemConfig initializer. - /// This is used by subclasses to reduce code duplication. - function defaultSystemConfigParams( - OPContractsManager.DeployInput memory, /* _input */ - OPContractsManager.DeployOutput memory _output - ) - internal - view - virtual - returns (IResourceMetering.ResourceConfig memory resourceConfig_, ISystemConfig.Addresses memory opChainAddrs_) - { - resourceConfig_ = Constants.DEFAULT_RESOURCE_CONFIG(); - - opChainAddrs_ = ISystemConfig.Addresses({ - l1CrossDomainMessenger: address(_output.l1CrossDomainMessengerProxy), - l1ERC721Bridge: address(_output.l1ERC721BridgeProxy), - l1StandardBridge: address(_output.l1StandardBridgeProxy), - optimismPortal: address(_output.optimismPortalProxy), - optimismMintableERC20Factory: address(_output.optimismMintableERC20FactoryProxy), - delayedWETH: address(0), // Will be used in OPCMv2. - opcm: address(0) // Unsupported for V1. - }); - - assertValidContractAddress(opChainAddrs_.l1CrossDomainMessenger); - assertValidContractAddress(opChainAddrs_.l1ERC721Bridge); - assertValidContractAddress(opChainAddrs_.l1StandardBridge); - assertValidContractAddress(opChainAddrs_.optimismPortal); - assertValidContractAddress(opChainAddrs_.optimismMintableERC20Factory); - } - - // -------- Utilities -------- - - /// @notice Verifies that all inputs are valid and reverts if any are invalid. - /// Typically the proxy admin owner is expected to have code, but this is not enforced here. - function assertValidInputs(OPContractsManager.DeployInput calldata _input) internal view { - if (_input.l2ChainId == 0 || _input.l2ChainId == block.chainid) revert OPContractsManager.InvalidChainId(); - - if (_input.roles.opChainProxyAdminOwner == address(0)) { - revert OPContractsManager.InvalidRoleAddress("opChainProxyAdminOwner"); - } - if (_input.roles.systemConfigOwner == address(0)) { - revert OPContractsManager.InvalidRoleAddress("systemConfigOwner"); - } - if (_input.roles.batcher == address(0)) revert OPContractsManager.InvalidRoleAddress("batcher"); - if (_input.roles.unsafeBlockSigner == address(0)) { - revert OPContractsManager.InvalidRoleAddress("unsafeBlockSigner"); - } - if (_input.roles.proposer == address(0)) revert OPContractsManager.InvalidRoleAddress("proposer"); - if (_input.roles.challenger == address(0)) revert OPContractsManager.InvalidRoleAddress("challenger"); - - if (_input.startingAnchorRoot.length == 0) revert OPContractsManager.InvalidStartingAnchorRoot(); - if (bytes32(_input.startingAnchorRoot) == bytes32(0)) revert OPContractsManager.InvalidStartingAnchorRoot(); - } - - /// @notice Transfers ownership - function transferOwnership(address _target, address _newOwner) internal { - // All transferOwnership targets have the same selector, so we just use IAddressManager - IAddressManager(_target).transferOwnership(_newOwner); - } - - // -------- Initializer Encoding -------- - - /// @notice Helper method for encoding the L1ERC721Bridge initializer data. - function encodeL1ERC721BridgeInitializer(OPContractsManager.DeployOutput memory _output) - internal - view - virtual - returns (bytes memory) - { - return - abi.encodeCall(IL1ERC721Bridge.initialize, (_output.l1CrossDomainMessengerProxy, _output.systemConfigProxy)); - } - - /// @notice Helper method for encoding the OptimismPortal initializer data. - function encodeOptimismPortalInitializer(OPContractsManager.DeployOutput memory _output) - internal - view - virtual - returns (bytes memory) - { - return abi.encodeCall(IOptimismPortal.initialize, (_output.systemConfigProxy, _output.anchorStateRegistryProxy)); - } - - /// @notice Helper method for encoding the OptimismPortalInterop initializer data. - function encodeOptimismPortalInteropInitializer(OPContractsManager.DeployOutput memory _output) - internal - view - virtual - returns (bytes memory) - { - return abi.encodeCall( - IOptimismPortalInterop.initialize, - (_output.systemConfigProxy, _output.anchorStateRegistryProxy, _output.ethLockboxProxy) - ); - } - - /// @notice Helper method for encoding the ETHLockbox initializer data. - function encodeETHLockboxInitializer( - OPContractsManager.DeployOutput memory _output, - IOptimismPortal[] memory _portals - ) - internal - view - virtual - returns (bytes memory) - { - return abi.encodeCall(IETHLockbox.initialize, (_output.systemConfigProxy, _portals)); - } - - /// @notice Helper method for encoding the SystemConfig initializer data. - function encodeSystemConfigInitializer( - OPContractsManager.DeployInput memory _input, - OPContractsManager.DeployOutput memory _output, - ISuperchainConfig _superchainConfig - ) - internal - view - virtual - returns (bytes memory) - { - (IResourceMetering.ResourceConfig memory referenceResourceConfig, ISystemConfig.Addresses memory opChainAddrs) = - defaultSystemConfigParams(_input, _output); - - return systemConfigInitializerData(_input, _superchainConfig, referenceResourceConfig, opChainAddrs); - } - - /// @notice Helper method for encoding the call data for the SystemConfig initializer. - function systemConfigInitializerData( - OPContractsManager.DeployInput memory _input, - ISuperchainConfig _superchainConfig, - IResourceMetering.ResourceConfig memory _referenceResourceConfig, - ISystemConfig.Addresses memory _opChainAddrs - ) - internal - view - virtual - returns (bytes memory) - { - return abi.encodeCall( - ISystemConfig.initialize, - ( - _input.roles.systemConfigOwner, - _input.basefeeScalar, - _input.blobBasefeeScalar, - bytes32(uint256(uint160(_input.roles.batcher))), // batcherHash - _input.gasLimit, - _input.roles.unsafeBlockSigner, - _referenceResourceConfig, - chainIdToBatchInboxAddress(_input.l2ChainId), - _opChainAddrs, - _input.l2ChainId, - _superchainConfig - ) - ); - } - - /// @notice Helper method for encoding the OptimismMintableERC20Factory initializer data. - function encodeOptimismMintableERC20FactoryInitializer(OPContractsManager.DeployOutput memory _output) - internal - pure - virtual - returns (bytes memory) - { - return abi.encodeCall(IOptimismMintableERC20Factory.initialize, (address(_output.l1StandardBridgeProxy))); - } - - /// @notice Helper method for encoding the L1CrossDomainMessenger initializer data. - function encodeL1CrossDomainMessengerInitializer(OPContractsManager.DeployOutput memory _output) - internal - view - virtual - returns (bytes memory) - { - return - abi.encodeCall(IL1CrossDomainMessenger.initialize, (_output.systemConfigProxy, _output.optimismPortalProxy)); - } - - /// @notice Helper method for encoding the L1StandardBridge initializer data. - function encodeL1StandardBridgeInitializer(OPContractsManager.DeployOutput memory _output) - internal - view - virtual - returns (bytes memory) - { - return abi.encodeCall( - IL1StandardBridge.initialize, (_output.l1CrossDomainMessengerProxy, _output.systemConfigProxy) - ); - } - - function encodeDisputeGameFactoryInitializer() internal view virtual returns (bytes memory) { - // This contract must be the initial owner so we can set game implementations, then - // ownership is transferred after. - return abi.encodeCall(IDisputeGameFactory.initialize, (address(this))); - } - - function encodeAnchorStateRegistryInitializer( - OPContractsManager.DeployInput memory _input, - OPContractsManager.DeployOutput memory _output - ) - internal - view - virtual - returns (bytes memory) - { - Proposal memory startingAnchorRoot = abi.decode(_input.startingAnchorRoot, (Proposal)); - return abi.encodeCall( - IAnchorStateRegistry.initialize, - ( - _output.systemConfigProxy, - _output.disputeGameFactoryProxy, - startingAnchorRoot, - GameTypes.PERMISSIONED_CANNON - ) - ); - } - - function encodeDelayedWETHInitializer(OPContractsManager.DeployOutput memory _output) - internal - view - virtual - returns (bytes memory) - { - return abi.encodeCall(IDelayedWETH.initialize, (_output.systemConfigProxy)); - } -} - -/// @title OPContractsManagerInteropMigrator -/// @notice This contract is used to migrate one or more OP Stack chains to use the Super Root dispute -/// games and shared dispute game contracts. -contract OPContractsManagerInteropMigrator is OPContractsManagerBase { - /// @notice Thrown when the ProxyAdmin owner of one or more of the provided OP Stack chains - /// being migrated does not match the ProxyAdmin owner of the first provided chain. - error OPContractsManagerInteropMigrator_ProxyAdminOwnerMismatch(); - - /// @notice Thrown when the SuperchainConfig of one or more of the provided OP Stack chains - /// being migrated does not match the SuperchainConfig of the first provided chain. - error OPContractsManagerInteropMigrator_SuperchainConfigMismatch(); - - /// @notice Thrown when the absolute prestate of one or more of the provided OP Stack chains - /// being migrated does not match the absolute prestate of the first provided chain. - error OPContractsManagerInteropMigrator_AbsolutePrestateMismatch(); - - /// @notice Parameters for creating the new Super Root dispute games that must be provided by - /// the caller. Other parameters are selected automatically. - struct GameParameters { - address proposer; - address challenger; - uint256 maxGameDepth; - uint256 splitDepth; - uint256 initBond; - Duration clockExtension; - Duration maxClockDuration; - } - - /// @notice Input parameters for the migration. - struct MigrateInput { - bool usePermissionlessGame; - Proposal startingAnchorRoot; - GameParameters gameParameters; - OPContractsManager.OpChainConfig[] opChainConfigs; - } - - /// @param _contractsContainer Container of blueprints and implementations. - constructor(OPContractsManagerContractsContainer _contractsContainer) OPContractsManagerBase(_contractsContainer) { } - - /// @notice Migrates one or more OP Stack chains to use the Super Root dispute games and shared - /// dispute game contracts. - /// @dev WARNING: This is a one-way operation. You cannot easily undo this operation without a - /// smart contract upgrade. Do not call this function unless you are 100% confident that - /// you know what you're doing and that you are prepared to fully execute this migration. - /// @param _input The input parameters for the migration. - function migrate(MigrateInput calldata _input) public virtual { - // 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 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. - if (_input.opChainConfigs[i].systemConfigProxy.proxyAdmin().owner() != proxyAdmin.owner()) { - revert OPContractsManagerInteropMigrator_ProxyAdminOwnerMismatch(); - } - if (_input.opChainConfigs[i].cannonPrestate.raw() != _input.opChainConfigs[0].cannonPrestate.raw()) { - revert OPContractsManagerInteropMigrator_AbsolutePrestateMismatch(); - } - 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. - IOptimismPortalInterop[] memory portals = new IOptimismPortalInterop[](_input.opChainConfigs.length); - for (uint256 i = 0; i < _input.opChainConfigs.length; i++) { - portals[i] = IOptimismPortalInterop(payable(_input.opChainConfigs[i].systemConfigProxy.optimismPortal())); - } - - // Check that the portals have the same SuperchainConfig. - for (uint256 i = 0; i < portals.length; i++) { - if (portals[i].superchainConfig() != portals[0].superchainConfig()) { - revert OPContractsManagerInteropMigrator_SuperchainConfigMismatch(); - } - } - - // NOTE that here and in the rest of this function, we are using the first provided chain's - // ProxyAdmin contract as the ProxyAdmin for all of the newly shared contracts. This is - // safe because we already checked that all of the provided chains have the same ProxyAdmin - // owner and therefore have the same access models. - address proxyAdminOwner = proxyAdmin.owner(); - - // Deploy the new ETHLockbox. - // NOTE that here and in the rest of this function we use block.timestamp as a fake chain - // id for any new contracts that are deployed. The L2 chain id is not used for anything - // except the salt mixer, so making it the same as the block timestamp means that new - // contracts will be generated every time this function is called. This is totally fine for - // our purposes here, there's no strong need to have deterministic addresses ahead of time. - IETHLockbox newEthLockbox = IETHLockbox( - deployProxy({ - _l2ChainId: block.timestamp, - _proxyAdmin: proxyAdmin, - _saltMixer: reusableSaltMixer(_input.opChainConfigs[0].systemConfigProxy), - _contractName: "ETHLockbox-Interop" - }) - ); - - // Separate context to avoid stack too deep. - { - // Lockbox requires standard portal interfaces, need to cast to IOptimismPortal. - IOptimismPortal[] memory castedPortals; - assembly ("memory-safe") { - castedPortals := portals - } - - // Initialize the new ETHLockbox. - // Note that this authorizes the portals to use the ETHLockbox. - upgradeToAndCall( - proxyAdmin, - address(newEthLockbox), - getImplementations().ethLockboxImpl, - abi.encodeCall(IETHLockbox.initialize, (portals[0].systemConfig(), castedPortals)) - ); - } - - // Deploy the new DisputeGameFactory. - IDisputeGameFactory newDisputeGameFactory = IDisputeGameFactory( - deployProxy({ - _l2ChainId: block.timestamp, - _proxyAdmin: proxyAdmin, - _saltMixer: reusableSaltMixer(_input.opChainConfigs[0].systemConfigProxy), - _contractName: "DisputeGameFactory-Interop" - }) - ); - - // Initialize the new DisputeGameFactory. - upgradeToAndCall( - proxyAdmin, - address(newDisputeGameFactory), - getImplementations().disputeGameFactoryImpl, - abi.encodeCall(IDisputeGameFactory.initialize, (proxyAdminOwner)) - ); - - // Deploy the new AnchorStateRegistry. - IAnchorStateRegistry newAnchorStateRegistry = IAnchorStateRegistry( - deployProxy({ - _l2ChainId: block.timestamp, - _proxyAdmin: proxyAdmin, - _saltMixer: reusableSaltMixer(_input.opChainConfigs[0].systemConfigProxy), - _contractName: "AnchorStateRegistry-Interop" - }) - ); - - // Select the correct game type based on the input. - GameType newGameType; - if (_input.usePermissionlessGame) { - newGameType = GameTypes.SUPER_CANNON; - } else { - newGameType = GameTypes.SUPER_PERMISSIONED_CANNON; - } - - // We can use portals[0].systemConfig() as they are members of the same superchain cluster (shared lockbox) - // Initialize the new AnchorStateRegistry. - upgradeToAndCall( - proxyAdmin, - address(newAnchorStateRegistry), - getImplementations().anchorStateRegistryImpl, - abi.encodeCall( - IAnchorStateRegistry.initialize, - (portals[0].systemConfig(), newDisputeGameFactory, _input.startingAnchorRoot, newGameType) - ) - ); - - // Migrate each portal to the new ETHLockbox and AnchorStateRegistry. - for (uint256 i = 0; i < portals.length; i++) { - // Authorize the existing ETHLockboxes to use the new ETHLockbox. - IETHLockbox existingLockbox = IETHLockbox(payable(address(portals[i].ethLockbox()))); - newEthLockbox.authorizeLockbox(existingLockbox); - - // Migrate the existing ETHLockbox to the new ETHLockbox. - existingLockbox.migrateLiquidity(newEthLockbox); - - // Before migrating the portal, clear out any implementations that might exist in the - // old DisputeGameFactory proxy. We clear out all potential game types to be safe. - IDisputeGameFactory oldDisputeGameFactory = - IDisputeGameFactory(payable(address(portals[i].disputeGameFactory()))); - clearGameImplementation(oldDisputeGameFactory, GameTypes.CANNON); - clearGameImplementation(oldDisputeGameFactory, GameTypes.SUPER_CANNON); - clearGameImplementation(oldDisputeGameFactory, GameTypes.PERMISSIONED_CANNON); - clearGameImplementation(oldDisputeGameFactory, GameTypes.SUPER_PERMISSIONED_CANNON); - clearGameImplementation(oldDisputeGameFactory, GameTypes.CANNON_KONA); - clearGameImplementation(oldDisputeGameFactory, GameTypes.SUPER_CANNON_KONA); - - // Migrate the portal to the new ETHLockbox and AnchorStateRegistry. - portals[i].migrateToSuperRoots(newEthLockbox, newAnchorStateRegistry); - } - - // Separate context to avoid stack too deep. - { - // Deploy a new DelayedWETH proxy for the permissioned game. - IDelayedWETH newPermissionedDelayedWETHProxy = IDelayedWETH( - payable( - deployProxy({ - _l2ChainId: block.timestamp, - _proxyAdmin: proxyAdmin, - _saltMixer: reusableSaltMixer(_input.opChainConfigs[0].systemConfigProxy), - _contractName: "DelayedWETH-Interop-Permissioned" - }) - ) - ); - - // Initialize the new DelayedWETH proxy. - upgradeToAndCall( - proxyAdmin, - address(newPermissionedDelayedWETHProxy), - getImplementations().delayedWETHImpl, - abi.encodeCall(IDelayedWETH.initialize, (portals[0].systemConfig())) - ); - - // NOTE that we use a chain id of 0 here (instead of the block timestamp) because the - // use of the chain id is different and actually passed into the constructor of the - // dispute game contracts. Since these are Super dispute games and involve multiple - // chains, the contracts enforce that the chain id is zero. - bytes memory gameArgs = LibGameArgs.encode( - LibGameArgs.GameArgs({ - absolutePrestate: _input.opChainConfigs[0].cannonPrestate.raw(), - vm: address(getImplementations().mipsImpl), - anchorStateRegistry: address(newAnchorStateRegistry), - weth: address(newPermissionedDelayedWETHProxy), - l2ChainId: uint256(0), - proposer: _input.gameParameters.proposer, - challenger: _input.gameParameters.challenger - }) - ); - // Register the new SuperPermissionedDisputeGame. - newDisputeGameFactory.setImplementation( - GameTypes.SUPER_PERMISSIONED_CANNON, - IDisputeGame(implementations().superPermissionedDisputeGameImpl), - gameArgs - ); - newDisputeGameFactory.setInitBond(GameTypes.SUPER_PERMISSIONED_CANNON, _input.gameParameters.initBond); - } - - // If the permissionless game is being used, set that up too. - if (_input.usePermissionlessGame) { - // Deploy a new DelayedWETH proxy for the permissionless game. - IDelayedWETH newPermissionlessDelayedWETHProxy = IDelayedWETH( - payable( - deployProxy({ - _l2ChainId: block.timestamp, - _proxyAdmin: proxyAdmin, - _saltMixer: reusableSaltMixer(_input.opChainConfigs[0].systemConfigProxy), - _contractName: "DelayedWETH-Interop-Permissionless" - }) - ) - ); - - // Initialize the new DelayedWETH proxy. - upgradeToAndCall( - proxyAdmin, - address(newPermissionlessDelayedWETHProxy), - getImplementations().delayedWETHImpl, - abi.encodeCall(IDelayedWETH.initialize, (portals[0].systemConfig())) - ); - - // Register the new SuperFaultDisputeGame. - bytes memory gameArgs = LibGameArgs.encode( - LibGameArgs.GameArgs({ - absolutePrestate: _input.opChainConfigs[0].cannonPrestate.raw(), - vm: address(getImplementations().mipsImpl), - anchorStateRegistry: address(newAnchorStateRegistry), - weth: address(newPermissionlessDelayedWETHProxy), - l2ChainId: uint256(0), - proposer: address(0), - challenger: address(0) - }) - ); - newDisputeGameFactory.setImplementation( - 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 (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 { - _dgf.setImplementation(_gameType, IDisputeGame(address(0)), hex""); - } -} - -contract OPContractsManager is ISemver { - // -------- Structs -------- - - /// @notice Represents the roles that can be set when deploying a standard OP Stack chain. - struct Roles { - address opChainProxyAdminOwner; - address systemConfigOwner; - address batcher; - address unsafeBlockSigner; - address proposer; - address challenger; - } - - /// @notice The full set of inputs to deploy a new OP Stack chain. - struct DeployInput { - Roles roles; - uint32 basefeeScalar; - uint32 blobBasefeeScalar; - uint256 l2ChainId; - // The correct type is Proposal memory but OP Deployer does not yet support structs. - bytes startingAnchorRoot; - // The salt mixer is used as part of making the resulting salt unique. - string saltMixer; - uint64 gasLimit; - // Configurable dispute game parameters. - GameType disputeGameType; - Claim disputeAbsolutePrestate; - uint256 disputeMaxGameDepth; - uint256 disputeSplitDepth; - Duration disputeClockExtension; - Duration disputeMaxClockDuration; - // Whether to use the custom gas token. - bool useCustomGasToken; - } - - /// @notice The full set of outputs from deploying a new OP Stack chain. - struct DeployOutput { - IProxyAdmin opChainProxyAdmin; - IAddressManager addressManager; - IL1ERC721Bridge l1ERC721BridgeProxy; - ISystemConfig systemConfigProxy; - IOptimismMintableERC20Factory optimismMintableERC20FactoryProxy; - IL1StandardBridge l1StandardBridgeProxy; - IL1CrossDomainMessenger l1CrossDomainMessengerProxy; - IETHLockbox ethLockboxProxy; - // Fault proof contracts below. - IOptimismPortal optimismPortalProxy; - IDisputeGameFactory disputeGameFactoryProxy; - IAnchorStateRegistry anchorStateRegistryProxy; - IFaultDisputeGame faultDisputeGame; - IPermissionedDisputeGame permissionedDisputeGame; - IDelayedWETH delayedWETHPermissionedGameProxy; - IDelayedWETH delayedWETHPermissionlessGameProxy; - } - - /// @notice Addresses of ERC-5202 Blueprint contracts. There are used for deploying full size - /// contracts, to reduce the code size of this factory contract. If it deployed full contracts - /// using the `new Proxy()` syntax, the code size would get large fast, since this contract would - /// contain the bytecode of every contract it deploys. Therefore we instead use Blueprints to - /// reduce the code size of this contract. - struct Blueprints { - address addressManager; - address proxy; - address proxyAdmin; - address l1ChugSplashProxy; - address resolvedDelegateProxy; - } - - /// @notice The latest implementation contracts for the OP Stack. - struct Implementations { - address superchainConfigImpl; - address protocolVersionsImpl; - address l1ERC721BridgeImpl; - address optimismPortalImpl; - address optimismPortalInteropImpl; - address ethLockboxImpl; - address systemConfigImpl; - address optimismMintableERC20FactoryImpl; - address l1CrossDomainMessengerImpl; - address l1StandardBridgeImpl; - address disputeGameFactoryImpl; - address anchorStateRegistryImpl; - address delayedWETHImpl; - address mipsImpl; - address faultDisputeGameImpl; - address permissionedDisputeGameImpl; - address superFaultDisputeGameImpl; - address superPermissionedDisputeGameImpl; - } - - /// @notice The input required to identify a chain for upgrading, along with new prestate hashes - struct OpChainConfig { - ISystemConfig systemConfigProxy; - Claim cannonPrestate; - Claim cannonKonaPrestate; - } - - /// @notice The input required to identify a chain for updating prestates - struct UpdatePrestateInput { - ISystemConfig systemConfigProxy; - Claim cannonPrestate; - Claim cannonKonaPrestate; - } - - struct AddGameInput { - string saltMixer; - ISystemConfig systemConfig; - IDelayedWETH delayedWETH; - GameType disputeGameType; - Claim disputeAbsolutePrestate; - uint256 disputeMaxGameDepth; - uint256 disputeSplitDepth; - Duration disputeClockExtension; - Duration disputeMaxClockDuration; - uint256 initialBond; - IBigStepper vm; - bool permissioned; - } - - struct AddGameOutput { - IDelayedWETH delayedWETH; - IFaultDisputeGame faultDisputeGame; - } - - // -------- Constants and Variables -------- - - /// @dev This needs to stay at 6.x.x because the next release will ship OPCMv2. Since we are - /// not actually planning to release a 7.x.x of OPCMv1, it needs to stay at 6.x.x to avoid - /// errors in the versioning rules of OPCMv2. - /// @custom:semver 6.0.5 - function version() public pure virtual returns (string memory) { - return "6.0.5"; - } - - OPContractsManagerGameTypeAdder public immutable opcmGameTypeAdder; - - OPContractsManagerDeployer public immutable opcmDeployer; - - OPContractsManagerUpgrader public immutable opcmUpgrader; - - OPContractsManagerInteropMigrator public immutable opcmInteropMigrator; - - OPContractsManagerStandardValidator public immutable opcmStandardValidator; - - /// @notice Address of the SuperchainConfig contract shared by all chains. - ISuperchainConfig public immutable superchainConfig; - - /// @notice Address of the ProtocolVersions contract shared by all chains. - IProtocolVersions public immutable protocolVersions; - - /// @notice The OPContractsManager contract that is currently being used. This is needed in the upgrade function - /// which is intended to be DELEGATECALLed. - OPContractsManager internal immutable thisOPCM; - - // -------- Errors -------- - - /// @notice Thrown when an address is the zero address. - error AddressNotFound(address who); - - /// @notice Throw when a contract address has no code. - error AddressHasNoCode(address who); - - /// @notice Thrown when a release version is already set. - error AlreadyReleased(); - - /// @notice Thrown when an invalid `l2ChainId` is provided to `deploy`. - error InvalidChainId(); - - /// @notice Thrown when a role's address is not valid. - error InvalidRoleAddress(string role); - - /// @notice Thrown when the latest release is not set upon initialization. - error LatestReleaseNotSet(); - - /// @notice Thrown when the starting anchor root is not provided. - error InvalidStartingAnchorRoot(); - - /// @notice Thrown when certain methods are called outside of a DELEGATECALL. - error OnlyDelegatecall(); - - /// @notice Thrown when game configs passed to addGameType are invalid. - error InvalidGameConfigs(); - - /// @notice Thrown when the SuperchainConfig of the chain does not match the SuperchainConfig of this OPCM. - error SuperchainConfigMismatch(ISystemConfig systemConfig); - - /// @notice Thrown when the SuperchainProxyAdmin does not match the SuperchainConfig's admin. - error SuperchainProxyAdminMismatch(); - - /// @notice Thrown when a prestate is not set for a game. - error PrestateNotSet(); - - /// @notice Thrown when the prestate of a permissioned disputed game is 0. - error PrestateRequired(); - - /// @notice Thrown if logic gated by a dev feature flag is incorrectly accessed. - error InvalidDevFeatureAccess(bytes32 devFeature); - - /// @notice Thrown when OPCM v2 is enabled via dev feature flag. - error OPContractsManager_V2Enabled(); - - // -------- Methods -------- - - constructor( - OPContractsManagerGameTypeAdder _opcmGameTypeAdder, - OPContractsManagerDeployer _opcmDeployer, - OPContractsManagerUpgrader _opcmUpgrader, - OPContractsManagerInteropMigrator _opcmInteropMigrator, - OPContractsManagerStandardValidator _opcmStandardValidator, - ISuperchainConfig _superchainConfig, - IProtocolVersions _protocolVersions - ) { - _opcmDeployer.assertValidContractAddress(address(_superchainConfig)); - _opcmDeployer.assertValidContractAddress(address(_protocolVersions)); - _opcmDeployer.assertValidContractAddress(address(_opcmGameTypeAdder)); - _opcmDeployer.assertValidContractAddress(address(_opcmDeployer)); - _opcmDeployer.assertValidContractAddress(address(_opcmUpgrader)); - _opcmDeployer.assertValidContractAddress(address(_opcmInteropMigrator)); - _opcmDeployer.assertValidContractAddress(address(_opcmStandardValidator)); - opcmGameTypeAdder = _opcmGameTypeAdder; - opcmDeployer = _opcmDeployer; - opcmUpgrader = _opcmUpgrader; - opcmInteropMigrator = _opcmInteropMigrator; - opcmStandardValidator = _opcmStandardValidator; - superchainConfig = _superchainConfig; - protocolVersions = _protocolVersions; - thisOPCM = this; - } - - /// @notice Validates the configuration of the L1 contracts. - function validate( - OPContractsManagerStandardValidator.ValidationInput memory _input, - bool _allowFailure - ) - public - view - returns (string memory) - { - return opcmStandardValidator.validate(_input, _allowFailure); - } - - /// @notice Validates the configuration of the L1 contracts. - /// @notice Supports overrides of certain storage values denoted in the ValidationOverrides struct. - function validateWithOverrides( - OPContractsManagerStandardValidator.ValidationInput memory _input, - bool _allowFailure, - OPContractsManagerStandardValidator.ValidationOverrides memory _overrides - ) - public - view - returns (string memory) - { - return opcmStandardValidator.validateWithOverrides(_input, _allowFailure, _overrides); - } - - /// @notice Validates the configuration of the L1 contracts. - function validate( - OPContractsManagerStandardValidator.ValidationInputDev memory _input, - bool _allowFailure - ) - public - view - returns (string memory) - { - return opcmStandardValidator.validate(_input, _allowFailure); - } - - /// @notice Validates the configuration of the L1 contracts. - /// @notice Supports overrides of certain storage values denoted in the ValidationOverrides struct. - function validateWithOverrides( - OPContractsManagerStandardValidator.ValidationInputDev memory _input, - bool _allowFailure, - OPContractsManagerStandardValidator.ValidationOverrides memory _overrides - ) - public - view - returns (string memory) - { - return opcmStandardValidator.validateWithOverrides(_input, _allowFailure, _overrides); - } - - /// @notice Deploys a new OP Stack chain. - /// @param _input The deploy input parameters for the deployment. - /// @return The deploy output values of the deployment. - function deploy(DeployInput calldata _input) external virtual returns (DeployOutput memory) { - _assertV2NotEnabled(); - - return opcmDeployer.deploy(_input, superchainConfig, msg.sender); - } - - /// @notice Upgrades a set of chains to the latest implementation contracts - /// @param _opChainConfigs Array of OpChain structs, one per chain to upgrade - /// @dev This function is intended to be DELEGATECALLed by an address that is the common owner of every chain in - /// `_opChainConfigs`'s ProxyAdmin. - /// @dev This function requires that each chain's superchainConfig is already upgraded. - function upgrade(OpChainConfig[] memory _opChainConfigs) external virtual { - _assertV2NotEnabled(); - - if (address(this) == address(thisOPCM)) revert OnlyDelegatecall(); - - bytes memory data = abi.encodeCall(OPContractsManagerUpgrader.upgrade, (_opChainConfigs)); - _performDelegateCall(address(opcmUpgrader), data); - } - - /// @notice Upgrades the SuperchainConfig contract. - /// @param _superchainConfig The SuperchainConfig contract to upgrade. - /// @dev This function is intended to be DELEGATECALLed by the superchainConfig's ProxyAdminOwner. - /// @dev This function will revert if the SuperchainConfig is already at or above the target version. - function upgradeSuperchainConfig(ISuperchainConfig _superchainConfig) external { - _assertV2NotEnabled(); - - if (address(this) == address(thisOPCM)) revert OnlyDelegatecall(); - - bytes memory data = abi.encodeCall(OPContractsManagerUpgrader.upgradeSuperchainConfig, (_superchainConfig)); - _performDelegateCall(address(opcmUpgrader), data); - } - - /// @notice addGameType deploys a new dispute game and links it to the DisputeGameFactory. The inputted _gameConfigs - /// must be added in ascending GameType order. - function addGameType(AddGameInput[] memory _gameConfigs) public virtual returns (AddGameOutput[] memory) { - _assertV2NotEnabled(); - - if (address(this) == address(thisOPCM)) revert OnlyDelegatecall(); - - bytes memory data = abi.encodeCall(OPContractsManagerGameTypeAdder.addGameType, (_gameConfigs)); - - bytes memory returnData = _performDelegateCall(address(opcmGameTypeAdder), data); - return abi.decode(returnData, (AddGameOutput[])); - } - - /// @notice Updates the prestate hash for dispute games while keeping all other parameters the same - /// @param _prestateUpdateInputs The new prestate hashes to use - function updatePrestate(UpdatePrestateInput[] memory _prestateUpdateInputs) public { - _assertV2NotEnabled(); - - if (address(this) == address(thisOPCM)) revert OnlyDelegatecall(); - - bytes memory data = abi.encodeCall(OPContractsManagerGameTypeAdder.updatePrestate, (_prestateUpdateInputs)); - - _performDelegateCall(address(opcmGameTypeAdder), data); - } - - /// @notice Migrates the Optimism contracts to the latest version. - /// @param _input Input parameters for the migration. - function migrate(OPContractsManagerInteropMigrator.MigrateInput calldata _input) external virtual { - _assertV2NotEnabled(); - - if (address(this) == address(thisOPCM)) revert OnlyDelegatecall(); - - bytes memory data = abi.encodeCall(OPContractsManagerInteropMigrator.migrate, (_input)); - _performDelegateCall(address(opcmInteropMigrator), data); - } - - /// @notice Maps an L2 chain ID to an L1 batch inbox address as defined by the standard - /// configuration's convention. This convention is `versionByte || keccak256(bytes32(chainId))[:19]`, - /// where || denotes concatenation`, versionByte is 0x00, and chainId is a uint256. - /// https://specs.optimism.io/protocol/configurability.html#consensus-parameters - function chainIdToBatchInboxAddress(uint256 _l2ChainId) public view returns (address) { - return opcmDeployer.chainIdToBatchInboxAddress(_l2ChainId); - } - - /// @notice Returns the blueprint contract addresses. - function blueprints() public view returns (Blueprints memory) { - return opcmDeployer.blueprints(); - } - - /// @notice Returns the implementation contract addresses. - function implementations() public view returns (Implementations memory) { - return opcmDeployer.implementations(); - } - - /// @notice Retrieves the development feature bitmap stored in this OPCM contract - /// @return The development feature bitmap. - function devFeatureBitmap() public view returns (bytes32) { - return opcmDeployer.devFeatureBitmap(); - } - - /// @notice Returns the status of a development feature. Note that this function does not check - /// that the input feature represents a single feature and the bitwise AND operation - /// allows for multiple features to be enabled at once. Users should generally check - /// for only a single feature at a time. - /// @param _feature The feature to check. - /// @return True if the feature is enabled, false otherwise. - function isDevFeatureEnabled(bytes32 _feature) public view returns (bool) { - return opcmDeployer.isDevFeatureEnabled(_feature); - } - - /// @notice Reverts if the dev feature flag for OPCM v2 is enabled. - function _assertV2NotEnabled() internal view { - if (isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - revert OPContractsManager_V2Enabled(); - } - } - - /// @notice Helper function to perform a delegatecall to a target contract - /// @param _target The target contract address - /// @param _data The calldata to send to the target - /// @return bytes The return data from the delegatecall - function _performDelegateCall(address _target, bytes memory _data) internal returns (bytes memory) { - // Perform the delegatecall - (bool success, bytes memory returnData) = _target.delegatecall(_data); - - // Check if the delegatecall was successful - if (!success) { - // If there was a revert message, bubble it up - assembly { - revert(add(returnData, 32), mload(returnData)) - } - } - - return returnData; - } -} diff --git a/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol b/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol index 7310b8d0ed3..1789ebb5aba 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManagerStandardValidator.sol @@ -40,8 +40,8 @@ import { IBigStepper } from "interfaces/dispute/IBigStepper.sol"; /// before and after an upgrade. contract OPContractsManagerStandardValidator is ISemver { /// @notice The semantic version of the OPContractsManagerStandardValidator contract. - /// @custom:semver 2.5.0 - string public constant version = "2.5.0"; + /// @custom:semver 2.7.0 + string public constant version = "2.7.0"; /// @notice The SuperchainConfig contract. ISuperchainConfig public superchainConfig; @@ -63,9 +63,6 @@ contract OPContractsManagerStandardValidator is ISemver { /// @notice The OptimismPortal implementation address. address public optimismPortalImpl; - /// @notice The OptimismPortalInterop implementation address. - address public optimismPortalInteropImpl; - /// @notice The ETHLockbox implementation address. address public ethLockboxImpl; @@ -112,7 +109,6 @@ contract OPContractsManagerStandardValidator is ISemver { struct Implementations { address l1ERC721BridgeImpl; address optimismPortalImpl; - address optimismPortalInteropImpl; address ethLockboxImpl; address systemConfigImpl; address optimismMintableERC20FactoryImpl; @@ -189,7 +185,6 @@ contract OPContractsManagerStandardValidator is ISemver { // Set implementation addresses from struct l1ERC721BridgeImpl = _implementations.l1ERC721BridgeImpl; optimismPortalImpl = _implementations.optimismPortalImpl; - optimismPortalInteropImpl = _implementations.optimismPortalInteropImpl; ethLockboxImpl = _implementations.ethLockboxImpl; systemConfigImpl = _implementations.systemConfigImpl; optimismMintableERC20FactoryImpl = _implementations.optimismMintableERC20FactoryImpl; @@ -437,23 +432,12 @@ contract OPContractsManagerStandardValidator is ISemver { { IOptimismPortal2 _portal = IOptimismPortal2(payable(_sysCfg.optimismPortal())); - if (DevFeatures.isDevFeatureEnabled(devFeatureBitmap, DevFeatures.OPTIMISM_PORTAL_INTEROP)) { - _errors = internalRequire( - LibString.eq(getVersion(address(_portal)), string.concat(getVersion(optimismPortalInteropImpl))), - "PORTAL-10", - _errors - ); - _errors = internalRequire( - getProxyImplementation(_admin, address(_portal)) == optimismPortalInteropImpl, "PORTAL-20", _errors - ); - } else { - _errors = internalRequire( - LibString.eq(getVersion(address(_portal)), getVersion(optimismPortalImpl)), "PORTAL-10", _errors - ); - _errors = internalRequire( - getProxyImplementation(_admin, address(_portal)) == optimismPortalImpl, "PORTAL-20", _errors - ); - } + _errors = internalRequire( + LibString.eq(getVersion(address(_portal)), getVersion(optimismPortalImpl)), "PORTAL-10", _errors + ); + _errors = internalRequire( + getProxyImplementation(_admin, address(_portal)) == optimismPortalImpl, "PORTAL-20", _errors + ); IDisputeGameFactory _dgf = IDisputeGameFactory(_sysCfg.disputeGameFactory()); _errors = internalRequire(address(_portal.disputeGameFactory()) == address(_dgf), "PORTAL-30", _errors); diff --git a/packages/contracts-bedrock/src/L1/OptimismPortal2.sol b/packages/contracts-bedrock/src/L1/OptimismPortal2.sol index 9117301b9d7..42fb472cbec 100644 --- a/packages/contracts-bedrock/src/L1/OptimismPortal2.sol +++ b/packages/contracts-bedrock/src/L1/OptimismPortal2.sol @@ -130,6 +130,18 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ReinitializableBase /// @custom:spacer superRootsActive bool private spacer_63_20_1; + /// @notice Emitted when the Portal is migrated. + /// @param oldLockbox The lockbox before the migration + /// @param newLockbox The shared lockbox + /// @param oldAnchorStateRegistry The anchorStateRegistry used before the migration + /// @param newAnchorStateRegistry The anchorStateRegistry used after the migration + event PortalMigrated( + IETHLockbox oldLockbox, + IETHLockbox newLockbox, + IAnchorStateRegistry oldAnchorStateRegistry, + IAnchorStateRegistry newAnchorStateRegistry + ); + /// @notice Emitted when a transaction is deposited from L1 to L2. The parameters of this event /// are read by the rollup node and used to derive deposit transactions on L2. /// @param from Address that triggered the deposit transaction. @@ -168,6 +180,9 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ReinitializableBase /// @notice Thrown when the portal is paused. error OptimismPortal_CallPaused(); + /// @notice Migrates the total ETH balance to the ETHLockbox. + event ETHMigrated(address indexed lockbox, uint256 balance); + /// @notice Thrown when a CGT withdrawal is not allowed. error OptimismPortal_NotAllowedOnCGTMode(); @@ -183,6 +198,9 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ReinitializableBase /// @notice Thrown when a withdrawal has not been proven against a valid dispute game. error OptimismPortal_InvalidDisputeGame(); + /// @notice Thrown when Interop is set without the lockbox feature flag + error OptimismPortal_InvalidInteropState(); + /// @notice Thrown when a withdrawal has not been proven against a valid merkle proof. error OptimismPortal_InvalidMerkleProof(); @@ -195,9 +213,17 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ReinitializableBase /// @notice Thrown when the root claim of a dispute game is invalid. error OptimismPortal_InvalidRootClaim(); + /// @notice Thrown when migrating to the registry that was previously + /// set on the OptimismPortal prior to the migration + error OptimismPortal_MigratingToSameRegistry(); + /// @notice Thrown when a withdrawal is being finalized by a reentrant call. error OptimismPortal_NoReentrancy(); + /// @notice Thrown when calling a function that is only available when INTEROP + /// is enabled + error OptimismPortal_NotUsingInterop(); + /// @notice Thrown when a withdrawal has not been proven for long enough. error OptimismPortal_ProofNotOldEnough(); @@ -208,9 +234,9 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ReinitializableBase error OptimismPortal_InvalidLockboxState(); /// @notice Semantic version. - /// @custom:semver 5.3.0 + /// @custom:semver 5.6.0 function version() public pure virtual returns (string memory) { - return "5.3.0"; + return "5.6.0"; } /// @param _proofMaturityDelaySeconds The proof maturity delay in seconds. @@ -224,7 +250,8 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ReinitializableBase /// @param _anchorStateRegistry Address of the AnchorStateRegistry. function initialize( ISystemConfig _systemConfig, - IAnchorStateRegistry _anchorStateRegistry + IAnchorStateRegistry _anchorStateRegistry, + IETHLockbox _ethLockbox ) external reinitializer(initVersion()) @@ -235,7 +262,11 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ReinitializableBase // Now perform initialization logic. systemConfig = _systemConfig; anchorStateRegistry = _anchorStateRegistry; + if (address(_ethLockbox) != address(0)) { + ethLockbox = _ethLockbox; + } + _assertValidInteropState(); // Assert that the lockbox state is valid. _assertValidLockboxState(); @@ -444,6 +475,67 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ReinitializableBase finalizeWithdrawalTransactionExternalProof(_tx, msg.sender); } + /// @notice Migrates the total ETH balance of this contract to the ETHLockbox. + function migrateLiquidity() public { + if (!_isUsingInterop()) revert OptimismPortal_NotUsingInterop(); + // Liquidity migration can only be triggered by the ProxyAdmin owner. + _assertOnlyProxyAdminOwner(); + + // Migrate the liquidity. + uint256 ethBalance = address(this).balance; + ethLockbox.lockETH{ value: ethBalance }(); + emit ETHMigrated(address(ethLockbox), ethBalance); + } + + /// @notice Allows the owner of the ProxyAdmin to migrate the OptimismPortal to use a new + /// lockbox, point at a new AnchorStateRegistry, and start to use the Super Roots proof + /// method. Primarily used for OptimismPortal instances to join the interop set, but + /// can also be used to swap the proof method from Output Roots to Super Roots if the + /// provided lockbox is the same as the current one. + /// @dev It is possible to change lockboxes without migrating liquidity. This can cause one + /// of the OptimismPortal instances connected to the new lockbox to not be able to + /// unlock sufficient ETH to finalize withdrawals which would trigger reverts. To avoid + /// this issue, guarantee that this function is called atomically alongside the + /// ETHLockbox.migrateLiquidity() function within the same transaction. + /// @param _newLockbox The address of the new ETHLockbox contract. + /// @param _newAnchorStateRegistry The address of the new AnchorStateRegistry contract. + + function migrateToSharedDisputeGame( + IETHLockbox _newLockbox, + IAnchorStateRegistry _newAnchorStateRegistry + ) + external + { + if (!_isUsingInterop()) revert OptimismPortal_NotUsingInterop(); + // Migration can only be triggered when the system is not paused because the migration can + // potentially unpause the system as a result of the modified ETHLockbox address. + _assertNotPaused(); + + // Migration can only be triggered by the ProxyAdmin owner. + _assertOnlyProxyAdminOwner(); + + // Chains can use this method to swap the proof method from Output Roots to Super Roots + // without joining the interop set. In this case, the old and new lockboxes will be the + // same. However, whether or not a chain is joining the interop set, all chains will need a + // new AnchorStateRegistry when migrating to Super Roots. We therefore check that the new + // AnchorStateRegistry is different than the old one to prevent this function from being + // accidentally misused. + if (anchorStateRegistry == _newAnchorStateRegistry) { + revert OptimismPortal_MigratingToSameRegistry(); + } + + // Update the ETHLockbox. + IETHLockbox oldLockbox = ethLockbox; + ethLockbox = _newLockbox; + + // Update the AnchorStateRegistry. + IAnchorStateRegistry oldAnchorStateRegistry = anchorStateRegistry; + anchorStateRegistry = _newAnchorStateRegistry; + + // Emit a PortalMigrated event. + emit PortalMigrated(oldLockbox, _newLockbox, oldAnchorStateRegistry, _newAnchorStateRegistry); + } + /// @notice Finalizes a withdrawal transaction, using an external proof submitter. /// @param _tx Withdrawal transaction to finalize. /// @param _proofSubmitter Address of the proof submitter. @@ -641,6 +733,12 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ReinitializableBase return systemConfig.isFeatureEnabled(Features.ETH_LOCKBOX) && address(ethLockbox) != address(0); } + /// @notice Checks if the Interop feature is enabled. + /// @return bool True if the Interop feature is enabled. + function _isUsingInterop() internal view returns (bool) { + return systemConfig.isFeatureEnabled(Features.INTEROP) && systemConfig.isFeatureEnabled(Features.ETH_LOCKBOX); + } + /// @notice Checks if the Custom Gas Token feature is enabled. /// @return bool True if the Custom Gas Token feature is enabled. function _isUsingCustomGasToken() internal view returns (bool) { @@ -656,6 +754,13 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ReinitializableBase } } + /// @notice Asserts the ETHLockbox feature flag must be set if INTEROP is set + function _assertValidInteropState() internal view { + if (systemConfig.isFeatureEnabled(Features.INTEROP) && !systemConfig.isFeatureEnabled(Features.ETH_LOCKBOX)) { + revert OptimismPortal_InvalidInteropState(); + } + } + /// @notice Asserts that the ETHLockbox is set/unset correctly depending on the feature flag. function _assertValidLockboxState() internal view { if ( diff --git a/packages/contracts-bedrock/src/L1/OptimismPortalInterop.sol b/packages/contracts-bedrock/src/L1/OptimismPortalInterop.sol deleted file mode 100644 index fda0ae38660..00000000000 --- a/packages/contracts-bedrock/src/L1/OptimismPortalInterop.sol +++ /dev/null @@ -1,744 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -// Contracts -import { ProxyAdminOwnedBase } from "src/universal/ProxyAdminOwnedBase.sol"; -import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -import { ResourceMetering } from "src/L1/ResourceMetering.sol"; -import { ReinitializableBase } from "src/universal/ReinitializableBase.sol"; - -// Libraries -import { EOA } from "src/libraries/EOA.sol"; -import { SafeCall } from "src/libraries/SafeCall.sol"; -import { Constants } from "src/libraries/Constants.sol"; -import { Types } from "src/libraries/Types.sol"; -import { Hashing } from "src/libraries/Hashing.sol"; -import { SecureMerkleTrie } from "src/libraries/trie/SecureMerkleTrie.sol"; -import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; -import { GameStatus, GameType, Claim } from "src/dispute/lib/Types.sol"; - -// Interfaces -import { ISemver } from "interfaces/universal/ISemver.sol"; -import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; -import { IResourceMetering } from "interfaces/L1/IResourceMetering.sol"; -import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; -import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; -import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; -import { IETHLockbox } from "interfaces/L1/IETHLockbox.sol"; -import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; - -/// @custom:proxied true -/// @title OptimismPortalInterop -/// @notice The OptimismPortal is a low-level contract responsible for passing messages between L1 -/// and L2. Messages sent directly to the OptimismPortal have no form of replayability. -/// Users are encouraged to use the L1CrossDomainMessenger for a higher-level interface. -contract OptimismPortalInterop is Initializable, ResourceMetering, ReinitializableBase, ProxyAdminOwnedBase, ISemver { - /// @notice Represents a proven withdrawal. - /// @custom:field disputeGameProxy Game that the withdrawal was proven against. - /// @custom:field timestamp Timestamp at which the withdrawal was proven. - struct ProvenWithdrawal { - IDisputeGame disputeGameProxy; - uint64 timestamp; - } - - /// @notice The delay between when a withdrawal is proven and when it may be finalized. - uint256 internal immutable PROOF_MATURITY_DELAY_SECONDS; - - /// @notice Version of the deposit event. - uint256 internal constant DEPOSIT_VERSION = 0; - - /// @notice The L2 gas limit set when eth is deposited using the receive() function. - uint64 internal constant RECEIVE_DEFAULT_GAS_LIMIT = 100_000; - - /// @notice Address of the L2 account which initiated a withdrawal in this transaction. - /// If the value of this variable is the default L2 sender address, then we are NOT - /// inside of a call to finalizeWithdrawalTransaction. - address public l2Sender; - - /// @notice A list of withdrawal hashes which have been successfully finalized. - mapping(bytes32 => bool) public finalizedWithdrawals; - - /// @custom:legacy - /// @custom:spacer provenWithdrawals - /// @notice Spacer taking up the legacy `provenWithdrawals` mapping slot. - bytes32 private spacer_52_0_32; - - /// @custom:legacy - /// @custom:spacer paused - /// @notice Spacer for backwards compatibility. - bool private spacer_53_0_1; - - /// @custom:legacy - /// @custom:spacer superchainConfig - /// @notice Spacer for backwards compatibility. - address private spacer_53_1_20; - - /// @custom:legacy - /// @custom:spacer l2Oracle - /// @notice Spacer taking up the legacy `l2Oracle` address slot. - address private spacer_54_0_20; - - /// @notice Address of the SystemConfig contract. - /// @custom:network-specific - ISystemConfig public systemConfig; - - /// @custom:network-specific - /// @custom:legacy - /// @custom:spacer disputeGameFactory - /// @notice Spacer taking up the legacy `disputeGameFactory` address slot. - address private spacer_56_0_20; - - /// @notice A mapping of withdrawal hashes to proof submitters to ProvenWithdrawal data. - mapping(bytes32 => mapping(address => ProvenWithdrawal)) public provenWithdrawals; - - /// @custom:legacy - /// @custom:spacer disputeGameBlacklist - bytes32 private spacer_58_0_32; - - /// @custom:legacy - /// @custom:spacer respectedGameType - GameType private spacer_59_0_4; - - /// @custom:legacy - /// @custom:spacer respectedGameTypeUpdatedAt - uint64 private spacer_59_4_8; - - /// @notice Mapping of withdrawal hashes to addresses that have submitted a proof for the - /// withdrawal. Original OptimismPortal contract only allowed one proof to be submitted - /// for any given withdrawal hash. Fault Proofs version of this contract must allow - /// multiple proofs for the same withdrawal hash to prevent a malicious user from - /// blocking other withdrawals by proving them against invalid proposals. Submitters - /// are tracked in an array to simplify the off-chain process of determining which - /// proof submission should be used when finalizing a withdrawal. - mapping(bytes32 => address[]) public proofSubmitters; - - /// @custom:legacy - /// @custom:spacer _balance - uint256 private spacer_61_0_32; - - /// @notice Address of the AnchorStateRegistry contract. - IAnchorStateRegistry public anchorStateRegistry; - - /// @notice Address of the ETHLockbox contract. - IETHLockbox public ethLockbox; - - /// @notice Whether the OptimismPortal is using Super Roots or Output Roots. - bool public superRootsActive; - - /// @notice Emitted when a transaction is deposited from L1 to L2. The parameters of this event - /// are read by the rollup node and used to derive deposit transactions on L2. - /// @param from Address that triggered the deposit transaction. - /// @param to Address that the deposit transaction is directed to. - /// @param version Version of this deposit transaction event. - /// @param opaqueData ABI encoded deposit data to be parsed off-chain. - event TransactionDeposited(address indexed from, address indexed to, uint256 indexed version, bytes opaqueData); - - /// @notice Emitted when a withdrawal transaction is proven. - /// @param withdrawalHash Hash of the withdrawal transaction. - /// @param from Address that triggered the withdrawal transaction. - /// @param to Address that the withdrawal transaction is directed to. - event WithdrawalProven(bytes32 indexed withdrawalHash, address indexed from, address indexed to); - - /// @notice Emitted when a withdrawal transaction is proven. Exists as a separate event to - /// allow for backwards compatibility for tooling that observes the WithdrawalProven - /// event. - /// @param withdrawalHash Hash of the withdrawal transaction. - /// @param proofSubmitter Address of the proof submitter. - event WithdrawalProvenExtension1(bytes32 indexed withdrawalHash, address indexed proofSubmitter); - - /// @notice Emitted when a withdrawal transaction is finalized. - /// @param withdrawalHash Hash of the withdrawal transaction. - /// @param success Whether the withdrawal transaction was successful. - event WithdrawalFinalized(bytes32 indexed withdrawalHash, bool success); - - /// @notice Emitted when the total ETH balance is migrated to the ETHLockbox. - /// @param lockbox The address of the ETHLockbox contract. - /// @param ethBalance Amount of ETH migrated. - event ETHMigrated(address indexed lockbox, uint256 ethBalance); - - /// @notice Emitted when the ETHLockbox contract is updated. - /// @param oldLockbox The address of the old ETHLockbox contract. - /// @param newLockbox The address of the new ETHLockbox contract. - /// @param oldAnchorStateRegistry The address of the old AnchorStateRegistry contract. - /// @param newAnchorStateRegistry The address of the new AnchorStateRegistry contract. - event PortalMigrated( - IETHLockbox oldLockbox, - IETHLockbox newLockbox, - IAnchorStateRegistry oldAnchorStateRegistry, - IAnchorStateRegistry newAnchorStateRegistry - ); - - /// @notice Thrown when a withdrawal has already been finalized. - error OptimismPortal_AlreadyFinalized(); - - /// @notice Thrown when the target of a withdrawal is unsafe. - error OptimismPortal_BadTarget(); - - /// @notice Thrown when the calldata for a deposit is too large. - error OptimismPortal_CalldataTooLarge(); - - /// @notice Thrown when the portal is paused. - error OptimismPortal_CallPaused(); - - /// @notice Thrown when a gas estimation transaction is being executed. - error OptimismPortal_GasEstimation(); - - /// @notice Thrown when the gas limit for a deposit is too low. - error OptimismPortal_GasLimitTooLow(); - - /// @notice Thrown when the target of a withdrawal is not a proper dispute game. - error OptimismPortal_ImproperDisputeGame(); - - /// @notice Thrown when a withdrawal has not been proven against a valid dispute game. - error OptimismPortal_InvalidDisputeGame(); - - /// @notice Thrown when a withdrawal has not been proven against a valid merkle proof. - error OptimismPortal_InvalidMerkleProof(); - - /// @notice Thrown when a withdrawal has not been proven against a valid output root proof. - error OptimismPortal_InvalidOutputRootProof(); - - /// @notice Thrown when a withdrawal's timestamp is not greater than the dispute game's creation timestamp. - error OptimismPortal_InvalidProofTimestamp(); - - /// @notice Thrown when the root claim of a dispute game is invalid. - error OptimismPortal_InvalidRootClaim(); - - /// @notice Thrown when a withdrawal is being finalized by a reentrant call. - error OptimismPortal_NoReentrancy(); - - /// @notice Thrown when a withdrawal has not been proven for long enough. - error OptimismPortal_ProofNotOldEnough(); - - /// @notice Thrown when a withdrawal has not been proven. - error OptimismPortal_Unproven(); - - /// @notice Thrown when trying to migrate to the same AnchorStateRegistry. - error OptimismPortal_MigratingToSameRegistry(); - - /// @notice Semantic version. - /// @custom:semver 5.3.1+interop - function version() public pure virtual returns (string memory) { - return "5.3.1+interop"; - } - - /// @param _proofMaturityDelaySeconds The proof maturity delay in seconds. - constructor(uint256 _proofMaturityDelaySeconds) ReinitializableBase(4) { - PROOF_MATURITY_DELAY_SECONDS = _proofMaturityDelaySeconds; - _disableInitializers(); - } - - /// @notice Initializer. - /// @param _systemConfig Address of the SystemConfig. - /// @param _anchorStateRegistry Address of the AnchorStateRegistry. - /// @param _ethLockbox Contract of the ETHLockbox. - function initialize( - ISystemConfig _systemConfig, - IAnchorStateRegistry _anchorStateRegistry, - IETHLockbox _ethLockbox - ) - external - reinitializer(initVersion()) - { - // Initialization transactions must come from the ProxyAdmin or its owner. - _assertOnlyProxyAdminOrProxyAdminOwner(); - - // Now perform initialization logic. - systemConfig = _systemConfig; - anchorStateRegistry = _anchorStateRegistry; - ethLockbox = _ethLockbox; - - // Set the l2Sender slot, only if it is currently empty. This signals the first - // initialization of the contract. - if (l2Sender == address(0)) { - l2Sender = Constants.DEFAULT_L2_SENDER; - } - - __ResourceMetering_init(); - } - - /// @notice Upgrades the OptimismPortal contract to have a reference to the AnchorStateRegistry and SystemConfig - /// @param _anchorStateRegistry AnchorStateRegistry contract. - /// @param _ethLockbox ETHLockbox contract. - function upgrade( - IAnchorStateRegistry _anchorStateRegistry, - IETHLockbox _ethLockbox - ) - external - reinitializer(initVersion()) - { - // Upgrade transactions must come from the ProxyAdmin or its owner. - _assertOnlyProxyAdminOrProxyAdminOwner(); - - // Now perform upgrade logic. - anchorStateRegistry = _anchorStateRegistry; - ethLockbox = _ethLockbox; - } - - /// @notice Getter for the current paused status. - function paused() public view returns (bool) { - return systemConfig.paused(); - } - - /// @notice Getter for the proof maturity delay. - function proofMaturityDelaySeconds() public view returns (uint256) { - return PROOF_MATURITY_DELAY_SECONDS; - } - - /// @notice Getter for the address of the DisputeGameFactory contract. - function disputeGameFactory() public view returns (IDisputeGameFactory) { - return anchorStateRegistry.disputeGameFactory(); - } - - /// @notice Returns the SuperchainConfig contract. - /// @return ISuperchainConfig The SuperchainConfig contract. - function superchainConfig() external view returns (ISuperchainConfig) { - return systemConfig.superchainConfig(); - } - - /// @custom:legacy - /// @notice Getter function for the address of the guardian. - function guardian() external view returns (address) { - return systemConfig.guardian(); - } - - /// @custom:legacy - /// @notice Getter for the dispute game finality delay. - function disputeGameFinalityDelaySeconds() external view returns (uint256) { - return anchorStateRegistry.disputeGameFinalityDelaySeconds(); - } - - /// @custom:legacy - /// @notice Getter for the respected game type. - function respectedGameType() external view returns (GameType) { - return anchorStateRegistry.respectedGameType(); - } - - /// @custom:legacy - /// @notice Getter for the retirement timestamp. Note that this value NO LONGER reflects the - /// timestamp at which the respected game type was updated. Game retirement and - /// respected game type value have been decoupled, this function now only returns the - /// retirement timestamp. - function respectedGameTypeUpdatedAt() external view returns (uint64) { - return anchorStateRegistry.retirementTimestamp(); - } - - /// @custom:legacy - /// @notice Getter for the dispute game blacklist. - /// @param _disputeGame The dispute game to check. - /// @return Whether the dispute game is blacklisted. - function disputeGameBlacklist(IDisputeGame _disputeGame) public view returns (bool) { - return anchorStateRegistry.disputeGameBlacklist(_disputeGame); - } - - /// @notice Computes the minimum gas limit for a deposit. - /// The minimum gas limit linearly increases based on the size of the calldata. - /// This is to prevent users from creating L2 resource usage without paying for it. - /// This function can be used when interacting with the portal to ensure forwards - /// compatibility. - /// @param _byteCount Number of bytes in the calldata. - /// @return The minimum gas limit for a deposit. - function minimumGasLimit(uint64 _byteCount) public pure returns (uint64) { - return _byteCount * 40 + 21000; - } - - /// @notice Accepts value so that users can send ETH directly to this contract and have the - /// funds be deposited to their address on L2. This is intended as a convenience - /// function for EOAs. Contracts should call the depositTransaction() function directly - /// otherwise any deposited funds will be lost due to address aliasing. - receive() external payable { - depositTransaction(msg.sender, msg.value, RECEIVE_DEFAULT_GAS_LIMIT, false, bytes("")); - } - - /// @notice Accepts ETH value without triggering a deposit to L2. - function donateETH() external payable { - // Intentionally empty. - } - - /// @notice Migrates the total ETH balance to the ETHLockbox. - function migrateLiquidity() public { - // Liquidity migration can only be triggered by the ProxyAdmin owner. - _assertOnlyProxyAdminOwner(); - - // Migrate the liquidity. - uint256 ethBalance = address(this).balance; - ethLockbox.lockETH{ value: ethBalance }(); - emit ETHMigrated(address(ethLockbox), ethBalance); - } - - /// @notice Allows the owner of the ProxyAdmin to migrate the OptimismPortal to use a new - /// lockbox, point at a new AnchorStateRegistry, and start to use the Super Roots proof - /// method. Primarily used for OptimismPortal instances to join the interop set, but - /// can also be used to swap the proof method from Output Roots to Super Roots if the - /// provided lockbox is the same as the current one. - /// @dev It is possible to change lockboxes without migrating liquidity. This can cause one - /// of the OptimismPortal instances connected to the new lockbox to not be able to - /// unlock sufficient ETH to finalize withdrawals which would trigger reverts. To avoid - /// this issue, guarantee that this function is called atomically alongside the - /// ETHLockbox.migrateLiquidity() function within the same transaction. - /// @param _newLockbox The address of the new ETHLockbox contract. - /// @param _newAnchorStateRegistry The address of the new AnchorStateRegistry contract. - function migrateToSuperRoots(IETHLockbox _newLockbox, IAnchorStateRegistry _newAnchorStateRegistry) external { - // Migration can only be triggered when the system is not paused because the migration can - // potentially unpause the system as a result of the modified ETHLockbox address. - _assertNotPaused(); - - // Migration can only be triggered by the ProxyAdmin owner. - _assertOnlyProxyAdminOwner(); - - // Chains can use this method to swap the proof method from Output Roots to Super Roots - // without joining the interop set. In this case, the old and new lockboxes will be the - // same. However, whether or not a chain is joining the interop set, all chains will need a - // new AnchorStateRegistry when migrating to Super Roots. We therefore check that the new - // AnchorStateRegistry is different than the old one to prevent this function from being - // accidentally misused. - if (anchorStateRegistry == _newAnchorStateRegistry) { - revert OptimismPortal_MigratingToSameRegistry(); - } - - // Update the ETHLockbox. - IETHLockbox oldLockbox = ethLockbox; - ethLockbox = _newLockbox; - - // Update the AnchorStateRegistry. - IAnchorStateRegistry oldAnchorStateRegistry = anchorStateRegistry; - anchorStateRegistry = _newAnchorStateRegistry; - - // Set the proof method to Super Roots. We expect that migration will happen more than once - // for some chains (switching to single-chain Super Roots and then later joining the - // interop set) so we don't need to check that this is false. - superRootsActive = true; - - // Emit a PortalMigrated event. - emit PortalMigrated(oldLockbox, _newLockbox, oldAnchorStateRegistry, _newAnchorStateRegistry); - } - - /// @notice Proves a withdrawal transaction. When super roots are active, uses the game's - /// rootClaimByChainId to get the output root for this chain. When super roots are - /// inactive, validates directly against the game's root claim. - /// @param _tx Withdrawal transaction to finalize. - /// @param _disputeGameIndex Index of the dispute game to prove the withdrawal against. - /// @param _outputRootProof Inclusion proof of the L2ToL1MessagePasser storage root. - /// @param _withdrawalProof Inclusion proof of the withdrawal within the L2ToL1MessagePasser. - function proveWithdrawalTransaction( - Types.WithdrawalTransaction memory _tx, - uint256 _disputeGameIndex, - Types.OutputRootProof calldata _outputRootProof, - bytes[] calldata _withdrawalProof - ) - external - { - _assertNotPaused(); - - // Fetch the dispute game proxy from the DisputeGameFactory contract. - (,, IDisputeGame disputeGameProxy) = disputeGameFactory().gameAtIndex(_disputeGameIndex); - - _proveWithdrawalTransaction(_tx, disputeGameProxy, _outputRootProof, _withdrawalProof); - } - - /// @notice Internal function for proving a withdrawal transaction. - /// @param _tx Withdrawal transaction to prove. - /// @param _disputeGameProxy Address of the dispute game to prove the withdrawal against. - /// @param _outputRootProof Inclusion proof of the L2ToL1MessagePasser storage root. - /// @param _withdrawalProof Inclusion proof of the withdrawal within the L2ToL1MessagePasser. - function _proveWithdrawalTransaction( - Types.WithdrawalTransaction memory _tx, - IDisputeGame _disputeGameProxy, - Types.OutputRootProof memory _outputRootProof, - bytes[] memory _withdrawalProof - ) - internal - { - // Make sure that the target address is safe. - if (_isUnsafeTarget(_tx.target)) { - revert OptimismPortal_BadTarget(); - } - - // Game must be a Proper Game. - if (!anchorStateRegistry.isGameProper(_disputeGameProxy)) { - revert OptimismPortal_ImproperDisputeGame(); - } - - // Game must have been respected game type when created. - if (!anchorStateRegistry.isGameRespected(_disputeGameProxy)) { - revert OptimismPortal_InvalidDisputeGame(); - } - - // Game must not have resolved in favor of the Challenger (invalid root claim). - if (_disputeGameProxy.status() == GameStatus.CHALLENGER_WINS) { - revert OptimismPortal_InvalidDisputeGame(); - } - - // As a sanity check, we make sure that the current timestamp is not less than or equal to - // the dispute game's creation timestamp. Not strictly necessary but extra layer of - // safety against weird bugs. Note that this blocks withdrawals from being proven in the - // same block that a dispute game is created. - if (block.timestamp <= _disputeGameProxy.createdAt().raw()) { - revert OptimismPortal_InvalidProofTimestamp(); - } - - // Validate the output root proof depending on proof method. - if (superRootsActive) { - // Get output root for this chain from the game's extraData (super root proof). - // Reverts with UnknownChainId if chainId not found in the super root. - uint256 chainId = systemConfig.l2ChainId(); - Claim outputRootClaim = _disputeGameProxy.rootClaimByChainId(chainId); - - // Verify that the output root can be generated with the elements in the proof. - if (outputRootClaim.raw() != Hashing.hashOutputRootProof(_outputRootProof)) { - revert OptimismPortal_InvalidOutputRootProof(); - } - } else { - // Verify that the output root can be generated with the elements in the proof. - if (_disputeGameProxy.rootClaim().raw() != Hashing.hashOutputRootProof(_outputRootProof)) { - revert OptimismPortal_InvalidOutputRootProof(); - } - } - - // Load the ProvenWithdrawal into memory, using the withdrawal hash as a unique identifier. - bytes32 withdrawalHash = Hashing.hashWithdrawal(_tx); - - // Compute the storage slot of the withdrawal hash in the L2ToL1MessagePasser contract. - // Refer to the Solidity documentation for more information on how storage layouts are - // computed for mappings. - bytes32 storageKey = keccak256( - abi.encode( - withdrawalHash, - uint256(0) // The withdrawals mapping is at the first slot in the layout. - ) - ); - - // Verify that the hash of this withdrawal was stored in the L2toL1MessagePasser contract - // on L2. If this is true, under the assumption that the SecureMerkleTrie does not have - // bugs, then we know that this withdrawal was actually triggered on L2 and can therefore - // be relayed on L1. - if ( - SecureMerkleTrie.verifyInclusionProof({ - _key: abi.encode(storageKey), - _value: hex"01", - _proof: _withdrawalProof, - _root: _outputRootProof.messagePasserStorageRoot - }) == false - ) { - revert OptimismPortal_InvalidMerkleProof(); - } - - // Designate the withdrawalHash as proven by storing the disputeGameProxy and timestamp in - // the provenWithdrawals mapping. A given user may re-prove a withdrawalHash multiple - // times, but each proof will reset the proof timer. - provenWithdrawals[withdrawalHash][msg.sender] = - ProvenWithdrawal({ disputeGameProxy: _disputeGameProxy, timestamp: uint64(block.timestamp) }); - - // Add the proof submitter to the list of proof submitters for this withdrawal hash. - proofSubmitters[withdrawalHash].push(msg.sender); - - // Emit a WithdrawalProven events. - emit WithdrawalProven(withdrawalHash, _tx.sender, _tx.target); - emit WithdrawalProvenExtension1(withdrawalHash, msg.sender); - } - - /// @notice Finalizes a withdrawal transaction. - /// @param _tx Withdrawal transaction to finalize. - function finalizeWithdrawalTransaction(Types.WithdrawalTransaction memory _tx) external { - finalizeWithdrawalTransactionExternalProof(_tx, msg.sender); - } - - /// @notice Finalizes a withdrawal transaction, using an external proof submitter. - /// @param _tx Withdrawal transaction to finalize. - /// @param _proofSubmitter Address of the proof submitter. - function finalizeWithdrawalTransactionExternalProof( - Types.WithdrawalTransaction memory _tx, - address _proofSubmitter - ) - public - { - // Cannot finalize withdrawal transactions while the system is paused. - _assertNotPaused(); - - // Make sure that the l2Sender has not yet been set. The l2Sender is set to a value other - // than the default value when a withdrawal transaction is being finalized. This check is - // a defacto reentrancy guard. - if (l2Sender != Constants.DEFAULT_L2_SENDER) { - revert OptimismPortal_NoReentrancy(); - } - - // Make sure that the target address is safe. - if (_isUnsafeTarget(_tx.target)) { - revert OptimismPortal_BadTarget(); - } - - // Grab the withdrawal. - bytes32 withdrawalHash = Hashing.hashWithdrawal(_tx); - - // Check that the withdrawal can be finalized. - checkWithdrawal(withdrawalHash, _proofSubmitter); - - // Mark the withdrawal as finalized so it can't be replayed. - finalizedWithdrawals[withdrawalHash] = true; - - // Unlock the ETH from the ETHLockbox. - if (_tx.value > 0) ethLockbox.unlockETH(_tx.value); - - // Set the l2Sender so contracts know who triggered this withdrawal on L2. - l2Sender = _tx.sender; - - // Trigger the call to the target contract. We use a custom low level method - // SafeCall.callWithMinGas to ensure two key properties - // 1. Target contracts cannot force this call to run out of gas by returning a very large - // amount of data (and this is OK because we don't care about the returndata here). - // 2. The amount of gas provided to the execution context of the target is at least the - // gas limit specified by the user. If there is not enough gas in the current context - // to accomplish this, `callWithMinGas` will revert. - bool success = SafeCall.callWithMinGas(_tx.target, _tx.gasLimit, _tx.value, _tx.data); - - // Reset the l2Sender back to the default value. - l2Sender = Constants.DEFAULT_L2_SENDER; - - // All withdrawals are immediately finalized. Replayability can - // be achieved through contracts built on top of this contract - emit WithdrawalFinalized(withdrawalHash, success); - - // Send ETH back to the Lockbox in the case of a failed transaction or it'll get stuck here - // and would need to be moved back via the migrateLiquidity function. - if (!success && _tx.value > 0) { - ethLockbox.lockETH{ value: _tx.value }(); - } - - // Reverting here is useful for determining the exact gas cost to successfully execute the - // sub call to the target contract if the minimum gas limit specified by the user would not - // be sufficient to execute the sub call. - if (!success && tx.origin == Constants.ESTIMATION_ADDRESS) { - revert OptimismPortal_GasEstimation(); - } - } - - /// @notice Checks that a withdrawal has been proven and is ready to be finalized. - /// @param _withdrawalHash Hash of the withdrawal. - /// @param _proofSubmitter Address of the proof submitter. - function checkWithdrawal(bytes32 _withdrawalHash, address _proofSubmitter) public view { - // Grab the withdrawal and dispute game proxy. - ProvenWithdrawal memory provenWithdrawal = provenWithdrawals[_withdrawalHash][_proofSubmitter]; - IDisputeGame disputeGameProxy = provenWithdrawal.disputeGameProxy; - - // Check that this withdrawal has not already been finalized, this is replay protection. - if (finalizedWithdrawals[_withdrawalHash]) { - revert OptimismPortal_AlreadyFinalized(); - } - - // A withdrawal can only be finalized if it has been proven. We know that a withdrawal has - // been proven at least once when its timestamp is non-zero. Unproven withdrawals will have - // a timestamp of zero. - if (provenWithdrawal.timestamp == 0) { - revert OptimismPortal_Unproven(); - } - - // As a sanity check, we make sure that the proven withdrawal's timestamp is greater than - // starting timestamp inside the Dispute Game. Not strictly necessary but extra layer of - // safety against weird bugs in the proving step. Note that this blocks withdrawals that - // are proven in the same block that a dispute game is created. - if (provenWithdrawal.timestamp <= disputeGameProxy.createdAt().raw()) { - revert OptimismPortal_InvalidProofTimestamp(); - } - - // A proven withdrawal must wait at least `PROOF_MATURITY_DELAY_SECONDS` before finalizing. - if (block.timestamp - provenWithdrawal.timestamp <= PROOF_MATURITY_DELAY_SECONDS) { - revert OptimismPortal_ProofNotOldEnough(); - } - - // Check that the root claim is valid. - if (!anchorStateRegistry.isGameClaimValid(disputeGameProxy)) { - revert OptimismPortal_InvalidRootClaim(); - } - } - - /// @notice Accepts deposits of ETH and data, and emits a TransactionDeposited event for use in - /// deriving deposit transactions. Note that if a deposit is made by a contract, its - /// address will be aliased when retrieved using `tx.origin` or `msg.sender`. Consider - /// using the CrossDomainMessenger contracts for a simpler developer experience. - /// @dev The `msg.value` is locked on the ETHLockbox and minted as ETH when the deposit - /// arrives on L2, while `_value` specifies how much ETH to send to the target. - /// @param _to Target address on L2. - /// @param _value ETH value to send to the recipient. - /// @param _gasLimit Amount of L2 gas to purchase by burning gas on L1. - /// @param _isCreation Whether or not the transaction is a contract creation. - /// @param _data Data to trigger the recipient with. - function depositTransaction( - address _to, - uint256 _value, - uint64 _gasLimit, - bool _isCreation, - bytes memory _data - ) - public - payable - metered(_gasLimit) - { - // Lock the ETH in the ETHLockbox. - if (msg.value > 0) ethLockbox.lockETH{ value: msg.value }(); - - // Just to be safe, make sure that people specify address(0) as the target when doing - // contract creations. - if (_isCreation && _to != address(0)) { - revert OptimismPortal_BadTarget(); - } - - // Prevent depositing transactions that have too small of a gas limit. Users should pay - // more for more resource usage. - if (_gasLimit < minimumGasLimit(uint64(_data.length))) { - revert OptimismPortal_GasLimitTooLow(); - } - - // Prevent the creation of deposit transactions that have too much calldata. This gives an - // upper limit on the size of unsafe blocks over the p2p network. 120kb is chosen to ensure - // that the transaction can fit into the p2p network policy of 128kb even though deposit - // transactions are not gossipped over the p2p network. - if (_data.length > 120_000) { - revert OptimismPortal_CalldataTooLarge(); - } - - // Transform the from-address to its alias if the caller is a contract. - address from = msg.sender; - if (!EOA.isSenderEOA()) { - from = AddressAliasHelper.applyL1ToL2Alias(msg.sender); - } - - // Compute the opaque data that will be emitted as part of the TransactionDeposited event. - // We use opaque data so that we can update the TransactionDeposited event in the future - // without breaking the current interface. - bytes memory opaqueData = abi.encodePacked(msg.value, _value, _gasLimit, _isCreation, _data); - - // Emit a TransactionDeposited event so that the rollup node can derive a deposit - // transaction for this deposit. - emit TransactionDeposited(from, _to, DEPOSIT_VERSION, opaqueData); - } - - /// @notice External getter for the number of proof submitters for a withdrawal hash. - /// @param _withdrawalHash Hash of the withdrawal. - /// @return The number of proof submitters for the withdrawal hash. - function numProofSubmitters(bytes32 _withdrawalHash) external view returns (uint256) { - return proofSubmitters[_withdrawalHash].length; - } - - /// @notice Asserts that the contract is not paused. - function _assertNotPaused() internal view { - if (paused()) { - revert OptimismPortal_CallPaused(); - } - } - - /// @notice Checks if a target address is unsafe. - function _isUnsafeTarget(address _target) internal view virtual returns (bool) { - // Prevent users from targeting an unsafe target address on a withdrawal transaction. - return _target == address(this) || _target == address(ethLockbox); - } - - /// @notice Getter for the resource config. Used internally by the ResourceMetering contract. - /// The SystemConfig is the source of truth for the resource config. - /// @return config_ ResourceMetering ResourceConfig - function _resourceConfig() internal view override returns (ResourceMetering.ResourceConfig memory config_) { - IResourceMetering.ResourceConfig memory config = systemConfig.resourceConfig(); - assembly ("memory-safe") { - config_ := config - } - } -} diff --git a/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerContainer.sol b/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerContainer.sol index 5315096a0ee..6c127ec8de6 100644 --- a/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerContainer.sol +++ b/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerContainer.sol @@ -26,7 +26,6 @@ contract OPContractsManagerContainer { address protocolVersionsImpl; address l1ERC721BridgeImpl; address optimismPortalImpl; - address optimismPortalInteropImpl; address ethLockboxImpl; address systemConfigImpl; address optimismMintableERC20FactoryImpl; diff --git a/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerMigrator.sol b/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerMigrator.sol index d0e9e70312a..0f0ef8e3c79 100644 --- a/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerMigrator.sol +++ b/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerMigrator.sol @@ -17,7 +17,6 @@ import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; -import { IOptimismPortalInterop } from "interfaces/L1/IOptimismPortalInterop.sol"; import { IETHLockbox } from "interfaces/L1/IETHLockbox.sol"; import { IOPContractsManagerContainer } from "interfaces/L1/opcm/IOPContractsManagerContainer.sol"; import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; @@ -240,7 +239,7 @@ contract OPContractsManagerMigrator is OPContractsManagerUtilsCaller { internal { // Convert portal to interop portal interface, and grab existing ETHLockbox and DGF. - IOptimismPortalInterop portal = IOptimismPortalInterop(payable(_systemConfig.optimismPortal())); + IOptimismPortal portal = IOptimismPortal(payable(_systemConfig.optimismPortal())); IETHLockbox existingLockbox = IETHLockbox(payable(address(portal.ethLockbox()))); IDisputeGameFactory existingDGF = IDisputeGameFactory(payable(address(portal.disputeGameFactory()))); @@ -272,11 +271,11 @@ contract OPContractsManagerMigrator is OPContractsManagerUtilsCaller { } // Migrate the portal to the new ETHLockbox and AnchorStateRegistry. - // This also sets superRootsActive = true. // NOTE: This requires the portal to already be upgraded to the interop version - // (OptimismPortalInterop). If the portal is not on the interop version, this call will + // (OptimismPortal2). And it requires the feature flag for INTEROP to be enabled + // If the portal is not on the interop version, this call will // fail. - portal.migrateToSuperRoots(_newLockbox, _newASR); + portal.migrateToSharedDisputeGame(_newLockbox, _newASR); } /// @notice Returns the contracts container. diff --git a/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerV2.sol b/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerV2.sol index 440f104211e..79aff092eb1 100644 --- a/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerV2.sol +++ b/packages/contracts-bedrock/src/L1/opcm/OPContractsManagerV2.sol @@ -24,7 +24,6 @@ import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; -import { IOptimismPortalInterop } from "interfaces/L1/IOptimismPortalInterop.sol"; import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; import { IL1CrossDomainMessenger } from "interfaces/L1/IL1CrossDomainMessenger.sol"; import { IL1ERC721Bridge } from "interfaces/L1/IL1ERC721Bridge.sol"; @@ -153,9 +152,9 @@ contract OPContractsManagerV2 is ISemver, OPContractsManagerUtilsCaller { /// - Major bump: New required sequential upgrade /// - Minor bump: Replacement OPCM for same upgrade /// - Patch bump: Development changes (expected for normal dev work) - /// @custom:semver 7.0.14 + /// @custom:semver 7.1.15 function version() public pure returns (string memory) { - return "7.0.14"; + return "7.1.15"; } /// @param _standardValidator The standard validator for this OPCM release. @@ -783,13 +782,20 @@ contract OPContractsManagerV2 is ISemver, OPContractsManagerUtilsCaller { ); // Update the OptimismPortal. + // When interop is enabled, the ETH_LOCKBOX feature must be set on SystemConfig before + // upgrading the portal. OptimismPortal2.initialize() calls _assertValidLockboxState() + // which requires the ETH_LOCKBOX feature flag and ethLockbox address to be consistent. + // Otherwise we end up in a state where we have a lockbox and the feature flag is off. if (isDevFeatureEnabled(DevFeatures.OPTIMISM_PORTAL_INTEROP)) { + if (!_cts.systemConfig.isFeatureEnabled(Features.ETH_LOCKBOX)) { + _cts.systemConfig.setFeature(Features.ETH_LOCKBOX, true); + } _upgrade( _cts.proxyAdmin, address(_cts.optimismPortal), - impls.optimismPortalInteropImpl, + impls.optimismPortalImpl, abi.encodeCall( - IOptimismPortalInterop.initialize, (_cts.systemConfig, _cts.anchorStateRegistry, _cts.ethLockbox) + IOptimismPortal.initialize, (_cts.systemConfig, _cts.anchorStateRegistry, _cts.ethLockbox) ) ); } else { @@ -797,7 +803,9 @@ contract OPContractsManagerV2 is ISemver, OPContractsManagerUtilsCaller { _cts.proxyAdmin, address(_cts.optimismPortal), impls.optimismPortalImpl, - abi.encodeCall(IOptimismPortal.initialize, (_cts.systemConfig, _cts.anchorStateRegistry)) + abi.encodeCall( + IOptimismPortal.initialize, (_cts.systemConfig, _cts.anchorStateRegistry, IETHLockbox(address(0))) + ) ); } @@ -828,9 +836,12 @@ contract OPContractsManagerV2 is ISemver, OPContractsManagerUtilsCaller { if (!_cts.systemConfig.isFeatureEnabled(Features.ETH_LOCKBOX)) { _cts.systemConfig.setFeature(Features.ETH_LOCKBOX, true); } + if (!_cts.systemConfig.isFeatureEnabled(Features.INTEROP)) { + _cts.systemConfig.setFeature(Features.INTEROP, true); + } // Migrate any ETH into the ETHLockbox. - IOptimismPortalInterop(payable(_cts.optimismPortal)).migrateLiquidity(); + IOptimismPortal(payable(_cts.optimismPortal)).migrateLiquidity(); } // Update the L1CrossDomainMessenger. diff --git a/packages/contracts-bedrock/src/libraries/Constants.sol b/packages/contracts-bedrock/src/libraries/Constants.sol index a3526f8ead5..da3e689f840 100644 --- a/packages/contracts-bedrock/src/libraries/Constants.sol +++ b/packages/contracts-bedrock/src/libraries/Constants.sol @@ -54,9 +54,6 @@ library Constants { /// contracts to be deployed. Used for both initial deployments and migrations. bytes internal constant PERMIT_ALL_CONTRACTS_INSTRUCTION = bytes("ALL"); - /// @notice The minimum OPCM version considered to support OPCM v2. - string internal constant OPCM_V2_MIN_VERSION = "7.0.0"; - /// @notice Current bundle artifact path for Network Upgrade Transaction bundles. string internal constant CURRENT_BUNDLE_PATH = "snapshots/upgrades/current-upgrade-bundle.json"; diff --git a/packages/contracts-bedrock/src/libraries/DevFeatures.sol b/packages/contracts-bedrock/src/libraries/DevFeatures.sol index 8f4b0dd960c..d677dbdac73 100644 --- a/packages/contracts-bedrock/src/libraries/DevFeatures.sol +++ b/packages/contracts-bedrock/src/libraries/DevFeatures.sol @@ -10,7 +10,7 @@ pragma solidity ^0.8.0; /// etc. /// We'll expand to using all available bits if we need more than 64 concurrent features. library DevFeatures { - /// @notice The feature that enables the OptimismPortalInterop contract. + /// @notice The feature that enables the Interop migration functions on the OptimismPortal2 contract. bytes32 public constant OPTIMISM_PORTAL_INTEROP = bytes32(0x0000000000000000000000000000000000000000000000000000000000000001); @@ -23,9 +23,6 @@ library DevFeatures { bytes32 public constant DEPLOY_V2_DISPUTE_GAMES = bytes32(0x0000000000000000000000000000000000000000000000000000000000000100); - /// @notice The feature that enables the OPContractsManagerV2 contract. - bytes32 public constant OPCM_V2 = bytes32(0x0000000000000000000000000000000000000000000000000000000000010000); - /// @notice The feature that enables L2CM. bytes32 public constant L2CM = bytes32(0x0000000000000000000000000000000000000000000000000000000000100000); diff --git a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol deleted file mode 100644 index 5cbaad95b4a..00000000000 --- a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol +++ /dev/null @@ -1,2417 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -// Testing -import { Test } from "test/setup/Test.sol"; -import { stdStorage, StdStorage } from "forge-std/StdStorage.sol"; -import { VmSafe } from "forge-std/Vm.sol"; -import { CommonTest } from "test/setup/CommonTest.sol"; -import { FeatureFlags } from "test/setup/FeatureFlags.sol"; -import { DeployOPChain_TestBase } from "test/opcm/DeployOPChain.t.sol"; - -// Scripts -import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; -import { Deploy } from "scripts/deploy/Deploy.s.sol"; -import { VerifyOPCM } from "scripts/deploy/VerifyOPCM.s.sol"; -import { DeployOPChain } from "scripts/deploy/DeployOPChain.s.sol"; -import { DisputeGames } from "test/setup/DisputeGames.sol"; -import { PastUpgrades } from "test/setup/PastUpgrades.sol"; - -// Libraries -import { Config } from "scripts/libraries/Config.sol"; -import { Types } from "scripts/libraries/Types.sol"; -import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; -import { GameType, Duration, Hash, Claim } from "src/dispute/lib/LibUDT.sol"; -import { Proposal, GameTypes } from "src/dispute/lib/Types.sol"; -import { LibGameArgs } from "src/dispute/lib/LibGameArgs.sol"; -import { DevFeatures } from "src/libraries/DevFeatures.sol"; -import { Types as LibTypes } from "src/libraries/Types.sol"; -import { Encoding } from "src/libraries/Encoding.sol"; -import { Hashing } from "src/libraries/Hashing.sol"; -// Interfaces -import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; -import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol"; -import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; -import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; -import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol"; - -import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; -import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; -import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; -import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; -import { - IOPContractsManager, - IOPContractsManagerGameTypeAdder, - IOPContractsManagerInteropMigrator, - IOPContractsManagerUpgrader, - IOPContractsManagerStandardValidator -} from "interfaces/L1/IOPContractsManager.sol"; -import { IETHLockbox } from "interfaces/L1/IETHLockbox.sol"; -import { IBigStepper } from "interfaces/dispute/IBigStepper.sol"; -import { ISuperFaultDisputeGame } from "interfaces/dispute/ISuperFaultDisputeGame.sol"; -import { ISuperPermissionedDisputeGame } from "interfaces/dispute/ISuperPermissionedDisputeGame.sol"; -import { IFaultDisputeGame } from "../../interfaces/dispute/IFaultDisputeGame.sol"; - -// Contracts -import { - OPContractsManager, - OPContractsManagerGameTypeAdder, - OPContractsManagerDeployer, - OPContractsManagerUpgrader, - OPContractsManagerContractsContainer, - OPContractsManagerInteropMigrator, - OPContractsManagerStandardValidator -} from "src/L1/OPContractsManager.sol"; -import { IPermissionedDisputeGame } from "../../interfaces/dispute/IPermissionedDisputeGame.sol"; -import { IProxy } from "../../interfaces/universal/IProxy.sol"; -import { IDelayedWETH } from "../../interfaces/dispute/IDelayedWETH.sol"; - -/// @title OPContractsManager_Harness -/// @notice Exposes internal functions for testing. -contract OPContractsManager_Harness is OPContractsManager { - constructor( - OPContractsManagerGameTypeAdder _opcmGameTypeAdder, - OPContractsManagerDeployer _opcmDeployer, - OPContractsManagerUpgrader _opcmUpgrader, - OPContractsManagerInteropMigrator _opcmInteropMigrator, - OPContractsManagerStandardValidator _opcmStandardValidator, - ISuperchainConfig _superchainConfig, - IProtocolVersions _protocolVersions - ) - OPContractsManager( - _opcmGameTypeAdder, - _opcmDeployer, - _opcmUpgrader, - _opcmInteropMigrator, - _opcmStandardValidator, - _superchainConfig, - _protocolVersions - ) - { } - - function chainIdToBatchInboxAddress_exposed(uint256 l2ChainId) public view returns (address) { - return super.chainIdToBatchInboxAddress(l2ChainId); - } -} - -/// @title OPContractsManager_Upgrade_Harness -/// @notice Exposes internal functions for testing. -contract OPContractsManager_Upgrade_Harness is CommonTest { - // The Upgraded event emitted by the Proxy contract. - event Upgraded(address indexed implementation); - - // The Upgraded event emitted by the OPContractsManager contract. - event Upgraded(uint256 indexed l2ChainId, ISystemConfig indexed systemConfig, address indexed upgrader); - - // The AddressSet event emitted by the AddressManager contract. - event AddressSet(string indexed name, address newAddress, address oldAddress); - - // The AdminChanged event emitted by the Proxy contract at init time or when the admin is - // changed. - event AdminChanged(address previousAdmin, address newAdmin); - - // The ImplementationSet event emitted by the DisputeGameFactory contract. - event ImplementationSet(address indexed impl, GameType indexed gameType); - - struct PreUpgradeState { - Claim cannonAbsolutePrestate; - Claim permissionedAbsolutePrestate; - Claim cannonKonaAbsolutePrestate; - IDelayedWETH permissionlessWethProxy; - IDelayedWETH permissionedCannonWethProxy; - } - - uint256 l2ChainId; - address upgrader; - IOPContractsManager.OpChainConfig[] opChainConfigs; - Claim cannonPrestate; - Claim cannonKonaPrestate; - string public opChain = Config.forkOpChain(); - PreUpgradeState preUpgradeState; - uint256 smokeTestNonce; // Counter to ensure unique l2BlockNumbers in smoke tests - - function setUp() public virtual override { - super.disableUpgradedFork(); - super.setUp(); - if (!isL1ForkTest()) { - // This test is only supported in forked tests, as we are testing the upgrade. - vm.skip(true); - } - - // All V1 upgrade tests can safely be skipped for V2. - skipIfDevFeatureEnabled(DevFeatures.OPCM_V2); - - skipIfOpsRepoTest( - "OPContractsManager_Upgrade_Harness: cannot test upgrade on superchain ops repo upgrade tests" - ); - - cannonPrestate = Claim.wrap(bytes32(keccak256("cannonPrestate"))); - cannonKonaPrestate = Claim.wrap(bytes32(keccak256("cannonKonaPrestate"))); - upgrader = proxyAdmin.owner(); - vm.label(upgrader, "ProxyAdmin Owner"); - - opChainConfigs.push( - IOPContractsManager.OpChainConfig({ - systemConfigProxy: systemConfig, - cannonPrestate: cannonPrestate, - cannonKonaPrestate: cannonKonaPrestate - }) - ); - - // Retrieve the l2ChainId, which was read from the superchain-registry, and saved in - // Artifacts encoded as an address. - l2ChainId = uint256(uint160(address(artifacts.mustGetAddress("L2ChainId")))); - - IDisputeGameFactory dgf = IDisputeGameFactory(address(artifacts.mustGetAddress("DisputeGameFactoryProxy"))); - - // Grab the pre-upgrade state. Use getGameImplPrestate to handle both v1 and v2 - // dispute games (v1 stores prestate on game impl, v2 stores it in gameArgs). - preUpgradeState = PreUpgradeState({ - cannonAbsolutePrestate: DisputeGames.getGameImplPrestate(dgf, GameTypes.CANNON), - permissionedAbsolutePrestate: DisputeGames.getGameImplPrestate(dgf, GameTypes.PERMISSIONED_CANNON), - cannonKonaAbsolutePrestate: DisputeGames.getGameImplPrestate(dgf, GameTypes.CANNON_KONA), - permissionlessWethProxy: DisputeGames.getGameImplDelayedWeth(dgf, GameTypes.CANNON), - permissionedCannonWethProxy: DisputeGames.getGameImplDelayedWeth(dgf, GameTypes.PERMISSIONED_CANNON) - }); - - // Since this superchainConfig is already at the expected reinitializer version... - // We do this to pass the reinitializer check when trying to upgrade the superchainConfig contract. - - // Get the value of the 0th storage slot of the superchainConfig contract. - bytes32 slot0 = vm.load(address(superchainConfig), bytes32(0)); - // Remove the value of initialized slot. - slot0 = slot0 & bytes32(~uint256(0xff)); - // Store 1 there. - slot0 = bytes32(uint256(slot0) + 1); - // Store the new value. - vm.store(address(superchainConfig), bytes32(0), slot0); - } - - /// @notice Helper function that runs an OPCM upgrade, asserts that the upgrade was successful, - /// asserts that it fits within a certain amount of gas, and runs the StandardValidator - /// over the result. - /// @param _opcm The OPCM contract to upgrade with. - /// @param _delegateCaller The address of the delegate caller to use for the upgrade. - /// @param _revertBytes The bytes of the revert to expect. - function _runOpcmUpgradeAndChecks( - IOPContractsManager _opcm, - address _delegateCaller, - bytes memory _revertBytes - ) - internal - { - // Grab some values before we upgrade, to be checked later - address initialChallenger = DisputeGames.permissionedGameChallenger(disputeGameFactory); - address initialProposer = DisputeGames.permissionedGameProposer(disputeGameFactory); - - // Always start by upgrading the SuperchainConfig contract. - address superchainPAO = IProxyAdmin(EIP1967Helper.getAdmin(address(superchainConfig))).owner(); - - // Execute the SuperchainConfig upgrade. - prankDelegateCall(superchainPAO); - (bool success, bytes memory reason) = - address(_opcm).delegatecall(abi.encodeCall(IOPContractsManager.upgradeSuperchainConfig, (superchainConfig))); - if (success == false) { - // Only acceptable revert reason is the SuperchainConfig already being up to date. This - // try/catch is better than checking the version via the implementations struct because - // the implementations struct interface can change between OPCM versions which would - // cause the test to break and be a pain to resolve. - assertTrue( - bytes4(reason) - == IOPContractsManagerUpgrader.OPContractsManagerUpgrader_SuperchainConfigAlreadyUpToDate.selector, - "Revert reason other than SuperchainConfigAlreadyUpToDate" - ); - } - - // Expect the revert if one is specified. - if (_revertBytes.length > 0) { - vm.expectRevert(_revertBytes); - } - - // Execute the chain upgrade. - prankDelegateCall(_delegateCaller); - (bool upgradeSuccess,) = - address(_opcm).delegatecall(abi.encodeCall(IOPContractsManager.upgrade, (opChainConfigs))); - assertTrue(upgradeSuccess, "upgrade failed"); - - // Return early if a revert was expected. Otherwise we'll get errors below. - if (_revertBytes.length > 0) { - return; - } - - // Less than 90% of the gas target of 2**24 (EIP-7825) to account for the gas used by - // using Safe. - uint256 fusakaLimit = 2 ** 24; - VmSafe.Gas memory gas = vm.lastCallGas(); - assertLt(gas.gasTotalUsed, fusakaLimit * 9 / 10, "Upgrade exceeds gas target of 90% of 2**24 (EIP-7825)"); - - // We expect there to only be one chain config for these tests, you will have to rework - // this test if you add more. - assertEq(opChainConfigs.length, 1); - - // Coverage changes bytecode, so we get various errors. We can safely ignore the result of - // the standard validator in the coverage case, if the validator is failing in coverage - // then it will also fail in other CI tests (unless it's the expected issues, in which case - // we can safely skip). - if (vm.isContext(VmSafe.ForgeContext.Coverage)) { - return; - } - - // Create validationOverrides - IOPContractsManagerStandardValidator.ValidationOverrides memory validationOverrides = - IOPContractsManagerStandardValidator.ValidationOverrides({ - l1PAOMultisig: opChainConfigs[0].systemConfigProxy.proxyAdmin().owner(), - challenger: initialChallenger - }); - - // Grab the validator before we do the error assertion because otherwise the assertion will - // try to apply to this function call instead. - IOPContractsManagerStandardValidator validator = _opcm.opcmStandardValidator(); - - // Mock getProxyImplementation for DelayedWETH and ETHLockbox proxies when running - // with an unoptimized Foundry profile. See Setup.mockUnoptimizedProxyImplementations. - mockUnoptimizedProxyImplementations( - disputeGameFactory, - proxyAdmin, - address(optimismPortal2.ethLockbox()), - validator.delayedWETHImpl(), - validator.ethLockboxImpl() - ); - - // If the absolute prestate is zero, we will always get a PDDG-40,PLDG-40 error here in the - // standard validator. This happens because an absolute prestate of zero means that the - // user is requesting to use the existing prestate. We could avoid the error by grabbing - // the prestate from the actual contracts, but that doesn't actually give us any valuable - // checks. Easier to just expect the error in this case. - // We add the prefix of OVERRIDES-L1PAOMULTISIG,OVERRIDES-CHALLENGER because we use validationOverrides. - // Note: The expected error for CANNON_KONA depends on whether it was set up by past upgrades. - bool cannonKonaExists = address(disputeGameFactory.gameImpls(GameTypes.CANNON_KONA)) != address(0); - if (opChainConfigs[0].cannonPrestate.raw() == bytes32(0)) { - if (opChainConfigs[0].cannonKonaPrestate.raw() == bytes32(0)) { - if (cannonKonaExists) { - // CANNON_KONA was set up by past upgrades, validator checks it against zero prestate input - vm.expectRevert( - "OPContractsManagerStandardValidator: OVERRIDES-L1PAOMULTISIG,OVERRIDES-CHALLENGER,PDDG-40,PLDG-40,CKDG-40" - ); - } else { - // CANNON_KONA doesn't exist - vm.expectRevert( - "OPContractsManagerStandardValidator: OVERRIDES-L1PAOMULTISIG,OVERRIDES-CHALLENGER,PDDG-40,PLDG-40,CKDG-10" - ); - } - } else { - vm.expectRevert( - "OPContractsManagerStandardValidator: OVERRIDES-L1PAOMULTISIG,OVERRIDES-CHALLENGER,PDDG-40,PLDG-40" - ); - } - } else if (opChainConfigs[0].cannonKonaPrestate.raw() == bytes32(0)) { - if (cannonKonaExists) { - vm.expectRevert( - "OPContractsManagerStandardValidator: OVERRIDES-L1PAOMULTISIG,OVERRIDES-CHALLENGER,CKDG-40" - ); - } else { - vm.expectRevert( - "OPContractsManagerStandardValidator: OVERRIDES-L1PAOMULTISIG,OVERRIDES-CHALLENGER,CKDG-10" - ); - } - } - - // Run the StandardValidator checks. - validator.validateWithOverrides( - IOPContractsManagerStandardValidator.ValidationInputDev({ - sysCfg: opChainConfigs[0].systemConfigProxy, - cannonPrestate: opChainConfigs[0].cannonPrestate.raw(), - cannonKonaPrestate: opChainConfigs[0].cannonKonaPrestate.raw(), - l2ChainID: l2ChainId, - proposer: initialProposer - }), - false, - validationOverrides - ); - _runPostUpgradeSmokeTests(_opcm, opChainConfigs[0], initialChallenger, initialProposer); - } - - /// @notice Runs some smoke tests after an upgrade - function _runPostUpgradeSmokeTests( - IOPContractsManager _opcm, - IOPContractsManager.OpChainConfig memory _opChainConfig, - address _challenger, - address _proposer - ) - internal - { - address expectedVm = address(_opcm.implementations().mipsImpl); - - Claim claim = Claim.wrap(bytes32(uint256(1))); - uint256 bondAmount = disputeGameFactory.initBonds(GameTypes.PERMISSIONED_CANNON); - vm.deal(address(_challenger), bondAmount); - (, uint256 rootBlockNumber) = optimismPortal2.anchorStateRegistry().getAnchorRoot(); - // Use nonce to ensure unique l2BlockNumber across multiple smoke test runs (e.g., runPastUpgrades + - // runCurrentUpgrade) - uint256 l2BlockNumber = rootBlockNumber + 1 + smokeTestNonce; - smokeTestNonce++; - - // Cannon Kona expected to be set if the cannon kona prestate is not zero AND the existing - // prestate for Cannon Kona is not - bool isCannonKonaSet = - DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.CANNON_KONA).raw() != bytes32(0); - - // Deploy live games and ensure they're configured correctly - GameType[] memory gameTypes = new GameType[](isCannonKonaSet ? 3 : 2); - gameTypes[0] = GameTypes.PERMISSIONED_CANNON; - gameTypes[1] = GameTypes.CANNON; - if (isCannonKonaSet) { - gameTypes[2] = GameTypes.CANNON_KONA; - } - for (uint256 i = 0; i < gameTypes.length; i++) { - GameType gt = gameTypes[i]; - - bytes32 expectedAbsolutePrestate = _opChainConfig.cannonPrestate.raw(); - if (expectedAbsolutePrestate == bytes32(0)) { - expectedAbsolutePrestate = preUpgradeState.permissionedAbsolutePrestate.raw(); - } - if (isCannonKonaSet && gt.raw() == GameTypes.CANNON_KONA.raw()) { - expectedAbsolutePrestate = _opChainConfig.cannonKonaPrestate.raw(); - if (expectedAbsolutePrestate == bytes32(0)) { - expectedAbsolutePrestate = preUpgradeState.cannonKonaAbsolutePrestate.raw(); - } - } - assertEq(bondAmount, disputeGameFactory.initBonds(gt)); - - vm.prank(_proposer, _proposer); - IPermissionedDisputeGame game = IPermissionedDisputeGame( - address(disputeGameFactory.create{ value: bondAmount }(gt, claim, abi.encode(l2BlockNumber))) - ); - (,,,, Claim rootClaim,,) = game.claimData(0); - - vm.assertEq(gt.raw(), game.gameType().raw()); - vm.assertEq(expectedAbsolutePrestate, game.absolutePrestate().raw()); - vm.assertEq(address(optimismPortal2.anchorStateRegistry()), address(game.anchorStateRegistry())); - vm.assertEq(l2ChainId, game.l2ChainId()); - vm.assertEq(302400, game.maxClockDuration().raw()); - vm.assertEq(10800, game.clockExtension().raw()); - vm.assertEq(73, game.maxGameDepth()); - vm.assertEq(30, game.splitDepth()); - vm.assertEq(l2BlockNumber, game.l2BlockNumber()); - vm.assertEq(expectedVm, address(game.vm())); - vm.assertEq(_proposer, game.gameCreator()); - vm.assertEq(claim.raw(), rootClaim.raw()); - vm.assertEq(blockhash(block.number - 1), game.l1Head().raw()); - - if (gt.raw() == GameTypes.PERMISSIONED_CANNON.raw()) { - vm.assertEq( - address(preUpgradeState.permissionedCannonWethProxy), - address(game.weth()), - "Incorrect permissioned WETH" - ); - vm.assertEq(_challenger, game.challenger()); - vm.assertEq(_proposer, game.proposer()); - } else { - vm.assertEq( - address(preUpgradeState.permissionlessWethProxy), - address(game.weth()), - "Incorrect permissionless WETH" - ); - } - } - - if (!isCannonKonaSet) { - assertEq(address(0), address(disputeGameFactory.gameImpls(GameTypes.CANNON_KONA))); - assertEq(0, disputeGameFactory.initBonds(GameTypes.CANNON_KONA)); - assertEq(0, disputeGameFactory.gameArgs(GameTypes.CANNON_KONA).length); - } - } - - /// @notice Executes all past upgrades that have not yet been executed on mainnet as of the - /// current simulation block defined in the justfile for this package. This function - /// might be empty if there are no previous upgrades to execute. You should remove - /// upgrades from this function once they've been executed on mainnet and the - /// simulation block has been bumped beyond the execution block. - /// @param _delegateCaller The address of the delegate caller to use for the upgrade. - function runPastUpgrades(address _delegateCaller) internal { - PastUpgrades.runPastUpgrades(_delegateCaller, systemConfig, superchainConfig, disputeGameFactory); - } - - /// @notice Executes the current upgrade and checks the results. - /// @param _delegateCaller The address of the delegate caller to use for the upgrade. - function runCurrentUpgrade(address _delegateCaller) public { - _runOpcmUpgradeAndChecks(opcm, _delegateCaller, bytes("")); - } - - /// @notice Executes the current upgrade and expects reverts. - /// @param _delegateCaller The address of the delegate caller to use for the upgrade. - /// @param _revertBytes The bytes of the revert to expect. - function runCurrentUpgrade(address _delegateCaller, bytes memory _revertBytes) public { - _runOpcmUpgradeAndChecks(opcm, _delegateCaller, _revertBytes); - } -} - -/// @title OPContractsManager_TestInit -/// @notice Reusable test initialization for `OPContractsManager` tests. -abstract contract OPContractsManager_TestInit is CommonTest { - using DisputeGames for *; - - event GameTypeAdded( - uint256 indexed l2ChainId, GameType indexed gameType, IDisputeGame newDisputeGame, IDisputeGame oldDisputeGame - ); - - address proposer; - address challenger; - - uint256 chain1L2ChainId; - uint256 chain2L2ChainId; - - IOPContractsManager.DeployOutput internal chainDeployOutput1; - IOPContractsManager.DeployOutput internal chainDeployOutput2; - - function setUp() public virtual override { - super.setUp(); - - // TODO(#18332): Remove this once we support all existing OPCM functions. - skipIfDevFeatureEnabled(DevFeatures.OPCM_V2); - - proposer = address(this); - challenger = address(this); - chain1L2ChainId = 100; - chain2L2ChainId = 101; - - chainDeployOutput1 = createChainContracts(chain1L2ChainId); - chainDeployOutput2 = createChainContracts(chain2L2ChainId); - - vm.deal(address(chainDeployOutput1.ethLockboxProxy), 100 ether); - vm.deal(address(chainDeployOutput2.ethLockboxProxy), 100 ether); - } - - /// @notice Sets up the environment variables for the VerifyOPCM test. - function setupEnvVars() public { - vm.setEnv("EXPECTED_SUPERCHAIN_CONFIG", vm.toString(address(opcm.superchainConfig()))); - vm.setEnv("EXPECTED_PROTOCOL_VERSIONS", vm.toString(address(opcm.protocolVersions()))); - } - - /// @notice Helper function to deploy a new set of L1 contracts via OPCM. - /// @param _l2ChainId The L2 chain ID to deploy the contracts for. - /// @return The deployed contracts. - function createChainContracts(uint256 _l2ChainId) internal returns (IOPContractsManager.DeployOutput memory) { - return opcm.deploy( - IOPContractsManager.DeployInput({ - roles: IOPContractsManager.Roles({ - opChainProxyAdminOwner: address(this), - systemConfigOwner: address(this), - batcher: address(this), - unsafeBlockSigner: address(this), - proposer: proposer, - challenger: challenger - }), - basefeeScalar: 1, - blobBasefeeScalar: 1, - startingAnchorRoot: abi.encode( - Proposal({ - root: Hash.wrap(0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef), - l2SequenceNumber: 0 - }) - ), - l2ChainId: _l2ChainId, - saltMixer: "hello", - gasLimit: 30_000_000, - disputeGameType: GameType.wrap(1), - disputeAbsolutePrestate: Claim.wrap( - bytes32(hex"038512e02c4c3f7bdaec27d00edf55b7155e0905301e1a88083e4e0a6764d54c") - ), - disputeMaxGameDepth: 73, - disputeSplitDepth: 30, - disputeClockExtension: Duration.wrap(10800), - disputeMaxClockDuration: Duration.wrap(302400), - useCustomGasToken: false - }) - ); - } - - function addGameType(IOPContractsManager.AddGameInput memory input) - internal - returns (IOPContractsManager.AddGameOutput memory) - { - IOPContractsManager.AddGameInput[] memory inputs = new IOPContractsManager.AddGameInput[](1); - inputs[0] = input; - - uint256 l2ChainId = input.systemConfig.l2ChainId(); - - // Expect the GameTypeAdded event to be emitted. - vm.expectEmit(true, true, true, false, address(this)); - emit GameTypeAdded( - l2ChainId, input.disputeGameType, IDisputeGame(payable(address(0))), IDisputeGame(payable(address(0))) - ); - (bool success, bytes memory rawGameOut) = - address(opcm).delegatecall(abi.encodeCall(IOPContractsManager.addGameType, (inputs))); - assertTrue(success, "addGameType failed"); - - IOPContractsManager.AddGameOutput[] memory addGameOutAll = - abi.decode(rawGameOut, (IOPContractsManager.AddGameOutput[])); - return addGameOutAll[0]; - } - - function newGameInputFactory(GameType _gameType) internal view returns (IOPContractsManager.AddGameInput memory) { - return IOPContractsManager.AddGameInput({ - saltMixer: "hello", - systemConfig: chainDeployOutput1.systemConfigProxy, - delayedWETH: IDelayedWETH(payable(address(0))), - disputeGameType: _gameType, - disputeAbsolutePrestate: Claim.wrap(bytes32(hex"deadbeef1234")), - disputeMaxGameDepth: 73, - disputeSplitDepth: 30, - disputeClockExtension: Duration.wrap(10800), - disputeMaxClockDuration: Duration.wrap(302400), - initialBond: 1 ether, - vm: IBigStepper(address(opcm.implementations().mipsImpl)), - permissioned: _gameType.raw() == GameTypes.PERMISSIONED_CANNON.raw() - || _gameType.raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw() - }); - } -} - -/// @title OPContractsManager_ChainIdToBatchInboxAddress_Test -/// @notice Tests the `chainIdToBatchInboxAddress` function of the `OPContractsManager` contract. -/// @dev These tests use the harness which exposes internal functions for testing. -contract OPContractsManager_ChainIdToBatchInboxAddress_Test is Test, FeatureFlags { - OPContractsManager_Harness opcmHarness; - address challenger = makeAddr("challenger"); - - function setUp() public { - ISuperchainConfig superchainConfigProxy = ISuperchainConfig(makeAddr("superchainConfig")); - IProtocolVersions protocolVersionsProxy = IProtocolVersions(makeAddr("protocolVersions")); - IProxyAdmin superchainProxyAdmin = IProxyAdmin(makeAddr("superchainProxyAdmin")); - OPContractsManager.Blueprints memory emptyBlueprints; - OPContractsManager.Implementations memory emptyImpls; - vm.etch(address(superchainConfigProxy), hex"01"); - vm.etch(address(protocolVersionsProxy), hex"01"); - - resolveFeaturesFromEnv(); - OPContractsManagerContractsContainer container = - new OPContractsManagerContractsContainer(emptyBlueprints, emptyImpls, devFeatureBitmap); - - OPContractsManager.Implementations memory __opcmImplementations = container.implementations(); - OPContractsManagerStandardValidator.Implementations memory opcmImplementations; - assembly { - opcmImplementations := __opcmImplementations - } - - opcmHarness = new OPContractsManager_Harness({ - _opcmGameTypeAdder: new OPContractsManagerGameTypeAdder(container), - _opcmDeployer: new OPContractsManagerDeployer(container), - _opcmUpgrader: new OPContractsManagerUpgrader(container), - _opcmInteropMigrator: new OPContractsManagerInteropMigrator(container), - _opcmStandardValidator: new OPContractsManagerStandardValidator( - opcmImplementations, superchainConfigProxy, address(superchainProxyAdmin), challenger, 100, bytes32(0) - ), - _superchainConfig: superchainConfigProxy, - _protocolVersions: protocolVersionsProxy - }); - } - - function test_calculatesBatchInboxAddress_succeeds() public view { - // These test vectors were calculated manually: - // 1. Compute the bytes32 encoding of the chainId: bytes32(uint256(chainId)); - // 2. Hash it and manually take the first 19 bytes, and prefixed it with 0x00. - uint256 chainId = 1234; - address expected = 0x0017FA14b0d73Aa6A26D6b8720c1c84b50984f5C; - address actual = opcmHarness.chainIdToBatchInboxAddress_exposed(chainId); - vm.assertEq(expected, actual); - - chainId = type(uint256).max; - expected = 0x00a9C584056064687E149968cBaB758a3376D22A; - actual = opcmHarness.chainIdToBatchInboxAddress_exposed(chainId); - vm.assertEq(expected, actual); - } -} - -/// @title OPContractsManager_AddGameType_Test -/// @notice Tests the `addGameType` function of the `OPContractsManager` contract. -contract OPContractsManager_AddGameType_Test is OPContractsManager_TestInit { - /// @notice Tests that we can add a PermissionedDisputeGame implementation with addGameType. - function test_addGameType_permissioned_succeeds() public { - // Create the input for the Permissioned game type. - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.PERMISSIONED_CANNON); - - // Run the addGameType call. - IOPContractsManager.AddGameOutput memory output = addGameType(input); - IFaultDisputeGame newFDG = assertValidGameType(input, output); - - // Check the values on the new game type. - IPermissionedDisputeGame newPDG = IPermissionedDisputeGame(address(newFDG)); - - // Check the proposer and challenger values. - assertEq(newPDG.proposer(), proposer, "proposer mismatch"); - assertEq(newPDG.challenger(), challenger, "challenger mismatch"); - - // L2 chain ID call should not revert because this is not a Super game. - assertEq(newPDG.l2ChainId(), chain1L2ChainId, "l2ChainId should be set correctly"); - - // Get the v2 implementation address from OPCM - IOPContractsManager.Implementations memory impls = opcm.implementations(); - - // Verify v2 implementation is registered in DisputeGameFactory - address registeredImpl = - address(chainDeployOutput1.disputeGameFactoryProxy.gameImpls(GameTypes.PERMISSIONED_CANNON)); - - // Verify implementation address matches permissionedDisputeGameImpl - assertEq( - registeredImpl, - address(impls.permissionedDisputeGameImpl), - "DisputeGameFactory should have v2 PermissionedDisputeGame implementation registered" - ); - - // Verify that the returned fault dispute game is the v2 implementation - assertEq( - address(output.faultDisputeGame), - address(impls.permissionedDisputeGameImpl), - "addGameType should return v2 PermissionedDisputeGame implementation" - ); - } - - /// @notice Tests that we can add a FaultDisputeGame implementation with addGameType. - function test_addGameType_cannon_succeeds() public { - // Create the input for the Permissionless game type. - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.CANNON); - - // Run the addGameType call. - IOPContractsManager.AddGameOutput memory output = addGameType(input); - IFaultDisputeGame newGame = assertValidGameType(input, output); - - // Check the values on the new game type. - IPermissionedDisputeGame notPDG = IPermissionedDisputeGame(address(newGame)); - - // Proposer call should revert because this is a permissionless game. - vm.expectRevert(); // nosemgrep: sol-safety-expectrevert-no-args - notPDG.proposer(); - - // L2 chain ID call should not revert because this is not a Super game. - assertEq(notPDG.l2ChainId(), chain1L2ChainId, "l2ChainId should be set correctly"); - - // Verify v2 implementation is registered in DisputeGameFactory - address registeredImpl = address(chainDeployOutput1.disputeGameFactoryProxy.gameImpls(input.disputeGameType)); - assertNotEq(registeredImpl, address(0), "Implementation should have been set"); - - // Get the v2 implementation address from OPCM - IOPContractsManager.Implementations memory impls = opcm.implementations(); - - // Verify implementation address matches permissionedDisputeGameImpl - assertEq( - registeredImpl, - address(impls.faultDisputeGameImpl), - "DisputeGameFactory should have v2 FaultDisputeGame implementation registered" - ); - - // Verify that the returned fault dispute game is the v2 implementation - assertEq( - address(output.faultDisputeGame), - address(impls.faultDisputeGameImpl), - "addGameType should return v2 FaultDisputeGame implementation" - ); - } - - /// @notice Tests that we can add a SuperPermissionedDisputeGame implementation with addGameType. - function test_addGameType_permissionedSuper_succeeds() public { - // The super game implementations are required for addGameType - skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); - - // Create the input for the Super game type. - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.SUPER_PERMISSIONED_CANNON); - - // Since OPCM will start with the standard Permissioned (non-Super) game type we won't have - // a Super dispute game to grab the proposer and challenger from. In production we'd either - // already have a Super dispute game or we'd trigger the migration to make sure one exists. - // Here for simplicity we'll just mock it out so the values exist. - - // Mock the DisputeGameFactory to return the non-Super implementation, good enough, it'll - // have the right variables on it for the test to pass. We're basically just pretending - // that the non-Super game is a Super game for the sake of this test. - vm.mockCall( - address(chainDeployOutput1.disputeGameFactoryProxy), - abi.encodeCall(IDisputeGameFactory.gameImpls, (GameTypes.SUPER_PERMISSIONED_CANNON)), - abi.encode(chainDeployOutput1.permissionedDisputeGame) - ); - vm.mockCall( - address(chainDeployOutput1.permissionedDisputeGame), - abi.encodeCall(IDisputeGame.gameType, ()), - abi.encode(GameTypes.SUPER_PERMISSIONED_CANNON) - ); - // Mock the proposer and challenger calls to behave like SuperPermissionedDisputeGame - // When V2 contracts are used the permissioned game may be the V2 contract and not have proposer and challenger - // in the implementation contract. - vm.mockCall( - address(chainDeployOutput1.permissionedDisputeGame), - abi.encodeCall(IPermissionedDisputeGame.proposer, ()), - abi.encode(proposer) - ); - vm.mockCall( - address(chainDeployOutput1.permissionedDisputeGame), - abi.encodeCall(IPermissionedDisputeGame.challenger, ()), - abi.encode(challenger) - ); - - // Run the addGameType call. - IOPContractsManager.AddGameOutput memory output = addGameType(input); - vm.clearMockedCalls(); - IFaultDisputeGame newGame = assertValidGameType(input, output); - // Check the values on the new game type. - IPermissionedDisputeGame newPDG = IPermissionedDisputeGame(address(newGame)); - assertEq(newPDG.proposer(), proposer, "proposer mismatch"); - assertEq(newPDG.challenger(), challenger, "challenger mismatch"); - - // Super games don't have the l2ChainId function. - vm.expectRevert(); // nosemgrep: sol-safety-expectrevert-no-args - newPDG.l2ChainId(); - } - - /// @notice Tests that we can add a SuperFaultDisputeGame implementation with addGameType. - function test_addGameType_superCannon_succeeds() public { - // The super game implementations are required for addGameType - skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); - - // Create the input for the Super game type. - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.SUPER_CANNON); - - // Run the addGameType call. - IOPContractsManager.AddGameOutput memory output = addGameType(input); - assertValidGameType(input, output); - - // Grab the new game type. - IPermissionedDisputeGame notPDG = IPermissionedDisputeGame(address(output.faultDisputeGame)); - - // Proposer should fail, this is a permissionless game. - vm.expectRevert(); // nosemgrep: sol-safety-expectrevert-no-args - notPDG.proposer(); - - // Super games don't have the l2ChainId function. - vm.expectRevert(); // nosemgrep: sol-safety-expectrevert-no-args - notPDG.l2ChainId(); - } - - /// @notice Tests that addGameType will revert if the game type is not supported. - function test_addGameType_unsupportedGameType_reverts() public { - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameType.wrap(2000)); - - // Run the addGameType call, should revert. - IOPContractsManager.AddGameInput[] memory inputs = new IOPContractsManager.AddGameInput[](1); - inputs[0] = input; - (bool success,) = address(opcm).delegatecall(abi.encodeCall(IOPContractsManager.addGameType, (inputs))); - assertFalse(success, "addGameType should have failed"); - } - - function test_addGameType_reusedDelayedWETH_succeeds() public { - IDelayedWETH delayedWETH = IDelayedWETH( - DeployUtils.create1({ - _name: "Proxy", - _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (address(this)))) - }) - ); - IProxy(payable(address(delayedWETH))).upgradeToAndCall( - address(opcm.implementations().delayedWETHImpl), - abi.encodeCall(IDelayedWETH.initialize, (chainDeployOutput1.systemConfigProxy)) - ); - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.CANNON); - input.delayedWETH = delayedWETH; - IOPContractsManager.AddGameOutput memory output = addGameType(input); - assertValidGameType(input, output); - assertEq(address(output.delayedWETH), address(delayedWETH), "delayedWETH address mismatch"); - } - - function test_addGameType_outOfOrderInputs_reverts() public { - IOPContractsManager.AddGameInput memory input1 = newGameInputFactory(GameType.wrap(2)); - IOPContractsManager.AddGameInput memory input2 = newGameInputFactory(GameType.wrap(1)); - IOPContractsManager.AddGameInput[] memory inputs = new IOPContractsManager.AddGameInput[](2); - inputs[0] = input1; - inputs[1] = input2; - - // For the sake of completeness, we run the call again to validate the success behavior. - (bool success,) = address(opcm).delegatecall(abi.encodeCall(IOPContractsManager.addGameType, (inputs))); - assertFalse(success, "addGameType should have failed"); - } - - function test_addGameType_duplicateGameType_reverts() public { - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.CANNON); - IOPContractsManager.AddGameInput[] memory inputs = new IOPContractsManager.AddGameInput[](2); - inputs[0] = input; - inputs[1] = input; - - // See test above for why we run the call twice. - (bool success, bytes memory revertData) = - address(opcm).delegatecall(abi.encodeCall(IOPContractsManager.addGameType, (inputs))); - assertFalse(success, "addGameType should have failed"); - assertEq(bytes4(revertData), IOPContractsManager.InvalidGameConfigs.selector, "revertData mismatch"); - } - - function test_addGameType_zeroLengthInput_reverts() public { - IOPContractsManager.AddGameInput[] memory inputs = new IOPContractsManager.AddGameInput[](0); - - (bool success, bytes memory revertData) = - address(opcm).delegatecall(abi.encodeCall(IOPContractsManager.addGameType, (inputs))); - assertFalse(success, "addGameType should have failed"); - assertEq(bytes4(revertData), IOPContractsManager.InvalidGameConfigs.selector, "revertData mismatch"); - } - - function test_addGameType_notDelegateCall_reverts() public { - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.PERMISSIONED_CANNON); - IOPContractsManager.AddGameInput[] memory inputs = new IOPContractsManager.AddGameInput[](1); - inputs[0] = input; - - vm.expectRevert(IOPContractsManager.OnlyDelegatecall.selector); - opcm.addGameType(inputs); - } - - function assertValidGameType( - IOPContractsManager.AddGameInput memory agi, - IOPContractsManager.AddGameOutput memory ago - ) - internal - returns (IFaultDisputeGame) - { - // Create a game so we can assert on game args which aren't baked into the implementation contract - Claim claim; - bytes memory extraData; - if (DisputeGames.isSuperGame(agi.disputeGameType)) { - LibTypes.OutputRootWithChainId[] memory outputRoots = new LibTypes.OutputRootWithChainId[](1); - outputRoots[0] = LibTypes.OutputRootWithChainId({ chainId: 100, root: keccak256(abi.encode(gasleft())) }); - LibTypes.SuperRootProof memory superRootProof; - superRootProof.version = bytes1(uint8(1)); - superRootProof.timestamp = uint64(123); - superRootProof.outputRoots = outputRoots; - extraData = Encoding.encodeSuperRootProof(superRootProof); - claim = Claim.wrap(Hashing.hashSuperRootProof(superRootProof)); - } else { - claim = Claim.wrap(bytes32(uint256(9876))); - extraData = abi.encode(uint256(123)); // l2BlockNumber - } - IFaultDisputeGame game = IFaultDisputeGame( - payable( - DisputeGames.createGame( - chainDeployOutput1.disputeGameFactoryProxy, agi.disputeGameType, proposer, claim, extraData - ) - ) - ); - - // Verify immutable fields on the game proxy - assertEq(game.gameType().raw(), agi.disputeGameType.raw(), "Game type should match"); - assertEq(game.clockExtension().raw(), agi.disputeClockExtension.raw(), "Clock extension should match"); - assertEq(game.maxClockDuration().raw(), agi.disputeMaxClockDuration.raw(), "Max clock duration should match"); - assertEq(game.splitDepth(), agi.disputeSplitDepth, "Split depth should match"); - assertEq(game.maxGameDepth(), agi.disputeMaxGameDepth, "Max game depth should match"); - assertEq(game.gameCreator(), proposer, "Game creator should match"); - assertEq(game.rootClaim().raw(), claim.raw(), "Claim should match"); - assertEq(game.l1Head().raw(), blockhash(block.number - 1), "L1 head should match"); - assertEq(game.l2SequenceNumber(), 123, "L2 sequence number should match"); - assertEq( - game.absolutePrestate().raw(), agi.disputeAbsolutePrestate.raw(), "Absolute prestate should match input" - ); - assertEq(address(game.vm()), address(agi.vm), "VM should match MIPS implementation"); - assertEq( - address(game.anchorStateRegistry()), - address(chainDeployOutput1.anchorStateRegistryProxy), - "ASR should match" - ); - assertEq(address(game.weth()), address(ago.delayedWETH), "WETH should match"); - - // Check the DGF - assertEq( - address(chainDeployOutput1.disputeGameFactoryProxy.gameImpls(agi.disputeGameType)), - address(ago.faultDisputeGame), - "gameImpl address mismatch" - ); - assertEq( - chainDeployOutput1.disputeGameFactoryProxy.initBonds(agi.disputeGameType), agi.initialBond, "bond mismatch" - ); - return game; - } - - /// @notice Tests that addGameType will revert if the game type is cannon-kona and the dev feature is not enabled - function test_addGameType_cannonKonaGameType_succeeds() public { - // Create the input for the cannon-kona game type. - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.CANNON_KONA); - - // Run the addGameType call. - IOPContractsManager.AddGameOutput memory output = addGameType(input); - IFaultDisputeGame game = assertValidGameType(input, output); - - // Check the values on the new game type. - IPermissionedDisputeGame notPDG = IPermissionedDisputeGame(address(game)); - - // Proposer call should revert because this is a permissionless game. - vm.expectRevert(); // nosemgrep: sol-safety-expectrevert-no-args - notPDG.proposer(); - - // L2 chain ID call should not revert because this is not a Super game. - assertNotEq(notPDG.l2ChainId(), 0, "l2ChainId should not be zero"); - } - - /// @notice Tests that addGameType will revert if the game type is cannon-kona and the dev feature is not enabled - function test_addGameType_superCannonKonaGameType_succeeds() public { - skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); - // Create the input for the cannon-kona game type. - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.SUPER_CANNON_KONA); - - // Run the addGameType call. - IOPContractsManager.AddGameOutput memory output = addGameType(input); - assertValidGameType(input, output); - - // Grab the new game type. - IPermissionedDisputeGame notPDG = IPermissionedDisputeGame(address(output.faultDisputeGame)); - - // Proposer should fail, this is a permissionless game. - vm.expectRevert(); // nosemgrep: sol-safety-expectrevert-no-args - notPDG.proposer(); - - // Super games don't have the l2ChainId function. - vm.expectRevert(); // nosemgrep: sol-safety-expectrevert-no-args - notPDG.l2ChainId(); - } -} - -/// @title OPContractsManager_UpdatePrestate_Test -/// @notice Tests the `updatePrestate` function of the `OPContractsManager` contract. -contract OPContractsManager_UpdatePrestate_Test is OPContractsManager_TestInit { - IOPContractsManager internal prestateUpdater; - OPContractsManager.AddGameInput[] internal gameInput; - - function setUp() public virtual override { - super.setUp(); - prestateUpdater = opcm; - } - - /// @notice Runs the OPCM updatePrestate function and checks the results. - /// @param _input The input to the OPCM updatePrestate function. - function _runUpdatePrestateAndChecks(IOPContractsManager.UpdatePrestateInput memory _input) internal { - _runUpdatePrestateAndChecks(_input, bytes("")); - } - - /// @notice Returns the game args of a v1 or v2 game. - function _getParsedGameArgs( - IDisputeGameFactory _dgf, - GameType _gameType - ) - internal - view - returns (LibGameArgs.GameArgs memory gameArgs_) - { - bytes memory args = _dgf.gameArgs(_gameType); - if (args.length == 0) { - IPermissionedDisputeGame game = IPermissionedDisputeGame(address(_dgf.gameImpls(_gameType))); - gameArgs_.absolutePrestate = game.absolutePrestate().raw(); - gameArgs_.vm = address(game.vm()); - gameArgs_.anchorStateRegistry = address(game.anchorStateRegistry()); - gameArgs_.weth = address(game.weth()); - gameArgs_.l2ChainId = game.l2ChainId(); - if ( - game.gameType().raw() == GameTypes.PERMISSIONED_CANNON.raw() - || game.gameType().raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw() - ) { - gameArgs_.proposer = game.proposer(); - gameArgs_.challenger = game.challenger(); - } - return gameArgs_; - } else { - return LibGameArgs.decode(args); - } - } - - function _assertGameArgsEqual( - LibGameArgs.GameArgs memory a, - LibGameArgs.GameArgs memory b, - bool _skipPrestateCheck - ) - internal - pure - { - if (!_skipPrestateCheck) { - assertEq(a.absolutePrestate, b.absolutePrestate, "absolutePrestate mismatch"); - } - assertEq(a.vm, b.vm, "vm mismatch"); - assertEq(a.anchorStateRegistry, b.anchorStateRegistry, "anchorStateRegistry mismatch"); - assertEq(a.weth, b.weth, "weth mismatch"); - assertEq(a.l2ChainId, b.l2ChainId, "l2ChainId mismatch"); - assertEq(a.proposer, b.proposer, "proposer mismatch"); - assertEq(a.challenger, b.challenger, "challenger mismatch"); - } - - /// @notice Runs the OPCM updatePrestate function and checks the results. - /// @param _input The input to the OPCM updatePrestate function. - /// @param _revertBytes The bytes of the revert to expect, if any. - function _runUpdatePrestateAndChecks( - IOPContractsManager.UpdatePrestateInput memory _input, - bytes memory _revertBytes - ) - internal - { - bool expectCannonUpdated = address( - IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()).gameImpls(GameTypes.CANNON) - ) != address(0); - bool expectCannonKonaUpdated = address( - IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()).gameImpls( - GameTypes.CANNON_KONA - ) - ) != address(0); - - // Retrieve current game args before updatePrestate - IDisputeGameFactory dgf = IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()); - LibGameArgs.GameArgs memory pdgArgsBefore = _getParsedGameArgs(dgf, GameTypes.PERMISSIONED_CANNON); - LibGameArgs.GameArgs memory cannonArgsBefore; - LibGameArgs.GameArgs memory cannonKonaArgsBefore; - if (expectCannonUpdated) { - cannonArgsBefore = _getParsedGameArgs(dgf, GameTypes.CANNON); - } - if (expectCannonKonaUpdated) { - cannonKonaArgsBefore = _getParsedGameArgs(dgf, GameTypes.CANNON_KONA); - } - - IOPContractsManager.UpdatePrestateInput[] memory inputs = new IOPContractsManager.UpdatePrestateInput[](1); - inputs[0] = _input; - - // make the call to cache the proxy admin owner before setting expectRevert - address proxyAdminOwner = chainDeployOutput1.opChainProxyAdmin.owner(); - if (_revertBytes.length > 0) { - vm.expectRevert(_revertBytes); - } - - // Trigger the updatePrestate function. - prankDelegateCall(proxyAdminOwner); - (bool success,) = - address(prestateUpdater).delegatecall(abi.encodeCall(IOPContractsManager.updatePrestate, (inputs))); - assertTrue(success, "updatePrestate failed"); - - // Return early if a revert was expected. Otherwise we'll get errors below. - if (_revertBytes.length > 0) { - return; - } - - LibGameArgs.GameArgs memory pdgArgsAfter = _getParsedGameArgs(dgf, GameTypes.PERMISSIONED_CANNON); - _assertGameArgsEqual(pdgArgsBefore, pdgArgsAfter, true); - assertEq(pdgArgsAfter.absolutePrestate, _input.cannonPrestate.raw(), "permissioned game prestate mismatch"); - // Ensure that the WETH contracts are not reverting - IDelayedWETH(payable(pdgArgsAfter.weth)).balanceOf(address(0)); - - if (expectCannonUpdated) { - LibGameArgs.GameArgs memory cannonArgsAfter = _getParsedGameArgs(dgf, GameTypes.CANNON); - _assertGameArgsEqual(cannonArgsBefore, cannonArgsAfter, true); - assertEq(cannonArgsAfter.absolutePrestate, _input.cannonPrestate.raw(), "cannon game prestate mismatch"); - // Ensure that the WETH contracts are not reverting - IDelayedWETH(payable(cannonArgsAfter.weth)).balanceOf(address(0)); - } else { - assertEq(address(dgf.gameImpls(GameTypes.CANNON)), (address(0)), "cannon game should not exist"); - } - - if (expectCannonKonaUpdated) { - LibGameArgs.GameArgs memory cannonKonaArgsAfter = _getParsedGameArgs(dgf, GameTypes.CANNON_KONA); - _assertGameArgsEqual(cannonKonaArgsBefore, cannonKonaArgsAfter, true); - assertEq( - cannonKonaArgsAfter.absolutePrestate, - _input.cannonKonaPrestate.raw(), - "cannon-kona game prestate mismatch" - ); - // Ensure that the WETH contracts are not reverting - IDelayedWETH(payable(cannonKonaArgsAfter.weth)).balanceOf(address(0)); - } else { - assertEq(address(dgf.gameImpls(GameTypes.CANNON_KONA)), (address(0)), "cannon_kona game should not exist"); - } - } - - /// @notice Mocks the existence of a previous SuperPermissionedDisputeGame so we can add a real - /// SuperPermissionedDisputeGame implementation by calling opcm.updatePrestate. - function _mockSuperPermissionedGame() internal { - vm.mockCall( - address(chainDeployOutput1.disputeGameFactoryProxy), - abi.encodeCall(IDisputeGameFactory.gameImpls, (GameTypes.SUPER_PERMISSIONED_CANNON)), - abi.encode(chainDeployOutput1.permissionedDisputeGame) - ); - vm.mockCall( - address(chainDeployOutput1.permissionedDisputeGame), - abi.encodeCall(IDisputeGame.gameType, ()), - abi.encode(GameTypes.SUPER_PERMISSIONED_CANNON) - ); - vm.mockCall( - address(chainDeployOutput1.permissionedDisputeGame), - abi.encodeCall(IPermissionedDisputeGame.proposer, ()), - abi.encode(proposer) - ); - vm.mockCall( - address(chainDeployOutput1.permissionedDisputeGame), - abi.encodeCall(IPermissionedDisputeGame.challenger, ()), - abi.encode(challenger) - ); - } - - /// @notice Tests that we can update the prestate when only the PermissionedDisputeGame exists. - function test_updatePrestate_pdgOnlyWithValidInput_succeeds() public { - Claim prestate = Claim.wrap(bytes32(hex"ABBA")); - _runUpdatePrestateAndChecks( - IOPContractsManager.UpdatePrestateInput( - chainDeployOutput1.systemConfigProxy, prestate, Claim.wrap(bytes32(0)) - ) - ); - } - - /// @notice Tests that we can update the prestate when both the PermissionedDisputeGame and - /// FaultDisputeGame exist. - function test_updatePrestate_bothGamesWithValidInput_succeeds() public { - // Add a FaultDisputeGame implementation via addGameType. - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.CANNON); - addGameType(input); - - Claim prestate = Claim.wrap(bytes32(hex"ABBA")); - _runUpdatePrestateAndChecks( - IOPContractsManager.UpdatePrestateInput( - chainDeployOutput1.systemConfigProxy, prestate, Claim.wrap(bytes32(0)) - ) - ); - } - - /// @notice Tests that we can update the prestate when a SuperFaultDisputeGame exists. Note - /// that this test isn't ideal because the system starts with a PermissionedDisputeGame - /// and then adds a SuperPermissionedDisputeGame and SuperFaultDisputeGame. In the real - /// system we wouldn't have that PermissionedDisputeGame to start with, but it - /// shouldn't matter because the function is independent of other game types that - /// exist. - function test_updatePrestate_withSuperGame_succeeds() public { - skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); - - _mockSuperPermissionedGame(); - - // Add a SuperPermissionedDisputeGame implementation via addGameType. - IOPContractsManager.AddGameInput memory input1 = newGameInputFactory(GameTypes.SUPER_PERMISSIONED_CANNON); - addGameType(input1); - vm.clearMockedCalls(); - - // Add a SuperFaultDisputeGame implementation via addGameType. - IOPContractsManager.AddGameInput memory input2 = newGameInputFactory(GameTypes.SUPER_CANNON); - addGameType(input2); - - // Clear out the PermissionedDisputeGame implementation. - address owner = chainDeployOutput1.disputeGameFactoryProxy.owner(); - vm.prank(owner); - chainDeployOutput1.disputeGameFactoryProxy.setImplementation( - GameTypes.PERMISSIONED_CANNON, IDisputeGame(payable(address(0))) - ); - - // Create the input for the function call. - Claim prestate = Claim.wrap(bytes32(hex"ABBA")); - IOPContractsManager.UpdatePrestateInput[] memory inputs = new IOPContractsManager.UpdatePrestateInput[](1); - inputs[0] = IOPContractsManager.UpdatePrestateInput( - chainDeployOutput1.systemConfigProxy, prestate, Claim.wrap(bytes32(0)) - ); - - // Trigger the updatePrestate function. - address proxyAdminOwner = chainDeployOutput1.opChainProxyAdmin.owner(); - prankDelegateCall(proxyAdminOwner); - (bool success,) = - address(prestateUpdater).delegatecall(abi.encodeCall(IOPContractsManager.updatePrestate, (inputs))); - assertTrue(success, "updatePrestate failed"); - - LibGameArgs.GameArgs memory permissionedGameArgs = LibGameArgs.decode( - IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()).gameArgs( - GameTypes.SUPER_PERMISSIONED_CANNON - ) - ); - LibGameArgs.GameArgs memory cannonGameArgs = LibGameArgs.decode( - IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()).gameArgs( - GameTypes.SUPER_CANNON - ) - ); - - // Check the prestate values. - assertEq(permissionedGameArgs.absolutePrestate, prestate.raw(), "pdg prestate mismatch"); - assertEq(cannonGameArgs.absolutePrestate, prestate.raw(), "fdg prestate mismatch"); - - // Ensure that the WETH contracts are not reverting - IDelayedWETH(payable(permissionedGameArgs.weth)).balanceOf(address(0)); - IDelayedWETH(payable(cannonGameArgs.weth)).balanceOf(address(0)); - } - - /// @notice Tests that the updatePrestate function will revert if the provided prestate is for - /// mixed game types (i.e. CANNON and SUPER_CANNON). - function test_updatePrestate_mixedGameTypes_reverts() public { - skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); - - // Add a SuperFaultDisputeGame implementation via addGameType. - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.SUPER_CANNON); - addGameType(input); - - // nosemgrep: sol-style-use-abi-encodecall - _runUpdatePrestateAndChecks( - IOPContractsManager.UpdatePrestateInput({ - systemConfigProxy: chainDeployOutput1.systemConfigProxy, - cannonPrestate: Claim.wrap(bytes32(hex"ABBA")), - cannonKonaPrestate: Claim.wrap(bytes32(0)) - }), - abi.encodeWithSelector( - IOPContractsManagerGameTypeAdder.OPContractsManagerGameTypeAdder_MixedGameTypes.selector - ) - ); - } - - /// @notice Tests that the updatePrestate function will revert if the provided prestate is the - /// zero hash. - function test_updatePrestate_whenPDGPrestateIsZero_reverts() public { - // nosemgrep: sol-style-use-abi-encodecall - _runUpdatePrestateAndChecks( - IOPContractsManager.UpdatePrestateInput({ - systemConfigProxy: chainDeployOutput1.systemConfigProxy, - cannonPrestate: Claim.wrap(bytes32(0)), - cannonKonaPrestate: Claim.wrap(bytes32(0)) - }), - abi.encodeWithSelector(IOPContractsManager.PrestateRequired.selector) - ); - } - - function test_updatePrestate_whenOnlyCannonPrestateIsZeroAndCannonGameTypeDisabled_reverts() public { - // nosemgrep: sol-style-use-abi-encodecall - _runUpdatePrestateAndChecks( - IOPContractsManager.UpdatePrestateInput({ - systemConfigProxy: chainDeployOutput1.systemConfigProxy, - cannonPrestate: Claim.wrap(bytes32(0)), - cannonKonaPrestate: Claim.wrap(bytes32(hex"ABBA")) - }), - abi.encodeWithSelector(IOPContractsManager.PrestateRequired.selector) - ); - } - - /// @notice Tests that we can update the prestate for both CANNON and CANNON_KONA game types. - function test_updatePrestate_bothGamesAndCannonKonaWithValidInput_succeeds() public { - // Add a FaultDisputeGame implementation via addGameType. - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.CANNON); - addGameType(input); - input = newGameInputFactory(GameTypes.CANNON_KONA); - addGameType(input); - - Claim cannonPrestate = Claim.wrap(bytes32(hex"ABBA")); - Claim cannonKonaPrestate = Claim.wrap(bytes32(hex"ADDA")); - _runUpdatePrestateAndChecks( - IOPContractsManager.UpdatePrestateInput({ - systemConfigProxy: chainDeployOutput1.systemConfigProxy, - cannonPrestate: cannonPrestate, - cannonKonaPrestate: cannonKonaPrestate - }) - ); - } - - function test_updatePrestate_cannonKonaWithSuperGame_succeeds() public { - skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); - - _mockSuperPermissionedGame(); - // Add a SuperPermissionedDisputeGame implementation via addGameType. - IOPContractsManager.AddGameInput memory input1 = newGameInputFactory(GameTypes.SUPER_PERMISSIONED_CANNON); - addGameType(input1); - vm.clearMockedCalls(); - - // Add a SuperFaultDisputeGame implementation via addGameType. - IOPContractsManager.AddGameInput memory input2 = newGameInputFactory(GameTypes.SUPER_CANNON); - addGameType(input2); - IOPContractsManager.AddGameInput memory input3 = newGameInputFactory(GameTypes.SUPER_CANNON_KONA); - addGameType(input3); - - // Clear out the PermissionedDisputeGame implementation. - address owner = chainDeployOutput1.disputeGameFactoryProxy.owner(); - vm.prank(owner); - chainDeployOutput1.disputeGameFactoryProxy.setImplementation( - GameTypes.PERMISSIONED_CANNON, IDisputeGame(payable(address(0))) - ); - - // Create the input for the function call. - Claim cannonPrestate = Claim.wrap(bytes32(hex"ABBA")); - Claim cannonKonaPrestate = Claim.wrap(bytes32(hex"ABBA")); - IOPContractsManager.UpdatePrestateInput[] memory inputs = new IOPContractsManager.UpdatePrestateInput[](1); - inputs[0] = IOPContractsManager.UpdatePrestateInput({ - systemConfigProxy: chainDeployOutput1.systemConfigProxy, - cannonPrestate: cannonPrestate, - cannonKonaPrestate: cannonKonaPrestate - }); - - // Trigger the updatePrestate function. - address proxyAdminOwner = chainDeployOutput1.opChainProxyAdmin.owner(); - prankDelegateCall(proxyAdminOwner); - (bool success,) = - address(prestateUpdater).delegatecall(abi.encodeCall(IOPContractsManager.updatePrestate, (inputs))); - assertTrue(success, "updatePrestate failed"); - - LibGameArgs.GameArgs memory permissionedGameArgs = - LibGameArgs.decode(chainDeployOutput1.disputeGameFactoryProxy.gameArgs(GameTypes.SUPER_PERMISSIONED_CANNON)); - LibGameArgs.GameArgs memory cannonGameArgs = - LibGameArgs.decode(chainDeployOutput1.disputeGameFactoryProxy.gameArgs(GameTypes.SUPER_CANNON)); - LibGameArgs.GameArgs memory cannonKonaGameArgs = - LibGameArgs.decode(chainDeployOutput1.disputeGameFactoryProxy.gameArgs(GameTypes.SUPER_CANNON_KONA)); - - // Check the prestate values. - assertEq(permissionedGameArgs.absolutePrestate, cannonPrestate.raw(), "pdg prestate mismatch"); - assertEq(cannonGameArgs.absolutePrestate, cannonPrestate.raw(), "fdg prestate mismatch"); - assertEq(cannonKonaGameArgs.absolutePrestate, cannonKonaPrestate.raw(), "fdgKona prestate mismatch"); - - // Ensure that the WETH contracts are not reverting - IDelayedWETH(payable(permissionedGameArgs.weth)).balanceOf(address(0)); - IDelayedWETH(payable(cannonGameArgs.weth)).balanceOf(address(0)); - IDelayedWETH(payable(cannonKonaGameArgs.weth)).balanceOf(address(0)); - } - - /// @notice Tests that we can update the prestate when both the PermissionedDisputeGame and - /// FaultDisputeGame exist, and the FaultDisputeGame is of type CANNON_KONA. - function test_updatePrestate_pdgAndCannonKonaOnly_succeeds() public { - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.CANNON_KONA); - addGameType(input); - - _runUpdatePrestateAndChecks( - IOPContractsManager.UpdatePrestateInput({ - systemConfigProxy: chainDeployOutput1.systemConfigProxy, - cannonPrestate: Claim.wrap(bytes32(hex"ABBA")), - cannonKonaPrestate: Claim.wrap(bytes32(hex"ADDA")) - }) - ); - } - - /// @notice Tests that the updatePrestate function will revert if the provided prestate is for - /// mixed game types (i.e. CANNON and SUPER_CANNON_KONA). - function test_updatePrestate_cannonKonaMixedGameTypes_reverts() public { - skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); - - // Add a SuperFaultDisputeGame implementation via addGameType. - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.SUPER_CANNON_KONA); - addGameType(input); - - // nosemgrep: sol-style-use-abi-encodecall - _runUpdatePrestateAndChecks( - IOPContractsManager.UpdatePrestateInput({ - systemConfigProxy: chainDeployOutput1.systemConfigProxy, - cannonPrestate: Claim.wrap(bytes32(hex"ABBA")), - cannonKonaPrestate: Claim.wrap(hex"ADDA") - }), - abi.encodeWithSelector( - IOPContractsManagerGameTypeAdder.OPContractsManagerGameTypeAdder_MixedGameTypes.selector - ) - ); - } - - /// @notice Tests that the updatePrestate function will revert if the provided prestate is the - /// zero hash. - function test_updatePrestate_presetCannonKonaWhenOnlyCannonPrestateIsZeroAndCannonGameTypeDisabled_reverts() - public - { - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.CANNON_KONA); - addGameType(input); - - // nosemgrep: sol-style-use-abi-encodecall - _runUpdatePrestateAndChecks( - IOPContractsManager.UpdatePrestateInput({ - systemConfigProxy: chainDeployOutput1.systemConfigProxy, - cannonPrestate: Claim.wrap(bytes32(0)), - cannonKonaPrestate: Claim.wrap(bytes32(hex"ABBA")) - }), - abi.encodeWithSelector(IOPContractsManager.PrestateRequired.selector) - ); - } - - /// @notice Tests that the updatePrestate function will revert if the provided prestate is the - /// zero hash. - function test_updatePrestate_whenCannonKonaPrestateIsZero_reverts() public { - IOPContractsManager.AddGameInput memory input = newGameInputFactory(GameTypes.CANNON_KONA); - addGameType(input); - - // nosemgrep: sol-style-use-abi-encodecall - _runUpdatePrestateAndChecks( - IOPContractsManager.UpdatePrestateInput({ - systemConfigProxy: chainDeployOutput1.systemConfigProxy, - cannonPrestate: Claim.wrap(bytes32(hex"ABBA")), - cannonKonaPrestate: Claim.wrap(bytes32(0)) - }), - abi.encodeWithSelector(IOPContractsManager.PrestateRequired.selector) - ); - } -} - -/// @title OPContractsManager_Upgrade_Test -/// @notice Tests the `upgrade` function of the `OPContractsManager` contract. -contract OPContractsManager_Upgrade_Test is OPContractsManager_Upgrade_Harness { - function setUp() public override { - super.setUp(); - - // Run all past upgrades. - runPastUpgrades(upgrader); - - // Grab the pre-upgrade state. Use getGameImplPrestate to handle both v1 and v2 - // dispute games (v1 stores prestate on game impl, v2 stores it in gameArgs). - preUpgradeState = PreUpgradeState({ - cannonAbsolutePrestate: DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.CANNON), - permissionedAbsolutePrestate: DisputeGames.getGameImplPrestate( - disputeGameFactory, GameTypes.PERMISSIONED_CANNON - ), - cannonKonaAbsolutePrestate: DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.CANNON_KONA), - permissionlessWethProxy: DisputeGames.getGameImplDelayedWeth(disputeGameFactory, GameTypes.CANNON), - permissionedCannonWethProxy: DisputeGames.getGameImplDelayedWeth( - disputeGameFactory, GameTypes.PERMISSIONED_CANNON - ) - }); - } - - function getDisputeGameV2AbsolutePrestate(GameType _gameType) internal view returns (Claim) { - bytes memory gameArgsBytes = disputeGameFactory.gameArgs(_gameType); - LibGameArgs.GameArgs memory gameArgs = LibGameArgs.decode(gameArgsBytes); - return Claim.wrap(gameArgs.absolutePrestate); - } - - function test_upgradeOPChainOnly_succeeds() public { - // Run the upgrade test and checks - runCurrentUpgrade(upgrader); - } - - function test_verifyOpcmCorrectness_succeeds() public { - skipIfUnoptimized(); - - // Set up environment variables with the actual OPCM addresses for tests that need them. - // These values come from the StandardValidator that was deployed with the OPCM. - vm.setEnv("EXPECTED_SUPERCHAIN_CONFIG", vm.toString(address(opcm.superchainConfig()))); - vm.setEnv("EXPECTED_PROTOCOL_VERSIONS", vm.toString(address(opcm.protocolVersions()))); - IOPContractsManagerStandardValidator validator = opcm.opcmStandardValidator(); - vm.setEnv("EXPECTED_L1_PAO_MULTISIG", vm.toString(validator.l1PAOMultisig())); - vm.setEnv("EXPECTED_CHALLENGER", vm.toString(validator.challenger())); - vm.setEnv("EXPECTED_WITHDRAWAL_DELAY_SECONDS", vm.toString(validator.withdrawalDelaySeconds())); - - // Run the upgrade test and checks - runCurrentUpgrade(upgrader); - - // Run the verification script without etherscan verification. Hard to run with etherscan - // verification in these tests, can do it but means we add even more dependencies to the - // test environment. - VerifyOPCM verify = new VerifyOPCM(); - verify.run(address(opcm), true); - } - - function test_upgrade_duplicateL2ChainId_succeeds() public { - // Deploy a new OPChain with the same L2 chain ID as the current OPChain - Deploy deploy = Deploy(address(uint160(uint256(keccak256(abi.encode("optimism.deploy")))))); - IOPContractsManager.DeployInput memory deployInput = deploy.getDeployInput(); - deployInput.l2ChainId = l2ChainId; - deployInput.saltMixer = "v2.0.0"; - opcm.deploy(deployInput); - - // Try to upgrade the current OPChain - runCurrentUpgrade(upgrader); - } - - /// @notice Tests that the absolute prestate can be overridden using the upgrade config. - function test_upgrade_absolutePrestateOverride_succeeds() public { - // Get the pdg and fdg before the upgrade. Use getGameImplPrestate to handle both v1 and v2 - // dispute games (v1 stores prestate on game impl, v2 stores it in gameArgs). - Claim pdgPrestateBefore = DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.PERMISSIONED_CANNON); - Claim fdgPrestateBefore = DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.CANNON); - - // Assert that the prestate is not zero. - assertNotEq(pdgPrestateBefore.raw(), bytes32(0)); - assertNotEq(fdgPrestateBefore.raw(), bytes32(0)); - - // Set the absolute prestate input to something non-zero. - opChainConfigs[0].cannonPrestate = Claim.wrap(bytes32(uint256(1))); - opChainConfigs[0].cannonKonaPrestate = Claim.wrap(bytes32(uint256(2))); - - // Run the upgrade. - runCurrentUpgrade(upgrader); - - // Get the absolute prestate after the upgrade - Claim pdgPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.PERMISSIONED_CANNON); - Claim fdgPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.CANNON); - - // Assert that the absolute prestate is the non-zero value we set. - assertEq(pdgPrestateAfter.raw(), bytes32(uint256(1))); - assertEq(fdgPrestateAfter.raw(), bytes32(uint256(1))); - - LibGameArgs.GameArgs memory cannonArgs = LibGameArgs.decode(disputeGameFactory.gameArgs(GameTypes.CANNON)); - LibGameArgs.GameArgs memory cannonKonaArgs = - LibGameArgs.decode(disputeGameFactory.gameArgs(GameTypes.CANNON_KONA)); - assertEq(cannonKonaArgs.weth, cannonArgs.weth); - assertEq(cannonKonaArgs.anchorStateRegistry, cannonArgs.anchorStateRegistry); - assertEq(cannonKonaArgs.absolutePrestate, bytes32(uint256(2))); - } - - /// @notice Tests that the old absolute prestate is used if the upgrade config does not set an - /// absolute prestate. - function test_upgrade_absolutePrestateNotSet_succeeds() public { - // Get the pdg and fdg before the upgrade. Use getGameImplPrestate to handle both v1 and v2 - // dispute games (v1 stores prestate on game impl, v2 stores it in gameArgs). - Claim pdgPrestateBefore = DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.PERMISSIONED_CANNON); - Claim fdgPrestateBefore = DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.CANNON); - Claim cannonKonaPrestateBefore = DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.CANNON_KONA); - - // Assert that the prestate is not zero. - assertNotEq(pdgPrestateBefore.raw(), bytes32(0)); - assertNotEq(fdgPrestateBefore.raw(), bytes32(0)); - assertNotEq(cannonKonaPrestateBefore.raw(), bytes32(0)); - - // Set the absolute prestate input to zero. - opChainConfigs[0].cannonPrestate = Claim.wrap(bytes32(0)); - opChainConfigs[0].cannonKonaPrestate = Claim.wrap(bytes32(0)); - - // Run the upgrade. - runCurrentUpgrade(upgrader); - - // Get the absolute prestate after the upgrade - Claim pdgPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.PERMISSIONED_CANNON); - Claim fdgPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.CANNON); - Claim cannonKonaPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.CANNON_KONA); - - // Assert that the absolute prestate is the same as before the upgrade. - assertEq(pdgPrestateAfter.raw(), pdgPrestateBefore.raw()); - assertEq(fdgPrestateAfter.raw(), fdgPrestateBefore.raw()); - assertEq(cannonKonaPrestateAfter.raw(), cannonKonaPrestateBefore.raw()); - } - - /// @notice Tests that the old absolute prestate is used and cannon kona is updated if the upgrade config does not - /// set a cannon prestate. - function test_upgrade_cannonPrestateNotSet_succeeds() public { - // Get the pdg and fdg before the upgrade. Use getGameImplPrestate to handle both v1 and v2 - // dispute games (v1 stores prestate on game impl, v2 stores it in gameArgs). - Claim pdgPrestateBefore = DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.PERMISSIONED_CANNON); - Claim fdgPrestateBefore = DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.CANNON); - Claim cannonKonaPrestateBefore = DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.CANNON_KONA); - - // Assert that the prestate is not zero. - assertNotEq(pdgPrestateBefore.raw(), bytes32(0)); - assertNotEq(fdgPrestateBefore.raw(), bytes32(0)); - assertNotEq(cannonKonaPrestateBefore.raw(), bytes32(0)); - - // Set the cannon prestate input to zero. - opChainConfigs[0].cannonPrestate = Claim.wrap(bytes32(0)); - - // Set the cannon kona prestate input to something non-zero. - opChainConfigs[0].cannonKonaPrestate = Claim.wrap(bytes32(uint256(1))); - - // Run the upgrade. - runCurrentUpgrade(upgrader); - - // Get the absolute prestate after the upgrade - Claim pdgPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.PERMISSIONED_CANNON); - Claim fdgPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.CANNON); - Claim cannonKonaPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.CANNON_KONA); - - // Assert that the absolute prestate is the same as before the upgrade. - assertEq(pdgPrestateAfter.raw(), pdgPrestateBefore.raw()); - assertEq(fdgPrestateAfter.raw(), fdgPrestateBefore.raw()); - - // Assert that the cannon kona prestate is the non-zero value we set. - assertEq(cannonKonaPrestateAfter.raw(), bytes32(uint256(1))); - } - - /// @notice Tests that the cannon absolute prestate is updated even if the cannon kona prestate is not specified - function test_upgrade_cannonKonaPrestateNotSet_succeeds() public { - // Get the pdg and fdg before the upgrade. Use getGameImplPrestate to handle both v1 and v2 - // dispute games (v1 stores prestate on game impl, v2 stores it in gameArgs). - Claim pdgPrestateBefore = DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.PERMISSIONED_CANNON); - Claim fdgPrestateBefore = DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.CANNON); - Claim cannonKonaPrestateBefore = DisputeGames.getGameImplPrestate(disputeGameFactory, GameTypes.CANNON_KONA); - - // Assert that the prestate is not zero. - assertNotEq(pdgPrestateBefore.raw(), bytes32(0)); - assertNotEq(fdgPrestateBefore.raw(), bytes32(0)); - assertNotEq(cannonKonaPrestateBefore.raw(), bytes32(0)); - - // Set the absolute prestate input to something non-zero. - opChainConfigs[0].cannonPrestate = Claim.wrap(bytes32(uint256(1))); - - // Set the cannon kona prestate input to zero. - opChainConfigs[0].cannonKonaPrestate = Claim.wrap(bytes32(0)); - - // Run the upgrade. - runCurrentUpgrade(upgrader); - - // Get the absolute prestate after the upgrade - Claim pdgPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.PERMISSIONED_CANNON); - Claim fdgPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.CANNON); - Claim cannonKonaPrestateAfter = getDisputeGameV2AbsolutePrestate(GameTypes.CANNON_KONA); - - // Assert that the absolute prestate is the non-zero value we set. - assertEq(pdgPrestateAfter.raw(), bytes32(uint256(1))); - assertEq(fdgPrestateAfter.raw(), bytes32(uint256(1))); - - // Assert that the cannon kona prestate is the same as before the upgrade. - assertEq(cannonKonaPrestateAfter.raw(), cannonKonaPrestateBefore.raw()); - } - - function test_upgrade_notDelegateCalled_reverts() public { - vm.prank(upgrader); - vm.expectRevert(IOPContractsManager.OnlyDelegatecall.selector); - opcm.upgrade(opChainConfigs); - } - - function test_upgrade_notProxyAdminOwner_reverts() public { - address delegateCaller = makeAddr("delegateCaller"); - - assertNotEq(superchainProxyAdmin.owner(), delegateCaller); - assertNotEq(proxyAdmin.owner(), delegateCaller); - - runCurrentUpgrade(delegateCaller, bytes("Ownable: caller is not the owner")); - } - - /// @notice Tests that upgrade reverts when absolutePrestate is zero and the existing game also - /// has an absolute prestate of zero. - function test_upgrade_absolutePrestateNotSet_reverts() public { - // Set the config to try to update the absolutePrestate to zero. - opChainConfigs[0].cannonPrestate = Claim.wrap(bytes32(0)); - - // Mock the PDG prestate to zero. This uses mockGameImplPrestate which handles both v1 and v2 - // dispute games correctly (v1 stores prestate on the game impl, v2 stores it in gameArgs). - DisputeGames.mockGameImplPrestate(disputeGameFactory, GameTypes.PERMISSIONED_CANNON, bytes32(0)); - - // Expect the upgrade to revert with PrestateNotSet. - // nosemgrep: sol-style-use-abi-encodecall - runCurrentUpgrade(upgrader, abi.encodeWithSelector(IOPContractsManager.PrestateNotSet.selector)); - } - - /// @notice Tests that the upgrade function reverts when the superchainConfig is not at the expected target version. - function test_upgrade_superchainConfigNeedsUpgrade_reverts() public { - // Force the SuperchainConfig to return an obviously outdated version. - vm.mockCall(address(superchainConfig), abi.encodeCall(ISuperchainConfig.version, ()), abi.encode("0.0.0")); - - // Try upgrading an OPChain without upgrading its superchainConfig. - // nosemgrep: sol-style-use-abi-encodecall - runCurrentUpgrade( - upgrader, - abi.encodeWithSelector( - IOPContractsManagerUpgrader.OPContractsManagerUpgrader_SuperchainConfigNeedsUpgrade.selector, (0) - ) - ); - } -} - -contract OPContractsManager_UpgradeSuperchainConfig_Test is OPContractsManager_Upgrade_Harness { - function setUp() public override { - super.setUp(); - - // The superchainConfig is already at the expected version so we mock this call here to bypass that check and - // get our expected error. - vm.mockCall(address(superchainConfig), abi.encodeCall(ISuperchainConfig.version, ()), abi.encode("2.2.0")); - } - - /// @notice Tests that the upgradeSuperchainConfig function succeeds when the superchainConfig is at the expected - /// version and the delegate caller is the superchainProxyAdmin owner. - function test_upgradeSuperchainConfig_succeeds() public { - IOPContractsManager.Implementations memory impls = opcm.implementations(); - - ISuperchainConfig superchainConfig = ISuperchainConfig(artifacts.mustGetAddress("SuperchainConfigProxy")); - - address superchainPAO = IProxyAdmin(EIP1967Helper.getAdmin(address(superchainConfig))).owner(); - - vm.expectEmit(address(superchainConfig)); - emit Upgraded(impls.superchainConfigImpl); - prankDelegateCall(superchainPAO); - (bool success,) = - address(opcm).delegatecall(abi.encodeCall(IOPContractsManager.upgradeSuperchainConfig, (superchainConfig))); - assertTrue(success, "upgradeSuperchainConfig failed"); - } - - /// @notice Tests that the upgradeSuperchainConfig function reverts when it is not called via delegatecall. - function test_upgradeSuperchainConfig_notDelegateCalled_reverts() public { - ISuperchainConfig superchainConfig = ISuperchainConfig(artifacts.mustGetAddress("SuperchainConfigProxy")); - - vm.expectRevert(IOPContractsManager.OnlyDelegatecall.selector); - opcm.upgradeSuperchainConfig(superchainConfig); - } - - /// @notice Tests that the upgradeSuperchainConfig function reverts when the delegate caller is not the - /// superchainProxyAdmin owner. - function test_upgradeSuperchainConfig_notProxyAdminOwner_reverts() public { - ISuperchainConfig superchainConfig = ISuperchainConfig(artifacts.mustGetAddress("SuperchainConfigProxy")); - - address delegateCaller = makeAddr("delegateCaller"); - - assertNotEq(superchainProxyAdmin.owner(), delegateCaller); - assertNotEq(proxyAdmin.owner(), delegateCaller); - - vm.expectRevert("Ownable: caller is not the owner"); - prankDelegateCall(delegateCaller); - (bool success,) = - address(opcm).delegatecall(abi.encodeCall(IOPContractsManager.upgradeSuperchainConfig, (superchainConfig))); - assertTrue(success, "upgradeSuperchainConfig failed"); - } - - /// @notice Tests that the upgradeSuperchainConfig function reverts when the superchainConfig version is the same or - /// newer than the target version. - function test_upgradeSuperchainConfig_superchainConfigAlreadyUpToDate_reverts() public { - ISuperchainConfig superchainConfig = ISuperchainConfig(artifacts.mustGetAddress("SuperchainConfigProxy")); - - // Set the version of the superchain config to a version that is the target version. - vm.clearMockedCalls(); - - // Mock the SuperchainConfig to return a very large version. - vm.mockCall(address(superchainConfig), abi.encodeCall(ISuperchainConfig.version, ()), abi.encode("99.99.99")); - - // Try to upgrade the SuperchainConfig contract again, should fail. - vm.expectRevert(IOPContractsManagerUpgrader.OPContractsManagerUpgrader_SuperchainConfigAlreadyUpToDate.selector); - prankDelegateCall(upgrader); - (bool success,) = - address(opcm).delegatecall(abi.encodeCall(IOPContractsManager.upgradeSuperchainConfig, (superchainConfig))); - assertTrue(success, "upgradeSuperchainConfig failed"); - } -} - -/// @title OPContractsManager_Migrate_Test -/// @notice Tests the `migrate` function of the `OPContractsManager` contract. -contract OPContractsManager_Migrate_Test is OPContractsManager_TestInit { - 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 { - super.setUp(); - skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); - } - - /// @notice Helper function to create the default migration input. - function _getDefaultInput() internal view returns (IOPContractsManagerInteropMigrator.MigrateInput memory) { - IOPContractsManagerInteropMigrator.GameParameters memory gameParameters = IOPContractsManagerInteropMigrator - .GameParameters({ - proposer: address(1234), - challenger: address(5678), - maxGameDepth: 73, - splitDepth: 30, - initBond: 1 ether, - clockExtension: Duration.wrap(10800), - maxClockDuration: Duration.wrap(302400) - }); - - IOPContractsManager.OpChainConfig[] memory opChainConfigs = new IOPContractsManager.OpChainConfig[](2); - opChainConfigs[0] = IOPContractsManager.OpChainConfig( - chainDeployOutput1.systemConfigProxy, cannonPrestate1, cannonKonaPrestate1 - ); - opChainConfigs[1] = IOPContractsManager.OpChainConfig( - chainDeployOutput2.systemConfigProxy, cannonPrestate1, cannonKonaPrestate1 - ); - - return IOPContractsManagerInteropMigrator.MigrateInput({ - usePermissionlessGame: true, - startingAnchorRoot: Proposal({ root: Hash.wrap(bytes32(hex"ABBA")), l2SequenceNumber: 1234 }), - gameParameters: gameParameters, - opChainConfigs: opChainConfigs - }); - } - - /// @notice Helper function to execute a migration. - /// @param _input The input to the migration function. - function _doMigration(IOPContractsManagerInteropMigrator.MigrateInput memory _input) internal { - _doMigration(_input, bytes4(0)); - } - - /// @notice Helper function to execute a migration with a revert selector. - /// @param _input The input to the migration function. - /// @param _revertSelector The selector of the revert to expect. - function _doMigration( - IOPContractsManagerInteropMigrator.MigrateInput memory _input, - bytes4 _revertSelector - ) - internal - { - // Set the proxy admin owner to be a delegate caller. - address proxyAdminOwner = chainDeployOutput1.opChainProxyAdmin.owner(); - - // Execute a delegatecall to the OPCM migration function. - // Check gas usage of the migration function. - uint256 gasBefore = gasleft(); - if (_revertSelector != bytes4(0)) { - vm.expectRevert(_revertSelector); - } - prankDelegateCall(proxyAdminOwner); - (bool success,) = address(opcm).delegatecall(abi.encodeCall(IOPContractsManager.migrate, (_input))); - assertTrue(success, "migrate failed"); - uint256 gasAfter = gasleft(); - - // Make sure the gas usage is less than 20 million so we can definitely fit in a block. - assertLt(gasBefore - gasAfter, 20_000_000, "Gas usage too high"); - } - - /// @notice Helper function to assert that the old game implementations are now zeroed out. - /// We need a separate helper to avoid stack too deep errors. - /// @param _disputeGameFactory The dispute game factory to check. - function _assertOldGamesZeroed(IDisputeGameFactory _disputeGameFactory) internal view { - // Assert that the old game implementations are now zeroed out. - _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"); - // Only explicitly zeroed out if feature is enabled. Otherwise left unchanged (which may still be 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 Creates a dummy super root proof consisting of all chains being migrated - function _createSuperRootProof( - IOPContractsManagerInteropMigrator.MigrateInput memory _input, - uint64 _l2SequenceNumber - ) - internal - view - returns (LibTypes.SuperRootProof memory super_) - { - LibTypes.OutputRootWithChainId[] memory outputRoots = - new LibTypes.OutputRootWithChainId[](_input.opChainConfigs.length); - for (uint256 j; j < _input.opChainConfigs.length; j++) { - outputRoots[j] = LibTypes.OutputRootWithChainId({ - chainId: uint32(_input.opChainConfigs[j].systemConfigProxy.l2ChainId()), - root: keccak256(abi.encode(gasleft())) - }); - } - super_.version = bytes1(uint8(1)); - super_.timestamp = uint64(_l2SequenceNumber); - super_.outputRoots = outputRoots; - } - - /// @notice Runs some tests after opcm.migrate - function _runPostMigrateSmokeTests(IOPContractsManagerInteropMigrator.MigrateInput memory _input) internal { - IDisputeGameFactory dgf = IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()); - IAnchorStateRegistry anchorStateRegistry = - IOptimismPortal2(payable(chainDeployOutput1.systemConfigProxy.optimismPortal())).anchorStateRegistry(); - address proposer = _input.gameParameters.proposer; - - (, uint256 l2SequenceNumberAnchor) = anchorStateRegistry.getAnchorRoot(); - uint256 l2SequenceNumber = l2SequenceNumberAnchor + 1; - 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])); - if (permissionlessWeth == address(0) && !DisputeGames.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 (!DisputeGames.isGamePermissioned(gameTypes[i])) { - // All permissionless FDG games should share the same weth contract - assertEq(gameArgs.weth, permissionlessWeth, "gameArgs weth mismatch"); - } - - LibTypes.SuperRootProof memory superRootProof = _createSuperRootProof(_input, uint64(l2SequenceNumber)); - uint256 bondAmount = dgf.initBonds(gameTypes[i]); - vm.deal(address(proposer), bondAmount); - vm.prank(proposer, proposer); - - ISuperPermissionedDisputeGame game = ISuperPermissionedDisputeGame( - address( - dgf.create{ value: bondAmount }( - gameTypes[i], - Claim.wrap(Hashing.hashSuperRootProof(superRootProof)), - Encoding.encodeSuperRootProof(superRootProof) - ) - ) - ); - - assertEq(game.gameType().raw(), gameTypes[i].raw(), "Super Cannon game type not set properly"); - assertEq( - game.maxClockDuration().raw(), - _input.gameParameters.maxClockDuration.raw(), - "max clock duration mismatch" - ); - assertEq( - game.clockExtension().raw(), _input.gameParameters.clockExtension.raw(), "max clock duration mismatch" - ); - assertEq(game.maxGameDepth(), _input.gameParameters.maxGameDepth, "max game depth mismatch"); - assertEq(game.splitDepth(), _input.gameParameters.splitDepth, "split depth mismatch"); - assertEq(game.l2SequenceNumber(), l2SequenceNumber, "sequence number mismatch"); - assertEq(game.gameCreator(), proposer, "game creator mismatch"); - assertEq(game.l1Head().raw(), blockhash(block.number - 1), "l1 head mismatch"); - - // check game args - assertEq(game.absolutePrestate().raw(), gameArgs.absolutePrestate, "prestate mismatch"); - assertEq(address(game.vm()), gameArgs.vm, "vm mismatch"); - assertEq(address(game.anchorStateRegistry()), gameArgs.anchorStateRegistry, "prestate mismatch"); - assertEq(address(game.weth()), gameArgs.weth, "weth mismatch"); - if (gameTypes[i].raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw()) { - assertEq(game.proposer(), gameArgs.proposer, "proposer mismatch"); - assertEq(game.challenger(), gameArgs.challenger, "challenger mismatch"); - } - } - } - - function _getPostMigrateExpectedGameTypes(IOPContractsManagerInteropMigrator.MigrateInput memory _input) - internal - pure - returns (GameType[] memory gameTypes_) - { - uint256 gameCount = 1; - bytes32 cannonKonaPrestate = _input.opChainConfigs[0].cannonKonaPrestate.raw(); - if (_input.usePermissionlessGame) { - gameCount += 1; - if (cannonKonaPrestate != bytes32(0)) { - gameCount += 1; - } - } - - gameTypes_ = new GameType[](gameCount); - gameTypes_[0] = GameTypes.SUPER_PERMISSIONED_CANNON; - if (_input.usePermissionlessGame) { - gameTypes_[1] = GameTypes.SUPER_CANNON; - if (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); - - // Check the respected game type - assertEq(asr.respectedGameType().raw(), GameTypes.SUPER_CANNON.raw(), "Super Cannon game type mismatch"); - - // Check initial bonds - assertEq( - dgf.initBonds(GameTypes.SUPER_CANNON), input.gameParameters.initBond, "Super Cannon init bond mismatch" - ); - assertEq( - dgf.initBonds(GameTypes.SUPER_PERMISSIONED_CANNON), - input.gameParameters.initBond, - "Super Permissioned Cannon init bond mismatch" - ); - assertEq( - dgf.initBonds(GameTypes.SUPER_CANNON_KONA), - input.gameParameters.initBond, - "Super CannonKona init bond mismatch" - ); - - // Check game configuration - _validateSuperGameImplParams(input, dgf, GameTypes.SUPER_PERMISSIONED_CANNON, "SUPER_PERMISSIONED_CANNON"); - _validateSuperGameImplParams(input, dgf, GameTypes.SUPER_CANNON, "SUPER_CANNON"); - _validateSuperGameImplParams(input, dgf, GameTypes.SUPER_CANNON_KONA, "SUPER_CANNON_KONA"); - - _runPostMigrateSmokeTests(input); - } - - /// @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; - - // Execute the migration. - _doMigration(input, IOPContractsManager.PrestateNotSet.selector); - } - - /// @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 the respected game type - assertEq(asr.respectedGameType().raw(), GameTypes.SUPER_CANNON.raw(), "Super Cannon game type mismatch"); - - // Check initial bonds - assertEq( - dgf.initBonds(GameTypes.SUPER_CANNON), input.gameParameters.initBond, "Super Cannon init bond mismatch" - ); - assertEq( - 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 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); - } - - /// @notice Tests that the migration function succeeds when requesting to not use the - /// 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); - } - - /// @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. - IDisputeGameFactory oldDisputeGameFactory1 = - IDisputeGameFactory(payable(chainDeployOutput1.systemConfigProxy.disputeGameFactory())); - IDisputeGameFactory oldDisputeGameFactory2 = - IDisputeGameFactory(payable(chainDeployOutput2.systemConfigProxy.disputeGameFactory())); - - // 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. - assertEq( - address(optimismPortal1.anchorStateRegistry()), - address(optimismPortal2.anchorStateRegistry()), - "AnchorStateRegistry mismatch" - ); - - // Extract the AnchorStateRegistry now that we know it's the same on both chains. - 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( - chainDeployOutput1.systemConfigProxy.disputeGameFactory(), - chainDeployOutput2.systemConfigProxy.disputeGameFactory(), - "DisputeGameFactory mismatch" - ); - - // Extract the DisputeGameFactory now that we know it's the same on both chains. - dgf_ = IDisputeGameFactory(chainDeployOutput1.systemConfigProxy.disputeGameFactory()); - - // 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. - IETHLockbox ethLockbox = optimismPortal1.ethLockbox(); - - // 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"); - } - - 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( - superImpl.maxGameDepth(), - _input.gameParameters.maxGameDepth, - string.concat("MaxGameDepth mismatch: ", _label) - ); - assertEq( - superImpl.splitDepth(), _input.gameParameters.splitDepth, string.concat("SplitDepth mismatch: ", _label) - ); - assertEq( - 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) - ); - } - - /// @notice Tests that the migration function reverts when the ProxyAdmin owners are - /// mismatched. - function test_migrate_mismatchedProxyAdminOwners_reverts() public { - IOPContractsManagerInteropMigrator.MigrateInput memory input = _getDefaultInput(); - - // Mock out the owners of the ProxyAdmins to be different. - vm.mockCall( - address(input.opChainConfigs[0].systemConfigProxy.proxyAdmin()), - abi.encodeCall(IProxyAdmin.owner, ()), - abi.encode(address(1234)) - ); - vm.mockCall( - address(input.opChainConfigs[1].systemConfigProxy.proxyAdmin()), - abi.encodeCall(IProxyAdmin.owner, ()), - abi.encode(address(5678)) - ); - - // Execute the migration. - _doMigration( - input, OPContractsManagerInteropMigrator.OPContractsManagerInteropMigrator_ProxyAdminOwnerMismatch.selector - ); - } - - /// @notice Tests that the migration function reverts when the absolute prestates are - /// mismatched. - function test_migrate_mismatchedCannonPrestates_reverts() public { - IOPContractsManagerInteropMigrator.MigrateInput memory input = _getDefaultInput(); - - // Set the prestates to be different. - input.opChainConfigs[0].cannonPrestate = cannonPrestate1; - input.opChainConfigs[1].cannonPrestate = cannonPrestate2; - - // Execute the migration. - _doMigration( - input, OPContractsManagerInteropMigrator.OPContractsManagerInteropMigrator_AbsolutePrestateMismatch.selector - ); - } - - /// @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. - // We should revert if there is a mismatch and cannonaKona is enabled - _doMigration( - input, OPContractsManagerInteropMigrator.OPContractsManagerInteropMigrator_AbsolutePrestateMismatch.selector - ); - } - - /// @notice Tests that the migration function reverts when the SuperchainConfig addresses are - /// mismatched. - function test_migrate_mismatchedSuperchainConfig_reverts() public { - IOPContractsManagerInteropMigrator.MigrateInput memory input = _getDefaultInput(); - - // Mock out the SuperchainConfig addresses to be different. - vm.mockCall( - address(chainDeployOutput1.optimismPortalProxy), - abi.encodeCall(IOptimismPortal2.superchainConfig, ()), - abi.encode(address(1234)) - ); - vm.mockCall( - address(chainDeployOutput2.optimismPortalProxy), - abi.encodeCall(IOptimismPortal2.superchainConfig, ()), - abi.encode(address(5678)) - ); - - // Execute the migration. - _doMigration( - input, OPContractsManagerInteropMigrator.OPContractsManagerInteropMigrator_SuperchainConfigMismatch.selector - ); - } - - function test_migrate_zerosOutCannonKonaGameTypes_succeeds() public { - IOPContractsManagerInteropMigrator.MigrateInput memory input = _getDefaultInput(); - - // Grab the existing DisputeGameFactory for each chain. - IDisputeGameFactory oldDisputeGameFactory1 = - IDisputeGameFactory(payable(chainDeployOutput1.systemConfigProxy.disputeGameFactory())); - IDisputeGameFactory oldDisputeGameFactory2 = - IDisputeGameFactory(payable(chainDeployOutput2.systemConfigProxy.disputeGameFactory())); - // Ensure cannon kona games have implementations - oldDisputeGameFactory1.setImplementation(GameTypes.CANNON_KONA, IDisputeGame(address(1))); - oldDisputeGameFactory2.setImplementation(GameTypes.CANNON_KONA, IDisputeGame(address(1))); - oldDisputeGameFactory1.setImplementation(GameTypes.SUPER_CANNON_KONA, IDisputeGame(address(2))); - oldDisputeGameFactory2.setImplementation(GameTypes.SUPER_CANNON_KONA, IDisputeGame(address(2))); - - // Execute the migration. - _doMigration(input); - - // Assert that the old game implementations are now zeroed out. - _assertOldGamesZeroed(oldDisputeGameFactory1); - _assertOldGamesZeroed(oldDisputeGameFactory2); - } -} - -/// @title OPContractsManager_Deploy_Test -/// @notice Tests the `deploy` function of the `OPContractsManager` contract. -/// @dev Unlike other test suites, we intentionally do not inherit from CommonTest or Setup. This -/// is because OPContractsManager acts as a deploy script, so we start from a clean slate here -/// and work OPContractsManager's deployment into the existing test setup, instead of using -/// the existing test setup to deploy OPContractsManager. We do however inherit from -/// DeployOPChain_TestBase so we can use its setup to deploy the implementations similarly -/// to how a real deployment would happen. -contract OPContractsManager_Deploy_Test is DeployOPChain_TestBase { - using DisputeGames for *; - using stdStorage for StdStorage; - - function setUp() public override { - super.setUp(); - skipIfDevFeatureEnabled(DevFeatures.OPCM_V2); - } - - // This helper function is used to convert the input struct type defined in DeployOPChain.s.sol - // to the input struct type defined in OPContractsManager.sol. - function toOPCMDeployInput(Types.DeployOPChainInput memory _doi) - internal - returns (IOPContractsManager.DeployInput memory) - { - bytes memory startingAnchorRoot = new DeployOPChain().startingAnchorRoot(); - return IOPContractsManager.DeployInput({ - roles: IOPContractsManager.Roles({ - opChainProxyAdminOwner: _doi.opChainProxyAdminOwner, - systemConfigOwner: _doi.systemConfigOwner, - batcher: _doi.batcher, - unsafeBlockSigner: _doi.unsafeBlockSigner, - proposer: _doi.proposer, - challenger: _doi.challenger - }), - basefeeScalar: _doi.basefeeScalar, - blobBasefeeScalar: _doi.blobBaseFeeScalar, - l2ChainId: _doi.l2ChainId, - startingAnchorRoot: startingAnchorRoot, - saltMixer: _doi.saltMixer, - gasLimit: _doi.gasLimit, - disputeGameType: _doi.disputeGameType, - disputeAbsolutePrestate: _doi.disputeAbsolutePrestate, - disputeMaxGameDepth: _doi.disputeMaxGameDepth, - disputeSplitDepth: _doi.disputeSplitDepth, - disputeClockExtension: _doi.disputeClockExtension, - disputeMaxClockDuration: _doi.disputeMaxClockDuration, - useCustomGasToken: _doi.useCustomGasToken - }); - } - - function test_deploy_l2ChainIdEqualsZero_reverts() public { - IOPContractsManager.DeployInput memory input = toOPCMDeployInput(deployOPChainInput); - input.l2ChainId = 0; - - vm.expectRevert(IOPContractsManager.InvalidChainId.selector); - IOPContractsManager(opcmAddr).deploy(input); - } - - function test_deploy_l2ChainIdEqualsCurrentChainId_reverts() public { - IOPContractsManager.DeployInput memory input = toOPCMDeployInput(deployOPChainInput); - input.l2ChainId = block.chainid; - - vm.expectRevert(IOPContractsManager.InvalidChainId.selector); - IOPContractsManager(opcmAddr).deploy(input); - } - - function test_deploy_succeeds() public { - vm.expectEmit(true, true, true, false); // TODO precompute the expected `deployOutput`. - emit Deployed(deployOPChainInput.l2ChainId, address(this), bytes("")); - IOPContractsManager(opcmAddr).deploy(toOPCMDeployInput(deployOPChainInput)); - } - - /// @notice Test that deploy sets the permissioned dispute game implementation - function test_deployPermissioned_succeeds() public { - // Sanity-check setup is consistent with devFeatures flag - IOPContractsManager.Implementations memory impls = IOPContractsManager(opcmAddr).implementations(); - address pdgImpl = address(impls.permissionedDisputeGameImpl); - address fdgImpl = address(impls.faultDisputeGameImpl); - assertFalse(pdgImpl == address(0), "PDG implementation address should be non-zero"); - assertFalse(fdgImpl == address(0), "FDG implementation address should be non-zero"); - - // Run OPCM.deploy - IOPContractsManager.DeployInput memory opcmInput = toOPCMDeployInput(deployOPChainInput); - IOPContractsManager.DeployOutput memory opcmOutput = IOPContractsManager(opcmAddr).deploy(opcmInput); - - // Verify that the DisputeGameFactory has registered an implementation for the PERMISSIONED_CANNON game type - address actualPDGAddress = address(opcmOutput.disputeGameFactoryProxy.gameImpls(GameTypes.PERMISSIONED_CANNON)); - assertNotEq(actualPDGAddress, address(0), "DisputeGameFactory should have a registered PERMISSIONED_CANNON"); - assertEq(actualPDGAddress, pdgImpl, "PDG address should match"); - - // Create a game proxy to test immutable fields - Claim claim = Claim.wrap(bytes32(uint256(9876))); - uint256 l2BlockNumber = uint256(123); - IPermissionedDisputeGame pdg = IPermissionedDisputeGame( - payable( - DisputeGames.createGame( - opcmOutput.disputeGameFactoryProxy, - GameTypes.PERMISSIONED_CANNON, - opcmInput.roles.proposer, - claim, - l2BlockNumber - ) - ) - ); - - // Verify immutable fields on the game proxy - // Constructor args - assertEq(pdg.gameType().raw(), GameTypes.PERMISSIONED_CANNON.raw(), "Game type should match"); - assertEq(pdg.clockExtension().raw(), opcmInput.disputeClockExtension.raw(), "Clock extension should match"); - assertEq( - pdg.maxClockDuration().raw(), opcmInput.disputeMaxClockDuration.raw(), "Max clock duration should match" - ); - assertEq(pdg.splitDepth(), opcmInput.disputeSplitDepth, "Split depth should match"); - assertEq(pdg.maxGameDepth(), opcmInput.disputeMaxGameDepth, "Max game depth should match"); - // Clone-with-immutable-args - assertEq(pdg.gameCreator(), opcmInput.roles.proposer, "Game creator should match"); - assertEq(pdg.rootClaim().raw(), claim.raw(), "Claim should match"); - assertEq(pdg.l1Head().raw(), blockhash(block.number - 1), "L1 head should match"); - assertEq(pdg.l2BlockNumber(), l2BlockNumber, "L2 Block number should match"); - assertEq( - pdg.absolutePrestate().raw(), - opcmInput.disputeAbsolutePrestate.raw(), - "Absolute prestate should match input" - ); - assertEq(address(pdg.vm()), address(impls.mipsImpl), "VM should match MIPS implementation"); - assertEq(address(pdg.anchorStateRegistry()), address(opcmOutput.anchorStateRegistryProxy), "ASR should match"); - assertEq(address(pdg.weth()), address(opcmOutput.delayedWETHPermissionedGameProxy), "WETH should match"); - assertEq(pdg.l2ChainId(), opcmInput.l2ChainId, "L2 chain ID should match"); - // For permissioned game, check proposer and challenger - assertEq(pdg.proposer(), opcmInput.roles.proposer, "Proposer should match"); - assertEq(pdg.challenger(), opcmInput.roles.challenger, "Challenger should match"); - } -} - -/// @title OPContractsManager_Version_Test -/// @notice Tests the `version` function of the `OPContractsManager` contract. -contract OPContractsManager_Version_Test is OPContractsManager_TestInit { - function test_semver_works() public view { - assertNotEq(abi.encode(opcm.version()), abi.encode(0)); - } -} diff --git a/packages/contracts-bedrock/test/L1/OPContractsManagerContractsContainer.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManagerContractsContainer.t.sol deleted file mode 100644 index 0028b6db813..00000000000 --- a/packages/contracts-bedrock/test/L1/OPContractsManagerContractsContainer.t.sol +++ /dev/null @@ -1,90 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -// Testing -import { OPContractsManager_TestInit } from "test/L1/OPContractsManager.t.sol"; - -// Contracts -import { OPContractsManager, OPContractsManagerContractsContainer } from "src/L1/OPContractsManager.sol"; - -/// @title OPContractsManagerContractsContainer_Constructor_Test -/// @notice Tests the constructor of the `OPContractsManagerContractsContainer` contract. -contract OPContractsManagerContractsContainer_Constructor_Test is OPContractsManager_TestInit { - /// @notice Tests that the constructor succeeds when the devFeatureBitmap is in dev. - /// @param _devFeatureBitmap The devFeatureBitmap to use. - function testFuzz_constructor_devBitmapInDev_succeeds(bytes32 _devFeatureBitmap) public { - // Etch into the magic testing address. - vm.etch(address(0xbeefcafe), hex"01"); - - // Convert to proper OPCM type for construction. - OPContractsManager opcm2 = OPContractsManager(address(opcm)); - - // Should not revert. - OPContractsManagerContractsContainer container = new OPContractsManagerContractsContainer({ - _blueprints: opcm2.blueprints(), - _implementations: opcm2.implementations(), - _devFeatureBitmap: _devFeatureBitmap - }); - - // Should have the correct devFeatureBitmap. - assertEq(container.devFeatureBitmap(), _devFeatureBitmap); - } - - /// @notice Tests that the constructor reverts when the devFeatureBitmap is in prod. - /// @param _devFeatureBitmap The devFeatureBitmap to use. - function testFuzz_constructor_devBitmapInProd_reverts(bytes32 _devFeatureBitmap) public { - // Anything but zero! - _devFeatureBitmap = bytes32(bound(uint256(_devFeatureBitmap), 1, type(uint256).max)); - - // Make sure magic address has no code. - vm.etch(address(0xbeefcafe), bytes("")); - - // Convert to proper OPCM type for construction. - OPContractsManager opcm2 = OPContractsManager(address(opcm)); - - // Set the chain ID to 1. - vm.chainId(1); - - // Fetch ahead of time to avoid expectRevert applying to these functions by accident. - OPContractsManager.Blueprints memory blueprints = opcm2.blueprints(); - OPContractsManager.Implementations memory implementations = opcm2.implementations(); - - // Should revert. - vm.expectRevert( - OPContractsManagerContractsContainer.OPContractsManagerContractsContainer_DevFeatureInProd.selector - ); - OPContractsManagerContractsContainer container = new OPContractsManagerContractsContainer({ - _blueprints: blueprints, - _implementations: implementations, - _devFeatureBitmap: _devFeatureBitmap - }); - - // Constructor shouldn't have worked, foundry makes this return address(1). - assertEq(address(container), address(1)); - } - - /// @notice Tests that the constructor succeeds when the devFeatureBitmap is used on the - /// mainnet chain ID but this is actually a test environment as shown by the magic - /// address having code. - /// @param _devFeatureBitmap The devFeatureBitmap to use. - function test_constructor_devBitmapMainnetButTestEnv_succeeds(bytes32 _devFeatureBitmap) public { - // Make sure magic address has code. - vm.etch(address(0xbeefcafe), hex"01"); - - // Convert to proper OPCM type for construction. - OPContractsManager opcm2 = OPContractsManager(address(opcm)); - - // Set the chain ID to 1. - vm.chainId(1); - - // Should not revert. - OPContractsManagerContractsContainer container = new OPContractsManagerContractsContainer({ - _blueprints: opcm2.blueprints(), - _implementations: opcm2.implementations(), - _devFeatureBitmap: _devFeatureBitmap - }); - - // Should have the correct devFeatureBitmap. - assertEq(container.devFeatureBitmap(), _devFeatureBitmap); - } -} diff --git a/packages/contracts-bedrock/test/L1/OPContractsManagerStandardValidator.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManagerStandardValidator.t.sol index eb266563bce..739a10d4deb 100644 --- a/packages/contracts-bedrock/test/L1/OPContractsManagerStandardValidator.t.sol +++ b/packages/contracts-bedrock/test/L1/OPContractsManagerStandardValidator.t.sol @@ -5,22 +5,19 @@ pragma solidity 0.8.15; import { CommonTest } from "test/setup/CommonTest.sol"; import { StandardConstants } from "scripts/deploy/StandardConstants.sol"; import { DisputeGames } from "../setup/DisputeGames.sol"; + // Libraries import { GameType, Hash } from "src/dispute/lib/LibUDT.sol"; import { GameTypes, Duration, Claim } from "src/dispute/lib/Types.sol"; import { ForgeArtifacts } from "scripts/libraries/ForgeArtifacts.sol"; import { Features } from "src/libraries/Features.sol"; -import { DevFeatures } from "src/libraries/DevFeatures.sol"; import { Config } from "scripts/libraries/Config.sol"; // Interfaces -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; - import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; -import { IBigStepper } from "interfaces/dispute/IBigStepper.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; import { ISemver } from "interfaces/universal/ISemver.sol"; import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; @@ -40,11 +37,7 @@ import { IOPContractsManagerStandardValidator } from "interfaces/L1/IOPContracts import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol"; import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol"; import { IMIPS64 } from "interfaces/cannon/IMIPS64.sol"; -import { IBigStepper } from "../../interfaces/dispute/IBigStepper.sol"; -import { IDisputeGameFactory } from "../../interfaces/dispute/IDisputeGameFactory.sol"; -import { DisputeGames } from "../setup/DisputeGames.sol"; import { IStaticERC1967Proxy } from "interfaces/universal/IStaticERC1967Proxy.sol"; -import { IDelayedWETH } from "../../interfaces/dispute/IDelayedWETH.sol"; import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; @@ -115,9 +108,6 @@ contract BadVersionReturner { /// @title OPContractsManagerStandardValidator_TestInit /// @notice Base contract for `OPContractsManagerStandardValidator` tests, handles common setup. abstract contract OPContractsManagerStandardValidator_TestInit is CommonTest { - /// @notice Deploy input that was used to deploy the contracts being tested. - IOPContractsManager.DeployInput deployInput; - /// @notice The l2ChainId, either from config or from registry if fork test. uint256 l2ChainId; @@ -159,9 +149,6 @@ abstract contract OPContractsManagerStandardValidator_TestInit is CommonTest { } super.setUp(); - // Grab the deploy input for later use. - deployInput = deploy.getDeployInput(); - // Load the dgf dgf = IDisputeGameFactory(artifacts.mustGetAddress("DisputeGameFactoryProxy")); @@ -171,11 +158,7 @@ abstract contract OPContractsManagerStandardValidator_TestInit is CommonTest { // Load the PreimageOracle once, we'll need it later. preimageOracle = IPreimageOracle(artifacts.mustGetAddress("PreimageOracle")); - if (isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - standardValidator = opcmV2.opcmStandardValidator(); - } else { - standardValidator = opcm.opcmStandardValidator(); - } + standardValidator = opcmV2.opcmStandardValidator(); // Values are slightly different for fork tests vs local tests. Most we can get from // reasonable sources, challenger we need to get from live system because there's no other @@ -225,10 +208,10 @@ abstract contract OPContractsManagerStandardValidator_TestInit is CommonTest { bytes32(uint256(uint160(standardValidator.l1PAOMultisig()))) ); } else { - l2ChainId = deployInput.l2ChainId; - cannonPrestate = deployInput.disputeAbsolutePrestate; - proposer = deployInput.roles.proposer; - challenger = deployInput.roles.challenger; + l2ChainId = deploy.cfg().l2ChainID(); + cannonPrestate = Claim.wrap(bytes32(deploy.cfg().faultGameAbsolutePrestate())); + proposer = deploy.cfg().l2OutputOracleProposer(); + challenger = deploy.cfg().l2OutputOracleChallenger(); } // Deploy the BadDisputeGameFactoryReturner once. @@ -240,86 +223,75 @@ abstract contract OPContractsManagerStandardValidator_TestInit is CommonTest { // Load the FaultDisputeGame once, we'll need it later. fdgImpl = IFaultDisputeGame(address(disputeGameFactory.gameImpls(GameTypes.CANNON))); } else { - if (!isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - // Deploy a permissionless FaultDisputeGame. - IOPContractsManager.AddGameOutput memory output = addGameType(GameTypes.CANNON, cannonPrestate); - fdgImpl = output.faultDisputeGame; - - // Deploy cannon-kona - addGameType(GameTypes.CANNON_KONA, cannonKonaPrestate); - } else { - // Get the ProxyAdmin owner. - address owner = proxyAdmin.owner(); - - // Prepare the upgrade input. - IOPContractsManagerUtils.DisputeGameConfig[] memory disputeGameConfigs = - new IOPContractsManagerUtils.DisputeGameConfig[](6); - disputeGameConfigs[0] = IOPContractsManagerUtils.DisputeGameConfig({ - enabled: true, - initBond: disputeGameFactory.initBonds(GameTypes.CANNON), - gameType: GameTypes.CANNON, - gameArgs: abi.encode( - IOPContractsManagerUtils.FaultDisputeGameConfig({ absolutePrestate: cannonPrestate }) - ) - }); - disputeGameConfigs[1] = IOPContractsManagerUtils.DisputeGameConfig({ - enabled: true, - initBond: disputeGameFactory.initBonds(GameTypes.PERMISSIONED_CANNON), - gameType: GameTypes.PERMISSIONED_CANNON, - gameArgs: abi.encode( - IOPContractsManagerUtils.PermissionedDisputeGameConfig({ - absolutePrestate: cannonPrestate, - proposer: proposer, - challenger: challenger + // Get the ProxyAdmin owner. + address owner = proxyAdmin.owner(); + + // Prepare the upgrade input. + IOPContractsManagerUtils.DisputeGameConfig[] memory disputeGameConfigs = + new IOPContractsManagerUtils.DisputeGameConfig[](6); + disputeGameConfigs[0] = IOPContractsManagerUtils.DisputeGameConfig({ + enabled: true, + initBond: disputeGameFactory.initBonds(GameTypes.CANNON), + gameType: GameTypes.CANNON, + gameArgs: abi.encode(IOPContractsManagerUtils.FaultDisputeGameConfig({ absolutePrestate: cannonPrestate })) + }); + disputeGameConfigs[1] = IOPContractsManagerUtils.DisputeGameConfig({ + enabled: true, + initBond: disputeGameFactory.initBonds(GameTypes.PERMISSIONED_CANNON), + gameType: GameTypes.PERMISSIONED_CANNON, + gameArgs: abi.encode( + IOPContractsManagerUtils.PermissionedDisputeGameConfig({ + absolutePrestate: cannonPrestate, + proposer: proposer, + challenger: challenger + }) + ) + }); + disputeGameConfigs[2] = IOPContractsManagerUtils.DisputeGameConfig({ + enabled: true, + initBond: disputeGameFactory.initBonds(GameTypes.CANNON_KONA), + gameType: GameTypes.CANNON_KONA, + gameArgs: abi.encode( + IOPContractsManagerUtils.FaultDisputeGameConfig({ absolutePrestate: cannonKonaPrestate }) + ) + }); + disputeGameConfigs[3] = IOPContractsManagerUtils.DisputeGameConfig({ + enabled: false, + initBond: 0, + gameType: GameTypes.SUPER_CANNON, + gameArgs: hex"" + }); + disputeGameConfigs[4] = IOPContractsManagerUtils.DisputeGameConfig({ + enabled: false, + initBond: 0, + gameType: GameTypes.SUPER_PERMISSIONED_CANNON, + gameArgs: hex"" + }); + disputeGameConfigs[5] = IOPContractsManagerUtils.DisputeGameConfig({ + enabled: false, + initBond: 0, + gameType: GameTypes.SUPER_CANNON_KONA, + gameArgs: hex"" + }); + + // Call upgrade to all games to be enabled. + prankDelegateCall(owner); + (bool success,) = address(opcmV2).delegatecall( + abi.encodeCall( + IOPContractsManagerV2.upgrade, + ( + IOPContractsManagerV2.UpgradeInput({ + systemConfig: systemConfig, + disputeGameConfigs: disputeGameConfigs, + extraInstructions: new IOPContractsManagerUtils.ExtraInstruction[](0) }) ) - }); - disputeGameConfigs[2] = IOPContractsManagerUtils.DisputeGameConfig({ - enabled: true, - initBond: disputeGameFactory.initBonds(GameTypes.CANNON_KONA), - gameType: GameTypes.CANNON_KONA, - gameArgs: abi.encode( - IOPContractsManagerUtils.FaultDisputeGameConfig({ absolutePrestate: cannonKonaPrestate }) - ) - }); - disputeGameConfigs[3] = IOPContractsManagerUtils.DisputeGameConfig({ - enabled: false, - initBond: 0, - gameType: GameTypes.SUPER_CANNON, - gameArgs: hex"" - }); - disputeGameConfigs[4] = IOPContractsManagerUtils.DisputeGameConfig({ - enabled: false, - initBond: 0, - gameType: GameTypes.SUPER_PERMISSIONED_CANNON, - gameArgs: hex"" - }); - disputeGameConfigs[5] = IOPContractsManagerUtils.DisputeGameConfig({ - enabled: false, - initBond: 0, - gameType: GameTypes.SUPER_CANNON_KONA, - gameArgs: hex"" - }); - - // Call upgrade to all games to be enabled. - prankDelegateCall(owner); - (bool success,) = address(opcmV2).delegatecall( - abi.encodeCall( - IOPContractsManagerV2.upgrade, - ( - IOPContractsManagerV2.UpgradeInput({ - systemConfig: systemConfig, - disputeGameConfigs: disputeGameConfigs, - extraInstructions: new IOPContractsManagerUtils.ExtraInstruction[](0) - }) - ) - ) - ); - assertTrue(success, "upgrade failed"); + ) + ); + assertTrue(success, "upgrade failed"); - // Grab the FaultDisputeGame implementation. - fdgImpl = IFaultDisputeGame(address(disputeGameFactory.gameImpls(GameTypes.CANNON))); - } + // Grab the FaultDisputeGame implementation. + fdgImpl = IFaultDisputeGame(address(disputeGameFactory.gameImpls(GameTypes.CANNON))); } } @@ -373,61 +345,6 @@ abstract contract OPContractsManagerStandardValidator_TestInit is CommonTest { challenger: address(0) }); } - - function addGameType( - GameType _gameType, - Claim _prestate - ) - internal - returns (IOPContractsManager.AddGameOutput memory) - { - IOPContractsManager.AddGameInput memory input = newGameInputFactory(_gameType, _prestate); - return addGameType(input); - } - - function addGameType(IOPContractsManager.AddGameInput memory input) - internal - returns (IOPContractsManager.AddGameOutput memory) - { - IOPContractsManager.AddGameInput[] memory inputs = new IOPContractsManager.AddGameInput[](1); - inputs[0] = input; - - address owner = deployInput.roles.opChainProxyAdminOwner; - vm.startPrank(address(owner), address(owner), true); - (bool success, bytes memory rawGameOut) = - address(opcm).delegatecall(abi.encodeCall(IOPContractsManager.addGameType, (inputs))); - assertTrue(success, "addGameType failed"); - vm.stopPrank(); - - IOPContractsManager.AddGameOutput[] memory addGameOutAll = - abi.decode(rawGameOut, (IOPContractsManager.AddGameOutput[])); - return addGameOutAll[0]; - } - - function newGameInputFactory( - GameType _gameType, - Claim _prestate - ) - internal - view - returns (IOPContractsManager.AddGameInput memory) - { - return IOPContractsManager.AddGameInput({ - saltMixer: "hello", - systemConfig: systemConfig, - delayedWETH: delayedWeth, - disputeGameType: _gameType, - disputeAbsolutePrestate: _prestate, - disputeMaxGameDepth: 73, - disputeSplitDepth: 30, - disputeClockExtension: Duration.wrap(10800), - disputeMaxClockDuration: Duration.wrap(302400), - initialBond: 1 ether, - vm: IBigStepper(address(opcm.implementations().mipsImpl)), - permissioned: _gameType.raw() == GameTypes.PERMISSIONED_CANNON.raw() - || _gameType.raw() == GameTypes.SUPER_PERMISSIONED_CANNON.raw() - }); - } } /// @title OPContractsManagerStandardValidator_CoreValidation_Test @@ -1382,19 +1299,7 @@ contract OPContractsManagerStandardValidator_DelayedWETH_Test is OPContractsMana /// DelayedWETH version is invalid. function test_validate_delayedWETHInvalidVersion_succeeds() public { vm.mockCall(address(delayedWeth), abi.encodeCall(ISemver.version, ()), abi.encode("0.0.1")); - - if (isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - assertEq("PDDG-DWETH-10,PLDG-DWETH-10,CKDG-DWETH-10", _validate(true)); - } else { - // One last mess here, during local tests delayedWeth refers to the contract attached to - // the FaultDisputeGame, but during fork tests it refers to the one attached to the - // PermissionedDisputeGame. We'll just branch based on the test type. - if (isL1ForkTest()) { - assertEq("PDDG-DWETH-10", _validate(true)); - } else { - assertEq("PLDG-DWETH-10,CKDG-DWETH-10", _validate(true)); - } - } + assertEq("PDDG-DWETH-10,PLDG-DWETH-10,CKDG-DWETH-10", _validate(true)); } /// @notice Tests that the validate function successfully returns the right error when the @@ -1405,16 +1310,7 @@ contract OPContractsManagerStandardValidator_DelayedWETH_Test is OPContractsMana abi.encodeCall(IProxyAdmin.getProxyImplementation, (address(delayedWeth))), abi.encode(address(0xbad)) ); - - if (isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - assertEq("PDDG-DWETH-20,PLDG-DWETH-20,CKDG-DWETH-20", _validate(true)); - } else { - if (isL1ForkTest()) { - assertEq("PDDG-DWETH-20", _validate(true)); - } else { - assertEq("PLDG-DWETH-20,CKDG-DWETH-20", _validate(true)); - } - } + assertEq("PDDG-DWETH-20,PLDG-DWETH-20,CKDG-DWETH-20", _validate(true)); } /// @notice Tests that the validate function successfully returns the right error when the @@ -1423,48 +1319,21 @@ contract OPContractsManagerStandardValidator_DelayedWETH_Test is OPContractsMana vm.mockCall( address(delayedWeth), abi.encodeCall(IProxyAdminOwnedBase.proxyAdminOwner, ()), abi.encode(address(0xbad)) ); - - if (isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - assertEq("PDDG-DWETH-30,PLDG-DWETH-30,CKDG-DWETH-30", _validate(true)); - } else { - if (isL1ForkTest()) { - assertEq("PDDG-DWETH-30", _validate(true)); - } else { - assertEq("PLDG-DWETH-30,CKDG-DWETH-30", _validate(true)); - } - } + assertEq("PDDG-DWETH-30,PLDG-DWETH-30,CKDG-DWETH-30", _validate(true)); } /// @notice Tests that the validate function successfully returns the right error when the /// DelayedWETH delay is invalid. function test_validate_delayedWETHInvalidDelay_succeeds() public { vm.mockCall(address(delayedWeth), abi.encodeCall(IDelayedWETH.delay, ()), abi.encode(1000)); - - if (isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - assertEq("PDDG-DWETH-40,PLDG-DWETH-40,CKDG-DWETH-40", _validate(true)); - } else { - if (isL1ForkTest()) { - assertEq("PDDG-DWETH-40", _validate(true)); - } else { - assertEq("PLDG-DWETH-40,CKDG-DWETH-40", _validate(true)); - } - } + assertEq("PDDG-DWETH-40,PLDG-DWETH-40,CKDG-DWETH-40", _validate(true)); } /// @notice Tests that the validate function successfully returns the right error when the /// DelayedWETH systemConfig is invalid. function test_validate_delayedWETHInvalidSystemConfig_succeeds() public { vm.mockCall(address(delayedWeth), abi.encodeCall(IDelayedWETH.systemConfig, ()), abi.encode(address(0xbad))); - - if (isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - assertEq("PDDG-DWETH-50,PLDG-DWETH-50,CKDG-DWETH-50", _validate(true)); - } else { - if (isL1ForkTest()) { - assertEq("PDDG-DWETH-50", _validate(true)); - } else { - assertEq("PLDG-DWETH-50,CKDG-DWETH-50", _validate(true)); - } - } + assertEq("PDDG-DWETH-50,PLDG-DWETH-50,CKDG-DWETH-50", _validate(true)); } /// @notice Tests that the validate function successfully returns the right error when the @@ -1473,16 +1342,7 @@ contract OPContractsManagerStandardValidator_DelayedWETH_Test is OPContractsMana vm.mockCall( address(delayedWeth), abi.encodeCall(IProxyAdminOwnedBase.proxyAdmin, ()), abi.encode(address(0xbad)) ); - - if (isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - assertEq("PDDG-DWETH-60,PLDG-DWETH-60,CKDG-DWETH-60", _validate(true)); - } else { - if (isL1ForkTest()) { - assertEq("PDDG-DWETH-60", _validate(true)); - } else { - assertEq("PLDG-DWETH-60,CKDG-DWETH-60", _validate(true)); - } - } + assertEq("PDDG-DWETH-60,PLDG-DWETH-60,CKDG-DWETH-60", _validate(true)); } } @@ -1892,11 +1752,10 @@ abstract contract OPContractsManagerStandardValidator_SuperMode_TestInit is Comm dgf = IDisputeGameFactory(artifacts.mustGetAddress("DisputeGameFactoryProxy")); standardValidator = opcmV2.opcmStandardValidator(); - IOPContractsManager.DeployInput memory deployInput = deploy.getDeployInput(); - l2ChainId = deployInput.l2ChainId; - cannonPrestate = deployInput.disputeAbsolutePrestate; - proposer = deployInput.roles.proposer; - challenger = deployInput.roles.challenger; + l2ChainId = deploy.cfg().l2ChainID(); + cannonPrestate = Claim.wrap(bytes32(deploy.cfg().faultGameAbsolutePrestate())); + proposer = deploy.cfg().l2OutputOracleProposer(); + challenger = deploy.cfg().l2OutputOracleChallenger(); // The deploy created SUPER_PERMISSIONED_CANNON (enabled) + SUPER_CANNON_KONA (disabled). // Run an upgrade to also enable SUPER_CANNON_KONA so that full validation passes. diff --git a/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol b/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol index 2d30b345920..f30f5bd0563 100644 --- a/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol +++ b/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol @@ -28,7 +28,6 @@ import { UnknownChainId } from "src/dispute/lib/Errors.sol"; // Interfaces import { IResourceMetering } from "interfaces/L1/IResourceMetering.sol"; import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; -import { IOptimismPortalInterop } from "interfaces/L1/IOptimismPortalInterop.sol"; import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; import { IProxy } from "interfaces/universal/IProxy.sol"; @@ -162,24 +161,6 @@ abstract contract OptimismPortal2_TestInit is DisputeGameFactory_TestInit { assertFalse(optimismPortal2.finalizedWithdrawals(Hashing.hashWithdrawal(_defaultTx))); } - /// @notice Sets the supeRootsActive variable to the provided value. - /// @param _superRootsActive The value to set the superRootsActive variable to. - function setSuperRootsActive(bool _superRootsActive) public { - // Get the slot for superRootsActive. - StorageSlot memory slot = ForgeArtifacts.getSlot("OptimismPortalInterop", "superRootsActive"); - - // Load the existing storage slot value. - bytes32 existingValue = vm.load(address(optimismPortal2), bytes32(slot.slot)); - - // Inject the bool into the existing storage slot value with a bitwise OR. - // Shift the bool left by the offset of the storage slot and OR with existing value. - bytes32 newValue = - bytes32(uint256(uint8(_superRootsActive ? 1 : 0)) << slot.offset * 8 | uint256(existingValue)); - - // Store the new value at the correct slot/offset. - vm.store(address(optimismPortal2), bytes32(slot.slot), newValue); - } - /// @notice Checks if the ETHLockbox feature is enabled. /// @return bool True if the ETHLockbox feature is enabled. function isUsingLockbox() public view returns (bool) { @@ -316,7 +297,7 @@ contract OptimismPortal2_Initialize_Test is OptimismPortal2_TestInit { // Call the `initialize` function with the sender vm.prank(_sender); - IOptimismPortalInterop(payable(optimismPortal2)).initialize(systemConfig, anchorStateRegistry, ethLockbox); + optimismPortal2.initialize(systemConfig, anchorStateRegistry, ethLockbox); } /// @notice Tests that the initialize function reverts when lockbox state is invalid. @@ -344,7 +325,7 @@ contract OptimismPortal2_Initialize_Test is OptimismPortal2_TestInit { // Call the `initialize` function vm.prank(address(proxyAdmin)); - optimismPortal2.initialize(systemConfig, anchorStateRegistry); + optimismPortal2.initialize(systemConfig, anchorStateRegistry, IETHLockbox(address(0))); } /// @notice Tests that the initialize function reverts if called by a non-proxy admin or owner. @@ -366,131 +347,7 @@ contract OptimismPortal2_Initialize_Test is OptimismPortal2_TestInit { // Call the `initialize` function with the sender vm.prank(_sender); - optimismPortal2.initialize(systemConfig, anchorStateRegistry); - } -} - -/// @title OptimismPortal2_UpgradeInterop_Test -/// @notice Reusable test for the current upgrade() function in the OptimismPortal2 contract. If -/// the upgrade() function is changed, tests inside of this contract should be updated to -/// reflect the new function. If the upgrade() function is removed, remove the -/// corresponding tests but leave this contract in place so it's easy to add tests back -/// in the future. -contract OptimismPortal2_UpgradeInterop_Test is CommonTest { - function setUp() public virtual override { - super.setUp(); - skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); - } - - /// @notice Tests that the upgrade() function succeeds. - function testFuzz_upgrade_interop_succeeds(address _newAnchorStateRegistry, uint256 _balance) external { - // Prevent overflow on an upgrade context - _balance = bound(_balance, 0, type(uint256).max - address(ethLockbox).balance); - - // Get the slot for _initialized. - StorageSlot memory slot = ForgeArtifacts.getSlot("OptimismPortal2", "_initialized"); - - // Set the initialized slot to 0. - vm.store(address(optimismPortal2), bytes32(slot.slot), bytes32(0)); - - // Set the balance of the portal and get the lockbox balance before the upgrade. - deal(address(optimismPortal2), _balance); - uint256 lockboxBalanceBefore = address(ethLockbox).balance; - - // Expect the ETH to be migrated to the lockbox. - vm.expectCall(address(ethLockbox), _balance, abi.encodeCall(ethLockbox.lockETH, ())); - - // Call the upgrade function. - vm.prank(address(optimismPortal2.proxyAdmin())); - IOptimismPortalInterop(payable(optimismPortal2)).upgrade( - IAnchorStateRegistry(_newAnchorStateRegistry), IETHLockbox(ethLockbox) - ); - - // Verify that the initialized slot was updated. - bytes32 initializedSlotAfter = vm.load(address(optimismPortal2), bytes32(slot.slot)); - assertEq(initializedSlotAfter, bytes32(uint256(optimismPortal2.initVersion()))); - - // Assert the portal is properly upgraded. - assertEq(address(optimismPortal2.ethLockbox()), address(ethLockbox)); - assertEq(address(optimismPortal2.anchorStateRegistry()), _newAnchorStateRegistry); - - // Balance has not updated. - assertEq(address(optimismPortal2).balance, _balance); - assertEq(address(ethLockbox).balance, lockboxBalanceBefore); - - // Now we migrate liquidity. - vm.prank(proxyAdminOwner); - IOptimismPortalInterop(payable(optimismPortal2)).migrateLiquidity(); - - // Balance has been updated. - assertEq(address(optimismPortal2).balance, 0); - assertEq(address(ethLockbox).balance, lockboxBalanceBefore + _balance); - } - - /// @notice Tests that the upgrade() function reverts if called a second time. - function test_upgrade_upgradeTwice_reverts() external { - // Get the slot for _initialized. - StorageSlot memory slot = ForgeArtifacts.getSlot("OptimismPortal2", "_initialized"); - - // Set the initialized slot to 0. - vm.store(address(optimismPortal2), bytes32(slot.slot), bytes32(0)); - - // Trigger first upgrade. - vm.prank(address(optimismPortal2.proxyAdmin())); - IOptimismPortalInterop(payable(optimismPortal2)).upgrade( - IAnchorStateRegistry(address(0xdeadbeef)), IETHLockbox(ethLockbox) - ); - - // Try to trigger second upgrade. - vm.prank(address(optimismPortal2.proxyAdmin())); - vm.expectRevert("Initializable: contract is already initialized"); - IOptimismPortalInterop(payable(optimismPortal2)).upgrade( - IAnchorStateRegistry(address(0xdeadbeef)), IETHLockbox(ethLockbox) - ); - } - - /// @notice Tests that the upgrade() function reverts if called after initialization. - function test_upgrade_afterInitialization_reverts() external { - // Get the slot for _initialized. - StorageSlot memory slot = ForgeArtifacts.getSlot("OptimismPortal2", "_initialized"); - - // Slot value should be set to already initialized. - bytes32 initializedSlotBefore = vm.load(address(optimismPortal2), bytes32(slot.slot)); - assertEq(initializedSlotBefore, bytes32(uint256(optimismPortal2.initVersion()))); - - // AnchorStateRegistry address should be non-zero. - assertNotEq(address(optimismPortal2.anchorStateRegistry()), address(0)); - - // SystemConfig address should be non-zero. - assertNotEq(address(optimismPortal2.systemConfig()), address(0)); - - // Try to trigger upgrade(). - vm.expectRevert("Initializable: contract is already initialized"); - IOptimismPortalInterop(payable(optimismPortal2)).upgrade( - IAnchorStateRegistry(address(0xdeadbeef)), IETHLockbox(ethLockbox) - ); - } - - /// @notice Tests that the upgrade() function reverts if called by a non-proxy admin or owner. - /// @param _sender The address of the sender to test. - function testFuzz_upgrade_notProxyAdminOrProxyAdminOwner_reverts(address _sender) public { - // Prank as the not ProxyAdmin or ProxyAdmin owner. - vm.assume(_sender != address(proxyAdmin) && _sender != proxyAdminOwner); - - // Get the slot for _initialized. - StorageSlot memory slot = ForgeArtifacts.getSlot("OptimismPortal2", "_initialized"); - - // Set the initialized slot to 0. - vm.store(address(optimismPortal2), bytes32(slot.slot), bytes32(0)); - - // Expect the revert with `ProxyAdminOwnedBase_NotProxyAdminOrProxyAdminOwner` selector. - vm.expectRevert(IProxyAdminOwnedBase.ProxyAdminOwnedBase_NotProxyAdminOrProxyAdminOwner.selector); - - // Call the `upgrade` function with the sender - vm.prank(_sender); - IOptimismPortalInterop(payable(optimismPortal2)).upgrade( - IAnchorStateRegistry(address(0xdeadbeef)), IETHLockbox(ethLockbox) - ); + optimismPortal2.initialize(systemConfig, anchorStateRegistry, IETHLockbox(address(0))); } } @@ -827,7 +684,7 @@ contract OptimismPortal2_MigrateLiquidity_Test is CommonTest { vm.assume(_caller != optimismPortal2.proxyAdminOwner()); vm.expectRevert(IProxyAdminOwnedBase.ProxyAdminOwnedBase_NotProxyAdminOwner.selector); vm.prank(_caller); - IOptimismPortalInterop(payable(optimismPortal2)).migrateLiquidity(); + optimismPortal2.migrateLiquidity(); } /// @notice Tests that the liquidity migration from the portal to the lockbox succeeds. @@ -844,37 +701,35 @@ contract OptimismPortal2_MigrateLiquidity_Test is CommonTest { emit ETHMigrated(address(ethLockbox), _portalBalance); vm.prank(proxyAdminOwner); - IOptimismPortalInterop(payable(optimismPortal2)).migrateLiquidity(); + optimismPortal2.migrateLiquidity(); assertEq(address(optimismPortal2).balance, 0); assertEq(address(ethLockbox).balance, lockboxBalanceBefore + _portalBalance); } } -/// @title OptimismPortal2_MigrateToSuperRoots_Test -/// @notice Test contract for OptimismPortal2 `migrateToSuperRoots` function. -contract OptimismPortal2_MigrateToSuperRoots_Test is OptimismPortal2_TestInit { +/// @title OptimismPortal2_migrateToSharedDisputeGame_Test +/// @notice Test contract for OptimismPortal2 `migrateToSharedDisputeGame` function. +contract OptimismPortal2_migrateToSharedDisputeGame_Test is OptimismPortal2_TestInit { function setUp() public override { super.setUp(); skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); } - /// @notice Tests that `migrateToSuperRoots` reverts if the caller is not the proxy admin + /// @notice Tests that `migrateToSharedDisputeGame` reverts if the caller is not the proxy admin /// owner. - function testFuzz_migrateToSuperRoots_notProxyAdminOwner_reverts(address _caller) external { + function testFuzz_migrateToSharedDisputeGame_notProxyAdminOwner_reverts(address _caller) external { vm.assume(_caller != optimismPortal2.proxyAdminOwner()); vm.expectRevert(IProxyAdminOwnedBase.ProxyAdminOwnedBase_NotProxyAdminOwner.selector); vm.prank(_caller); - IOptimismPortalInterop(payable(optimismPortal2)).migrateToSuperRoots( - IETHLockbox(address(1)), IAnchorStateRegistry(address(1)) - ); + optimismPortal2.migrateToSharedDisputeGame(IETHLockbox(address(1)), IAnchorStateRegistry(address(1))); } - /// @notice Tests that `migrateToSuperRoots` reverts if the new registry is the same as the + /// @notice Tests that `migrateToSharedDisputeGame` reverts if the new registry is the same as the /// current one. /// @param _newLockbox The new ETHLockbox to migrate to. - function testFuzz_migrateToSuperRoots_usingSameRegistry_reverts(address _newLockbox) external { + function testFuzz_migrateToSharedDisputeGame_usingSameRegistry_reverts(address _newLockbox) external { vm.assume(_newLockbox != address(optimismPortal2.ethLockbox())); // Use the same registry as the current one. @@ -884,18 +739,21 @@ contract OptimismPortal2_MigrateToSuperRoots_Test is OptimismPortal2_TestInit { address caller = optimismPortal2.proxyAdminOwner(); // Expect the migration to revert. - vm.expectRevert(IOptimismPortalInterop.OptimismPortal_MigratingToSameRegistry.selector); + vm.expectRevert(IOptimismPortal.OptimismPortal_MigratingToSameRegistry.selector); vm.prank(caller); - IOptimismPortalInterop(payable(optimismPortal2)).migrateToSuperRoots( - IETHLockbox(_newLockbox), newAnchorStateRegistry - ); + optimismPortal2.migrateToSharedDisputeGame(IETHLockbox(_newLockbox), newAnchorStateRegistry); } - /// @notice Tests that `migrateToSuperRoots` updates the ETHLockbox contract, updates the + /// @notice Tests that `migrateToSharedDisputeGame` updates the ETHLockbox contract, updates the /// AnchorStateRegistry, and sets the superRootsActive flag to true. /// @param _newLockbox The new ETHLockbox to migrate to. /// @param _newAnchorStateRegistry The new AnchorStateRegistry to migrate to. - function testFuzz_migrateToSuperRoots_succeeds(address _newLockbox, address _newAnchorStateRegistry) external { + function testFuzz_migrateToSharedDisputeGame_succeeds( + address _newLockbox, + address _newAnchorStateRegistry + ) + external + { address oldLockbox = address(optimismPortal2.ethLockbox()); address oldAnchorStateRegistry = address(optimismPortal2.anchorStateRegistry()); vm.assume(_newLockbox != oldLockbox); @@ -905,17 +763,17 @@ contract OptimismPortal2_MigrateToSuperRoots_Test is OptimismPortal2_TestInit { emit PortalMigrated(oldLockbox, _newLockbox, oldAnchorStateRegistry, _newAnchorStateRegistry); vm.prank(optimismPortal2.proxyAdminOwner()); - IOptimismPortalInterop(payable(optimismPortal2)).migrateToSuperRoots( + optimismPortal2.migrateToSharedDisputeGame( IETHLockbox(_newLockbox), IAnchorStateRegistry(_newAnchorStateRegistry) ); assertEq(address(optimismPortal2.ethLockbox()), _newLockbox); assertEq(address(optimismPortal2.anchorStateRegistry()), _newAnchorStateRegistry); - assertTrue(IOptimismPortalInterop(payable(optimismPortal2)).superRootsActive()); + assertTrue(systemConfig.isFeatureEnabled(Features.INTEROP)); } - /// @notice Tests that `migrateToSuperRoots` reverts when the system is paused. - function test_migrateToSuperRoots_paused_reverts() external { + /// @notice Tests that `migrateToSharedDisputeGame` reverts when the system is paused. + function test_migrateToSharedDisputeGame_paused_reverts() external { vm.startPrank(optimismPortal2.guardian()); systemConfig.superchainConfig().pause(address(0)); vm.stopPrank(); @@ -923,15 +781,19 @@ contract OptimismPortal2_MigrateToSuperRoots_Test is OptimismPortal2_TestInit { address caller = optimismPortal2.proxyAdminOwner(); vm.expectRevert(IOptimismPortal.OptimismPortal_CallPaused.selector); vm.prank(caller); - IOptimismPortalInterop(payable(optimismPortal2)).migrateToSuperRoots( - IETHLockbox(address(1)), IAnchorStateRegistry(address(1)) - ); + optimismPortal2.migrateToSharedDisputeGame(IETHLockbox(address(1)), IAnchorStateRegistry(address(1))); } } /// @title OptimismPortal2_ProveWithdrawalTransaction_Test /// @notice Test contract for OptimismPortal2 `proveWithdrawalTransaction` function. contract OptimismPortal2_ProveWithdrawalTransaction_Test is OptimismPortal2_TestInit { + /// @notice Enables super root behavior on the portal for testing. + function _enableSuperRoots() internal { + // OptimismPortal2 uses stateless GameTypes.isSuperGame() check. + vm.mockCall(address(game), abi.encodeCall(game.gameType, ()), abi.encode(GameTypes.SUPER_CANNON_KONA)); + } + /// @notice Tests that `proveWithdrawalTransaction` reverts when paused. function test_proveWithdrawalTransaction_paused_reverts() external { vm.startPrank(optimismPortal2.guardian()); @@ -1195,13 +1057,12 @@ contract OptimismPortal2_ProveWithdrawalTransaction_Test is OptimismPortal2_Test }); } - /// @notice Tests that `proveWithdrawalTransaction` reverts when superRootsActive is true + /// @notice Tests that `proveWithdrawalTransaction` reverts when super roots are active /// and the game's rootClaimByChainId reverts with UnknownChainId. function test_proveWithdrawalTransaction_superRootsVersionBadChainId_reverts() external { skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); - // Enable super roots. - setSuperRootsActive(true); + _enableSuperRoots(); // Mock rootClaimByChainId to revert with UnknownChainId. vm.mockCallRevert( @@ -1212,7 +1073,7 @@ contract OptimismPortal2_ProveWithdrawalTransaction_Test is OptimismPortal2_Test // Should revert because chainId not found in super root. vm.expectRevert(UnknownChainId.selector); - IOptimismPortalInterop(payable(optimismPortal2)).proveWithdrawalTransaction({ + optimismPortal2.proveWithdrawalTransaction({ _tx: _defaultTx, _disputeGameIndex: _proposedGameIndex, _outputRootProof: _outputRootProof, @@ -1220,13 +1081,12 @@ contract OptimismPortal2_ProveWithdrawalTransaction_Test is OptimismPortal2_Test }); } - /// @notice Tests that `proveWithdrawalTransaction` reverts when superRootsActive is true + /// @notice Tests that `proveWithdrawalTransaction` reverts when super roots are active /// and the output root proof doesn't match the game's rootClaimByChainId. function test_proveWithdrawalTransaction_superRootsVersionBadOutputRootProof_reverts() external { skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); - // Enable super roots. - setSuperRootsActive(true); + _enableSuperRoots(); // Mock rootClaimByChainId to return a different output root (wrong one). bytes32 wrongOutputRoot = keccak256(abi.encode(_outputRoot)); @@ -1237,8 +1097,8 @@ contract OptimismPortal2_ProveWithdrawalTransaction_Test is OptimismPortal2_Test ); // Should revert because the output root proof doesn't match. - vm.expectRevert(IOptimismPortalInterop.OptimismPortal_InvalidOutputRootProof.selector); - IOptimismPortalInterop(payable(optimismPortal2)).proveWithdrawalTransaction({ + vm.expectRevert(IOptimismPortal.OptimismPortal_InvalidOutputRootProof.selector); + optimismPortal2.proveWithdrawalTransaction({ _tx: _defaultTx, _disputeGameIndex: _proposedGameIndex, _outputRootProof: _outputRootProof, @@ -1246,13 +1106,12 @@ contract OptimismPortal2_ProveWithdrawalTransaction_Test is OptimismPortal2_Test }); } - /// @notice Tests that `proveWithdrawalTransaction` succeeds when superRootsActive is true + /// @notice Tests that `proveWithdrawalTransaction` succeeds when super roots are active /// and all parameters are valid. function test_proveWithdrawalTransaction_superRootsVersion_succeeds() external { skipIfDevFeatureDisabled(DevFeatures.OPTIMISM_PORTAL_INTEROP); - // Enable super roots. - setSuperRootsActive(true); + _enableSuperRoots(); // Mock rootClaimByChainId to return the correct output root. vm.mockCall( @@ -1262,7 +1121,7 @@ contract OptimismPortal2_ProveWithdrawalTransaction_Test is OptimismPortal2_Test ); // Should succeed. - IOptimismPortalInterop(payable(optimismPortal2)).proveWithdrawalTransaction({ + optimismPortal2.proveWithdrawalTransaction({ _tx: _defaultTx, _disputeGameIndex: _proposedGameIndex, _outputRootProof: _outputRootProof, diff --git a/packages/contracts-bedrock/test/L1/SystemConfig.t.sol b/packages/contracts-bedrock/test/L1/SystemConfig.t.sol index 1ee10710236..ed84b847e72 100644 --- a/packages/contracts-bedrock/test/L1/SystemConfig.t.sol +++ b/packages/contracts-bedrock/test/L1/SystemConfig.t.sol @@ -10,8 +10,8 @@ import { ForgeArtifacts, StorageSlot } from "scripts/libraries/ForgeArtifacts.so // Libraries import { Constants } from "src/libraries/Constants.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; -import { Features } from "src/libraries/Features.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; +import { Features } from "src/libraries/Features.sol"; // Interfaces import { IResourceMetering } from "interfaces/L1/IResourceMetering.sol"; @@ -101,6 +101,16 @@ contract SystemConfig_Initialize_Test is SystemConfig_TestInit { skipIfForkTest("SystemConfig_Initialize_Test: cannot test initialization on forked network"); } + function test_initialize_interopFlag_succeeds() external view { + if (isDevFeatureEnabled(DevFeatures.OPTIMISM_PORTAL_INTEROP)) { + /// if devfeature flag is on, check in system config is on + assertTrue(systemConfig.isFeatureEnabled(Features.INTEROP)); + } else { + /// if dev feature flag is off, check system config is off + assertFalse(systemConfig.isFeatureEnabled(Features.INTEROP)); + } + } + /// @notice Tests that initialization sets the correct values. function test_initialize_succeeds() external view { assertEq(systemConfig.owner(), owner); @@ -884,6 +894,12 @@ contract SystemConfig_IsFeatureEnabled_Test is SystemConfig_TestInit { systemConfig.setFeature(Features.CUSTOM_GAS_TOKEN, false); } + // Normalize INTEROP to avoid environment-dependent state + if (systemConfig.isFeatureEnabled(Features.INTEROP)) { + vm.prank(address(systemConfig.proxyAdmin())); + systemConfig.setFeature(Features.INTEROP, false); + } + assertFalse(systemConfig.isFeatureEnabled(_feature)); } @@ -989,9 +1005,7 @@ contract SystemConfig_IsCustomGasToken_Test is SystemConfig_TestInit { contract SystemConfig_LastUsedOPCM_Test is SystemConfig_TestInit { /// @notice Tests that `lastUsedOPCM` returns the correct OPCM V2 address and that /// `lastUsedOPCMVersion` matches the OPCM V2 version. - function test_lastUsedOPCM_opcmV2_succeeds() external { - skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); - + function test_lastUsedOPCM_opcmV2_succeeds() external view { // Verify that the lastUsedOPCM address matches the deployed OPCM V2 address assertEq(systemConfig.lastUsedOPCM(), address(opcmV2)); diff --git a/packages/contracts-bedrock/test/L1/opcm/OPContractsManagerContainer.t.sol b/packages/contracts-bedrock/test/L1/opcm/OPContractsManagerContainer.t.sol index 6ce881b6171..2cfe2e9f407 100644 --- a/packages/contracts-bedrock/test/L1/opcm/OPContractsManagerContainer.t.sol +++ b/packages/contracts-bedrock/test/L1/opcm/OPContractsManagerContainer.t.sol @@ -30,7 +30,6 @@ contract OPContractsManagerContainer_TestInit is Test { protocolVersionsImpl: makeAddr("protocolVersionsImpl"), l1ERC721BridgeImpl: makeAddr("l1ERC721BridgeImpl"), optimismPortalImpl: makeAddr("optimismPortalImpl"), - optimismPortalInteropImpl: makeAddr("optimismPortalInteropImpl"), ethLockboxImpl: makeAddr("ethLockboxImpl"), systemConfigImpl: makeAddr("systemConfigImpl"), optimismMintableERC20FactoryImpl: makeAddr("optimismMintableERC20FactoryImpl"), diff --git a/packages/contracts-bedrock/test/L1/opcm/OPContractsManagerUtils.t.sol b/packages/contracts-bedrock/test/L1/opcm/OPContractsManagerUtils.t.sol index c725605e978..c8bc625f148 100644 --- a/packages/contracts-bedrock/test/L1/opcm/OPContractsManagerUtils.t.sol +++ b/packages/contracts-bedrock/test/L1/opcm/OPContractsManagerUtils.t.sol @@ -105,7 +105,6 @@ contract OPContractsManagerUtils_TestInit is Test { protocolVersionsImpl: makeAddr("protocolVersionsImpl"), l1ERC721BridgeImpl: makeAddr("l1ERC721BridgeImpl"), optimismPortalImpl: makeAddr("optimismPortalImpl"), - optimismPortalInteropImpl: makeAddr("optimismPortalInteropImpl"), ethLockboxImpl: makeAddr("ethLockboxImpl"), systemConfigImpl: makeAddr("systemConfigImpl"), optimismMintableERC20FactoryImpl: makeAddr("optimismMintableERC20FactoryImpl"), diff --git a/packages/contracts-bedrock/test/L1/opcm/OPContractsManagerV2.t.sol b/packages/contracts-bedrock/test/L1/opcm/OPContractsManagerV2.t.sol index f0eaf39ec05..e805a06652a 100644 --- a/packages/contracts-bedrock/test/L1/opcm/OPContractsManagerV2.t.sol +++ b/packages/contracts-bedrock/test/L1/opcm/OPContractsManagerV2.t.sol @@ -13,9 +13,9 @@ import { Config } from "scripts/libraries/Config.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; import { Claim, Hash } from "src/dispute/lib/LibUDT.sol"; import { GameType, GameTypes, Proposal } from "src/dispute/lib/Types.sol"; +import { Constants } from "src/libraries/Constants.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; import { Features } from "src/libraries/Features.sol"; -import { Constants } from "src/libraries/Constants.sol"; // Interfaces import { IResourceMetering } from "interfaces/L1/IResourceMetering.sol"; @@ -29,7 +29,6 @@ import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManager import { IOPContractsManagerContainer } from "interfaces/L1/opcm/IOPContractsManagerContainer.sol"; import { IOPContractsManagerMigrator } from "interfaces/L1/opcm/IOPContractsManagerMigrator.sol"; import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol"; -import { IOptimismPortalInterop } from "interfaces/L1/IOptimismPortalInterop.sol"; import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; import { IETHLockbox } from "interfaces/L1/IETHLockbox.sol"; @@ -52,7 +51,6 @@ contract OPContractsManagerV2_TestInit is CommonTest { /// @notice Sets up the test suite. function setUp() public virtual override { super.setUp(); - skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); } /// @notice Helper function that runs an OPCM V2 deploy, asserts that the deploy was successful, @@ -501,8 +499,6 @@ contract OPContractsManagerV2_Upgrade_Test is OPContractsManagerV2_Upgrade_TestI /// @notice Tests that the upgrade function succeeds when executed normally. function test_upgrade_succeeds() public { - skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); - // Run the upgrade test and checks runCurrentUpgradeV2(chainPAO); } @@ -510,8 +506,6 @@ contract OPContractsManagerV2_Upgrade_Test is OPContractsManagerV2_Upgrade_TestI /// @notice Tests that calling upgrade twice does not revert, ensuring the upgrade function /// has no one-time-only state transitions that would block a subsequent upgrade call. function test_upgrade_calledTwice_succeeds() public { - skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); - runCurrentUpgradeV2(chainPAO); runCurrentUpgradeV2(chainPAO); } @@ -754,8 +748,6 @@ contract OPContractsManagerV2_Upgrade_Test is OPContractsManagerV2_Upgrade_TestI /// @notice Tests that the upgrade flow can update the Cannon and Permissioned prestate. function test_upgrade_updatePrestate_succeeds() public { - skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); - // Run baseline upgrade and capture the current prestates. runCurrentUpgradeV2(chainPAO); assertEq( @@ -838,8 +830,6 @@ contract OPContractsManagerV2_Upgrade_Test is OPContractsManagerV2_Upgrade_TestI /// even when the SuperchainConfig has the system globally paused. This is critical /// because upgrades may be needed during incident response when the system is paused. function test_upgrade_whenPaused_succeeds() public { - skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); - // First, pause the system globally using the guardian. address guardian = superchainConfig.guardian(); vm.prank(guardian); @@ -1387,11 +1377,7 @@ contract OPContractsManagerV2_IsPermittedUpgradeSequence_Test is OPContractsMana address oldOPCM = makeAddr("oldOPCM"); // Mock the current OPCM version to be 7.0.0 (below threshold). - vm.mockCall( - address(opcmV2), - abi.encodeCall(IOPContractsManagerV2.version, ()), - abi.encode(Constants.OPCM_V2_MIN_VERSION) - ); + vm.mockCall(address(opcmV2), abi.encodeCall(IOPContractsManagerV2.version, ()), abi.encode("7.0.0")); // Mock lastUsedOPCM to return the old OPCM address. vm.mockCall(address(systemConfig), abi.encodeCall(ISystemConfig.lastUsedOPCM, ()), abi.encode(oldOPCM)); @@ -2054,16 +2040,13 @@ contract OPContractsManagerV2_Migrate_Test is OPContractsManagerV2_TestInit { assertTrue(newLockbox.authorizedPortals(portal1), "ETHLockbox does not have portal 1 authorized"); assertTrue(newLockbox.authorizedPortals(portal2), "ETHLockbox does not have portal 2 authorized"); - // Check that superRootsActive is true on both portals. + // Check that the INTEROP feature is enabled on both SystemConfigs. assertTrue( - IOptimismPortalInterop(payable(address(portal1))).superRootsActive(), - "Portal 1 superRootsActive should be true" + chainContracts1.systemConfig.isFeatureEnabled(Features.INTEROP), "Chain 1 INTEROP feature should be enabled" ); assertTrue( - IOptimismPortalInterop(payable(address(portal2))).superRootsActive(), - "Portal 2 superRootsActive should be true" + chainContracts2.systemConfig.isFeatureEnabled(Features.INTEROP), "Chain 2 INTEROP feature should be enabled" ); - // Check that the ETH_LOCKBOX feature is enabled on both SystemConfigs. assertTrue( chainContracts1.systemConfig.isFeatureEnabled(Features.ETH_LOCKBOX), @@ -2100,6 +2083,11 @@ contract OPContractsManagerV2_Migrate_Test is OPContractsManagerV2_TestInit { /// @param _owner2 The owner address for the second chain's ProxyAdmin. function testFuzz_migrate_mismatchedProxyAdminOwners_reverts(address _owner1, address _owner2) public { vm.assume(_owner1 != _owner2); + // Exclude the OPCM address itself: when the pranked delegate-call address equals + // address(opcmV2), the _onlyDelegateCall guard reverts before the owner check, + // producing a different revert selector than this test expects. + vm.assume(_owner1 != address(opcmV2)); + vm.assume(_owner2 != address(opcmV2)); assumeNotPrecompile(_owner1); assumeNotPrecompile(_owner2); assumeNotForgeAddress(_owner1); diff --git a/packages/contracts-bedrock/test/L2/L2DevFeatureFlags.t.sol b/packages/contracts-bedrock/test/L2/L2DevFeatureFlags.t.sol index bd91616d734..88a3248148c 100644 --- a/packages/contracts-bedrock/test/L2/L2DevFeatureFlags.t.sol +++ b/packages/contracts-bedrock/test/L2/L2DevFeatureFlags.t.sol @@ -85,7 +85,7 @@ contract L2DevFeatureFlags_IsDevFeatureEnabled_Test is L2DevFeatureFlags_TestIni } /// @notice Tests that `isDevFeatureEnabled` works correctly with the known OPTIMISM_PORTAL_INTEROP feature. - function test_isDevFeatureEnabled_optimismPortalInterop_succeeds() public { + function test_isDevFeatureEnabled_interop_succeeds() public { vm.prank(Constants.DEPOSITOR_ACCOUNT); l2DevFeatureFlags.setDevFeatureBitmap(DevFeatures.OPTIMISM_PORTAL_INTEROP); @@ -102,6 +102,5 @@ contract L2DevFeatureFlags_IsDevFeatureEnabled_Test is L2DevFeatureFlags_TestIni assertTrue(l2DevFeatureFlags.isDevFeatureEnabled(DevFeatures.OPTIMISM_PORTAL_INTEROP)); assertTrue(l2DevFeatureFlags.isDevFeatureEnabled(DevFeatures.CANNON_KONA)); - assertFalse(l2DevFeatureFlags.isDevFeatureEnabled(DevFeatures.OPCM_V2)); } } diff --git a/packages/contracts-bedrock/test/kontrol/scripts/make-summary-deployment.sh b/packages/contracts-bedrock/test/kontrol/scripts/make-summary-deployment.sh index 8a7646a0b46..69ea3950df3 100755 --- a/packages/contracts-bedrock/test/kontrol/scripts/make-summary-deployment.sh +++ b/packages/contracts-bedrock/test/kontrol/scripts/make-summary-deployment.sh @@ -55,8 +55,8 @@ fi # Sender just needs to be anything but the default sender (0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38) # Otherwise state changes inside of Deploy.s.sol get stored in the state diff under the default script address (0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496) # Conflicts with other stuff that happens inside of Kontrol and leads to errors that are hard to debug -DEPLOY_CONFIG_PATH=deploy-config/hardhat.json \ - DEPLOYMENT_OUTFILE="$CONTRACT_NAMES" \ +DEPLOYMENT_OUTFILE="$CONTRACT_NAMES" \ +KONTROL_CONTEXT=true \ forge script --sender 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -vvv scripts/deploy/Deploy.s.sol:Deploy --sig runWithStateDiff echo "Created state diff json" diff --git a/packages/contracts-bedrock/test/mocks/TestERC1271Wallet.sol b/packages/contracts-bedrock/test/mocks/TestERC1271Wallet.sol deleted file mode 100644 index 6e2ef47f67e..00000000000 --- a/packages/contracts-bedrock/test/mocks/TestERC1271Wallet.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; -import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol"; -import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; - -/// @notice Simple ERC1271 wallet that can be used to test the ERC1271 signature checker. -/// @notice https://github.com/OpenZeppelin/openzeppelin-contracts/ -/// blob/master/contracts/mocks/ERC1271WalletMock.sol -contract TestERC1271Wallet is Ownable, IERC1271 { - constructor(address originalOwner) { - transferOwnership(originalOwner); - } - - function isValidSignature( - bytes32 _hash, - bytes memory _signature - ) - public - view - override - returns (bytes4 magicValue_) - { - return ECDSA.recover(_hash, _signature) == owner() ? this.isValidSignature.selector : bytes4(0); - } -} diff --git a/packages/contracts-bedrock/test/opcm/DeployImplementations.t.sol b/packages/contracts-bedrock/test/opcm/DeployImplementations.t.sol index 3696f339d27..521be152f1e 100644 --- a/packages/contracts-bedrock/test/opcm/DeployImplementations.t.sol +++ b/packages/contracts-bedrock/test/opcm/DeployImplementations.t.sol @@ -167,7 +167,7 @@ contract DeployImplementations_Test is Test, FeatureFlags { assertEq(address(output1.mipsSingleton), address(output2.mipsSingleton), "900"); assertEq(address(output1.disputeGameFactoryImpl), address(output2.disputeGameFactoryImpl), "1000"); assertEq(address(output1.anchorStateRegistryImpl), address(output2.anchorStateRegistryImpl), "1100"); - assertEq(address(output1.opcm), address(output2.opcm), "1200"); + assertEq(address(output1.opcmV2), address(output2.opcmV2), "1200"); assertEq(address(output1.ethLockboxImpl), address(output2.ethLockboxImpl), "1300"); assertEq(address(output1.faultDisputeGameImpl), address(output2.faultDisputeGameImpl), "1400"); assertEq(address(output1.permissionedDisputeGameImpl), address(output2.permissionedDisputeGameImpl), "1500"); @@ -248,9 +248,6 @@ contract DeployImplementations_Test is Test, FeatureFlags { DeployImplementations.Output memory output = deployImplementations.run(input); - // Check which OPCM version is deployed - bool opcmV2Enabled = DevFeatures.isDevFeatureEnabled(_devFeatureBitmap, DevFeatures.OPCM_V2); - // Basic assertions assertNotEq(address(output.anchorStateRegistryImpl), address(0), "100"); assertNotEq(address(output.delayedWETHImpl), address(0), "200"); @@ -261,25 +258,9 @@ contract DeployImplementations_Test is Test, FeatureFlags { assertNotEq(address(output.l1StandardBridgeImpl), address(0), "600"); assertNotEq(address(output.mipsSingleton), address(0), "700"); - // OPCM version-specific assertions - if (opcmV2Enabled) { - assertNotEq(address(output.opcmV2), address(0), "800"); - assertNotEq(address(output.opcmContainer), address(0), "900"); - assertNotEq(address(output.opcmStandardValidator), address(0), "1000"); - // V1 contracts should be null when V2 is enabled - assertEq(address(output.opcm), address(0), "800-v1"); - assertEq(address(output.opcmContractsContainer), address(0), "900-v1"); - assertEq(address(output.opcmDeployer), address(0), "1000-v1"); - assertEq(address(output.opcmGameTypeAdder), address(0), "1100-v1"); - } else { - assertNotEq(address(output.opcm), address(0), "800"); - assertNotEq(address(output.opcmContractsContainer), address(0), "900"); - assertNotEq(address(output.opcmDeployer), address(0), "1000"); - assertNotEq(address(output.opcmGameTypeAdder), address(0), "1100"); - // V2 contracts should be null when V1 is enabled - assertEq(address(output.opcmV2), address(0), "800-v2"); - assertEq(address(output.opcmContainer), address(0), "900-v2"); - } + assertNotEq(address(output.opcmV2), address(0), "800"); + assertNotEq(address(output.opcmContainer), address(0), "900"); + assertNotEq(address(output.opcmStandardValidator), address(0), "1000"); assertNotEq(address(output.faultDisputeGameImpl), address(0), "V2 should be deployed when enabled"); assertNotEq(address(output.permissionedDisputeGameImpl), address(0), "V2 should be deployed when enabled"); @@ -375,25 +356,9 @@ contract DeployImplementations_Test is Test, FeatureFlags { assertNotEq(address(output.l1StandardBridgeImpl).code, empty, "1800"); assertNotEq(address(output.mipsSingleton).code, empty, "1900"); - // OPCM version-specific code assertions - if (opcmV2Enabled) { - assertNotEq(address(output.opcmV2).code, empty, "2000"); - assertNotEq(address(output.opcmContainer).code, empty, "2100"); - assertNotEq(address(output.opcmStandardValidator).code, empty, "2200"); - // V1 contracts should be empty when V2 is enabled - assertEq(address(output.opcm).code, empty, "2000-v1"); - assertEq(address(output.opcmContractsContainer).code, empty, "2100-v1"); - assertEq(address(output.opcmDeployer).code, empty, "2200-v1"); - assertEq(address(output.opcmGameTypeAdder).code, empty, "2300-v1"); - } else { - assertNotEq(address(output.opcm).code, empty, "2000"); - assertNotEq(address(output.opcmContractsContainer).code, empty, "2100"); - assertNotEq(address(output.opcmDeployer).code, empty, "2200"); - assertNotEq(address(output.opcmGameTypeAdder).code, empty, "2300"); - // V2 contracts should be empty when V1 is enabled - assertEq(address(output.opcmV2).code, empty, "2000-v2"); - assertEq(address(output.opcmContainer).code, empty, "2100-v2"); - } + assertNotEq(address(output.opcmV2).code, empty, "2000"); + assertNotEq(address(output.opcmContainer).code, empty, "2100"); + assertNotEq(address(output.opcmStandardValidator).code, empty, "2200"); assertNotEq(address(output.faultDisputeGameImpl).code, empty, "V2 FDG should have code when enabled"); assertNotEq(address(output.permissionedDisputeGameImpl).code, empty, "V2 PDG should have code when enabled"); diff --git a/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol b/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol index 2e846db55ba..78622cc284e 100644 --- a/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol +++ b/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.15; // Testing import { Test } from "test/setup/Test.sol"; import { FeatureFlags } from "test/setup/FeatureFlags.sol"; -import { DevFeatures } from "src/libraries/DevFeatures.sol"; // Scripts import { DeploySuperchain } from "scripts/deploy/DeploySuperchain.s.sol"; @@ -15,9 +14,11 @@ import { Types } from "scripts/libraries/Types.sol"; // Libraries import { Features } from "src/libraries/Features.sol"; +import { DevFeatures } from "src/libraries/DevFeatures.sol"; // Interfaces -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; +import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; +import { IOPContractsManagerContainer } from "interfaces/L1/opcm/IOPContractsManagerContainer.sol"; import { Claim, Duration, GameType, GameTypes } from "src/dispute/lib/Types.sol"; import { IPermissionedDisputeGame } from "interfaces/dispute/IPermissionedDisputeGame.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; @@ -109,9 +110,7 @@ contract DeployOPChain_TestBase is Test, FeatureFlags { devFeatureBitmap: devFeatureBitmap }) ); - // Select OPCM v1 or v2 based on feature flag - opcmAddr = isDevFeatureEnabled(DevFeatures.OPCM_V2) ? address(dio.opcmV2) : address(dio.opcm); - vm.label(address(dio.opcm), "opcm"); + opcmAddr = address(dio.opcmV2); vm.label(address(dio.opcmV2), "opcmV2"); // Set superchainConfig from deployment @@ -172,19 +171,12 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { DeployOPChain.Output memory doo = deployOPChain.run(deployOPChainInput); - // Skip init bond checks for OPCM v2 (bonds are set during deployment, not zero) - if (!isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - // Verify that the initial bonds are zero for OPCM v1. - assertEq(doo.disputeGameFactoryProxy.initBonds(GameTypes.CANNON), 0, "2700"); - assertEq(doo.disputeGameFactoryProxy.initBonds(GameTypes.PERMISSIONED_CANNON), 0, "2800"); - } - // Check dispute game deployments // Validate permissionedDisputeGame (PDG) address GameType permGameType = isDevFeatureEnabled(DevFeatures.SUPER_ROOT_GAMES_MIGRATION) ? GameTypes.SUPER_PERMISSIONED_CANNON : GameTypes.PERMISSIONED_CANNON; - IOPContractsManager.Implementations memory impls = IOPContractsManager(opcmAddr).implementations(); + IOPContractsManagerContainer.Implementations memory impls = IOPContractsManagerV2(opcmAddr).implementations(); address expectedPDGAddress = isDevFeatureEnabled(DevFeatures.SUPER_ROOT_GAMES_MIGRATION) ? impls.superPermissionedDisputeGameImpl : impls.permissionedDisputeGameImpl; @@ -192,19 +184,6 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { assertNotEq(actualPDGAddress, address(0), "PDG address should be non-zero"); assertEq(actualPDGAddress, expectedPDGAddress, "PDG address should match expected address"); - // Skip PDG getter checks for OPCM v2 (game args are passed at creation time) - if (!isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - // Check PDG getters - IPermissionedDisputeGame pdg = IPermissionedDisputeGame(actualPDGAddress); - bytes32 expectedPrestate = bytes32(0); - assertEq(pdg.l2BlockNumber(), 0, "3000"); - assertEq(Claim.unwrap(pdg.absolutePrestate()), expectedPrestate, "3100"); - assertEq(Duration.unwrap(pdg.clockExtension()), 10800, "3200"); - assertEq(Duration.unwrap(pdg.maxClockDuration()), 302400, "3300"); - assertEq(pdg.splitDepth(), 30, "3400"); - assertEq(pdg.maxGameDepth(), 73, "3500"); - } - // Verify custom gas token feature is set as seeded assertEq( doo.systemConfigProxy.isCustomGasToken(), @@ -251,16 +230,12 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { } function test_run_cannonGameType_reverts() public { - skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); - deployOPChainInput.disputeGameType = GameTypes.CANNON; vm.expectRevert("DeployOPChain: only PERMISSIONED_CANNON game type is supported for initial deployment"); deployOPChain.run(deployOPChainInput); } function test_run_cannonKonaGameType_reverts() public { - skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); - deployOPChainInput.disputeGameType = GameTypes.CANNON_KONA; vm.expectRevert("DeployOPChain: only PERMISSIONED_CANNON game type is supported for initial deployment"); deployOPChain.run(deployOPChainInput); @@ -269,8 +244,6 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { /// @notice Tests that faultDisputeGame is set to address(0) and permissionedDisputeGame is set to the correct /// implementation for GameTypes.PERMISSIONED_CANNON. function test_run_faultDisputeGamePermissionedCannon_succeeds() public { - skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); - deployOPChainInput.disputeGameType = GameTypes.PERMISSIONED_CANNON; DeployOPChain.Output memory doo = deployOPChain.run(deployOPChainInput); @@ -317,34 +290,31 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { "superchainConfig mismatch" ); - // OPCM v2 specific assertions - if (isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - bool isSuperRoot = isDevFeatureEnabled(DevFeatures.SUPER_ROOT_GAMES_MIGRATION); - GameType permType = isSuperRoot ? GameTypes.SUPER_PERMISSIONED_CANNON : GameTypes.PERMISSIONED_CANNON; - GameType konaType = isSuperRoot ? GameTypes.SUPER_CANNON_KONA : GameTypes.CANNON_KONA; - - // Permissioned game must always be enabled with DEFAULT_INIT_BOND init bond - assertEq(doo.disputeGameFactoryProxy.initBonds(permType), deployOPChain.DEFAULT_INIT_BOND()); - assertNotEq(address(doo.disputeGameFactoryProxy.gameImpls(permType)), address(0)); - - // CANNON must be disabled for initial deployment (not deployed for super root path) - if (!isSuperRoot) { - assertEq(doo.disputeGameFactoryProxy.initBonds(GameTypes.CANNON), 0, "CANNON init bond should be 0"); - assertEq( - address(doo.disputeGameFactoryProxy.gameImpls(GameTypes.CANNON)), - address(0), - "CANNON impl should be the zero address" - ); - } - - // Kona must be disabled for initial deployment - assertEq(doo.disputeGameFactoryProxy.initBonds(konaType), 0, "CANNON_KONA init bond should be 0"); + bool isSuperRoot = isDevFeatureEnabled(DevFeatures.SUPER_ROOT_GAMES_MIGRATION); + GameType permType = isSuperRoot ? GameTypes.SUPER_PERMISSIONED_CANNON : GameTypes.PERMISSIONED_CANNON; + GameType konaType = isSuperRoot ? GameTypes.SUPER_CANNON_KONA : GameTypes.CANNON_KONA; + + // Permissioned game must always be enabled with DEFAULT_INIT_BOND init bond + assertEq(doo.disputeGameFactoryProxy.initBonds(permType), deployOPChain.DEFAULT_INIT_BOND()); + assertNotEq(address(doo.disputeGameFactoryProxy.gameImpls(permType)), address(0)); + + // CANNON must be disabled for initial deployment (not deployed for super root path) + if (!isSuperRoot) { + assertEq(doo.disputeGameFactoryProxy.initBonds(GameTypes.CANNON), 0, "CANNON init bond should be 0"); assertEq( - address(doo.disputeGameFactoryProxy.gameImpls(konaType)), + address(doo.disputeGameFactoryProxy.gameImpls(GameTypes.CANNON)), address(0), - "CANNON_KONA impl should be the zero address" + "CANNON impl should be the zero address" ); } + + // Kona must be disabled for initial deployment + assertEq(doo.disputeGameFactoryProxy.initBonds(konaType), 0, "CANNON_KONA init bond should be 0"); + assertEq( + address(doo.disputeGameFactoryProxy.gameImpls(konaType)), + address(0), + "CANNON_KONA impl should be the zero address" + ); } } diff --git a/packages/contracts-bedrock/test/opcm/InteropMigration.t.sol b/packages/contracts-bedrock/test/opcm/InteropMigration.t.sol index ac909974eb2..8a0d39eccb7 100644 --- a/packages/contracts-bedrock/test/opcm/InteropMigration.t.sol +++ b/packages/contracts-bedrock/test/opcm/InteropMigration.t.sol @@ -8,10 +8,9 @@ import { Test } from "test/setup/Test.sol"; import { InteropMigrationInput, InteropMigration, InteropMigrationOutput } from "scripts/deploy/InteropMigration.s.sol"; // Libraries -import { Claim, Duration, Hash, GameType, Proposal } from "src/dispute/lib/Types.sol"; +import { Hash, GameType, Proposal } from "src/dispute/lib/Types.sol"; // Interfaces -import { IOPContractsManagerInteropMigrator, IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManagerMigrator } from "interfaces/L1/opcm/IOPContractsManagerMigrator.sol"; import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; @@ -46,40 +45,6 @@ contract InteropMigrationInput_Test is Test { assertEq(input.opcm(), mockOPCM); } - function test_setMigrateInputV1_succeeds() public { - // Create sample V1 input - IOPContractsManager.OpChainConfig[] memory configs = new IOPContractsManager.OpChainConfig[](1); - address systemConfig1 = makeAddr("systemConfig1"); - vm.etch(systemConfig1, hex"01"); - - configs[0] = IOPContractsManager.OpChainConfig({ - systemConfigProxy: ISystemConfig(systemConfig1), - cannonPrestate: Claim.wrap(bytes32(uint256(1))), - cannonKonaPrestate: Claim.wrap(bytes32(uint256(11))) - }); - - IOPContractsManagerInteropMigrator.MigrateInput memory migrateInput = IOPContractsManagerInteropMigrator - .MigrateInput({ - usePermissionlessGame: true, - startingAnchorRoot: Proposal({ root: Hash.wrap(bytes32(uint256(1))), l2SequenceNumber: 100 }), - gameParameters: IOPContractsManagerInteropMigrator.GameParameters({ - proposer: makeAddr("proposer"), - challenger: makeAddr("challenger"), - maxGameDepth: 73, - splitDepth: 30, - initBond: 1 ether, - clockExtension: Duration.wrap(10800), - maxClockDuration: Duration.wrap(302400) - }), - opChainConfigs: configs - }); - - input.set(input.migrateInput.selector, migrateInput); - - bytes memory storedInput = input.migrateInput(); - assertEq(storedInput, abi.encode(migrateInput)); - } - function test_setMigrateInputV2_succeeds() public { // Create sample V2 input ISystemConfig[] memory systemConfigs = new ISystemConfig[](1); @@ -124,23 +89,10 @@ contract InteropMigrationInput_Test is Test { } contract MockOPCM { - event MigrateV1Called(address indexed sysCfgProxy, bytes32 indexed cannonPrestate); event MigrateV2Called(address indexed sysCfg, uint32 indexed gameType); - bool public opcmV2Enabled; - - constructor(bool _opcmV2Enabled) { - opcmV2Enabled = _opcmV2Enabled; - } - - function version() public view returns (string memory) { - return opcmV2Enabled ? "7.0.0" : "6.0.0"; - } - - function migrate(IOPContractsManagerInteropMigrator.MigrateInput memory _input) public { - emit MigrateV1Called( - address(_input.opChainConfigs[0].systemConfigProxy), Claim.unwrap(_input.opChainConfigs[0].cannonPrestate) - ); + function version() public pure returns (string memory) { + return "7.0.0"; } function migrate(IOPContractsManagerMigrator.MigrateInput memory _input) public { @@ -149,18 +101,8 @@ contract MockOPCM { } contract MockOPCMRevert { - bool public opcmV2Enabled; - - constructor(bool _opcmV2Enabled) { - opcmV2Enabled = _opcmV2Enabled; - } - - function version() public view returns (string memory) { - return opcmV2Enabled ? "7.0.0" : "6.0.0"; - } - - function migrate(IOPContractsManagerInteropMigrator.MigrateInput memory /*_input*/ ) public pure { - revert("MockOPCMRevert: revert migrate"); + function version() public pure returns (string memory) { + return "7.0.0"; } function migrate(IOPContractsManagerMigrator.MigrateInput memory /*_input*/ ) public pure { @@ -168,101 +110,6 @@ contract MockOPCMRevert { } } -contract InteropMigrationV1_Test is Test { - MockOPCM mockOPCM; - MockOPCMRevert mockOPCMRevert; - InteropMigrationInput input; - IOPContractsManager.OpChainConfig config; - InteropMigration migration; - address prank; - - event MigrateV1Called(address indexed sysCfgProxy, bytes32 indexed cannonPrestate); - - function setUp() public { - // Create mock OPCM with V2 disabled - mockOPCM = new MockOPCM(false); - input = new InteropMigrationInput(); - input.set(input.opcm.selector, address(mockOPCM)); - - // Setup V1 migration input - address systemConfig = makeAddr("systemConfigProxy"); - vm.etch(systemConfig, hex"01"); - - config = IOPContractsManager.OpChainConfig({ - systemConfigProxy: ISystemConfig(systemConfig), - cannonPrestate: Claim.wrap(keccak256("cannonPrestate")), - cannonKonaPrestate: Claim.wrap(keccak256("cannonKonaPrestate")) - }); - - IOPContractsManager.OpChainConfig[] memory configs = new IOPContractsManager.OpChainConfig[](1); - configs[0] = config; - - IOPContractsManagerInteropMigrator.MigrateInput memory migrateInput = IOPContractsManagerInteropMigrator - .MigrateInput({ - usePermissionlessGame: true, - startingAnchorRoot: Proposal({ root: Hash.wrap(bytes32(uint256(1))), l2SequenceNumber: 100 }), - gameParameters: IOPContractsManagerInteropMigrator.GameParameters({ - proposer: makeAddr("proposer"), - challenger: makeAddr("challenger"), - maxGameDepth: 73, - splitDepth: 30, - initBond: 1 ether, - clockExtension: Duration.wrap(10800), - maxClockDuration: Duration.wrap(302400) - }), - opChainConfigs: configs - }); - - input.set(input.migrateInput.selector, migrateInput); - - prank = makeAddr("prank"); - input.set(input.prank.selector, prank); - - migration = new InteropMigration(); - } - - function test_migrateV1_succeeds() public { - // MigrateV1Called should be emitted by the prank since it's a delegatecall. - vm.expectEmit(address(prank)); - emit MigrateV1Called(address(config.systemConfigProxy), Claim.unwrap(config.cannonPrestate)); - - // mocks for post-migration checks - address portal = makeAddr("optimismPortal"); - address dgf = makeAddr("disputeGameFactory"); - vm.mockCall( - address(config.systemConfigProxy), abi.encodeCall(ISystemConfig.optimismPortal, ()), abi.encode(portal) - ); - vm.etch(dgf, hex"01"); - vm.mockCall(portal, abi.encodeCall(IOptimismPortal.disputeGameFactory, ()), abi.encode(dgf)); - - InteropMigrationOutput output = new InteropMigrationOutput(); - migration.run(input, output); - - assertEq(address(output.disputeGameFactory()), dgf); - } - - function test_migrateV1_migrate_reverts() public { - // Set mock OPCM to revert on migrate - mockOPCMRevert = new MockOPCMRevert(false); - input.set(input.opcm.selector, address(mockOPCMRevert)); - - InteropMigrationOutput output = new InteropMigrationOutput(); - vm.expectRevert("MockOPCMRevert: revert migrate"); - migration.run(input, output); - } - - function test_opcmV1_withNoCode_reverts() public { - // Set an address with no code as OPCM - address emptyOPCM = makeAddr("emptyOPCM"); - input.set(input.opcm.selector, emptyOPCM); - - InteropMigrationOutput output = new InteropMigrationOutput(); - - vm.expectRevert("InteropMigration: OPCM address has no code"); - migration.run(input, output); - } -} - contract InteropMigrationV2_Test is Test { MockOPCM mockOPCM; MockOPCMRevert mockOPCMRevert; @@ -274,8 +121,7 @@ contract InteropMigrationV2_Test is Test { event MigrateV2Called(address indexed sysCfg, uint32 indexed gameType); function setUp() public { - // Create mock OPCM with V2 enabled - mockOPCM = new MockOPCM(true); + mockOPCM = new MockOPCM(); input = new InteropMigrationInput(); input.set(input.opcm.selector, address(mockOPCM)); @@ -330,8 +176,7 @@ contract InteropMigrationV2_Test is Test { } function test_migrateV2_migrate_reverts() public { - // Set mock OPCM with V2 enabled to revert on migrate - mockOPCMRevert = new MockOPCMRevert(true); + mockOPCMRevert = new MockOPCMRevert(); input.set(input.opcm.selector, address(mockOPCMRevert)); InteropMigrationOutput output = new InteropMigrationOutput(); diff --git a/packages/contracts-bedrock/test/opcm/UpgradeOPChain.t.sol b/packages/contracts-bedrock/test/opcm/UpgradeOPChain.t.sol index a428963ce29..fa866053bbf 100644 --- a/packages/contracts-bedrock/test/opcm/UpgradeOPChain.t.sol +++ b/packages/contracts-bedrock/test/opcm/UpgradeOPChain.t.sol @@ -8,199 +8,15 @@ import { Test } from "test/setup/Test.sol"; import { UpgradeOPChain, UpgradeOPChainInput } from "scripts/deploy/UpgradeOPChain.s.sol"; // Contracts -import { OPContractsManager } from "src/L1/OPContractsManager.sol"; import { OPContractsManagerV2 } from "src/L1/opcm/OPContractsManagerV2.sol"; -import { UpgradeOPChain, UpgradeOPChainInput } from "scripts/deploy/UpgradeOPChain.s.sol"; // Libraries -import { Claim } from "src/dispute/lib/Types.sol"; import { GameType } from "src/dispute/lib/LibUDT.sol"; -import { Constants } from "src/libraries/Constants.sol"; // Interfaces import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; -contract UpgradeOPChainInput_Test is Test { - UpgradeOPChainInput input; - MockOPCMV1 _mockOPCM; - - function setUp() public { - input = new UpgradeOPChainInput(); - _mockOPCM = new MockOPCMV1(); - input.set(input.opcm.selector, address(_mockOPCM)); - } - - /// @notice This test verifies that the UpgradeOPChain script correctly reverts when the upgrade input is not - /// completely set. - function test_getters_whenNotSet_reverts() public { - UpgradeOPChainInput freshInput = new UpgradeOPChainInput(); - - vm.expectRevert("UpgradeOPCMInput: prank not set"); - freshInput.prank(); - - vm.expectRevert("UpgradeOPCMInput: not set"); - freshInput.opcm(); - - vm.expectRevert("UpgradeOPCMInput: not set"); - freshInput.upgradeInput(); - } - - /// @notice This test verifies that the UpgradeOPChain script correctly sets the upgrade input with - /// the address type. - function testFuzz_setAddress_succeeds(address mockPrank, address mockOPCM) public { - vm.assume(mockPrank != address(0)); - vm.assume(mockOPCM != address(0)); - - UpgradeOPChainInput freshInput = new UpgradeOPChainInput(); - freshInput.set(freshInput.prank.selector, mockPrank); - freshInput.set(freshInput.opcm.selector, mockOPCM); - - assertEq(freshInput.prank(), mockPrank); - assertEq(freshInput.opcm(), mockOPCM); - } - - /// @notice This test verifies that the UpgradeOPChain script correctly sets the upgrade input with - /// the OPContractsManager.OpChainConfig[] type. - function testFuzz_setOpChainConfigs_succeeds( - address systemConfig1, - address systemConfig2, - bytes32 prestate1, - bytes32 konaPrestate1, - bytes32 prestate2, - bytes32 konaPrestate2 - ) - public - { - // Assume non-zero addresses for system configs - vm.assume(systemConfig1 != address(0)); - vm.assume(systemConfig2 != address(0)); - // Assume not precompiles for system configs - assumeNotPrecompile(systemConfig1); - assumeNotPrecompile(systemConfig2); - // Ensure system configs don't collide with test contracts - vm.assume(systemConfig1 != address(input)); - vm.assume(systemConfig1 != address(_mockOPCM)); - vm.assume(systemConfig2 != address(input)); - vm.assume(systemConfig2 != address(_mockOPCM)); - - // Create sample OpChainConfig array - OPContractsManager.OpChainConfig[] memory configs = new OPContractsManager.OpChainConfig[](2); - - // Setup mock addresses and contracts for first config - vm.etch(systemConfig1, hex"01"); - - configs[0] = OPContractsManager.OpChainConfig({ - systemConfigProxy: ISystemConfig(systemConfig1), - cannonPrestate: Claim.wrap(prestate1), - cannonKonaPrestate: Claim.wrap(konaPrestate1) - }); - - // Setup mock addresses and contracts for second config - vm.etch(systemConfig2, hex"01"); - - configs[1] = OPContractsManager.OpChainConfig({ - systemConfigProxy: ISystemConfig(systemConfig2), - cannonPrestate: Claim.wrap(prestate2), - cannonKonaPrestate: Claim.wrap(konaPrestate2) - }); - - input.set(input.upgradeInput.selector, configs); - - bytes memory storedConfigs = input.upgradeInput(); - assertEq(storedConfigs, abi.encode(configs)); - - // Additional verification of stored claims if needed - OPContractsManager.OpChainConfig[] memory decodedConfigs = - abi.decode(storedConfigs, (OPContractsManager.OpChainConfig[])); - assertEq(Claim.unwrap(decodedConfigs[0].cannonPrestate), prestate1); - assertEq(Claim.unwrap(decodedConfigs[1].cannonPrestate), prestate2); - assertEq(Claim.unwrap(decodedConfigs[0].cannonKonaPrestate), konaPrestate1); - assertEq(Claim.unwrap(decodedConfigs[1].cannonKonaPrestate), konaPrestate2); - } - - /// @notice This test verifies that the UpgradeOPChain script correctly reverts when setting the upgrade input with - /// a zero address. - function test_setAddress_withZeroAddress_reverts() public { - UpgradeOPChainInput freshInput = new UpgradeOPChainInput(); - - vm.expectRevert("UpgradeOPCMInput: cannot set zero address"); - freshInput.set(freshInput.prank.selector, address(0)); - - vm.expectRevert("UpgradeOPCMInput: cannot set zero address"); - freshInput.set(freshInput.opcm.selector, address(0)); - } - - /// @notice This test verifies that the UpgradeOPChain script correctly reverts when setting the upgrade input with - /// an empty array. - function test_setOpChainConfigs_withEmptyArray_reverts() public { - OPContractsManager.OpChainConfig[] memory emptyConfigs = new OPContractsManager.OpChainConfig[](0); - - vm.expectRevert("UpgradeOPCMInput: cannot set empty array"); - input.set(input.upgradeInput.selector, emptyConfigs); - } - - /// @notice This test verifies that the UpgradeOPChain script correctly reverts when setting the upgrade input with - /// an invalid selector. - function testFuzz_set_withInvalidSelector_reverts(bytes4 invalidSelector, address testAddr) public { - // Assume the selector is not one of the valid selectors - vm.assume(invalidSelector != input.prank.selector); - vm.assume(invalidSelector != input.opcm.selector); - vm.assume(invalidSelector != input.upgradeInput.selector); - vm.assume(testAddr != address(0)); - - vm.expectRevert("UpgradeOPCMInput: unknown selector"); - input.set(invalidSelector, testAddr); - - // Create a single config for testing invalid selector - OPContractsManager.OpChainConfig[] memory configs = new OPContractsManager.OpChainConfig[](1); - address mockSystemConfig = makeAddr("systemConfig"); - vm.etch(mockSystemConfig, hex"01"); - - configs[0] = OPContractsManager.OpChainConfig({ - systemConfigProxy: ISystemConfig(mockSystemConfig), - cannonPrestate: Claim.wrap(bytes32(uint256(1))), - cannonKonaPrestate: Claim.wrap(bytes32(uint256(2))) - }); - - vm.expectRevert("UpgradeOPCMInput: unknown selector"); - input.set(invalidSelector, configs); - } - - /// @notice This test verifies that the UpgradeOPChain script correctly reverts when setting the upgrade input with - /// OPCM v2 input when OPCM v1 is enabled. - function testFuzz_setUpgradeInputV2_onV1OPCM_reverts( - address systemConfig, - bool enabled, - uint256 initBond, - uint32 gameType - ) - public - { - vm.assume(systemConfig != address(0)); - vm.assume(initBond > 0); - - // Try to set V2 input when V1 is enabled - IOPContractsManagerUtils.DisputeGameConfig[] memory disputeGameConfigs = - new IOPContractsManagerUtils.DisputeGameConfig[](1); - disputeGameConfigs[0] = IOPContractsManagerUtils.DisputeGameConfig({ - enabled: enabled, - initBond: initBond, - gameType: GameType.wrap(gameType), - gameArgs: abi.encode("test") - }); - - OPContractsManagerV2.UpgradeInput memory upgradeInput = OPContractsManagerV2.UpgradeInput({ - systemConfig: ISystemConfig(systemConfig), - disputeGameConfigs: disputeGameConfigs, - extraInstructions: new IOPContractsManagerUtils.ExtraInstruction[](0) - }); - - vm.expectRevert("UpgradeOPCMInput: cannot set OPCM v2 upgrade input when OPCM v1 is enabled"); - input.set(input.upgradeInput.selector, upgradeInput); - } -} - contract UpgradeOPChainInput_TestV2 is Test { UpgradeOPChainInput input; MockOPCMV2 mockOPCM; @@ -296,47 +112,6 @@ contract UpgradeOPChainInput_TestV2 is Test { vm.expectRevert("UpgradeOPCMInput: cannot set empty dispute game configs array"); input.set(input.upgradeInput.selector, upgradeInput); } - - /// @notice This test verifies that the UpgradeOPChain script correctly reverts when setting the upgrade input with - /// OPCM v1 input when OPCM v2 is enabled. - function testFuzz_setUpgradeInputV1_onV2OPCM_reverts( - address systemConfigProxy, - bytes32 cannonPrestate, - bytes32 cannonKonaPrestate - ) - public - { - vm.assume(systemConfigProxy != address(0)); - - // Try to set V1 input when V2 is enabled - OPContractsManager.OpChainConfig[] memory configs = new OPContractsManager.OpChainConfig[](1); - configs[0] = OPContractsManager.OpChainConfig({ - systemConfigProxy: ISystemConfig(systemConfigProxy), - cannonPrestate: Claim.wrap(cannonPrestate), - cannonKonaPrestate: Claim.wrap(cannonKonaPrestate) - }); - - vm.expectRevert("UpgradeOPCMInput: cannot set OPCM v1 upgrade input when OPCM v2 is enabled"); - input.set(input.upgradeInput.selector, configs); - } -} - -contract MockOPCMV1 { - event UpgradeCalled( - address indexed sysCfgProxy, bytes32 indexed absolutePrestate, bytes32 indexed cannonKonaPrestate - ); - - function version() public pure returns (string memory) { - return "6.0.0"; - } - - function upgrade(OPContractsManager.OpChainConfig[] memory _opChainConfigs) public { - emit UpgradeCalled( - address(_opChainConfigs[0].systemConfigProxy), - Claim.unwrap(_opChainConfigs[0].cannonPrestate), - Claim.unwrap(_opChainConfigs[0].cannonKonaPrestate) - ); - } } contract MockOPCMV2 { @@ -347,7 +122,7 @@ contract MockOPCMV2 { ); function version() public pure returns (string memory) { - return Constants.OPCM_V2_MIN_VERSION; + return "7.0.0"; } function upgrade(OPContractsManagerV2.UpgradeInput memory _upgradeInput) public { @@ -357,77 +132,6 @@ contract MockOPCMV2 { } } -contract UpgradeOPChain_Test is Test { - MockOPCMV1 mockOPCM; - UpgradeOPChainInput uoci; - OPContractsManager.OpChainConfig config; - UpgradeOPChain upgradeOPChain; - address prank; - - event UpgradeCalled( - address indexed sysCfgProxy, bytes32 indexed absolutePrestate, bytes32 indexed cannonKonaPrestate - ); - - function setUp() public { - mockOPCM = new MockOPCMV1(); - uoci = new UpgradeOPChainInput(); - uoci.set(uoci.opcm.selector, address(mockOPCM)); - prank = makeAddr("prank"); - uoci.set(uoci.prank.selector, prank); - upgradeOPChain = new UpgradeOPChain(); - } - - /// @notice This test verifies that the UpgradeOPChain script correctly encodes and passes down the upgrade input - /// arguments to the OPCM contract's upgrade function. - /// @dev It does not test the actual upgrade functionality. - function testFuzz_upgrade_succeeds( - address systemConfigProxy, - bytes32 cannonPrestate, - bytes32 cannonKonaPrestate - ) - public - { - vm.assume(systemConfigProxy != address(0)); - - config = OPContractsManager.OpChainConfig({ - systemConfigProxy: ISystemConfig(systemConfigProxy), - cannonPrestate: Claim.wrap(cannonPrestate), - cannonKonaPrestate: Claim.wrap(cannonKonaPrestate) - }); - OPContractsManager.OpChainConfig[] memory configs = new OPContractsManager.OpChainConfig[](1); - configs[0] = config; - uoci.set(uoci.upgradeInput.selector, configs); - - // UpgradeCalled should be emitted by the prank since it's a delegate call. - vm.expectEmit(address(prank)); - emit UpgradeCalled( - address(config.systemConfigProxy), - Claim.unwrap(config.cannonPrestate), - Claim.unwrap(config.cannonKonaPrestate) - ); - upgradeOPChain.run(uoci); - } - - /// @notice This test verifies that the UpgradeOPChain script correctly reverts when the OPCM upgrade - /// call fails - function test_upgrade_whenOPCMReverts_reverts() public { - address systemConfigProxy = makeAddr("systemConfig"); - config = OPContractsManager.OpChainConfig({ - systemConfigProxy: ISystemConfig(systemConfigProxy), - cannonPrestate: Claim.wrap(bytes32(uint256(1))), - cannonKonaPrestate: Claim.wrap(bytes32(uint256(2))) - }); - OPContractsManager.OpChainConfig[] memory configs = new OPContractsManager.OpChainConfig[](1); - configs[0] = config; - uoci.set(uoci.upgradeInput.selector, configs); - - vm.mockCallRevert(prank, OPContractsManager.upgrade.selector, abi.encode("UpgradeOPChain: upgrade failed")); - - vm.expectRevert("UpgradeOPChain: upgrade failed"); - upgradeOPChain.run(uoci); - } -} - contract UpgradeOPChain_TestV2 is Test { MockOPCMV2 mockOPCM; UpgradeOPChainInput uoci; diff --git a/packages/contracts-bedrock/test/opcm/UpgradeSuperchainConfig.t.sol b/packages/contracts-bedrock/test/opcm/UpgradeSuperchainConfig.t.sol index a4ec0153c4e..d36ee2cc635 100644 --- a/packages/contracts-bedrock/test/opcm/UpgradeSuperchainConfig.t.sol +++ b/packages/contracts-bedrock/test/opcm/UpgradeSuperchainConfig.t.sol @@ -8,35 +8,17 @@ import { Test } from "test/setup/Test.sol"; import { UpgradeSuperchainConfig } from "scripts/deploy/UpgradeSuperchainConfig.s.sol"; // Interfaces -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; -// Libraries -import { Constants } from "src/libraries/Constants.sol"; - -/// @title MockOPCMV1 -/// @notice This contract is used to mock the OPCM contract and emit an event which we check for in the test. -contract MockOPCMV1 { - event UpgradeCalled(address indexed superchainConfig); - - function version() public pure returns (string memory) { - return "6.0.0"; - } - - function upgradeSuperchainConfig(ISuperchainConfig _superchainConfig) public { - emit UpgradeCalled(address(_superchainConfig)); - } -} - /// @title MockOPCMV2 /// @notice This contract is used to mock the OPCM v2 contract and emit an event which we check for in the test. contract MockOPCMV2 { event UpgradeCalled(IOPContractsManagerV2.SuperchainUpgradeInput indexed superchainUpgradeInput); function version() public pure returns (string memory) { - return Constants.OPCM_V2_MIN_VERSION; + return "7.0.0"; } function upgradeSuperchain(IOPContractsManagerV2.SuperchainUpgradeInput memory _superchainUpgradeInput) public { @@ -44,72 +26,6 @@ contract MockOPCMV2 { } } -/// @title UpgradeSuperchainConfig_Test -/// @notice This test is used to test the UpgradeSuperchainConfig script. -contract UpgradeSuperchainConfigV1_Run_Test is Test { - MockOPCMV1 mockOPCM; - UpgradeSuperchainConfig.Input input; - UpgradeSuperchainConfig upgradeSuperchainConfig; - address prank; - ISuperchainConfig superchainConfig; - - event UpgradeCalled(address indexed superchainConfig); - - /// @notice Sets up the test suite. - function setUp() public virtual { - mockOPCM = new MockOPCMV1(); - - input.opcm = address(mockOPCM); - - superchainConfig = ISuperchainConfig(makeAddr("superchainConfig")); - prank = makeAddr("prank"); - - input.superchainConfig = superchainConfig; - input.prank = prank; - - upgradeSuperchainConfig = new UpgradeSuperchainConfig(); - } - - /// @notice Tests that the UpgradeSuperchainConfig script succeeds when called with non-zero input values. - function test_upgrade_succeeds() public { - // UpgradeCalled should be emitted by the prank since it's a delegate call. - vm.expectEmit(address(prank)); - emit UpgradeCalled(address(superchainConfig)); - upgradeSuperchainConfig.run(input); - } - - /// @notice Tests that the UpgradeSuperchainConfig script reverts when called with zero input values. - function test_run_nullInput_reverts() public { - input.prank = address(0); - vm.expectRevert("UpgradeSuperchainConfig: prank not set"); - upgradeSuperchainConfig.run(input); - input.prank = prank; - - input.opcm = address(0); - vm.expectRevert("UpgradeSuperchainConfig: opcm not set"); - upgradeSuperchainConfig.run(input); - input.opcm = address(mockOPCM); - - input.superchainConfig = ISuperchainConfig(address(0)); - vm.expectRevert("UpgradeSuperchainConfig: superchainConfig not set"); - upgradeSuperchainConfig.run(input); - input.superchainConfig = ISuperchainConfig(address(superchainConfig)); - } - - /// @notice Tests that the UpgradeSuperchainConfig script reverts when the OPCM upgradeSuperchainConfig - /// call fails - function test_upgrade_whenOPCMReverts_reverts() public { - vm.mockCallRevert( - prank, - IOPContractsManager.upgradeSuperchainConfig.selector, - abi.encode("UpgradeSuperchainConfig: upgrade failed") - ); - - vm.expectRevert("UpgradeSuperchainConfig: upgrade failed"); - upgradeSuperchainConfig.run(input); - } -} - /// @title UpgradeSuperchainConfigV2_Run_Test /// @notice This test is used to test the UpgradeSuperchainConfig script with OPCM v2. contract UpgradeSuperchainConfigV2_Run_Test is Test { diff --git a/packages/contracts-bedrock/test/safe-tools/SafeTestTools.sol b/packages/contracts-bedrock/test/safe-tools/SafeTestTools.sol index 35b0ef9ee8e..7962d5f5f16 100644 --- a/packages/contracts-bedrock/test/safe-tools/SafeTestTools.sol +++ b/packages/contracts-bedrock/test/safe-tools/SafeTestTools.sol @@ -166,44 +166,6 @@ library SafeTestLib { return sortedPKs; } - /// @dev Sign a transaction as a safe owner with a private key. - function signTransaction( - SafeInstance memory instance, - uint256 pk, - address to, - uint256 value, - bytes memory data, - Enum.Operation operation, - uint256 safeTxGas, - uint256 baseGas, - uint256 gasPrice, - address gasToken, - address refundReceiver - ) - internal - view - returns (uint8 v, bytes32 r, bytes32 s) - { - bytes32 txDataHash; - { - uint256 _nonce = instance.safe.nonce(); - txDataHash = instance.safe.getTransactionHash({ - to: to, - value: value, - data: data, - operation: operation, - safeTxGas: safeTxGas, - baseGas: baseGas, - gasPrice: gasPrice, - gasToken: gasToken, - refundReceiver: refundReceiver, - _nonce: _nonce - }); - } - - (v, r, s) = Vm(VM_ADDR).sign(pk, txDataHash); - } - /// @dev Get the previous owner in the linked list of owners. /// This version of getPrevOwner will call to the Safe contract to get the current list of owners. /// Note that this will break vm.expectRevert() tests by making a call which does not revert.. @@ -350,12 +312,6 @@ library SafeTestLib { EIP1271Sign(instance, abi.encodePacked(digest)); } - /// @dev Increments the nonce of the Safe by sending an empty transaction. - function incrementNonce(SafeInstance memory instance) internal returns (uint256 newNonce) { - execTransaction(instance, address(0), 0, "", Enum.Operation.Call, 0, 0, 0, address(0), address(0), ""); - return instance.safe.nonce(); - } - /// @dev Adds a new owner to the safe function changeThreshold(SafeInstance memory instance, uint256 threshold) internal { execTransaction(instance, address(instance.safe), 0, abi.encodeCall(OwnerManager.changeThreshold, (threshold))); @@ -495,13 +451,6 @@ contract SafeTestTools { uint256 internal saltNonce = uint256(keccak256(bytes("SAFE TEST"))); - /// @dev can be called to reinitialize the singleton, proxyFactory and handler. Useful for forking. - function _initializeSafeTools() internal { - singleton = new GnosisSafe(); - proxyFactory = new GnosisSafeProxyFactory(); - handler = new CompatibilityFallbackHandler(); - } - /// @dev Sets up a Safe with the given parameters. /// @param ownerPKs The public keys of the owners. /// @param threshold The threshold for the Safe. diff --git a/packages/contracts-bedrock/test/scripts/ReadImplementationAddresses.t.sol b/packages/contracts-bedrock/test/scripts/ReadImplementationAddresses.t.sol index b5b09edb45a..3f4176ef0a2 100644 --- a/packages/contracts-bedrock/test/scripts/ReadImplementationAddresses.t.sol +++ b/packages/contracts-bedrock/test/scripts/ReadImplementationAddresses.t.sol @@ -8,13 +8,10 @@ import { CommonTest } from "test/setup/CommonTest.sol"; import { ReadImplementationAddresses } from "scripts/deploy/ReadImplementationAddresses.s.sol"; // Interfaces -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; +import { IOPContractsManagerContainer } from "interfaces/L1/opcm/IOPContractsManagerContainer.sol"; import { IMIPS64 } from "interfaces/cannon/IMIPS64.sol"; -// Libraries -import { DevFeatures } from "src/libraries/DevFeatures.sol"; - /// @title ReadImplementationAddressesTest /// @notice Tests that ReadImplementationAddresses correctly reads implementation addresses /// from the deployed contracts. Uses CommonTest to get real deployed contracts. @@ -26,9 +23,9 @@ contract ReadImplementationAddressesTest is CommonTest { script = new ReadImplementationAddresses(); } - /// @notice Returns the OPCM instance, handling V1 vs V2 feature flag. - function _opcm() internal view returns (IOPContractsManager) { - return isDevFeatureEnabled(DevFeatures.OPCM_V2) ? IOPContractsManager(address(opcmV2)) : opcm; + /// @notice Returns the OPCM instance. + function _opcm() internal view returns (IOPContractsManagerV2) { + return IOPContractsManagerV2(address(opcmV2)); } /// @notice Builds the input struct from the deployed contracts. @@ -49,8 +46,8 @@ contract ReadImplementationAddressesTest is CommonTest { ReadImplementationAddresses.Output memory output = script.run(input); // Get expected implementations from OPCM - IOPContractsManager opcm_ = _opcm(); - IOPContractsManager.Implementations memory impls = opcm_.implementations(); + IOPContractsManagerV2 opcm_ = _opcm(); + IOPContractsManagerContainer.Implementations memory impls = opcm_.implementations(); // Assert implementations from OPCM match output assertEq(output.delayedWETH, impls.delayedWETHImpl, "DelayedWETH should match"); @@ -70,26 +67,10 @@ contract ReadImplementationAddressesTest is CommonTest { output.opcmStandardValidator, address(opcm_.opcmStandardValidator()), "OPCM StandardValidator should match" ); - // Assert V1 vs V2 specific fields - if (isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - // V2: deployer/upgrader/gameTypeAdder are zero, migrator comes from opcmMigrator() - assertEq(output.opcmDeployer, address(0), "OPCM Deployer should be zero in V2"); - assertEq(output.opcmUpgrader, address(0), "OPCM Upgrader should be zero in V2"); - assertEq(output.opcmGameTypeAdder, address(0), "OPCM GameTypeAdder should be zero in V2"); - assertEq( - output.opcmInteropMigrator, - address(IOPContractsManagerV2(address(opcm_)).opcmMigrator()), - "OPCM InteropMigrator should match" - ); - } else { - // V1: all component addresses come from opcm getters - assertEq(output.opcmDeployer, address(opcm_.opcmDeployer()), "OPCM Deployer should match"); - assertEq(output.opcmUpgrader, address(opcm_.opcmUpgrader()), "OPCM Upgrader should match"); - assertEq(output.opcmGameTypeAdder, address(opcm_.opcmGameTypeAdder()), "OPCM GameTypeAdder should match"); - assertEq( - output.opcmInteropMigrator, address(opcm_.opcmInteropMigrator()), "OPCM InteropMigrator should match" - ); - } + assertEq(output.opcmDeployer, address(0), "OPCM Deployer should be zero"); + assertEq(output.opcmUpgrader, address(0), "OPCM Upgrader should be zero"); + assertEq(output.opcmGameTypeAdder, address(0), "OPCM GameTypeAdder should be zero"); + assertEq(output.opcmInteropMigrator, address(opcm_.opcmMigrator()), "OPCM InteropMigrator should match"); } /// @notice Tests that ReadImplementationAddresses.runWithBytes succeeds. @@ -101,8 +82,8 @@ contract ReadImplementationAddressesTest is CommonTest { ReadImplementationAddresses.Output memory output = abi.decode(outputBytes, (ReadImplementationAddresses.Output)); // Get expected implementations from OPCM - IOPContractsManager opcm_ = _opcm(); - IOPContractsManager.Implementations memory impls = opcm_.implementations(); + IOPContractsManagerV2 opcm_ = _opcm(); + IOPContractsManagerContainer.Implementations memory impls = opcm_.implementations(); // Assert key values match assertEq(output.delayedWETH, impls.delayedWETHImpl, "DelayedWETH should match"); diff --git a/packages/contracts-bedrock/test/scripts/ReadSuperchainDeployment.t.sol b/packages/contracts-bedrock/test/scripts/ReadSuperchainDeployment.t.sol index bb85679d55d..db928b543a9 100644 --- a/packages/contracts-bedrock/test/scripts/ReadSuperchainDeployment.t.sol +++ b/packages/contracts-bedrock/test/scripts/ReadSuperchainDeployment.t.sol @@ -9,28 +9,18 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; import { ReadSuperchainDeployment } from "scripts/deploy/ReadSuperchainDeployment.s.sol"; // Interfaces -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; -import { IProtocolVersions, ProtocolVersion } from "interfaces/L1/IProtocolVersions.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; import { IProxy } from "interfaces/universal/IProxy.sol"; -import { Constants } from "src/libraries/Constants.sol"; // Test addresses declared as constants for convenience. address constant TEST_SUPERCHAIN_CONFIG_IMPL = address(0x3001); address constant TEST_SUPERCHAIN_PROXY_ADMIN = address(0x3002); address constant TEST_GUARDIAN = address(0x3003); address constant TEST_SUPERCHAIN_PROXY_ADMIN_OWNER = address(0x3004); -address constant TEST_OPCM_IMPL = address(0x2000); -address constant TEST_PROTOCOL_VERSIONS_PROXY = address(0x3005); -address constant TEST_PROTOCOL_VERSIONS_IMPL = address(0x3006); -address constant TEST_PROTOCOL_VERSIONS_OWNER = address(0x3007); -uint256 constant TEST_RECOMMENDED_VERSION = 1; -uint256 constant TEST_REQUIRED_VERSION = 2; /// @title ReadSuperchainDeploymentTest -/// @notice Tests that ReadSuperchainDeployment.run and ReadSuperchainDeployment.runWithBytes succeed with OPCM V1 -/// and OPCM V2. +/// @notice Tests that ReadSuperchainDeployment.run and ReadSuperchainDeployment.runWithBytes succeed. contract ReadSuperchainDeploymentTest is Test { ReadSuperchainDeployment script; ReadSuperchainDeployment.Input input; @@ -40,35 +30,8 @@ contract ReadSuperchainDeploymentTest is Test { input.superchainConfigProxy = ISuperchainConfig(makeAddr("superchainConfigProxy")); } - /// @notice Tests that ReadSuperchainDeployment.run succeeds with OPCM V2 (opcmAddress is zero). - function test_run_withOPCMV2ZeroAddress_succeeds() public { - input.opcmAddress = IOPContractsManager(address(0)); - - _setUpSuperchainConfigProxy(); - _mockSuperchainConfigCalls(); - - ReadSuperchainDeployment.Output memory output = script.run(input); - - assertEq(address(output.superchainConfigProxy), address(input.superchainConfigProxy)); - assertEq(address(output.superchainConfigImpl), TEST_SUPERCHAIN_CONFIG_IMPL); - assertEq(address(output.superchainProxyAdmin), TEST_SUPERCHAIN_PROXY_ADMIN); - assertEq(output.guardian, TEST_GUARDIAN); - assertEq(output.superchainProxyAdminOwner, TEST_SUPERCHAIN_PROXY_ADMIN_OWNER); - assertEq(address(output.protocolVersionsImpl), address(0)); - assertEq(address(output.protocolVersionsProxy), address(0)); - assertEq(output.protocolVersionsOwner, address(0)); - assertEq(output.recommendedProtocolVersion, bytes32(0)); - assertEq(output.requiredProtocolVersion, bytes32(0)); - } - - /// @notice Tests that ReadSuperchainDeployment.run succeeds with OPCM V2 (opcm version >= 7.0.0). - function test_run_withOPCMV2VersionGteMin_succeeds() public { - input.opcmAddress = IOPContractsManager(TEST_OPCM_IMPL); - vm.etch(TEST_OPCM_IMPL, "0x01"); - _mockExpect( - TEST_OPCM_IMPL, abi.encodeCall(IOPContractsManager.version, ()), abi.encode(Constants.OPCM_V2_MIN_VERSION) - ); - + /// @notice Tests that ReadSuperchainDeployment.run succeeds. + function test_run_succeeds() public { _setUpSuperchainConfigProxy(); _mockSuperchainConfigCalls(); @@ -79,16 +42,10 @@ contract ReadSuperchainDeploymentTest is Test { assertEq(address(output.superchainProxyAdmin), TEST_SUPERCHAIN_PROXY_ADMIN); assertEq(output.guardian, TEST_GUARDIAN); assertEq(output.superchainProxyAdminOwner, TEST_SUPERCHAIN_PROXY_ADMIN_OWNER); - assertEq(address(output.protocolVersionsImpl), address(0)); - assertEq(address(output.protocolVersionsProxy), address(0)); - assertEq(output.protocolVersionsOwner, address(0)); - assertEq(output.recommendedProtocolVersion, bytes32(0)); - assertEq(output.requiredProtocolVersion, bytes32(0)); } - /// @notice Tests that ReadSuperchainDeployment.runWithBytes succeeds with OPCM V2. - function test_runWithBytes_withOPCMV2_succeeds() public { - input.opcmAddress = IOPContractsManager(address(0)); + /// @notice Tests that ReadSuperchainDeployment.runWithBytes succeeds. + function test_runWithBytes_succeeds() public { _setUpSuperchainConfigProxy(); _mockSuperchainConfigCalls(); @@ -101,67 +58,13 @@ contract ReadSuperchainDeploymentTest is Test { assertEq(address(output.superchainProxyAdmin), TEST_SUPERCHAIN_PROXY_ADMIN); assertEq(output.guardian, TEST_GUARDIAN); assertEq(output.superchainProxyAdminOwner, TEST_SUPERCHAIN_PROXY_ADMIN_OWNER); - assertEq(address(output.protocolVersionsImpl), address(0)); - assertEq(address(output.protocolVersionsProxy), address(0)); - assertEq(output.protocolVersionsOwner, address(0)); - assertEq(output.recommendedProtocolVersion, bytes32(0)); - assertEq(output.requiredProtocolVersion, bytes32(0)); } - /// @notice Tests that run reverts when OPCM V2 and superchainConfigProxy has no code. - function test_run_opcmV2SuperchainConfigNoCode_reverts() public { - input.opcmAddress = IOPContractsManager(address(0)); + /// @notice Tests that run reverts when superchainConfigProxy has no code. + function test_run_superchainConfigNoCode_reverts() public { // Do not etch code to superchainConfigProxy - vm.expectRevert("ReadSuperchainDeployment: superchainConfigProxy has no code for OPCM v2"); - script.run(input); - } - - /// @notice Tests that ReadSuperchainDeployment.run succeeds with OPCM V1. - function test_run_withOPCMV1_succeeds() public { - _mockOPCMV1(); - _setUpSuperchainConfigProxy(); - _mockSuperchainConfigCalls(); - _mockProtocolVersionsCalls(); - - ReadSuperchainDeployment.Output memory output = script.run(input); - - assertEq(address(output.superchainConfigProxy), address(input.superchainConfigProxy)); - assertEq(address(output.superchainConfigImpl), TEST_SUPERCHAIN_CONFIG_IMPL); - assertEq(address(output.superchainProxyAdmin), TEST_SUPERCHAIN_PROXY_ADMIN); - assertEq(output.guardian, TEST_GUARDIAN); - assertEq(output.superchainProxyAdminOwner, TEST_SUPERCHAIN_PROXY_ADMIN_OWNER); - assertEq(address(output.protocolVersionsImpl), TEST_PROTOCOL_VERSIONS_IMPL); - assertEq(address(output.protocolVersionsProxy), TEST_PROTOCOL_VERSIONS_PROXY); - assertEq(output.protocolVersionsOwner, TEST_PROTOCOL_VERSIONS_OWNER); - assertEq(output.recommendedProtocolVersion, bytes32(TEST_RECOMMENDED_VERSION)); - assertEq(output.requiredProtocolVersion, bytes32(TEST_REQUIRED_VERSION)); - } - - /// @notice Tests that ReadSuperchainDeployment.runWithBytes succeeds with OPCM V1. - function test_runWithBytes_withOPCMV1_succeeds() public { - _mockOPCMV1(); - vm.etch(address(input.superchainConfigProxy), "0x01"); - _setUpSuperchainConfigProxy(); - _mockSuperchainConfigCalls(); - _mockProtocolVersionsCalls(); - - bytes memory inputBytes = abi.encode(input); - bytes memory outputBytes = script.runWithBytes(inputBytes); - ReadSuperchainDeployment.Output memory output = abi.decode(outputBytes, (ReadSuperchainDeployment.Output)); - - assertEq(address(output.superchainConfigProxy), address(input.superchainConfigProxy)); - assertEq(address(output.protocolVersionsImpl), TEST_PROTOCOL_VERSIONS_IMPL); - assertEq(output.recommendedProtocolVersion, bytes32(TEST_RECOMMENDED_VERSION)); - assertEq(output.requiredProtocolVersion, bytes32(TEST_REQUIRED_VERSION)); - } - - /// @notice Tests that run reverts when OPCM address is non-zero but has no code. - function test_run_opcmCodeLengthZero_reverts() public { - input.opcmAddress = IOPContractsManager(makeAddr("opcmNoCode")); - vm.etch(address(input.superchainConfigProxy), "0x01"); - - vm.expectRevert("ReadSuperchainDeployment: OPCM address has no code"); + vm.expectRevert("ReadSuperchainDeployment: superchainConfigProxy has no code"); script.run(input); } @@ -173,7 +76,7 @@ contract ReadSuperchainDeploymentTest is Test { EIP1967Helper.setAdmin(address(input.superchainConfigProxy), TEST_SUPERCHAIN_PROXY_ADMIN); } - /// @notice Mocks SuperchainConfig proxy and ProxyAdmin calls used in both OPCM v1 and v2 paths. + /// @notice Mocks SuperchainConfig proxy and ProxyAdmin calls. function _mockSuperchainConfigCalls() internal { _mockExpect( address(input.superchainConfigProxy), @@ -192,48 +95,6 @@ contract ReadSuperchainDeploymentTest is Test { ); } - /// @notice Mocks OPCM V1: version, protocolVersions(), superchainConfig(). - function _mockOPCMV1() internal { - input.opcmAddress = IOPContractsManager(TEST_OPCM_IMPL); - vm.etch(TEST_OPCM_IMPL, "0x01"); - - _mockExpect(TEST_OPCM_IMPL, abi.encodeCall(IOPContractsManager.version, ()), abi.encode("6.0.0")); - _mockExpect( - TEST_OPCM_IMPL, - abi.encodeCall(IOPContractsManager.protocolVersions, ()), - abi.encode(TEST_PROTOCOL_VERSIONS_PROXY) - ); - _mockExpect( - TEST_OPCM_IMPL, - abi.encodeCall(IOPContractsManager.superchainConfig, ()), - abi.encode(address(input.superchainConfigProxy)) - ); - } - - /// @notice Mocks ProtocolVersions proxy: implementation(), owner(), recommended(), required(). - function _mockProtocolVersionsCalls() internal { - _mockExpect( - TEST_PROTOCOL_VERSIONS_PROXY, - abi.encodeCall(IProxy.implementation, ()), - abi.encode(TEST_PROTOCOL_VERSIONS_IMPL) - ); - _mockExpect( - TEST_PROTOCOL_VERSIONS_PROXY, - abi.encodeCall(IProtocolVersions.owner, ()), - abi.encode(TEST_PROTOCOL_VERSIONS_OWNER) - ); - _mockExpect( - TEST_PROTOCOL_VERSIONS_PROXY, - abi.encodeCall(IProtocolVersions.recommended, ()), - abi.encode(ProtocolVersion.wrap(TEST_RECOMMENDED_VERSION)) - ); - _mockExpect( - TEST_PROTOCOL_VERSIONS_PROXY, - abi.encodeCall(IProtocolVersions.required, ()), - abi.encode(ProtocolVersion.wrap(TEST_REQUIRED_VERSION)) - ); - } - /// @notice Internal helper to mock and expect calls. function _mockExpect(address _target, bytes memory _callData, bytes memory _returnData) internal { vm.mockCall(_target, _callData, _returnData); diff --git a/packages/contracts-bedrock/test/scripts/VerifyOPCM.t.sol b/packages/contracts-bedrock/test/scripts/VerifyOPCM.t.sol index 62a63d750f3..b541b898023 100644 --- a/packages/contracts-bedrock/test/scripts/VerifyOPCM.t.sol +++ b/packages/contracts-bedrock/test/scripts/VerifyOPCM.t.sol @@ -12,7 +12,6 @@ import { CommonTest } from "test/setup/CommonTest.sol"; import { VerifyOPCM } from "scripts/deploy/VerifyOPCM.s.sol"; // Interfaces -import { IOPContractsManager, IOPContractsManagerUpgrader } from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManagerStandardValidator } from "interfaces/L1/IOPContractsManagerStandardValidator.sol"; import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol"; @@ -34,12 +33,12 @@ contract VerifyOPCM_Harness is VerifyOPCM { return _loadArtifactInfo(_artifactPath); } - function getOpcmPropertyRefs(IOPContractsManager _opcm) public returns (OpcmContractRef[] memory) { + function getOpcmPropertyRefs(IOPContractsManagerV2 _opcm) public returns (OpcmContractRef[] memory) { return _getOpcmPropertyRefs(_opcm); } function getOpcmContractRefs( - IOPContractsManager _opcm, + IOPContractsManagerV2 _opcm, string memory _property, bool _blueprint ) @@ -61,7 +60,7 @@ contract VerifyOPCM_Harness is VerifyOPCM { return _verifyOpcmUtilsConsistency(_propRefs); } - function verifyOpcmImmutableVariables(IOPContractsManager _opcm) public returns (bool) { + function verifyOpcmImmutableVariables(IOPContractsManagerV2 _opcm) public returns (bool) { return _verifyOpcmImmutableVariables(_opcm); } @@ -89,7 +88,7 @@ contract VerifyOPCM_Harness is VerifyOPCM { return _verifyAnchorStateRegistryDelays(_asr); } - function verifyStandardValidatorArgs(IOPContractsManager _opcm, address _validator) public returns (bool) { + function verifyStandardValidatorArgs(IOPContractsManagerV2 _opcm, address _validator) public returns (bool) { return _verifyStandardValidatorArgs(_opcm, _validator); } @@ -102,33 +101,24 @@ contract VerifyOPCM_Harness is VerifyOPCM { /// @notice Reusable test initialization for `VerifyOPCM` tests. abstract contract VerifyOPCM_TestInit is CommonTest { VerifyOPCM_Harness internal harness; + IOPContractsManagerV2 internal opcm; function setUp() public virtual override { super.setUp(); harness = new VerifyOPCM_Harness(); harness.setUp(); - // If OPCM V2 is enabled, set up the test environment for OPCM V2. - // nosemgrep: sol-style-vm-env-only-in-config-sol - if (vm.envOr("DEV_FEATURE__OPCM_V2", false)) { - opcm = IOPContractsManager(address(opcmV2)); - } + opcm = IOPContractsManagerV2(address(opcmV2)); // Always set up the environment variables for the test. setupEnvVars(); - // Set the OPCM address so that runSingle also runs for V2 OPCM if the dev feature is enabled. + // Set the OPCM address. vm.setEnv("OPCM_ADDRESS", vm.toString(address(opcm))); } /// @notice Sets up the environment variables for the VerifyOPCM test. function setupEnvVars() public { - // If OPCM V2 is not enabled, set the environment variables for the old OPCM. - if (!isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - vm.setEnv("EXPECTED_SUPERCHAIN_CONFIG", vm.toString(address(opcm.superchainConfig()))); - vm.setEnv("EXPECTED_PROTOCOL_VERSIONS", vm.toString(address(opcm.protocolVersions()))); - } - // Grab a reference to the validator. IOPContractsManagerStandardValidator validator = IOPContractsManagerStandardValidator(opcm.opcmStandardValidator()); @@ -197,7 +187,7 @@ contract VerifyOPCM_Run_Test is VerifyOPCM_TestInit { // Mock opcm to return a non-zero dev feature bitmap. vm.mockCall( - address(opcm), abi.encodeCall(IOPContractsManager.devFeatureBitmap, ()), abi.encode(_devFeatureBitmap) + address(opcm), abi.encodeCall(IOPContractsManagerV2.devFeatureBitmap, ()), abi.encode(_devFeatureBitmap) ); // Set the chain ID to 1. @@ -432,7 +422,7 @@ contract VerifyOPCM_Run_Test is VerifyOPCM_TestInit { // Mock this specific component to return a different address vm.mockCall( propRefs[i].addr, - abi.encodeCall(IOPContractsManagerUpgrader.contractsContainer, ()), + abi.encodeCall(IOPContractsManagerV2.contractsContainer, ()), abi.encode(differentContainer) ); @@ -454,9 +444,6 @@ contract VerifyOPCM_Run_Test is VerifyOPCM_TestInit { function test_verifyOpcmUtilsConsistency_succeeds() public { skipIfUnoptimized(); - // Only run for OPCM V2 - skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); - // Get the property references (which include the component addresses) VerifyOPCM.OpcmContractRef[] memory propRefs = harness.getOpcmPropertyRefs(opcm); @@ -468,9 +455,6 @@ contract VerifyOPCM_Run_Test is VerifyOPCM_TestInit { function test_verifyOpcmUtilsConsistency_mismatch_reverts() public { skipIfUnoptimized(); - // Only run for OPCM V2 - skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); - // Get the property references (which include the component addresses) VerifyOPCM.OpcmContractRef[] memory propRefs = harness.getOpcmPropertyRefs(opcm); @@ -489,9 +473,6 @@ contract VerifyOPCM_Run_Test is VerifyOPCM_TestInit { function test_verifyOpcmUtilsConsistency_eachComponent_reverts() public { skipIfUnoptimized(); - // Only run for OPCM V2 - skipIfDevFeatureDisabled(DevFeatures.OPCM_V2); - // Get the property references (which include the component addresses) VerifyOPCM.OpcmContractRef[] memory propRefs = harness.getOpcmPropertyRefs(opcm); @@ -535,7 +516,7 @@ contract VerifyOPCM_Run_Test is VerifyOPCM_TestInit { if (_hasContractsContainer(field)) { vm.mockCall( _propRefs[i].addr, - abi.encodeCall(IOPContractsManagerUpgrader.contractsContainer, ()), + abi.encodeCall(IOPContractsManagerV2.contractsContainer, ()), abi.encode(_mockAddress) ); return; @@ -624,19 +605,6 @@ contract VerifyOPCM_Run_Test is VerifyOPCM_TestInit { assertFalse(result, "OPCM with invalid immutable variables should fail verification"); } - /// @notice Tests that the script fails when OPCM immutable variables are invalid. - /// We test this by setting expected addresses and mocking OPCM methods to return different addresses. - function test_verifyOpcmImmutableVariables_mismatch_fails() public { - skipIfUnoptimized(); - - // If OPCM V2 is enabled because we do not use environment variables for OPCM V2. - skipIfDevFeatureEnabled(DevFeatures.OPCM_V2); - - // Test that mocking each individual getter causes verification to fail - _assertOnOpcmGetter(IOPContractsManager.superchainConfig.selector); - _assertOnOpcmGetter(IOPContractsManager.protocolVersions.selector); - } - /// @notice Tests that the ABI getter validation succeeds when all getters are accounted for. function test_validateAllGettersAccounted_succeeds() public { // This should succeed as setUp() configures all expected getters diff --git a/packages/contracts-bedrock/test/setup/CommonTest.sol b/packages/contracts-bedrock/test/setup/CommonTest.sol index 8fca5316f5a..612b48b677c 100644 --- a/packages/contracts-bedrock/test/setup/CommonTest.sol +++ b/packages/contracts-bedrock/test/setup/CommonTest.sol @@ -28,8 +28,6 @@ abstract contract CommonTest is Test, Setup, Events { address alice; address bob; - bytes32 constant nonZeroHash = keccak256(abi.encode("NON_ZERO")); - /// @notice The default initial bond value for dispute games. uint256 constant DEFAULT_DISPUTE_GAME_INIT_BOND = 0.08 ether; @@ -55,7 +53,6 @@ abstract contract CommonTest is Test, Setup, Events { IOptimismMintableERC20Full L2Token; ILegacyMintableERC20Full LegacyL2Token; ERC20 NativeL2Token; - IOptimismMintableERC20Full RemoteL1Token; function setUp() public virtual override { // Setup.setup() may switch the tests over to a newly forked network. Therefore @@ -189,14 +186,6 @@ abstract contract CommonTest is Test, Setup, Events { NativeL2Token = new ERC20("Native L2 Token", "L2T"); - RemoteL1Token = IOptimismMintableERC20Full( - l1OptimismMintableERC20Factory.createStandardL2Token( - address(NativeL2Token), - string(abi.encodePacked("L1-", NativeL2Token.name())), - string(abi.encodePacked("L1-", NativeL2Token.symbol())) - ) - ); - BadL1Token = ERC20( l1OptimismMintableERC20Factory.createStandardL2Token( address(1), diff --git a/packages/contracts-bedrock/test/setup/DisputeGames.sol b/packages/contracts-bedrock/test/setup/DisputeGames.sol index 4a7bcf13415..74a11a9f006 100644 --- a/packages/contracts-bedrock/test/setup/DisputeGames.sol +++ b/packages/contracts-bedrock/test/setup/DisputeGames.sol @@ -68,11 +68,6 @@ library DisputeGames { 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(); - } - /// @notice Checks if the game type is a super game type function isSuperGame(GameType _gameType) internal pure returns (bool) { return GameTypes.isSuperGame(_gameType); @@ -125,35 +120,6 @@ library DisputeGames { } } - /// @notice Gets the absolute prestate for a game type, handling both v1 and v2 dispute games. - /// V1 games store the prestate on the game implementation, v2 games store it in gameArgs. - /// Returns Claim.wrap(bytes32(0)) if no implementation exists for the game type. - /// @param _dgf The dispute game factory. - /// @param _gameType The game type to get the prestate for. - /// @return prestate_ The absolute prestate claim. - function getGameImplPrestate( - IDisputeGameFactory _dgf, - GameType _gameType - ) - internal - view - returns (Claim prestate_) - { - // Return zero if no implementation exists for this game type - address gameImpl = address(_dgf.gameImpls(_gameType)); - if (gameImpl == address(0)) { - return Claim.wrap(bytes32(0)); - } - - (bool gameArgsExist, bytes memory gameArgsData) = _getGameArgs(_dgf, _gameType); - if (gameArgsExist) { - LibGameArgs.GameArgs memory gameArgs = LibGameArgs.decode(gameArgsData); - prestate_ = Claim.wrap(gameArgs.absolutePrestate); - } else { - prestate_ = IFaultDisputeGame(gameImpl).absolutePrestate(); - } - } - /// @notice Gets the DelayedWETH for a game type, handling both v1 and v2 dispute games. /// V1 games store the prestate on the game implementation, v2 games store it in gameArgs. /// Returns address(0) if no implementation exists for the game type. diff --git a/packages/contracts-bedrock/test/setup/Events.sol b/packages/contracts-bedrock/test/setup/Events.sol index 7a87a29dc27..9c5922fce3c 100644 --- a/packages/contracts-bedrock/test/setup/Events.sol +++ b/packages/contracts-bedrock/test/setup/Events.sol @@ -46,14 +46,6 @@ abstract contract Events { bool isCreation, bytes data ); - event WhatHappened(bool success, bytes returndata); - - event OutputProposed( - bytes32 indexed outputRoot, uint256 indexed l2OutputIndex, uint256 indexed l2BlockNumber, uint256 l1Timestamp - ); - - event OutputsDeleted(uint256 indexed prevNextOutputIndex, uint256 indexed newNextOutputIndex); - event Withdrawal(uint256 value, address to, address from); event Withdrawal(uint256 value, address to, address from, Types.WithdrawalNetwork withdrawalNetwork); @@ -77,10 +69,6 @@ abstract contract Events { address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data ); - event DepositFailed( - address indexed l1Token, address indexed l2Token, address indexed from, address to, uint256 amount, bytes data - ); - event ETHBridgeInitiated(address indexed from, address indexed to, uint256 amount, bytes data); event ETHBridgeFinalized(address indexed from, address indexed to, uint256 amount, bytes data); diff --git a/packages/contracts-bedrock/test/setup/FFIInterface.sol b/packages/contracts-bedrock/test/setup/FFIInterface.sol index cb516716d9a..2345757be42 100644 --- a/packages/contracts-bedrock/test/setup/FFIInterface.sol +++ b/packages/contracts-bedrock/test/setup/FFIInterface.sol @@ -293,52 +293,6 @@ contract FFIInterface { return (memRoot, proof); } - function getCannonMemoryProof2( - uint32 pc, - uint32 insn, - uint32 memAddr, - uint32 memVal, - uint32 memAddrForProof - ) - external - returns (bytes32, bytes memory) - { - string[] memory cmds = new string[](8); - cmds[0] = "scripts/go-ffi/go-ffi"; - cmds[1] = "diff"; - cmds[2] = "cannonMemoryProof2"; - cmds[3] = vm.toString(pc); - cmds[4] = vm.toString(insn); - cmds[5] = vm.toString(memAddr); - cmds[6] = vm.toString(memVal); - cmds[7] = vm.toString(memAddrForProof); - bytes memory result = Process.run(cmds); - (bytes32 memRoot, bytes memory proof) = abi.decode(result, (bytes32, bytes)); - return (memRoot, proof); - } - - function getCannonMemoryProofWrongLeaf( - uint32 pc, - uint32 insn, - uint32 memAddr, - uint32 memVal - ) - external - returns (bytes32, bytes memory) - { - string[] memory cmds = new string[](7); - cmds[0] = "scripts/go-ffi/go-ffi"; - cmds[1] = "diff"; - cmds[2] = "cannonMemoryProofWrongLeaf"; - cmds[3] = vm.toString(pc); - cmds[4] = vm.toString(insn); - cmds[5] = vm.toString(memAddr); - cmds[6] = vm.toString(memVal); - bytes memory result = Process.run(cmds); - (bytes32 memRoot, bytes memory proof) = abi.decode(result, (bytes32, bytes)); - return (memRoot, proof); - } - function getCannonMemory64Proof(uint64 addr, uint64 value) external returns (bytes32, bytes memory) { string[] memory cmds = new string[](5); cmds[0] = "scripts/go-ffi/go-ffi"; diff --git a/packages/contracts-bedrock/test/setup/FeatureFlags.sol b/packages/contracts-bedrock/test/setup/FeatureFlags.sol index 4c55191a69d..4cbd8070e92 100644 --- a/packages/contracts-bedrock/test/setup/FeatureFlags.sol +++ b/packages/contracts-bedrock/test/setup/FeatureFlags.sol @@ -41,10 +41,6 @@ abstract contract FeatureFlags { console.log("Setup: DEV_FEATURE__OPTIMISM_PORTAL_INTEROP is enabled"); devFeatureBitmap |= DevFeatures.OPTIMISM_PORTAL_INTEROP; } - if (Config.devFeatureOpcmV2()) { - console.log("Setup: DEV_FEATURE__OPCM_V2 is enabled"); - devFeatureBitmap |= DevFeatures.OPCM_V2; - } if (Config.devFeatureL2CM()) { console.log("Setup: DEV_FEATURE__L2CM is enabled"); devFeatureBitmap |= DevFeatures.L2CM; @@ -69,8 +65,6 @@ abstract contract FeatureFlags { function getFeatureName(bytes32 _feature) public pure returns (string memory) { if (_feature == DevFeatures.OPTIMISM_PORTAL_INTEROP) { return "DEV_FEATURE__OPTIMISM_PORTAL_INTEROP"; - } else if (_feature == DevFeatures.OPCM_V2) { - return "DEV_FEATURE__OPCM_V2"; } else if (_feature == DevFeatures.L2CM) { return "DEV_FEATURE__L2CM"; } else if (_feature == DevFeatures.ZK_DISPUTE_GAME) { diff --git a/packages/contracts-bedrock/test/setup/ForkL1Live.s.sol b/packages/contracts-bedrock/test/setup/ForkL1Live.s.sol index 743ceccfca2..fbd8ad94e24 100644 --- a/packages/contracts-bedrock/test/setup/ForkL1Live.s.sol +++ b/packages/contracts-bedrock/test/setup/ForkL1Live.s.sol @@ -18,7 +18,6 @@ import { Config } from "scripts/libraries/Config.sol"; // Libraries import { GameType, GameTypes, Claim, Proposal, Hash } from "src/dispute/lib/Types.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; -import { DevFeatures } from "src/libraries/DevFeatures.sol"; import { LibString } from "@solady/utils/LibString.sol"; import { LibGameArgs } from "src/dispute/lib/LibGameArgs.sol"; @@ -30,11 +29,9 @@ import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol"; import { IAddressManager } from "interfaces/legacy/IAddressManager.sol"; import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; import { IProxyAdmin } from "interfaces/universal/IProxyAdmin.sol"; -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol"; import { IETHLockbox } from "interfaces/L1/IETHLockbox.sol"; import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol"; -import { IOPContractsManagerUpgrader } from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; @@ -135,10 +132,6 @@ contract ForkL1Live is Deployer, StdAssertions, FeatureFlags { // Superchain shared contracts saveProxyAndImpl("SuperchainConfig", superchainToml, ".superchain_config_addr"); saveProxyAndImpl("ProtocolVersions", superchainToml, ".protocol_versions_addr"); - artifacts.save( - "OPContractsManager", vm.parseTomlAddress(standardVersionsToml, "$.RELEASE.op_contracts_manager.address") - ); - // Core contracts artifacts.save("ProxyAdmin", vm.parseJsonAddress(addressesJson, string.concat("$.", chainId, ".ProxyAdmin"))); saveProxyAndImpl("SystemConfig", opToml, ".addresses.SystemConfigProxy"); @@ -212,41 +205,6 @@ contract ForkL1Live is Deployer, StdAssertions, FeatureFlags { deploy.deployImplementations(); } - /// @notice Performs a single OPCM upgrade. - /// @param _opcm The OPCM contract to upgrade. - /// @param _delegateCaller The address of the upgrader to use for the upgrade. - function _doUpgrade(IOPContractsManager _opcm, address _delegateCaller) internal { - ISystemConfig systemConfig = ISystemConfig(artifacts.mustGetAddress("SystemConfigProxy")); - IOPContractsManager.OpChainConfig[] memory opChains = new IOPContractsManager.OpChainConfig[](1); - opChains[0] = IOPContractsManager.OpChainConfig({ - systemConfigProxy: systemConfig, - cannonPrestate: Claim.wrap(bytes32(keccak256("cannonPrestate"))), - cannonKonaPrestate: Claim.wrap(bytes32(keccak256("cannonKonaPrestate"))) - }); - - // Execute the SuperchainConfig upgrade. - // Always try to upgrade the SuperchainConfig. Not always necessary but easier to do it - // every time rather than adding or removing this code for each upgrade. - ISuperchainConfig superchainConfig = ISuperchainConfig(artifacts.mustGetAddress("SuperchainConfigProxy")); - IProxyAdmin superchainProxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(superchainConfig))); - address superchainPAO = superchainProxyAdmin.owner(); - vm.prank(superchainPAO, true); - (bool success, bytes memory reason) = - address(_opcm).delegatecall(abi.encodeCall(IOPContractsManager.upgradeSuperchainConfig, (superchainConfig))); - if (success == false) { - assertTrue( - bytes4(reason) - == IOPContractsManagerUpgrader.OPContractsManagerUpgrader_SuperchainConfigAlreadyUpToDate.selector, - "Revert reason other than SuperchainConfigAlreadyUpToDate" - ); - } - - // Upgrade the chain. - vm.prank(_delegateCaller, true); - (bool upgradeSuccess,) = address(_opcm).delegatecall(abi.encodeCall(IOPContractsManager.upgrade, (opChains))); - assertTrue(upgradeSuccess, "upgrade failed"); - } - /// @notice Performs a single OPCM V2 upgrade. /// @param _opcm The OPCM V2 contract to upgrade. /// @param _delegateCaller The address of the upgrader to use for the upgrade. @@ -473,13 +431,8 @@ contract ForkL1Live is Deployer, StdAssertions, FeatureFlags { PastUpgrades.runPastUpgrades(upgrader, systemConfig, superchainConfig, disputeGameFactoryForPastUpgrades); // Current upgrade. - if (isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - IOPContractsManagerV2 opcmV2 = IOPContractsManagerV2(artifacts.mustGetAddress("OPContractsManagerV2")); - _doUpgradeV2(opcmV2, upgrader); - } else { - IOPContractsManager opcm = IOPContractsManager(artifacts.mustGetAddress("OPContractsManager")); - _doUpgrade(opcm, upgrader); - } + IOPContractsManagerV2 opcmV2 = IOPContractsManagerV2(artifacts.mustGetAddress("OPContractsManagerV2")); + _doUpgradeV2(opcmV2, upgrader); console.log("ForkL1Live: Saving newly deployed contracts"); diff --git a/packages/contracts-bedrock/test/setup/PastUpgrades.sol b/packages/contracts-bedrock/test/setup/PastUpgrades.sol index 54662bd7514..4a56b612a42 100644 --- a/packages/contracts-bedrock/test/setup/PastUpgrades.sol +++ b/packages/contracts-bedrock/test/setup/PastUpgrades.sol @@ -17,7 +17,6 @@ import { Claim, GameTypes } from "src/dispute/lib/Types.sol"; import { SemverComp } from "src/libraries/SemverComp.sol"; // Interfaces -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; import { IOPContractsManagerV2 } from "interfaces/L1/opcm/IOPContractsManagerV2.sol"; import { IOPContractsManagerUtils } from "interfaces/L1/opcm/IOPContractsManagerUtils.sol"; import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; @@ -111,11 +110,12 @@ library PastUpgrades { return; } - // Resolve on-chain versions and filter to >= 6.x.x + // Resolve on-chain versions and filter to >= 7.x.x (V2 OPCMs only). + // V1 OPCMs (6.x.x) use the IOPContractsManager interface and are not supported. ResolvedOPCM[] memory resolved = _resolveAndFilterOPCMs(opcms); if (resolved.length == 0) { - console.log("PastUpgrades: No OPCMs >= 6.x.x found for chain %d", block.chainid); + console.log("PastUpgrades: No OPCMs >= 7.x.x found for chain %d", block.chainid); return; } @@ -147,52 +147,10 @@ library PastUpgrades { console.log("PastUpgrades: Running upgrade with OPCM %s (v%s)", opcm.addr, opcm.opcmVersion); - if (opcm.semver.major == 6) { - executeV1Upgrade(opcm.addr, _delegateCaller, _systemConfig, _superchainConfig); - } else { - executeV2Upgrade(opcm.addr, _delegateCaller, _systemConfig, _superchainConfig, _disputeGameFactory); - } + executeV2Upgrade(opcm.addr, _delegateCaller, _systemConfig, _superchainConfig, _disputeGameFactory); } } - /// @notice Executes a single V1 OPCM upgrade. - /// @param _opcm The V1 OPCM contract address. - /// @param _delegateCaller The address to use as the delegate caller. - /// @param _systemConfig The SystemConfig proxy address. - /// @param _superchainConfig The SuperchainConfig proxy address. - function executeV1Upgrade( - address _opcm, - address _delegateCaller, - ISystemConfig _systemConfig, - ISuperchainConfig _superchainConfig - ) - internal - { - // Get the superchain PAO - IProxyAdmin superchainProxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(_superchainConfig))); - address superchainPAO = superchainProxyAdmin.owner(); - - // Upgrade the SuperchainConfig first - vm.prank(superchainPAO, true); - (bool scSuccess,) = - _opcm.delegatecall(abi.encodeCall(IOPContractsManager.upgradeSuperchainConfig, (_superchainConfig))); - // Acceptable to fail if already up to date - scSuccess; - - // Build the OpChainConfig for the chain being upgraded - IOPContractsManager.OpChainConfig[] memory opChainConfigs = new IOPContractsManager.OpChainConfig[](1); - opChainConfigs[0] = IOPContractsManager.OpChainConfig({ - systemConfigProxy: _systemConfig, - cannonPrestate: Claim.wrap(DUMMY_CANNON_PRESTATE), - cannonKonaPrestate: Claim.wrap(DUMMY_CANNON_KONA_PRESTATE) - }); - - // Execute the OPCMv1 chain upgrade - vm.prank(_delegateCaller, true); - (bool upgradeSuccess,) = _opcm.delegatecall(abi.encodeCall(IOPContractsManager.upgrade, (opChainConfigs))); - require(upgradeSuccess, "PastUpgrades: OPCMv1 upgrade failed"); - } - /// @notice Executes a single V2 OPCM upgrade. /// @param _opcm The V2 OPCM contract address. /// @param _delegateCaller The address to use as the delegate caller. @@ -325,7 +283,8 @@ library PastUpgrades { } } - /// @notice Resolves on-chain versions for OPCMs and filters to >= 6.x.x + /// @notice Resolves on-chain versions for OPCMs and filters to >= 7.x.x (V2 OPCMs only). + /// V1 OPCMs (6.x.x) use the IOPContractsManager interface and are not compatible. /// @param _opcms The OPCMs from FFI /// @return resolved_ The resolved and filtered OPCMs function _resolveAndFilterOPCMs(OPCMInfo[] memory _opcms) private view returns (ResolvedOPCM[] memory resolved_) { @@ -334,7 +293,7 @@ library PastUpgrades { for (uint256 i = 0; i < _opcms.length; i++) { string memory opcmVersion = ISemver(_opcms[i].addr).version(); SemverComp.Semver memory sv = SemverComp.parse(opcmVersion); - if (sv.major >= 6) { + if (sv.major >= 7) { count++; } } @@ -345,7 +304,7 @@ library PastUpgrades { for (uint256 i = 0; i < _opcms.length; i++) { string memory opcmVersion = ISemver(_opcms[i].addr).version(); SemverComp.Semver memory sv = SemverComp.parse(opcmVersion); - if (sv.major >= 6) { + if (sv.major >= 7) { resolved_[idx] = ResolvedOPCM({ addr: _opcms[i].addr, opcmVersion: opcmVersion, semver: sv }); idx++; } diff --git a/packages/contracts-bedrock/test/setup/Setup.sol b/packages/contracts-bedrock/test/setup/Setup.sol index 0882193995a..4e82600911f 100644 --- a/packages/contracts-bedrock/test/setup/Setup.sol +++ b/packages/contracts-bedrock/test/setup/Setup.sol @@ -26,10 +26,8 @@ import { Predeploys } from "src/libraries/Predeploys.sol"; import { Preinstalls } from "src/libraries/Preinstalls.sol"; import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; import { Chains } from "scripts/libraries/Chains.sol"; -import { DevFeatures } from "src/libraries/DevFeatures.sol"; - // Interfaces -import { IOPContractsManager } from "interfaces/L1/IOPContractsManager.sol"; + import { IOptimismPortal2 as IOptimismPortal } from "interfaces/L1/IOptimismPortal2.sol"; import { IETHLockbox } from "interfaces/L1/IETHLockbox.sol"; import { IL1CrossDomainMessenger } from "interfaces/L1/IL1CrossDomainMessenger.sol"; @@ -119,7 +117,6 @@ abstract contract Setup is FeatureFlags { IFaultDisputeGame faultDisputeGame; IDelayedWETH delayedWeth; IPermissionedDisputeGame permissionedDisputeGame; - IDelayedWETH delayedWETHPermissionedGameProxy; // L1 contracts - core address proxyAdminOwner; @@ -137,7 +134,6 @@ abstract contract Setup is FeatureFlags { IProtocolVersions protocolVersions; ISuperchainConfig superchainConfig; IDataAvailabilityChallenge dataAvailabilityChallenge; - IOPContractsManager opcm; IOPContractsManagerV2 opcmV2; IBigStepper mips; @@ -394,11 +390,7 @@ abstract contract Setup is FeatureFlags { anchorStateRegistry = IAnchorStateRegistry(artifacts.mustGetAddress("AnchorStateRegistryProxy")); disputeGameFactory = IDisputeGameFactory(artifacts.mustGetAddress("DisputeGameFactoryProxy")); delayedWeth = IDelayedWETH(artifacts.mustGetAddress("DelayedWETHProxy")); - if (isDevFeatureEnabled(DevFeatures.OPCM_V2)) { - opcmV2 = IOPContractsManagerV2(artifacts.mustGetAddress("OPContractsManagerV2")); - } else { - opcm = IOPContractsManager(artifacts.mustGetAddress("OPContractsManager")); - } + opcmV2 = IOPContractsManagerV2(artifacts.mustGetAddress("OPContractsManagerV2")); proxyAdmin = IProxyAdmin(artifacts.mustGetAddress("ProxyAdmin")); proxyAdminOwner = proxyAdmin.owner(); superchainProxyAdmin = IProxyAdmin(EIP1967Helper.getAdmin(address(superchainConfig))); diff --git a/packages/contracts-bedrock/test/vendor/Initializable.t.sol b/packages/contracts-bedrock/test/vendor/Initializable.t.sol index c68145c8226..c4fee59eed4 100644 --- a/packages/contracts-bedrock/test/vendor/Initializable.t.sol +++ b/packages/contracts-bedrock/test/vendor/Initializable.t.sol @@ -15,6 +15,7 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; // Interfaces +import { IETHLockbox } from "interfaces/L1/IETHLockbox.sol"; import { ISystemConfig } from "interfaces/L1/ISystemConfig.sol"; import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; import { IResourceMetering } from "interfaces/L1/IResourceMetering.sol"; @@ -22,7 +23,6 @@ import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.so import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; import { ProtocolVersion } from "interfaces/L1/IProtocolVersions.sol"; import { IOptimismPortal2 } from "interfaces/L1/IOptimismPortal2.sol"; -import { IOptimismPortalInterop } from "interfaces/L1/IOptimismPortalInterop.sol"; /// @title Initializer_Test /// @dev Ensures that the `initialize()` function on contracts cannot be called more than @@ -123,14 +123,12 @@ contract Initializer_Test is CommonTest { ); if (isDevFeatureEnabled(DevFeatures.OPTIMISM_PORTAL_INTEROP)) { - // OptimismPortal2Impl contracts.push( InitializeableContract({ name: "OptimismPortal2Impl", target: EIP1967Helper.getImplementation(address(optimismPortal2)), initCalldata: abi.encodeCall( - IOptimismPortalInterop(payable(optimismPortal2)).initialize, - (systemConfig, anchorStateRegistry, ethLockbox) + optimismPortal2.initialize, (systemConfig, anchorStateRegistry, ethLockbox) ) }) ); @@ -140,18 +138,18 @@ contract Initializer_Test is CommonTest { name: "OptimismPortal2Proxy", target: address(optimismPortal2), initCalldata: abi.encodeCall( - IOptimismPortalInterop(payable(optimismPortal2)).initialize, - (systemConfig, anchorStateRegistry, ethLockbox) + optimismPortal2.initialize, (systemConfig, anchorStateRegistry, ethLockbox) ) }) ); } else { - // OptimismPortal2Impl contracts.push( InitializeableContract({ name: "OptimismPortal2Impl", target: EIP1967Helper.getImplementation(address(optimismPortal2)), - initCalldata: abi.encodeCall(optimismPortal2.initialize, (systemConfig, anchorStateRegistry)) + initCalldata: abi.encodeCall( + optimismPortal2.initialize, (systemConfig, anchorStateRegistry, IETHLockbox(address(0))) + ) }) ); // OptimismPortal2Proxy @@ -159,7 +157,9 @@ contract Initializer_Test is CommonTest { InitializeableContract({ name: "OptimismPortal2Proxy", target: address(optimismPortal2), - initCalldata: abi.encodeCall(optimismPortal2.initialize, (systemConfig, anchorStateRegistry)) + initCalldata: abi.encodeCall( + optimismPortal2.initialize, (systemConfig, anchorStateRegistry, IETHLockbox(address(0))) + ) }) ); } @@ -383,7 +383,7 @@ contract Initializer_Test is CommonTest { function test_cannotReinitialize_succeeds() public { // Collect exclusions. uint256 j; - string[] memory excludes = new string[](11); + string[] memory excludes = new string[](9); // Contract is currently not being deployed as part of the standard deployment script. excludes[j++] = "src/L2/OptimismSuperchainERC20.sol"; // Periphery contracts don't get deployed as part of the standard deployment script. @@ -398,10 +398,6 @@ contract Initializer_Test is CommonTest { excludes[j++] = "src/dispute/SuperFaultDisputeGame.sol"; excludes[j++] = "src/dispute/SuperPermissionedDisputeGame.sol"; excludes[j++] = "src/dispute/zk/ZKDisputeGame.sol"; - // TODO: Eventually remove this exclusion. Same reason as above dispute contracts. - excludes[j++] = "src/L1/OPContractsManager.sol"; - // TODO: Eventually remove this exclusion. Same reason as above dispute contracts. - excludes[j++] = "src/L1/OptimismPortalInterop.sol"; // L2 contract initialization is tested in Predeploys.t.sol excludes[j++] = "src/L2/*"; excludes[j++] = "src/L1/FeesDepositor.sol"; diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 8891089c44d..73ada2844f6 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -106,9 +106,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.2.31" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9d22005bf31b018f31ef9ecadb5d2c39cf4f6acc8db0456f72c815f3d7f757" +checksum = "f4e9e31d834fe25fe991b8884e4b9f0e59db4a97d86e05d1464d6899c013cd62" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -121,9 +121,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e56cae3909bcb2347f77c0f318ef5eb7e131ea6d0a94d31f8bfb6e4c5e3c7c7" +checksum = "7f16daaf7e1f95f62c6c3bf8a3fc3d78b08ae9777810c0bb5e94966c7cd57ef0" dependencies = [ "alloy-eips", "alloy-primitives", @@ -149,9 +149,9 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4394690a8a64757316c57c57f2c663bf8395febb4c4baa049a058ebd122b668" +checksum = "118998d9015332ab1b4720ae1f1e3009491966a0349938a1f43ff45a8a4c6299" dependencies = [ "alloy-consensus", "alloy-eips", @@ -240,9 +240,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b97433ffdb356d11b6c89b08c69a787b9f55d787cdeee733c12fdf85d465ef1" +checksum = "e6ef28c9fdad22d4eec52d894f5f2673a0895f1e5ef196734568e68c0f6caca8" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -266,31 +266,29 @@ dependencies = [ [[package]] name = "alloy-evm" -version = "0.27.3" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b991c370ce44e70a3a9e474087e3d65e42e66f967644ad729dc4cec09a21fd09" +checksum = "e13146597a586a4166ac31b192883e08c044272d6b8c43de231ee1f43dd9a115" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-hardforks", - "alloy-op-hardforks", "alloy-primitives", "alloy-rpc-types-engine", "alloy-rpc-types-eth", "alloy-sol-types", "auto_impl", "derive_more", - "op-alloy", - "op-revm", "revm", "thiserror 2.0.18", + "tracing", ] [[package]] name = "alloy-genesis" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6173ced325833e40ccb781bb372c720df638a966bad6ed6733682b6bff63d855" +checksum = "bbf9480307b09d22876efb67d30cadd9013134c21f3a17ec9f93fd7536d38024" dependencies = [ "alloy-eips", "alloy-primitives", @@ -329,9 +327,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae95062f48461967424eecb1e1ab703e493b6a7aca7f9c327cc1c06758eb6ec2" +checksum = "422d110f1c40f1f8d0e5562b0b649c35f345fccb7093d9f02729943dcd1eef71" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -344,9 +342,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464d9c2c5bca3ff3f020f2ab502629043486a1b3645c5c11613c1dade4eb6f5e" +checksum = "7197a66d94c4de1591cdc16a9bcea5f8cccd0da81b865b49aef97b1b4016e0fa" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -370,9 +368,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2158d382ef9743ae7185c9fcd33cd9a99967419fdcd5eebc83ff7c0e79cad2bc" +checksum = "eb82711d59a43fdfd79727c99f270b974c784ec4eb5728a0d0d22f26716c87ef" dependencies = [ "alloy-consensus", "alloy-eips", @@ -383,7 +381,7 @@ dependencies = [ [[package]] name = "alloy-op-evm" -version = "0.26.3" +version = "0.30.0" dependencies = [ "alloy-consensus", "alloy-eips", @@ -444,9 +442,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b08405e82effb4985f7cbe83d5067730e79893c8699793c1e113043ffeac9d" +checksum = "bf6b18b929ef1d078b834c3631e9c925177f3b23ddc6fa08a722d13047205876" dependencies = [ "alloy-chains", "alloy-consensus", @@ -489,9 +487,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f39b713fb8fd7abb6ee7601d467f71d2c2541b7799dd02d3a8f9f650d1d3f6d" +checksum = "5ad54073131e7292d4e03e1aa2287730f737280eb160d8b579fb31939f558c11" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -504,7 +502,7 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", - "tower 0.5.3", + "tower", "tracing", "wasmtimer", ] @@ -533,9 +531,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96846729dd095dd5a87bf5bd8efea2345ca41ceab6dda212c49f5c8ca6e2a536" +checksum = "94fcc9604042ca80bd37aa5e232ea1cd851f337e31e2babbbb345bc0b1c30de3" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -551,7 +549,7 @@ dependencies = [ "serde_json", "tokio", "tokio-stream", - "tower 0.5.3", + "tower", "tracing", "url", "wasmtimer", @@ -559,9 +557,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f20059ff046049aae59f6e19d96462214ad3290cf9920394309dd7ffc284390" +checksum = "4faad925d3a669ffc15f43b3deec7fbdf2adeb28a4d6f9cf4bc661698c0f8f4b" dependencies = [ "alloy-primitives", "alloy-rpc-types-debug", @@ -573,9 +571,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-admin" -version = "1.7.3" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42325c117af3a9e49013f881c1474168db57978e02085fc9853a1c89e0562740" +checksum = "b38080c2b01ad1bacbd3583cf7f6f800e5e0ffc11eaddaad7321225733a2d818" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -585,9 +583,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "1.7.3" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a3100b76987c1b1dc81f3abe592b7edc29e92b1242067a69d65e0030b35cf9" +checksum = "47df51bedb3e6062cb9981187a51e86d0d64a4de66eb0855e9efe6574b044ddf" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -597,9 +595,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b71da7e5cdd0d5ffebc459f5987888fd3380969c2f94f8cb652ad91ae51bba" +checksum = "3823026d1ed239a40f12364fac50726c8daf1b6ab8077a97212c5123910429ed" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -608,9 +606,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-beacon" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3569433bc2cddd4f00b1dd533a38a07512b55e62d11f662fde20930b613b57" +checksum = "f526dbd7bb039327cfd0ccf18c8a29ffd7402616b0c7a0239512bf8417d544c7" dependencies = [ "alloy-eips", "alloy-primitives", @@ -628,9 +626,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-debug" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d9d9a32059dff4809fe4db016db13ba1a20babf767c4cd26e97c93ee9efe4c" +checksum = "2145138f3214928f08cd13da3cb51ef7482b5920d8ac5a02ecd4e38d1a8f6d1e" dependencies = [ "alloy-primitives", "derive_more", @@ -640,9 +638,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f083328dbf7aa5abfe5c0a7758ec9acc86a45bfbcfb45c54186c6caa78036f2a" +checksum = "bb9b97b6e7965679ad22df297dda809b11cebc13405c1b537e5cffecc95834fa" dependencies = [ "alloy-consensus", "alloy-eips", @@ -661,9 +659,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1641df7ef4d15cd43843d399252c90a95abf465a67e2a2b2fd76f4e93cc60e15" +checksum = "59c095f92c4e1ff4981d89e9aa02d5f98c762a1980ab66bec49c44be11349da2" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -683,9 +681,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-mev" -version = "1.7.3" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe85bf3be739126aa593dca9fb3ab13ca93fa7873e6f2247be64d7f2cb15f34a" +checksum = "8eae9c65ff60dcc262247b6ebb5ad391ddf36d09029802c1768c5723e0cfa2f4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -698,9 +696,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00e2d5ab1f7310c7ecd69962af8c99d2557335ff8cf1baf39c8ff6eec9c171d" +checksum = "2e5a4d010f86cd4e01e5205ec273911e538e1738e76d8bafe9ecd245910ea5a3" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -712,9 +710,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "1.7.3" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d459f902a2313737bc66d18ed094c25d2aeb268b74d98c26bbbda2aa44182ab0" +checksum = "942d26a2ca8891b26de4a8529d21091e21c1093e27eb99698f1a86405c76b1ff" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -724,9 +722,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1c2c0b5f024814f1c04ae76ff71862d06c836e7d67102daf8a557e5056be68" +checksum = "11ece63b89294b8614ab3f483560c08d016930f842bf36da56bf0b764a15c11e" dependencies = [ "alloy-primitives", "arbitrary", @@ -736,9 +734,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f59de30d9d3b13ce6a1b90e85270dc086e4e4733aaa12b250fb30e1eb35849" +checksum = "43f447aefab0f1c0649f71edc33f590992d4e122bc35fb9cdbbf67d4421ace85" dependencies = [ "alloy-primitives", "async-trait", @@ -751,9 +749,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e64733ea58cfb393c901047638e9ff6890c0a45dc5855bfa077f8bace0f9f9" +checksum = "f721f4bf2e4812e5505aaf5de16ef3065a8e26b9139ac885862d00b5a55a659a" dependencies = [ "alloy-consensus", "alloy-network", @@ -840,9 +838,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec9c680a7ee0879aa27ea2e347f14e3a973a262e4325964fa1ab062b8a796064" +checksum = "8098f965442a9feb620965ba4b4be5e2b320f4ec5a3fff6bfa9e1ff7ef42bed1" dependencies = [ "alloy-json-rpc", "auto_impl", @@ -855,7 +853,7 @@ dependencies = [ "serde_json", "thiserror 2.0.18", "tokio", - "tower 0.5.3", + "tower", "tracing", "url", "wasmtimer", @@ -863,9 +861,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9abaedb9123ebe4b1527bc88a0409d65b2727c3de89a289284ba91ad70ae99" +checksum = "e8597d36d546e1dab822345ad563243ec3920e199322cb554ce56c8ef1a1e2e7" dependencies = [ "alloy-json-rpc", "alloy-rpc-types-engine", @@ -878,16 +876,16 @@ dependencies = [ "jsonwebtoken", "reqwest 0.13.2", "serde_json", - "tower 0.5.3", + "tower", "tracing", "url", ] [[package]] name = "alloy-transport-ipc" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74911eda4fd7ef12f446b1661f11787f9fb31bde4ab4a0a68efcac9b98cfdf" +checksum = "a1bd98c3870b8a44b79091dde5216a81d58ffbc1fd8ed61b776f9fee0f3bdf20" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -905,9 +903,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "130762ef3e6c0fb7dc1b855d4f359eb8ea6f2df2f800f40aa52d27737bf640f1" +checksum = "ec3ab7a72b180992881acc112628b7668337a19ce15293ee974600ea7b693691" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -916,7 +914,7 @@ dependencies = [ "rustls", "serde_json", "tokio", - "tokio-tungstenite 0.28.0", + "tokio-tungstenite", "tracing", "url", "ws_stream_wasm", @@ -944,9 +942,9 @@ dependencies = [ [[package]] name = "alloy-tx-macros" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a3684226a2220bb6e84a5ab74877e66628882336ecfba97482c9d473aa2b1cc" +checksum = "d69722eddcdf1ce096c3ab66cf8116999363f734eb36fe94a148f4f71c85da84" dependencies = [ "darling 0.23.0", "proc-macro2", @@ -1616,64 +1614,6 @@ dependencies = [ "fs_extra", ] -[[package]] -name = "axum" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower 0.5.3", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backoff" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" -dependencies = [ - "getrandom 0.2.17", - "instant", - "rand 0.8.5", -] - [[package]] name = "backon" version = "1.6.0" @@ -1696,7 +1636,7 @@ dependencies = [ "miniz_oxide 0.8.9", "object", "rustc-demangle", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -2359,7 +2299,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -2840,6 +2780,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -3351,12 +3300,6 @@ dependencies = [ "litrs", ] -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - [[package]] name = "downcast" version = "0.11.0" @@ -3423,7 +3366,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", - "serde", "signature", ] @@ -3489,12 +3431,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" -[[package]] -name = "endian-type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" - [[package]] name = "enr" version = "0.13.0" @@ -3710,15 +3646,21 @@ dependencies = [ "reth-db-api", "reth-engine-primitives", "reth-ethereum", + "reth-evm", "reth-network-peers", + "reth-node-api", "reth-node-builder", "reth-op", "reth-optimism-evm", "reth-optimism-flashblocks", "reth-optimism-forks", "reth-payload-builder", + "reth-payload-primitives", + "reth-primitives-traits", + "reth-provider", "reth-rpc-api", "reth-rpc-engine-api", + "reth-trie-common", "revm", "revm-primitives", "serde", @@ -4193,8 +4135,8 @@ dependencies = [ "libc", "log", "rustversion", - "windows-link", - "windows-result", + "windows-link 0.2.1", + "windows-result 0.4.1", ] [[package]] @@ -4729,12 +4671,10 @@ dependencies = [ "hyper-util", "log", "rustls", - "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.6", ] [[package]] @@ -4804,7 +4744,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.62.2", ] [[package]] @@ -4978,7 +4918,7 @@ dependencies = [ "rtnetlink", "system-configuration", "tokio", - "windows", + "windows 0.62.2", ] [[package]] @@ -5124,15 +5064,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - [[package]] name = "interprocess" version = "2.4.0" @@ -5363,7 +5294,7 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tokio-stream", - "tower 0.5.3", + "tower", "tracing", "wasm-bindgen-futures", ] @@ -5387,7 +5318,7 @@ dependencies = [ "serde_json", "thiserror 2.0.18", "tokio", - "tower 0.5.3", + "tower", "url", ] @@ -5427,7 +5358,7 @@ dependencies = [ "tokio", "tokio-stream", "tokio-util", - "tower 0.5.3", + "tower", "tracing", ] @@ -5452,7 +5383,7 @@ dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", - "tower 0.5.3", + "tower", ] [[package]] @@ -5465,7 +5396,7 @@ dependencies = [ "jsonrpsee-client-transport", "jsonrpsee-core", "jsonrpsee-types", - "tower 0.5.3", + "tower", "url", ] @@ -5540,7 +5471,7 @@ dependencies = [ "kona-registry", "libc", "libp2p", - "metrics-exporter-prometheus 0.18.1", + "metrics-exporter-prometheus", "metrics-process", "rstest", "serde", @@ -5666,7 +5597,6 @@ version = "0.1.2" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-json-rpc", "alloy-network", "alloy-primitives", "alloy-provider", @@ -5678,30 +5608,25 @@ dependencies = [ "arbitrary", "async-trait", "derive_more", - "http", "http-body-util", - "jsonrpsee-types", "kona-genesis", "kona-macros", "kona-protocol", "kona-registry", "metrics", - "metrics-exporter-prometheus 0.18.1", + "metrics-exporter-prometheus", "op-alloy-consensus", "op-alloy-network", "op-alloy-provider", "op-alloy-rpc-types", "op-alloy-rpc-types-engine", - "parking_lot", "rand 0.9.2", - "rollup-boost", - "rollup-boost-types", "rstest", "serde", "serde_json", "thiserror 2.0.18", "tokio", - "tower 0.5.3", + "tower", "tracing", "url", ] @@ -5938,7 +5863,6 @@ dependencies = [ "dirs", "discv5", "futures", - "http", "jsonrpsee", "kona-cli", "kona-derive", @@ -5959,7 +5883,6 @@ dependencies = [ "op-alloy-provider", "op-alloy-rpc-types-engine", "reqwest 0.13.2", - "rollup-boost", "rstest", "serde_json", "strum", @@ -6000,7 +5923,6 @@ dependencies = [ "derive_more", "discv5", "futures", - "http", "http-body-util", "jsonrpsee", "kona-derive", @@ -6023,14 +5945,13 @@ dependencies = [ "op-alloy-provider", "op-alloy-rpc-types-engine", "rand 0.9.2", - "rollup-boost", "rstest", "strum", "thiserror 2.0.18", "tokio", "tokio-stream", "tokio-util", - "tower 0.5.3", + "tower", "tracing", "url", ] @@ -6219,7 +6140,7 @@ dependencies = [ "serde_json", "thiserror 2.0.18", "tokio", - "tower 0.5.3", + "tower", "tracing", ] @@ -6286,7 +6207,6 @@ dependencies = [ "op-alloy-rpc-jsonrpsee", "op-alloy-rpc-types", "op-alloy-rpc-types-engine", - "rollup-boost", "serde", "serde_json", "thiserror 2.0.18", @@ -6409,7 +6329,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -7026,12 +6946,6 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - [[package]] name = "memchr" version = "2.8.0" @@ -7077,27 +6991,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "metrics-exporter-prometheus" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7399781913e5393588a8d8c6a2867bf85fb38eaf2502fdce465aad2dc6f034" -dependencies = [ - "base64 0.22.1", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "indexmap 2.13.0", - "ipnet", - "metrics", - "metrics-util 0.19.1", - "quanta", - "thiserror 1.0.69", - "tokio", - "tracing", -] - [[package]] name = "metrics-exporter-prometheus" version = "0.18.1" @@ -7111,7 +7004,7 @@ dependencies = [ "indexmap 2.13.0", "ipnet", "metrics", - "metrics-util 0.20.1", + "metrics-util", "quanta", "thiserror 2.0.18", "tokio", @@ -7131,27 +7024,7 @@ dependencies = [ "once_cell", "procfs", "rlimit", - "windows", -] - -[[package]] -name = "metrics-util" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8496cc523d1f94c1385dd8f0f0c2c480b2b8aeccb5b7e4485ad6365523ae376" -dependencies = [ - "aho-corasick", - "crossbeam-epoch", - "crossbeam-utils", - "hashbrown 0.15.5", - "indexmap 2.13.0", - "metrics", - "ordered-float", - "quanta", - "radix_trie", - "rand 0.9.2", - "rand_xoshiro", - "sketches-ddsketch", + "windows 0.62.2", ] [[package]] @@ -7277,13 +7150,10 @@ version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85f8024e1c8e71c778968af91d43700ce1d11b219d127d79fb2934153b82b42b" dependencies = [ - "async-lock", "crossbeam-channel", "crossbeam-epoch", "crossbeam-utils", "equivalent", - "event-listener", - "futures-util", "parking_lot", "portable-atomic", "smallvec", @@ -7437,15 +7307,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "nibble_vec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" -dependencies = [ - "smallvec", -] - [[package]] name = "nix" version = "0.30.1" @@ -7717,7 +7578,7 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "op-alloy" -version = "0.23.1" +version = "0.24.0" dependencies = [ "op-alloy-consensus", "op-alloy-network", @@ -7729,7 +7590,7 @@ dependencies = [ [[package]] name = "op-alloy-consensus" -version = "0.23.1" +version = "0.24.0" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7741,8 +7602,13 @@ dependencies = [ "alloy-signer", "arbitrary", "bincode 2.0.1", + "bytes", "derive_more", + "modular-bitfield", "rand 0.9.2", + "reth-codecs", + "reth-codecs-derive", + "reth-zstd-compressors", "serde", "serde_json", "serde_with", @@ -7757,7 +7623,7 @@ checksum = "a79f352fc3893dcd670172e615afef993a41798a1d3fc0db88a3e60ef2e70ecc" [[package]] name = "op-alloy-network" -version = "0.23.1" +version = "0.24.0" dependencies = [ "alloy-consensus", "alloy-network", @@ -7770,7 +7636,7 @@ dependencies = [ [[package]] name = "op-alloy-provider" -version = "0.23.1" +version = "0.24.0" dependencies = [ "alloy-network", "alloy-primitives", @@ -7783,7 +7649,7 @@ dependencies = [ [[package]] name = "op-alloy-rpc-jsonrpsee" -version = "0.23.1" +version = "0.24.0" dependencies = [ "alloy-primitives", "jsonrpsee", @@ -7791,19 +7657,22 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types" -version = "0.23.1" +version = "0.24.0" dependencies = [ "alloy-consensus", "alloy-eips", + "alloy-network", "alloy-network-primitives", "alloy-primitives", "alloy-rpc-types-eth", "alloy-serde", + "alloy-signer", "arbitrary", "derive_more", "jsonrpsee", "op-alloy-consensus", "rand 0.9.2", + "reth-rpc-traits", "serde", "serde_json", "similar-asserts", @@ -7812,7 +7681,7 @@ dependencies = [ [[package]] name = "op-alloy-rpc-types-engine" -version = "0.23.1" +version = "0.24.0" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7872,13 +7741,16 @@ dependencies = [ [[package]] name = "op-revm" -version = "15.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c92b75162c2ed1661849fa51683b11254a5b661798360a2c24be918edafd40" +version = "17.0.0" dependencies = [ + "alloy-primitives", + "alloy-sol-types", "auto_impl", "revm", + "rstest", "serde", + "serde_json", + "sha2", ] [[package]] @@ -7941,20 +7813,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "opentelemetry" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "236e667b670a5cdf90c258f5a55794ec5ac5027e960c224bff8367a59e1e6426" -dependencies = [ - "futures-core", - "futures-sink", - "js-sys", - "pin-project-lite", - "thiserror 2.0.18", - "tracing", -] - [[package]] name = "opentelemetry" version = "0.31.0" @@ -7975,26 +7833,12 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef6a1ac5ca3accf562b8c306fa8483c85f4390f768185ab775f242f7fe8fdcc2" dependencies = [ - "opentelemetry 0.31.0", + "opentelemetry", "tracing", "tracing-core", "tracing-subscriber 0.3.23", ] -[[package]] -name = "opentelemetry-http" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8863faf2910030d139fb48715ad5ff2f35029fc5f244f6d5f689ddcf4d26253" -dependencies = [ - "async-trait", - "bytes", - "http", - "opentelemetry 0.28.0", - "reqwest 0.12.28", - "tracing", -] - [[package]] name = "opentelemetry-http" version = "0.31.0" @@ -8004,76 +7848,39 @@ dependencies = [ "async-trait", "bytes", "http", - "opentelemetry 0.31.0", + "opentelemetry", "reqwest 0.12.28", ] [[package]] name = "opentelemetry-otlp" -version = "0.28.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bef114c6d41bea83d6dc60eb41720eedd0261a67af57b66dd2b84ac46c01d91" +checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" dependencies = [ - "async-trait", - "futures-core", "http", - "opentelemetry 0.28.0", - "opentelemetry-http 0.28.0", - "opentelemetry-proto 0.28.0", - "opentelemetry_sdk 0.28.0", - "prost 0.13.5", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost", "reqwest 0.12.28", - "serde_json", "thiserror 2.0.18", "tokio", - "tonic 0.12.3", + "tonic", "tracing", ] [[package]] -name = "opentelemetry-otlp" +name = "opentelemetry-proto" version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf" +checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" dependencies = [ - "http", - "opentelemetry 0.31.0", - "opentelemetry-http 0.31.0", - "opentelemetry-proto 0.31.0", - "opentelemetry_sdk 0.31.0", - "prost 0.14.3", - "reqwest 0.12.28", - "thiserror 2.0.18", - "tokio", - "tonic 0.14.5", - "tracing", -] - -[[package]] -name = "opentelemetry-proto" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f8870d3024727e99212eb3bb1762ec16e255e3e6f58eeb3dc8db1aa226746d" -dependencies = [ - "base64 0.22.1", - "hex", - "opentelemetry 0.28.0", - "opentelemetry_sdk 0.28.0", - "prost 0.13.5", - "serde", - "tonic 0.12.3", -] - -[[package]] -name = "opentelemetry-proto" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" -dependencies = [ - "opentelemetry 0.31.0", - "opentelemetry_sdk 0.31.0", - "prost 0.14.3", - "tonic 0.14.5", + "opentelemetry", + "opentelemetry_sdk", + "prost", + "tonic", "tonic-prost", ] @@ -8083,27 +7890,6 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e62e29dfe041afb8ed2a6c9737ab57db4907285d999ef8ad3a59092a36bdc846" -[[package]] -name = "opentelemetry_sdk" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84dfad6042089c7fc1f6118b7040dc2eb4ab520abbf410b79dc481032af39570" -dependencies = [ - "async-trait", - "futures-channel", - "futures-executor", - "futures-util", - "glob", - "opentelemetry 0.28.0", - "percent-encoding", - "rand 0.8.5", - "serde_json", - "thiserror 2.0.18", - "tokio", - "tokio-stream", - "tracing", -] - [[package]] name = "opentelemetry_sdk" version = "0.31.0" @@ -8113,7 +7899,7 @@ dependencies = [ "futures-channel", "futures-executor", "futures-util", - "opentelemetry 0.31.0", + "opentelemetry", "percent-encoding", "rand 0.9.2", "thiserror 2.0.18", @@ -8125,15 +7911,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "ordered-float" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" -dependencies = [ - "num-traits", -] - [[package]] name = "p256" version = "0.13.2" @@ -8173,7 +7950,6 @@ version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" dependencies = [ - "arbitrary", "arrayvec", "bitvec", "byte-slice-cast", @@ -8223,7 +7999,7 @@ dependencies = [ "libc", "redox_syscall 0.5.18", "smallvec", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -8490,7 +8266,7 @@ dependencies = [ "flate2", "num", "paste", - "prost 0.14.3", + "prost", ] [[package]] @@ -8695,16 +8471,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "prost" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" -dependencies = [ - "bytes", - "prost-derive 0.13.5", -] - [[package]] name = "prost" version = "0.14.3" @@ -8712,20 +8478,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" dependencies = [ "bytes", - "prost-derive 0.14.3", -] - -[[package]] -name = "prost-derive" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" -dependencies = [ - "anyhow", - "itertools 0.14.0", - "proc-macro2", - "quote", - "syn 2.0.117", + "prost-derive", ] [[package]] @@ -8888,16 +8641,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" -[[package]] -name = "radix_trie" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" -dependencies = [ - "endian-type", - "nibble_vec", -] - [[package]] name = "rancor" version = "0.1.1" @@ -9237,32 +8980,23 @@ dependencies = [ "http-body", "http-body-util", "hyper", - "hyper-rustls", "hyper-util", "js-sys", "log", "percent-encoding", "pin-project-lite", - "quinn", - "rustls", - "rustls-native-certs", - "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-rustls", - "tokio-util", - "tower 0.5.3", + "tower", "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", "web-sys", - "webpki-roots 1.0.6", ] [[package]] @@ -9273,7 +9007,9 @@ checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ "base64 0.22.1", "bytes", + "futures-channel", "futures-core", + "futures-util", "http", "http-body", "http-body-util", @@ -9294,12 +9030,14 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-rustls", - "tower 0.5.3", + "tokio-util", + "tower", "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", ] @@ -9311,8 +9049,8 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" [[package]] name = "reth-basic-payload-builder" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9321,6 +9059,7 @@ dependencies = [ "futures-util", "metrics", "reth-chain-state", + "reth-execution-cache", "reth-metrics", "reth-payload-builder", "reth-payload-builder-primitives", @@ -9329,14 +9068,16 @@ dependencies = [ "reth-revm", "reth-storage-api", "reth-tasks", + "reth-trie-parallel", + "serde", "tokio", "tracing", ] [[package]] name = "reth-chain-state" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9367,8 +9108,8 @@ dependencies = [ [[package]] name = "reth-chainspec" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-chains", "alloy-consensus", @@ -9387,8 +9128,8 @@ dependencies = [ [[package]] name = "reth-cli" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-genesis", "clap", @@ -9396,13 +9137,12 @@ dependencies = [ "reth-cli-runner", "reth-db", "serde_json", - "shellexpand", ] [[package]] name = "reth-cli-commands" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-chains", "alloy-consensus", @@ -9411,6 +9151,7 @@ dependencies = [ "alloy-rlp", "arbitrary", "backon", + "blake3", "clap", "comfy-table", "crossterm", @@ -9426,7 +9167,8 @@ dependencies = [ "proptest", "proptest-arbitrary-interop", "ratatui", - "reqwest 0.12.28", + "rayon", + "reqwest 0.13.2", "reth-chainspec", "reth-cli", "reth-cli-runner", @@ -9487,8 +9229,8 @@ dependencies = [ [[package]] name = "reth-cli-runner" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "reth-tasks", "tokio", @@ -9497,8 +9239,8 @@ dependencies = [ [[package]] name = "reth-cli-util" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eips", "alloy-primitives", @@ -9511,14 +9253,16 @@ dependencies = [ "secp256k1 0.30.0", "serde", "thiserror 2.0.18", + "tikv-jemalloc-sys", "tikv-jemallocator", "tracy-client", ] [[package]] name = "reth-codecs" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf1df733d93427eb197cf80a7aaa68bff8949e1b59d34cde1ad410351a24136d" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9528,7 +9272,7 @@ dependencies = [ "arbitrary", "bytes", "modular-bitfield", - "op-alloy-consensus", + "parity-scale-codec", "reth-codecs-derive", "reth-zstd-compressors", "serde", @@ -9537,8 +9281,9 @@ dependencies = [ [[package]] name = "reth-codecs-derive" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d14acf8feadf1eed0734d1766b55b6c19a374d4cb140bc862880f96da33e7e5a" dependencies = [ "proc-macro2", "quote", @@ -9547,8 +9292,8 @@ dependencies = [ [[package]] name = "reth-config" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "eyre", "humantime-serde", @@ -9563,8 +9308,8 @@ dependencies = [ [[package]] name = "reth-consensus" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -9576,11 +9321,12 @@ dependencies = [ [[package]] name = "reth-consensus-common" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", + "alloy-primitives", "reth-chainspec", "reth-consensus", "reth-primitives-traits", @@ -9588,8 +9334,8 @@ dependencies = [ [[package]] name = "reth-consensus-debug-client" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9602,7 +9348,7 @@ dependencies = [ "derive_more", "eyre", "futures", - "reqwest 0.12.28", + "reqwest 0.13.2", "reth-node-api", "reth-primitives-traits", "reth-tracing", @@ -9614,8 +9360,8 @@ dependencies = [ [[package]] name = "reth-db" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "derive_more", @@ -9623,6 +9369,7 @@ dependencies = [ "metrics", "page_size", "parking_lot", + "quanta", "reth-db-api", "reth-fs-util", "reth-libmdbx", @@ -9641,11 +9388,10 @@ dependencies = [ [[package]] name = "reth-db-api" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", - "alloy-genesis", "alloy-primitives", "arbitrary", "arrayvec", @@ -9653,8 +9399,6 @@ dependencies = [ "derive_more", "metrics", "modular-bitfield", - "op-alloy-consensus", - "parity-scale-codec", "proptest", "reth-codecs", "reth-db-models", @@ -9670,8 +9414,8 @@ dependencies = [ [[package]] name = "reth-db-common" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -9700,8 +9444,8 @@ dependencies = [ [[package]] name = "reth-db-models" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eips", "alloy-primitives", @@ -9715,8 +9459,8 @@ dependencies = [ [[package]] name = "reth-discv4" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -9740,8 +9484,8 @@ dependencies = [ [[package]] name = "reth-discv5" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -9764,8 +9508,8 @@ dependencies = [ [[package]] name = "reth-dns-discovery" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "dashmap", @@ -9788,8 +9532,8 @@ dependencies = [ [[package]] name = "reth-downloaders" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9823,8 +9567,8 @@ dependencies = [ [[package]] name = "reth-e2e-test-utils" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9859,7 +9603,6 @@ dependencies = [ "reth-payload-builder", "reth-payload-builder-primitives", "reth-payload-primitives", - "reth-primitives", "reth-primitives-traits", "reth-provider", "reth-rpc-api", @@ -9881,8 +9624,8 @@ dependencies = [ [[package]] name = "reth-ecies" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "aes", "alloy-primitives", @@ -9909,15 +9652,14 @@ dependencies = [ [[package]] name = "reth-engine-local" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-primitives", "alloy-rpc-types-engine", "eyre", "futures-util", - "op-alloy-rpc-types-engine", "reth-chainspec", "reth-engine-primitives", "reth-ethereum-engine-primitives", @@ -9933,8 +9675,8 @@ dependencies = [ [[package]] name = "reth-engine-primitives" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9956,32 +9698,10 @@ dependencies = [ "tokio", ] -[[package]] -name = "reth-engine-service" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" -dependencies = [ - "futures", - "pin-project", - "reth-chainspec", - "reth-consensus", - "reth-engine-primitives", - "reth-engine-tree", - "reth-evm", - "reth-network-p2p", - "reth-node-types", - "reth-payload-builder", - "reth-provider", - "reth-prune", - "reth-stages-api", - "reth-tasks", - "reth-trie-db", -] - [[package]] name = "reth-engine-tree" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eip7928", @@ -9992,7 +9712,6 @@ dependencies = [ "alloy-rpc-types-engine", "crossbeam-channel", "derive_more", - "fixed-cache", "futures", "metrics", "moka", @@ -10006,6 +9725,7 @@ dependencies = [ "reth-errors", "reth-ethereum-primitives", "reth-evm", + "reth-execution-cache", "reth-execution-types", "reth-metrics", "reth-network-p2p", @@ -10029,7 +9749,6 @@ dependencies = [ "revm", "revm-primitives", "schnellru", - "smallvec", "thiserror 2.0.18", "tokio", "tracing", @@ -10037,8 +9756,8 @@ dependencies = [ [[package]] name = "reth-engine-util" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", @@ -10065,8 +9784,8 @@ dependencies = [ [[package]] name = "reth-era" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10080,14 +9799,14 @@ dependencies = [ [[package]] name = "reth-era-downloader" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "bytes", "eyre", "futures-util", - "reqwest 0.12.28", + "reqwest 0.13.2", "reth-era", "reth-fs-util", "sha2", @@ -10096,8 +9815,8 @@ dependencies = [ [[package]] name = "reth-era-utils" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -10118,8 +9837,8 @@ dependencies = [ [[package]] name = "reth-errors" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "reth-consensus", "reth-execution-errors", @@ -10129,8 +9848,8 @@ dependencies = [ [[package]] name = "reth-eth-wire" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-chains", "alloy-primitives", @@ -10158,8 +9877,8 @@ dependencies = [ [[package]] name = "reth-eth-wire-types" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-chains", "alloy-consensus", @@ -10182,8 +9901,8 @@ dependencies = [ [[package]] name = "reth-ethereum" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-rpc-types-engine", "alloy-rpc-types-eth", @@ -10223,8 +9942,8 @@ dependencies = [ [[package]] name = "reth-ethereum-cli" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "clap", "eyre", @@ -10246,8 +9965,8 @@ dependencies = [ [[package]] name = "reth-ethereum-consensus" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10262,26 +9981,24 @@ dependencies = [ [[package]] name = "reth-ethereum-engine-primitives" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eips", "alloy-primitives", - "alloy-rlp", "alloy-rpc-types-engine", "reth-engine-primitives", "reth-ethereum-primitives", "reth-payload-primitives", "reth-primitives-traits", "serde", - "sha2", "thiserror 2.0.18", ] [[package]] name = "reth-ethereum-forks" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eip2124", "alloy-hardforks", @@ -10294,8 +10011,8 @@ dependencies = [ [[package]] name = "reth-ethereum-payload-builder" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10309,6 +10026,7 @@ dependencies = [ "reth-ethereum-primitives", "reth-evm", "reth-evm-ethereum", + "reth-execution-cache", "reth-payload-builder", "reth-payload-builder-primitives", "reth-payload-primitives", @@ -10323,28 +10041,22 @@ dependencies = [ [[package]] name = "reth-ethereum-primitives" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", - "alloy-rlp", "alloy-rpc-types-eth", - "alloy-serde", - "arbitrary", - "modular-bitfield", "reth-codecs", "reth-primitives-traits", - "reth-zstd-compressors", "serde", - "serde_with", ] [[package]] name = "reth-etl" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "rayon", "reth-db-api", @@ -10353,8 +10065,8 @@ dependencies = [ [[package]] name = "reth-evm" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10377,16 +10089,14 @@ dependencies = [ [[package]] name = "reth-evm-ethereum" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-evm", "alloy-primitives", "alloy-rpc-types-engine", - "derive_more", - "parking_lot", "reth-chainspec", "reth-ethereum-forks", "reth-ethereum-primitives", @@ -10397,10 +10107,28 @@ dependencies = [ "revm", ] +[[package]] +name = "reth-execution-cache" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" +dependencies = [ + "alloy-primitives", + "fixed-cache", + "metrics", + "parking_lot", + "reth-errors", + "reth-metrics", + "reth-primitives-traits", + "reth-provider", + "reth-revm", + "reth-trie", + "tracing", +] + [[package]] name = "reth-execution-errors" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-evm", "alloy-primitives", @@ -10412,13 +10140,14 @@ dependencies = [ [[package]] name = "reth-execution-types" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-evm", "alloy-primitives", + "alloy-rlp", "derive_more", "reth-ethereum-primitives", "reth-primitives-traits", @@ -10430,8 +10159,8 @@ dependencies = [ [[package]] name = "reth-exex" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10468,8 +10197,8 @@ dependencies = [ [[package]] name = "reth-exex-test-utils" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eips", "eyre", @@ -10500,8 +10229,8 @@ dependencies = [ [[package]] name = "reth-exex-types" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eips", "alloy-primitives", @@ -10514,8 +10243,8 @@ dependencies = [ [[package]] name = "reth-fs-util" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "serde", "serde_json", @@ -10524,8 +10253,8 @@ dependencies = [ [[package]] name = "reth-invalid-block-hooks" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -10552,8 +10281,8 @@ dependencies = [ [[package]] name = "reth-ipc" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "bytes", "futures", @@ -10566,17 +10295,18 @@ dependencies = [ "tokio", "tokio-stream", "tokio-util", - "tower 0.5.3", + "tower", "tracing", ] [[package]] name = "reth-libmdbx" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "bitflags 2.11.0", "byteorder", + "crossbeam-queue", "dashmap", "derive_more", "parking_lot", @@ -10588,8 +10318,8 @@ dependencies = [ [[package]] name = "reth-mdbx-sys" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "bindgen", "cc", @@ -10597,8 +10327,8 @@ dependencies = [ [[package]] name = "reth-metrics" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "futures", "metrics", @@ -10609,8 +10339,8 @@ dependencies = [ [[package]] name = "reth-net-banlist" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "ipnet", @@ -10618,12 +10348,12 @@ dependencies = [ [[package]] name = "reth-net-nat" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "futures-util", "if-addrs 0.14.0", - "reqwest 0.12.28", + "reqwest 0.13.2", "serde_with", "thiserror 2.0.18", "tokio", @@ -10632,8 +10362,8 @@ dependencies = [ [[package]] name = "reth-network" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10689,8 +10419,8 @@ dependencies = [ [[package]] name = "reth-network-api" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -10714,8 +10444,8 @@ dependencies = [ [[package]] name = "reth-network-p2p" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10737,8 +10467,8 @@ dependencies = [ [[package]] name = "reth-network-peers" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -10752,8 +10482,8 @@ dependencies = [ [[package]] name = "reth-network-types" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eip2124", "humantime-serde", @@ -10766,8 +10496,8 @@ dependencies = [ [[package]] name = "reth-nippy-jar" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "anyhow", "bincode 1.3.3", @@ -10783,8 +10513,8 @@ dependencies = [ [[package]] name = "reth-node-api" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-rpc-types-engine", "eyre", @@ -10807,8 +10537,8 @@ dependencies = [ [[package]] name = "reth-node-builder" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10835,7 +10565,6 @@ dependencies = [ "reth-downloaders", "reth-engine-local", "reth-engine-primitives", - "reth-engine-service", "reth-engine-tree", "reth-engine-util", "reth-evm", @@ -10876,8 +10605,8 @@ dependencies = [ [[package]] name = "reth-node-core" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10914,12 +10643,12 @@ dependencies = [ "reth-stages-types", "reth-storage-api", "reth-storage-errors", + "reth-tasks", "reth-tracing", "reth-tracing-otlp", "reth-transaction-pool", "secp256k1 0.30.0", "serde", - "shellexpand", "strum", "thiserror 2.0.18", "toml", @@ -10931,8 +10660,8 @@ dependencies = [ [[package]] name = "reth-node-ethereum" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eips", "alloy-network", @@ -10969,8 +10698,8 @@ dependencies = [ [[package]] name = "reth-node-ethstats" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -10986,15 +10715,15 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tokio-stream", - "tokio-tungstenite 0.28.0", + "tokio-tungstenite", "tracing", "url", ] [[package]] name = "reth-node-events" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -11017,8 +10746,8 @@ dependencies = [ [[package]] name = "reth-node-metrics" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "bytes", "eyre", @@ -11028,26 +10757,26 @@ dependencies = [ "jsonrpsee-server", "mappings", "metrics", - "metrics-exporter-prometheus 0.18.1", + "metrics-exporter-prometheus", "metrics-process", - "metrics-util 0.20.1", + "metrics-util", "pprof_util", "procfs", - "reqwest 0.12.28", + "reqwest 0.13.2", "reth-fs-util", "reth-metrics", "reth-tasks", "tempfile", "tikv-jemalloc-ctl", "tokio", - "tower 0.5.3", + "tower", "tracing", ] [[package]] name = "reth-node-types" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "reth-chainspec", "reth-db-api", @@ -11167,6 +10896,7 @@ dependencies = [ "reth-stages", "reth-static-file", "reth-static-file-types", + "reth-tasks", "reth-tracing", "serde", "tempfile", @@ -11303,7 +11033,7 @@ dependencies = [ "serde_json", "test-case", "tokio", - "tokio-tungstenite 0.28.0", + "tokio-tungstenite", "tracing", "url", ] @@ -11344,7 +11074,6 @@ dependencies = [ "reth-db", "reth-db-api", "reth-e2e-test-utils", - "reth-engine-local", "reth-evm", "reth-network", "reth-node-api", @@ -11401,6 +11130,7 @@ dependencies = [ "either", "op-alloy-consensus", "op-alloy-rpc-types-engine", + "op-revm", "reth-basic-payload-builder", "reth-chainspec", "reth-evm", @@ -11409,7 +11139,6 @@ dependencies = [ "reth-optimism-forks", "reth-optimism-primitives", "reth-optimism-txpool", - "reth-payload-builder", "reth-payload-builder-primitives", "reth-payload-primitives", "reth-payload-util", @@ -11520,7 +11249,7 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tokio-stream", - "tower 0.5.3", + "tower", "tracing", ] @@ -11623,20 +11352,23 @@ dependencies = [ [[package]] name = "reth-payload-builder" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-primitives", "alloy-rpc-types", + "derive_more", "futures-util", "metrics", "reth-chain-state", "reth-ethereum-engine-primitives", + "reth-execution-cache", "reth-metrics", "reth-payload-builder-primitives", "reth-payload-primitives", "reth-primitives-traits", + "reth-trie-parallel", "tokio", "tokio-stream", "tracing", @@ -11644,8 +11376,8 @@ dependencies = [ [[package]] name = "reth-payload-builder-primitives" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "pin-project", "reth-payload-primitives", @@ -11656,16 +11388,16 @@ dependencies = [ [[package]] name = "reth-payload-primitives" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", + "alloy-rlp", "alloy-rpc-types-engine", "auto_impl", "either", - "op-alloy-rpc-types-engine", "reth-chain-state", "reth-chainspec", "reth-errors", @@ -11673,14 +11405,15 @@ dependencies = [ "reth-primitives-traits", "reth-trie-common", "serde", + "sha2", "thiserror 2.0.18", "tokio", ] [[package]] name = "reth-payload-util" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -11689,31 +11422,19 @@ dependencies = [ [[package]] name = "reth-payload-validator" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", "reth-primitives-traits", ] -[[package]] -name = "reth-primitives" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" -dependencies = [ - "alloy-consensus", - "once_cell", - "reth-ethereum-forks", - "reth-ethereum-primitives", - "reth-primitives-traits", - "reth-static-file-types", -] - [[package]] name = "reth-primitives-traits" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03650bb740d1bca0d974c007248177ae7a7e38c50c9f46eb02292c5d9bc01252" dependencies = [ "alloy-consensus", "alloy-eips", @@ -11723,16 +11444,15 @@ dependencies = [ "alloy-rpc-types-eth", "alloy-trie", "arbitrary", - "auto_impl", "byteorder", "bytes", "dashmap", "derive_more", "modular-bitfield", "once_cell", - "op-alloy-consensus", "proptest", "proptest-arbitrary-interop", + "quanta", "rayon", "reth-codecs", "revm-bytecode", @@ -11740,17 +11460,17 @@ dependencies = [ "revm-state", "secp256k1 0.30.0", "serde", - "serde_with", "thiserror 2.0.18", ] [[package]] name = "reth-provider" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", + "alloy-genesis", "alloy-primitives", "alloy-rpc-types-engine", "eyre", @@ -11791,8 +11511,8 @@ dependencies = [ [[package]] name = "reth-prune" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -11820,8 +11540,8 @@ dependencies = [ [[package]] name = "reth-prune-types" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "arbitrary", @@ -11836,10 +11556,12 @@ dependencies = [ [[package]] name = "reth-revm" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-debug", "reth-primitives-traits", "reth-storage-api", "reth-storage-errors", @@ -11849,8 +11571,8 @@ dependencies = [ [[package]] name = "reth-rpc" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -11909,6 +11631,7 @@ dependencies = [ "reth-rpc-server-types", "reth-storage-api", "reth-tasks", + "reth-tracing", "reth-transaction-pool", "reth-trie-common", "revm", @@ -11926,8 +11649,8 @@ dependencies = [ [[package]] name = "reth-rpc-api" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eip7928", "alloy-eips", @@ -11951,13 +11674,14 @@ dependencies = [ "reth-network-peers", "reth-rpc-eth-api", "reth-trie-common", + "serde", "serde_json", ] [[package]] name = "reth-rpc-builder" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-network", "alloy-provider", @@ -11975,9 +11699,11 @@ dependencies = [ "reth-metrics", "reth-network-api", "reth-node-core", + "reth-payload-primitives", "reth-primitives-traits", "reth-rpc", "reth-rpc-api", + "reth-rpc-engine-api", "reth-rpc-eth-api", "reth-rpc-eth-types", "reth-rpc-layer", @@ -11990,15 +11716,15 @@ dependencies = [ "thiserror 2.0.18", "tokio", "tokio-util", - "tower 0.5.3", + "tower", "tower-http", "tracing", ] [[package]] name = "reth-rpc-convert" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-evm", @@ -12006,26 +11732,23 @@ dependencies = [ "alloy-network", "alloy-primitives", "alloy-rpc-types-eth", - "alloy-signer", "auto_impl", "dyn-clone", "jsonrpsee-types", - "op-alloy-consensus", - "op-alloy-network", - "op-alloy-rpc-types", - "reth-ethereum-primitives", "reth-evm", "reth-primitives-traits", + "reth-rpc-traits", "thiserror 2.0.18", ] [[package]] name = "reth-rpc-engine-api" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eips", "alloy-primitives", + "alloy-rlp", "alloy-rpc-types-engine", "async-trait", "jsonrpsee-core", @@ -12051,11 +11774,12 @@ dependencies = [ [[package]] name = "reth-rpc-eth-api" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-dyn-abi", + "alloy-eip7928", "alloy-eips", "alloy-evm", "alloy-json-rpc", @@ -12089,14 +11813,15 @@ dependencies = [ "reth-trie-common", "revm", "revm-inspectors", + "serde_json", "tokio", "tracing", ] [[package]] name = "reth-rpc-eth-types" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -12114,7 +11839,7 @@ dependencies = [ "jsonrpsee-types", "metrics", "rand 0.9.2", - "reqwest 0.12.28", + "reqwest 0.13.2", "reth-chain-state", "reth-chainspec", "reth-errors", @@ -12143,22 +11868,22 @@ dependencies = [ [[package]] name = "reth-rpc-layer" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-rpc-types-engine", "http", "jsonrpsee-http-client", "pin-project", - "tower 0.5.3", + "tower", "tower-http", "tracing", ] [[package]] name = "reth-rpc-server-types" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eips", "alloy-primitives", @@ -12171,21 +11896,37 @@ dependencies = [ "strum", ] +[[package]] +name = "reth-rpc-traits" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9230acfd70f7f27bc52da3f397e1896432ce160f9bd460d9788f1a28d61588c" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-signer", + "reth-primitives-traits", + "thiserror 2.0.18", +] + [[package]] name = "reth-stages" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", - "bincode 1.3.3", + "alloy-rlp", "eyre", "futures-util", "itertools 0.14.0", "num-traits", + "page_size", "rayon", - "reqwest 0.12.28", + "reqwest 0.13.2", "reth-chainspec", "reth-codecs", "reth-config", @@ -12201,6 +11942,7 @@ dependencies = [ "reth-execution-types", "reth-exex", "reth-fs-util", + "reth-libmdbx", "reth-network-p2p", "reth-primitives-traits", "reth-provider", @@ -12223,8 +11965,8 @@ dependencies = [ [[package]] name = "reth-stages-api" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eips", "alloy-primitives", @@ -12232,6 +11974,7 @@ dependencies = [ "auto_impl", "futures-util", "metrics", + "reth-codecs", "reth-consensus", "reth-errors", "reth-metrics", @@ -12250,8 +11993,8 @@ dependencies = [ [[package]] name = "reth-stages-types" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "arbitrary", @@ -12264,8 +12007,8 @@ dependencies = [ [[package]] name = "reth-static-file" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "parking_lot", @@ -12284,8 +12027,8 @@ dependencies = [ [[package]] name = "reth-static-file-types" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "clap", @@ -12299,8 +12042,8 @@ dependencies = [ [[package]] name = "reth-storage-api" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -12323,13 +12066,14 @@ dependencies = [ [[package]] name = "reth-storage-errors" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rlp", "derive_more", + "reth-codecs", "reth-primitives-traits", "reth-prune-types", "reth-static-file-types", @@ -12340,17 +12084,20 @@ dependencies = [ [[package]] name = "reth-tasks" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ - "auto_impl", - "dyn-clone", + "crossbeam-utils", + "dashmap", "futures-util", + "libc", "metrics", + "parking_lot", "pin-project", "rayon", "reth-metrics", "thiserror 2.0.18", + "thread-priority", "tokio", "tracing", "tracing-futures", @@ -12358,8 +12105,8 @@ dependencies = [ [[package]] name = "reth-testing-utils" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -12374,8 +12121,8 @@ dependencies = [ [[package]] name = "reth-tokio-util" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "tokio", "tokio-stream", @@ -12384,8 +12131,8 @@ dependencies = [ [[package]] name = "reth-tracing" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "clap", "eyre", @@ -12403,26 +12150,26 @@ dependencies = [ [[package]] name = "reth-tracing-otlp" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "clap", "eyre", - "opentelemetry 0.31.0", + "opentelemetry", "opentelemetry-appender-tracing", - "opentelemetry-otlp 0.31.0", + "opentelemetry-otlp", "opentelemetry-semantic-conventions", - "opentelemetry_sdk 0.31.0", + "opentelemetry_sdk", "tracing", - "tracing-opentelemetry 0.32.1", + "tracing-opentelemetry", "tracing-subscriber 0.3.23", "url", ] [[package]] name = "reth-transaction-pool" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -12467,8 +12214,8 @@ dependencies = [ [[package]] name = "reth-trie" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -12493,8 +12240,8 @@ dependencies = [ [[package]] name = "reth-trie-common" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -12520,8 +12267,8 @@ dependencies = [ [[package]] name = "reth-trie-db" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "metrics", @@ -12540,12 +12287,15 @@ dependencies = [ [[package]] name = "reth-trie-parallel" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ + "alloy-eip7928", + "alloy-evm", "alloy-primitives", "alloy-rlp", "crossbeam-channel", + "crossbeam-utils", "derive_more", "itertools 0.14.0", "metrics", @@ -12557,16 +12307,16 @@ dependencies = [ "reth-storage-errors", "reth-tasks", "reth-trie", - "reth-trie-common", "reth-trie-sparse", + "revm-state", "thiserror 2.0.18", "tracing", ] [[package]] name = "reth-trie-sparse" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "2.0.0" +source = "git+https://github.com/paradigmxyz/reth?tag=v2.0.0#eb4c15e5e36d8776d46629beae4c0a69af7ab04f" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -12578,23 +12328,27 @@ dependencies = [ "reth-metrics", "reth-primitives-traits", "reth-trie-common", + "serde", + "serde_json", + "slotmap", "smallvec", "tracing", ] [[package]] name = "reth-zstd-compressors" -version = "1.11.3" -source = "git+https://github.com/paradigmxyz/reth?tag=v1.11.3#d6324d63e27ef6b7c49cdc9b1977c1b808234c7b" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be2e9bda3e45c5d87cfbe811676bfb9cb1f0e6fa82d1dd6a3e8cd996512f236" dependencies = [ "zstd", ] [[package]] name = "revm" -version = "34.0.0" +version = "36.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2aabdebaa535b3575231a88d72b642897ae8106cf6b0d12eafc6bfdf50abfc7" +checksum = "b0abc15d09cd211e9e73410ada10134069c794d4bcdb787dfc16a1bf0939849c" dependencies = [ "revm-bytecode", "revm-context", @@ -12611,9 +12365,9 @@ dependencies = [ [[package]] name = "revm-bytecode" -version = "8.0.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d1e5c1eaa44d39d537f668bc5c3409dc01e5c8be954da6c83370bbdf006457" +checksum = "e86e468df3cf5cf59fa7ef71a3e9ccabb76bb336401ea2c0674f563104cf3c5e" dependencies = [ "bitvec", "phf", @@ -12623,9 +12377,9 @@ dependencies = [ [[package]] name = "revm-context" -version = "13.0.0" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "892ff3e6a566cf8d72ffb627fdced3becebbd9ba64089c25975b9b028af326a5" +checksum = "9eb1f0a76b14d684a444fc52f7bf6b7564bf882599d91ee62e76d602e7a187c7" dependencies = [ "bitvec", "cfg-if", @@ -12640,9 +12394,9 @@ dependencies = [ [[package]] name = "revm-context-interface" -version = "14.0.0" +version = "16.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57f61cc6d23678c4840af895b19f8acfbbd546142ec8028b6526c53cc1c16c98" +checksum = "fc256b27743e2912ca16899568e6652a372eb5d1d573e6edb16c7836b16cf487" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -12656,9 +12410,9 @@ dependencies = [ [[package]] name = "revm-database" -version = "10.0.0" +version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529528d0b05fe646be86223032c3e77aa8b05caa2a35447d538c55965956a511" +checksum = "2c0a7d6da41061f2c50f99a2632571026b23684b5449ff319914151f4449b6c8" dependencies = [ "alloy-eips", "revm-bytecode", @@ -12670,9 +12424,9 @@ dependencies = [ [[package]] name = "revm-database-interface" -version = "9.0.0" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7bf93ac5b91347c057610c0d96e923db8c62807e03f036762d03e981feddc1d" +checksum = "bd497a38a79057b94a049552cb1f925ad15078bc1a479c132aeeebd1d2ccc768" dependencies = [ "auto_impl", "either", @@ -12684,9 +12438,9 @@ dependencies = [ [[package]] name = "revm-handler" -version = "15.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd0e43e815a85eded249df886c4badec869195e70cdd808a13cfca2794622d2" +checksum = "9f1eed729ca9b228ae98688f352235871e9b8be3d568d488e4070f64c56e9d3d" dependencies = [ "auto_impl", "derive-where", @@ -12703,9 +12457,9 @@ dependencies = [ [[package]] name = "revm-inspector" -version = "15.0.0" +version = "17.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3ccad59db91ef93696536a0dbaf2f6f17cfe20d4d8843ae118edb7e97947ef" +checksum = "cbf5102391706513689f91cb3cb3d97b5f13a02e8647e6e9cb7620877ef84847" dependencies = [ "auto_impl", "either", @@ -12721,9 +12475,9 @@ dependencies = [ [[package]] name = "revm-inspectors" -version = "0.34.2" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e435414e9de50a1b930da602067c76365fea2fea11e80ceb50783c94ddd127f" +checksum = "9487362b728f80dd2033ef5f4d0688453435bbe7caa721fa7e3b8fa25d89242b" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -12741,9 +12495,9 @@ dependencies = [ [[package]] name = "revm-interpreter" -version = "32.0.0" +version = "34.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11406408597bc249392d39295831c4b641b3a6f5c471a7c41104a7a1e3564c07" +checksum = "cf22f80612bb8f58fd1f578750281f2afadb6c93835b14ae6a4d6b75ca26f445" dependencies = [ "revm-bytecode", "revm-context-interface", @@ -12775,6 +12529,7 @@ dependencies = [ "ripemd", "secp256k1 0.31.1", "sha2", + "substrate-bn", ] [[package]] @@ -12791,9 +12546,9 @@ dependencies = [ [[package]] name = "revm-state" -version = "9.0.0" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311720d4f0f239b041375e7ddafdbd20032a33b7bae718562ea188e188ed9fd3" +checksum = "d29404707763da607e5d6e4771cb203998c28159279c2f64cc32de08d2814651" dependencies = [ "alloy-eip7928", "bitflags 2.11.0", @@ -12938,87 +12693,6 @@ dependencies = [ "chrono", ] -[[package]] -name = "rollup-boost" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d1d7c635dec67c86346eb871e8a22dd1596c33d4a96a9a4926b4d2fd703b63" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "alloy-rpc-types-engine", - "alloy-rpc-types-eth", - "alloy-serde", - "backoff", - "blake3", - "bytes", - "clap", - "dashmap", - "dotenvy", - "ed25519-dalek", - "eyre", - "futures", - "hex", - "http", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "jsonrpsee", - "lru 0.16.3", - "metrics", - "metrics-derive", - "metrics-exporter-prometheus 0.16.2", - "metrics-util 0.19.1", - "moka", - "op-alloy-rpc-types-engine", - "opentelemetry 0.28.0", - "opentelemetry-otlp 0.28.0", - "opentelemetry_sdk 0.28.0", - "parking_lot", - "paste", - "rollup-boost-types", - "rustls", - "serde", - "serde_json", - "sha2", - "thiserror 2.0.18", - "tokio", - "tokio-tungstenite 0.26.2", - "tokio-util", - "tower 0.5.3", - "tower-http", - "tracing", - "tracing-opentelemetry 0.29.0", - "tracing-subscriber 0.3.23", - "url", - "uuid", - "vergen", - "vergen-git2", -] - -[[package]] -name = "rollup-boost-types" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756f32c7f241ab6d91d823e94d20f6e0729bfcaec3b545bd30f33b24e50f5821" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "alloy-rpc-types-engine", - "alloy-rpc-types-eth", - "alloy-serde", - "blake3", - "ed25519-dalek", - "futures", - "moka", - "op-alloy-rpc-types-engine", - "serde", - "serde_json", - "thiserror 2.0.18", - "tracing", -] - [[package]] name = "route-recognizer" version = "0.3.1" @@ -13734,15 +13408,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shellexpand" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32824fab5e16e6c4d86dc1ba84489390419a39f97699852b66480bb87d297ed8" -dependencies = [ - "dirs", -] - [[package]] name = "shlex" version = "1.3.0" @@ -13853,6 +13518,15 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + [[package]] name = "small_btree" version = "0.1.0" @@ -14001,6 +13675,19 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand 0.8.5", + "rustc-hex", +] + [[package]] name = "subtle" version = "2.6.1" @@ -14072,7 +13759,7 @@ dependencies = [ "ntapi", "objc2-core-foundation", "objc2-io-kit", - "windows", + "windows 0.62.2", ] [[package]] @@ -14276,6 +13963,20 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "thread-priority" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2210811179577da3d54eb69ab0b50490ee40491a25d95b8c6011ba40771cb721" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "libc", + "log", + "rustversion", + "windows 0.61.3", +] + [[package]] name = "thread_local" version = "1.1.9" @@ -14455,20 +14156,6 @@ dependencies = [ "tokio-util", ] -[[package]] -name = "tokio-tungstenite" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" -dependencies = [ - "futures-util", - "log", - "native-tls", - "tokio", - "tokio-native-tls", - "tungstenite 0.26.2", -] - [[package]] name = "tokio-tungstenite" version = "0.28.0" @@ -14478,10 +14165,11 @@ dependencies = [ "futures-util", "log", "rustls", + "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls", - "tungstenite 0.28.0", + "tungstenite", "webpki-roots 0.26.11", ] @@ -14560,36 +14248,6 @@ version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" -[[package]] -name = "tonic" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.22.1", - "bytes", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-timeout", - "hyper-util", - "percent-encoding", - "pin-project", - "prost 0.13.5", - "socket2 0.5.10", - "tokio", - "tokio-stream", - "tower 0.4.13", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tonic" version = "0.14.5" @@ -14610,7 +14268,7 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-stream", - "tower 0.5.3", + "tower", "tower-layer", "tower-service", "tracing", @@ -14623,28 +14281,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a55376a0bbaa4975a3f10d009ad763d8f4108f067c7c2e74f3001fb49778d309" dependencies = [ "bytes", - "prost 0.14.3", - "tonic 0.14.5", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", + "prost", + "tonic", ] [[package]] @@ -14691,7 +14329,7 @@ dependencies = [ "pin-project-lite", "tokio", "tokio-util", - "tower 0.5.3", + "tower", "tower-layer", "tower-service", "tracing", @@ -14789,9 +14427,9 @@ dependencies = [ [[package]] name = "tracing-logfmt" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1f47d22deb79c3f59fcf2a1f00f60cbdc05462bf17d1cd356c1fefa3f444bd" +checksum = "a250055a3518b5efba928a18ffac8d32d42ea607a9affff4532144cd5b2e378e" dependencies = [ "time", "tracing", @@ -14799,24 +14437,6 @@ dependencies = [ "tracing-subscriber 0.3.23", ] -[[package]] -name = "tracing-opentelemetry" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721f2d2569dce9f3dfbbddee5906941e953bfcdf736a62da3377f5751650cc36" -dependencies = [ - "js-sys", - "once_cell", - "opentelemetry 0.28.0", - "opentelemetry_sdk 0.28.0", - "smallvec", - "tracing", - "tracing-core", - "tracing-log", - "tracing-subscriber 0.3.23", - "web-time", -] - [[package]] name = "tracing-opentelemetry" version = "0.32.1" @@ -14824,7 +14444,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ac28f2d093c6c477eaa76b23525478f38de514fa9aeb1285738d4b97a9552fc" dependencies = [ "js-sys", - "opentelemetry 0.31.0", + "opentelemetry", "smallvec", "tracing", "tracing-core", @@ -14963,24 +14583,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" -dependencies = [ - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "native-tls", - "rand 0.9.2", - "sha1", - "thiserror 2.0.18", - "utf-8", -] - [[package]] name = "tungstenite" version = "0.28.0" @@ -15382,9 +14984,9 @@ dependencies = [ [[package]] name = "wasm-streams" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" dependencies = [ "futures-util", "js-sys", @@ -15512,16 +15114,38 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections 0.2.0", + "windows-core 0.61.2", + "windows-future 0.2.1", + "windows-link 0.1.3", + "windows-numerics 0.2.0", +] + [[package]] name = "windows" version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ - "windows-collections", - "windows-core", - "windows-future", - "windows-numerics", + "windows-collections 0.3.2", + "windows-core 0.62.2", + "windows-future 0.3.2", + "windows-numerics 0.3.1", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", ] [[package]] @@ -15530,7 +15154,20 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-core", + "windows-core 0.62.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -15541,9 +15178,20 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading 0.1.0", ] [[package]] @@ -15552,9 +15200,9 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core", - "windows-link", - "windows-threading", + "windows-core 0.62.2", + "windows-link 0.2.1", + "windows-threading 0.2.1", ] [[package]] @@ -15579,20 +15227,36 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + [[package]] name = "windows-numerics" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-core", - "windows-link", + "windows-core 0.62.2", + "windows-link 0.2.1", ] [[package]] @@ -15601,9 +15265,18 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -15612,7 +15285,16 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -15621,7 +15303,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -15675,7 +15357,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -15730,7 +15412,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link", + "windows-link 0.2.1", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -15741,13 +15423,22 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows-threading" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 6c1c681aa84..7353326abc5 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,7 +1,7 @@ [workspace.package] edition = "2024" license = "MIT OR Apache-2.0" -rust-version = "1.92" +rust-version = "1.94" authors = ["Op Stack Contributors"] homepage = "https://github.com/ethereum-optimism/optimism" repository = "https://github.com/ethereum-optimism/optimism" @@ -49,6 +49,9 @@ members = [ # Alloy OP Hardforks "alloy-op-hardforks/", + + # Op-Revm + "op-revm/", ] default-members = [ "kona/bin/host", @@ -286,109 +289,115 @@ reth-optimism-trie = { path = "op-reth/crates/trie/" } reth-optimism-txpool = { path = "op-reth/crates/txpool/" } # ==================== OP-ALLOY INTERNAL CRATES ==================== -op-alloy-consensus = { version = "0.23.1", path = "op-alloy/crates/consensus", default-features = false } -op-alloy-network = { version = "0.23.1", path = "op-alloy/crates/network", default-features = false } -op-alloy-provider = { version = "0.23.1", path = "op-alloy/crates/provider", default-features = false } -op-alloy-rpc-types = { version = "0.23.1", path = "op-alloy/crates/rpc-types", default-features = false } -op-alloy-rpc-types-engine = { version = "0.23.1", path = "op-alloy/crates/rpc-types-engine", default-features = false } -op-alloy-rpc-jsonrpsee = { version = "0.23.1", path = "op-alloy/crates/rpc-jsonrpsee", default-features = false } +op-alloy-consensus = { version = "0.24.0", path = "op-alloy/crates/consensus", default-features = false } +op-alloy-network = { version = "0.24.0", path = "op-alloy/crates/network", default-features = false } +op-alloy-provider = { version = "0.24.0", path = "op-alloy/crates/provider", default-features = false } +op-alloy-rpc-types = { version = "0.24.0", path = "op-alloy/crates/rpc-types", default-features = false } +op-alloy-rpc-types-engine = { version = "0.24.0", path = "op-alloy/crates/rpc-types-engine", default-features = false } +op-alloy-rpc-jsonrpsee = { version = "0.24.0", path = "op-alloy/crates/rpc-jsonrpsee", default-features = false } # ==================== ALLOY-OP-EVM / ALLOY-OP-HARDFORKS ==================== -alloy-op-evm = { version = "0.26.3", path = "alloy-op-evm/", default-features = false } +alloy-op-evm = { version = "0.30.0", path = "alloy-op-evm/", default-features = false } alloy-op-hardforks = { version = "0.4.7", path = "alloy-op-hardforks/", default-features = false } -# ==================== RETH CRATES (v1.11.3) ==================== -reth = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-basic-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-chain-state = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-cli = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-cli-commands = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-cli-runner = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-cli-util = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-codecs = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-consensus-common = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-db-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-db-common = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-downloaders = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-e2e-test-utils = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-engine-local = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-engine-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-eth-wire = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-eth-wire-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-ethereum-cli = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-ethereum-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-ethereum-forks = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-ethereum-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-evm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-exex = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-exex-test-utils = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-execution-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-execution-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-fs-util = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-metrics = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-network = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-network-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-network-peers = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-node-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-node-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-node-core = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-node-events = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-node-metrics = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-payload-builder-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-payload-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-payload-util = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-payload-validator = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-provider = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-prune = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-prune-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-revm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-rpc = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-rpc-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-rpc-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-rpc-engine-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-rpc-eth-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-rpc-eth-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-rpc-server-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-stages = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-stages-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-static-file = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-static-file-types = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-storage-api = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-storage-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-tasks = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-tracing = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-transaction-pool = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-trie = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-trie-common = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } -reth-trie-db = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3" } -reth-zstd-compressors = { git = "https://github.com/paradigmxyz/reth", tag = "v1.11.3", default-features = false } +# ==================== RETH CRATES (crates.io) ==================== +reth-codecs = { version = "0.1.0", default-features = false, features = [ + "alloy", +] } +reth-codecs-derive = "0.1.0" +reth-primitives-traits = { version = "0.1.0", default-features = false } +reth-rpc-traits = { version = "0.1.0", default-features = false } +reth-zstd-compressors = { version = "0.1.0", default-features = false } + +# ==================== RETH CRATES (git @ v2.0.0) ==================== +reth = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-basic-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-chain-state = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-cli = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-cli-commands = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-cli-runner = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-cli-util = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-consensus-common = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-db = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-db-api = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-db-common = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-downloaders = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-e2e-test-utils = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-engine-local = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-engine-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-eth-wire = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-eth-wire-types = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-ethereum-cli = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-ethereum-consensus = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-ethereum-forks = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-ethereum-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-evm = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-exex = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-exex-test-utils = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-execution-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-execution-types = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-fs-util = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-metrics = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-network = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-network-api = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-network-peers = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-node-api = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-node-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-node-core = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-node-events = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-node-metrics = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-payload-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-payload-builder-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-payload-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-payload-util = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-payload-validator = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-provider = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-prune = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-prune-types = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-revm = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-rpc = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-rpc-api = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-rpc-builder = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-rpc-engine-api = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-rpc-eth-api = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-rpc-eth-types = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-rpc-server-types = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-stages = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-stages-types = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-static-file = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-static-file-types = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-storage-api = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-storage-errors = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-tasks = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-tracing = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-transaction-pool = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-trie = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } +reth-trie-common = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0", default-features = false } +reth-trie-db = { git = "https://github.com/paradigmxyz/reth", tag = "v2.0.0" } # ==================== REVM (latest: op-reth versions) ==================== -revm = { version = "34.0.0", default-features = false } -revm-bytecode = { version = "8.0.0", default-features = false } -revm-database = { version = "10.0.0", default-features = false } -revm-state = { version = "9.0.0", default-features = false } -revm-primitives = { version = "22.0.0", default-features = false } -revm-interpreter = { version = "32.0.0", default-features = false } -revm-database-interface = { version = "9.0.0", default-features = false } -op-revm = { version = "15.0.0", default-features = false } -revm-inspectors = "0.34.2" +revm = { version = "36.0.0", default-features = false } +revm-bytecode = { version = "9.0.0", default-features = false } +revm-database = { version = "12.0.0", default-features = false } +revm-state = { version = "10.0.0", default-features = false } +revm-primitives = { version = "22.1.0", default-features = false } +revm-interpreter = { version = "34.0.0", default-features = false } +revm-database-interface = { version = "10.0.0", default-features = false } +op-revm = { version = "17.0.0", path = "op-revm/", default-features = false } +revm-inspectors = "0.36.1" # ==================== ALLOY ==================== -alloy-chains = { version = "0.2.30", default-features = false } +alloy-chains = { version = "0.2.33", default-features = false } alloy-dyn-abi = "1.5.6" alloy-eip2124 = { version = "0.2.0", default-features = false } -alloy-eip7928 = { version = "0.3.2", default-features = false } -alloy-evm = { version = "0.27.2", default-features = false } +alloy-eip7928 = { version = "0.3.3", default-features = false } +alloy-evm = { version = "0.30.0", default-features = false } alloy-primitives = { version = "1.5.6", default-features = false, features = [ "map-foldhash", ] } @@ -438,7 +447,7 @@ alloy-transport-ipc = { version = "1.8.2", default-features = false } alloy-transport-ws = { version = "1.8.2", default-features = false } # ==================== OP-ALLOY (from crates.io) ==================== -op-alloy = { version = "0.23.1", path = "op-alloy/crates/op-alloy", default-features = false } +op-alloy = { version = "0.24.0", path = "op-alloy/crates/op-alloy", default-features = false } op-alloy-flz = { version = "0.13.1", default-features = false } # ==================== ASYNC ==================== @@ -616,8 +625,6 @@ ratatui = "0.30.0" rayon = "1.11.0" reqwest = { version = "0.13.2", default-features = false, features = ["query"] } ringbuffer = "0.16.0" -rollup-boost = "0.7.13" -rollup-boost-types = "0.1.0" rustc-hash = { version = "2.1", default-features = false } rustls = { version = "0.23", default-features = false } rustls-pemfile = { version = "2.2", default-features = false } @@ -647,18 +654,3 @@ snmalloc-rs = { version = "0.3.8", features = ["build_cc"] } # K/V database rocksdb = { version = "0.24.0", default-features = false } - -[patch.crates-io] -# Duplicated by: reth-payload-primitives, reth-engine-local (reth git), rollup-boost, -# rollup-boost-types (crates.io) -op-alloy-rpc-types-engine = { path = "op-alloy/crates/rpc-types-engine" } -# Duplicated by: reth-codecs, reth-db-api, reth-primitives-traits, reth-rpc-convert (reth git) -op-alloy-consensus = { path = "op-alloy/crates/consensus" } -# Duplicated by: reth-rpc-convert (reth git) -op-alloy-network = { path = "op-alloy/crates/network" } -# Duplicated by: reth-rpc-convert (reth git) -op-alloy-rpc-types = { path = "op-alloy/crates/rpc-types" } -# Duplicated by: alloy-evm (crates.io) -op-alloy = { path = "op-alloy/crates/op-alloy" } -# Duplicated by: alloy-evm (crates.io) -alloy-op-hardforks = { path = "alloy-op-hardforks/" } diff --git a/rust/alloy-op-evm/Cargo.toml b/rust/alloy-op-evm/Cargo.toml index d64db38c865..68265b37318 100644 --- a/rust/alloy-op-evm/Cargo.toml +++ b/rust/alloy-op-evm/Cargo.toml @@ -2,9 +2,9 @@ name = "alloy-op-evm" description = "OP EVM implementation" -version = "0.26.3" +version = "0.30.0" edition = "2021" -rust-version = "1.92" +rust-version = "1.94" authors = ["Alloy Contributors", "OpLabsPBC"] license.workspace = true homepage = "https://github.com/ethereum-optimism/optimism" @@ -14,7 +14,7 @@ repository = "https://github.com/ethereum-optimism/optimism" workspace = true [dependencies] -alloy-evm = { workspace = true, features = ["op"] } +alloy-evm = { workspace = true } alloy-eips = { workspace = true } alloy-consensus = { workspace = true } @@ -50,3 +50,10 @@ gmp = ["alloy-evm/gmp"] engine = ["op-alloy/rpc-types-engine"] rpc = ["alloy-evm/rpc", "op-alloy/rpc-types"] asm-keccak = ["alloy-evm/asm-keccak", "alloy-primitives/asm-keccak", "revm/asm-keccak"] +arbitrary = [ + "alloy-consensus/arbitrary", + "alloy-eips/arbitrary", + "alloy-primitives/arbitrary", + "op-alloy/arbitrary", + "revm/arbitrary", +] diff --git a/rust/alloy-op-evm/src/block/mod.rs b/rust/alloy-op-evm/src/block/mod.rs index 4334c9bd72f..c064617cc38 100644 --- a/rust/alloy-op-evm/src/block/mod.rs +++ b/rust/alloy-op-evm/src/block/mod.rs @@ -27,7 +27,7 @@ use receipt_builder::OpReceiptBuilder; use revm::{ Database as _, DatabaseCommit, Inspector, context::{Block, result::ResultAndState}, - database::{DatabaseCommitExt, State}, + database::DatabaseCommitExt, }; mod canyon; @@ -74,6 +74,10 @@ impl TxResult for OpTxResult { fn result(&self) -> &ResultAndState { &self.inner.result } + + fn into_result(self) -> ResultAndState { + self.inner.result + } } /// Block executor for Optimism. @@ -198,11 +202,6 @@ where type Result = OpTxResult::TxType>; fn apply_pre_execution_changes(&mut self) -> Result<(), BlockExecutionError> { - // Set state clear flag if the block is after the Spurious Dragon hardfork. - let state_clear_flag = - self.spec.is_spurious_dragon_active_at_block(self.evm.block().number().saturating_to()); - self.evm.db_mut().set_state_clear_flag(state_clear_flag); - self.system_caller.apply_blockhashes_contract_call(self.ctx.parent_hash, &mut self.evm)?; self.system_caller .apply_beacon_root_contract_call(self.ctx.parent_beacon_block_root, &mut self.evm)?; @@ -460,12 +459,12 @@ where fn create_executor<'a, DB, I>( &'a self, - evm: EvmF::Evm<&'a mut State, I>, + evm: EvmF::Evm, ctx: Self::ExecutionCtx<'a>, ) -> impl BlockExecutorFor<'a, Self, DB, I> where - DB: Database + 'a, - I: Inspector>> + 'a, + DB: StateDB + 'a, + I: Inspector> + 'a, { OpBlockExecutor::new(evm, ctx, &self.spec, &self.receipt_builder) } @@ -491,7 +490,7 @@ mod tests { use revm::{ Context, context::BlockEnv, - database::{CacheDB, EmptyDB, InMemoryDB}, + database::{CacheDB, EmptyDB, InMemoryDB, State}, inspector::NoOpInspector, primitives::HashMap, state::AccountInfo, @@ -506,7 +505,7 @@ mod tests { let executor_factory = OpBlockExecutorFactory::new( OpAlloyReceiptBuilder::default(), OpChainHardforks::op_mainnet(), - OpEvmFactory::>::default(), + OpEvmFactory::::default(), ); let mut db = State::builder().with_database(CacheDB::::default()).build(); let evm = executor_factory.evm_factory.create_evm(&mut db, EvmEnv::default()); @@ -575,7 +574,12 @@ mod tests { gas_limit: u64, jovian_timestamp: u64, ) -> OpBlockExecutor< - OpEvm<&'a mut State, NoOpInspector>, + OpEvm< + &'a mut State, + NoOpInspector, + op_revm::precompiles::OpPrecompiles, + crate::OpTx, + >, &'a OpAlloyReceiptBuilder, &'a OpChainHardforks, > { diff --git a/rust/alloy-op-evm/src/env.rs b/rust/alloy-op-evm/src/env.rs index 089f31c406a..79f41c12b3b 100644 --- a/rust/alloy-op-evm/src/env.rs +++ b/rust/alloy-op-evm/src/env.rs @@ -139,6 +139,9 @@ fn evm_env_for_op( basefee: input.base_fee_per_gas, // EIP-4844 excess blob gas of this block, introduced in Cancun blob_excess_gas_and_price, + // EIP-7843 slot number. Not yet used in the OP Stack. + // TODO(optimism#19853): populate from block header once EIP-7843 is enabled. + slot_num: 0, }; EvmEnv::new(cfg_env, block_env) diff --git a/rust/alloy-op-evm/src/lib.rs b/rust/alloy-op-evm/src/lib.rs index 04bf2096618..f4caaca242b 100644 --- a/rust/alloy-op-evm/src/lib.rs +++ b/rust/alloy-op-evm/src/lib.rs @@ -39,6 +39,9 @@ use revm::{ interpreter::{InterpreterResult, interpreter::EthInterpreter}, }; +pub mod tx; +pub use tx::OpTx; + pub mod block; pub use block::{OpBlockExecutionCtx, OpBlockExecutor, OpBlockExecutorFactory}; @@ -49,11 +52,9 @@ pub use block::{OpBlockExecutionCtx, OpBlockExecutor, OpBlockExecutorFactory}; /// [`OpEvm`](op_revm::OpEvm) type. /// /// The `Tx` type parameter controls the transaction environment type. By default it uses -/// [`OpTransaction`] directly, but consumers can provide a newtype wrapper to -/// satisfy additional trait bounds (e.g. `FromRecoveredTx`, -/// `TransactionEnv`). +/// [`OpTx`] which wraps [`OpTransaction`] and implements the necessary foreign traits. #[allow(missing_debug_implementations)] // missing revm::OpContext Debug impl -pub struct OpEvm> { +pub struct OpEvm { inner: op_revm::OpEvm, I, EthInstructions>, P>, inspect: bool, _tx: PhantomData, @@ -183,10 +184,10 @@ where /// Factory producing [`OpEvm`]s. /// /// The `Tx` type parameter controls the transaction type used by the created EVMs. -/// By default it uses [`OpTransaction`] directly, but consumers can specify a newtype -/// wrapper to satisfy additional trait bounds. +/// By default it uses [`OpTx`] which wraps [`OpTransaction`] and implements +/// the necessary foreign traits. #[derive(Debug)] -pub struct OpEvmFactory>(PhantomData); +pub struct OpEvmFactory(PhantomData); impl Clone for OpEvmFactory { fn clone(&self) -> Self { @@ -272,7 +273,7 @@ mod tests { #[test] fn test_precompiles_jovian_fail() { - let mut evm = OpEvmFactory::>::default().create_evm( + let mut evm = OpEvmFactory::::default().create_evm( EmptyDB::default(), EvmEnv::new(CfgEnv::new_with_spec(OpSpecId::JOVIAN), BlockEnv::default()), ); @@ -342,7 +343,7 @@ mod tests { #[test] fn test_precompiles_jovian() { - let mut evm = OpEvmFactory::>::default().create_evm( + let mut evm = OpEvmFactory::::default().create_evm( EmptyDB::default(), EvmEnv::new(CfgEnv::new_with_spec(OpSpecId::JOVIAN), BlockEnv::default()), ); diff --git a/rust/alloy-op-evm/src/tx.rs b/rust/alloy-op-evm/src/tx.rs new file mode 100644 index 00000000000..b519914e9c9 --- /dev/null +++ b/rust/alloy-op-evm/src/tx.rs @@ -0,0 +1,231 @@ +//! [`OpTx`] newtype wrapper around [`OpTransaction`]. + +use crate::block::OpTxEnv; +use alloy_consensus::{ + Signed, TxEip1559, TxEip2930, TxEip4844, TxEip4844Variant, TxEip7702, TxLegacy, +}; +use alloy_eips::{Encodable2718, Typed2718, eip7594::Encodable7594}; +use alloy_evm::{FromRecoveredTx, FromTxWithEncoded, IntoTxEnv, TransactionEnvMut}; +use alloy_primitives::{Address, B256, Bytes, TxKind, U256}; +use core::ops::{Deref, DerefMut}; +use op_alloy::consensus::{OpTxEnvelope, TxDeposit}; +use op_revm::{OpTransaction, transaction::deposit::DepositTransactionParts}; +use revm::context::TxEnv; + +/// Helper to convert a deposit transaction into a [`TxEnv`]. +fn deposit_tx_env(tx: &TxDeposit, caller: Address) -> TxEnv { + TxEnv { + tx_type: tx.ty(), + caller, + gas_limit: tx.gas_limit, + kind: tx.to, + value: tx.value, + data: tx.input.clone(), + ..Default::default() + } +} + +/// Newtype wrapper around [`OpTransaction`] that allows implementing foreign traits. +#[derive(Clone, Debug, Default)] +pub struct OpTx(pub OpTransaction); + +impl From for OpTransaction { + fn from(tx: OpTx) -> Self { + tx.0 + } +} + +impl Deref for OpTx { + type Target = OpTransaction; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for OpTx { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl IntoTxEnv for OpTx { + fn into_tx_env(self) -> Self { + self + } +} + +impl OpTxEnv for OpTx { + fn encoded_bytes(&self) -> Option<&Bytes> { + self.0.enveloped_tx.as_ref() + } +} + +impl revm::context::Transaction for OpTx { + type AccessListItem<'a> + = as revm::context::Transaction>::AccessListItem<'a> + where + Self: 'a; + type Authorization<'a> + = as revm::context::Transaction>::Authorization<'a> + where + Self: 'a; + + fn tx_type(&self) -> u8 { + self.0.tx_type() + } + fn caller(&self) -> Address { + self.0.caller() + } + fn gas_limit(&self) -> u64 { + self.0.gas_limit() + } + fn value(&self) -> U256 { + self.0.value() + } + fn input(&self) -> &Bytes { + self.0.input() + } + fn nonce(&self) -> u64 { + revm::context::Transaction::nonce(&self.0) + } + fn kind(&self) -> TxKind { + self.0.kind() + } + fn chain_id(&self) -> Option { + self.0.chain_id() + } + fn gas_price(&self) -> u128 { + self.0.gas_price() + } + fn access_list(&self) -> Option>> { + self.0.access_list() + } + fn blob_versioned_hashes(&self) -> &[B256] { + self.0.blob_versioned_hashes() + } + fn max_fee_per_blob_gas(&self) -> u128 { + self.0.max_fee_per_blob_gas() + } + fn authorization_list_len(&self) -> usize { + self.0.authorization_list_len() + } + fn authorization_list(&self) -> impl Iterator> { + self.0.authorization_list() + } + fn max_priority_fee_per_gas(&self) -> Option { + self.0.max_priority_fee_per_gas() + } +} + +impl FromRecoveredTx for OpTx { + fn from_recovered_tx(tx: &OpTxEnvelope, sender: Address) -> Self { + let encoded = tx.encoded_2718(); + Self::from_encoded_tx(tx, sender, encoded.into()) + } +} + +impl FromTxWithEncoded for OpTx { + fn from_encoded_tx(tx: &OpTxEnvelope, caller: Address, encoded: Bytes) -> Self { + match tx { + OpTxEnvelope::Legacy(tx) => Self::from_encoded_tx(tx, caller, encoded), + OpTxEnvelope::Eip1559(tx) => Self::from_encoded_tx(tx, caller, encoded), + OpTxEnvelope::Eip2930(tx) => Self::from_encoded_tx(tx, caller, encoded), + OpTxEnvelope::Eip7702(tx) => Self::from_encoded_tx(tx, caller, encoded), + OpTxEnvelope::Deposit(tx) => Self::from_encoded_tx(tx.inner(), caller, encoded), + } + } +} + +/// Generates [`FromRecoveredTx`] and [`FromTxWithEncoded`] impls for [`OpTx`] from a +/// `Signed<$tx>` and bare `$tx` type. The bare type conversion creates the [`TxEnv`] via +/// [`FromRecoveredTx`] and wraps it in an [`OpTransaction`]. +macro_rules! impl_from_tx { + ($($tx:ty),+ $(,)?) => { + $( + impl FromRecoveredTx> for OpTx { + fn from_recovered_tx(tx: &Signed<$tx>, sender: Address) -> Self { + let encoded = tx.encoded_2718(); + Self::from_encoded_tx(tx, sender, encoded.into()) + } + } + + impl FromTxWithEncoded> for OpTx { + fn from_encoded_tx(tx: &Signed<$tx>, caller: Address, encoded: Bytes) -> Self { + Self::from_encoded_tx(tx.tx(), caller, encoded) + } + } + + impl FromTxWithEncoded<$tx> for OpTx { + fn from_encoded_tx(tx: &$tx, caller: Address, encoded: Bytes) -> Self { + let base = TxEnv::from_recovered_tx(tx, caller); + Self(OpTransaction { + base, + enveloped_tx: Some(encoded), + deposit: Default::default(), + }) + } + } + )+ + }; +} + +impl_from_tx!(TxLegacy, TxEip2930, TxEip1559, TxEip4844, TxEip7702); + +/// `TxEip4844Variant` conversion is not necessary for `OpTx`, but it's useful +/// sugar for Foundry. +impl FromRecoveredTx>> for OpTx +where + T: Encodable7594 + Send + Sync, +{ + fn from_recovered_tx(tx: &Signed>, sender: Address) -> Self { + let encoded = tx.encoded_2718(); + Self::from_encoded_tx(tx, sender, encoded.into()) + } +} + +impl FromTxWithEncoded>> for OpTx { + fn from_encoded_tx(tx: &Signed>, caller: Address, encoded: Bytes) -> Self { + Self::from_encoded_tx(tx.tx(), caller, encoded) + } +} + +impl FromTxWithEncoded> for OpTx { + fn from_encoded_tx(tx: &TxEip4844Variant, caller: Address, encoded: Bytes) -> Self { + let base = TxEnv::from_recovered_tx(tx, caller); + Self(OpTransaction { base, enveloped_tx: Some(encoded), deposit: Default::default() }) + } +} + +impl FromRecoveredTx for OpTx { + fn from_recovered_tx(tx: &TxDeposit, sender: Address) -> Self { + let encoded = tx.encoded_2718(); + Self::from_encoded_tx(tx, sender, encoded.into()) + } +} + +impl FromTxWithEncoded for OpTx { + fn from_encoded_tx(tx: &TxDeposit, caller: Address, encoded: Bytes) -> Self { + let base = deposit_tx_env(tx, caller); + let deposit = DepositTransactionParts { + source_hash: tx.source_hash, + mint: Some(tx.mint), + is_system_transaction: tx.is_system_transaction, + }; + Self(OpTransaction { base, enveloped_tx: Some(encoded), deposit }) + } +} + +impl TransactionEnvMut for OpTx { + fn set_gas_limit(&mut self, gas_limit: u64) { + self.0.base.gas_limit = gas_limit; + } + + fn set_nonce(&mut self, nonce: u64) { + self.0.base.nonce = nonce; + } + + fn set_access_list(&mut self, access_list: alloy_eips::eip2930::AccessList) { + self.0.base.access_list = access_list; + } +} diff --git a/rust/alloy-op-hardforks/Cargo.toml b/rust/alloy-op-hardforks/Cargo.toml index 338c707e4d5..7a6434d8232 100644 --- a/rust/alloy-op-hardforks/Cargo.toml +++ b/rust/alloy-op-hardforks/Cargo.toml @@ -4,7 +4,7 @@ description = "Bindings for named OP hardforks" version = "0.4.7" edition = "2024" -rust-version = "1.92" +rust-version = "1.94" authors = ["Alloy Contributors", "OpLabsPBC"] license.workspace = true homepage = "https://github.com/ethereum-optimism/optimism" diff --git a/rust/clippy.toml b/rust/clippy.toml index 2b69e81286b..058aa492e5f 100644 --- a/rust/clippy.toml +++ b/rust/clippy.toml @@ -1,4 +1,4 @@ -msrv = "1.92" +msrv = "1.94" too-large-for-stack = 128 doc-valid-idents = [ "P2P", diff --git a/rust/justfile b/rust/justfile index 46d0fc21ec6..9e7580160b4 100644 --- a/rust/justfile +++ b/rust/justfile @@ -28,14 +28,24 @@ build *args='': build-release *args='': cargo build --workspace --release {{args}} -# Build the rollup node -build-node: +# Build kona-node +build-kona-node: cargo build --release --bin kona-node +# Build kona-node in debug mode (faster compilation for local E2E test iteration) +build-kona-node-debug: + cargo build --bin kona-node + +alias build-node := build-kona-node + # Build op-reth build-op-reth: cargo build --release --bin op-reth +# Build op-reth in debug mode (faster compilation for local E2E test iteration) +build-op-reth-debug: + cargo build --bin op-reth + ############################### Test ################################ # Run all tests (unit + doc tests) @@ -111,6 +121,9 @@ check-no-std: op-alloy-consensus op-alloy-rpc-types op-alloy-rpc-types-engine + + # op-revm + op-revm ) # We need to install the riscv32imac-unknown-none-elf target before starting to build the no-std crates. diff --git a/rust/kona/bin/client/src/fpvm_evm/factory.rs b/rust/kona/bin/client/src/fpvm_evm/factory.rs index d12cd27c0f1..7ec5e2865d4 100644 --- a/rust/kona/bin/client/src/fpvm_evm/factory.rs +++ b/rust/kona/bin/client/src/fpvm_evm/factory.rs @@ -67,7 +67,7 @@ where let revm_evm = RevmOpEvm(RevmEvm { ctx, inspector: NoOpInspector {}, - instruction: EthInstructions::new_mainnet(), + instruction: EthInstructions::new_mainnet_with_spec(spec_id.into()), precompiles: OpFpvmPrecompiles::new_with_spec( spec_id, self.hint_writer.clone(), @@ -90,7 +90,7 @@ where let revm_evm = RevmOpEvm(RevmEvm { ctx, inspector, - instruction: EthInstructions::new_mainnet(), + instruction: EthInstructions::new_mainnet_with_spec(spec_id.into()), precompiles: OpFpvmPrecompiles::new_with_spec( spec_id, self.hint_writer.clone(), diff --git a/rust/kona/bin/client/src/fpvm_evm/precompiles/test_utils.rs b/rust/kona/bin/client/src/fpvm_evm/precompiles/test_utils.rs index bf9d781efcf..38e8df77970 100644 --- a/rust/kona/bin/client/src/fpvm_evm/precompiles/test_utils.rs +++ b/rust/kona/bin/client/src/fpvm_evm/precompiles/test_utils.rs @@ -43,7 +43,8 @@ pub(crate) fn execute_native_precompile>( input: T, gas: u64, ) -> PrecompileResult { - let precompiles = revm::handler::EthPrecompiles::default(); + let precompiles = + revm::handler::EthPrecompiles::new(revm::primitives::hardfork::SpecId::PRAGUE); let Some(precompile) = precompiles.precompiles.get(&address) else { panic!("Precompile not found"); }; diff --git a/rust/kona/bin/host/src/interop/cfg.rs b/rust/kona/bin/host/src/interop/cfg.rs index 6338521c114..a178fb77488 100644 --- a/rust/kona/bin/host/src/interop/cfg.rs +++ b/rust/kona/bin/host/src/interop/cfg.rs @@ -22,7 +22,12 @@ use kona_providers_alloy::{OnlineBeaconClient, OnlineBlobProvider}; use kona_std_fpvm::{FileChannel, FileDescriptor}; use op_alloy_network::Optimism; use serde::Serialize; -use std::{collections::HashMap, path::PathBuf, str::FromStr, sync::Arc}; +use std::{ + collections::{BTreeMap, HashMap}, + path::PathBuf, + str::FromStr, + sync::Arc, +}; use tokio::task::{self, JoinHandle}; /// The interop host application. @@ -228,13 +233,14 @@ impl InteropHost { } /// Reads the [`RollupConfig`]s from the file system and returns a map of L2 chain ID -> - /// [`RollupConfig`]s. + /// [`RollupConfig`]s. Uses `BTreeMap` to ensure deterministic JSON serialization order when + /// these configs are served as preimages to the cannon VM. pub fn read_rollup_configs( &self, - ) -> Option, InteropHostError>> { + ) -> Option, InteropHostError>> { let rollup_config_paths = self.rollup_config_paths.as_ref()?; - Some(rollup_config_paths.iter().try_fold(HashMap::default(), |mut acc, path| { + Some(rollup_config_paths.iter().try_fold(BTreeMap::default(), |mut acc, path| { // Read the serialized config from the file system. let ser_config = std::fs::read_to_string(path)?; diff --git a/rust/kona/bin/host/src/interop/handler.rs b/rust/kona/bin/host/src/interop/handler.rs index 1cd794cb17e..c2d7953bd22 100644 --- a/rust/kona/bin/host/src/interop/handler.rs +++ b/rust/kona/bin/host/src/interop/handler.rs @@ -35,8 +35,6 @@ use kona_protocol::{BlockInfo, OutputRoot, Predeploys}; use kona_providers_alloy::BlobWithCommitmentAndProof; use kona_registry::{L1_CONFIGS, ROLLUP_CONFIGS}; use op_alloy_rpc_types_engine::OpPayloadAttributes; -use op_revm::OpTransaction; -use revm::context::TxEnv; use std::sync::Arc; use tokio::task; use tracing::{Instrument, debug, info, info_span, warn}; @@ -567,7 +565,7 @@ impl HintHandler for InteropHintHandler { rollup_config.as_ref(), l2_provider.clone(), l2_provider, - OpEvmFactory::>::default(), + OpEvmFactory::::default(), None, ); let mut driver = Driver::new(cursor, executor, pipeline); diff --git a/rust/kona/bin/node/Cargo.toml b/rust/kona/bin/node/Cargo.toml index 9feedad43a8..026156d391e 100644 --- a/rust/kona/bin/node/Cargo.toml +++ b/rust/kona/bin/node/Cargo.toml @@ -49,7 +49,6 @@ op-alloy-rpc-types-engine = { workspace = true, features = ["serde"] } # general url.workspace = true -http.workspace = true dirs.workspace = true strum.workspace = true discv5.workspace = true @@ -71,9 +70,6 @@ tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } backon = { workspace = true, features = ["std", "tokio", "tokio-sleep"] } tracing-subscriber = { workspace = true, features = ["fmt", "env-filter"] } -# rollup boost -rollup-boost.workspace = true - [dev-dependencies] rstest.workspace = true tempfile.workspace = true diff --git a/rust/kona/bin/node/src/commands/node.rs b/rust/kona/bin/node/src/commands/node.rs index 093e7ee6fd4..b000be8b743 100644 --- a/rust/kona/bin/node/src/commands/node.rs +++ b/rust/kona/bin/node/src/commands/node.rs @@ -2,8 +2,8 @@ use crate::{ flags::{ - BuilderClientArgs, DerivationDelegateArgs, GlobalArgs, L1ClientArgs, L2ClientArgs, P2PArgs, - RollupBoostFlags, RpcArgs, SequencerArgs, + DerivationDelegateArgs, GlobalArgs, L1ClientArgs, L2ClientArgs, P2PArgs, RpcArgs, + SequencerArgs, }, metrics::{CliMetrics, init_rollup_config_metrics}, }; @@ -21,7 +21,7 @@ use kona_registry::{L1Config, scr_rollup_config_by_alloy_ident}; use op_alloy_network::Optimism; use op_alloy_provider::ext::engine::OpEngineApi; use serde_json::from_reader; -use std::{fs::File, io::Write, path::PathBuf, sync::Arc, time::Duration}; +use std::{fs::File, io::Write, path::PathBuf, sync::Arc}; use strum::IntoEnumIterator; use tracing::{debug, error, info}; @@ -94,10 +94,6 @@ pub struct NodeCommand { #[clap(flatten)] pub l2_client_args: L2ClientArgs, - /// Optional block builder client. - #[clap(flatten)] - pub builder_client_args: BuilderClientArgs, - /// Optional derivation delegation client. #[clap(flatten)] pub derivation_delegate_args: DerivationDelegateArgs, @@ -119,10 +115,6 @@ pub struct NodeCommand { /// SEQUENCER CLI arguments. #[command(flatten)] pub sequencer_flags: SequencerArgs, - - /// Rollup boost CLI arguments - contains the builder and l2 engine arguments. - #[command(flatten)] - pub rollup_boost_flags: RollupBoostFlags, } impl Default for NodeCommand { @@ -130,7 +122,6 @@ impl Default for NodeCommand { Self { l1_rpc_args: L1ClientArgs::default(), l2_client_args: L2ClientArgs::default(), - builder_client_args: BuilderClientArgs::default(), derivation_delegate_args: DerivationDelegateArgs::default(), l2_config_file: None, l1_config_file: None, @@ -138,7 +129,6 @@ impl Default for NodeCommand { p2p_flags: P2PArgs::default(), rpc_flags: RpcArgs::default(), sequencer_flags: SequencerArgs::default(), - rollup_boost_flags: RollupBoostFlags::default(), } } } @@ -308,15 +298,10 @@ impl NodeCommand { let engine_config = EngineConfig { config: Arc::new(cfg.clone()), - builder_url: self.builder_client_args.l2_builder_rpc.clone(), - builder_jwt_secret: self.builder_jwt_secret()?, - builder_timeout: Duration::from_millis(self.builder_client_args.builder_timeout), l2_url: self.l2_client_args.l2_engine_rpc.clone(), l2_jwt_secret: jwt_secret, - l2_timeout: Duration::from_millis(self.l2_client_args.l2_engine_timeout), l1_url: self.l1_rpc_args.l1_eth_rpc.clone(), mode: self.node_mode, - rollup_boost: self.rollup_boost_flags.as_rollup_boost_args(), }; RollupNodeBuilder::new( @@ -396,24 +381,6 @@ impl NodeCommand { Self::default_jwt_secret("l2_jwt.hex") } - /// Returns the builder JWT secret for the engine API - /// using the provided [`PathBuf`]. If the file is not found, - /// it will return the default JWT secret. - pub fn builder_jwt_secret(&self) -> anyhow::Result { - if let Some(path) = &self.builder_client_args.builder_jwt_path && - let Ok(secret) = std::fs::read_to_string(path) - { - return JwtSecret::from_hex(secret) - .map_err(|e| anyhow::anyhow!("Failed to parse JWT secret: {e}")); - } - - if let Some(secret) = &self.builder_client_args.builder_jwt_secret { - return Ok(*secret); - } - - Self::default_jwt_secret("builder_jwt.hex") - } - /// Uses the current directory to attempt to read /// the JWT secret from a file named `file_name`. /// If the file is not found, it will create a new random JWT secret and write it to the file. diff --git a/rust/kona/bin/node/src/flags/engine/flashblocks.rs b/rust/kona/bin/node/src/flags/engine/flashblocks.rs deleted file mode 100644 index dbbb8d3b4d9..00000000000 --- a/rust/kona/bin/node/src/flags/engine/flashblocks.rs +++ /dev/null @@ -1,161 +0,0 @@ -use clap::Parser; -use reqwest::Url; - -const DEFAULT_FLASHBLOCKS_BUILDER_URL: &str = "ws://localhost:1111"; -const DEFAULT_FLASHBLOCKS_HOST: &str = "localhost"; -const DEFAULT_FLASHBLOCKS_PORT: u16 = 1112; - -const DEFAULT_FLASHBLOCKS_BUILDER_WS_INITIAL_RECONNECT_MS: u64 = 10; -const DEFAULT_FLASHBLOCKS_BUILDER_WS_MAX_RECONNECT_MS: u64 = 5000; -const DEFAULT_FLASHBLOCKS_BUILDER_WS_CONNECT_TIMEOUT_MS: u64 = 5000; -const DEFAULT_FLASHBLOCKS_BUILDER_WS_PING_INTERVAL_MS: u64 = 500; -const DEFAULT_FLASHBLOCKS_BUILDER_WS_PONG_TIMEOUT_MS: u64 = 1500; - -/// Flashblocks flags. -#[derive(Clone, Debug, clap::Args)] -pub struct FlashblocksFlags { - /// Enable Flashblocks client - #[arg( - long, - visible_alias = "rollup-boost.flashblocks", - env = "KONA_NODE_FLASHBLOCKS", - default_value = "false" - )] - pub flashblocks: bool, - - /// Flashblocks Builder `WebSocket` URL - #[arg( - long, - visible_alias = "rollup-boost.flashblocks-builder-url", - env = "KONA_NODE_FLASHBLOCKS_BUILDER_URL", - default_value = DEFAULT_FLASHBLOCKS_BUILDER_URL - )] - pub flashblocks_builder_url: Url, - - /// Flashblocks `WebSocket` host for outbound connections - #[arg( - long, - visible_alias = "rollup-boost.flashblocks-host", - env = "KONA_NODE_FLASHBLOCKS_HOST", - default_value = DEFAULT_FLASHBLOCKS_HOST - )] - pub flashblocks_host: String, - - /// Flashblocks `WebSocket` port for outbound connections - #[arg( - long, - visible_alias = "rollup-boost.flashblocks-port", - env = "KONA_NODE_FLASHBLOCKS_PORT", - default_value_t = DEFAULT_FLASHBLOCKS_PORT - )] - pub flashblocks_port: u16, - - /// Websocket connection configuration - #[command(flatten)] - pub flashblocks_ws_config: FlashblocksWebsocketFlags, -} - -impl Default for FlashblocksFlags { - fn default() -> Self { - Self { - flashblocks: false, - flashblocks_builder_url: Url::parse(DEFAULT_FLASHBLOCKS_BUILDER_URL).unwrap(), - flashblocks_host: DEFAULT_FLASHBLOCKS_HOST.to_string(), - flashblocks_port: DEFAULT_FLASHBLOCKS_PORT, - flashblocks_ws_config: FlashblocksWebsocketFlags::default(), - } - } -} - -/// Configuration for the Flashblocks `WebSocket` connection. -#[derive(Parser, Debug, Clone, Copy)] -pub struct FlashblocksWebsocketFlags { - /// Minimum time for exponential backoff for timeout if builder disconnected - #[arg( - long, - visible_alias = "rollup-boost.flashblocks-initial-reconnect-ms", - env = "KONA_NODE_FLASHBLOCKS_BUILDER_WS_INITIAL_RECONNECT_MS", - default_value_t = DEFAULT_FLASHBLOCKS_BUILDER_WS_INITIAL_RECONNECT_MS - )] - pub flashblock_builder_ws_initial_reconnect_ms: u64, - - /// Maximum time for exponential backoff for timeout if builder disconnected - #[arg( - long, - visible_alias = "rollup-boost.flashblocks-max-reconnect-ms", - env = "KONA_NODE_FLASHBLOCKS_BUILDER_WS_MAX_RECONNECT_MS", - default_value_t = DEFAULT_FLASHBLOCKS_BUILDER_WS_MAX_RECONNECT_MS - )] - pub flashblock_builder_ws_max_reconnect_ms: u64, - - /// Timeout for connection attempt - #[arg( - long, - visible_alias = "rollup-boost.flashblocks-connect-timeout-ms", - env = "KONA_NODE_FLASHBLOCKS_BUILDER_WS_CONNECT_TIMEOUT_MS", - default_value_t = DEFAULT_FLASHBLOCKS_BUILDER_WS_CONNECT_TIMEOUT_MS - )] - pub flashblock_builder_ws_connect_timeout_ms: u64, - - /// Interval in milliseconds between ping messages sent to upstream servers to detect - /// unresponsive connections - #[arg( - long, - visible_alias = "rollup-boost.flashblocks-ping-interval-ms", - env = "KONA_NODE_FLASHBLOCKS_BUILDER_WS_PING_INTERVAL_MS", - default_value_t = DEFAULT_FLASHBLOCKS_BUILDER_WS_PING_INTERVAL_MS - )] - pub flashblock_builder_ws_ping_interval_ms: u64, - - /// Timeout in milliseconds to wait for pong responses from upstream servers before considering - /// the connection dead - #[arg( - long, - visible_alias = "rollup-boost.flashblocks-pong-timeout-ms", - env = "KONA_NODE_FLASHBLOCKS_BUILDER_WS_PONG_TIMEOUT_MS", - default_value_t = DEFAULT_FLASHBLOCKS_BUILDER_WS_PONG_TIMEOUT_MS - )] - pub flashblock_builder_ws_pong_timeout_ms: u64, -} - -impl FlashblocksFlags { - /// Converts the flashblocks cli arguments to the flashblocks arguments used by the rollup-boost - /// server. - pub fn as_rollup_boost_args(self) -> rollup_boost::FlashblocksWsArgs { - rollup_boost::FlashblocksWsArgs { - flashblocks_ws: self.flashblocks, - flashblocks_builder_url: self.flashblocks_builder_url, - flashblocks_host: self.flashblocks_host, - flashblocks_port: self.flashblocks_port, - flashblocks_ws_config: rollup_boost::FlashblocksWebsocketConfig { - flashblock_builder_ws_initial_reconnect_ms: self - .flashblocks_ws_config - .flashblock_builder_ws_initial_reconnect_ms, - flashblock_builder_ws_max_reconnect_ms: self - .flashblocks_ws_config - .flashblock_builder_ws_max_reconnect_ms, - flashblock_builder_ws_connect_timeout_ms: self - .flashblocks_ws_config - .flashblock_builder_ws_connect_timeout_ms, - flashblock_builder_ws_ping_interval_ms: self - .flashblocks_ws_config - .flashblock_builder_ws_ping_interval_ms, - flashblock_builder_ws_pong_timeout_ms: self - .flashblocks_ws_config - .flashblock_builder_ws_pong_timeout_ms, - }, - } - } -} - -impl Default for FlashblocksWebsocketFlags { - fn default() -> Self { - Self { - flashblock_builder_ws_initial_reconnect_ms: 10, - flashblock_builder_ws_max_reconnect_ms: 5000, - flashblock_builder_ws_connect_timeout_ms: 5000, - flashblock_builder_ws_ping_interval_ms: 500, - flashblock_builder_ws_pong_timeout_ms: 1500, - } - } -} diff --git a/rust/kona/bin/node/src/flags/engine/mod.rs b/rust/kona/bin/node/src/flags/engine/mod.rs index 68a5d65551f..8819894b7f6 100644 --- a/rust/kona/bin/node/src/flags/engine/mod.rs +++ b/rust/kona/bin/node/src/flags/engine/mod.rs @@ -1,8 +1,2 @@ -mod flashblocks; -pub use flashblocks::{FlashblocksFlags, FlashblocksWebsocketFlags}; - mod providers; -pub use providers::{BuilderClientArgs, DerivationDelegateArgs, L1ClientArgs, L2ClientArgs}; - -mod rollup_boost; -pub use rollup_boost::RollupBoostFlags; +pub use providers::{DerivationDelegateArgs, L1ClientArgs, L2ClientArgs}; diff --git a/rust/kona/bin/node/src/flags/engine/providers.rs b/rust/kona/bin/node/src/flags/engine/providers.rs index 340125176be..039635d09d8 100644 --- a/rust/kona/bin/node/src/flags/engine/providers.rs +++ b/rust/kona/bin/node/src/flags/engine/providers.rs @@ -3,50 +3,11 @@ use kona_node_service::DerivationDelegateConfig; use std::path::PathBuf; use url::Url; -const DEFAULT_BUILDER_TIMEOUT: u64 = 30; const DEFAULT_L2_ENGINE_TIMEOUT: u64 = 30_000; const DEFAULT_L2_TRUST_RPC: bool = true; const DEFAULT_L1_TRUST_RPC: bool = true; -/// Rollup-boost builder client arguments. -#[derive(Clone, Debug, clap::Args)] -pub struct BuilderClientArgs { - /// URL of the builder RPC API. - #[arg( - long, - visible_alias = "builder", - env = "KONA_NODE_BUILDER_RPC", - default_value = "http://localhost:8552" - )] - pub l2_builder_rpc: Url, - /// Hex encoded JWT secret to use for the authenticated builder RPC server. - #[arg(long, visible_alias = "builder.auth", env = "KONA_NODE_BUILDER_AUTH")] - pub builder_jwt_secret: Option, - /// Path to a JWT secret to use for the authenticated builder RPC server. - #[arg(long, visible_alias = "builder.jwt-path", env = "KONA_NODE_BUILDER_JWT_PATH")] - pub builder_jwt_path: Option, - /// Timeout for http calls in milliseconds. - #[arg( - long, - visible_alias = "builder.timeout", - env = "KONA_NODE_BUILDER_TIMEOUT", - default_value_t = DEFAULT_BUILDER_TIMEOUT - )] - pub builder_timeout: u64, -} - -impl Default for BuilderClientArgs { - fn default() -> Self { - Self { - l2_builder_rpc: Url::parse("http://localhost:8552").unwrap(), - builder_jwt_secret: None, - builder_jwt_path: None, - builder_timeout: DEFAULT_BUILDER_TIMEOUT, - } - } -} - /// L1 client arguments. #[derive(Clone, Debug, clap::Args)] pub struct L1ClientArgs { diff --git a/rust/kona/bin/node/src/flags/engine/rollup_boost.rs b/rust/kona/bin/node/src/flags/engine/rollup_boost.rs deleted file mode 100644 index bb1c6ee147b..00000000000 --- a/rust/kona/bin/node/src/flags/engine/rollup_boost.rs +++ /dev/null @@ -1,119 +0,0 @@ -use crate::flags::engine::flashblocks::FlashblocksFlags; -use rollup_boost::{BlockSelectionPolicy, ExecutionMode}; - -/// Custom block builder flags. -#[derive(Clone, Debug, clap::Args)] -pub struct RollupBoostFlags { - /// Execution mode to start rollup boost with - #[arg( - long, - visible_alias = "rollup-boost.execution-mode", - env = "KONA_NODE_ROLLUP_BOOST_EXECUTION_MODE", - default_value = "disabled" - )] - pub execution_mode: ExecutionMode, - - /// Block selection policy to use for the rollup boost server. - #[arg( - long, - visible_alias = "rollup-boost.block-selection-policy", - env = "KONA_NODE_ROLLUP_BOOST_BLOCK_SELECTION_POLICY" - )] - pub block_selection_policy: Option, - - /// Should we use the l2 client for computing state root - #[arg( - long, - visible_alias = "rollup-boost.external-state-root", - env = "KONA_NODE_ROLLUP_BOOST_EXTERNAL_STATE_ROOT", - default_value = "false" - )] - pub external_state_root: bool, - - /// Allow all engine API calls to builder even when marked as unhealthy - /// This is default true assuming no builder CL set up - #[arg( - long, - visible_alias = "rollup-boost.ignore-unhealthy-builders", - env = "KONA_NODE_ROLLUP_BOOST_IGNORE_UNHEALTHY_BUILDERS", - default_value = "false" - )] - pub ignore_unhealthy_builders: bool, - - /// Duration in seconds between async health checks on the builder - #[arg( - long, - visible_alias = "rollup-boost.health-check-interval", - env = "KONA_NODE_ROLLUP_BOOST_HEALTH_CHECK_INTERVAL", - default_value = "60" - )] - pub health_check_interval: u64, - - /// Max duration in seconds between the unsafe head block of the builder and the current time - #[arg( - long, - visible_alias = "rollup-boost.max-unsafe-interval", - env = "KONA_NODE_ROLLUP_BOOST_MAX_UNSAFE_INTERVAL", - default_value = "10" - )] - pub max_unsafe_interval: u64, - - /// Flashblocks configuration - #[clap(flatten)] - pub flashblocks: FlashblocksFlags, -} - -impl Default for RollupBoostFlags { - fn default() -> Self { - Self { - execution_mode: ExecutionMode::Disabled, - block_selection_policy: None, - external_state_root: false, - ignore_unhealthy_builders: false, - flashblocks: FlashblocksFlags::default(), - health_check_interval: 60, - max_unsafe_interval: 10, - } - } -} - -impl RollupBoostFlags { - /// Converts the rollup boost cli arguments to the rollup boost arguments used by the engine. - pub fn as_rollup_boost_args(self) -> kona_engine::RollupBoostServerArgs { - kona_engine::RollupBoostServerArgs { - initial_execution_mode: self.execution_mode, - block_selection_policy: self.block_selection_policy, - external_state_root: self.external_state_root, - ignore_unhealthy_builders: self.ignore_unhealthy_builders, - flashblocks: self.flashblocks.flashblocks.then_some( - kona_engine::FlashblocksClientArgs { - flashblocks_builder_url: self.flashblocks.flashblocks_builder_url, - flashblocks_host: self.flashblocks.flashblocks_host, - flashblocks_port: self.flashblocks.flashblocks_port, - flashblocks_ws_config: kona_engine::FlashblocksWebsocketConfig { - flashblock_builder_ws_initial_reconnect_ms: self - .flashblocks - .flashblocks_ws_config - .flashblock_builder_ws_initial_reconnect_ms, - flashblock_builder_ws_max_reconnect_ms: self - .flashblocks - .flashblocks_ws_config - .flashblock_builder_ws_max_reconnect_ms, - flashblock_builder_ws_connect_timeout_ms: self - .flashblocks - .flashblocks_ws_config - .flashblock_builder_ws_connect_timeout_ms, - flashblock_builder_ws_ping_interval_ms: self - .flashblocks - .flashblocks_ws_config - .flashblock_builder_ws_ping_interval_ms, - flashblock_builder_ws_pong_timeout_ms: self - .flashblocks - .flashblocks_ws_config - .flashblock_builder_ws_pong_timeout_ms, - }, - }, - ), - } - } -} diff --git a/rust/kona/bin/node/src/flags/mod.rs b/rust/kona/bin/node/src/flags/mod.rs index 3d4ea40b6e2..b63526a8bd2 100644 --- a/rust/kona/bin/node/src/flags/mod.rs +++ b/rust/kona/bin/node/src/flags/mod.rs @@ -22,7 +22,4 @@ mod signer; pub use signer::{SignerArgs, SignerArgsParseError}; mod engine; -pub use engine::{ - BuilderClientArgs, DerivationDelegateArgs, FlashblocksFlags, FlashblocksWebsocketFlags, - L1ClientArgs, L2ClientArgs, RollupBoostFlags, -}; +pub use engine::{DerivationDelegateArgs, L1ClientArgs, L2ClientArgs}; diff --git a/rust/kona/crates/node/engine/Cargo.toml b/rust/kona/crates/node/engine/Cargo.toml index 3545fcaf9f9..643ae9d47aa 100644 --- a/rust/kona/crates/node/engine/Cargo.toml +++ b/rust/kona/crates/node/engine/Cargo.toml @@ -20,7 +20,6 @@ kona-protocol = {workspace = true, features = ["serde", "std"]} # alloy alloy-eips.workspace = true alloy-consensus.workspace = true -alloy-json-rpc.workspace = true alloy-network.workspace = true alloy-transport.workspace = true alloy-primitives.workspace = true @@ -48,17 +47,10 @@ tower.workspace = true http-body-util.workspace = true derive_more = { workspace = true, features = ["display", "deref", "from_str", "constructor"] } serde_json.workspace = true -jsonrpsee-types.workspace = true # metrics metrics = { workspace = true, optional = true } -# rollup boost -rollup-boost.workspace = true -rollup-boost-types.workspace = true -http.workspace = true -parking_lot.workspace = true - [dev-dependencies] kona-registry.workspace = true rand = {workspace = true, features = ["thread_rng"]} @@ -70,5 +62,6 @@ rstest.workspace = true [features] metrics = [ "dep:metrics" ] test-utils = [ - "kona-protocol/test-utils" + "kona-protocol/test-utils", + "alloy-primitives/rand", ] diff --git a/rust/kona/crates/node/engine/src/client.rs b/rust/kona/crates/node/engine/src/client.rs index 4e73ece6919..71c1cb9a96e 100644 --- a/rust/kona/crates/node/engine/src/client.rs +++ b/rust/kona/crates/node/engine/src/client.rs @@ -1,6 +1,6 @@ //! An Engine API Client. -use crate::{Metrics, RollupBoostServerArgs, RollupBoostServerError}; +use crate::Metrics; use alloy_eips::{BlockId, eip1898::BlockNumberOrTag}; use alloy_network::{Ethereum, Network}; use alloy_primitives::{Address, B256, BlockHash, Bytes, StorageKey}; @@ -21,7 +21,6 @@ use alloy_transport_http::{ }, }; use async_trait::async_trait; -use http::uri::InvalidUri; use http_body_util::Full; use kona_genesis::RollupConfig; use kona_protocol::{FromBlockError, L2BlockInfo}; @@ -32,19 +31,7 @@ use op_alloy_rpc_types_engine::{ OpExecutionPayloadEnvelopeV3, OpExecutionPayloadEnvelopeV4, OpExecutionPayloadV4, OpPayloadAttributes, ProtocolVersion, }; -use parking_lot::Mutex; -use rollup_boost::{ - EngineApiServer, Flashblocks, FlashblocksWebsocketConfig, Probes, RollupBoostServer, - RpcClientError, -}; -use rollup_boost_types::payload::PayloadSource; -use std::{ - future::Future, - net::{AddrParseError, IpAddr, SocketAddr}, - str::FromStr, - sync::Arc, - time::{Duration, Instant}, -}; +use std::{future::Future, sync::Arc, time::Instant}; use thiserror::Error; use tower::ServiceBuilder; use url::Url; @@ -63,7 +50,7 @@ pub enum EngineClientError { /// A Hyper HTTP client with a JWT authentication layer. pub type HyperAuthClient> = HyperClient>>; -/// Engine API client used to communicate with L1/L2 ELs and optional rollup-boost. +/// Engine API client used to communicate with L1/L2 ELs. /// `EngineClient` trait that is very coupled to its only implementation. /// The main reason this exists is for mocking/unit testing. #[async_trait] @@ -106,8 +93,6 @@ pub trait EngineClient: OpEngineApi> + Send + Sy /// The [`OpEngineClient`] handles JWT authentication and manages connections to both L1 and L2 /// execution layers. It automatically selects the appropriate Engine API version based on the /// rollup configuration and block timestamps. -/// -/// Engine API client used to communicate with L1/L2 ELs and optional rollup-boost. #[derive(Clone, Debug)] pub struct OpEngineClient where @@ -120,8 +105,6 @@ where l1_provider: L1Provider, /// The [`RollupConfig`] for determining Engine API versions based on hardfork activations. cfg: Arc, - /// The rollup boost server - pub rollup_boost: Arc, } impl OpEngineClient @@ -144,124 +127,22 @@ where /// The builder for the [`OpEngineClient`]. #[derive(Debug, Clone)] pub struct EngineClientBuilder { - /// The builder URL. - pub builder: Url, - /// The builder JWT secret. - pub builder_jwt: JwtSecret, - /// The builder timeout. - pub builder_timeout: Duration, /// The L2 Engine API endpoint URL. pub l2: Url, /// The L2 JWT secret. pub l2_jwt: JwtSecret, - /// The L2 timeout. - pub l2_timeout: Duration, /// The L1 RPC URL. pub l1_rpc: Url, /// The [`RollupConfig`] for determining Engine API versions based on hardfork activations. pub cfg: Arc, - /// The rollup boost arguments. - pub rollup_boost: RollupBoostServerArgs, -} - -/// An error that occurred in the [`EngineClientBuilder`]. -#[derive(Error, Debug)] -pub enum EngineClientBuilderError { - /// An error occurred while parsing the URL - #[error("An error occurred while parsing the URL: {0}")] - UrlParseError(#[from] InvalidUri), - /// An error occurred while parsing the IP address - #[error("An error occurred while parsing the IP address: {0}")] - IpAddrParseError(#[from] AddrParseError), - /// An error occurred while creating the RPC client - #[error("An error occurred while creating the RPC client: {0}")] - RpcClientError(#[from] RpcClientError), - /// An error occurred while creating the Flashblocks service - #[error("An error occurred while creating the Flashblocks service: {0}")] - FlashblocksError(String), } impl EngineClientBuilder { /// Creates a new [`OpEngineClient`] with authenticated HTTP connections. /// - /// Sets up JWT-authenticated connections to the Engine API endpoint through the rollup-boost - /// server along with an unauthenticated connection to the L1 chain. - /// - /// # FIXME(@theochap, ``, ``): - /// This method can be simplified/improved in a few ways: - /// - Unify kona's and rollup-boost's RPC client creation - /// - Removed the `dyn RollupBoostServerLike` type erasure. - pub fn build( - self, - ) -> Result>, EngineClientBuilderError> - { - let probes = Arc::new(Probes::default()); - let l2_client = rollup_boost::RpcClient::new( - http::Uri::from_str(self.l2.to_string().as_str())?, - self.l2_jwt, - self.l2_timeout.as_millis() as u64, - PayloadSource::L2, - )?; - let builder_client = rollup_boost::RpcClient::new( - http::Uri::from_str(self.builder.to_string().as_str())?, - self.builder_jwt, - self.builder_timeout.as_millis() as u64, - PayloadSource::Builder, - )?; - - let rollup_boost_server = match self.rollup_boost.flashblocks { - Some(flashblocks) => { - let inbound_url = flashblocks.flashblocks_builder_url; - let outbound_addr = SocketAddr::new( - IpAddr::from_str(&flashblocks.flashblocks_host)?, - flashblocks.flashblocks_port, - ); - - let ws_config = flashblocks.flashblocks_ws_config; - - let builder_client = Arc::new( - Flashblocks::run( - builder_client, - inbound_url, - outbound_addr, - FlashblocksWebsocketConfig { - flashblock_builder_ws_initial_reconnect_ms: ws_config - .flashblock_builder_ws_initial_reconnect_ms, - flashblock_builder_ws_max_reconnect_ms: ws_config - .flashblock_builder_ws_max_reconnect_ms, - flashblock_builder_ws_connect_timeout_ms: ws_config - .flashblock_builder_ws_connect_timeout_ms, - flashblock_builder_ws_ping_interval_ms: ws_config - .flashblock_builder_ws_ping_interval_ms, - flashblock_builder_ws_pong_timeout_ms: ws_config - .flashblock_builder_ws_pong_timeout_ms, - }, - ) - .map_err(|e| EngineClientBuilderError::FlashblocksError(e.to_string()))?, - ); - Arc::new(rollup_boost::RollupBoostServer::new( - l2_client, - builder_client, - Arc::new(Mutex::new(self.rollup_boost.initial_execution_mode)), - self.rollup_boost.block_selection_policy, - probes, - self.rollup_boost.external_state_root, - self.rollup_boost.ignore_unhealthy_builders, - )) - } - None => Arc::new(rollup_boost::RollupBoostServer::new( - l2_client, - Arc::new(builder_client), - Arc::new(Mutex::new(self.rollup_boost.initial_execution_mode)), - self.rollup_boost.block_selection_policy, - probes, - self.rollup_boost.external_state_root, - self.rollup_boost.ignore_unhealthy_builders, - )), - }; - - // TODO(ethereum-optimism/optimism#18656): remove this client, upstream the remaining - // EngineApiExt methods to the RollupBoostServer + /// Sets up a JWT-authenticated connection to the L2 Engine API endpoint + /// along with an unauthenticated connection to the L1 chain. + pub fn build(self) -> OpEngineClient> { let engine = OpEngineClient::>::rpc_client::( self.l2, self.l2_jwt, @@ -269,7 +150,7 @@ impl EngineClientBuilder { let l1_provider = RootProvider::new_http(self.l1_rpc); - Ok(OpEngineClient { engine, l1_provider, cfg: self.cfg, rollup_boost: rollup_boost_server }) + OpEngineClient { engine, l1_provider, cfg: self.cfg } } } @@ -346,11 +227,13 @@ where payload: ExecutionPayloadV3, parent_beacon_block_root: B256, ) -> TransportResult { - let call = self.rollup_boost.new_payload_v3(payload, vec![], parent_beacon_block_root); + let call = >>::new_payload_v3( + &self.engine, + payload, + parent_beacon_block_root, + ); - record_call_time(call, Metrics::NEW_PAYLOAD_METHOD) - .await - .map_err(|err| RollupBoostServerError::from(err).into()) + record_call_time(call, Metrics::NEW_PAYLOAD_METHOD).await } async fn new_payload_v4( @@ -358,16 +241,13 @@ where payload: OpExecutionPayloadV4, parent_beacon_block_root: B256, ) -> TransportResult { - let call = self.rollup_boost.new_payload_v4( - payload.clone(), - vec![], + let call = >>::new_payload_v4( + &self.engine, + payload, parent_beacon_block_root, - vec![], ); - record_call_time(call, Metrics::NEW_PAYLOAD_METHOD) - .await - .map_err(|err| RollupBoostServerError::from(err).into()) + record_call_time(call, Metrics::NEW_PAYLOAD_METHOD).await } async fn fork_choice_updated_v2( @@ -390,11 +270,14 @@ where fork_choice_state: ForkchoiceState, payload_attributes: Option, ) -> TransportResult { - let call = self.rollup_boost.fork_choice_updated_v3(fork_choice_state, payload_attributes); + let call = + >>::fork_choice_updated_v3( + &self.engine, + fork_choice_state, + payload_attributes, + ); - record_call_time(call, Metrics::FORKCHOICE_UPDATE_METHOD) - .await - .map_err(|err| RollupBoostServerError::from(err).into()) + record_call_time(call, Metrics::FORKCHOICE_UPDATE_METHOD).await } async fn get_payload_v2( @@ -413,22 +296,24 @@ where &self, payload_id: PayloadId, ) -> TransportResult { - let call = self.rollup_boost.get_payload_v3(payload_id); + let call = >>::get_payload_v3( + &self.engine, + payload_id, + ); - record_call_time(call, Metrics::GET_PAYLOAD_METHOD) - .await - .map_err(|err| RollupBoostServerError::from(err).into()) + record_call_time(call, Metrics::GET_PAYLOAD_METHOD).await } async fn get_payload_v4( &self, payload_id: PayloadId, ) -> TransportResult { - let call = self.rollup_boost.get_payload_v4(payload_id); + let call = >>::get_payload_v4( + &self.engine, + payload_id, + ); - record_call_time(call, Metrics::GET_PAYLOAD_METHOD) - .await - .map_err(|err| RollupBoostServerError::from(err).into()) + record_call_time(call, Metrics::GET_PAYLOAD_METHOD).await } async fn get_payload_bodies_by_hash_v1( diff --git a/rust/kona/crates/node/engine/src/lib.rs b/rust/kona/crates/node/engine/src/lib.rs index 22b647bb468..f70a9942964 100644 --- a/rust/kona/crates/node/engine/src/lib.rs +++ b/rust/kona/crates/node/engine/src/lib.rs @@ -51,14 +51,7 @@ pub use attributes::{AttributesMatch, AttributesMismatch}; mod client; pub use client::{ - EngineClient, EngineClientBuilder, EngineClientBuilderError, EngineClientError, - HyperAuthClient, OpEngineClient, -}; - -mod rollup_boost; -pub use rollup_boost::{ - FlashblocksClientArgs, FlashblocksWebsocketConfig, RollupBoostServer, RollupBoostServerArgs, - RollupBoostServerError, + EngineClient, EngineClientBuilder, EngineClientError, HyperAuthClient, OpEngineClient, }; mod versions; diff --git a/rust/kona/crates/node/engine/src/rollup_boost.rs b/rust/kona/crates/node/engine/src/rollup_boost.rs deleted file mode 100644 index 9dc21079839..00000000000 --- a/rust/kona/crates/node/engine/src/rollup_boost.rs +++ /dev/null @@ -1,83 +0,0 @@ -//! Rollup-boost abstraction used by the engine client. - -use alloy_json_rpc::{ErrorPayload, RpcError}; -use alloy_transport::TransportErrorKind; -use rollup_boost::ExecutionMode; -use std::fmt::Debug; - -use rollup_boost::BlockSelectionPolicy; -pub use rollup_boost::RollupBoostServer; -use url::Url; - -/// Configuration for the rollup-boost server. -#[derive(Clone, Debug)] -pub struct RollupBoostServerArgs { - /// The initial execution mode of the rollup-boost server. - pub initial_execution_mode: ExecutionMode, - /// The block selection policy of the rollup-boost server. - pub block_selection_policy: Option, - /// Whether to use the l2 client for computing state root. - pub external_state_root: bool, - /// Allow all engine API calls to builder even when marked as unhealthy - /// This is default true assuming no builder CL set up - pub ignore_unhealthy_builders: bool, - /// Flashblocks configuration - pub flashblocks: Option, -} - -/// Configuration for the Flashblocks client. -#[derive(Clone, Debug)] -pub struct FlashblocksClientArgs { - /// Flashblocks Builder `WebSocket` URL - pub flashblocks_builder_url: Url, - - /// Flashblocks `WebSocket` host for outbound connections - pub flashblocks_host: String, - - /// Flashblocks `WebSocket` port for outbound connections - pub flashblocks_port: u16, - - /// Websocket connection configuration - pub flashblocks_ws_config: FlashblocksWebsocketConfig, -} - -/// Configuration for the Flashblocks `WebSocket` connection. -#[derive(Debug, Clone, Copy)] -pub struct FlashblocksWebsocketConfig { - /// Minimum time for exponential backoff for timeout if builder disconnected - pub flashblock_builder_ws_initial_reconnect_ms: u64, - - /// Maximum time for exponential backoff for timeout if builder disconnected - pub flashblock_builder_ws_max_reconnect_ms: u64, - - /// Timeout for connection attempt - pub flashblock_builder_ws_connect_timeout_ms: u64, - - /// Interval in milliseconds between ping messages sent to upstream servers to detect - /// unresponsive connections - pub flashblock_builder_ws_ping_interval_ms: u64, - - /// Timeout in milliseconds to wait for pong responses from upstream servers before considering - /// the connection dead - pub flashblock_builder_ws_pong_timeout_ms: u64, -} - -/// An error that occurred in the rollup-boost server. -#[derive(Debug, thiserror::Error)] -pub enum RollupBoostServerError { - /// JSON-RPC error. - #[error("Rollup boost server error: {0}")] - Jsonrpsee(#[from] jsonrpsee_types::ErrorObjectOwned), -} - -impl From for RpcError { - fn from(error: RollupBoostServerError) -> Self { - match error { - RollupBoostServerError::Jsonrpsee(error) => Self::ErrorResp(ErrorPayload { - code: error.code().into(), - message: error.message().to_string().into(), - data: None, - }), - } - } -} diff --git a/rust/kona/crates/node/rpc/Cargo.toml b/rust/kona/crates/node/rpc/Cargo.toml index dadfbeb43c2..3b4a26e08c6 100644 --- a/rust/kona/crates/node/rpc/Cargo.toml +++ b/rust/kona/crates/node/rpc/Cargo.toml @@ -61,9 +61,6 @@ alloy-rpc-client = { workspace = true, features = ["reqwest"], optional = true } # `metrics` feature metrics = { workspace = true, optional = true } -# `rollup-boost` feature -rollup-boost.workspace = true - [dev-dependencies] serde_json.workspace = true diff --git a/rust/kona/crates/node/rpc/src/admin.rs b/rust/kona/crates/node/rpc/src/admin.rs index 4c13c01d7d0..e7714791eab 100644 --- a/rust/kona/crates/node/rpc/src/admin.rs +++ b/rust/kona/crates/node/rpc/src/admin.rs @@ -1,6 +1,6 @@ //! Admin RPC Module -use crate::{AdminApiServer, RollupBoostAdminClient, SequencerAdminAPIClient}; +use crate::{AdminApiServer, SequencerAdminAPIClient}; use alloy_primitives::B256; use async_trait::async_trait; use core::fmt::Debug; @@ -9,10 +9,6 @@ use jsonrpsee::{ types::{ErrorCode, ErrorObject}, }; use op_alloy_rpc_types_engine::OpExecutionPayloadEnvelope; -use rollup_boost::{ - ExecutionMode, GetExecutionModeResponse, SetExecutionModeRequest, SetExecutionModeResponse, -}; -use tokio::sync::oneshot; /// The query types to the network actor for the admin api. #[derive(Debug)] @@ -24,71 +20,43 @@ pub enum NetworkAdminQuery { }, } -/// The query types to the rollup boost component of the engine actor. -/// Only set when rollup boost is enabled. -#[derive(Debug)] -pub enum RollupBoostAdminQuery { - /// An admin rpc request to set the execution mode. - SetExecutionMode { - /// The execution mode to set. - execution_mode: ExecutionMode, - /// The sender to send the response confirming the execution mode was updated. - sender: oneshot::Sender<()>, - }, - /// An admin rpc request to get the execution mode. - GetExecutionMode { - /// The sender to send the execution mode to. - sender: oneshot::Sender, - }, -} - type NetworkAdminQuerySender = tokio::sync::mpsc::Sender; /// The admin rpc server. #[derive(Debug)] -pub struct AdminRpc { +pub struct AdminRpc { /// The sequencer admin API client. pub sequencer_admin_client: Option, /// The sender to the network actor. pub network_sender: NetworkAdminQuerySender, - /// The sender to the rollup boost component of the engine actor. - /// Only set when rollup boost is enabled. - pub rollup_boost_client: Option, } -impl - AdminRpc +impl AdminRpc where - RollupBoostAdminClient_: RollupBoostAdminClient, SequencerAdminAPIClient_: SequencerAdminAPIClient, { - /// Constructs a new [`AdminRpc`] given the sequencer sender, network sender, and execution - /// mode. + /// Constructs a new [`AdminRpc`] given the sequencer sender and network sender. /// /// # Parameters /// /// - `sequencer_sender`: The [`SequencerAdminAPIClient`] used to fulfill sequencer admin /// queries. /// - `network_sender`: The sender to the network actor. - /// - `rollup_boost_sender`: The [`RollupBoostAdminClient`] used to fulfill rollup boost admin - /// queries. + /// /// # Returns /// /// A new [`AdminRpc`] instance. pub const fn new( sequencer_admin_client: Option, network_sender: NetworkAdminQuerySender, - rollup_boost_client: Option, ) -> Self { - Self { sequencer_admin_client, network_sender, rollup_boost_client } + Self { sequencer_admin_client, network_sender } } } #[async_trait] -impl AdminApiServer - for AdminRpc +impl AdminApiServer for AdminRpc where - RollupBoostAdminClient_: RollupBoostAdminClient + 'static + Send + Sync, SequencerAdminAPIClient_: SequencerAdminAPIClient + 'static + Send + Sync, { async fn admin_post_unsafe_payload( @@ -186,25 +154,6 @@ where .map_err(|_| ErrorObject::from(ErrorCode::InternalError)) } - async fn set_execution_mode( - &self, - request: SetExecutionModeRequest, - ) -> RpcResult { - let Some(ref client) = self.rollup_boost_client else { - return Err(ErrorObject::from(ErrorCode::MethodNotFound)); - }; - - client.set_execution_mode(request).await - } - - async fn get_execution_mode(&self) -> RpcResult { - let Some(ref client) = self.rollup_boost_client else { - return Err(ErrorObject::from(ErrorCode::MethodNotFound)); - }; - - client.get_execution_mode().await - } - async fn admin_reset_derivation_pipeline(&self) -> RpcResult<()> { // If the sequencer is not enabled (mode runs in validator mode), return an error. let Some(ref sequencer_client) = self.sequencer_admin_client else { diff --git a/rust/kona/crates/node/rpc/src/client.rs b/rust/kona/crates/node/rpc/src/client.rs index 1505e48f70f..7833b0636f0 100644 --- a/rust/kona/crates/node/rpc/src/client.rs +++ b/rust/kona/crates/node/rpc/src/client.rs @@ -5,7 +5,6 @@ use jsonrpsee::core::RpcResult; use kona_engine::EngineState; use kona_genesis::RollupConfig; use kona_protocol::{L2BlockInfo, OutputRoot}; -use rollup_boost::{GetExecutionModeResponse, SetExecutionModeRequest, SetExecutionModeResponse}; use std::fmt::Debug; use thiserror::Error; use tokio::sync::watch; @@ -35,19 +34,6 @@ pub trait EngineRpcClient: Debug + Send + Sync + Clone { async fn dev_subscribe_to_engine_state(&self) -> RpcResult>; } -/// Client trait wrapping RPC implementation for the rollup boost admin endpoints. -#[async_trait] -pub trait RollupBoostAdminClient: Send + Sync + Debug { - /// Sets the execution mode for the rollup boost server. - async fn set_execution_mode( - &self, - request: SetExecutionModeRequest, - ) -> RpcResult; - - /// Gets the current execution mode from the rollup boost server. - async fn get_execution_mode(&self) -> RpcResult; -} - /// Client trait wrapping RPC implementation for the Sequencer admin endpoints. #[async_trait] pub trait SequencerAdminAPIClient: Send + Sync + Debug { diff --git a/rust/kona/crates/node/rpc/src/health.rs b/rust/kona/crates/node/rpc/src/health.rs index 777c5c781e6..1a831bcc7c3 100644 --- a/rust/kona/crates/node/rpc/src/health.rs +++ b/rust/kona/crates/node/rpc/src/health.rs @@ -1,52 +1,8 @@ use async_trait::async_trait; use jsonrpsee::core::RpcResult; -use rollup_boost::Health; -use tokio::sync::oneshot; use crate::jsonrpsee::HealthzApiServer; -/// Key for the rollup boost health status. -/// +----------------+-------------------------------+--------------------------------------+-------------------------------+ -/// | Execution Mode | Healthy | `PartialContent` | Service Unavailable | -/// +----------------+-------------------------------+--------------------------------------+-------------------------------+ -/// | Enabled | - Request-path: L2 succeeds | - Request-path: builder fails/stale | - Request-path: L2 fails | -/// | | (get/new payload) → 200 | while L2 succeeds → 206 | (error from L2) → 503 | -/// | | - Background: builder | - Background: builder fetch fails or | - Background: never sets 503 | -/// | | latest-unsafe is fresh → | latest-unsafe is stale → 206 | | -/// | | 200 | | | -/// +----------------+-------------------------------+--------------------------------------+-------------------------------+ -/// | `DryRun` | - Request-path: L2 succeeds | - Never set in `DryRun` | - Request-path: L2 fails | -/// | | (always returns L2) → 200 | (degrade only in Enabled) | (error from L2) → 503 | -/// | | - Background: builder stale | | - Background: never sets 503 | -/// | | ignored (remains 200) | | | -/// +----------------+-------------------------------+--------------------------------------+-------------------------------+ -/// | Disabled | - Request-path: L2 succeeds | - Never set in Disabled | - Request-path: L2 fails | -/// | | (builder skipped) → 200 | (degrade only in Enabled) | (error from L2) → 503 | -/// | | - Background: N/A | | - Background: never sets 503 | -/// +----------------+-------------------------------+--------------------------------------+-------------------------------+ -/// -/// This type is the same as [`Health`], but it implements `serde::Serialize` -/// and `serde::Deserialize`. -#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -pub enum RollupBoostHealth { - /// Rollup boost is healthy. - Healthy, - /// Rollup boost is partially healthy. - PartialContent, - /// Rollup boost service is unavailable. - ServiceUnavailable, -} - -impl From for RollupBoostHealth { - fn from(health: Health) -> Self { - match health { - Health::Healthy => Self::Healthy, - Health::PartialContent => Self::PartialContent, - Health::ServiceUnavailable => Self::ServiceUnavailable, - } - } -} - /// A healthcheck response for the RPC server. #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] pub struct HealthzResponse { @@ -54,20 +10,6 @@ pub struct HealthzResponse { pub version: String, } -/// A healthcheck response for the rollup boost health. -#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] -pub struct RollupBoostHealthzResponse { - /// The rollup boost health. - pub rollup_boost_health: RollupBoostHealth, -} - -/// A query to get the health of the rollup boost server. -#[derive(Debug)] -pub struct RollupBoostHealthQuery { - /// The sender to send the rollup boost health to. - pub sender: oneshot::Sender, -} - /// The healthz rpc server. #[derive(Debug, Clone)] pub struct HealthzRpc {} diff --git a/rust/kona/crates/node/rpc/src/jsonrpsee.rs b/rust/kona/crates/node/rpc/src/jsonrpsee.rs index c09ca3e4bea..c79acccdc5c 100644 --- a/rust/kona/crates/node/rpc/src/jsonrpsee.rs +++ b/rust/kona/crates/node/rpc/src/jsonrpsee.rs @@ -1,9 +1,6 @@ //! The Optimism RPC API using `jsonrpsee` -use crate::{ - OutputResponse, SafeHeadResponse, - health::{HealthzResponse, RollupBoostHealthzResponse}, -}; +use crate::{OutputResponse, SafeHeadResponse, health::HealthzResponse}; use alloy_eips::BlockNumberOrTag; use alloy_primitives::B256; use core::net::IpAddr; @@ -16,7 +13,6 @@ use kona_genesis::RollupConfig; use kona_gossip::{PeerCount, PeerDump, PeerInfo, PeerStats}; use kona_protocol::SyncStatus; use op_alloy_rpc_types_engine::OpExecutionPayloadEnvelope; -use rollup_boost::{GetExecutionModeResponse, SetExecutionModeRequest, SetExecutionModeResponse}; #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), allow(unused_imports))] use getrandom as _; // required for compiling wasm32-unknown-unknown @@ -206,17 +202,6 @@ pub trait AdminApi { /// Resets the derivation pipeline. #[method(name = "resetDerivationPipeline")] async fn admin_reset_derivation_pipeline(&self) -> RpcResult<()>; - - /// Sets the rollup boost execution mode. - #[method(name = "setExecutionMode")] - async fn set_execution_mode( - &self, - request: SetExecutionModeRequest, - ) -> RpcResult; - - /// Gets the rollup boost execution mode. - #[method(name = "getExecutionMode")] - async fn get_execution_mode(&self) -> RpcResult; } /// The admin namespace for the consensus node. @@ -227,12 +212,3 @@ pub trait HealthzApi { #[method(name = "healthz")] async fn healthz(&self) -> RpcResult; } - -/// The rollup boost health namespace. -#[cfg_attr(not(feature = "client"), rpc(server, namespace = "kona-rollup-boost"))] -#[cfg_attr(feature = "client", rpc(server, client, namespace = "kona-rollup-boost"))] -pub trait RollupBoostHealthzApi { - /// Gets the rollup boost health. - #[method(name = "healthz")] - async fn rollup_boost_healthz(&self) -> RpcResult; -} diff --git a/rust/kona/crates/node/rpc/src/lib.rs b/rust/kona/crates/node/rpc/src/lib.rs index 28d8559986b..37b4dbe11a7 100644 --- a/rust/kona/crates/node/rpc/src/lib.rs +++ b/rust/kona/crates/node/rpc/src/lib.rs @@ -10,12 +10,10 @@ extern crate tracing; mod admin; -pub use admin::{AdminRpc, NetworkAdminQuery, RollupBoostAdminQuery}; +pub use admin::{AdminRpc, NetworkAdminQuery}; mod client; -pub use client::{ - EngineRpcClient, RollupBoostAdminClient, SequencerAdminAPIClient, SequencerAdminAPIError, -}; +pub use client::{EngineRpcClient, SequencerAdminAPIClient, SequencerAdminAPIError}; mod config; pub use config::RpcBuilder; @@ -37,7 +35,7 @@ pub use dev::DevEngineRpc; mod jsonrpsee; pub use jsonrpsee::{ AdminApiServer, DevEngineApiServer, HealthzApiServer, MinerApiExtServer, OpAdminApiServer, - OpP2PApiServer, RollupBoostHealthzApiServer, RollupNodeApiServer, WsServer, + OpP2PApiServer, RollupNodeApiServer, WsServer, }; #[cfg(feature = "client")] @@ -53,7 +51,4 @@ mod ws; pub use ws::WsRPC; mod health; -pub use health::{ - HealthzResponse, HealthzRpc, RollupBoostHealth, RollupBoostHealthQuery, - RollupBoostHealthzResponse, -}; +pub use health::{HealthzResponse, HealthzRpc}; diff --git a/rust/kona/crates/node/service/Cargo.toml b/rust/kona/crates/node/service/Cargo.toml index 9014f105fca..b63636047f9 100644 --- a/rust/kona/crates/node/service/Cargo.toml +++ b/rust/kona/crates/node/service/Cargo.toml @@ -25,9 +25,6 @@ kona-rpc = { workspace = true, features = ["client"] } kona-peers.workspace = true kona-macros.workspace = true -# rollup-boost -rollup-boost.workspace = true - # alloy alloy-chains.workspace = true alloy-signer.workspace = true @@ -75,7 +72,6 @@ arbitrary.workspace = true rand.workspace = true anyhow.workspace = true backon.workspace = true -http.workspace = true mockall.workspace = true alloy-primitives = { workspace = true, features = ["k256"] } alloy-rpc-types-engine = { workspace = true, features = ["arbitrary"] } diff --git a/rust/kona/crates/node/service/src/actors/engine/config.rs b/rust/kona/crates/node/service/src/actors/engine/config.rs index be4bd3b83fc..fc1e6c4b809 100644 --- a/rust/kona/crates/node/service/src/actors/engine/config.rs +++ b/rust/kona/crates/node/service/src/actors/engine/config.rs @@ -1,12 +1,10 @@ use crate::NodeMode; use alloy_provider::RootProvider; use alloy_rpc_types_engine::JwtSecret; -use kona_engine::{ - EngineClientBuilder, EngineClientBuilderError, OpEngineClient, RollupBoostServerArgs, -}; +use kona_engine::{EngineClientBuilder, OpEngineClient}; use kona_genesis::RollupConfig; use op_alloy_network::Optimism; -use std::{sync::Arc, time::Duration}; +use std::sync::Arc; use url::Url; /// Configuration for the Engine Actor. @@ -15,19 +13,10 @@ pub struct EngineConfig { /// The [`RollupConfig`]. pub config: Arc, - /// Builder url. - pub builder_url: Url, - /// Builder jwt secret. - pub builder_jwt_secret: JwtSecret, - /// Builder timeout. - pub builder_timeout: Duration, - /// The engine rpc url. pub l2_url: Url, /// The engine jwt secret. pub l2_jwt_secret: JwtSecret, - /// The l2 timeout. - pub l2_timeout: Duration, /// The L1 rpc url. pub l1_url: Url, @@ -36,27 +25,16 @@ pub struct EngineConfig { /// When the node is in sequencer mode, the engine actor will receive requests to build blocks /// from the sequencer actor. pub mode: NodeMode, - - /// The rollup boost arguments. - pub rollup_boost: RollupBoostServerArgs, } impl EngineConfig { /// Builds and returns the [`OpEngineClient`]. - pub fn build_engine_client( - self, - ) -> Result>, EngineClientBuilderError> - { + pub fn build_engine_client(self) -> OpEngineClient> { EngineClientBuilder { - builder: self.builder_url.clone(), - builder_jwt: self.builder_jwt_secret, - builder_timeout: self.builder_timeout, - l2: self.l2_url.clone(), + l2: self.l2_url, l2_jwt: self.l2_jwt_secret, - l2_timeout: self.l2_timeout, - l1_rpc: self.l1_url.clone(), - cfg: self.config.clone(), - rollup_boost: self.rollup_boost, + l1_rpc: self.l1_url, + cfg: self.config, } .build() } diff --git a/rust/kona/crates/node/service/src/actors/engine/error.rs b/rust/kona/crates/node/service/src/actors/engine/error.rs index 1a8055c35ec..64fe428d00e 100644 --- a/rust/kona/crates/node/service/src/actors/engine/error.rs +++ b/rust/kona/crates/node/service/src/actors/engine/error.rs @@ -2,7 +2,7 @@ //! //! [`EngineActor`]: super::EngineActor -use kona_engine::{EngineClientBuilderError, EngineResetError, EngineTaskErrors}; +use kona_engine::{EngineResetError, EngineTaskErrors}; /// An error from the [`EngineActor`]. /// @@ -15,9 +15,6 @@ pub enum EngineError { /// Engine reset error. #[error(transparent)] EngineReset(#[from] EngineResetError), - /// Engine client builder error. - #[error(transparent)] - EngineClientBuilder(#[from] EngineClientBuilderError), /// Engine task error. #[error(transparent)] EngineTask(#[from] EngineTaskErrors), diff --git a/rust/kona/crates/node/service/src/actors/engine/request.rs b/rust/kona/crates/node/service/src/actors/engine/request.rs index 5b058d8bfed..511b7eb7c32 100644 --- a/rust/kona/crates/node/service/src/actors/engine/request.rs +++ b/rust/kona/crates/node/service/src/actors/engine/request.rs @@ -1,7 +1,6 @@ use alloy_rpc_types_engine::PayloadId; use kona_engine::{BuildTaskError, ConsolidateInput, EngineQueries, SealTaskError}; use kona_protocol::OpAttributesWithParent; -use kona_rpc::{RollupBoostAdminQuery, RollupBoostHealthQuery}; use op_alloy_rpc_types_engine::OpExecutionPayloadEnvelope; use thiserror::Error; use tokio::sync::mpsc; @@ -56,14 +55,7 @@ pub enum EngineActorRequest { /// RPC Request for the engine to handle. #[derive(Debug)] -pub enum EngineRpcRequest { - /// Engine RPC query. - EngineQuery(Box), - /// Rollup boost admin request. - RollupBoostAdminRequest(Box), - /// Rollup boost health request. - RollupBoostHealthRequest(Box), -} +pub struct EngineRpcRequest(pub Box); /// A request to build a payload. /// Contains the attributes to build and a channel to send back the resulting `PayloadId`. diff --git a/rust/kona/crates/node/service/src/actors/engine/rollup_boost.rs b/rust/kona/crates/node/service/src/actors/engine/rollup_boost.rs deleted file mode 100644 index 8b137891791..00000000000 --- a/rust/kona/crates/node/service/src/actors/engine/rollup_boost.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/rust/kona/crates/node/service/src/actors/engine/rpc_request_processor.rs b/rust/kona/crates/node/service/src/actors/engine/rpc_request_processor.rs index d622d93e019..1c48c4a5bc7 100644 --- a/rust/kona/crates/node/service/src/actors/engine/rpc_request_processor.rs +++ b/rust/kona/crates/node/service/src/actors/engine/rpc_request_processor.rs @@ -1,8 +1,7 @@ use crate::{EngineError, EngineRpcRequest}; use derive_more::Constructor; -use kona_engine::{EngineClient, EngineState, RollupBoostServer}; +use kona_engine::{EngineClient, EngineState}; use kona_genesis::RollupConfig; -use kona_rpc::RollupBoostAdminQuery; use std::sync::Arc; use tokio::{ sync::{mpsc, watch}, @@ -25,8 +24,6 @@ pub trait EngineRpcRequestReceiver: Send + Sync { pub struct EngineRpcProcessor { /// An [`EngineClient`] used for creating engine tasks. engine_client: Arc, - // RollupBoost server handle - rollup_boost_server: Arc, /// The [`RollupConfig`] used to build tasks. rollup_config: Arc, /// Receiver for [`EngineState`] updates. @@ -40,54 +37,23 @@ where EngineClient_: EngineClient + 'static, { async fn handle_rpc_request(&self, request: EngineRpcRequest) -> Result<(), EngineError> { - match request { - EngineRpcRequest::EngineQuery(req) => { - trace!(target: "engine", ?req, "Received engine query."); + let EngineRpcRequest(req) = request; + trace!(target: "engine", ?req, "Received engine query."); - if let Err(e) = req - .handle( - &self.engine_state_receiver, - &self.engine_queue_length_receiver, - &self.engine_client, - &self.rollup_config, - ) - .await - { - warn!(target: "engine", err = ?e, "Failed to handle engine query."); - } - } - EngineRpcRequest::RollupBoostAdminRequest(admin_query) => { - trace!(target: "engine", ?admin_query, "Received rollup boost admin query."); - - self.handle_rollup_boost_admin_query(*admin_query); - } - EngineRpcRequest::RollupBoostHealthRequest(health_query) => { - trace!(target: "engine", ?health_query, "Received rollup boost health query."); - - let health = self.rollup_boost_server.probes().health(); - health_query.sender.send(health.into()).unwrap(); - } + if let Err(e) = req + .handle( + &self.engine_state_receiver, + &self.engine_queue_length_receiver, + &self.engine_client, + &self.rollup_config, + ) + .await + { + warn!(target: "engine", err = ?e, "Failed to handle engine query."); } Ok(()) } - - fn handle_rollup_boost_admin_query(&self, admin_query: RollupBoostAdminQuery) { - match admin_query { - RollupBoostAdminQuery::SetExecutionMode { execution_mode, sender } => { - self.rollup_boost_server.set_execution_mode(execution_mode); - let _ = sender.send(()).map_err(|_| { - warn!(target: "engine", "set execution mode response channel closed when trying to send"); - }); - } - RollupBoostAdminQuery::GetExecutionMode { sender } => { - let execution_mode = self.rollup_boost_server.get_execution_mode(); - let _ = sender.send(execution_mode).map_err(|_| { - warn!(target: "engine", "get execution mode response channel closed when trying to send"); - }); - } - } - } } impl EngineRpcRequestReceiver for EngineRpcProcessor diff --git a/rust/kona/crates/node/service/src/actors/mod.rs b/rust/kona/crates/node/service/src/actors/mod.rs index 5002b554cf4..de24ab9de65 100644 --- a/rust/kona/crates/node/service/src/actors/mod.rs +++ b/rust/kona/crates/node/service/src/actors/mod.rs @@ -15,8 +15,7 @@ pub use engine::{ mod rpc; pub use rpc::{ - QueuedEngineRpcClient, QueuedSequencerAdminAPIClient, RollupBoostAdminApiClient, - RollupBoostHealthRpcClient, RpcActor, RpcActorError, RpcContext, + QueuedEngineRpcClient, QueuedSequencerAdminAPIClient, RpcActor, RpcActorError, RpcContext, }; mod derivation; diff --git a/rust/kona/crates/node/service/src/actors/rpc/actor.rs b/rust/kona/crates/node/service/src/actors/rpc/actor.rs index d8b25a8d17e..5da44dfeef2 100644 --- a/rust/kona/crates/node/service/src/actors/rpc/actor.rs +++ b/rust/kona/crates/node/service/src/actors/rpc/actor.rs @@ -10,9 +10,8 @@ use jsonrpsee::{ use kona_gossip::P2pRpcRequest; use kona_rpc::{ AdminApiServer, AdminRpc, DevEngineApiServer, DevEngineRpc, EngineRpcClient, HealthzApiServer, - HealthzRpc, L1WatcherQueries, NetworkAdminQuery, OpP2PApiServer, P2pRpc, - RollupBoostAdminClient, RollupBoostHealthzApiServer, RollupNodeApiServer, RollupRpc, - RpcBuilder, SequencerAdminAPIClient, WsRPC, WsServer, + HealthzRpc, L1WatcherQueries, NetworkAdminQuery, OpP2PApiServer, P2pRpc, RollupNodeApiServer, + RollupRpc, RpcBuilder, SequencerAdminAPIClient, WsRPC, WsServer, }; use std::time::Duration; use tokio::sync::mpsc; @@ -20,23 +19,15 @@ use tokio_util::sync::{CancellationToken, WaitForCancellationFuture}; /// An actor that handles the RPC server for the rollup node. #[derive(Constructor, Debug)] -pub struct RpcActor< - EngineRpcClient_, - RollupBoostAdminClient_, - RollupBoostHealth, - SequencerAdminApiClient_, -> where +pub struct RpcActor +where EngineRpcClient_: EngineRpcClient, - RollupBoostAdminClient_: RollupBoostAdminClient, - RollupBoostHealth: RollupBoostHealthzApiServer, SequencerAdminApiClient_: SequencerAdminAPIClient, { /// A launcher for the rpc. config: RpcBuilder, engine_rpc_client: EngineRpcClient_, - rollup_boost_admin_rpc_client: RollupBoostAdminClient_, - rollup_boost_health_rpc_client: RollupBoostHealth, sequencer_admin_rpc_client: Option, } @@ -72,11 +63,8 @@ async fn launch( ) -> Result { let middleware = tower::ServiceBuilder::new() .layer( - ProxyGetRequestLayer::new([ - ("/healthz", "healthz"), - ("/kona-rollup-boost/healthz", "kona-rollup-boost_healthz"), - ]) - .expect("Critical: Failed to build GET method proxy"), + ProxyGetRequestLayer::new([("/healthz", "healthz")]) + .expect("Critical: Failed to build GET method proxy"), ) .timeout(Duration::from_secs(2)); let server = Server::builder().set_http_middleware(middleware).build(config.socket).await?; @@ -91,18 +79,10 @@ async fn launch( } #[async_trait] -impl - NodeActor - for RpcActor< - EngineRpcClient_, - RollupBoostAdminClient_, - RollupBoostHealth, - SequencerAdminApiClient_, - > +impl NodeActor + for RpcActor where EngineRpcClient_: EngineRpcClient + 'static, - RollupBoostAdminClient_: RollupBoostAdminClient + 'static, - RollupBoostHealth: RollupBoostHealthzApiServer + 'static, SequencerAdminApiClient_: SequencerAdminAPIClient + 'static, { type Error = RpcActorError; @@ -120,21 +100,12 @@ where let mut modules = RpcModule::new(()); modules.merge(HealthzApiServer::into_rpc(HealthzRpc {}))?; - modules - .merge(RollupBoostHealthzApiServer::into_rpc(self.rollup_boost_health_rpc_client))?; // Build the p2p rpc module. modules.merge(P2pRpc::new(p2p_network).into_rpc())?; // Build the admin rpc module. - modules.merge( - AdminRpc::new( - self.sequencer_admin_rpc_client, - network_admin, - Some(self.rollup_boost_admin_rpc_client), - ) - .into_rpc(), - )?; + modules.merge(AdminRpc::new(self.sequencer_admin_rpc_client, network_admin).into_rpc())?; // Create context for communication between actors. let rollup_rpc = RollupRpc::new(self.engine_rpc_client.clone(), l1_watcher_queries); diff --git a/rust/kona/crates/node/service/src/actors/rpc/engine_rpc_client.rs b/rust/kona/crates/node/service/src/actors/rpc/engine_rpc_client.rs index bbf02f130ef..b81a8c65e18 100644 --- a/rust/kona/crates/node/service/src/actors/rpc/engine_rpc_client.rs +++ b/rust/kona/crates/node/service/src/actors/rpc/engine_rpc_client.rs @@ -28,9 +28,9 @@ impl EngineRpcClient for QueuedEngineRpcClient { let (config_tx, config_rx) = oneshot::channel(); self.engine_actor_request_tx - .send(EngineActorRequest::RpcRequest(Box::new(EngineRpcRequest::EngineQuery( - Box::new(EngineQueries::Config(config_tx)), - )))) + .send(EngineActorRequest::RpcRequest(Box::new(EngineRpcRequest(Box::new( + EngineQueries::Config(config_tx), + ))))) .await .map_err(|_| ErrorObject::from(ErrorCode::InternalError))?; @@ -44,9 +44,9 @@ impl EngineRpcClient for QueuedEngineRpcClient { let (state_tx, state_rx) = oneshot::channel(); self.engine_actor_request_tx - .send(EngineActorRequest::RpcRequest(Box::new(EngineRpcRequest::EngineQuery( - Box::new(EngineQueries::State(state_tx)), - )))) + .send(EngineActorRequest::RpcRequest(Box::new(EngineRpcRequest(Box::new( + EngineQueries::State(state_tx), + ))))) .await .map_err(|_| ErrorObject::from(ErrorCode::InternalError))?; @@ -63,9 +63,9 @@ impl EngineRpcClient for QueuedEngineRpcClient { let (output_tx, output_rx) = oneshot::channel(); self.engine_actor_request_tx - .send(EngineActorRequest::RpcRequest(Box::new(EngineRpcRequest::EngineQuery( - Box::new(EngineQueries::OutputAtBlock { block, sender: output_tx }), - )))) + .send(EngineActorRequest::RpcRequest(Box::new(EngineRpcRequest(Box::new( + EngineQueries::OutputAtBlock { block, sender: output_tx }, + ))))) .await .map_err(|_| ErrorObject::from(ErrorCode::InternalError))?; @@ -79,9 +79,9 @@ impl EngineRpcClient for QueuedEngineRpcClient { let (length_tx, length_rx) = oneshot::channel(); self.engine_actor_request_tx - .send(EngineActorRequest::RpcRequest(Box::new(EngineRpcRequest::EngineQuery( - Box::new(EngineQueries::TaskQueueLength(length_tx)), - )))) + .send(EngineActorRequest::RpcRequest(Box::new(EngineRpcRequest(Box::new( + EngineQueries::TaskQueueLength(length_tx), + ))))) .await .map_err(|_| ErrorObject::from(ErrorCode::InternalError))?; @@ -95,9 +95,9 @@ impl EngineRpcClient for QueuedEngineRpcClient { let (sub_tx, sub_rx) = oneshot::channel(); self.engine_actor_request_tx - .send(EngineActorRequest::RpcRequest(Box::new(EngineRpcRequest::EngineQuery( - Box::new(EngineQueries::QueueLengthReceiver(sub_tx)), - )))) + .send(EngineActorRequest::RpcRequest(Box::new(EngineRpcRequest(Box::new( + EngineQueries::QueueLengthReceiver(sub_tx), + ))))) .await .map_err(|_| ErrorObject::from(ErrorCode::InternalError))?; @@ -110,9 +110,9 @@ impl EngineRpcClient for QueuedEngineRpcClient { let (sub_tx, sub_rx) = oneshot::channel(); self.engine_actor_request_tx - .send(EngineActorRequest::RpcRequest(Box::new(EngineRpcRequest::EngineQuery( - Box::new(EngineQueries::StateReceiver(sub_tx)), - )))) + .send(EngineActorRequest::RpcRequest(Box::new(EngineRpcRequest(Box::new( + EngineQueries::StateReceiver(sub_tx), + ))))) .await .map_err(|_| ErrorObject::from(ErrorCode::InternalError))?; diff --git a/rust/kona/crates/node/service/src/actors/rpc/mod.rs b/rust/kona/crates/node/service/src/actors/rpc/mod.rs index 8838bd37687..a567a3a6336 100644 --- a/rust/kona/crates/node/service/src/actors/rpc/mod.rs +++ b/rust/kona/crates/node/service/src/actors/rpc/mod.rs @@ -7,8 +7,5 @@ pub use engine_rpc_client::QueuedEngineRpcClient; mod error; pub use error::RpcActorError; -mod rollup_boost_rpc_client; -pub use rollup_boost_rpc_client::{RollupBoostAdminApiClient, RollupBoostHealthRpcClient}; - mod sequencer_rpc_client; pub use sequencer_rpc_client::QueuedSequencerAdminAPIClient; diff --git a/rust/kona/crates/node/service/src/actors/rpc/rollup_boost_rpc_client.rs b/rust/kona/crates/node/service/src/actors/rpc/rollup_boost_rpc_client.rs deleted file mode 100644 index dee64408b92..00000000000 --- a/rust/kona/crates/node/service/src/actors/rpc/rollup_boost_rpc_client.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::{EngineActorRequest, EngineRpcRequest}; -use async_trait::async_trait; -use jsonrpsee::{ - core::RpcResult, - types::{ErrorCode, ErrorObject}, -}; -use kona_rpc::{RollupBoostAdminClient, RollupBoostHealthzApiServer, RollupBoostHealthzResponse}; -use rollup_boost::{GetExecutionModeResponse, SetExecutionModeRequest, SetExecutionModeResponse}; -use std::fmt::Debug; -use tokio::sync::{mpsc, oneshot}; - -/// [`RollupBoostHealthzApiServer`] implementation to send the request to `EngineActor`'s request -/// channel. -#[derive(Debug)] -pub struct RollupBoostHealthRpcClient { - /// A channel to use to send the `EngineActor` requests. - pub engine_actor_request_tx: mpsc::Sender, -} - -#[async_trait] -impl RollupBoostHealthzApiServer for RollupBoostHealthRpcClient { - async fn rollup_boost_healthz(&self) -> RpcResult { - let (health_tx, health_rx) = oneshot::channel(); - - self.engine_actor_request_tx - .send(EngineActorRequest::RpcRequest(Box::new( - EngineRpcRequest::RollupBoostHealthRequest(Box::new( - kona_rpc::RollupBoostHealthQuery { sender: health_tx }, - )), - ))) - .await - .map_err(|_| ErrorObject::from(ErrorCode::InternalError))?; - - health_rx.await.map_err(|_| { - error!(target: "block_engine", "Failed to receive rollup boost health from engine rpc"); - ErrorObject::from(ErrorCode::InternalError) - }).map(|resp| RollupBoostHealthzResponse{rollup_boost_health: resp}) - } -} - -/// [`RollupBoostAdminClient`] implementation to send the request to `EngineActor`'s request -/// channel. -#[derive(Debug)] -pub struct RollupBoostAdminApiClient { - /// A channel to use to send the `EngineActor` requests. - pub engine_actor_request_tx: mpsc::Sender, -} - -#[async_trait] -impl RollupBoostAdminClient for RollupBoostAdminApiClient { - async fn set_execution_mode( - &self, - request: SetExecutionModeRequest, - ) -> RpcResult { - let engine_actor_request_tx = self.engine_actor_request_tx.clone(); - let (mode_tx, mode_rx) = oneshot::channel(); - - engine_actor_request_tx - .send(EngineActorRequest::RpcRequest(Box::new( - EngineRpcRequest::RollupBoostAdminRequest(Box::new( - kona_rpc::RollupBoostAdminQuery::SetExecutionMode { - execution_mode: request.execution_mode, - sender: mode_tx, - }, - )), - ))) - .await - .map_err(|_| ErrorObject::from(ErrorCode::InternalError))?; - - mode_rx - .await - .map_err(|_| ErrorObject::from(ErrorCode::InternalError)) - .map(|_| SetExecutionModeResponse { execution_mode: request.execution_mode }) - } - - async fn get_execution_mode(&self) -> RpcResult { - let engine_actor_request_tx = self.engine_actor_request_tx.clone(); - let (mode_tx, mode_rx) = oneshot::channel(); - - engine_actor_request_tx - .send(EngineActorRequest::RpcRequest(Box::new( - EngineRpcRequest::RollupBoostAdminRequest(Box::new( - kona_rpc::RollupBoostAdminQuery::GetExecutionMode { sender: mode_tx }, - )), - ))) - .await - .map_err(|_| ErrorObject::from(ErrorCode::InternalError))?; - - mode_rx - .await - .map_err(|_| ErrorObject::from(ErrorCode::InternalError)) - .map(|execution_mode| GetExecutionModeResponse { execution_mode }) - } -} diff --git a/rust/kona/crates/node/service/src/actors/sequencer/actor.rs b/rust/kona/crates/node/service/src/actors/sequencer/actor.rs index 0722c031683..72bc5673a79 100644 --- a/rust/kona/crates/node/service/src/actors/sequencer/actor.rs +++ b/rust/kona/crates/node/service/src/actors/sequencer/actor.rs @@ -13,7 +13,7 @@ use crate::{ update_conductor_commitment_duration_metrics, update_seal_duration_metrics, update_total_transactions_sequenced, }, - origin_selector::OriginSelector, + origin_selector::{L1OriginSelectorError, OriginSelector}, }, }, }; @@ -225,6 +225,15 @@ where .await { Ok(l1_origin) => l1_origin, + Err(L1OriginSelectorError::OriginNotFound(hash)) => { + warn!( + target: "sequencer", + %hash, + "L1 origin block not found, resetting engine" + ); + self.engine_client.reset_engine_forkchoice().await?; + return Ok(None); + } Err(err) => { warn!( target: "sequencer", diff --git a/rust/kona/crates/node/service/src/actors/sequencer/origin_selector.rs b/rust/kona/crates/node/service/src/actors/sequencer/origin_selector.rs index 5ff8cdd8631..097e4eb0b37 100644 --- a/rust/kona/crates/node/service/src/actors/sequencer/origin_selector.rs +++ b/rust/kona/crates/node/service/src/actors/sequencer/origin_selector.rs @@ -70,7 +70,7 @@ impl OriginSelector for L1OriginSelec } let Some(current) = self.current else { - unreachable!("Current L1 origin should always be set by `select_origins`"); + return Err(L1OriginSelectorError::OriginNotFound(unsafe_head.l1_origin.hash)); }; let max_seq_drift = self.cfg.max_sequencer_drift(current.timestamp); @@ -128,7 +128,12 @@ impl L1OriginSelector

{ in_recovery_mode: bool, ) -> Result<(), L1OriginSelectorError> { if in_recovery_mode { - self.current = self.l1.get_block_by_hash(unsafe_head.l1_origin.hash).await?; + self.current = Some( + self.l1 + .get_block_by_hash(unsafe_head.l1_origin.hash) + .await? + .ok_or(L1OriginSelectorError::OriginNotFound(unsafe_head.l1_origin.hash))?, + ); self.next = self.l1.get_block_by_number(unsafe_head.l1_origin.number + 1).await?; return Ok(()); } @@ -141,9 +146,12 @@ impl L1OriginSelector

{ self.next = None; } else { // Find the current origin block, as it is missing. - let current = self.l1.get_block_by_hash(unsafe_head.l1_origin.hash).await?; - - self.current = current; + self.current = Some( + self.l1 + .get_block_by_hash(unsafe_head.l1_origin.hash) + .await? + .ok_or(L1OriginSelectorError::OriginNotFound(unsafe_head.l1_origin.hash))?, + ); self.next = None; } @@ -185,6 +193,9 @@ pub enum L1OriginSelectorError { "Waiting for more L1 data to be available to select the next L1 origin block. Current L1 origin: {0:?}" )] NotEnoughData(BlockInfo), + /// The L1 origin block could not be found by its hash. + #[error("L1 origin block not found for hash: {0}")] + OriginNotFound(B256), } /// L1 [`BlockInfo`] provider interface for the [`L1OriginSelector`]. @@ -493,4 +504,129 @@ mod test { assert!(matches!(next_err, L1OriginSelectorError::NotEnoughData(_))); } } + + #[tokio::test] + async fn test_next_l1_origin_recovery_mode_found() { + const L2_BLOCK_TIME: u64 = 2; + + let cfg = Arc::new(RollupConfig { + block_time: L2_BLOCK_TIME, + max_sequencer_drift: 600, + ..Default::default() + }); + + let mut provider = MockOriginSelectorProvider::default(); + provider.with_block(BlockInfo { + parent_hash: B256::ZERO, + hash: B256::with_last_byte(1), + number: 1, + timestamp: 12, + }); + provider.with_block(BlockInfo { + parent_hash: B256::with_last_byte(1), + hash: B256::with_last_byte(2), + number: 2, + timestamp: 24, + }); + + let mut selector = L1OriginSelector::new(cfg, provider); + + let unsafe_head = L2BlockInfo { + block_info: BlockInfo { + hash: B256::ZERO, + number: 5, + timestamp: 10, + ..Default::default() + }, + l1_origin: NumHash { number: 1, hash: B256::with_last_byte(1) }, + seq_num: 0, + }; + + let origin = selector.next_l1_origin(unsafe_head, true).await.unwrap(); + assert_eq!(origin.number, 1); + assert_eq!(origin.hash, B256::with_last_byte(1)); + } + + #[tokio::test] + async fn test_next_l1_origin_recovery_mode_not_found() { + const L2_BLOCK_TIME: u64 = 2; + + let cfg = Arc::new(RollupConfig { + block_time: L2_BLOCK_TIME, + max_sequencer_drift: 600, + ..Default::default() + }); + + let provider = MockOriginSelectorProvider::default(); + let mut selector = L1OriginSelector::new(cfg, provider); + + let unsafe_head = L2BlockInfo { + block_info: BlockInfo { + hash: B256::ZERO, + number: 5, + timestamp: 10, + ..Default::default() + }, + l1_origin: NumHash { number: 1, hash: B256::with_last_byte(1) }, + seq_num: 0, + }; + + let result = selector.next_l1_origin(unsafe_head, true).await; + assert!(matches!( + result, + Err(L1OriginSelectorError::OriginNotFound(hash)) if hash == B256::with_last_byte(1) + )); + } + + #[tokio::test] + async fn test_next_l1_origin_normal_mode_origin_not_found() { + const L2_BLOCK_TIME: u64 = 2; + + let cfg = Arc::new(RollupConfig { + block_time: L2_BLOCK_TIME, + max_sequencer_drift: 600, + ..Default::default() + }); + + let mut provider = MockOriginSelectorProvider::default(); + provider.with_block(BlockInfo { + parent_hash: B256::ZERO, + hash: B256::ZERO, + number: 0, + timestamp: 0, + }); + + let mut selector = L1OriginSelector::new(cfg, provider); + + // First call: set current to block 0. + let unsafe_head_epoch0 = L2BlockInfo { + block_info: BlockInfo { + hash: B256::ZERO, + number: 0, + timestamp: 0, + ..Default::default() + }, + l1_origin: NumHash { number: 0, hash: B256::ZERO }, + seq_num: 0, + }; + let _ = selector.next_l1_origin(unsafe_head_epoch0, false).await.unwrap(); + + // Second call: reference a non-existent L1 origin hash, triggering the else branch. + let unsafe_head_missing = L2BlockInfo { + block_info: BlockInfo { + hash: B256::ZERO, + number: 1, + timestamp: L2_BLOCK_TIME, + ..Default::default() + }, + l1_origin: NumHash { number: 99, hash: B256::with_last_byte(0xFF) }, + seq_num: 0, + }; + + let result = selector.next_l1_origin(unsafe_head_missing, false).await; + assert!(matches!( + result, + Err(L1OriginSelectorError::OriginNotFound(hash)) if hash == B256::with_last_byte(0xFF) + )); + } } diff --git a/rust/kona/crates/node/service/src/lib.rs b/rust/kona/crates/node/service/src/lib.rs index deeab0fb47e..182c87281be 100644 --- a/rust/kona/crates/node/service/src/lib.rs +++ b/rust/kona/crates/node/service/src/lib.rs @@ -31,10 +31,10 @@ pub use actors::{ NetworkEngineClient, NetworkHandler, NetworkInboundData, NodeActor, OriginSelector, QueuedDerivationEngineClient, QueuedEngineDerivationClient, QueuedEngineRpcClient, QueuedL1WatcherDerivationClient, QueuedNetworkEngineClient, QueuedSequencerAdminAPIClient, - QueuedSequencerEngineClient, QueuedUnsafePayloadGossipClient, ResetRequest, - RollupBoostAdminApiClient, RollupBoostHealthRpcClient, RpcActor, RpcActorError, RpcContext, - SealRequest, SequencerActor, SequencerActorError, SequencerAdminQuery, SequencerConfig, - SequencerEngineClient, UnsafePayloadGossipClient, UnsafePayloadGossipClientError, + QueuedSequencerEngineClient, QueuedUnsafePayloadGossipClient, ResetRequest, RpcActor, + RpcActorError, RpcContext, SealRequest, SequencerActor, SequencerActorError, + SequencerAdminQuery, SequencerConfig, SequencerEngineClient, UnsafePayloadGossipClient, + UnsafePayloadGossipClientError, }; mod metrics; diff --git a/rust/kona/crates/node/service/src/service/builder.rs b/rust/kona/crates/node/service/src/service/builder.rs index 2c229167963..2e852cebc76 100644 --- a/rust/kona/crates/node/service/src/service/builder.rs +++ b/rust/kona/crates/node/service/src/service/builder.rs @@ -133,7 +133,6 @@ impl RollupNodeBuilder { /// - The L2 engine URL is not set. /// - The jwt secret is not set. /// - The P2P config is not set. - /// - The rollup boost args are not set. pub fn build(self) -> RollupNode { let mut l1_beacon = OnlineBeaconClient::new_http(self.l1_config_builder.beacon.to_string()); if let Some(l1_slot_duration) = self.l1_config_builder.slot_duration_override { diff --git a/rust/kona/crates/node/service/src/service/node.rs b/rust/kona/crates/node/service/src/service/node.rs index 7c130b21220..f21f8d3ab0c 100644 --- a/rust/kona/crates/node/service/src/service/node.rs +++ b/rust/kona/crates/node/service/src/service/node.rs @@ -6,8 +6,7 @@ use crate::{ NetworkActor, NetworkBuilder, NetworkConfig, NodeActor, NodeMode, QueuedDerivationEngineClient, QueuedEngineDerivationClient, QueuedEngineRpcClient, QueuedL1WatcherDerivationClient, QueuedNetworkEngineClient, QueuedSequencerAdminAPIClient, QueuedSequencerEngineClient, - RollupBoostAdminApiClient, RollupBoostHealthRpcClient, RpcActor, RpcContext, SequencerActor, - SequencerConfig, + RpcActor, RpcContext, SequencerActor, SequencerConfig, actors::{BlockStream, NetworkInboundData, QueuedUnsafePayloadGossipClient}, }; use alloy_eips::BlockNumberOrTag; @@ -203,10 +202,7 @@ impl RollupNode { let (engine_queue_length_tx, engine_queue_length_rx) = watch::channel(0); let engine = Engine::new(engine_state, engine_state_tx, engine_queue_length_tx); - let engine_client = Arc::new(self.engine_config().build_engine_client().map_err(|e| { - error!(target: "service", error = ?e, "engine client build failed"); - format!("Engine client build failed: {e:?}") - })?); + let engine_client = Arc::new(self.engine_config().build_engine_client()); let engine_processor = EngineProcessor::new( engine_client.clone(), @@ -217,8 +213,7 @@ impl RollupNode { ); let engine_rpc_processor = EngineRpcProcessor::new( - engine_client.clone(), - engine_client.rollup_boost.clone(), + engine_client, self.config.clone(), engine_state_rx, engine_queue_length_rx, @@ -391,12 +386,6 @@ impl RollupNode { RpcActor::new( b, QueuedEngineRpcClient::new(engine_actor_request_tx.clone()), - RollupBoostAdminApiClient { - engine_actor_request_tx: engine_actor_request_tx.clone(), - }, - RollupBoostHealthRpcClient { - engine_actor_request_tx: engine_actor_request_tx.clone(), - }, sequencer_admin_client, ) }); diff --git a/rust/kona/crates/node/service/tests/rollup_boost_missing_jwt.rs b/rust/kona/crates/node/service/tests/rollup_boost_missing_jwt.rs deleted file mode 100644 index ba2a06032e2..00000000000 --- a/rust/kona/crates/node/service/tests/rollup_boost_missing_jwt.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! Reproduces panic: "failed to create rollup boost server: Missing Client JWT secret" when -//! constructing rollup-boost without an L2 client JWT provided. - -#[cfg(test)] -mod tests { - use http::Uri; - use rollup_boost::{ - ExecutionMode, FlashblocksWebsocketConfig, FlashblocksWsArgs, Probes, RollupBoostLibArgs, - RollupBoostServer, - }; - use std::sync::Arc; - - #[test] - fn repro_missing_client_jwt_secret() { - // Build args with execution enabled and flashblocks enabled but NO L2 JWT provided. - // This mirrors the failing acceptance configuration when no client JWT is wired through. - let args = RollupBoostLibArgs { - builder: rollup_boost::BuilderArgs { - // Any URI; builder may be disabled at runtime, but server creation still validates - // args. - builder_url: "http://127.0.0.1:8551".parse::().unwrap(), - builder_jwt_token: None, - builder_jwt_path: None, // intentionally missing - builder_timeout: 1000, - }, - l2_client: rollup_boost::L2ClientArgs { - l2_url: "http://127.0.0.1:8551".parse::().unwrap(), - l2_jwt_token: None, - l2_jwt_path: None, /* intentionally missing -> triggers the panic/error in server - * ctor */ - l2_timeout: 1000, - }, - // Default is ExecutionMode::Enabled in the crate; rely on that or set explicitly if - // needed. - flashblocks_ws: Some(FlashblocksWsArgs { - flashblocks_ws: true, - flashblocks_builder_url: "ws://127.0.0.1:1111".parse().unwrap(), - flashblocks_host: "127.0.0.1".to_string(), - flashblocks_port: 1112, - flashblocks_ws_config: FlashblocksWebsocketConfig { - flashblock_builder_ws_initial_reconnect_ms: 5000, - flashblock_builder_ws_max_reconnect_ms: 5000, - flashblock_builder_ws_connect_timeout_ms: 5000, - flashblock_builder_ws_ping_interval_ms: 500, - flashblock_builder_ws_pong_timeout_ms: 1500, - }, - }), - flashblocks_p2p: None, - block_selection_policy: None, - execution_mode: ExecutionMode::Enabled, - external_state_root: false, - ignore_unhealthy_builders: false, - health_check_interval: 10, - max_unsafe_interval: 10, - }; - - let probes = Arc::new(Probes::default()); - let err = RollupBoostServer::new_from_args(args, probes) - .expect_err("expected missing JWT to error"); - let msg = format!("{err}"); - assert!( - msg.to_lowercase().contains("missing client jwt secret"), - "unexpected error: {msg}" - ); - } -} diff --git a/rust/kona/crates/proof/executor/src/builder/core.rs b/rust/kona/crates/proof/executor/src/builder/core.rs index dc141dee1e1..23e18adccb6 100644 --- a/rust/kona/crates/proof/executor/src/builder/core.rs +++ b/rust/kona/crates/proof/executor/src/builder/core.rs @@ -248,11 +248,8 @@ where ); // Step 2. Create the executor, using the trie database. - let mut state = State::builder() - .with_database(&mut self.trie_db) - .with_bundle_update() - .without_state_clear() - .build(); + let mut state = + State::builder().with_database(&mut self.trie_db).with_bundle_update().build(); let evm = self.factory.evm_factory().create_evm(&mut state, evm_env); let ctx = OpBlockExecutionCtx { parent_hash, diff --git a/rust/kona/crates/proof/executor/src/db/mod.rs b/rust/kona/crates/proof/executor/src/db/mod.rs index 4ff84f248ca..aa2d8e2a260 100644 --- a/rust/kona/crates/proof/executor/src/db/mod.rs +++ b/rust/kona/crates/proof/executor/src/db/mod.rs @@ -62,7 +62,7 @@ pub use traits::{NoopTrieDBProvider, TrieDBProvider}; /// let executor_factory = OpBlockExecutorFactory::new( /// OpAlloyReceiptBuilder::default(), /// OpChainHardforks::op_mainnet(), -/// OpEvmFactory::>::default(), +/// OpEvmFactory::::default(), /// ); /// let mut state = State::builder().with_database(trie_db).with_bundle_update().build(); /// let evm = executor_factory.evm_factory().create_evm(&mut state, EvmEnv::default()); diff --git a/rust/kona/crates/proof/executor/src/test_utils.rs b/rust/kona/crates/proof/executor/src/test_utils.rs index db9000a84ac..2d392f4f5b0 100644 --- a/rust/kona/crates/proof/executor/src/test_utils.rs +++ b/rust/kona/crates/proof/executor/src/test_utils.rs @@ -13,8 +13,6 @@ use kona_genesis::RollupConfig; use kona_mpt::{NoopTrieHinter, TrieNode, TrieProvider}; use kona_registry::ROLLUP_CONFIGS; use op_alloy_rpc_types_engine::OpPayloadAttributes; -use op_revm::OpTransaction; -use revm::context::TxEnv; use rocksdb::{DB, Options}; use serde::{Deserialize, Serialize}; use std::{path::PathBuf, sync::Arc}; @@ -47,7 +45,7 @@ pub async fn run_test_fixture(fixture_path: PathBuf) { let mut executor = StatelessL2Builder::new( &fixture.rollup_config, - OpEvmFactory::>::default(), + OpEvmFactory::::default(), provider, NoopTrieHinter, fixture.parent_header.seal_slow(), @@ -183,7 +181,7 @@ impl ExecutorTestFixtureCreator { let mut executor = StatelessL2Builder::new( rollup_config, - OpEvmFactory::>::default(), + OpEvmFactory::::default(), self, NoopTrieHinter, parent_header, diff --git a/rust/kona/crates/proof/proof-interop/Cargo.toml b/rust/kona/crates/proof/proof-interop/Cargo.toml index 9409ce789a3..73731e9c390 100644 --- a/rust/kona/crates/proof/proof-interop/Cargo.toml +++ b/rust/kona/crates/proof/proof-interop/Cargo.toml @@ -70,4 +70,5 @@ arbitrary = [ "op-alloy-consensus/arbitrary", "op-alloy-rpc-types-engine/arbitrary", "revm/arbitrary", + "alloy-op-evm/arbitrary", ] diff --git a/rust/kona/crates/proof/proof-interop/src/boot.rs b/rust/kona/crates/proof/proof-interop/src/boot.rs index 8960648e581..c17e0dae580 100644 --- a/rust/kona/crates/proof/proof-interop/src/boot.rs +++ b/rust/kona/crates/proof/proof-interop/src/boot.rs @@ -133,10 +133,12 @@ impl BootInfo { { chain_ids.iter().map(|id| (*id, ROLLUP_CONFIGS[id].clone())).collect() } else { + let missing_ids: Vec = + chain_ids.into_iter().filter(|id| !ROLLUP_CONFIGS.contains_key(id)).collect(); warn!( target: "boot_loader", "No rollup config found for chain IDs {:?}, falling back to preimage oracle. This is insecure in production without additional validation!", - chain_ids + missing_ids ); let ser_cfg = oracle .get(PreimageKey::new_local(L2_ROLLUP_CONFIG_KEY.to())) diff --git a/rust/kona/crates/proof/proof-interop/src/consolidation.rs b/rust/kona/crates/proof/proof-interop/src/consolidation.rs index 31d98854869..89e65f833dd 100644 --- a/rust/kona/crates/proof/proof-interop/src/consolidation.rs +++ b/rust/kona/crates/proof/proof-interop/src/consolidation.rs @@ -1,12 +1,11 @@ //! Interop dependency resolution and consolidation logic. use crate::{BootInfo, OptimisticBlock, OracleInteropProvider, PreState}; -use alloc::vec::Vec; +use alloc::{collections::BTreeSet, vec::Vec}; use alloy_consensus::{Header, Sealed}; -use alloy_eips::Encodable2718; use alloy_evm::{EvmFactory, FromRecoveredTx, FromTxWithEncoded}; use alloy_op_evm::block::OpTxEnv; -use alloy_primitives::{Address, B256, Bytes, Sealable, TxKind, U256, address}; +use alloy_primitives::Sealable; use alloy_rpc_types_engine::PayloadAttributes; use core::fmt::Debug; use kona_executor::{Eip1559ValidationError, ExecutorError, StatelessL2Builder}; @@ -14,9 +13,8 @@ use kona_interop::{MessageGraph, MessageGraphError}; use kona_mpt::OrderedListWalker; use kona_preimage::CommsClient; use kona_proof::{errors::OracleProviderError, l2::OracleL2ChainProvider}; -use kona_protocol::OutputRoot; use kona_registry::{HashMap, ROLLUP_CONFIGS}; -use op_alloy_consensus::{InteropBlockReplacementDepositSource, OpTxEnvelope, OpTxType, TxDeposit}; +use op_alloy_consensus::{OpTxEnvelope, OpTxType}; use op_alloy_rpc_types_engine::OpPayloadAttributes; use op_revm::OpSpecId; use revm::context::BlockEnv; @@ -40,6 +38,9 @@ where l2_providers: HashMap>, /// The inner [`EvmFactory`] to create EVM instances for re-execution of bad blocks. evm_factory: Evm, + /// Chain IDs that have already been replaced with deposit-only blocks. These are skipped + /// during validation since deposit-only blocks cannot contain executing messages. + replaced_chains: BTreeSet, } impl<'a, C, Evm> SuperchainConsolidator<'a, C, Evm> @@ -58,7 +59,13 @@ where l2_providers: HashMap>, evm_factory: Evm, ) -> Self { - Self { boot_info, interop_provider, l2_providers, evm_factory } + Self { + boot_info, + interop_provider, + l2_providers, + evm_factory, + replaced_chains: BTreeSet::new(), + } } /// Recursively consolidates the dependencies of the blocks within the [`MessageGraph`]. @@ -95,9 +102,20 @@ where /// /// [Header]: alloy_consensus::Header async fn consolidate_once(&mut self) -> Result<(), ConsolidationError> { - // Derive the message graph from the current set of block headers. + // Filter out chains that have already been replaced with deposit-only blocks. + // Deposit-only blocks cannot contain executing messages, so they are already + // cross-safe and do not need to be re-validated. + let heads_to_check: HashMap> = self + .interop_provider + .local_safe_heads() + .iter() + .filter(|(chain_id, _)| !self.replaced_chains.contains(chain_id)) + .map(|(k, v)| (*k, v.clone())) + .collect(); + + // Derive the message graph from the non-replaced block headers. let graph = MessageGraph::derive( - self.interop_provider.local_safe_heads(), + &heads_to_check, &self.interop_provider, &self.boot_info.rollup_configs, self.boot_info.dependency_set.get_message_expiry_window(), @@ -127,12 +145,16 @@ where .interop_provider .local_safe_heads() .get(chain_id) - .ok_or(MessageGraphError::EmptyDependencySet)?; + .ok_or(MessageGraphError::EmptyDependencySet)? + .clone(); // Look up the parent header for the block. let parent_header = self.interop_provider.header_by_hash(*chain_id, header.parent_hash).await?; + // Send a hint for the block's transactions so the host pre-fetches the trie nodes. + self.interop_provider.hint_transactions(*chain_id, header.hash()).await?; + // Traverse the transactions trie of the block to re-execute. let trie_walker = OrderedListWalker::try_new_hydrated( header.transactions_root, @@ -141,13 +163,6 @@ where .map_err(OracleProviderError::TrieWalker)?; let transactions = trie_walker.into_iter().map(|(_, rlp)| rlp).collect::>(); - // Explicitly panic if a block sent off for re-execution already contains nothing but - // deposits. - assert!( - !transactions.iter().all(|f| !f.is_empty() && f[0] == OpTxType::Deposit), - "Impossible case; Block with only deposits found to be invalid. Something has gone horribly wrong!" - ); - // Fetch the rollup config + provider for the current chain ID. let rollup_config = ROLLUP_CONFIGS .get(chain_id) @@ -169,18 +184,12 @@ where .find(|block| block.block_hash == header.hash()) .ok_or(MessageGraphError::EmptyDependencySet)?; - // Filter out all transactions that are not deposits to start. - let mut transactions = transactions + // Filter out all transactions that are not deposits. + let transactions = transactions .into_iter() .filter(|t| !t.is_empty() && t[0] == OpTxType::Deposit) .collect::>(); - // Add the deposit replacement system transaction at the end of the list. - transactions.push(Self::craft_replacement_transaction( - header, - original_optimistic_block.output_root, - )); - // Re-craft the execution payload, trimming off all non-deposit transactions. let deposit_only_payload = OpPayloadAttributes { payload_attributes: PayloadAttributes { @@ -240,43 +249,13 @@ where // Replace the original optimistic block with the deposit only block. *original_optimistic_block = OptimisticBlock::new(new_header.hash(), new_output_root); - // Replace the original header with the new header. + // Replace the original header with the new header and mark the chain as replaced. self.interop_provider.replace_local_safe_head(*chain_id, new_header); + self.replaced_chains.insert(*chain_id); } Ok(()) } - - /// Forms the replacement transaction inserted into a deposit-only block in the event that a - /// block is reduced due to invalid messages. - /// - /// - fn craft_replacement_transaction(old_header: &Sealed

, old_output_root: B256) -> Bytes { - const REPLACEMENT_SENDER: Address = address!("deaddeaddeaddeaddeaddeaddeaddeaddead0002"); - const REPLACEMENT_GAS: u64 = 36000; - - let source = InteropBlockReplacementDepositSource::new(old_output_root); - let output_root = OutputRoot::from_parts( - old_header.state_root, - old_header.withdrawals_root.unwrap_or_default(), - old_header.hash(), - ); - let replacement_tx = OpTxEnvelope::Deposit( - TxDeposit { - source_hash: source.source_hash(), - from: REPLACEMENT_SENDER, - to: TxKind::Call(Address::ZERO), - mint: 0, - value: U256::ZERO, - gas_limit: REPLACEMENT_GAS, - is_system_transaction: false, - input: output_root.encode().into(), - } - .seal(), - ); - - replacement_tx.encoded_2718().into() - } } /// An error type for the [`SuperchainConsolidator`] struct. diff --git a/rust/kona/crates/proof/proof-interop/src/provider.rs b/rust/kona/crates/proof/proof-interop/src/provider.rs index 22ca1202fd0..62f22fbb07b 100644 --- a/rust/kona/crates/proof/proof-interop/src/provider.rs +++ b/rust/kona/crates/proof/proof-interop/src/provider.rs @@ -46,6 +46,19 @@ where } } + /// Sends an [`HintType::L2Transactions`] hint for the given block, instructing the host to + /// pre-fetch the transaction trie nodes into the preimage oracle's key-value store. + pub async fn hint_transactions( + &self, + chain_id: u64, + block_hash: B256, + ) -> Result<(), ::Error> { + HintType::L2Transactions + .with_data(&[block_hash.as_slice(), chain_id.to_be_bytes().as_ref()]) + .send(self.oracle.as_ref()) + .await + } + /// Returns a reference to the local safe heads map. pub const fn local_safe_heads(&self) -> &HashMap> { &self.local_safe_heads diff --git a/rust/kona/crates/protocol/derive/src/stages/traversal/indexed.rs b/rust/kona/crates/protocol/derive/src/stages/traversal/indexed.rs index 6c7f0cfb9e3..40253c46819 100644 --- a/rust/kona/crates/protocol/derive/src/stages/traversal/indexed.rs +++ b/rust/kona/crates/protocol/derive/src/stages/traversal/indexed.rs @@ -99,9 +99,17 @@ impl IndexedTraversal { block_info.number, ); + let prev_block_holocene = self.rollup_config.is_holocene_active(block.timestamp); + let next_block_holocene = self.rollup_config.is_holocene_active(block_info.timestamp); + // Update the origin block. self.update_origin(block_info); + // If Holocene activates on this block, flag it so the pipeline driver resets. + if !prev_block_holocene && next_block_holocene { + return Err(ResetError::HoloceneActivation.reset()); + } + Ok(()) } } @@ -157,7 +165,7 @@ mod tests { use alloc::vec; use alloy_consensus::Receipt; use alloy_primitives::{B256, Bytes, Log, LogData, address, b256, hex}; - use kona_genesis::{CONFIG_UPDATE_EVENT_VERSION_0, CONFIG_UPDATE_TOPIC}; + use kona_genesis::{CONFIG_UPDATE_EVENT_VERSION_0, CONFIG_UPDATE_TOPIC, HardForkConfig}; const L1_SYS_CONFIG_ADDR: Address = address!("1337000000000000000000000000000000000000"); @@ -324,4 +332,32 @@ mod tests { let expected = address!("000000000000000000000000000000000000bEEF"); assert_eq!(traversal.system_config.batcher_address, expected); } + + #[tokio::test] + async fn test_managed_traversal_holocene_activation_reset() { + let first = b256!("3333333333333333333333333333333333333333333333333333333333333333"); + let second = b256!("4444444444444444444444444444444444444444444444444444444444444444"); + // Block before Holocene activation (timestamp 99), block at activation (timestamp 100). + let block1 = BlockInfo { hash: first, timestamp: 99, ..BlockInfo::default() }; + let block2 = BlockInfo { number: 1, hash: second, parent_hash: first, timestamp: 100 }; + + let mut provider = TestChainProvider::default(); + provider.insert_block(0, block1); + provider.insert_block(1, block2); + provider.insert_receipts(second, vec![]); + + let rollup_config = RollupConfig { + l1_system_config_address: L1_SYS_CONFIG_ADDR, + hardforks: HardForkConfig { holocene_time: Some(100), ..Default::default() }, + ..RollupConfig::default() + }; + let mut traversal = IndexedTraversal::new(provider, Arc::new(rollup_config)); + traversal.block = Some(block1); + traversal.done = true; + + let err = traversal.provide_next_block(block2).await.unwrap_err(); + assert_eq!(err, ResetError::HoloceneActivation.reset()); + // Origin should still be updated despite the reset error. + assert_eq!(traversal.origin(), Some(block2)); + } } diff --git a/rust/kona/crates/protocol/genesis/Cargo.toml b/rust/kona/crates/protocol/genesis/Cargo.toml index 87446eca090..0e0d017d056 100644 --- a/rust/kona/crates/protocol/genesis/Cargo.toml +++ b/rust/kona/crates/protocol/genesis/Cargo.toml @@ -51,6 +51,7 @@ alloy-primitives = { workspace = true, features = ["rand", "arbitrary"] } [features] default = [] +rollup_config_override = [] revm = [ "dep:op-revm" ] tabled = [ "dep:tabled", "std" ] std = [ diff --git a/rust/kona/crates/protocol/genesis/src/chain/config.rs b/rust/kona/crates/protocol/genesis/src/chain/config.rs index b2cf56dc440..8a1958526ed 100644 --- a/rust/kona/crates/protocol/genesis/src/chain/config.rs +++ b/rust/kona/crates/protocol/genesis/src/chain/config.rs @@ -5,6 +5,8 @@ use alloy_chains::Chain; use alloy_eips::eip1559::BaseFeeParams; use alloy_primitives::Address; +#[cfg(feature = "rollup_config_override")] +use crate::FJORD_MAX_SEQUENCER_DRIFT; use crate::{ AddressList, AltDAConfig, BaseFeeConfig, ChainGenesis, GRANITE_CHANNEL_TIMEOUT, HardForkConfig, Roles, RollupConfig, SuperchainLevel, base_fee_params, base_fee_params_canyon, @@ -176,6 +178,8 @@ impl ChainConfig { // necessary. channel_timeout: 300, granite_channel_timeout: GRANITE_CHANNEL_TIMEOUT, + #[cfg(feature = "rollup_config_override")] + fjord_max_sequencer_drift: FJORD_MAX_SEQUENCER_DRIFT, chain_op_config: self.base_fee_config(), alt_da_config: self.alt_da.clone(), } diff --git a/rust/kona/crates/protocol/genesis/src/rollup.rs b/rust/kona/crates/protocol/genesis/src/rollup.rs index a3785e25c4a..4c88d69b0f6 100644 --- a/rust/kona/crates/protocol/genesis/src/rollup.rs +++ b/rust/kona/crates/protocol/genesis/src/rollup.rs @@ -23,6 +23,14 @@ const fn default_granite_channel_timeout() -> u64 { GRANITE_CHANNEL_TIMEOUT } +/// The max sequencer drift needs to be changes for some chains, e.g. those that build only on +/// finalized L1 blocks, where L1 finality delays can exceed the standard +/// [`FJORD_MAX_SEQUENCER_DRIFT`]. +#[cfg(all(feature = "serde", feature = "rollup_config_override"))] +const fn default_fjord_max_sequencer_drift() -> u64 { + FJORD_MAX_SEQUENCER_DRIFT +} + /// The Rollup configuration. #[derive(Debug, Clone, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -47,6 +55,10 @@ pub struct RollupConfig { /// The channel timeout after the Granite hardfork. #[cfg_attr(feature = "serde", serde(default = "default_granite_channel_timeout"))] pub granite_channel_timeout: u64, + /// The max sequencer drift after the Fjord hardfork. + #[cfg(feature = "rollup_config_override")] + #[cfg_attr(feature = "serde", serde(default = "default_fjord_max_sequencer_drift"))] + pub fjord_max_sequencer_drift: u64, /// The L1 chain ID pub l1_chain_id: u64, /// The L2 chain ID @@ -103,6 +115,8 @@ impl<'a> arbitrary::Arbitrary<'a> for RollupConfig { seq_window_size: u.arbitrary()?, channel_timeout: u.arbitrary()?, granite_channel_timeout: u.arbitrary()?, + #[cfg(feature = "rollup_config_override")] + fjord_max_sequencer_drift: u.arbitrary()?, l1_chain_id: u.arbitrary()?, l2_chain_id: u.arbitrary()?, hardforks: HardForkConfig::arbitrary(u)?, @@ -129,6 +143,8 @@ impl Default for RollupConfig { seq_window_size: 0, channel_timeout: 0, granite_channel_timeout: GRANITE_CHANNEL_TIMEOUT, + #[cfg(feature = "rollup_config_override")] + fjord_max_sequencer_drift: FJORD_MAX_SEQUENCER_DRIFT, l1_chain_id: 0, l2_chain_id: Chain::from_id(0), hardforks: HardForkConfig::default(), @@ -329,10 +345,12 @@ impl RollupConfig { /// Returns the max sequencer drift for the given timestamp. pub fn max_sequencer_drift(&self, timestamp: u64) -> u64 { if self.is_fjord_active(timestamp) { - FJORD_MAX_SEQUENCER_DRIFT - } else { - self.max_sequencer_drift + #[cfg(feature = "rollup_config_override")] + return self.fjord_max_sequencer_drift; + #[cfg(not(feature = "rollup_config_override"))] + return FJORD_MAX_SEQUENCER_DRIFT; } + self.max_sequencer_drift } /// Returns the max rlp bytes per channel for the given timestamp. @@ -890,6 +908,8 @@ mod tests { seq_window_size: 3600, channel_timeout: 300, granite_channel_timeout: GRANITE_CHANNEL_TIMEOUT, + #[cfg(feature = "rollup_config_override")] + fjord_max_sequencer_drift: FJORD_MAX_SEQUENCER_DRIFT, l1_chain_id: 3151908, l2_chain_id: Chain::from_id(1337), hardforks: HardForkConfig { @@ -975,4 +995,41 @@ mod tests { assert_eq!(cfg.block_number_from_timestamp(20), 5); assert_eq!(cfg.block_number_from_timestamp(30), 10); } + + #[cfg(feature = "rollup_config_override")] + mod rollup_config_override_tests { + use super::*; + + #[test] + fn test_max_sequencer_drift_override() { + let mut config = RollupConfig { + max_sequencer_drift: 100, + fjord_max_sequencer_drift: 2892, + hardforks: HardForkConfig { fjord_time: Some(10), ..Default::default() }, + ..Default::default() + }; + assert_eq!(config.max_sequencer_drift(0), 100); + assert_eq!(config.max_sequencer_drift(10), 2892); + config.fjord_max_sequencer_drift = 3600; + assert_eq!(config.max_sequencer_drift(10), 3600); + } + + #[test] + #[cfg(feature = "serde")] + fn test_serde_fjord_max_sequencer_drift_override() { + // Default value survives round-trip. + let config = RollupConfig::default(); + assert_eq!(config.fjord_max_sequencer_drift, FJORD_MAX_SEQUENCER_DRIFT); + let serialized = serde_json::to_string(&config).unwrap(); + let deserialized: RollupConfig = serde_json::from_str(&serialized).unwrap(); + assert_eq!(deserialized.fjord_max_sequencer_drift, FJORD_MAX_SEQUENCER_DRIFT); + + // Custom value survives round-trip. + let mut config = config; + config.fjord_max_sequencer_drift = 2892; + let serialized = serde_json::to_string(&config).unwrap(); + let deserialized: RollupConfig = serde_json::from_str(&serialized).unwrap(); + assert_eq!(deserialized.fjord_max_sequencer_drift, 2892); + } + } } diff --git a/rust/kona/crates/protocol/hardforks/Cargo.toml b/rust/kona/crates/protocol/hardforks/Cargo.toml index 0210f18d8c1..4547c63b004 100644 --- a/rust/kona/crates/protocol/hardforks/Cargo.toml +++ b/rust/kona/crates/protocol/hardforks/Cargo.toml @@ -27,8 +27,8 @@ op-alloy-consensus.workspace = true [dev-dependencies] alloy-primitives = { workspace = true, features = ["rand", "arbitrary"] } -revm = { version = "34.0.0", default-features = false } -op-revm = { version = "15.0.0", default-features = false } +revm.workspace = true +op-revm.workspace = true [features] default = [] diff --git a/rust/kona/crates/protocol/interop/src/depset.rs b/rust/kona/crates/protocol/interop/src/depset.rs index 5b9b29e7efc..eb99ec204d8 100644 --- a/rust/kona/crates/protocol/interop/src/depset.rs +++ b/rust/kona/crates/protocol/interop/src/depset.rs @@ -1,6 +1,6 @@ use crate::MESSAGE_EXPIRY_WINDOW; +use alloc::collections::BTreeMap; use alloy_primitives::ChainId; -use kona_registry::HashMap; /// Configuration for a dependency of a chain #[derive(Debug, Clone, PartialEq, Eq)] @@ -15,7 +15,7 @@ pub struct ChainDependency {} #[allow(clippy::zero_sized_map_values)] pub struct DependencySet { /// Dependencies information per chain. - pub dependencies: HashMap, + pub dependencies: BTreeMap, /// Override message expiry window to use for this dependency set. pub override_message_expiry_window: Option, @@ -35,11 +35,11 @@ impl DependencySet { #[allow(clippy::zero_sized_map_values)] mod tests { use super::*; + use alloc::collections::BTreeMap; use alloy_primitives::ChainId; - use kona_registry::HashMap; const fn create_dependency_set( - dependencies: HashMap, + dependencies: BTreeMap, override_expiry: u64, ) -> DependencySet { DependencySet { dependencies, override_message_expiry_window: Some(override_expiry) } @@ -47,7 +47,7 @@ mod tests { #[test] fn test_get_message_expiry_window_default() { - let deps = HashMap::default(); + let deps = BTreeMap::default(); // override_message_expiry_window is 0, so default should be used let ds = create_dependency_set(deps, 0); assert_eq!( @@ -59,7 +59,7 @@ mod tests { #[test] fn test_get_message_expiry_window_override() { - let deps = HashMap::default(); + let deps = BTreeMap::default(); let override_value = 12345; let ds = create_dependency_set(deps, override_value); assert_eq!( diff --git a/rust/kona/crates/protocol/interop/src/graph.rs b/rust/kona/crates/protocol/interop/src/graph.rs index 35310fb1be3..e10b8015580 100644 --- a/rust/kona/crates/protocol/interop/src/graph.rs +++ b/rust/kona/crates/protocol/interop/src/graph.rs @@ -709,4 +709,37 @@ mod test { let graph = MessageGraph::derive(&headers, &provider, &cfgs, CUSTOM_EXPIRY).await.unwrap(); graph.resolve().await.unwrap(); } + + /// When a chain has been replaced with a deposit-only block, it is excluded from the headers + /// passed to `derive` (since deposit-only blocks cannot contain executing messages). Executing + /// messages on other chains that reference initiating messages from the replaced chain must + /// still resolve successfully, because the provider retains the replaced chain's data. + #[tokio::test] + async fn test_resolve_with_replaced_chain_excluded_from_headers() { + let mut superchain = default_superchain(); + + let chain_a_time = superchain.chain(CHAIN_A_ID).header.timestamp; + + // Chain A has an initiating message. Chain B executes it. + superchain.chain(CHAIN_A_ID).add_initiating_message(MOCK_MESSAGE.into()); + superchain.chain(CHAIN_B_ID).add_executing_message( + ExecutingMessageBuilder::default() + .with_message_hash(keccak256(MOCK_MESSAGE)) + .with_origin_chain_id(CHAIN_A_ID) + .with_origin_timestamp(chain_a_time), + ); + + let (headers, cfgs, provider) = superchain.build(); + + // Simulate chain A having been replaced with a deposit-only block by excluding it + // from the headers passed to derive. The provider still has chain A's data. + let filtered_headers = + headers.into_iter().filter(|(chain_id, _)| *chain_id != CHAIN_A_ID).collect(); + + let graph = + MessageGraph::derive(&filtered_headers, &provider, &cfgs, MESSAGE_EXPIRY_WINDOW) + .await + .unwrap(); + graph.resolve().await.unwrap(); + } } diff --git a/rust/kona/crates/protocol/protocol/src/batch/core.rs b/rust/kona/crates/protocol/protocol/src/batch/core.rs index 7ac31bb08ac..0ebb9a50513 100644 --- a/rust/kona/crates/protocol/protocol/src/batch/core.rs +++ b/rust/kona/crates/protocol/protocol/src/batch/core.rs @@ -42,7 +42,7 @@ impl Batch { } // Read the batch type - let batch_type = BatchType::from(r[0]); + let batch_type = BatchType::try_from(r[0]).map_err(BatchDecodingError::UnknownBatchType)?; r.advance(1); match batch_type { @@ -131,6 +131,13 @@ mod tests { }), decoded); } + #[test] + fn test_unknown_batch_type_returns_error() { + let data = [0xFF, 0x00]; // unknown batch type 0xFF followed by dummy data + let result = Batch::decode(&mut data.as_slice(), &RollupConfig::default()); + assert_eq!(result, Err(BatchDecodingError::UnknownBatchType(0xFF))); + } + #[test] fn test_empty_span_batch() { let mut out = Vec::new(); diff --git a/rust/kona/crates/protocol/protocol/src/batch/errors.rs b/rust/kona/crates/protocol/protocol/src/batch/errors.rs index 33f621af5de..650c6949b28 100644 --- a/rust/kona/crates/protocol/protocol/src/batch/errors.rs +++ b/rust/kona/crates/protocol/protocol/src/batch/errors.rs @@ -40,6 +40,9 @@ pub enum BatchDecodingError { /// Empty buffer #[error("Empty buffer")] EmptyBuffer, + /// Unknown batch type + #[error("Unknown batch type: {0}")] + UnknownBatchType(u8), /// Error decoding an Alloy RLP #[error("Error decoding an Alloy RLP: {0}")] AlloyRlpError(alloy_rlp::Error), diff --git a/rust/kona/crates/protocol/protocol/src/batch/type.rs b/rust/kona/crates/protocol/protocol/src/batch/type.rs index 9bb9a481d9c..7ce2cacf96e 100644 --- a/rust/kona/crates/protocol/protocol/src/batch/type.rs +++ b/rust/kona/crates/protocol/protocol/src/batch/type.rs @@ -28,12 +28,14 @@ pub enum BatchType { Span = SPAN_BATCH_TYPE, } -impl From for BatchType { - fn from(val: u8) -> Self { +impl TryFrom for BatchType { + type Error = u8; + + fn try_from(val: u8) -> Result { match val { - SINGLE_BATCH_TYPE => Self::Single, - SPAN_BATCH_TYPE => Self::Span, - _ => panic!("Invalid batch type: {val}"), + SINGLE_BATCH_TYPE => Ok(Self::Single), + SPAN_BATCH_TYPE => Ok(Self::Span), + _ => Err(val), } } } @@ -51,7 +53,7 @@ impl Encodable for BatchType { impl Decodable for BatchType { fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { let val = u8::decode(buf)?; - Ok(Self::from(val)) + Self::try_from(val).map_err(|_| alloy_rlp::Error::Custom("invalid batch type")) } } @@ -68,4 +70,25 @@ mod test { let decoded = BatchType::decode(&mut buf.as_slice()).unwrap(); assert_eq!(batch_type, decoded); } + + #[test] + fn test_try_from_valid_types() { + assert_eq!(BatchType::try_from(SINGLE_BATCH_TYPE), Ok(BatchType::Single)); + assert_eq!(BatchType::try_from(SPAN_BATCH_TYPE), Ok(BatchType::Span)); + } + + #[test] + fn test_try_from_unknown_type_returns_error() { + assert_eq!(BatchType::try_from(0xFF), Err(0xFF)); + assert_eq!(BatchType::try_from(0x02), Err(0x02)); + } + + #[test] + fn test_rlp_decode_unknown_type_returns_error() { + let mut buf = Vec::new(); + // RLP-encode an invalid batch type byte + 0xFFu8.encode(&mut buf); + let result = BatchType::decode(&mut buf.as_slice()); + assert!(result.is_err()); + } } diff --git a/rust/kona/crates/protocol/protocol/src/utils.rs b/rust/kona/crates/protocol/protocol/src/utils.rs index c1c4251f306..cfc27103ddb 100644 --- a/rust/kona/crates/protocol/protocol/src/utils.rs +++ b/rust/kona/crates/protocol/protocol/src/utils.rs @@ -9,7 +9,7 @@ use op_alloy_consensus::{OpBlock, decode_holocene_extra_data, decode_jovian_extr use crate::{ L1BlockInfoBedrockOnlyFields as _, L1BlockInfoEcotoneBaseFields as _, L1BlockInfoTx, - OpBlockConversionError, SpanBatchError, SpanDecodingError, + MAX_SPAN_BATCH_ELEMENTS, OpBlockConversionError, SpanBatchError, SpanDecodingError, }; /// Converts the [`OpBlock`] to a partial [`SystemConfig`]. @@ -116,6 +116,12 @@ pub fn read_tx_data(r: &mut &[u8]) -> Result<(Vec, TxType), SpanBatchError> let tx_payload = if rlp_header.list { // Grab the raw RLP for the transaction data from `r`. It was unaffected since we copied it. let payload_length_with_header = rlp_header.payload_length + rlp_header.length(); + if payload_length_with_header > MAX_SPAN_BATCH_ELEMENTS as usize { + return Err(SpanBatchError::TooBigSpanBatchSize); + } + if r.len() < payload_length_with_header { + return Err(SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionData)); + } let payload = r[0..payload_length_with_header].to_vec(); r.advance(payload_length_with_header); Ok(payload) @@ -380,4 +386,29 @@ mod tests { }; assert_eq!(config, expected); } + + #[test] + fn test_read_tx_data_truncated_payload() { + // RLP list header claiming 100 bytes of payload, but only 3 bytes actually present. + // 0xf8 0x64 = list header with 1-byte length prefix, payload length 100 + let mut data: &[u8] = &[0xf8, 0x64, 0x00, 0x00, 0x00]; + let err = read_tx_data(&mut data).unwrap_err(); + assert_eq!(err, SpanBatchError::Decoding(SpanDecodingError::InvalidTransactionData)); + } + + #[test] + fn test_read_tx_data_exceeds_max_span_batch_elements() { + // RLP list header claiming MAX_SPAN_BATCH_ELEMENTS + 1 bytes of payload. + // 0xfa = list with 3-byte length prefix (0xf7 + 3), then 0x989681 = 10_000_001. + // Header::decode validates the claimed length against the buffer, so we must provide + // a buffer large enough for decoding to succeed before the max size check triggers. + let mut data = vec![0u8; MAX_SPAN_BATCH_ELEMENTS as usize + 5]; + data[0] = 0xfa; + data[1] = 0x98; + data[2] = 0x96; + data[3] = 0x81; + let mut slice: &[u8] = &data; + let err = read_tx_data(&mut slice).unwrap_err(); + assert_eq!(err, SpanBatchError::TooBigSpanBatchSize); + } } diff --git a/rust/kona/crates/protocol/registry/Cargo.toml b/rust/kona/crates/protocol/registry/Cargo.toml index ffe2511d58d..71611127e0f 100644 --- a/rust/kona/crates/protocol/registry/Cargo.toml +++ b/rust/kona/crates/protocol/registry/Cargo.toml @@ -47,6 +47,7 @@ alloy-eips.workspace = true [features] default = [] +rollup_config_override = ["kona-genesis/rollup_config_override"] tabled = [ "dep:tabled", "std" ] std = [ "alloy-chains/std", diff --git a/rust/kona/crates/protocol/registry/src/test_utils/base_mainnet.rs b/rust/kona/crates/protocol/registry/src/test_utils/base_mainnet.rs index 9333caa3f75..6338c580954 100644 --- a/rust/kona/crates/protocol/registry/src/test_utils/base_mainnet.rs +++ b/rust/kona/crates/protocol/registry/src/test_utils/base_mainnet.rs @@ -8,6 +8,8 @@ use alloy_op_hardforks::{ BASE_MAINNET_ISTHMUS_TIMESTAMP, BASE_MAINNET_JOVIAN_TIMESTAMP, }; use alloy_primitives::{address, b256, uint}; +#[cfg(feature = "rollup_config_override")] +use kona_genesis::FJORD_MAX_SEQUENCER_DRIFT; use kona_genesis::{ BASE_MAINNET_BASE_FEE_CONFIG, ChainGenesis, HardForkConfig, RollupConfig, SystemConfig, }; @@ -44,6 +46,8 @@ pub const BASE_MAINNET_CONFIG: RollupConfig = RollupConfig { seq_window_size: 3600, channel_timeout: 300, granite_channel_timeout: 50, + #[cfg(feature = "rollup_config_override")] + fjord_max_sequencer_drift: FJORD_MAX_SEQUENCER_DRIFT, l1_chain_id: 1, l2_chain_id: Chain::base_mainnet(), hardforks: HardForkConfig { diff --git a/rust/kona/crates/protocol/registry/src/test_utils/base_sepolia.rs b/rust/kona/crates/protocol/registry/src/test_utils/base_sepolia.rs index 613eadbb293..2cbc40c14bc 100644 --- a/rust/kona/crates/protocol/registry/src/test_utils/base_sepolia.rs +++ b/rust/kona/crates/protocol/registry/src/test_utils/base_sepolia.rs @@ -8,6 +8,8 @@ use alloy_op_hardforks::{ BASE_SEPOLIA_ISTHMUS_TIMESTAMP, BASE_SEPOLIA_JOVIAN_TIMESTAMP, }; use alloy_primitives::{address, b256, uint}; +#[cfg(feature = "rollup_config_override")] +use kona_genesis::FJORD_MAX_SEQUENCER_DRIFT; use kona_genesis::{ BASE_SEPOLIA_BASE_FEE_CONFIG, ChainGenesis, HardForkConfig, RollupConfig, SystemConfig, }; @@ -44,6 +46,8 @@ pub const BASE_SEPOLIA_CONFIG: RollupConfig = RollupConfig { seq_window_size: 3600, channel_timeout: 300, granite_channel_timeout: 50, + #[cfg(feature = "rollup_config_override")] + fjord_max_sequencer_drift: FJORD_MAX_SEQUENCER_DRIFT, l1_chain_id: 11155111, l2_chain_id: Chain::base_sepolia(), chain_op_config: BASE_SEPOLIA_BASE_FEE_CONFIG, diff --git a/rust/kona/crates/protocol/registry/src/test_utils/op_mainnet.rs b/rust/kona/crates/protocol/registry/src/test_utils/op_mainnet.rs index 656501f0e0e..d0f08c36124 100644 --- a/rust/kona/crates/protocol/registry/src/test_utils/op_mainnet.rs +++ b/rust/kona/crates/protocol/registry/src/test_utils/op_mainnet.rs @@ -8,6 +8,8 @@ use alloy_op_hardforks::{ OP_MAINNET_JOVIAN_TIMESTAMP, }; use alloy_primitives::{address, b256, uint}; +#[cfg(feature = "rollup_config_override")] +use kona_genesis::FJORD_MAX_SEQUENCER_DRIFT; use kona_genesis::{ ChainGenesis, HardForkConfig, OP_MAINNET_BASE_FEE_CONFIG, RollupConfig, SystemConfig, }; @@ -44,6 +46,8 @@ pub const OP_MAINNET_CONFIG: RollupConfig = RollupConfig { seq_window_size: 3600_u64, channel_timeout: 300_u64, granite_channel_timeout: 50, + #[cfg(feature = "rollup_config_override")] + fjord_max_sequencer_drift: FJORD_MAX_SEQUENCER_DRIFT, l1_chain_id: 1_u64, l2_chain_id: Chain::optimism_mainnet(), chain_op_config: OP_MAINNET_BASE_FEE_CONFIG, diff --git a/rust/kona/crates/protocol/registry/src/test_utils/op_sepolia.rs b/rust/kona/crates/protocol/registry/src/test_utils/op_sepolia.rs index b49c3433ecf..8923796817a 100644 --- a/rust/kona/crates/protocol/registry/src/test_utils/op_sepolia.rs +++ b/rust/kona/crates/protocol/registry/src/test_utils/op_sepolia.rs @@ -8,6 +8,8 @@ use alloy_op_hardforks::{ OP_SEPOLIA_JOVIAN_TIMESTAMP, }; use alloy_primitives::{address, b256, uint}; +#[cfg(feature = "rollup_config_override")] +use kona_genesis::FJORD_MAX_SEQUENCER_DRIFT; use kona_genesis::{ ChainGenesis, HardForkConfig, OP_SEPOLIA_BASE_FEE_CONFIG, RollupConfig, SystemConfig, }; @@ -44,6 +46,8 @@ pub const OP_SEPOLIA_CONFIG: RollupConfig = RollupConfig { seq_window_size: 3600, channel_timeout: 300, granite_channel_timeout: 50, + #[cfg(feature = "rollup_config_override")] + fjord_max_sequencer_drift: FJORD_MAX_SEQUENCER_DRIFT, l1_chain_id: 11155111, l2_chain_id: Chain::optimism_sepolia(), chain_op_config: OP_SEPOLIA_BASE_FEE_CONFIG, diff --git a/rust/kona/crates/providers/providers-alloy/Cargo.toml b/rust/kona/crates/providers/providers-alloy/Cargo.toml index cb1ec23758a..5debeae6e5c 100644 --- a/rust/kona/crates/providers/providers-alloy/Cargo.toml +++ b/rust/kona/crates/providers/providers-alloy/Cargo.toml @@ -27,6 +27,7 @@ alloy-serde.workspace = true alloy-eips = { workspace = true, features = ["kzg"] } alloy-transport.workspace = true alloy-transport-http = { workspace = true, features = ["reqwest", "reqwest-rustls-tls", "hyper", "hyper-tls", "jwt-auth"] } +reqwest = { workspace = true, features = ["query"] } alloy-consensus.workspace = true alloy-rpc-types-beacon.workspace = true alloy-rpc-types-engine.workspace = true @@ -38,7 +39,6 @@ alloy-primitives = { workspace = true, features = ["map"] } op-alloy-consensus.workspace = true op-alloy-network.workspace = true -reqwest.workspace = true # Misc lru.workspace = true diff --git a/rust/kona/docker/apps/kona_app_generic.dockerfile b/rust/kona/docker/apps/kona_app_generic.dockerfile index f1bc963a134..edae3a25e30 100644 --- a/rust/kona/docker/apps/kona_app_generic.dockerfile +++ b/rust/kona/docker/apps/kona_app_generic.dockerfile @@ -18,7 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config # Install rust -ENV RUST_VERSION=1.92 +ENV RUST_VERSION=1.94 RUN curl https://sh.rustup.rs -sSf | bash -s -- -y --default-toolchain ${RUST_VERSION} --profile minimal ENV PATH="/root/.cargo/bin:${PATH}" diff --git a/rust/kona/tests/README.md b/rust/kona/tests/README.md index 77b7711123f..308ff4f2106 100644 --- a/rust/kona/tests/README.md +++ b/rust/kona/tests/README.md @@ -46,13 +46,12 @@ just test-e2e-sysgo node node/common simple-kona To run acceptance tests for the Rust stack: ```bash -just acceptance-tests CL_TYPE EL_TYPE GATE +just acceptance-tests CL_TYPE EL_TYPE ``` Where: - `CL_TYPE`: Consensus layer type (`kona` or `op-node`) - `EL_TYPE`: Execution layer type (`op-reth` or `op-geth`) -- `GATE`: The gate to run (default: `jovian`) ### Other Recipes diff --git a/rust/kona/tests/justfile b/rust/kona/tests/justfile index e684d0f6f79..495db0831ec 100644 --- a/rust/kona/tests/justfile +++ b/rust/kona/tests/justfile @@ -21,7 +21,7 @@ build-kona PROFILE="release": #!/bin/bash cd {{SOURCE}}/.. && cargo build --bin kona-node --profile {{PROFILE}} -acceptance-tests CL_TYPE="kona-node" EL_TYPE="op-reth" GATE="jovian": +acceptance-tests CL_TYPE="kona-node" EL_TYPE="op-reth": #!/bin/bash if [ "{{CL_TYPE}}" = "kona-node" ] ; then echo "Building kona-node..." @@ -33,11 +33,10 @@ acceptance-tests CL_TYPE="kona-node" EL_TYPE="op-reth" GATE="jovian": just build-reth fi - just acceptance-tests-run {{CL_TYPE}} {{EL_TYPE}} {{GATE}} + just acceptance-tests-run {{CL_TYPE}} {{EL_TYPE}} # Run acceptance tests for the rust stack. By default runs the acceptance tests for kona-node with op-reth. -# Uses the jovian gate by default. -acceptance-tests-run CL_TYPE="kona-node" EL_TYPE="op-reth" GATE="jovian": +acceptance-tests-run CL_TYPE="kona-node" EL_TYPE="op-reth": #!/bin/bash if [ "{{CL_TYPE}}" = "kona-node" ] ; then echo "Running acceptance tests for kona-node" @@ -49,12 +48,12 @@ acceptance-tests-run CL_TYPE="kona-node" EL_TYPE="op-reth" GATE="jovian": export OP_RETH_EXEC_PATH="{{SOURCE}}/../../reth/target/debug/op-reth" fi - echo "Running acceptance tests for {{CL_TYPE}} with {{EL_TYPE}} on gate {{GATE}}..." + echo "Running acceptance tests for {{CL_TYPE}} with {{EL_TYPE}}..." export DEVSTACK_L2CL_KIND="{{CL_TYPE}}" export DEVSTACK_L2EL_KIND="{{EL_TYPE}}" export LOG_LEVEL="debug" - cd {{SOURCE}}/optimism/op-acceptance-tests && just acceptance-test "" "{{GATE}}" + cd {{SOURCE}}/optimism/op-acceptance-tests && just acceptance-test # Run the e2e tests for the sysgo orchestrator. # Builds the kona-node and op-reth binaries and runs the tests. diff --git a/rust/op-alloy/crates/consensus/Cargo.toml b/rust/op-alloy/crates/consensus/Cargo.toml index 4fa43515e54..65bda39978e 100644 --- a/rust/op-alloy/crates/consensus/Cargo.toml +++ b/rust/op-alloy/crates/consensus/Cargo.toml @@ -2,7 +2,7 @@ name = "op-alloy-consensus" description = "Optimism alloy consensus types" -version = "0.23.1" +version = "0.24.0" edition.workspace = true rust-version.workspace = true authors = ["Alloy Contributors"] @@ -37,6 +37,13 @@ serde_with = { workspace = true, optional = true } alloy-serde = { workspace = true, optional = true } serde = { workspace = true, features = ["derive"], optional = true } +# reth-core / reth-codec +reth-codecs = { workspace = true, optional = true } +reth-codecs-derive = { workspace = true, optional = true } +reth-zstd-compressors = { workspace = true, optional = true } +bytes = { workspace = true, optional = true } +modular-bitfield = { workspace = true, optional = true } + [dev-dependencies] rand.workspace = true bincode = { workspace = true } @@ -57,9 +64,20 @@ std = [ "alloy-serde?/std", "serde?/std", "serde_with?/std", - "thiserror/std" + "thiserror/std", + "bytes?/std", + "reth-codecs?/std", + "reth-zstd-compressors?/std" ] alloy-compat = ["serde", "dep:alloy-network", "dep:alloy-rpc-types-eth"] +reth-core = [] +reth-codec = [ + "dep:reth-codecs", + "dep:reth-codecs-derive", + "dep:reth-zstd-compressors", + "dep:bytes", + "dep:modular-bitfield", +] k256 = ["alloy-primitives/k256", "alloy-consensus/k256"] kzg = ["alloy-eips/kzg", "alloy-consensus/kzg", "std"] arbitrary = [ @@ -70,7 +88,8 @@ arbitrary = [ "alloy-primitives/rand", "alloy-primitives/arbitrary", "alloy-rpc-types-eth?/arbitrary", - "alloy-serde?/arbitrary" + "alloy-serde?/arbitrary", + "reth-codecs?/arbitrary", ] serde = [ "dep:serde", @@ -78,7 +97,9 @@ serde = [ "alloy-primitives/serde", "alloy-consensus/serde", "alloy-eips/serde", - "alloy-rpc-types-eth?/serde" + "alloy-rpc-types-eth?/serde", + "bytes?/serde", + "reth-codecs?/serde", ] serde-bincode-compat = [ "serde_with", diff --git a/rust/op-alloy/crates/consensus/src/lib.rs b/rust/op-alloy/crates/consensus/src/lib.rs index 455ed3e3c05..02a15b95d88 100644 --- a/rust/op-alloy/crates/consensus/src/lib.rs +++ b/rust/op-alloy/crates/consensus/src/lib.rs @@ -9,6 +9,12 @@ extern crate alloc; +#[cfg(feature = "reth-core")] +mod reth_core; + +#[cfg(feature = "reth-codec")] +mod reth_codec; + #[cfg(feature = "alloy-compat")] mod alloy_compat; diff --git a/rust/op-alloy/crates/consensus/src/reth_codec.rs b/rust/op-alloy/crates/consensus/src/reth_codec.rs new file mode 100644 index 00000000000..d3bd124f584 --- /dev/null +++ b/rust/op-alloy/crates/consensus/src/reth_codec.rs @@ -0,0 +1,376 @@ +//! Compact codec implementations for OP Stack consensus types. +//! +//! Ported from reth v1.11.3 (`d6324d63e`), where they lived behind the `op` feature: +//! - Transaction codecs: `crates/storage/codecs/src/alloy/transaction/optimism.rs` +//! - Receipt codecs: `crates/storage/codecs/src/alloy/optimism.rs` +//! +//! Differences from upstream: +//! - `CompactOpReceipt` uses `Vec` instead of `Cow<'a, Vec>` because the crates.io +//! `reth-codecs-derive` macro doesn't support lifetime parameters. The wire format is identical; +//! only serialization performance differs (clone vs borrow). +//! - `Compress`/`Decompress` impls for `OpTxEnvelope` and `OpReceipt` are added here since they +//! were previously provided by reth's in-tree codecs crate. + +use crate::{OpReceipt, OpTxEnvelope, OpTxType, OpTypedTransaction, TxDeposit}; +use alloc::vec::Vec; +use alloy_consensus::{Receipt, Signed}; +use alloy_primitives::{Address, B256, Bytes, Log, Signature, TxKind, U256}; +use reth_codecs::{ + Compact, + alloy::transaction::{CompactEnvelope, Envelope, FromTxCompact, ToTxCompact}, + txtype::*, +}; + +// --- OpTxType --- + +impl Compact for OpTxType { + fn to_compact(&self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + match self { + Self::Legacy => COMPACT_IDENTIFIER_LEGACY, + Self::Eip2930 => COMPACT_IDENTIFIER_EIP2930, + Self::Eip1559 => COMPACT_IDENTIFIER_EIP1559, + Self::Eip7702 => { + buf.put_u8(alloy_consensus::constants::EIP7702_TX_TYPE_ID); + COMPACT_EXTENDED_IDENTIFIER_FLAG + } + Self::Deposit => { + buf.put_u8(crate::DEPOSIT_TX_TYPE_ID); + COMPACT_EXTENDED_IDENTIFIER_FLAG + } + } + } + + fn from_compact(mut buf: &[u8], identifier: usize) -> (Self, &[u8]) { + use bytes::Buf; + match identifier { + COMPACT_IDENTIFIER_LEGACY => (Self::Legacy, buf), + COMPACT_IDENTIFIER_EIP2930 => (Self::Eip2930, buf), + COMPACT_IDENTIFIER_EIP1559 => (Self::Eip1559, buf), + COMPACT_EXTENDED_IDENTIFIER_FLAG => { + let extended_identifier = buf.get_u8(); + let ty = match extended_identifier { + alloy_consensus::constants::EIP7702_TX_TYPE_ID => Self::Eip7702, + crate::DEPOSIT_TX_TYPE_ID => Self::Deposit, + _ => panic!("Unsupported OpTxType identifier: {extended_identifier}"), + }; + (ty, buf) + } + _ => panic!("Unknown identifier for OpTxType: {identifier}"), + } + } +} + +// --- TxDeposit --- + +/// Mirror struct for compact encoding of [`TxDeposit`]. +#[derive(reth_codecs_derive::Compact)] +#[reth_codecs(crate = "reth_codecs")] +struct CompactTxDeposit { + source_hash: B256, + from: Address, + to: TxKind, + mint: Option, + value: U256, + gas_limit: u64, + is_system_transaction: bool, + input: Bytes, +} + +impl From<&TxDeposit> for CompactTxDeposit { + fn from(tx: &TxDeposit) -> Self { + Self { + source_hash: tx.source_hash, + from: tx.from, + to: tx.to, + mint: match tx.mint { + 0 => None, + v => Some(v), + }, + value: tx.value, + gas_limit: tx.gas_limit, + is_system_transaction: tx.is_system_transaction, + input: tx.input.clone(), + } + } +} + +impl From for TxDeposit { + fn from(tx: CompactTxDeposit) -> Self { + Self { + source_hash: tx.source_hash, + from: tx.from, + to: tx.to, + mint: tx.mint.unwrap_or_default(), + value: tx.value, + gas_limit: tx.gas_limit, + is_system_transaction: tx.is_system_transaction, + input: tx.input, + } + } +} + +impl Compact for TxDeposit { + fn to_compact(&self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + CompactTxDeposit::from(self).to_compact(buf) + } + + fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) { + let (compact, buf) = CompactTxDeposit::from_compact(buf, len); + (compact.into(), buf) + } +} + +// --- OpTypedTransaction --- + +impl Compact for OpTypedTransaction { + fn to_compact(&self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + let tx_type = self.tx_type(); + let identifier = tx_type.to_compact(buf); + match self { + Self::Legacy(tx) => { + tx.to_compact(buf); + } + Self::Eip2930(tx) => { + tx.to_compact(buf); + } + Self::Eip1559(tx) => { + tx.to_compact(buf); + } + Self::Eip7702(tx) => { + tx.to_compact(buf); + } + Self::Deposit(tx) => { + tx.to_compact(buf); + } + } + identifier + } + + fn from_compact(buf: &[u8], identifier: usize) -> (Self, &[u8]) { + let (tx_type, buf) = OpTxType::from_compact(buf, identifier); + match tx_type { + OpTxType::Legacy => { + let (tx, buf) = alloy_consensus::TxLegacy::from_compact(buf, buf.len()); + (Self::Legacy(tx), buf) + } + OpTxType::Eip2930 => { + let (tx, buf) = alloy_consensus::TxEip2930::from_compact(buf, buf.len()); + (Self::Eip2930(tx), buf) + } + OpTxType::Eip1559 => { + let (tx, buf) = alloy_consensus::TxEip1559::from_compact(buf, buf.len()); + (Self::Eip1559(tx), buf) + } + OpTxType::Eip7702 => { + let (tx, buf) = alloy_consensus::TxEip7702::from_compact(buf, buf.len()); + (Self::Eip7702(tx), buf) + } + OpTxType::Deposit => { + let (tx, buf) = TxDeposit::from_compact(buf, buf.len()); + (Self::Deposit(tx), buf) + } + } + } +} + +// --- OpTxEnvelope --- + +impl Envelope for OpTxEnvelope { + fn signature(&self) -> &Signature { + match self { + Self::Legacy(tx) => tx.signature(), + Self::Eip2930(tx) => tx.signature(), + Self::Eip1559(tx) => tx.signature(), + Self::Eip7702(tx) => tx.signature(), + Self::Deposit(_) => { + const DEPOSIT_SIG: Signature = Signature::new(U256::ZERO, U256::ZERO, false); + &DEPOSIT_SIG + } + } + } + + fn tx_type(&self) -> Self::TxType { + alloy_consensus::Typed2718::ty(self).try_into().expect("valid op tx type") + } +} + +impl ToTxCompact for OpTxEnvelope { + fn to_tx_compact(&self, buf: &mut (impl bytes::BufMut + AsMut<[u8]>)) { + // Only write the tx body without the type prefix. The type is serialized separately + // by CompactEnvelope. + match self { + Self::Legacy(tx) => { + tx.tx().to_compact(buf); + } + Self::Eip2930(tx) => { + tx.tx().to_compact(buf); + } + Self::Eip1559(tx) => { + tx.tx().to_compact(buf); + } + Self::Eip7702(tx) => { + tx.tx().to_compact(buf); + } + Self::Deposit(tx) => { + tx.inner().to_compact(buf); + } + }; + } +} + +impl FromTxCompact for OpTxEnvelope { + type TxType = OpTxType; + + fn from_tx_compact(buf: &[u8], tx_type: Self::TxType, signature: Signature) -> (Self, &[u8]) + where + Self: Sized, + { + // Deserialize the tx body directly based on tx_type. The type prefix was already + // consumed by CompactEnvelope. + match tx_type { + OpTxType::Legacy => { + let (tx, buf) = alloy_consensus::TxLegacy::from_compact(buf, buf.len()); + (Self::Legacy(Signed::new_unhashed(tx, signature)), buf) + } + OpTxType::Eip2930 => { + let (tx, buf) = alloy_consensus::TxEip2930::from_compact(buf, buf.len()); + (Self::Eip2930(Signed::new_unhashed(tx, signature)), buf) + } + OpTxType::Eip1559 => { + let (tx, buf) = alloy_consensus::TxEip1559::from_compact(buf, buf.len()); + (Self::Eip1559(Signed::new_unhashed(tx, signature)), buf) + } + OpTxType::Eip7702 => { + let (tx, buf) = alloy_consensus::TxEip7702::from_compact(buf, buf.len()); + (Self::Eip7702(Signed::new_unhashed(tx, signature)), buf) + } + OpTxType::Deposit => { + let (tx, buf) = TxDeposit::from_compact(buf, buf.len()); + (Self::Deposit(alloy_consensus::Sealed::new(tx)), buf) + } + } + } +} + +impl Compact for OpTxEnvelope { + fn to_compact(&self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + ::to_compact(self, buf) + } + + fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) { + ::from_compact(buf, len) + } +} + +impl reth_codecs::Compress for OpTxEnvelope { + type Compressed = Vec; + + fn compress_to_buf>(&self, buf: &mut B) { + let _ = Compact::to_compact(self, buf); + } +} + +impl reth_codecs::Decompress for OpTxEnvelope { + fn decompress(value: &[u8]) -> Result { + let (obj, _) = Compact::from_compact(value, value.len()); + Ok(obj) + } +} + +// --- OpReceipt --- + +/// Mirror struct for compact encoding of [`crate::OpDepositReceipt`]. +#[derive(reth_codecs_derive::CompactZstd)] +#[reth_codecs(crate = "reth_codecs")] +#[reth_zstd( + compressor = reth_zstd_compressors::with_receipt_compressor, + decompressor = reth_zstd_compressors::with_receipt_decompressor +)] +struct CompactOpReceipt { + tx_type: OpTxType, + success: bool, + cumulative_gas_used: u64, + logs: Vec, + deposit_nonce: Option, + deposit_receipt_version: Option, +} + +impl From<&OpReceipt> for CompactOpReceipt { + fn from(receipt: &OpReceipt) -> Self { + use alloy_consensus::TxReceipt; + let (deposit_nonce, deposit_receipt_version) = match receipt { + OpReceipt::Deposit(deposit) => (deposit.deposit_nonce, deposit.deposit_receipt_version), + _ => (None, None), + }; + Self { + tx_type: receipt.tx_type(), + success: receipt.status(), + cumulative_gas_used: receipt.cumulative_gas_used(), + logs: receipt.as_receipt().logs.clone(), + deposit_nonce, + deposit_receipt_version, + } + } +} + +impl From for OpReceipt { + fn from(compact: CompactOpReceipt) -> Self { + let receipt = Receipt { + status: compact.success.into(), + cumulative_gas_used: compact.cumulative_gas_used, + logs: compact.logs, + }; + match compact.tx_type { + OpTxType::Legacy => Self::Legacy(receipt), + OpTxType::Eip2930 => Self::Eip2930(receipt), + OpTxType::Eip1559 => Self::Eip1559(receipt), + OpTxType::Eip7702 => Self::Eip7702(receipt), + OpTxType::Deposit => Self::Deposit(crate::OpDepositReceipt { + inner: receipt, + deposit_nonce: compact.deposit_nonce, + deposit_receipt_version: compact.deposit_receipt_version, + }), + } + } +} + +impl Compact for OpReceipt { + fn to_compact(&self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + CompactOpReceipt::from(self).to_compact(buf) + } + + fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) { + let (compact, buf) = CompactOpReceipt::from_compact(buf, len); + (compact.into(), buf) + } +} + +impl reth_codecs::Compress for OpReceipt { + type Compressed = Vec; + + fn compress_to_buf>(&self, buf: &mut B) { + let _ = Compact::to_compact(self, buf); + } +} + +impl reth_codecs::Decompress for OpReceipt { + fn decompress(value: &[u8]) -> Result { + let (obj, _) = Compact::from_compact(value, value.len()); + Ok(obj) + } +} diff --git a/rust/op-alloy/crates/consensus/src/reth_core.rs b/rust/op-alloy/crates/consensus/src/reth_core.rs new file mode 100644 index 00000000000..585eca1cb60 --- /dev/null +++ b/rust/op-alloy/crates/consensus/src/reth_core.rs @@ -0,0 +1,83 @@ +//! Implementations of `InMemorySize` for OP Stack consensus types. +//! +//! Ported from reth v1.11.3 (`d6324d63e`): +//! - `crates/primitives-traits/src/size.rs` (behind `cfg(feature = "op")`) +//! +//! Differences from upstream: +//! - `OpTxType` and `TxDeposit` impls are new (upstream only had them for the compound types, but +//! the `reth-core` crate now requires them standalone). +//! - `OpTxEnvelope::Deposit` explicitly sizes the seal hash + inner tx, whereas upstream delegated +//! to `Sealed::size()` which did the same internally. + +use crate::{ + OpDepositReceipt, OpPooledTransaction, OpReceipt, OpTxEnvelope, OpTxType, OpTypedTransaction, + TxDeposit, +}; +use alloy_consensus::InMemorySize; + +impl InMemorySize for OpTxType { + fn size(&self) -> usize { + core::mem::size_of::() + } +} + +impl InMemorySize for TxDeposit { + fn size(&self) -> usize { + core::mem::size_of::() + self.input.len() + } +} + +impl InMemorySize for OpDepositReceipt { + fn size(&self) -> usize { + self.inner.size() + + core::mem::size_of_val(&self.deposit_nonce) + + core::mem::size_of_val(&self.deposit_receipt_version) + } +} + +impl InMemorySize for OpReceipt { + fn size(&self) -> usize { + match self { + Self::Legacy(receipt) | + Self::Eip2930(receipt) | + Self::Eip1559(receipt) | + Self::Eip7702(receipt) => receipt.size(), + Self::Deposit(receipt) => receipt.size(), + } + } +} + +impl InMemorySize for OpTypedTransaction { + fn size(&self) -> usize { + match self { + Self::Legacy(tx) => tx.size(), + Self::Eip2930(tx) => tx.size(), + Self::Eip1559(tx) => tx.size(), + Self::Eip7702(tx) => tx.size(), + Self::Deposit(tx) => tx.size(), + } + } +} + +impl InMemorySize for OpPooledTransaction { + fn size(&self) -> usize { + match self { + Self::Legacy(tx) => tx.size(), + Self::Eip2930(tx) => tx.size(), + Self::Eip1559(tx) => tx.size(), + Self::Eip7702(tx) => tx.size(), + } + } +} + +impl InMemorySize for OpTxEnvelope { + fn size(&self) -> usize { + match self { + Self::Legacy(tx) => tx.size(), + Self::Eip2930(tx) => tx.size(), + Self::Eip1559(tx) => tx.size(), + Self::Eip7702(tx) => tx.size(), + Self::Deposit(tx) => core::mem::size_of::() + tx.inner().size(), + } + } +} diff --git a/rust/op-alloy/crates/network/Cargo.toml b/rust/op-alloy/crates/network/Cargo.toml index 739b4df136a..a063b681514 100644 --- a/rust/op-alloy/crates/network/Cargo.toml +++ b/rust/op-alloy/crates/network/Cargo.toml @@ -2,7 +2,7 @@ name = "op-alloy-network" description = "Optimism blockchain RPC behavior abstraction" -version = "0.23.1" +version = "0.24.0" edition.workspace = true rust-version.workspace = true authors = ["Alloy Contributors"] diff --git a/rust/op-alloy/crates/op-alloy/Cargo.toml b/rust/op-alloy/crates/op-alloy/Cargo.toml index 01f792166be..d767a44f3d0 100644 --- a/rust/op-alloy/crates/op-alloy/Cargo.toml +++ b/rust/op-alloy/crates/op-alloy/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "op-alloy" description = "Connect applications to the OP Stack" -version = "0.23.1" +version = "0.24.0" edition.workspace = true rust-version.workspace = true authors = ["Alloy Contributors"] @@ -68,6 +68,8 @@ consensus = ["dep:op-alloy-consensus"] rpc-types = ["dep:op-alloy-rpc-types"] rpc-types-engine = ["dep:op-alloy-rpc-types-engine"] +reth = ["rpc-types", "op-alloy-rpc-types/reth"] + # std features network = ["dep:op-alloy-network"] rpc-jsonrpsee = ["dep:op-alloy-rpc-jsonrpsee"] diff --git a/rust/op-alloy/crates/provider/Cargo.toml b/rust/op-alloy/crates/provider/Cargo.toml index 6eea54cf581..613e8549f19 100644 --- a/rust/op-alloy/crates/provider/Cargo.toml +++ b/rust/op-alloy/crates/provider/Cargo.toml @@ -2,7 +2,7 @@ name = "op-alloy-provider" description = "Interface with an OP Stack blockchain" -version = "0.23.1" +version = "0.24.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/rust/op-alloy/crates/rpc-jsonrpsee/Cargo.toml b/rust/op-alloy/crates/rpc-jsonrpsee/Cargo.toml index 1e0eec62d0e..59ec619aac3 100644 --- a/rust/op-alloy/crates/rpc-jsonrpsee/Cargo.toml +++ b/rust/op-alloy/crates/rpc-jsonrpsee/Cargo.toml @@ -2,7 +2,7 @@ name = "op-alloy-rpc-jsonrpsee" description = "Optimism RPC Client" -version = "0.23.1" +version = "0.24.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/rust/op-alloy/crates/rpc-types-engine/Cargo.toml b/rust/op-alloy/crates/rpc-types-engine/Cargo.toml index 2b7a8d0b3ac..324d3b9a571 100644 --- a/rust/op-alloy/crates/rpc-types-engine/Cargo.toml +++ b/rust/op-alloy/crates/rpc-types-engine/Cargo.toml @@ -2,7 +2,7 @@ name = "op-alloy-rpc-types-engine" description = "Optimism RPC types for the `engine` namespace" -version = "0.23.1" +version = "0.24.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/rust/op-alloy/crates/rpc-types/Cargo.toml b/rust/op-alloy/crates/rpc-types/Cargo.toml index 58537af2a04..b0e2fce1148 100644 --- a/rust/op-alloy/crates/rpc-types/Cargo.toml +++ b/rust/op-alloy/crates/rpc-types/Cargo.toml @@ -2,7 +2,7 @@ name = "op-alloy-rpc-types" description = "Optimism RPC types" -version = "0.23.1" +version = "0.24.0" edition.workspace = true rust-version.workspace = true license.workspace = true @@ -32,6 +32,9 @@ serde = { workspace = true, features = ["derive"] } # RPC jsonrpsee = { workspace = true, optional = true } +reth-rpc-traits = { workspace = true, optional = true } +alloy-signer = { workspace = true, optional = true } +alloy-network = { workspace = true, optional = true } # arbitrary arbitrary = { workspace = true, features = ["derive"], optional = true } @@ -61,7 +64,8 @@ std = [ "derive_more/std", "serde/std", "serde_json/std", - "thiserror/std" + "thiserror/std", + "reth-rpc-traits?/std" ] arbitrary = [ "std", @@ -83,3 +87,4 @@ serde = [ "alloy-rpc-types-eth/serde" ] jsonrpsee = ["dep:jsonrpsee"] +reth = ["dep:reth-rpc-traits", "dep:alloy-signer", "dep:alloy-network"] diff --git a/rust/op-alloy/crates/rpc-types/src/lib.rs b/rust/op-alloy/crates/rpc-types/src/lib.rs index e34acc9726c..f77b33eeec7 100644 --- a/rust/op-alloy/crates/rpc-types/src/lib.rs +++ b/rust/op-alloy/crates/rpc-types/src/lib.rs @@ -20,3 +20,6 @@ pub use transaction::{OpTransactionFields, OpTransactionRequest, Transaction}; pub mod error; pub use error::SuperchainDAError; + +#[cfg(feature = "reth")] +mod reth_compat; diff --git a/rust/op-alloy/crates/rpc-types/src/reth_compat.rs b/rust/op-alloy/crates/rpc-types/src/reth_compat.rs new file mode 100644 index 00000000000..a0153d63dc0 --- /dev/null +++ b/rust/op-alloy/crates/rpc-types/src/reth_compat.rs @@ -0,0 +1,65 @@ +//! Implementations of `reth-rpc-traits` for OP types. +//! +//! Ported from reth v1.11.3 (`d6324d63e`), where they lived behind `cfg(feature = "op")`: +//! - `FromConsensusTx`, `TryIntoSimTx`: `crates/rpc/rpc-convert/src/transaction.rs` +//! - `SignableTxRequest`: `crates/rpc/rpc-convert/src/rpc.rs` +//! +//! The traits themselves moved from `reth-rpc-convert` to the published `reth-rpc-traits` +//! crate (v0.1.0), so the impls now target `reth-rpc-traits` types. The logic is identical +//! to upstream. + +use alloy_consensus::SignableTransaction; +use alloy_primitives::Address; +use alloy_signer::Signature; +use core::convert::Infallible; +use op_alloy_consensus::{ + OpTxEnvelope, TxDeposit, + transaction::{OpTransaction, OpTransactionInfo}, +}; +use reth_rpc_traits::{FromConsensusTx, SignTxRequestError, SignableTxRequest, TryIntoSimTx}; + +use crate::OpTransactionRequest; + +impl FromConsensusTx for crate::Transaction { + type TxInfo = OpTransactionInfo; + type Err = Infallible; + + fn from_consensus_tx(tx: T, signer: Address, tx_info: Self::TxInfo) -> Result { + Ok(Self::from_transaction( + alloy_consensus::transaction::Recovered::new_unchecked(tx, signer), + tx_info, + )) + } +} + +impl TryIntoSimTx for OpTransactionRequest { + fn try_into_sim_tx(self) -> Result> { + let tx = self.build_typed_tx().map_err(|request| { + alloy_consensus::error::ValueError::new(request, "Required fields missing") + })?; + + // Create an empty signature for the transaction. + let signature = Signature::new(Default::default(), Default::default(), false); + + Ok(tx.into_signed(signature).into()) + } +} + +impl SignableTxRequest for OpTransactionRequest { + async fn try_build_and_sign( + self, + signer: impl alloy_network::TxSigner + Send, + ) -> Result { + let mut tx = + self.build_typed_tx().map_err(|_| SignTxRequestError::InvalidTransactionRequest)?; + + // Deposit transactions must not be signed by the user. + if matches!(tx, op_alloy_consensus::OpTypedTransaction::Deposit(TxDeposit { .. })) { + return Err(SignTxRequestError::InvalidTransactionRequest); + } + + let signature = signer.sign_transaction(&mut tx).await?; + + Ok(tx.into_signed(signature).into()) + } +} diff --git a/rust/op-reth/DockerfileOp b/rust/op-reth/DockerfileOp index e7a4a58557e..0e50209ce3f 100644 --- a/rust/op-reth/DockerfileOp +++ b/rust/op-reth/DockerfileOp @@ -1,4 +1,4 @@ -FROM lukemathwalker/cargo-chef:latest-rust-1.92 AS chef +FROM lukemathwalker/cargo-chef:latest-rust-1.94 AS chef WORKDIR /app LABEL org.opencontainers.image.source=https://github.com/paradigmxyz/reth diff --git a/rust/op-reth/bin/Cargo.toml b/rust/op-reth/bin/Cargo.toml index a1e1473c8c5..6c00b836e7a 100644 --- a/rust/op-reth/bin/Cargo.toml +++ b/rust/op-reth/bin/Cargo.toml @@ -61,7 +61,6 @@ min-info-logs = ["tracing/release_max_level_info"] min-debug-logs = ["tracing/release_max_level_debug"] min-trace-logs = ["tracing/release_max_level_trace"] -edge = ["reth-optimism-cli/edge"] [[bin]] name = "op-reth" diff --git a/rust/op-reth/crates/cli/Cargo.toml b/rust/op-reth/crates/cli/Cargo.toml index fcc61b1a9fd..d288dd9c13a 100644 --- a/rust/op-reth/crates/cli/Cargo.toml +++ b/rust/op-reth/crates/cli/Cargo.toml @@ -17,7 +17,7 @@ reth-cli-commands.workspace = true reth-consensus.workspace = true reth-rpc-server-types.workspace = true reth-primitives-traits.workspace = true -reth-db = { workspace = true, features = ["mdbx", "op"] } +reth-db = { workspace = true, features = ["mdbx"] } reth-db-api.workspace = true reth-db-common.workspace = true reth-downloaders.workspace = true @@ -43,7 +43,8 @@ reth-chainspec.workspace = true reth-node-events.workspace = true reth-optimism-evm.workspace = true reth-cli-runner.workspace = true -reth-node-builder = { workspace = true, features = ["op"] } +reth-tasks.workspace = true +reth-node-builder.workspace = true reth-tracing.workspace = true # eth @@ -97,6 +98,7 @@ keccak-cache-global = [ jemalloc = [ "reth-node-core/jemalloc", "reth-node-metrics/jemalloc", + "reth-provider/jemalloc", ] jemalloc-prof = [ "jemalloc", @@ -109,7 +111,7 @@ jemalloc-symbols = [ tracy = ["reth-tracing/tracy", "reth-node-core/tracy"] -dev = ["dep:proptest", "reth-cli-commands/arbitrary"] +dev = ["dep:proptest", "reth-cli-commands/arbitrary", "op-alloy-consensus/arbitrary"] serde = [ "alloy-consensus/serde", @@ -122,4 +124,3 @@ serde = [ "reth-optimism-chainspec/serde", ] -edge = ["reth-cli-commands/edge", "reth-node-core/edge"] diff --git a/rust/op-reth/crates/cli/src/app.rs b/rust/op-reth/crates/cli/src/app.rs index 730bda4c274..1189fc74ae8 100644 --- a/rust/op-reth/crates/cli/src/app.rs +++ b/rust/op-reth/crates/cli/src/app.rs @@ -86,16 +86,20 @@ where runner.run_command_until_exit(|ctx| command.execute(ctx, launcher)) } Commands::Init(command) => { - runner.run_blocking_until_ctrl_c(command.execute::()) + let runtime = runner.runtime(); + runner.run_blocking_until_ctrl_c(command.execute::(runtime)) } Commands::InitState(command) => { - runner.run_blocking_until_ctrl_c(command.execute::()) + let runtime = runner.runtime(); + runner.run_blocking_until_ctrl_c(command.execute::(runtime)) } Commands::ImportOp(command) => { - runner.run_blocking_until_ctrl_c(command.execute::()) + let runtime = runner.runtime(); + runner.run_blocking_until_ctrl_c(command.execute::(runtime)) } Commands::ImportReceiptsOp(command) => { - runner.run_blocking_until_ctrl_c(command.execute::()) + let runtime = runner.runtime(); + runner.run_blocking_until_ctrl_c(command.execute::(runtime)) } Commands::DumpGenesis(command) => runner.run_blocking_until_ctrl_c(command.execute()), Commands::Db(command) => { @@ -112,10 +116,12 @@ where #[cfg(feature = "dev")] Commands::TestVectors(command) => runner.run_until_ctrl_c(command.execute()), Commands::ReExecute(command) => { - runner.run_until_ctrl_c(command.execute::(components)) + let runtime = runner.runtime(); + runner.run_until_ctrl_c(command.execute::(components, runtime)) } Commands::OpProofs(command) => { - runner.run_blocking_until_ctrl_c(command.execute::()) + let runtime = runner.runtime(); + runner.run_blocking_until_ctrl_c(command.execute::(runtime)) } } } @@ -131,7 +137,7 @@ where let otlp_status = runner.block_on(self.cli.traces.init_otlp_tracing(&mut layers))?; let otlp_logs_status = runner.block_on(self.cli.traces.init_otlp_logs(&mut layers))?; - self.guard = self.cli.logs.init_tracing_with_layers(layers)?; + self.guard = self.cli.logs.init_tracing_with_layers(layers, false)?; info!(target: "reth::cli", "Initialized tracing, debug log directory: {}", self.cli.logs.log_file_directory); match otlp_status { diff --git a/rust/op-reth/crates/cli/src/commands/import.rs b/rust/op-reth/crates/cli/src/commands/import.rs index 0d7e0cde8cd..3bbdc45972f 100644 --- a/rust/op-reth/crates/cli/src/commands/import.rs +++ b/rust/op-reth/crates/cli/src/commands/import.rs @@ -43,6 +43,7 @@ impl> ImportOpCommand { /// Execute `import` command pub async fn execute>( self, + runtime: reth_tasks::Runtime, ) -> eyre::Result<()> { info!(target: "reth::cli", "reth {} starting", version_metadata().short_version); @@ -55,7 +56,8 @@ impl> ImportOpCommand { "Chunking chain import" ); - let Environment { provider_factory, config, .. } = self.env.init::(AccessRights::RW)?; + let Environment { provider_factory, config, .. } = + self.env.init::(AccessRights::RW, runtime.clone())?; // we use noop here because we expect the inputs to be valid let consensus = Arc::new(NoopConsensus::default()); @@ -106,6 +108,7 @@ impl> ImportOpCommand { static_file_producer.clone(), true, OpExecutorProvider::optimism(provider_factory.chain_spec()), + runtime.clone(), )?; // override the tip diff --git a/rust/op-reth/crates/cli/src/commands/import_receipts.rs b/rust/op-reth/crates/cli/src/commands/import_receipts.rs index d2a66fe90d0..17270f62165 100644 --- a/rust/op-reth/crates/cli/src/commands/import_receipts.rs +++ b/rust/op-reth/crates/cli/src/commands/import_receipts.rs @@ -51,6 +51,7 @@ impl> ImportReceiptsOpCommand { /// Execute `import` command pub async fn execute>( self, + runtime: reth_tasks::Runtime, ) -> eyre::Result<()> { info!(target: "reth::cli", "reth {} starting", version_metadata().short_version); @@ -59,7 +60,7 @@ impl> ImportReceiptsOpCommand { "Chunking receipts import" ); - let Environment { provider_factory, .. } = self.env.init::(AccessRights::RW)?; + let Environment { provider_factory, .. } = self.env.init::(AccessRights::RW, runtime)?; import_receipts_from_file( provider_factory, diff --git a/rust/op-reth/crates/cli/src/commands/init_state.rs b/rust/op-reth/crates/cli/src/commands/init_state.rs index 09e2bd23ab7..b277bb1d0c5 100644 --- a/rust/op-reth/crates/cli/src/commands/init_state.rs +++ b/rust/op-reth/crates/cli/src/commands/init_state.rs @@ -40,12 +40,13 @@ impl> InitStateCommandOp { /// Execute the `init` command pub async fn execute>( mut self, + runtime: reth_tasks::Runtime, ) -> eyre::Result<()> { // If using --without-ovm for OP mainnet, handle the special case with hardcoded Bedrock // header. Otherwise delegate to the base InitStateCommand implementation. if self.without_ovm { if self.init_state.env.chain.is_optimism_mainnet() { - return self.execute_with_bedrock_header::(); + return self.execute_with_bedrock_header::(runtime); } // For non-mainnet OP chains with --without-ovm, use the base implementation @@ -53,7 +54,7 @@ impl> InitStateCommandOp { self.init_state.without_evm = true; } - self.init_state.execute::().await + self.init_state.execute::(runtime).await } /// Execute init-state with hardcoded Bedrock header for OP mainnet. @@ -61,9 +62,10 @@ impl> InitStateCommandOp { N: CliNodeTypes, >( self, + runtime: reth_tasks::Runtime, ) -> eyre::Result<()> { info!(target: "reth::cli", "Reth init-state starting for OP mainnet"); - let env = self.init_state.env.init::(AccessRights::RW)?; + let env = self.init_state.env.init::(AccessRights::RW, runtime)?; let Environment { config, provider_factory, .. } = env; let static_file_provider = provider_factory.static_file_provider(); diff --git a/rust/op-reth/crates/cli/src/commands/op_proofs/init.rs b/rust/op-reth/crates/cli/src/commands/op_proofs/init.rs index 1c1d2be34aa..094be02d7a3 100644 --- a/rust/op-reth/crates/cli/src/commands/op_proofs/init.rs +++ b/rust/op-reth/crates/cli/src/commands/op_proofs/init.rs @@ -37,12 +37,13 @@ impl> InitCommand { /// Execute `initialize-op-proofs` command pub async fn execute>( self, + runtime: reth_tasks::Runtime, ) -> eyre::Result<()> { info!(target: "reth::cli", "reth {} starting", version_metadata().short_version); info!(target: "reth::cli", "Initializing OP proofs storage at: {:?}", self.storage_path); // Initialize the environment with read-only access - let Environment { provider_factory, .. } = self.env.init::(AccessRights::RO)?; + let Environment { provider_factory, .. } = self.env.init::(AccessRights::RO, runtime)?; // Create the proofs storage without the metrics wrapper. // During initialization we write billions of entries; the metrics layer's diff --git a/rust/op-reth/crates/cli/src/commands/op_proofs/mod.rs b/rust/op-reth/crates/cli/src/commands/op_proofs/mod.rs index 9f49a288ccb..fae3476e494 100644 --- a/rust/op-reth/crates/cli/src/commands/op_proofs/mod.rs +++ b/rust/op-reth/crates/cli/src/commands/op_proofs/mod.rs @@ -22,11 +22,12 @@ impl> Command { /// Execute `op-proofs` command pub async fn execute>( self, + runtime: reth_tasks::Runtime, ) -> eyre::Result<()> { match self.command { - Subcommands::Init(cmd) => cmd.execute::().await, - Subcommands::Prune(cmd) => cmd.execute::().await, - Subcommands::Unwind(cmd) => cmd.execute::().await, + Subcommands::Init(cmd) => cmd.execute::(runtime).await, + Subcommands::Prune(cmd) => cmd.execute::(runtime).await, + Subcommands::Unwind(cmd) => cmd.execute::(runtime).await, } } } diff --git a/rust/op-reth/crates/cli/src/commands/op_proofs/prune.rs b/rust/op-reth/crates/cli/src/commands/op_proofs/prune.rs index 369f3e56625..643e22c4334 100644 --- a/rust/op-reth/crates/cli/src/commands/op_proofs/prune.rs +++ b/rust/op-reth/crates/cli/src/commands/op_proofs/prune.rs @@ -47,12 +47,13 @@ impl> PruneCommand { /// Execute [`PruneCommand`]. pub async fn execute>( self, + runtime: reth_tasks::Runtime, ) -> eyre::Result<()> { info!(target: "reth::cli", "reth {} starting", version_metadata().short_version); info!(target: "reth::cli", "Pruning OP proofs storage at: {:?}", self.storage_path); // Initialize the environment with read-only access - let Environment { provider_factory, .. } = self.env.init::(AccessRights::RO)?; + let Environment { provider_factory, .. } = self.env.init::(AccessRights::RO, runtime)?; let storage: Arc = Arc::new( MdbxProofsStorage::new(&self.storage_path) diff --git a/rust/op-reth/crates/cli/src/commands/op_proofs/unwind.rs b/rust/op-reth/crates/cli/src/commands/op_proofs/unwind.rs index d22cf5f801c..3dd6ec881b8 100644 --- a/rust/op-reth/crates/cli/src/commands/op_proofs/unwind.rs +++ b/rust/op-reth/crates/cli/src/commands/op_proofs/unwind.rs @@ -62,12 +62,13 @@ impl> UnwindCommand { /// Execute [`UnwindCommand`]. pub async fn execute>( self, + runtime: reth_tasks::Runtime, ) -> eyre::Result<()> { info!(target: "reth::cli", "reth {} starting", version_metadata().short_version); info!(target: "reth::cli", "Unwinding OP proofs storage at: {:?}", self.storage_path); // Initialize the environment with read-only access - let Environment { provider_factory, .. } = self.env.init::(AccessRights::RO)?; + let Environment { provider_factory, .. } = self.env.init::(AccessRights::RO, runtime)?; // Create the proofs storage let storage: Arc = Arc::new( diff --git a/rust/op-reth/crates/consensus/src/validation/mod.rs b/rust/op-reth/crates/consensus/src/validation/mod.rs index 10861f5b9c0..08d06a7e56f 100644 --- a/rust/op-reth/crates/consensus/src/validation/mod.rs +++ b/rust/op-reth/crates/consensus/src/validation/mod.rs @@ -114,32 +114,22 @@ pub fn validate_block_post_execution( // operation as hashing that is required for state root got calculated in every // transaction This was replaced with is_success flag. // See more about EIP here: https://eips.ethereum.org/EIPS/eip-658 - if chain_spec.is_byzantium_active_at_block(header.number()) { - let result = if let Some((receipts_root, logs_bloom)) = receipt_root_bloom { - compare_receipts_root_and_logs_bloom( - receipts_root, - logs_bloom, - header.receipts_root(), - header.logs_bloom(), - ) - } else { - verify_receipts_optimism( - header.receipts_root(), - header.logs_bloom(), - receipts, - chain_spec, - header.timestamp(), - ) - }; - - if let Err(error) = result { - let receipts = receipts - .iter() - .map(|r| Bytes::from(r.with_bloom_ref().encoded_2718())) - .collect::>(); - tracing::debug!(%error, ?receipts, "receipts verification failed"); - return Err(error); - } + let _ = receipt_root_bloom; + if chain_spec.is_byzantium_active_at_block(header.number()) && + let Err(error) = verify_receipts_optimism( + header.receipts_root(), + header.logs_bloom(), + receipts, + chain_spec, + header.timestamp(), + ) + { + let receipts = receipts + .iter() + .map(|r| Bytes::from(r.with_bloom_ref().encoded_2718())) + .collect::>(); + tracing::debug!(%error, ?receipts, "receipts verification failed"); + return Err(error) } // Check if gas used matches the value set in header. diff --git a/rust/op-reth/crates/evm/Cargo.toml b/rust/op-reth/crates/evm/Cargo.toml index 61c892f2032..1f996c94884 100644 --- a/rust/op-reth/crates/evm/Cargo.toml +++ b/rust/op-reth/crates/evm/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] # Reth reth-chainspec.workspace = true -reth-evm = { workspace = true, features = ["op"] } +reth-evm.workspace = true reth-primitives-traits.workspace = true reth-execution-errors.workspace = true reth-execution-types.workspace = true diff --git a/rust/op-reth/crates/evm/src/lib.rs b/rust/op-reth/crates/evm/src/lib.rs index 516aaf64757..4654ee0947f 100644 --- a/rust/op-reth/crates/evm/src/lib.rs +++ b/rust/op-reth/crates/evm/src/lib.rs @@ -22,9 +22,7 @@ use core::fmt::Debug; use op_alloy_consensus::EIP1559ParamError; use op_revm::OpSpecId; use reth_chainspec::EthChainSpec; -use reth_evm::{ - ConfigureEvm, EvmEnv, TransactionEnv, eth::NextEvmEnvAttributes, precompiles::PrecompilesMap, -}; +use reth_evm::{ConfigureEvm, EvmEnv, eth::NextEvmEnvAttributes, precompiles::PrecompilesMap}; use reth_optimism_chainspec::OpChainSpec; use reth_optimism_forks::OpHardforks; use reth_optimism_primitives::{DepositReceipt, OpPrimitives}; @@ -143,7 +141,7 @@ where EvmF: EvmFactory< Tx: FromRecoveredTx + FromTxWithEncoded - + TransactionEnv + + alloy_evm::TransactionEnvMut + OpTxEnv, Precompiles = PrecompilesMap, Spec = OpSpecId, @@ -260,6 +258,7 @@ where basefee: payload.payload.as_v1().base_fee_per_gas.to(), // EIP-4844 excess blob gas of this block, introduced in Cancun blob_excess_gas_and_price, + slot_num: 0, }; Ok(EvmEnv { cfg_env, block_env }) diff --git a/rust/op-reth/crates/evm/src/tx.rs b/rust/op-reth/crates/evm/src/tx.rs index 00c2546be65..26bd3d881b7 100644 --- a/rust/op-reth/crates/evm/src/tx.rs +++ b/rust/op-reth/crates/evm/src/tx.rs @@ -1,251 +1,42 @@ -//! [`OpTx`] newtype wrapper around [`OpTransaction`]. +//! OP transaction environment types. -use alloy_consensus::{ - Signed, TxEip1559, TxEip2930, TxEip4844, TxEip4844Variant, TxEip7702, TxLegacy, -}; -use alloy_eips::{Encodable2718, Typed2718, eip7594::Encodable7594}; -use alloy_evm::{FromRecoveredTx, FromTxWithEncoded, IntoTxEnv}; -use alloy_op_evm::block::OpTxEnv; -use alloy_primitives::{Address, B256, Bytes, TxKind, U256}; -use core::ops::{Deref, DerefMut}; -use op_alloy_consensus::{OpTxEnvelope, TxDeposit}; -use op_revm::{OpTransaction, transaction::deposit::DepositTransactionParts}; -use reth_evm::TransactionEnv; -use revm::context::TxEnv; +pub use alloy_op_evm::OpTx; -/// Helper to convert a deposit transaction into a [`TxEnv`]. -fn deposit_tx_env(tx: &TxDeposit, caller: Address) -> TxEnv { - TxEnv { - tx_type: tx.ty(), - caller, - gas_limit: tx.gas_limit, - kind: tx.to, - value: tx.value, - data: tx.input.clone(), - ..Default::default() - } -} - -/// Newtype wrapper around [`OpTransaction`] that allows implementing foreign traits. -#[derive(Clone, Debug, Default)] -pub struct OpTx(pub OpTransaction); - -impl From for OpTransaction { - fn from(tx: OpTx) -> Self { - tx.0 - } -} - -impl Deref for OpTx { - type Target = OpTransaction; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for OpTx { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl IntoTxEnv for OpTx { - fn into_tx_env(self) -> Self { - self - } -} - -impl OpTxEnv for OpTx { - fn encoded_bytes(&self) -> Option<&Bytes> { - self.0.enveloped_tx.as_ref() - } -} +/// Converter that builds an [`OpTx`] from an +/// [`OpTransactionRequest`](op_alloy_rpc_types::OpTransactionRequest). +/// +/// Implements `TxEnvConverter` for use in `RpcConverter`, bypassing the orphan rule +/// issue with `TryIntoTxEnv` (neither `OpTransactionRequest` nor the trait is local). +#[derive(Debug, Clone, Copy, Default)] +pub struct OpTxEnvConverter; -impl revm::context::Transaction for OpTx { - type AccessListItem<'a> - = as revm::context::Transaction>::AccessListItem<'a> - where - Self: 'a; - type Authorization<'a> - = as revm::context::Transaction>::Authorization<'a> +#[cfg(feature = "rpc")] +mod rpc_impl { + use super::*; + use alloy_evm::rpc::{EthTxEnvError, TryIntoTxEnv}; + use op_alloy_rpc_types::OpTransactionRequest; + use reth_evm::ConfigureEvm; + use reth_rpc_eth_api::transaction::TxEnvConverter; + + impl TxEnvConverter for OpTxEnvConverter where - Self: 'a; - - fn tx_type(&self) -> u8 { - self.0.tx_type() - } - fn caller(&self) -> Address { - self.0.caller() - } - fn gas_limit(&self) -> u64 { - self.0.gas_limit() - } - fn value(&self) -> U256 { - self.0.value() - } - fn input(&self) -> &Bytes { - self.0.input() - } - fn nonce(&self) -> u64 { - revm::context::Transaction::nonce(&self.0) - } - fn kind(&self) -> TxKind { - self.0.kind() - } - fn chain_id(&self) -> Option { - self.0.chain_id() - } - fn gas_price(&self) -> u128 { - self.0.gas_price() - } - fn access_list(&self) -> Option>> { - self.0.access_list() - } - fn blob_versioned_hashes(&self) -> &[B256] { - self.0.blob_versioned_hashes() - } - fn max_fee_per_blob_gas(&self) -> u128 { - self.0.max_fee_per_blob_gas() - } - fn authorization_list_len(&self) -> usize { - self.0.authorization_list_len() - } - fn authorization_list(&self) -> impl Iterator> { - self.0.authorization_list() - } - fn max_priority_fee_per_gas(&self) -> Option { - self.0.max_priority_fee_per_gas() - } -} - -impl FromRecoveredTx for OpTx { - fn from_recovered_tx(tx: &OpTxEnvelope, sender: Address) -> Self { - let encoded = tx.encoded_2718(); - Self::from_encoded_tx(tx, sender, encoded.into()) - } -} - -impl FromTxWithEncoded for OpTx { - fn from_encoded_tx(tx: &OpTxEnvelope, caller: Address, encoded: Bytes) -> Self { - match tx { - OpTxEnvelope::Legacy(tx) => Self::from_encoded_tx(tx, caller, encoded), - OpTxEnvelope::Eip1559(tx) => Self::from_encoded_tx(tx, caller, encoded), - OpTxEnvelope::Eip2930(tx) => Self::from_encoded_tx(tx, caller, encoded), - OpTxEnvelope::Eip7702(tx) => Self::from_encoded_tx(tx, caller, encoded), - OpTxEnvelope::Deposit(tx) => Self::from_encoded_tx(tx.inner(), caller, encoded), + Evm: ConfigureEvm, + reth_evm::TxEnvFor: From, + { + type Error = EthTxEnvError; + + fn convert_tx_env( + &self, + req: OpTransactionRequest, + evm_env: &reth_evm::EvmEnvFor, + ) -> Result, Self::Error> { + let base: revm::context::TxEnv = req.as_ref().clone().try_into_tx_env(evm_env)?; + let op_tx = OpTx(op_revm::OpTransaction { + base, + enveloped_tx: Some(alloy_primitives::Bytes::new()), + deposit: Default::default(), + }); + Ok(op_tx.into()) } } } - -/// Generates [`FromRecoveredTx`] and [`FromTxWithEncoded`] impls for [`OpTx`] from a -/// `Signed<$tx>` and bare `$tx` type. The bare type conversion creates the [`TxEnv`] via -/// [`FromRecoveredTx`] and wraps it in an [`OpTransaction`]. -macro_rules! impl_from_tx { - ($($tx:ty),+ $(,)?) => { - $( - impl FromRecoveredTx> for OpTx { - fn from_recovered_tx(tx: &Signed<$tx>, sender: Address) -> Self { - let encoded = tx.encoded_2718(); - Self::from_encoded_tx(tx, sender, encoded.into()) - } - } - - impl FromTxWithEncoded> for OpTx { - fn from_encoded_tx(tx: &Signed<$tx>, caller: Address, encoded: Bytes) -> Self { - Self::from_encoded_tx(tx.tx(), caller, encoded) - } - } - - impl FromTxWithEncoded<$tx> for OpTx { - fn from_encoded_tx(tx: &$tx, caller: Address, encoded: Bytes) -> Self { - let base = TxEnv::from_recovered_tx(tx, caller); - Self(OpTransaction { - base, - enveloped_tx: Some(encoded), - deposit: Default::default(), - }) - } - } - )+ - }; -} - -impl_from_tx!(TxLegacy, TxEip2930, TxEip1559, TxEip4844, TxEip7702); - -/// `TxEip4844Variant` conversion is not necessary for `OpTx`, but it's useful -/// sugar for Foundry. -impl FromRecoveredTx>> for OpTx -where - T: Encodable7594 + Send + Sync, -{ - fn from_recovered_tx(tx: &Signed>, sender: Address) -> Self { - let encoded = tx.encoded_2718(); - Self::from_encoded_tx(tx, sender, encoded.into()) - } -} - -impl FromTxWithEncoded>> for OpTx { - fn from_encoded_tx(tx: &Signed>, caller: Address, encoded: Bytes) -> Self { - Self::from_encoded_tx(tx.tx(), caller, encoded) - } -} - -impl FromTxWithEncoded> for OpTx { - fn from_encoded_tx(tx: &TxEip4844Variant, caller: Address, encoded: Bytes) -> Self { - let base = TxEnv::from_recovered_tx(tx, caller); - Self(OpTransaction { base, enveloped_tx: Some(encoded), deposit: Default::default() }) - } -} - -impl FromRecoveredTx for OpTx { - fn from_recovered_tx(tx: &TxDeposit, sender: Address) -> Self { - let encoded = tx.encoded_2718(); - Self::from_encoded_tx(tx, sender, encoded.into()) - } -} - -impl FromTxWithEncoded for OpTx { - fn from_encoded_tx(tx: &TxDeposit, caller: Address, encoded: Bytes) -> Self { - let base = deposit_tx_env(tx, caller); - let deposit = DepositTransactionParts { - source_hash: tx.source_hash, - mint: Some(tx.mint), - is_system_transaction: tx.is_system_transaction, - }; - Self(OpTransaction { base, enveloped_tx: Some(encoded), deposit }) - } -} - -#[cfg(feature = "rpc")] -impl alloy_evm::rpc::TryIntoTxEnv - for op_alloy_rpc_types::OpTransactionRequest -{ - type Err = alloy_evm::rpc::EthTxEnvError; - - fn try_into_tx_env( - self, - evm_env: &alloy_evm::EvmEnv, - ) -> Result { - let inner: OpTransaction = self.try_into_tx_env(evm_env)?; - Ok(OpTx(inner)) - } -} - -impl TransactionEnv for OpTx { - fn set_gas_limit(&mut self, gas_limit: u64) { - self.0.base.gas_limit = gas_limit; - } - - fn nonce(&self) -> u64 { - self.0.base.nonce - } - - fn set_nonce(&mut self, nonce: u64) { - self.0.base.nonce = nonce; - } - - fn set_access_list(&mut self, access_list: alloy_eips::eip2930::AccessList) { - self.0.base.access_list = access_list; - } -} diff --git a/rust/op-reth/crates/exex/Cargo.toml b/rust/op-reth/crates/exex/Cargo.toml index 5a9a9b6d016..9ba9500eda0 100644 --- a/rust/op-reth/crates/exex/Cargo.toml +++ b/rust/op-reth/crates/exex/Cargo.toml @@ -35,7 +35,7 @@ tokio.workspace = true [dev-dependencies] futures.workspace = true -reth-db = { workspace = true, features = ["op", "test-utils"] } +reth-db = { workspace = true, features = ["test-utils"] } reth-node-builder.workspace = true reth-optimism-node.workspace = true reth-optimism-chainspec.workspace = true diff --git a/rust/op-reth/crates/flashblocks/src/consensus.rs b/rust/op-reth/crates/flashblocks/src/consensus.rs index 453d9bffa04..61172dfbc33 100644 --- a/rust/op-reth/crates/flashblocks/src/consensus.rs +++ b/rust/op-reth/crates/flashblocks/src/consensus.rs @@ -4,7 +4,7 @@ use alloy_rpc_types_engine::PayloadStatusEnum; use op_alloy_rpc_types_engine::OpExecutionData; use reth_engine_primitives::ConsensusEngineHandle; use reth_optimism_payload_builder::OpPayloadTypes; -use reth_payload_primitives::{EngineApiMessageVersion, ExecutionPayload, PayloadTypes}; +use reth_payload_primitives::{ExecutionPayload, PayloadTypes}; use tracing::*; /// Consensus client that sends FCUs and new payloads using blocks from a [`FlashBlockService`]. @@ -104,11 +104,7 @@ where finalized_block_hash: finalized_hash, }; - match self - .engine_handle - .fork_choice_updated(fcu_state, None, EngineApiMessageVersion::V5) - .await - { + match self.engine_handle.fork_choice_updated(fcu_state, None).await { Ok(result) => { debug!( target: "flashblocks", @@ -180,6 +176,14 @@ impl TryFrom<&FlashBlockCompleteSequence> for OpExecutionData { } } +impl TryFrom<&FlashBlockCompleteSequence> for reth_optimism_payload_builder::OpExecData { + type Error = &'static str; + + fn try_from(sequence: &FlashBlockCompleteSequence) -> Result { + OpExecutionData::try_from(sequence).map(Into::into) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/rust/op-reth/crates/flashblocks/src/worker.rs b/rust/op-reth/crates/flashblocks/src/worker.rs index af9658ab978..192c8ea016c 100644 --- a/rust/op-reth/crates/flashblocks/src/worker.rs +++ b/rust/op-reth/crates/flashblocks/src/worker.rs @@ -311,9 +311,6 @@ where .context_for_next_block(parent_header, attrs) .map_err(RethError::other)?; - // The cached bundle prestate already includes pre-execution state changes. - // Only set the state clear flag (Spurious Dragon empty-account handling). - state.set_state_clear_flag(true); let evm = self.evm_config.evm_with_env(&mut state, evm_env); let mut executor = self.evm_config.create_executor(evm, execution_ctx.clone()); @@ -379,9 +376,9 @@ where let BlockBuilderOutcome { execution_result, block, hashed_state, .. } = if args.compute_state_root { trace!(target: "flashblocks", "Computing block state root"); - builder.finish(&state_provider)? + builder.finish(&state_provider, None)? } else { - builder.finish(NoopProvider::default())? + builder.finish(NoopProvider::default(), None)? }; let bundle = state.take_bundle(); diff --git a/rust/op-reth/crates/node/Cargo.toml b/rust/op-reth/crates/node/Cargo.toml index 9b06f8d1456..92df4eaf961 100644 --- a/rust/op-reth/crates/node/Cargo.toml +++ b/rust/op-reth/crates/node/Cargo.toml @@ -29,10 +29,10 @@ reth-tasks.workspace = true reth-trie-common.workspace = true reth-node-core.workspace = true reth-rpc-engine-api.workspace = true -reth-engine-local = { workspace = true, features = ["op"] } + reth-rpc-api.workspace = true -reth-db = { workspace = true, features = ["op"] } -reth-db-api = { workspace = true, features = ["op"] } +reth-db.workspace = true +reth-db-api.workspace = true # op-reth reth-optimism-payload-builder.workspace = true @@ -88,7 +88,7 @@ serde_json = { workspace = true, optional = true } [dev-dependencies] reth-optimism-node = { workspace = true, features = ["test-utils"] } -reth-db = { workspace = true, features = ["op", "test-utils"] } +reth-db = { workspace = true, features = ["test-utils"] } reth-node-builder = { workspace = true, features = ["test-utils"] } reth-provider = { workspace = true, features = ["test-utils"] } reth-tasks.workspace = true diff --git a/rust/op-reth/crates/node/src/engine.rs b/rust/op-reth/crates/node/src/engine.rs index 217cb953e68..84b85580d02 100644 --- a/rust/op-reth/crates/node/src/engine.rs +++ b/rust/op-reth/crates/node/src/engine.rs @@ -1,10 +1,7 @@ use alloy_consensus::BlockHeader; use alloy_primitives::B256; use alloy_rpc_types_engine::{ExecutionPayloadEnvelopeV2, ExecutionPayloadV1}; -use op_alloy_rpc_types_engine::{ - OpExecutionData, OpExecutionPayloadEnvelopeV3, OpExecutionPayloadEnvelopeV4, - OpPayloadAttributes, -}; +use op_alloy_rpc_types_engine::{OpExecutionPayloadEnvelopeV3, OpExecutionPayloadEnvelopeV4}; use reth_consensus::ConsensusError; use reth_node_api::{ BuiltPayload, EngineApiValidator, EngineTypes, NodePrimitives, PayloadValidator, @@ -17,7 +14,9 @@ use reth_node_api::{ }; use reth_optimism_consensus::isthmus; use reth_optimism_forks::OpHardforks; -use reth_optimism_payload_builder::{OpExecutionPayloadValidator, OpPayloadTypes}; +use reth_optimism_payload_builder::{ + OpExecData, OpExecutionPayloadValidator, OpPayloadAttrs, OpPayloadTypes, +}; use reth_optimism_primitives::{L2_TO_L1_MESSAGE_PASSER_ADDRESS, OpBlock}; use reth_primitives_traits::{Block, RecoveredBlock, SealedBlock, SignedTransaction}; use reth_provider::StateProviderFactory; @@ -31,25 +30,24 @@ pub struct OpEngineTypes { _marker: PhantomData, } -impl> PayloadTypes for OpEngineTypes { +impl> PayloadTypes for OpEngineTypes { type ExecutionData = T::ExecutionData; type BuiltPayload = T::BuiltPayload; type PayloadAttributes = T::PayloadAttributes; - type PayloadBuilderAttributes = T::PayloadBuilderAttributes; fn block_to_payload( block: SealedBlock< <::Primitives as NodePrimitives>::Block, >, ) -> ::ExecutionData { - OpExecutionData::from_block_unchecked( + OpExecData::from(op_alloy_rpc_types_engine::OpExecutionData::from_block_unchecked( block.hash(), &block.into_block().into_ethereum_block(), - ) + )) } } -impl> EngineTypes for OpEngineTypes +impl> EngineTypes for OpEngineTypes where T::BuiltPayload: BuiltPayload> + TryInto @@ -118,7 +116,7 @@ where P: StateProviderFactory + Unpin + 'static, Tx: SignedTransaction + Unpin + 'static, ChainSpec: OpHardforks + Send + Sync + 'static, - Types: PayloadTypes, + Types: PayloadTypes, { type Block = alloy_consensus::Block; @@ -154,17 +152,17 @@ where fn convert_payload_to_block( &self, - payload: OpExecutionData, + payload: OpExecData, ) -> Result, NewPayloadError> { - self.inner.ensure_well_formed_payload(payload).map_err(NewPayloadError::other) + self.inner.ensure_well_formed_payload(payload.0).map_err(NewPayloadError::other) } } impl EngineApiValidator for OpEngineValidator where Types: PayloadTypes< - PayloadAttributes = OpPayloadAttributes, - ExecutionData = OpExecutionData, + PayloadAttributes = OpPayloadAttrs, + ExecutionData = OpExecData, BuiltPayload: BuiltPayload>, >, P: StateProviderFactory + Unpin + 'static, @@ -204,9 +202,7 @@ where validate_version_specific_fields( self.chain_spec(), version, - PayloadOrAttributes::::PayloadAttributes( - attributes, - ), + PayloadOrAttributes::::PayloadAttributes(attributes), )?; if attributes.gas_limit.is_none() { @@ -307,6 +303,7 @@ mod test { use alloy_op_hardforks::BASE_SEPOLIA_JOVIAN_TIMESTAMP; use alloy_primitives::{Address, B64, B256, b64}; use alloy_rpc_types_engine::PayloadAttributes; + use op_alloy_rpc_types_engine::OpPayloadAttributes; use reth_optimism_chainspec::BASE_SEPOLIA; use reth_provider::noop::NoopProvider; use reth_trie_common::KeccakKeyHasher; @@ -323,12 +320,12 @@ mod test { }}; } - const fn get_attributes( + fn get_attributes( eip_1559_params: Option, min_base_fee: Option, timestamp: u64, - ) -> OpPayloadAttributes { - OpPayloadAttributes { + ) -> OpPayloadAttrs { + OpPayloadAttrs(OpPayloadAttributes { gas_limit: Some(1000), eip_1559_params, min_base_fee, @@ -341,7 +338,7 @@ mod test { withdrawals: Some(vec![]), parent_beacon_block_root: Some(B256::ZERO), }, - } + }) } #[test] diff --git a/rust/op-reth/crates/node/src/node.rs b/rust/op-reth/crates/node/src/node.rs index 1f1fb1477d5..94d23f80f17 100644 --- a/rust/op-reth/crates/node/src/node.rs +++ b/rust/op-reth/crates/node/src/node.rs @@ -7,9 +7,9 @@ use crate::{ txpool::{OpTransactionPool, OpTransactionValidator}, }; use op_alloy_consensus::{OpPooledTransaction, interop::SafetyLevel}; -use op_alloy_rpc_types_engine::OpExecutionData; -use reth_chainspec::{ChainSpecProvider, EthChainSpec, ForkCondition, Hardforks}; -use reth_engine_local::LocalPayloadAttributesBuilder; +use reth_chainspec::{ + BaseFeeParams, ChainSpecProvider, EthChainSpec, EthereumHardforks, ForkCondition, Hardforks, +}; use reth_evm::ConfigureEvm; use reth_network::{ NetworkConfig, NetworkHandle, NetworkManager, NetworkPrimitives, PeersInfo, @@ -38,7 +38,7 @@ use reth_optimism_consensus::OpBeaconConsensus; use reth_optimism_evm::{OpEvmConfig, OpRethReceiptBuilder}; use reth_optimism_forks::OpHardforks; use reth_optimism_payload_builder::{ - OpAttributes, OpBuiltPayload, OpPayloadPrimitives, + OpBuiltPayload, OpExecData, OpPayloadBuilderAttributes, OpPayloadPrimitives, builder::OpPayloadTransactions, config::{OpBuilderConfig, OpDAConfig, OpGasLimitConfig}, }; @@ -61,10 +61,75 @@ use reth_transaction_pool::{ TransactionValidationTaskExecutor, blobstore::DiskFileBlobStore, }; use reth_trie_common::KeccakKeyHasher; -use serde::de::DeserializeOwned; use std::{marker::PhantomData, sync::Arc}; use url::Url; +use reth_optimism_payload_builder::OpPayloadAttrs; + +/// Builds [`OpPayloadAttrs`] for local/dev-mode payload generation. +struct OpLocalPayloadAttributesBuilder { + chain_spec: Arc, +} + +impl PayloadAttributesBuilder for OpLocalPayloadAttributesBuilder { + fn build( + &self, + parent: &reth_primitives_traits::SealedHeader, + ) -> OpPayloadAttrs { + use alloy_consensus::BlockHeader; + use alloy_primitives::{Address, B64}; + + let timestamp = std::cmp::max( + parent.timestamp().saturating_add(1), + std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(), + ); + + let eth_attrs = alloy_rpc_types_engine::PayloadAttributes { + timestamp, + prev_randao: alloy_primitives::B256::random(), + suggested_fee_recipient: Address::random(), + withdrawals: self + .chain_spec + .is_shanghai_active_at_timestamp(timestamp) + .then(Default::default), + parent_beacon_block_root: self + .chain_spec + .is_cancun_active_at_timestamp(timestamp) + .then(alloy_primitives::B256::random), + }; + + /// Dummy system transaction for dev mode. + /// OP Mainnet transaction at index 0 in block 124665056. + const TX_SET_L1_BLOCK: [u8; 251] = alloy_primitives::hex!( + "7ef8f8a0683079df94aa5b9cf86687d739a60a9b4f0835e520ec4d664e2e415dca17a6df94deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e200000146b000f79c500000000000000040000000066d052e700000000013ad8a3000000000000000000000000000000000000000000000000000000003ef1278700000000000000000000000000000000000000000000000000000000000000012fdf87b89884a61e74b322bbcf60386f543bfae7827725efaaf0ab1de2294a590000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f32985" + ); + + let default_params = BaseFeeParams::optimism(); + let denominator = std::env::var("OP_DEV_EIP1559_DENOMINATOR") + .ok() + .and_then(|v| v.parse::().ok()) + .unwrap_or(default_params.max_change_denominator as u32); + let elasticity = std::env::var("OP_DEV_EIP1559_ELASTICITY") + .ok() + .and_then(|v| v.parse::().ok()) + .unwrap_or(default_params.elasticity_multiplier as u32); + let gas_limit = std::env::var("OP_DEV_GAS_LIMIT").ok().and_then(|v| v.parse::().ok()); + + let mut eip1559_bytes = [0u8; 8]; + eip1559_bytes[0..4].copy_from_slice(&denominator.to_be_bytes()); + eip1559_bytes[4..8].copy_from_slice(&elasticity.to_be_bytes()); + + OpPayloadAttrs(op_alloy_rpc_types_engine::OpPayloadAttributes { + payload_attributes: eth_attrs, + transactions: Some(vec![TX_SET_L1_BLOCK.into()]), + no_tx_pool: None, + gas_limit, + eip_1559_params: Some(B64::from(eip1559_bytes)), + min_base_fee: Some(0), + }) + } +} + /// Marker trait for Optimism node types with standard engine, chain spec, and primitives. pub trait OpNodeTypes: NodeTypes @@ -87,7 +152,7 @@ pub trait OpFullNodeTypes: ChainSpec: OpHardforks, Primitives: OpPayloadPrimitives, Storage = OpStorage, - Payload: EngineTypes, + Payload: EngineTypes, > { } @@ -97,7 +162,7 @@ impl OpFullNodeTypes for N where ChainSpec: OpHardforks, Primitives: OpPayloadPrimitives, Storage = OpStorage, - Payload: EngineTypes, + Payload: EngineTypes, > { } @@ -277,7 +342,7 @@ where fn local_payload_attributes_builder( chain_spec: &Self::ChainSpec, ) -> impl PayloadAttributesBuilder<::PayloadAttributes> { - LocalPayloadAttributesBuilder::new(Arc::new(chain_spec.clone())) + OpLocalPayloadAttributesBuilder { chain_spec: Arc::new(chain_spec.clone()) } } } @@ -441,6 +506,34 @@ where ) } + /// Maps the [`EngineValidatorBuilder`] builder type. + pub fn with_engine_validator( + self, + engine_validator_builder: T, + ) -> OpAddOns { + let Self { + rpc_add_ons, + da_config, + gas_limit_config, + sequencer_url, + sequencer_headers, + enable_tx_conditional, + min_suggested_priority_fee, + historical_rpc, + .. + } = self; + OpAddOns::new( + rpc_add_ons.with_engine_validator(engine_validator_builder), + da_config, + gas_limit_config, + sequencer_url, + sequencer_headers, + historical_rpc, + enable_tx_conditional, + min_suggested_priority_fee, + ) + } + /// Sets the RPC middleware stack for processing RPC requests. /// /// This method configures a custom middleware stack that will be applied to all RPC requests @@ -493,18 +586,14 @@ where } } -impl NodeAddOns +impl NodeAddOns for OpAddOns where N: FullNodeComponents< - Types: NodeTypes< - ChainSpec: OpHardforks, - Primitives: OpPayloadPrimitives, - Payload: PayloadTypes, - >, + Types: NodeTypes, Evm: ConfigureEvm< NextBlockEnvCtx: BuildNextEnv< - Attrs, + OpPayloadBuilderAttributes>, HeaderTy, ::ChainSpec, >, @@ -516,7 +605,6 @@ where EB: EngineApiBuilder, EVB: EngineValidatorBuilder, RpcMiddleware: RethRpcMiddleware, - Attrs: OpAttributes, RpcPayloadAttributes: DeserializeOwned>, { type Handle = RpcHandle; @@ -563,11 +651,12 @@ where ctx.node.evm_config().clone(), ); // install additional OP specific rpc methods - let debug_ext = OpDebugWitnessApi::<_, _, _, Attrs>::new( - ctx.node.provider().clone(), - Box::new(ctx.node.task_executor().clone()), - builder, - ); + let debug_ext = + OpDebugWitnessApi::<_, _, _, OpPayloadBuilderAttributes>>::new( + ctx.node.provider().clone(), + ctx.node.task_executor().clone(), + builder, + ); let miner_ext = OpMinerExtApi::new(da_config, gas_limit_config); let sequencer_client = if let Some(url) = sequencer_url { @@ -622,18 +711,14 @@ where } } -impl RethRpcAddOns +impl RethRpcAddOns for OpAddOns where N: FullNodeComponents< - Types: NodeTypes< - ChainSpec: OpHardforks, - Primitives: OpPayloadPrimitives, - Payload: PayloadTypes, - >, + Types: NodeTypes, Evm: ConfigureEvm< NextBlockEnvCtx: BuildNextEnv< - Attrs, + OpPayloadBuilderAttributes>, HeaderTy, ::ChainSpec, >, @@ -645,7 +730,6 @@ where EB: EngineApiBuilder, EVB: EngineValidatorBuilder, RpcMiddleware: RethRpcMiddleware, - Attrs: OpAttributes, RpcPayloadAttributes: DeserializeOwned>, { type EthApi = EthB::EthApi; @@ -1130,7 +1214,7 @@ impl OpPayloadBuilder { } } -impl PayloadBuilderBuilder for OpPayloadBuilder +impl PayloadBuilderBuilder for OpPayloadBuilder where Node: FullNodeTypes< Provider: ChainSpecProvider, @@ -1138,24 +1222,28 @@ where Primitives: OpPayloadPrimitives, Payload: PayloadTypes< BuiltPayload = OpBuiltPayload>, - PayloadBuilderAttributes = Attrs, + PayloadAttributes = OpPayloadAttrs, >, >, >, Evm: ConfigureEvm< Primitives = PrimitivesTy, NextBlockEnvCtx: BuildNextEnv< - Attrs, + OpPayloadBuilderAttributes>, HeaderTy, ::ChainSpec, >, > + 'static, Pool: TransactionPool>> + Unpin + 'static, Txs: OpPayloadTransactions, - Attrs: OpAttributes>, { - type PayloadBuilder = - reth_optimism_payload_builder::OpPayloadBuilder; + type PayloadBuilder = reth_optimism_payload_builder::OpPayloadBuilder< + Pool, + Node::Provider, + Evm, + Txs, + OpPayloadBuilderAttributes>, + >; async fn build_payload_builder( self, @@ -1303,10 +1391,7 @@ pub struct OpEngineValidatorBuilder; impl PayloadValidatorBuilder for OpEngineValidatorBuilder where Node: FullNodeComponents< - Types: NodeTypes< - ChainSpec: OpHardforks, - Payload: PayloadTypes, - >, + Types: NodeTypes>, >, { type Validator = OpEngineValidator< diff --git a/rust/op-reth/crates/node/src/proof_history.rs b/rust/op-reth/crates/node/src/proof_history.rs index 21a0265f366..404b938bc1b 100644 --- a/rust/op-reth/crates/node/src/proof_history.rs +++ b/rust/op-reth/crates/node/src/proof_history.rs @@ -76,7 +76,7 @@ pub async fn launch_node_with_proof_history( ctx.node().provider().clone(), ctx.registry.eth_api().clone(), storage, - Box::new(ctx.node().task_executor().clone()), + ctx.node().task_executor().clone(), ctx.node().evm_config().clone(), ); let eth_replaced = ctx.modules.replace_configured(api_ext.into_rpc())?; diff --git a/rust/op-reth/crates/node/src/rpc.rs b/rust/op-reth/crates/node/src/rpc.rs index 9c959a38da5..e766d6c3f6a 100644 --- a/rust/op-reth/crates/node/src/rpc.rs +++ b/rust/op-reth/crates/node/src/rpc.rs @@ -5,7 +5,7 @@ //! Builds offline `TraceApi` with only EVM and database. This can be useful //! for example when downloading a state snapshot (pre-synced node) from some mirror. //! -//! ```rust +//! ```rust,no_run //! use alloy_rpc_types_eth::BlockId; //! use op_alloy_network::Optimism; //! use reth_db::test_utils::create_test_rw_db_with_path; @@ -23,7 +23,7 @@ //! use reth_provider::providers::BlockchainProvider; //! use reth_rpc::TraceApi; //! use reth_rpc_eth_types::{EthConfig, EthStateCache}; -//! use reth_tasks::{Runtime, pool::BlockingTaskGuard}; +//! use reth_tasks::{RuntimeBuilder, pool::BlockingTaskGuard}; //! use reth_trie_db::ChangesetCache; //! use std::sync::Arc; //! @@ -32,13 +32,14 @@ //! // build core node with all components disabled except EVM and state //! let sepolia = NodeConfig::new(OP_SEPOLIA.clone()); //! let db = create_test_rw_db_with_path(sepolia.datadir()); -//! let runtime = Runtime::with_existing_handle(tokio::runtime::Handle::current()).unwrap(); +//! let runtime = +//! RuntimeBuilder::new(Default::default()).build().expect("failed to build runtime"); //! let launch_ctx = LaunchContext::new(runtime, sepolia.datadir()); //! let node = launch_ctx //! .with_loaded_toml_config(sepolia) //! .unwrap() //! .attach(Arc::new(db)) -//! .with_provider_factory::<_, OpEvmConfig>(ChangesetCache::new()) +//! .with_provider_factory::<_, OpEvmConfig>(ChangesetCache::new(), None) //! .await //! .unwrap() //! .with_genesis() @@ -90,13 +91,13 @@ pub use reth_optimism_rpc::{OpEngineApi, OpEthApi, OpEthApiBuilder}; use crate::OP_NAME_CLIENT; use alloy_rpc_types_engine::ClientVersionV1; -use op_alloy_rpc_types_engine::OpExecutionData; use reth_chainspec::EthereumHardforks; use reth_node_api::{ AddOnsContext, EngineApiValidator, EngineTypes, FullNodeComponents, NodeTypes, }; use reth_node_builder::rpc::{EngineApiBuilder, PayloadValidatorBuilder}; use reth_node_core::version::{CLIENT_CODE, version_metadata}; +use reth_optimism_payload_builder::OpExecData; use reth_optimism_rpc::engine::OP_ENGINE_CAPABILITIES; use reth_payload_builder::PayloadStore; use reth_rpc_engine_api::{EngineApi, EngineCapabilities}; @@ -112,7 +113,7 @@ where N: FullNodeComponents< Types: NodeTypes< ChainSpec: EthereumHardforks, - Payload: EngineTypes, + Payload: EngineTypes, >, >, EV: PayloadValidatorBuilder, @@ -142,7 +143,7 @@ where ctx.beacon_engine_handle.clone(), PayloadStore::new(ctx.node.payload_builder_handle().clone()), ctx.node.pool().clone(), - Box::new(ctx.node.task_executor().clone()), + ctx.node.task_executor().clone(), client, EngineCapabilities::new(OP_ENGINE_CAPABILITIES.iter().copied()), engine_validator, diff --git a/rust/op-reth/crates/node/src/utils.rs b/rust/op-reth/crates/node/src/utils.rs index 435ec2b9250..8b0ae3a44e2 100644 --- a/rust/op-reth/crates/node/src/utils.rs +++ b/rust/op-reth/crates/node/src/utils.rs @@ -1,13 +1,13 @@ -use crate::{OpBuiltPayload, OpNode as OtherOpNode, OpPayloadBuilderAttributes}; +use crate::{OpBuiltPayload, OpNode as OtherOpNode}; use alloy_genesis::Genesis; use alloy_primitives::{Address, B256}; -use alloy_rpc_types_engine::PayloadAttributes; +use op_alloy_rpc_types_engine::OpPayloadAttributes; use reth_e2e_test_utils::{ NodeHelperType, TmpDB, transaction::TransactionTestContext, wallet::Wallet, }; use reth_node_api::NodeTypesWithDBAdapter; use reth_optimism_chainspec::OpChainSpecBuilder; -use reth_payload_builder::EthPayloadBuilderAttributes; +use reth_optimism_payload_builder::OpPayloadAttrs; use reth_provider::providers::BlockchainProvider; use std::sync::Arc; use tokio::sync::Mutex; @@ -53,21 +53,19 @@ pub async fn advance_chain( } /// Helper function to create a new eth payload attributes -pub fn optimism_payload_attributes(timestamp: u64) -> OpPayloadBuilderAttributes { - let attributes = PayloadAttributes { - timestamp, - prev_randao: B256::ZERO, - suggested_fee_recipient: Address::ZERO, - withdrawals: Some(vec![]), - parent_beacon_block_root: Some(B256::ZERO), - }; - - OpPayloadBuilderAttributes { - payload_attributes: EthPayloadBuilderAttributes::new(B256::ZERO, attributes), - transactions: vec![], - no_tx_pool: false, +pub const fn optimism_payload_attributes(timestamp: u64) -> OpPayloadAttrs { + OpPayloadAttrs(OpPayloadAttributes { + payload_attributes: alloy_rpc_types_engine::PayloadAttributes { + timestamp, + prev_randao: B256::ZERO, + suggested_fee_recipient: Address::ZERO, + withdrawals: Some(vec![]), + parent_beacon_block_root: Some(B256::ZERO), + }, + transactions: None, + no_tx_pool: None, gas_limit: Some(30_000_000), eip_1559_params: None, min_base_fee: None, - } + }) } diff --git a/rust/op-reth/crates/node/tests/e2e-testsuite/testsuite.rs b/rust/op-reth/crates/node/tests/e2e-testsuite/testsuite.rs index a95034778cd..9837d9afc14 100644 --- a/rust/op-reth/crates/node/tests/e2e-testsuite/testsuite.rs +++ b/rust/op-reth/crates/node/tests/e2e-testsuite/testsuite.rs @@ -7,7 +7,7 @@ use reth_e2e_test_utils::testsuite::{ setup::{NetworkSetup, Setup}, }; use reth_optimism_chainspec::{OP_MAINNET, OpChainSpecBuilder}; -use reth_optimism_node::{OpEngineTypes, OpNode}; +use reth_optimism_node::{OpEngineTypes, OpNode, payload::OpPayloadAttrs}; use std::sync::Arc; #[tokio::test] @@ -30,7 +30,7 @@ async fn test_testsuite_op_assert_mine_block() -> Result<()> { vec![], Some(B256::ZERO), // TODO: refactor once we have actions to generate payload attributes. - OpPayloadAttributes { + OpPayloadAttrs(OpPayloadAttributes { payload_attributes: alloy_rpc_types_engine::PayloadAttributes { timestamp: std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) @@ -46,7 +46,7 @@ async fn test_testsuite_op_assert_mine_block() -> Result<()> { eip_1559_params: None, min_base_fee: None, gas_limit: Some(30_000_000), - }, + }), )); test.run::().await?; @@ -75,7 +75,7 @@ async fn test_testsuite_op_assert_mine_block_isthmus_activated() -> Result<()> { vec![], Some(B256::ZERO), // TODO: refactor once we have actions to generate payload attributes. - OpPayloadAttributes { + OpPayloadAttrs(OpPayloadAttributes { payload_attributes: alloy_rpc_types_engine::PayloadAttributes { timestamp: std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) @@ -91,7 +91,7 @@ async fn test_testsuite_op_assert_mine_block_isthmus_activated() -> Result<()> { eip_1559_params: Some(B64::ZERO), min_base_fee: None, gas_limit: Some(30_000_000), - }, + }), )); test.run::().await?; diff --git a/rust/op-reth/crates/node/tests/it/custom_genesis.rs b/rust/op-reth/crates/node/tests/it/custom_genesis.rs index 7aa9ee695a0..d6317eac853 100644 --- a/rust/op-reth/crates/node/tests/it/custom_genesis.rs +++ b/rust/op-reth/crates/node/tests/it/custom_genesis.rs @@ -1,6 +1,6 @@ //! Tests for custom genesis block number support. -use alloy_consensus::BlockHeader; +use alloy_consensus::{BlockHeader, Sealable}; use alloy_genesis::Genesis; use alloy_primitives::B256; use reth_chainspec::EthChainSpec; @@ -88,8 +88,13 @@ async fn test_op_node_custom_genesis_number() { assert!(header.is_none(), "Block {block_num} before genesis should not exist"); } - // Advance the chain with a single block - let _ = wallet; // wallet available for future use + // Initialize the forkchoice state with the genesis block hash so that + // `current_forkchoice_state()` can resolve the latest header. With storage_v2, + // the canonical chain tip must be explicitly set via a forkchoice update. + let genesis_hash = genesis_header.unwrap().seal_slow().hash(); + node.update_forkchoice(genesis_hash, genesis_hash).await.unwrap(); + + // Advance the chain with a single block. let block_payloads = node .advance(1, |_| { Box::pin({ @@ -117,6 +122,6 @@ async fn test_op_node_custom_genesis_number() { assert_eq!( block.number(), 1001, - "Block number should be 1001 after advancing from genesis 100" + "Block number should be 1001 after advancing from genesis 1000" ); } diff --git a/rust/op-reth/crates/payload/Cargo.toml b/rust/op-reth/crates/payload/Cargo.toml index 93a2553744b..3c40b3bd7ba 100644 --- a/rust/op-reth/crates/payload/Cargo.toml +++ b/rust/op-reth/crates/payload/Cargo.toml @@ -20,21 +20,21 @@ reth-transaction-pool.workspace = true reth-storage-api.workspace = true reth-evm.workspace = true reth-execution-types.workspace = true -reth-payload-builder.workspace = true reth-payload-builder-primitives.workspace = true reth-payload-util.workspace = true -reth-payload-primitives = { workspace = true, features = ["op"] } +reth-payload-primitives.workspace = true reth-basic-payload-builder.workspace = true reth-payload-validator.workspace = true # op-reth reth-optimism-evm.workspace = true reth-optimism-forks.workspace = true -reth-optimism-primitives.workspace = true +reth-optimism-primitives = { workspace = true, features = ["reth-codec"] } reth-optimism-txpool.workspace = true # ethereum revm.workspace = true +op-revm.workspace = true alloy-eips.workspace = true alloy-primitives.workspace = true alloy-rlp.workspace = true diff --git a/rust/op-reth/crates/payload/src/builder.rs b/rust/op-reth/crates/payload/src/builder.rs index 2477a8bf9a9..3183cc6a734 100644 --- a/rust/op-reth/crates/payload/src/builder.rs +++ b/rust/op-reth/crates/payload/src/builder.rs @@ -8,6 +8,7 @@ use alloy_evm::Evm as AlloyEvm; use alloy_primitives::{B256, U256}; use alloy_rpc_types_debug::ExecutionWitness; use alloy_rpc_types_engine::PayloadId; +use op_revm::{L1BlockInfo, constants::L1_BLOCK_CONTRACT}; use reth_basic_payload_builder::*; use reth_chainspec::{ChainSpecProvider, EthChainSpec}; use reth_evm::{ @@ -16,7 +17,6 @@ use reth_evm::{ execute::{ BlockBuilder, BlockBuilderOutcome, BlockExecutionError, BlockExecutor, BlockValidationError, }, - op_revm::{L1BlockInfo, constants::L1_BLOCK_CONTRACT}, }; use reth_execution_types::BlockExecutionOutput; use reth_optimism_forks::OpHardforks; @@ -27,7 +27,7 @@ use reth_optimism_txpool::{ interop::{MaybeInteropTransaction, is_valid_interop}, }; use reth_payload_builder_primitives::PayloadBuilderError; -use reth_payload_primitives::{BuildNextEnv, BuiltPayloadExecutedBlock, PayloadBuilderAttributes}; +use reth_payload_primitives::{BuildNextEnv, BuiltPayloadExecutedBlock}; use reth_payload_util::{BestPayloadTransactions, NoopPayloadTransactions, PayloadTransactions}; use reth_primitives_traits::{ HeaderTy, NodePrimitives, SealedHeader, SealedHeaderFor, SignedTransaction, TxTy, @@ -179,7 +179,7 @@ where Txs: PayloadTransactions + OpPooledTx>, { - let BuildArguments { mut cached_reads, config, cancel, best_payload } = args; + let BuildArguments { mut cached_reads, config, cancel, best_payload, .. } = args; let ctx = OpPayloadBuilderCtx { evm_config: self.evm_config.clone(), @@ -209,14 +209,11 @@ where &self, parent: SealedHeader, attributes: Attrs::RpcPayloadAttributes, - ) -> Result - where - Attrs: PayloadBuilderAttributes, - { - let attributes = - Attrs::try_new(parent.hash(), attributes, 3).map_err(PayloadBuilderError::other)?; + ) -> Result { + let attributes = Attrs::try_new(parent.hash(), attributes, 3)?; + let payload_id = attributes.payload_id(); - let config = PayloadConfig { parent_header: Arc::new(parent), attributes }; + let config = PayloadConfig { parent_header: Arc::new(parent), attributes, payload_id }; let ctx = OpPayloadBuilderCtx { evm_config: self.evm_config.clone(), builder_config: self.config.clone(), @@ -234,20 +231,26 @@ where } /// Implementation of the [`PayloadBuilder`] trait for [`OpPayloadBuilder`]. -impl PayloadBuilder - for OpPayloadBuilder +/// +/// This impl uses [`crate::payload::OpPayloadAttrs`] (the RPC payload attributes wrapper) as the +/// `Attributes` type, converting to [`OpPayloadBuilderAttributes`] internally for building. +impl PayloadBuilder + for OpPayloadBuilder> where N: OpPayloadPrimitives, Client: StateProviderFactory + ChainSpecProvider + Clone, Pool: TransactionPool>, Evm: ConfigureEvm< Primitives = N, - NextBlockEnvCtx: BuildNextEnv, + NextBlockEnvCtx: BuildNextEnv< + OpPayloadBuilderAttributes, + N::BlockHeader, + Client::ChainSpec, + >, >, Txs: OpPayloadTransactions, - Attrs: OpAttributes, { - type Attributes = Attrs; + type Attributes = crate::payload::OpPayloadAttrs; type BuiltPayload = OpBuiltPayload; fn try_build( @@ -255,7 +258,10 @@ where args: BuildArguments, ) -> Result, PayloadBuilderError> { let pool = self.pool.clone(); - self.build_payload(args, |attrs| self.best_transactions.best_transactions(pool, attrs)) + let converted_args = convert_build_args::(args)?; + self.build_payload(converted_args, |attrs| { + self.best_transactions.best_transactions(pool, attrs) + }) } fn on_missing_payload( @@ -276,15 +282,49 @@ where let args = BuildArguments { config, cached_reads: Default::default(), + execution_cache: None, + trie_handle: None, cancel: Default::default(), best_payload: None, }; - self.build_payload(args, |_| NoopPayloadTransactions::::default())? - .into_payload() - .ok_or_else(|| PayloadBuilderError::MissingPayload) + let converted_args = convert_build_args::(args)?; + self.build_payload(converted_args, |_| { + NoopPayloadTransactions::::default() + })? + .into_payload() + .ok_or_else(|| PayloadBuilderError::MissingPayload) } } +/// Converts `BuildArguments` from [`OpPayloadAttrs`](crate::payload::OpPayloadAttrs) to +/// [`OpPayloadBuilderAttributes`], decoding the RPC transaction bytes into typed transactions. +fn convert_build_args( + args: BuildArguments>, +) -> Result< + BuildArguments, OpBuiltPayload>, + PayloadBuilderError, +> { + let BuildArguments { config, cached_reads, execution_cache, trie_handle, cancel, best_payload } = + args; + let parent_hash = config.parent_header.hash(); + let payload_id = config.payload_id; + let builder_attrs = + OpPayloadBuilderAttributes::from_rpc_attrs(parent_hash, payload_id, config.attributes.0) + .map_err(PayloadBuilderError::other)?; + Ok(BuildArguments { + config: PayloadConfig { + parent_header: config.parent_header, + attributes: builder_attrs, + payload_id, + }, + cached_reads, + execution_cache, + trie_handle, + cancel, + best_payload, + }) +} + /// The type that builds the payload. /// /// Payload building for optimism is composed of several steps. @@ -369,7 +409,7 @@ impl OpBuilder<'_, Txs> { } let BlockBuilderOutcome { execution_result, hashed_state, trie_updates, block } = - builder.finish(state_provider)?; + builder.finish(state_provider, None)?; let sealed_block = Arc::new(block.sealed_block().clone()); debug!(target: "payload_builder", id=%ctx.attributes().payload_id(), sealed_block_header = ?sealed_block.header(), "sealed built block"); @@ -599,7 +639,7 @@ where ) -> Result< impl BlockBuilder< Primitives = Evm::Primitives, - Executor: BlockExecutorFor<'a, Evm::BlockExecutorFactory, DB>, + Executor: BlockExecutorFor<'a, Evm::BlockExecutorFactory, &'a mut State>, > + 'a, PayloadBuilderError, > { diff --git a/rust/op-reth/crates/payload/src/lib.rs b/rust/op-reth/crates/payload/src/lib.rs index 6ccd90ec373..41834e63994 100644 --- a/rust/op-reth/crates/payload/src/lib.rs +++ b/rust/op-reth/crates/payload/src/lib.rs @@ -17,7 +17,8 @@ pub mod error; pub mod payload; use op_alloy_rpc_types_engine::OpExecutionData; pub use payload::{ - OpBuiltPayload, OpPayloadAttributes, OpPayloadBuilderAttributes, payload_id_optimism, + OpBuiltPayload, OpExecData, OpPayloadAttributes, OpPayloadAttrs, OpPayloadBuilderAttributes, + payload_id_optimism, }; mod traits; use reth_optimism_primitives::OpPrimitives; @@ -29,6 +30,39 @@ pub use validator::OpExecutionPayloadValidator; pub mod config; +// Implement `ConfigureEngineEvm` by delegating to the `OpExecutionData` implementation. +// This must live here because `OpExecData` is defined in this crate (orphan rules). +impl reth_evm::ConfigureEngineEvm + for reth_optimism_evm::OpEvmConfig +where + N: NodePrimitives, + R: Send + Sync + Unpin + Clone + 'static, + ChainSpec: Send + Sync + Unpin + Clone + 'static, + Self: reth_evm::ConfigureEngineEvm, +{ + fn evm_env_for_payload( + &self, + payload: &OpExecData, + ) -> Result, ::Error> { + reth_evm::ConfigureEngineEvm::::evm_env_for_payload(self, &payload.0) + } + + fn context_for_payload<'a>( + &self, + payload: &'a OpExecData, + ) -> Result, ::Error> { + reth_evm::ConfigureEngineEvm::::context_for_payload(self, &payload.0) + } + + fn tx_iterator_for_payload( + &self, + payload: &OpExecData, + ) -> Result, ::Error> + { + reth_evm::ConfigureEngineEvm::::tx_iterator_for_payload(self, &payload.0) + } +} + /// ZST that aggregates Optimism [`PayloadTypes`]. #[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)] #[non_exhaustive] @@ -38,19 +72,18 @@ impl PayloadTypes for OpPayloadTypes where OpBuiltPayload: BuiltPayload, { - type ExecutionData = OpExecutionData; + type ExecutionData = crate::payload::OpExecData; type BuiltPayload = OpBuiltPayload; - type PayloadAttributes = OpPayloadAttributes; - type PayloadBuilderAttributes = OpPayloadBuilderAttributes; + type PayloadAttributes = crate::payload::OpPayloadAttrs; fn block_to_payload( block: SealedBlock< <::Primitives as NodePrimitives>::Block, >, ) -> Self::ExecutionData { - OpExecutionData::from_block_unchecked( + crate::payload::OpExecData::from(OpExecutionData::from_block_unchecked( block.hash(), &block.into_block().into_ethereum_block(), - ) + )) } } diff --git a/rust/op-reth/crates/payload/src/payload.rs b/rust/op-reth/crates/payload/src/payload.rs index 516a598ab1e..cedd5a62f5a 100644 --- a/rust/op-reth/crates/payload/src/payload.rs +++ b/rust/op-reth/crates/payload/src/payload.rs @@ -19,23 +19,142 @@ use op_alloy_rpc_types_engine::{ use reth_chainspec::EthChainSpec; use reth_optimism_evm::OpNextBlockEnvAttributes; use reth_optimism_forks::OpHardforks; -use reth_payload_builder::{EthPayloadBuilderAttributes, PayloadBuilderError}; -use reth_payload_primitives::{ - BuildNextEnv, BuiltPayload, BuiltPayloadExecutedBlock, PayloadBuilderAttributes, -}; +use reth_payload_builder_primitives::PayloadBuilderError; +use reth_payload_primitives::{BuildNextEnv, BuiltPayload, BuiltPayloadExecutedBlock}; use reth_primitives_traits::{ NodePrimitives, SealedBlock, SealedHeader, SignedTransaction, WithEncoded, }; /// Re-export for use in downstream arguments. -pub use op_alloy_rpc_types_engine::OpPayloadAttributes; +pub use op_alloy_rpc_types_engine::{OpExecutionData, OpPayloadAttributes}; use reth_optimism_primitives::OpPrimitives; +use reth_payload_primitives::EngineApiMessageVersion; + +/// Newtype wrapper around [`OpExecutionData`] to implement +/// [`reth_payload_primitives::ExecutionPayload`]. +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(transparent)] +pub struct OpExecData(pub OpExecutionData); + +impl core::ops::Deref for OpExecData { + type Target = OpExecutionData; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From for OpExecData { + fn from(data: OpExecutionData) -> Self { + Self(data) + } +} + +impl reth_payload_primitives::ExecutionPayload for OpExecData { + fn parent_hash(&self) -> B256 { + self.0.payload.parent_hash() + } + + fn block_hash(&self) -> B256 { + self.0.payload.block_hash() + } + + fn block_number(&self) -> u64 { + self.0.payload.block_number() + } + + fn withdrawals(&self) -> Option<&Vec> { + self.0.withdrawals() + } + + fn block_access_list(&self) -> Option<&Bytes> { + None + } + + fn parent_beacon_block_root(&self) -> Option { + self.0.sidecar.parent_beacon_block_root() + } + + fn timestamp(&self) -> u64 { + self.0.payload.timestamp() + } + + fn gas_used(&self) -> u64 { + self.0.payload.as_v1().gas_used + } + + fn transaction_count(&self) -> usize { + self.0.payload.as_v1().transactions.len() + } +} + +/// Newtype wrapper around [`OpPayloadAttributes`] to implement +/// [`reth_payload_primitives::PayloadAttributes`]. +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(transparent)] +pub struct OpPayloadAttrs(pub OpPayloadAttributes); + +impl core::ops::Deref for OpPayloadAttrs { + type Target = OpPayloadAttributes; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From for OpPayloadAttrs { + fn from(attrs: OpPayloadAttributes) -> Self { + Self(attrs) + } +} + +impl From for OpPayloadAttrs { + fn from(attrs: alloy_rpc_types_engine::PayloadAttributes) -> Self { + Self(OpPayloadAttributes { + payload_attributes: attrs, + transactions: None, + no_tx_pool: None, + gas_limit: None, + eip_1559_params: None, + min_base_fee: None, + }) + } +} + +impl reth_payload_primitives::PayloadAttributes for OpPayloadAttrs { + fn payload_id(&self, parent_hash: &B256) -> PayloadId { + // Use the default engine API message version for computing the payload id. + payload_id_optimism(parent_hash, &self.0, EngineApiMessageVersion::default() as u8) + } + + fn timestamp(&self) -> u64 { + self.0.payload_attributes.timestamp + } + + fn withdrawals(&self) -> Option<&Vec> { + self.0.payload_attributes.withdrawals.as_ref() + } + + fn parent_beacon_block_root(&self) -> Option { + self.0.payload_attributes.parent_beacon_block_root + } +} /// Optimism Payload Builder Attributes #[derive(Debug, Clone, PartialEq, Eq)] pub struct OpPayloadBuilderAttributes { - /// Inner ethereum payload builder attributes - pub payload_attributes: EthPayloadBuilderAttributes, + /// Id of the payload + pub id: PayloadId, + /// Parent block to build the payload on top + pub parent: B256, + /// Unix timestamp for the generated payload + pub timestamp: u64, + /// Address of the recipient for collecting transaction fee + pub suggested_fee_recipient: Address, + /// Randomness value for the generated payload + pub prev_randao: B256, + /// Withdrawals for the generated payload + pub withdrawals: Withdrawals, + /// Root of the parent beacon block + pub parent_beacon_block_root: Option, /// `NoTxPool` option for the generated payload pub no_tx_pool: bool, /// Decoded transactions and the original EIP-2718 encoded bytes as received in the payload @@ -49,15 +168,84 @@ pub struct OpPayloadBuilderAttributes { pub min_base_fee: Option, } +// Manual serde implementations required because: +// - Serialize: the `transactions` field must serialize as encoded bytes (Vec<&Bytes>), not as the +// inner `WithEncoded` type, so #[derive(Serialize)] can't be used. +// - Deserialize: intentionally errors out since this builder type is never deserialized from the +// wire (the engine API uses OpPayloadAttributes, not this builder type). +impl serde::Serialize for OpPayloadBuilderAttributes { + fn serialize(&self, serializer: S) -> Result { + use serde::ser::SerializeStruct; + let mut s = serializer.serialize_struct("OpPayloadBuilderAttributes", 11)?; + s.serialize_field("id", &self.id)?; + s.serialize_field("parent", &self.parent)?; + s.serialize_field("timestamp", &self.timestamp)?; + s.serialize_field("suggestedFeeRecipient", &self.suggested_fee_recipient)?; + s.serialize_field("prevRandao", &self.prev_randao)?; + s.serialize_field("withdrawals", &self.withdrawals)?; + s.serialize_field("parentBeaconBlockRoot", &self.parent_beacon_block_root)?; + s.serialize_field("noTxPool", &self.no_tx_pool)?; + // Serialize transactions as encoded bytes + let tx_bytes: Vec<&alloy_primitives::Bytes> = + self.transactions.iter().map(|t| t.encoded_bytes()).collect(); + s.serialize_field("transactions", &tx_bytes)?; + s.serialize_field("gasLimit", &self.gas_limit)?; + s.serialize_field("eip1559Params", &self.eip_1559_params)?; + s.serialize_field("minBaseFee", &self.min_base_fee)?; + s.end() + } +} + +impl<'de, T: Decodable2718 + Send + Sync + Debug + Unpin + 'static> serde::Deserialize<'de> + for OpPayloadBuilderAttributes +{ + fn deserialize>(_deserializer: D) -> Result { + // This type is never deserialized in practice; the PayloadAttributes trait bound + // requires DeserializeOwned but the engine API uses OpPayloadAttributes for + // deserialization, not OpPayloadBuilderAttributes. + Err(serde::de::Error::custom( + "OpPayloadBuilderAttributes cannot be deserialized directly; \ + use OpPayloadAttributes instead", + )) + } +} + +impl + reth_payload_primitives::PayloadAttributes for OpPayloadBuilderAttributes +{ + fn payload_id(&self, _parent_hash: &B256) -> PayloadId { + // The payload ID was already computed during construction via try_new. + self.id + } + + fn timestamp(&self) -> u64 { + self.timestamp + } + + fn withdrawals(&self) -> Option<&Vec> { + Some(&self.withdrawals.0) + } + + fn parent_beacon_block_root(&self) -> Option { + self.parent_beacon_block_root + } +} + impl Default for OpPayloadBuilderAttributes { fn default() -> Self { Self { - payload_attributes: Default::default(), - no_tx_pool: Default::default(), - gas_limit: Default::default(), - eip_1559_params: Default::default(), - transactions: Default::default(), - min_base_fee: Default::default(), + id: PayloadId::default(), + parent: B256::default(), + timestamp: 0, + suggested_fee_recipient: Address::default(), + prev_randao: B256::default(), + withdrawals: Default::default(), + parent_beacon_block_root: None, + no_tx_pool: false, + transactions: Vec::new(), + gas_limit: None, + eip_1559_params: None, + min_base_fee: None, } } } @@ -87,20 +275,15 @@ impl OpPayloadBuilderAttributes { } } -impl PayloadBuilderAttributes - for OpPayloadBuilderAttributes -{ - type RpcPayloadAttributes = OpPayloadAttributes; - type Error = alloy_rlp::Error; - +impl OpPayloadBuilderAttributes { /// Creates a new payload builder for the given parent block and the attributes. /// /// Derives the unique [`PayloadId`] for the given parent and attributes - fn try_new( + pub fn try_new( parent: B256, attributes: OpPayloadAttributes, version: u8, - ) -> Result { + ) -> Result { let id = payload_id_optimism(&parent, &attributes, version); let transactions = attributes @@ -112,7 +295,7 @@ impl PayloadBuilderAtt }) .collect::>()?; - let payload_attributes = EthPayloadBuilderAttributes { + Ok(Self { id, parent, timestamp: attributes.payload_attributes.timestamp, @@ -120,10 +303,6 @@ impl PayloadBuilderAtt prev_randao: attributes.payload_attributes.prev_randao, withdrawals: attributes.payload_attributes.withdrawals.unwrap_or_default().into(), parent_beacon_block_root: attributes.payload_attributes.parent_beacon_block_root, - }; - - Ok(Self { - payload_attributes, no_tx_pool: attributes.no_tx_pool.unwrap_or_default(), transactions, gas_limit: attributes.gas_limit, @@ -132,40 +311,73 @@ impl PayloadBuilderAtt }) } - fn payload_id(&self) -> PayloadId { - self.payload_attributes.id + /// Creates a new payload builder from RPC attributes with a pre-computed payload ID. + /// + /// This is used when the payload ID has already been computed (e.g., by the payload service) + /// and we just need to decode the transaction bytes. + pub fn from_rpc_attrs( + parent: B256, + id: PayloadId, + attributes: OpPayloadAttributes, + ) -> Result { + let transactions = attributes + .transactions + .unwrap_or_default() + .into_iter() + .map(|data| { + Decodable2718::decode_2718_exact(data.as_ref()).map(|tx| WithEncoded::new(data, tx)) + }) + .collect::>()?; + + Ok(Self { + id, + parent, + timestamp: attributes.payload_attributes.timestamp, + suggested_fee_recipient: attributes.payload_attributes.suggested_fee_recipient, + prev_randao: attributes.payload_attributes.prev_randao, + withdrawals: attributes.payload_attributes.withdrawals.unwrap_or_default().into(), + parent_beacon_block_root: attributes.payload_attributes.parent_beacon_block_root, + no_tx_pool: attributes.no_tx_pool.unwrap_or_default(), + transactions, + gas_limit: attributes.gas_limit, + eip_1559_params: attributes.eip_1559_params, + min_base_fee: attributes.min_base_fee, + }) } - fn parent(&self) -> B256 { - self.payload_attributes.parent + /// Returns the identifier of the payload. + pub const fn payload_id(&self) -> PayloadId { + self.id } - fn timestamp(&self) -> u64 { - self.payload_attributes.timestamp + /// Returns the parent block hash. + pub const fn parent(&self) -> B256 { + self.parent } - fn parent_beacon_block_root(&self) -> Option { - self.payload_attributes.parent_beacon_block_root + /// Returns the timestamp for the payload. + pub const fn timestamp(&self) -> u64 { + self.timestamp } - fn suggested_fee_recipient(&self) -> Address { - self.payload_attributes.suggested_fee_recipient + /// Returns the parent beacon block root. + pub const fn parent_beacon_block_root(&self) -> Option { + self.parent_beacon_block_root } - fn prev_randao(&self) -> B256 { - self.payload_attributes.prev_randao + /// Returns the suggested fee recipient. + pub const fn suggested_fee_recipient(&self) -> Address { + self.suggested_fee_recipient } - fn withdrawals(&self) -> &Withdrawals { - &self.payload_attributes.withdrawals + /// Returns the prev randao value. + pub const fn prev_randao(&self) -> B256 { + self.prev_randao } -} -impl From - for OpPayloadBuilderAttributes -{ - fn from(value: EthPayloadBuilderAttributes) -> Self { - Self { payload_attributes: value, ..Default::default() } + /// Returns the withdrawals. + pub const fn withdrawals(&self) -> &Withdrawals { + &self.withdrawals } } @@ -414,16 +626,16 @@ where parent: &SealedHeader, chain_spec: &ChainSpec, ) -> Result { - let extra_data = if chain_spec.is_jovian_active_at_timestamp(attributes.timestamp()) { + let extra_data = if chain_spec.is_jovian_active_at_timestamp(attributes.timestamp) { attributes .get_jovian_extra_data( - chain_spec.base_fee_params_at_timestamp(attributes.timestamp()), + chain_spec.base_fee_params_at_timestamp(attributes.timestamp), ) .map_err(PayloadBuilderError::other)? - } else if chain_spec.is_holocene_active_at_timestamp(attributes.timestamp()) { + } else if chain_spec.is_holocene_active_at_timestamp(attributes.timestamp) { attributes .get_holocene_extra_data( - chain_spec.base_fee_params_at_timestamp(attributes.timestamp()), + chain_spec.base_fee_params_at_timestamp(attributes.timestamp), ) .map_err(PayloadBuilderError::other)? } else { @@ -431,11 +643,11 @@ where }; Ok(Self { - timestamp: attributes.timestamp(), - suggested_fee_recipient: attributes.suggested_fee_recipient(), - prev_randao: attributes.prev_randao(), + timestamp: attributes.timestamp, + suggested_fee_recipient: attributes.suggested_fee_recipient, + prev_randao: attributes.prev_randao, gas_limit: attributes.gas_limit.unwrap_or_else(|| parent.gas_limit()), - parent_beacon_block_root: attributes.parent_beacon_block_root(), + parent_beacon_block_root: attributes.parent_beacon_block_root, extra_data, }) } diff --git a/rust/op-reth/crates/payload/src/traits.rs b/rust/op-reth/crates/payload/src/traits.rs index bd371ee1a0f..d4607f40738 100644 --- a/rust/op-reth/crates/payload/src/traits.rs +++ b/rust/op-reth/crates/payload/src/traits.rs @@ -1,9 +1,11 @@ use alloy_consensus::BlockBody; +use alloy_primitives::B256; +use alloy_rpc_types_engine::PayloadId; use reth_optimism_primitives::{DepositReceipt, transaction::OpTransaction}; -use reth_payload_primitives::PayloadBuilderAttributes; +use reth_payload_builder_primitives::PayloadBuilderError; use reth_primitives_traits::{FullBlockHeader, NodePrimitives, SignedTransaction, WithEncoded}; -use crate::OpPayloadBuilderAttributes; +use crate::{OpPayloadAttributes, OpPayloadBuilderAttributes}; /// Helper trait to encapsulate common bounds on [`NodePrimitives`] for OP payload builder. pub trait OpPayloadPrimitives: @@ -36,10 +38,28 @@ where } /// Attributes for the OP payload builder. -pub trait OpAttributes: PayloadBuilderAttributes { +pub trait OpAttributes: Send + Sync + core::fmt::Debug + 'static { /// Primitive transaction type. type Transaction: SignedTransaction; + /// The RPC payload attributes type used to create these builder attributes. + type RpcPayloadAttributes; + + /// Creates a new instance from the parent hash and RPC payload attributes. + fn try_new( + parent: B256, + attributes: Self::RpcPayloadAttributes, + version: u8, + ) -> Result + where + Self: Sized; + + /// Returns the identifier of the payload. + fn payload_id(&self) -> PayloadId; + + /// Returns the timestamp for the payload. + fn timestamp(&self) -> u64; + /// Whether to use the transaction pool for the payload. fn no_tx_pool(&self) -> bool; @@ -49,6 +69,23 @@ pub trait OpAttributes: PayloadBuilderAttributes { impl OpAttributes for OpPayloadBuilderAttributes { type Transaction = T; + type RpcPayloadAttributes = OpPayloadAttributes; + + fn try_new( + parent: B256, + attributes: OpPayloadAttributes, + version: u8, + ) -> Result { + Self::try_new(parent, attributes, version).map_err(PayloadBuilderError::other) + } + + fn payload_id(&self) -> PayloadId { + self.id + } + + fn timestamp(&self) -> u64 { + self.timestamp + } fn no_tx_pool(&self) -> bool { self.no_tx_pool diff --git a/rust/op-reth/crates/primitives/Cargo.toml b/rust/op-reth/crates/primitives/Cargo.toml index 70b30300b31..937aea3efa8 100644 --- a/rust/op-reth/crates/primitives/Cargo.toml +++ b/rust/op-reth/crates/primitives/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] # reth -reth-primitives-traits = { workspace = true, features = ["op"] } +reth-primitives-traits.workspace = true # ethereum alloy-primitives.workspace = true @@ -22,14 +22,15 @@ alloy-eips.workspace = true alloy-rlp.workspace = true # op -op-alloy-consensus.workspace = true +op-alloy-consensus = { workspace = true, features = ["reth-core", "k256"] } # codec serde = { workspace = true, optional = true } serde_with = { workspace = true, optional = true } [dev-dependencies] -reth-codecs = { workspace = true, features = ["test-utils", "op"] } +reth-codecs = { workspace = true, features = ["test-utils"] } +op-alloy-consensus = { workspace = true, features = ["reth-core", "k256", "reth-codec", "arbitrary"] } bytes.workspace = true modular-bitfield.workspace = true @@ -65,6 +66,7 @@ alloy-compat = ["op-alloy-consensus/alloy-compat"] reth-codec = [ "std", "reth-primitives-traits/reth-codec", + "op-alloy-consensus/reth-codec", ] serde = [ "dep:serde", @@ -83,7 +85,6 @@ serde-bincode-compat = [ "serde_with", "alloy-consensus/serde-bincode-compat", "op-alloy-consensus/serde-bincode-compat", - "reth-primitives-traits/serde-bincode-compat", "alloy-eips/serde-bincode-compat", ] arbitrary = [ diff --git a/rust/op-reth/crates/primitives/src/receipt.rs b/rust/op-reth/crates/primitives/src/receipt.rs index 1a7baed9c0f..21c620ae67f 100644 --- a/rust/op-reth/crates/primitives/src/receipt.rs +++ b/rust/op-reth/crates/primitives/src/receipt.rs @@ -46,21 +46,17 @@ pub(super) mod serde_bincode_compat { /// /// Intended to use with the [`serde_with::serde_as`] macro in the following way: /// ```rust - /// use reth_optimism_primitives::OpReceipt; - /// use reth_primitives_traits::serde_bincode_compat::SerdeBincodeCompat; - /// use serde::{Deserialize, Serialize, de::DeserializeOwned}; + /// use reth_optimism_primitives::{OpReceipt, serde_bincode_compat}; + /// use serde::{Deserialize, Serialize}; /// use serde_with::serde_as; /// /// #[serde_as] /// #[derive(Serialize, Deserialize)] /// struct Data { - /// #[serde_as( - /// as = "reth_primitives_traits::serde_bincode_compat::BincodeReprFor<'_, OpReceipt>" - /// )] + /// #[serde_as(as = "serde_bincode_compat::OpReceipt<'_>")] /// receipt: OpReceipt, /// } /// ``` - #[allow(rustdoc::private_doc_tests)] #[derive(Debug, Serialize, Deserialize)] pub enum OpReceipt<'a> { /// Legacy receipt diff --git a/rust/op-reth/crates/primitives/src/transaction/signed.rs b/rust/op-reth/crates/primitives/src/transaction/signed.rs index ddfb83612d1..6fcb6dc183c 100644 --- a/rust/op-reth/crates/primitives/src/transaction/signed.rs +++ b/rust/op-reth/crates/primitives/src/transaction/signed.rs @@ -154,16 +154,6 @@ impl IsTyped2718 for OpTransactionSigned { } } -impl SignedTransaction for OpTransactionSigned { - fn is_system_tx(&self) -> bool { - self.is_deposit() - } - - fn recalculate_hash(&self) -> B256 { - keccak256(self.encoded_2718()) - } -} - macro_rules! impl_from_signed { ($($tx:ident),*) => { $( @@ -414,7 +404,7 @@ impl Hash for OpTransactionSigned { } } -#[cfg(feature = "reth-codec")] +#[cfg(any(test, feature = "reth-codec"))] impl reth_codecs::Compact for OpTransactionSigned { fn to_compact(&self, buf: &mut B) -> usize where diff --git a/rust/op-reth/crates/reth/Cargo.toml b/rust/op-reth/crates/reth/Cargo.toml index 19b44f3d67e..4fb6654c499 100644 --- a/rust/op-reth/crates/reth/Cargo.toml +++ b/rust/op-reth/crates/reth/Cargo.toml @@ -12,13 +12,13 @@ workspace = true [dependencies] # reth -reth-primitives-traits = { workspace = true, features = ["op"] } +reth-primitives-traits.workspace = true reth-chainspec.workspace = true reth-network = { workspace = true, optional = true } reth-network-api = { workspace = true, optional = true } reth-eth-wire = { workspace = true, optional = true } reth-provider = { workspace = true, optional = true } -reth-db = { workspace = true, optional = true, features = ["mdbx", "op"] } +reth-db = { workspace = true, optional = true, features = ["mdbx"] } reth-codecs = { workspace = true, optional = true } reth-storage-api = { workspace = true, optional = true } reth-node-api = { workspace = true, optional = true } @@ -64,7 +64,8 @@ std = [ "reth-storage-api?/std", "reth-evm?/std", "reth-revm?/std", - "alloy-primitives/std" + "alloy-primitives/std", + "reth-codecs?/std", ] arbitrary = [ "std", @@ -112,7 +113,7 @@ consensus = [ ] evm = ["dep:reth-evm", "dep:reth-optimism-evm", "dep:reth-revm"] exex = ["provider", "dep:reth-exex"] -node-api = ["dep:reth-node-api", "dep:reth-node-core"] +node-api = ["dep:reth-node-api", "dep:reth-node-core", "dep:reth-codecs", "reth-optimism-primitives/reth-codec"] node = [ "provider", "consensus", @@ -139,6 +140,7 @@ jemalloc = [ "reth-cli-util?/jemalloc", "reth-node-core?/jemalloc", "reth-optimism-cli?/jemalloc", + "reth-provider?/jemalloc", ] js-tracer = [ "rpc", @@ -156,8 +158,8 @@ portable = [ "reth-optimism-evm?/portable", "reth-revm?/portable", ] -provider = ["storage-api", "tasks", "dep:reth-provider", "dep:reth-db", "dep:reth-codecs"] +provider = ["storage-api", "tasks", "dep:reth-provider", "dep:reth-db", "dep:reth-codecs", "reth-optimism-primitives/reth-codec"] pool = ["dep:reth-transaction-pool"] storage-api = ["dep:reth-storage-api"] trie = ["dep:reth-trie", "alloy-primitives/rayon"] -trie-db = ["trie", "dep:reth-trie-db"] +trie-db = ["trie", "dep:reth-trie-db", "dep:reth-codecs", "reth-optimism-primitives/reth-codec"] diff --git a/rust/op-reth/crates/rpc/Cargo.toml b/rust/op-reth/crates/rpc/Cargo.toml index 6c7d5cc398b..e19996291c0 100644 --- a/rust/op-reth/crates/rpc/Cargo.toml +++ b/rust/op-reth/crates/rpc/Cargo.toml @@ -15,9 +15,9 @@ workspace = true # reth reth-basic-payload-builder.workspace = true reth-evm.workspace = true -reth-primitives-traits = { workspace = true, features = ["op"] } +reth-primitives-traits.workspace = true reth-storage-api.workspace = true -reth-rpc-eth-api = { workspace = true, features = ["op"] } +reth-rpc-eth-api.workspace = true reth-rpc-eth-types.workspace = true reth-rpc-server-types.workspace = true reth-tasks = { workspace = true, features = ["rayon"] } @@ -57,7 +57,7 @@ alloy-transport-http.workspace = true alloy-consensus.workspace = true alloy-rpc-types-engine.workspace = true op-alloy-network.workspace = true -op-alloy-rpc-types.workspace = true +op-alloy-rpc-types = { workspace = true, features = ["reth"] } op-alloy-rpc-types-engine.workspace = true op-alloy-rpc-jsonrpsee.workspace = true op-alloy-consensus.workspace = true diff --git a/rust/op-reth/crates/rpc/src/debug.rs b/rust/op-reth/crates/rpc/src/debug.rs index c46d87b67c6..8cb6a3d4dc7 100644 --- a/rust/op-reth/crates/rpc/src/debug.rs +++ b/rust/op-reth/crates/rpc/src/debug.rs @@ -33,7 +33,7 @@ use reth_revm::{State, database::StateProviderDatabase, witness::ExecutionWitnes use reth_rpc_api::eth::helpers::FullEthApi; use reth_rpc_eth_types::EthApiError; use reth_rpc_server_types::{ToRpcResult, result::internal_rpc_err}; -use reth_tasks::TaskSpawner; +use reth_tasks::Runtime; use serde::{Deserialize, Serialize}; use std::{marker::PhantomData, sync::Arc}; use tokio::sync::{Semaphore, oneshot}; @@ -86,7 +86,7 @@ where provider: Provider, eth_api: Eth, preimage_store: OpProofsStorage, - task_spawner: Box, + task_spawner: Runtime, evm_config: EvmConfig, ) -> Self { Self { @@ -109,7 +109,7 @@ pub struct DebugApiExtInner, state_provider_factory: OpStateProviderFactory, evm_config: EvmConfig, - task_spawner: Box, + task_spawner: Runtime, semaphore: Semaphore, _attrs: PhantomData, metrics: DebugApiExtMetrics, @@ -126,7 +126,7 @@ where provider: Provider, eth_api: Eth, storage: OpProofsStorage

, - task_spawner: Box, + task_spawner: Runtime, evm_config: EvmConfig, ) -> Self { Self { @@ -170,7 +170,7 @@ where Eth: FullEthApi + Send + Sync + 'static, ErrorObject<'static>: From, P: OpProofsStore + Clone + 'static, - Attrs: OpAttributes>, + Attrs: OpAttributes, RpcPayloadAttributes: Send>, N: OpPayloadPrimitives, EvmConfig: ConfigureEvm< Primitives = N, @@ -201,14 +201,18 @@ where let (tx, rx) = oneshot::channel(); let this = self.inner.clone(); - self.inner.task_spawner.spawn_blocking_task(Box::pin(async move { + self.inner.task_spawner.spawn_blocking_task(async move { let result = async { let parent_hash = parent_header.hash(); let attributes = Attrs::try_new(parent_hash, attributes, 3) .map_err(PayloadBuilderError::other)?; - let config = - PayloadConfig { parent_header: Arc::new(parent_header), attributes }; + let payload_id = attributes.payload_id(); + let config = PayloadConfig { + parent_header: Arc::new(parent_header), + attributes, + payload_id, + }; let ctx = OpPayloadBuilderCtx { evm_config: this.evm_config.clone(), chain_spec: this.provider.chain_spec(), @@ -237,7 +241,7 @@ where }; let _ = tx.send(result.await); - })); + }); rx.await .map_err(|err| internal_rpc_err(err.to_string()))? diff --git a/rust/op-reth/crates/rpc/src/engine.rs b/rust/op-reth/crates/rpc/src/engine.rs index f9e67fdfd91..f3b86e498c9 100644 --- a/rust/op-reth/crates/rpc/src/engine.rs +++ b/rust/op-reth/crates/rpc/src/engine.rs @@ -10,11 +10,11 @@ use derive_more::Constructor; use jsonrpsee::proc_macros::rpc; use jsonrpsee_core::{RpcResult, server::RpcModule}; use op_alloy_rpc_types_engine::{ - OpExecutionData, OpExecutionPayloadV4, ProtocolVersion, ProtocolVersionFormatV0, - SuperchainSignal, + OpExecutionPayloadV4, ProtocolVersion, ProtocolVersionFormatV0, SuperchainSignal, }; use reth_chainspec::EthereumHardforks; use reth_node_api::{EngineApiValidator, EngineTypes}; +use reth_optimism_payload_builder::OpExecData; use reth_rpc_api::IntoEngineApiRpcModule; use reth_rpc_engine_api::EngineApi; use reth_storage_api::{BlockReader, HeaderProvider, StateProviderFactory}; @@ -267,14 +267,14 @@ impl OpEngineApiServer for OpEngineApi where Provider: HeaderProvider + BlockReader + StateProviderFactory + 'static, - EngineT: EngineTypes, + EngineT: EngineTypes, Pool: TransactionPool + 'static, Validator: EngineApiValidator, ChainSpec: EthereumHardforks + Send + Sync + 'static, { async fn new_payload_v2(&self, payload: ExecutionPayloadInputV2) -> RpcResult { trace!(target: "rpc::engine", "Serving engine_newPayloadV2"); - let payload = OpExecutionData::v2(payload); + let payload = OpExecData::from(op_alloy_rpc_types_engine::OpExecutionData::v2(payload)); Ok(self.inner.new_payload_v2_metered(payload).await?) } @@ -285,7 +285,11 @@ where parent_beacon_block_root: B256, ) -> RpcResult { trace!(target: "rpc::engine", "Serving engine_newPayloadV3"); - let payload = OpExecutionData::v3(payload, versioned_hashes, parent_beacon_block_root); + let payload = OpExecData::from(op_alloy_rpc_types_engine::OpExecutionData::v3( + payload, + versioned_hashes, + parent_beacon_block_root, + )); Ok(self.inner.new_payload_v3_metered(payload).await?) } @@ -298,12 +302,12 @@ where execution_requests: Requests, ) -> RpcResult { trace!(target: "rpc::engine", "Serving engine_newPayloadV4"); - let payload = OpExecutionData::v4( + let payload = OpExecData::from(op_alloy_rpc_types_engine::OpExecutionData::v4( payload, versioned_hashes, parent_beacon_block_root, execution_requests, - ); + )); Ok(self.inner.new_payload_v4_metered(payload).await?) } diff --git a/rust/op-reth/crates/rpc/src/eth/mod.rs b/rust/op-reth/crates/rpc/src/eth/mod.rs index d53b11d8bf0..8291bde0dec 100644 --- a/rust/op-reth/crates/rpc/src/eth/mod.rs +++ b/rust/op-reth/crates/rpc/src/eth/mod.rs @@ -38,7 +38,7 @@ use reth_rpc_eth_api::{ RpcNodeCoreExt, RpcTypes, helpers::{ EthApiSpec, EthFees, EthState, LoadFee, LoadPendingBlock, LoadState, SpawnBlocking, Trace, - pending_block::BuildPendingEnv, + bal::GetBlockAccessList, pending_block::BuildPendingEnv, }, }; use reth_rpc_eth_types::{ @@ -46,7 +46,7 @@ use reth_rpc_eth_types::{ }; use reth_storage_api::ProviderHeader; use reth_tasks::{ - TaskSpawner, + Runtime, pool::{BlockingTaskGuard, BlockingTaskPool}, }; use std::{ @@ -304,7 +304,7 @@ where Rpc: RpcConvert, { #[inline] - fn io_task_spawner(&self) -> impl TaskSpawner { + fn io_task_spawner(&self) -> &Runtime { self.inner.eth_api.task_spawner() } @@ -386,6 +386,14 @@ where { } +impl GetBlockAccessList for OpEthApi +where + N: RpcNodeCore, + OpEthApiError: FromEvmError, + Rpc: RpcConvert, +{ +} + impl fmt::Debug for OpEthApi { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OpEthApi").finish_non_exhaustive() @@ -434,6 +442,9 @@ pub type OpRpcConvert = RpcConverter< OpReceiptConverter<::Provider>, (), OpTxInfoMapper<::Provider>, + (), + (), + reth_optimism_evm::tx::OpTxEnvConverter, >; /// Builds [`OpEthApi`] for Optimism. @@ -554,7 +565,8 @@ where } = self; let rpc_converter = RpcConverter::new(OpReceiptConverter::new(ctx.components.provider().clone())) - .with_mapper(OpTxInfoMapper::new(ctx.components.provider().clone())); + .with_mapper(OpTxInfoMapper::new(ctx.components.provider().clone())) + .with_tx_env_converter(reth_optimism_evm::tx::OpTxEnvConverter); let sequencer_client = if let Some(url) = sequencer_url { Some( diff --git a/rust/op-reth/crates/rpc/src/eth/transaction.rs b/rust/op-reth/crates/rpc/src/eth/transaction.rs index 3af2d59bee4..01c51ba7bbe 100644 --- a/rust/op-reth/crates/rpc/src/eth/transaction.rs +++ b/rust/op-reth/crates/rpc/src/eth/transaction.rs @@ -178,8 +178,8 @@ where return Ok(Some(receipt)); } } - let Some((tx, meta, receipt)) = tx_receipt else { return Ok(None) }; - self.build_transaction_receipt(tx, meta, receipt).await.map(Some) + let Some((tx, meta, receipt, all_receipts)) = tx_receipt else { return Ok(None) }; + self.build_transaction_receipt(tx, meta, receipt, all_receipts).await.map(Some) } } } diff --git a/rust/op-reth/crates/rpc/src/witness.rs b/rust/op-reth/crates/rpc/src/witness.rs index 0da4fe418b0..624828621f6 100644 --- a/rust/op-reth/crates/rpc/src/witness.rs +++ b/rust/op-reth/crates/rpc/src/witness.rs @@ -16,7 +16,7 @@ use reth_storage_api::{ BlockReaderIdExt, NodePrimitivesProvider, StateProviderFactory, errors::{ProviderError, ProviderResult}, }; -use reth_tasks::TaskSpawner; +use reth_tasks::Runtime; use reth_transaction_pool::TransactionPool; use std::{fmt::Debug, sync::Arc}; use tokio::sync::{Semaphore, oneshot}; @@ -30,7 +30,7 @@ impl OpDebugWitnessApi, + task_spawner: Runtime, builder: OpPayloadBuilder, ) -> Self { let semaphore = Arc::new(Semaphore::new(3)); @@ -74,7 +74,7 @@ where Primitives = Provider::Primitives, NextBlockEnvCtx: BuildNextEnv, > + 'static, - Attrs: OpAttributes>, + Attrs: OpAttributes, RpcPayloadAttributes: Send>, { async fn execute_payload( &self, @@ -87,10 +87,10 @@ where let (tx, rx) = oneshot::channel(); let this = self.clone(); - self.inner.task_spawner.spawn_blocking_task(Box::pin(async move { + self.inner.task_spawner.spawn_blocking_task(async move { let res = this.inner.builder.payload_witness(parent_header, attributes); let _ = tx.send(res); - })); + }); rx.await .map_err(|err| internal_rpc_err(err.to_string()))? @@ -116,6 +116,6 @@ impl Debug struct OpDebugWitnessApiInner { provider: Provider, builder: OpPayloadBuilder, - task_spawner: Box, + task_spawner: Runtime, semaphore: Arc, } diff --git a/rust/op-reth/crates/trie/Cargo.toml b/rust/op-reth/crates/trie/Cargo.toml index 9d768751027..229463b39af 100644 --- a/rust/op-reth/crates/trie/Cargo.toml +++ b/rust/op-reth/crates/trie/Cargo.toml @@ -13,6 +13,7 @@ workspace = true [dependencies] # reth +reth-codecs.workspace = true reth-db = { workspace = true, features = ["mdbx"] } reth-evm.workspace = true reth-execution-errors.workspace = true @@ -80,13 +81,11 @@ serial_test.workspace = true [features] serde-bincode-compat = [ - "reth-primitives-traits/serde-bincode-compat", "reth-trie-common/serde-bincode-compat", "alloy-consensus/serde-bincode-compat", "alloy-eips/serde-bincode-compat", "reth-trie/serde-bincode-compat", "dep:reth-ethereum-primitives", - "reth-ethereum-primitives?/serde-bincode-compat", "reth-ethereum-primitives?/serde", ] metrics = [ diff --git a/rust/op-reth/crates/trie/src/db/models/block.rs b/rust/op-reth/crates/trie/src/db/models/block.rs index c2066dad1f6..d2aeff23e48 100644 --- a/rust/op-reth/crates/trie/src/db/models/block.rs +++ b/rust/op-reth/crates/trie/src/db/models/block.rs @@ -2,6 +2,7 @@ use alloy_eips::BlockNumHash; use alloy_primitives::B256; use bytes::BufMut; use derive_more::{From, Into}; +use reth_codecs::DecompressError; use reth_db::{ DatabaseError, table::{Compress, Decompress}, @@ -25,12 +26,14 @@ impl Compress for BlockNumberHash { } impl Decompress for BlockNumberHash { - fn decompress(value: &[u8]) -> Result { + fn decompress(value: &[u8]) -> Result { if value.len() != 40 { - return Err(DatabaseError::Decode); + return Err(DecompressError::new(DatabaseError::Decode)); } - let number = u64::from_be_bytes(value[..8].try_into().map_err(|_| DatabaseError::Decode)?); + let number = u64::from_be_bytes( + value[..8].try_into().map_err(|_| DecompressError::new(DatabaseError::Decode))?, + ); let hash = B256::from_slice(&value[8..40]); Ok(Self(BlockNumHash { number, hash })) diff --git a/rust/op-reth/crates/trie/src/db/models/change_set.rs b/rust/op-reth/crates/trie/src/db/models/change_set.rs index dbfdc815e43..248d0602794 100644 --- a/rust/op-reth/crates/trie/src/db/models/change_set.rs +++ b/rust/op-reth/crates/trie/src/db/models/change_set.rs @@ -47,8 +47,8 @@ impl table::Compress for ChangeSet { } impl table::Decompress for ChangeSet { - fn decompress(value: &[u8]) -> Result { - Self::decode(value) + fn decompress(value: &[u8]) -> Result { + Self::decode(value).map_err(reth_codecs::DecompressError::new) } } diff --git a/rust/op-reth/crates/trie/src/db/models/storage.rs b/rust/op-reth/crates/trie/src/db/models/storage.rs index 922d252627a..ad520c1e831 100644 --- a/rust/op-reth/crates/trie/src/db/models/storage.rs +++ b/rust/op-reth/crates/trie/src/db/models/storage.rs @@ -1,5 +1,6 @@ use alloy_primitives::{B256, U256}; use derive_more::{Constructor, From, Into}; +use reth_codecs::DecompressError; use reth_db::{ DatabaseError, table::{Compress, Decode, Decompress, Encode}, @@ -114,11 +115,12 @@ impl Compress for StorageValue { } impl Decompress for StorageValue { - fn decompress(value: &[u8]) -> Result { + fn decompress(value: &[u8]) -> Result { if value.len() != 32 { - return Err(DatabaseError::Decode); + return Err(DecompressError::new(DatabaseError::Decode)); } - let bytes: [u8; 32] = value.try_into().map_err(|_| DatabaseError::Decode)?; + let bytes: [u8; 32] = + value.try_into().map_err(|_| DecompressError::new(DatabaseError::Decode))?; Ok(Self(U256::from_be_bytes(bytes))) } } diff --git a/rust/op-reth/crates/trie/src/db/models/version.rs b/rust/op-reth/crates/trie/src/db/models/version.rs index 26f985c9674..90af12012fb 100644 --- a/rust/op-reth/crates/trie/src/db/models/version.rs +++ b/rust/op-reth/crates/trie/src/db/models/version.rs @@ -1,4 +1,5 @@ use bytes::{Buf, BufMut}; +use reth_codecs::DecompressError; use reth_db::{ DatabaseError, table::{Compress, Decompress}, @@ -45,7 +46,7 @@ impl Compress for MaybeDeleted { } impl Decompress for MaybeDeleted { - fn decompress(value: &[u8]) -> Result { + fn decompress(value: &[u8]) -> Result { if value.is_empty() { // Empty = deleted Ok(Self(None)) @@ -96,9 +97,9 @@ impl Compress for VersionedValue { } impl Decompress for VersionedValue { - fn decompress(value: &[u8]) -> Result { + fn decompress(value: &[u8]) -> Result { if value.len() < 8 { - return Err(DatabaseError::Decode); + return Err(DecompressError::new(DatabaseError::Decode)); } let mut buf: &[u8] = value; diff --git a/rust/op-reth/crates/trie/src/initialize.rs b/rust/op-reth/crates/trie/src/initialize.rs index 92f260b83b3..d5f8f7b7979 100644 --- a/rust/op-reth/crates/trie/src/initialize.rs +++ b/rust/op-reth/crates/trie/src/initialize.rs @@ -17,7 +17,8 @@ use reth_db::{ }; use reth_primitives_traits::{Account, StorageEntry}; use reth_trie_common::{ - BranchNodeCompact, Nibbles, StorageTrieEntry, StoredNibbles, StoredNibblesSubKey, + BranchNodeCompact, Nibbles, PackedStoredNibbles, StorageTrieEntry, StoredNibbles, + StoredNibblesSubKey, }; use std::time::Instant; use tracing::{debug, info}; @@ -96,8 +97,8 @@ define_simple_cursor_iter!(HashedAccountsInit, tables::HashedAccounts, B256, Acc define_dup_cursor_iter!(HashedStoragesInit, tables::HashedStorages, B256, StorageEntry); define_simple_cursor_iter!( AccountsTrieInit, - tables::AccountsTrie, - StoredNibbles, + tables::PackedAccountsTrie, + PackedStoredNibbles, BranchNodeCompact ); define_dup_cursor_iter!(StoragesTrieInit, tables::StoragesTrie, B256, StorageTrieEntry); @@ -120,7 +121,7 @@ impl CompletionEstimatable for B256 { } } -impl CompletionEstimatable for StoredNibbles { +impl CompletionEstimatable for PackedStoredNibbles { fn estimate_progress(&self) -> f64 { // use the first 6 nibbles as a progress estimate let progress_nibbles = @@ -266,12 +267,13 @@ impl &self, start_key: Option, ) -> Result<(), OpProofsStorageError> { - let mut start_cursor = self.tx.cursor_read::()?; + let mut start_cursor = self.tx.cursor_read::()?; if let Some(latest_key) = start_key { + let packed_key = PackedStoredNibbles::from(latest_key); start_cursor - .seek(latest_key.clone())? - .filter(|(k, _)| *k == latest_key) + .seek(packed_key.clone())? + .filter(|(k, _)| *k == packed_key) .ok_or(OpProofsStorageError::InitializeStorageInconsistentState)?; } @@ -440,7 +442,7 @@ impl InitTable for HashedStoragesInit { } impl InitTable for AccountsTrieInit { - type Key = StoredNibbles; + type Key = PackedStoredNibbles; type Value = BranchNodeCompact; /// Save mapping of account trie paths to branch nodes to storage. @@ -650,13 +652,13 @@ mod tests { // Insert test trie nodes into database let tx = db.tx_mut().unwrap(); - let mut cursor = tx.cursor_write::().unwrap(); + let mut cursor = tx.cursor_write::().unwrap(); let branch = create_test_branch_node(); let nodes = vec![ - (StoredNibbles(Nibbles::from_nibbles_unchecked(vec![1])), branch.clone()), - (StoredNibbles(Nibbles::from_nibbles_unchecked(vec![2])), branch.clone()), - (StoredNibbles(Nibbles::from_nibbles_unchecked(vec![3])), branch), + (PackedStoredNibbles(Nibbles::from_nibbles_unchecked(vec![1])), branch.clone()), + (PackedStoredNibbles(Nibbles::from_nibbles_unchecked(vec![2])), branch.clone()), + (PackedStoredNibbles(Nibbles::from_nibbles_unchecked(vec![3])), branch), ]; for (path, node) in &nodes { @@ -777,10 +779,10 @@ mod tests { drop(cursor); // Add account trie - let mut cursor = tx.cursor_write::().unwrap(); + let mut cursor = tx.cursor_write::().unwrap(); cursor .append( - StoredNibbles(Nibbles::from_nibbles_unchecked(vec![1])), + PackedStoredNibbles(Nibbles::from_nibbles_unchecked(vec![1])), &create_test_branch_node(), ) .unwrap(); @@ -1042,15 +1044,15 @@ mod tests { store.set_initial_state_anchor(BlockNumHash::new(0, B256::default())).expect("set anchor"); - let p1 = StoredNibbles(Nibbles::from_nibbles_unchecked(vec![1])); - let p2 = StoredNibbles(Nibbles::from_nibbles_unchecked(vec![2])); - let p3 = StoredNibbles(Nibbles::from_nibbles_unchecked(vec![3])); - let p4 = StoredNibbles(Nibbles::from_nibbles_unchecked(vec![4])); + let p1 = PackedStoredNibbles(Nibbles::from_nibbles_unchecked(vec![1])); + let p2 = PackedStoredNibbles(Nibbles::from_nibbles_unchecked(vec![2])); + let p3 = PackedStoredNibbles(Nibbles::from_nibbles_unchecked(vec![3])); + let p4 = PackedStoredNibbles(Nibbles::from_nibbles_unchecked(vec![4])); // Phase 1 source: p1,p2 { let tx = db.tx_mut().unwrap(); - let mut cur = tx.cursor_write::().unwrap(); + let mut cur = tx.cursor_write::().unwrap(); cur.append(p1.clone(), &create_test_branch_node()).unwrap(); cur.append(p2.clone(), &create_test_branch_node()).unwrap(); tx.commit().unwrap(); @@ -1065,13 +1067,13 @@ mod tests { assert_eq!( store.initial_state_anchor().expect("get anchor").latest_account_trie_key, - Some(p2.clone()) + Some(StoredNibbles::from(p2.clone())) ); // Phase 2 source: p3,p4 { let tx = db.tx_mut().unwrap(); - let mut cur = tx.cursor_write::().unwrap(); + let mut cur = tx.cursor_write::().unwrap(); cur.append(p3.clone(), &create_test_branch_node()).unwrap(); cur.append(p4.clone(), &create_test_branch_node()).unwrap(); tx.commit().unwrap(); @@ -1081,12 +1083,12 @@ mod tests { { let tx = db.tx().unwrap(); let job = InitializationJob::new(store.clone(), tx); - job.initialize_accounts_trie(Some(p2.clone())).unwrap(); + job.initialize_accounts_trie(Some(StoredNibbles::from(p2.clone()))).unwrap(); } assert_eq!( store.initial_state_anchor().expect("get anchor").latest_account_trie_key, - Some(p4.clone()) + Some(StoredNibbles::from(p4.clone())) ); // Verify 4 ordered, no dupes diff --git a/rust/op-reth/crates/trie/src/provider.rs b/rust/op-reth/crates/trie/src/provider.rs index ee2ce3881ce..fd52b3e71ca 100644 --- a/rust/op-reth/crates/trie/src/provider.rs +++ b/rust/op-reth/crates/trie/src/provider.rs @@ -196,14 +196,6 @@ where { fn storage(&self, address: Address, storage_key: B256) -> ProviderResult> { let hashed_key = keccak256(storage_key); - self.storage_by_hashed_key(address, hashed_key) - } - - fn storage_by_hashed_key( - &self, - address: Address, - hashed_key: B256, - ) -> ProviderResult> { Ok(self .storage .storage_hashed_cursor(keccak256(address.0), self.block_number) diff --git a/rust/op-reth/crates/txpool/src/pool.rs b/rust/op-reth/crates/txpool/src/pool.rs index 6b0398e603d..598c77b0354 100644 --- a/rust/op-reth/crates/txpool/src/pool.rs +++ b/rust/op-reth/crates/txpool/src/pool.rs @@ -287,10 +287,9 @@ where delegate!(async fn add_transaction(&self, origin: TransactionOrigin, transaction: Self::Transaction) -> PoolResult); delegate!(async fn add_transactions(&self, origin: TransactionOrigin, transactions: Vec) -> Vec>); - // Cannot delegate via macro: `impl IntoIterator` arg not matchable by macro `:ty`. async fn add_transactions_with_origins( &self, - transactions: impl IntoIterator + Send, + transactions: Vec<(TransactionOrigin, Self::Transaction)>, ) -> Vec> { self.inner.add_transactions_with_origins(transactions).await } diff --git a/rust/op-reth/crates/txpool/src/transaction.rs b/rust/op-reth/crates/txpool/src/transaction.rs index 1ed83561047..8271e26a81f 100644 --- a/rust/op-reth/crates/txpool/src/transaction.rs +++ b/rust/op-reth/crates/txpool/src/transaction.rs @@ -134,6 +134,10 @@ where self.inner.transaction().clone() } + fn consensus_ref(&self) -> Recovered<&Self::Consensus> { + Recovered::new_unchecked(self.inner.transaction.inner(), self.inner.transaction.signer()) + } + fn into_consensus(self) -> Recovered { self.inner.transaction } diff --git a/rust/op-reth/examples/custom-node/Cargo.toml b/rust/op-reth/examples/custom-node/Cargo.toml index 13acd70ef3d..2114178082d 100644 --- a/rust/op-reth/examples/custom-node/Cargo.toml +++ b/rust/op-reth/examples/custom-node/Cargo.toml @@ -19,6 +19,11 @@ reth-rpc-api.workspace = true reth-engine-primitives.workspace = true reth-rpc-engine-api.workspace = true reth-ethereum = { workspace = true, features = ["node-api", "network", "evm", "pool", "trie", "storage-api", "provider"] } +reth-node-api.workspace = true +reth-payload-primitives.workspace = true +reth-primitives-traits.workspace = true +reth-provider.workspace = true +reth-trie-common.workspace = true # revm revm.workspace = true @@ -30,6 +35,7 @@ alloy-eips.workspace = true alloy-evm.workspace = true alloy-genesis.workspace = true alloy-op-evm.workspace = true +reth-evm.workspace = true reth-optimism-evm.workspace = true alloy-primitives.workspace = true alloy-rlp.workspace = true @@ -68,5 +74,8 @@ arbitrary = [ "reth-db-api/arbitrary", "alloy-rpc-types-eth/arbitrary", "op-alloy-rpc-types/arbitrary", + "alloy-op-evm/arbitrary", + "reth-primitives-traits/arbitrary", + "reth-trie-common/arbitrary", ] default = [] diff --git a/rust/op-reth/examples/custom-node/src/chainspec.rs b/rust/op-reth/examples/custom-node/src/chainspec.rs index 4291b3549e4..b8c63f4e137 100644 --- a/rust/op-reth/examples/custom-node/src/chainspec.rs +++ b/rust/op-reth/examples/custom-node/src/chainspec.rs @@ -1,12 +1,9 @@ use crate::primitives::CustomHeader; use alloy_genesis::Genesis; -use reth_ethereum::{ - chainspec::{EthChainSpec, EthereumHardforks, Hardfork, Hardforks}, - primitives::SealedHeader, -}; use reth_network_peers::NodeRecord; -use reth_op::chainspec::OpChainSpec; +use reth_op::chainspec::{EthChainSpec, EthereumHardforks, Hardfork, Hardforks, OpChainSpec}; use reth_optimism_forks::OpHardforks; +use reth_primitives_traits::SealedHeader; #[derive(Debug, Clone)] pub struct CustomChainSpec { @@ -21,28 +18,25 @@ impl CustomChainSpec { } impl Hardforks for CustomChainSpec { - fn fork(&self, fork: H) -> reth_ethereum::chainspec::ForkCondition { + fn fork(&self, fork: H) -> reth_op::chainspec::ForkCondition { self.inner.fork(fork) } fn forks_iter( &self, - ) -> impl Iterator { + ) -> impl Iterator { self.inner.forks_iter() } - fn fork_id(&self, head: &reth_ethereum::chainspec::Head) -> reth_ethereum::chainspec::ForkId { + fn fork_id(&self, head: &reth_op::chainspec::Head) -> reth_op::chainspec::ForkId { self.inner.fork_id(head) } - fn latest_fork_id(&self) -> reth_ethereum::chainspec::ForkId { + fn latest_fork_id(&self) -> reth_op::chainspec::ForkId { self.inner.latest_fork_id() } - fn fork_filter( - &self, - head: reth_ethereum::chainspec::Head, - ) -> reth_ethereum::chainspec::ForkFilter { + fn fork_filter(&self, head: reth_op::chainspec::Head) -> reth_op::chainspec::ForkFilter { self.inner.fork_filter(head) } } @@ -50,14 +44,11 @@ impl Hardforks for CustomChainSpec { impl EthChainSpec for CustomChainSpec { type Header = CustomHeader; - fn chain(&self) -> reth_ethereum::chainspec::Chain { + fn chain(&self) -> reth_op::chainspec::Chain { self.inner.chain() } - fn base_fee_params_at_timestamp( - &self, - timestamp: u64, - ) -> reth_ethereum::chainspec::BaseFeeParams { + fn base_fee_params_at_timestamp(&self, timestamp: u64) -> reth_op::chainspec::BaseFeeParams { self.inner.base_fee_params_at_timestamp(timestamp) } @@ -65,7 +56,7 @@ impl EthChainSpec for CustomChainSpec { self.inner.blob_params_at_timestamp(timestamp) } - fn deposit_contract(&self) -> Option<&reth_ethereum::chainspec::DepositContract> { + fn deposit_contract(&self) -> Option<&reth_op::chainspec::DepositContract> { self.inner.deposit_contract() } @@ -101,8 +92,8 @@ impl EthChainSpec for CustomChainSpec { impl EthereumHardforks for CustomChainSpec { fn ethereum_fork_activation( &self, - fork: reth_ethereum::chainspec::EthereumHardfork, - ) -> reth_ethereum::chainspec::ForkCondition { + fork: reth_op::chainspec::EthereumHardfork, + ) -> reth_op::chainspec::ForkCondition { self.inner.ethereum_fork_activation(fork) } } @@ -111,7 +102,7 @@ impl OpHardforks for CustomChainSpec { fn op_fork_activation( &self, fork: reth_optimism_forks::OpHardfork, - ) -> reth_ethereum::chainspec::ForkCondition { + ) -> reth_op::chainspec::ForkCondition { self.inner.op_fork_activation(fork) } } diff --git a/rust/op-reth/examples/custom-node/src/engine.rs b/rust/op-reth/examples/custom-node/src/engine.rs index 821e890a2a9..327db93c3e5 100644 --- a/rust/op-reth/examples/custom-node/src/engine.rs +++ b/rust/op-reth/examples/custom-node/src/engine.rs @@ -6,24 +6,27 @@ use crate::{ }; use alloy_eips::eip2718::WithEncoded; use alloy_primitives::Bytes; +use alloy_rpc_types_engine::PayloadId; use op_alloy_rpc_types_engine::{OpExecutionData, OpExecutionPayload}; use reth_engine_primitives::EngineApiValidator; -use reth_ethereum::{ - node::api::{ - AddOnsContext, BuiltPayload, BuiltPayloadExecutedBlock, EngineApiMessageVersion, - EngineObjectValidationError, ExecutionPayload, FullNodeComponents, NewPayloadError, - NodePrimitives, PayloadAttributes, PayloadBuilderAttributes, PayloadOrAttributes, - PayloadTypes, PayloadValidator, validate_version_specific_fields, +use reth_node_api::{ + AddOnsContext, BuiltPayload, BuiltPayloadExecutedBlock, FullNodeComponents, NodePrimitives, + PayloadValidator, + payload::{ + EngineApiMessageVersion, EngineObjectValidationError, ExecutionPayload, NewPayloadError, + PayloadOrAttributes, PayloadTypes, }, - primitives::SealedBlock, - storage::StateProviderFactory, - trie::{KeccakKeyHasher, KeyHasher}, + validate_version_specific_fields, }; use reth_node_builder::{InvalidPayloadAttributesError, rpc::PayloadValidatorBuilder}; use reth_op::node::{ OpBuiltPayload, OpEngineTypes, OpPayloadAttributes, OpPayloadBuilderAttributes, engine::OpEngineValidator, payload::OpAttributes, }; +use reth_payload_builder::PayloadBuilderError; +use reth_primitives_traits::SealedBlock; +use reth_provider::StateProviderFactory; +use reth_trie_common::{KeccakKeyHasher, KeyHasher}; use revm_primitives::U256; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -64,11 +67,11 @@ impl ExecutionPayload for CustomExecutionData { } fn timestamp(&self) -> u64 { - self.inner.timestamp() + self.inner.payload.timestamp() } fn gas_used(&self) -> u64 { - self.inner.gas_used() + self.inner.payload.as_v1().gas_used } fn transaction_count(&self) -> usize { @@ -90,22 +93,8 @@ impl TryFrom<&reth_optimism_flashblocks::FlashBlockCompleteSequence> for CustomE #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CustomPayloadAttributes { #[serde(flatten)] - inner: OpPayloadAttributes, - extension: u64, -} - -impl PayloadAttributes for CustomPayloadAttributes { - fn timestamp(&self) -> u64 { - self.inner.timestamp() - } - - fn withdrawals(&self) -> Option<&Vec> { - self.inner.withdrawals() - } - - fn parent_beacon_block_root(&self) -> Option { - self.inner.parent_beacon_block_root() - } + pub inner: OpPayloadAttributes, + pub extension: u64, } #[derive(Debug, Clone)] @@ -114,55 +103,35 @@ pub struct CustomPayloadBuilderAttributes { pub extension: u64, } -impl PayloadBuilderAttributes for CustomPayloadBuilderAttributes { +impl OpAttributes for CustomPayloadBuilderAttributes { + type Transaction = CustomTransaction; type RpcPayloadAttributes = CustomPayloadAttributes; - type Error = alloy_rlp::Error; fn try_new( parent: revm_primitives::B256, - rpc_payload_attributes: Self::RpcPayloadAttributes, + attributes: Self::RpcPayloadAttributes, version: u8, - ) -> Result + ) -> Result where Self: Sized, { - let CustomPayloadAttributes { inner, extension } = rpc_payload_attributes; - - Ok(Self { inner: OpPayloadBuilderAttributes::try_new(parent, inner, version)?, extension }) - } + let CustomPayloadAttributes { inner, extension } = attributes; - fn payload_id(&self) -> alloy_rpc_types_engine::PayloadId { - self.inner.payload_id() + Ok(Self { + inner: OpPayloadBuilderAttributes::try_new(parent, inner, version) + .map_err(PayloadBuilderError::other)?, + extension, + }) } - fn parent(&self) -> revm_primitives::B256 { - self.inner.parent() + fn payload_id(&self) -> PayloadId { + self.inner.id } fn timestamp(&self) -> u64 { - self.inner.timestamp() + self.inner.timestamp } - fn parent_beacon_block_root(&self) -> Option { - self.inner.parent_beacon_block_root() - } - - fn suggested_fee_recipient(&self) -> revm_primitives::Address { - self.inner.suggested_fee_recipient() - } - - fn prev_randao(&self) -> revm_primitives::B256 { - self.inner.prev_randao() - } - - fn withdrawals(&self) -> &alloy_eips::eip4895::Withdrawals { - self.inner.withdrawals() - } -} - -impl OpAttributes for CustomPayloadBuilderAttributes { - type Transaction = CustomTransaction; - fn no_tx_pool(&self) -> bool { self.inner.no_tx_pool } @@ -206,8 +175,7 @@ impl From impl PayloadTypes for CustomPayloadTypes { type ExecutionData = CustomExecutionData; type BuiltPayload = OpBuiltPayload; - type PayloadAttributes = CustomPayloadAttributes; - type PayloadBuilderAttributes = CustomPayloadBuilderAttributes; + type PayloadAttributes = reth_op::node::payload::OpPayloadAttrs; fn block_to_payload( block: SealedBlock< @@ -252,8 +220,8 @@ where fn validate_payload_attributes_against_header( &self, - _attr: &CustomPayloadAttributes, - _header: &::Header, + _attr: &reth_op::node::payload::OpPayloadAttrs, + _header: &::Header, ) -> Result<(), InvalidPayloadAttributesError> { // skip default timestamp validation Ok(()) @@ -265,7 +233,7 @@ where ) -> Result, NewPayloadError> { let sealed_block = PayloadValidator::::convert_payload_to_block( &self.inner, - payload.inner, + reth_op::node::payload::OpExecData(payload.inner), )?; let (header, body) = sealed_block.split_sealed_header_body(); let header = CustomHeader { inner: header.into_header(), extension: payload.extension }; @@ -281,7 +249,11 @@ where fn validate_version_specific_fields( &self, version: EngineApiMessageVersion, - payload_or_attrs: PayloadOrAttributes<'_, CustomExecutionData, CustomPayloadAttributes>, + payload_or_attrs: PayloadOrAttributes< + '_, + CustomExecutionData, + reth_op::node::payload::OpPayloadAttrs, + >, ) -> Result<(), EngineObjectValidationError> { validate_version_specific_fields(self.chain_spec(), version, payload_or_attrs) } @@ -289,7 +261,7 @@ where fn ensure_well_formed_attributes( &self, version: EngineApiMessageVersion, - attributes: &CustomPayloadAttributes, + attributes: &reth_op::node::payload::OpPayloadAttrs, ) -> Result<(), EngineObjectValidationError> { validate_version_specific_fields( self.chain_spec(), diff --git a/rust/op-reth/examples/custom-node/src/engine_api.rs b/rust/op-reth/examples/custom-node/src/engine_api.rs index 0aec72ecd01..88a930a288a 100644 --- a/rust/op-reth/examples/custom-node/src/engine_api.rs +++ b/rust/op-reth/examples/custom-node/src/engine_api.rs @@ -8,9 +8,8 @@ use alloy_rpc_types_engine::{ }; use async_trait::async_trait; use jsonrpsee::{RpcModule, core::RpcResult, proc_macros::rpc}; -use reth_ethereum::node::api::{ - AddOnsContext, ConsensusEngineHandle, EngineApiMessageVersion, FullNodeComponents, -}; +use reth_engine_primitives::ConsensusEngineHandle; +use reth_node_api::{AddOnsContext, FullNodeComponents}; use reth_node_builder::rpc::EngineApiBuilder; use reth_op::node::OpBuiltPayload; use reth_payload_builder::PayloadStore; @@ -95,7 +94,10 @@ impl CustomEngineApiServer for CustomEngineApi { Ok(self .inner .beacon_consensus - .fork_choice_updated(fork_choice_state, payload_attributes, EngineApiMessageVersion::V3) + .fork_choice_updated( + fork_choice_state, + payload_attributes.map(|a| reth_op::node::payload::OpPayloadAttrs(a.inner)), + ) .await .map_err(EngineApiError::ForkChoiceUpdate)?) } diff --git a/rust/op-reth/examples/custom-node/src/evm/alloy.rs b/rust/op-reth/examples/custom-node/src/evm/alloy.rs index 6acca149569..7f95c898fd3 100644 --- a/rust/op-reth/examples/custom-node/src/evm/alloy.rs +++ b/rust/op-reth/examples/custom-node/src/evm/alloy.rs @@ -1,17 +1,18 @@ use crate::evm::{CustomTxEnv, PaymentTxEnv}; use alloy_evm::{Database, Evm, EvmEnv, EvmFactory, precompiles::PrecompilesMap}; -use alloy_op_evm::{OpEvm, OpEvmFactory, OpTxError}; +use alloy_op_evm::{OpEvm, OpEvmFactory, OpTx, OpTxError}; use alloy_primitives::{Address, Bytes}; use op_revm::{ L1BlockInfo, OpContext, OpHaltReason, OpSpecId, OpTransaction, precompiles::OpPrecompiles, }; -use reth_ethereum::evm::revm::{ +use revm::{ Context, Inspector, Journal, context::{BlockEnv, CfgEnv, result::ResultAndState}, + context_interface::result::EVMError, handler::PrecompileProvider, + inspector::NoOpInspector, interpreter::InterpreterResult, }; -use revm::{context_interface::result::EVMError, inspector::NoOpInspector}; use std::error::Error; /// EVM context contains data that EVM needs for execution of [`CustomTxEnv`]. @@ -19,11 +20,11 @@ pub type CustomContext = Context, CfgEnv, DB, Journal, L1BlockInfo>; pub struct CustomEvm { - inner: OpEvm, + inner: OpEvm, } impl CustomEvm { - pub fn new(op: OpEvm) -> Self { + pub fn new(op: OpEvm) -> Self { Self { inner: op } } } @@ -56,7 +57,7 @@ where tx: Self::Tx, ) -> Result, Self::Error> { match tx { - CustomTxEnv::Op(tx) => self.inner.transact_raw(tx.into()), + CustomTxEnv::Op(tx) => self.inner.transact_raw(tx), CustomTxEnv::Payment(..) => todo!(), } } diff --git a/rust/op-reth/examples/custom-node/src/evm/assembler.rs b/rust/op-reth/examples/custom-node/src/evm/assembler.rs index 2fb06eb8dc9..1be3b9d044c 100644 --- a/rust/op-reth/examples/custom-node/src/evm/assembler.rs +++ b/rust/op-reth/examples/custom-node/src/evm/assembler.rs @@ -4,11 +4,12 @@ use crate::{ primitives::{Block, CustomHeader, CustomTransaction}, }; use alloy_evm::block::{BlockExecutionError, BlockExecutorFactory}; -use reth_ethereum::{ +use reth_op::{ + DepositReceipt, evm::primitives::execute::{BlockAssembler, BlockAssemblerInput}, - primitives::Receipt, + node::OpBlockAssembler, }; -use reth_op::{DepositReceipt, node::OpBlockAssembler}; +use reth_primitives_traits::Receipt; use std::sync::Arc; #[derive(Clone, Debug)] diff --git a/rust/op-reth/examples/custom-node/src/evm/builder.rs b/rust/op-reth/examples/custom-node/src/evm/builder.rs index 4be3253b9d5..aeeea2c9fff 100644 --- a/rust/op-reth/examples/custom-node/src/evm/builder.rs +++ b/rust/op-reth/examples/custom-node/src/evm/builder.rs @@ -1,5 +1,5 @@ use crate::{chainspec::CustomChainSpec, evm::CustomEvmConfig, primitives::CustomNodePrimitives}; -use reth_ethereum::node::api::FullNodeTypes; +use reth_node_api::FullNodeTypes; use reth_node_builder::{BuilderContext, NodeTypes, components::ExecutorBuilder}; use std::{future, future::Future}; diff --git a/rust/op-reth/examples/custom-node/src/evm/config.rs b/rust/op-reth/examples/custom-node/src/evm/config.rs index 094e0b48de5..e505845f621 100644 --- a/rust/op-reth/examples/custom-node/src/evm/config.rs +++ b/rust/op-reth/examples/custom-node/src/evm/config.rs @@ -12,18 +12,14 @@ use alloy_rpc_types_engine::PayloadError; use op_alloy_rpc_types_engine::flashblock::OpFlashblockPayloadBase; use op_revm::OpSpecId; use reth_engine_primitives::ExecutableTxIterator; -use reth_ethereum::{ - chainspec::EthChainSpec, - node::api::{BuildNextEnv, ConfigureEvm, PayloadBuilderError}, - primitives::{SealedBlock, SealedHeader}, -}; +use reth_node_api::{BuildNextEnv, ConfigureEvm, PayloadBuilderError}; use reth_node_builder::{ConfigureEngineEvm, NewPayloadError}; use reth_op::{ - chainspec::OpHardforks, + chainspec::{EthChainSpec, OpHardforks}, evm::primitives::{EvmEnvFor, ExecutionCtxFor}, node::{OpEvmConfig, OpNextBlockEnvAttributes, OpRethReceiptBuilder}, - primitives::SignedTransaction, }; +use reth_primitives_traits::{SealedBlock, SealedHeader, SignedTransaction}; use reth_rpc_api::eth::helpers::pending_block::BuildPendingEnv; use revm_primitives::Bytes; use std::sync::Arc; @@ -178,3 +174,21 @@ where Ok(CustomNextBlockEnvAttributes { inner, extension: attributes.extension }) } } + +impl + BuildNextEnv, H, ChainSpec> + for CustomNextBlockEnvAttributes +where + H: BlockHeader, + ChainSpec: EthChainSpec + OpHardforks, +{ + fn build_next_env( + attributes: &reth_op::node::OpPayloadBuilderAttributes, + parent: &SealedHeader, + chain_spec: &ChainSpec, + ) -> Result { + let inner = OpNextBlockEnvAttributes::build_next_env(attributes, parent, chain_spec)?; + + Ok(CustomNextBlockEnvAttributes { inner, extension: 0 }) + } +} diff --git a/rust/op-reth/examples/custom-node/src/evm/env.rs b/rust/op-reth/examples/custom-node/src/evm/env.rs index e7296243f3f..c71c6daba48 100644 --- a/rust/op-reth/examples/custom-node/src/evm/env.rs +++ b/rust/op-reth/examples/custom-node/src/evm/env.rs @@ -1,16 +1,16 @@ use crate::primitives::{CustomTransaction, TxPayment}; use alloy_eips::{Typed2718, eip2930::AccessList}; -use alloy_evm::{FromRecoveredTx, FromTxWithEncoded, IntoTxEnv}; +use alloy_evm::{FromRecoveredTx, FromTxWithEncoded, IntoTxEnv, TransactionEnvMut}; use alloy_op_evm::block::OpTxEnv; use alloy_primitives::{Address, B256, Bytes, TxKind, U256}; use op_alloy_consensus::OpTxEnvelope; -use reth_ethereum::evm::{primitives::TransactionEnv, revm::context::TxEnv}; use reth_optimism_evm::OpTx; +use revm::context::TxEnv; /// An Optimism transaction extended by [`PaymentTxEnv`] that can be fed to [`Evm`]. /// /// [`Evm`]: alloy_evm::Evm -#[derive(Clone, Debug)] +#[derive(Clone, Debug, derive_more::From)] pub enum CustomTxEnv { Op(reth_optimism_evm::OpTx), Payment(PaymentTxEnv), @@ -210,15 +210,11 @@ impl revm::context::Transaction for PaymentTxEnv { } } -impl TransactionEnv for PaymentTxEnv { +impl TransactionEnvMut for PaymentTxEnv { fn set_gas_limit(&mut self, gas_limit: u64) { self.0.set_gas_limit(gas_limit); } - fn nonce(&self) -> u64 { - self.0.nonce() - } - fn set_nonce(&mut self, nonce: u64) { self.0.set_nonce(nonce); } @@ -228,7 +224,7 @@ impl TransactionEnv for PaymentTxEnv { } } -impl TransactionEnv for CustomTxEnv { +impl TransactionEnvMut for CustomTxEnv { fn set_gas_limit(&mut self, gas_limit: u64) { match self { Self::Op(tx) => tx.set_gas_limit(gas_limit), @@ -236,13 +232,6 @@ impl TransactionEnv for CustomTxEnv { } } - fn nonce(&self) -> u64 { - match self { - Self::Op(tx) => tx.nonce(), - Self::Payment(tx) => tx.nonce(), - } - } - fn set_nonce(&mut self, nonce: u64) { match self { Self::Op(tx) => tx.set_nonce(nonce), diff --git a/rust/op-reth/examples/custom-node/src/evm/executor.rs b/rust/op-reth/examples/custom-node/src/evm/executor.rs index e396f47fc4e..b61fd76eacb 100644 --- a/rust/op-reth/examples/custom-node/src/evm/executor.rs +++ b/rust/op-reth/examples/custom-node/src/evm/executor.rs @@ -7,27 +7,27 @@ use crate::{ }; use alloy_consensus::transaction::Recovered; use alloy_evm::{ - Database, Evm, RecoveredTx, + Evm, RecoveredTx, block::{ BlockExecutionError, BlockExecutionResult, BlockExecutor, BlockExecutorFactory, - BlockExecutorFor, ExecutableTx, OnStateHook, + BlockExecutorFor, ExecutableTx, OnStateHook, StateDB, }, precompiles::PrecompilesMap, }; use alloy_op_evm::{OpBlockExecutionCtx, OpBlockExecutor, block::OpTxResult}; -use reth_ethereum::evm::primitives::InspectorFor; +use op_revm::OpContext; use reth_op::{OpReceipt, OpTxType, chainspec::OpChainSpec, node::OpRethReceiptBuilder}; -use revm::database::State; +use revm::Inspector; use std::sync::Arc; pub struct CustomBlockExecutor { inner: OpBlockExecutor>, } -impl<'db, DB, E> BlockExecutor for CustomBlockExecutor +impl BlockExecutor for CustomBlockExecutor where - DB: Database + 'db, - E: Evm, Tx = CustomTxEnv>, + DB: StateDB, + E: Evm, { type Transaction = CustomTransaction; type Receipt = OpReceipt; @@ -88,12 +88,12 @@ impl BlockExecutorFactory for CustomEvmConfig { fn create_executor<'a, DB, I>( &'a self, - evm: CustomEvm<&'a mut State, I, PrecompilesMap>, + evm: CustomEvm, ctx: CustomBlockExecutionCtx, ) -> impl BlockExecutorFor<'a, Self, DB, I> where - DB: Database + 'a, - I: InspectorFor> + 'a, + DB: StateDB + 'a, + I: Inspector> + 'a, { CustomBlockExecutor { inner: OpBlockExecutor::new( diff --git a/rust/op-reth/examples/custom-node/src/lib.rs b/rust/op-reth/examples/custom-node/src/lib.rs index 9892f2af529..6023ee67515 100644 --- a/rust/op-reth/examples/custom-node/src/lib.rs +++ b/rust/op-reth/examples/custom-node/src/lib.rs @@ -7,6 +7,10 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// Required for feature forwarding +use reth_ethereum as _; +use reth_payload_primitives as _; + use crate::{ engine::{CustomEngineValidatorBuilder, CustomPayloadTypes}, engine_api::CustomEngineApiBuilder, @@ -17,9 +21,9 @@ use crate::{ }; use chainspec::CustomChainSpec; use primitives::CustomNodePrimitives; -use reth_ethereum::node::api::{FullNodeTypes, NodeTypes}; +use reth_node_api::FullNodeTypes; use reth_node_builder::{ - Node, NodeAdapter, + Node, NodeAdapter, NodeTypes, components::{BasicPayloadServiceBuilder, ComponentsBuilder}, }; use reth_op::{ diff --git a/rust/op-reth/examples/custom-node/src/pool.rs b/rust/op-reth/examples/custom-node/src/pool.rs index fad72be0d77..40a5248d980 100644 --- a/rust/op-reth/examples/custom-node/src/pool.rs +++ b/rust/op-reth/examples/custom-node/src/pool.rs @@ -7,9 +7,7 @@ use alloy_consensus::{ }; use alloy_primitives::{Address, B256, Sealed}; use op_alloy_consensus::{OpPooledTransaction, OpTransaction, TxDeposit}; -use reth_ethereum::primitives::{ - InMemorySize, SignedTransaction, serde_bincode_compat::RlpBincode, -}; +use reth_primitives_traits::InMemorySize; #[derive(Clone, Debug, TransactionEnvelope)] #[envelope(tx_type_name = CustomPooledTxType)] @@ -44,8 +42,6 @@ impl TryFrom for CustomPooledTransaction { } } -impl RlpBincode for CustomPooledTransaction {} - impl OpTransaction for CustomPooledTransaction { fn is_deposit(&self) -> bool { false @@ -81,8 +77,6 @@ impl TxHashRef for CustomPooledTransaction { } } -impl SignedTransaction for CustomPooledTransaction {} - impl InMemorySize for CustomPooledTransaction { fn size(&self) -> usize { match self { diff --git a/rust/op-reth/examples/custom-node/src/primitives/header.rs b/rust/op-reth/examples/custom-node/src/primitives/header.rs index beaa7626f00..049f655c6a4 100644 --- a/rust/op-reth/examples/custom-node/src/primitives/header.rs +++ b/rust/op-reth/examples/custom-node/src/primitives/header.rs @@ -2,7 +2,7 @@ use alloy_consensus::Header; use alloy_primitives::{Address, B64, B256, BlockNumber, Bloom, Bytes, Sealable, U256}; use alloy_rlp::{Encodable, RlpDecodable, RlpEncodable}; use reth_codecs::Compact; -use reth_ethereum::primitives::{BlockHeader, InMemorySize, serde_bincode_compat::RlpBincode}; +use reth_primitives_traits::{BlockHeader, InMemorySize}; use revm_primitives::keccak256; use serde::{Deserialize, Serialize}; @@ -173,12 +173,10 @@ impl reth_db_api::table::Compress for CustomHeader { } impl reth_db_api::table::Decompress for CustomHeader { - fn decompress(value: &[u8]) -> Result { + fn decompress(value: &[u8]) -> Result { let (obj, _) = Compact::from_compact(value, value.len()); Ok(obj) } } impl BlockHeader for CustomHeader {} - -impl RlpBincode for CustomHeader {} diff --git a/rust/op-reth/examples/custom-node/src/primitives/mod.rs b/rust/op-reth/examples/custom-node/src/primitives/mod.rs index 773ff4888cc..322f6f53392 100644 --- a/rust/op-reth/examples/custom-node/src/primitives/mod.rs +++ b/rust/op-reth/examples/custom-node/src/primitives/mod.rs @@ -12,8 +12,8 @@ pub use tx_type::*; pub mod tx_custom; pub use tx_custom::*; -use reth_ethereum::primitives::NodePrimitives; use reth_op::OpReceipt; +use reth_primitives_traits::NodePrimitives; #[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct CustomNodePrimitives; diff --git a/rust/op-reth/examples/custom-node/src/primitives/tx.rs b/rust/op-reth/examples/custom-node/src/primitives/tx.rs index 803d5d238b6..c0457be4bda 100644 --- a/rust/op-reth/examples/custom-node/src/primitives/tx.rs +++ b/rust/op-reth/examples/custom-node/src/primitives/tx.rs @@ -12,8 +12,8 @@ use reth_codecs::{ Compact, alloy::transaction::{CompactEnvelope, FromTxCompact, ToTxCompact}, }; -use reth_ethereum::primitives::{InMemorySize, serde_bincode_compat::RlpBincode}; -use reth_op::{OpTransaction, primitives::SignedTransaction}; +use reth_op::OpTransaction; +use reth_primitives_traits::InMemorySize; use revm_primitives::Address; /// Either [`OpTxEnvelope`] or [`TxPayment`]. @@ -28,8 +28,6 @@ pub enum CustomTransaction { Payment(Signed), } -impl RlpBincode for CustomTransaction {} - impl reth_codecs::alloy::transaction::Envelope for CustomTransaction { fn signature(&self) -> &Signature { match self { @@ -132,8 +130,6 @@ impl TxHashRef for CustomTransaction { } } -impl SignedTransaction for CustomTransaction {} - impl InMemorySize for CustomTransaction { fn size(&self) -> usize { match self { diff --git a/rust/op-reth/examples/custom-node/src/primitives/tx_custom.rs b/rust/op-reth/examples/custom-node/src/primitives/tx_custom.rs index d65012df171..bad998bc337 100644 --- a/rust/op-reth/examples/custom-node/src/primitives/tx_custom.rs +++ b/rust/op-reth/examples/custom-node/src/primitives/tx_custom.rs @@ -6,7 +6,7 @@ use alloy_consensus::{ use alloy_eips::{Typed2718, eip2930::AccessList, eip7702::SignedAuthorization}; use alloy_primitives::{Address, B256, Bytes, ChainId, Signature, TxKind, U256}; use alloy_rlp::{BufMut, Decodable, Encodable}; -use reth_ethereum::primitives::{InMemorySize, serde_bincode_compat::RlpBincode}; +use reth_primitives_traits::InMemorySize; /// A transaction with a priority fee ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)). #[derive( @@ -276,5 +276,3 @@ impl InMemorySize for TxPayment { TxPayment::size(self) } } - -impl RlpBincode for TxPayment {} diff --git a/rust/op-reth/examples/custom-node/src/rpc.rs b/rust/op-reth/examples/custom-node/src/rpc.rs index da8add0f0bf..9f51f0f0fe9 100644 --- a/rust/op-reth/examples/custom-node/src/rpc.rs +++ b/rust/op-reth/examples/custom-node/src/rpc.rs @@ -3,15 +3,11 @@ use crate::{ primitives::{CustomHeader, CustomTransaction}, }; use alloy_consensus::error::ValueError; -use alloy_evm::EvmEnv; use alloy_network::TxSigner; use op_alloy_consensus::OpTxEnvelope; use op_alloy_rpc_types::{OpTransactionReceipt, OpTransactionRequest}; use reth_op::rpc::RpcTypes; -use reth_rpc_api::eth::{ - EthTxEnvError, SignTxRequestError, SignableTxRequest, TryIntoSimTx, TryIntoTxEnv, -}; -use revm::context::BlockEnv; +use reth_rpc_api::eth::{SignTxRequestError, SignableTxRequest, TryIntoSimTx}; #[derive(Debug, Clone, Copy, Default)] #[non_exhaustive] @@ -30,14 +26,31 @@ impl TryIntoSimTx for OpTransactionRequest { } } -impl TryIntoTxEnv for OpTransactionRequest { - type Err = EthTxEnvError; +/// Custom `TxEnvConverter` that converts [`OpTransactionRequest`] into [`CustomTxEnv`]. +#[derive(Debug, Clone, Copy, Default)] +pub struct CustomTxEnvConverter; + +impl reth_rpc_api::eth::transaction::TxEnvConverter + for CustomTxEnvConverter +where + Evm: reth_evm::ConfigureEvm, + reth_evm::TxEnvFor: From, +{ + type Error = alloy_evm::rpc::EthTxEnvError; - fn try_into_tx_env( - self, - evm_env: &EvmEnv, - ) -> Result { - Ok(CustomTxEnv::Op(reth_optimism_evm::OpTx(self.try_into_tx_env(evm_env)?))) + fn convert_tx_env( + &self, + req: OpTransactionRequest, + evm_env: &reth_evm::EvmEnvFor, + ) -> Result, Self::Error> { + use alloy_evm::rpc::TryIntoTxEnv; + let base: revm::context::TxEnv = req.as_ref().clone().try_into_tx_env(evm_env)?; + let op_tx = reth_optimism_evm::OpTx(op_revm::OpTransaction { + base, + enveloped_tx: Some(alloy_primitives::Bytes::new()), + deposit: Default::default(), + }); + Ok(CustomTxEnv::Op(op_tx).into()) } } diff --git a/rust/op-reth/examples/engine-api-access/Cargo.toml b/rust/op-reth/examples/engine-api-access/Cargo.toml index 3e1f185077f..6a5422eb803 100644 --- a/rust/op-reth/examples/engine-api-access/Cargo.toml +++ b/rust/op-reth/examples/engine-api-access/Cargo.toml @@ -7,7 +7,7 @@ license.workspace = true [dependencies] # reth -reth-db = { workspace = true, features = ["op", "test-utils"] } +reth-db = { workspace = true, features = ["test-utils"] } reth-node-builder.workspace = true reth-optimism-node.workspace = true reth-optimism-chainspec.workspace = true diff --git a/rust/op-reth/tests/proofs/core/execute_payload_test.go b/rust/op-reth/tests/proofs/core/execute_payload_test.go index 5ad4eccd96d..d4e3d5e7986 100644 --- a/rust/op-reth/tests/proofs/core/execute_payload_test.go +++ b/rust/op-reth/tests/proofs/core/execute_payload_test.go @@ -17,6 +17,13 @@ func TestExecutePayloadSuccess(gt *testing.T) { user := sys.FunderL2.NewFundedEOA(eth.OneHundredthEther) opRethELNode := sys.RethWithProofL2ELNode() + // Wait for the validator's EL head to reach the sequencer's head. + seqHead, err := sys.L2ELSequencerNode().Escape().L2EthClient().InfoByLabel(ctx, eth.Unsafe) + if err != nil { + gt.Fatal(err) + } + sys.L2ELValidatorNode().WaitForBlockNumber(seqHead.NumberU64()) + plannedTxOption := user.PlanTransfer(user.Address(), eth.OneWei) plannedTx := txplan.NewPlannedTx(plannedTxOption) signedTx, err := plannedTx.Signed.Eval(ctx) @@ -34,6 +41,12 @@ func TestExecutePayloadSuccess(gt *testing.T) { gt.Fatal(err) } + // Wait for the proofs ExEx store to index the parent block. The ExEx processes + // ChainCommitted notifications asynchronously, so the EL head can advance before + // the store is ready. debug_executePayload reads from the ExEx store and will + // fail with "no state found" if it hasn't caught up yet. + utils.WaitForProofsStoreBlock(t, opRethELNode.Escape().L2EthClient(), lastBlock.NumberU64()) + blockTime := lastBlock.Time() + 1 gasLimit := eth.Uint64Quantity(lastBlock.GasLimit()) @@ -72,6 +85,13 @@ func TestExecutePayloadWithInvalidParentHash(gt *testing.T) { user := sys.FunderL2.NewFundedEOA(eth.OneHundredthEther) opRethELNode := sys.RethWithProofL2ELNode() + // Wait for the validator's EL head to reach the sequencer's head. + seqHead, err := sys.L2ELSequencerNode().Escape().L2EthClient().InfoByLabel(ctx, eth.Unsafe) + if err != nil { + gt.Fatal(err) + } + sys.L2ELValidatorNode().WaitForBlockNumber(seqHead.NumberU64()) + plannedTxOption := user.PlanTransfer(user.Address(), eth.OneWei) plannedTx := txplan.NewPlannedTx(plannedTxOption) signedTx, err := plannedTx.Signed.Eval(ctx) @@ -89,6 +109,9 @@ func TestExecutePayloadWithInvalidParentHash(gt *testing.T) { gt.Fatal(err) } + // Wait for the proofs ExEx store to index the parent block (same race as TestExecutePayloadSuccess). + utils.WaitForProofsStoreBlock(t, opRethELNode.Escape().L2EthClient(), lastBlock.NumberU64()) + blockTime := lastBlock.Time() + 1 gasLimit := eth.Uint64Quantity(lastBlock.GasLimit()) diff --git a/rust/op-reth/tests/proofs/utils/utils.go b/rust/op-reth/tests/proofs/utils/utils.go index e47fdc47e15..10e79d4ffc1 100644 --- a/rust/op-reth/tests/proofs/utils/utils.go +++ b/rust/op-reth/tests/proofs/utils/utils.go @@ -4,9 +4,11 @@ import ( "encoding/json" "os" "strings" + "time" "github.com/ethereum-optimism/optimism/op-devstack/devtest" "github.com/ethereum-optimism/optimism/op-devstack/dsl" + "github.com/ethereum-optimism/optimism/op-service/apis" "github.com/ethereum-optimism/optimism/op-service/txplan" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -49,6 +51,33 @@ func LoadArtifact(t devtest.T, artifactPath string) (abi.ABI, []byte) { return parsedABI, common.FromHex(binHex) } +// WaitForProofsStoreBlock polls the op-reth debug_proofsSyncStatus RPC until the +// proofs ExEx store has indexed at least up to targetBlock. The ExEx processes +// ChainCommitted notifications asynchronously, so the EL head can advance before +// the proofs store has caught up. Any RPC that depends on OpStateProviderFactory +// (e.g. debug_executePayload) will fail with "no state found" if called before +// the store is ready. +func WaitForProofsStoreBlock(t devtest.T, client apis.EthClient, targetBlock uint64) { + type syncStatus struct { + Earliest *uint64 `json:"earliest"` + Latest *uint64 `json:"latest"` + } + require.Eventually(t, func() bool { + var status syncStatus + err := client.RPC().CallContext(t.Ctx(), &status, "debug_proofsSyncStatus") + if err != nil { + t.Logf("debug_proofsSyncStatus call failed (retrying): %v", err) + return false + } + if status.Latest == nil { + t.Logf("proofs store not yet initialized, waiting...") + return false + } + t.Logf("proofs store status: latest=%d target=%d", *status.Latest, targetBlock) + return *status.Latest >= targetBlock + }, 30*time.Second, 200*time.Millisecond, "proofs store did not index block %d in time", targetBlock) +} + // DeployContract deploys the contract creation bytecode from the given artifact. // user must provide a Plan() method compatible with txplan.NewPlannedTx (kept generic). func DeployContract(t devtest.T, user *dsl.EOA, bin []byte) (common.Address, *types.Receipt) { diff --git a/rust/op-revm/README.md b/rust/op-revm/README.md new file mode 100644 index 00000000000..d36dcb73681 --- /dev/null +++ b/rust/op-revm/README.md @@ -0,0 +1,57 @@ +# op-revm + +Optimism variant of [revm](https://github.com/bluealloy/revm) — the OP Stack's +modifications to the Ethereum Virtual Machine, packaged as a custom EVM built +on top of the upstream `revm` framework. + +`op-revm` adds: + +- Deposit transactions and the deposit transaction type +- L1 cost / blob fee accounting (`L1BlockInfo`) +- Operator fee handling (Isthmus / Jovian) +- OP-specific precompiles (BN254 pairing acceleration, etc.) +- OP-specific halt reasons and transaction errors +- Hardfork-aware spec selection (`OpSpecId`) + +## Provenance + +This crate is a vendored copy of upstream +[`bluealloy/revm`'s `crates/op-revm`](https://github.com/bluealloy/revm/tree/main/crates/op-revm) +imported into the monorepo so it can evolve in lock-step with the rest of the +OP Stack Rust code. See [`CHANGELOG.md`](./CHANGELOG.md) for the upstream +release history. + +## Features + +- `default = ["std", "c-kzg", "secp256k1", "portable", "blst"]` +- `std` — enables `std`-dependent features in `revm`, `alloy-primitives`, + `serde_json`, etc. +- `serde` — derives `serde` impls and forwards to `revm/serde` and + `alloy-primitives/serde` +- `portable`, `c-kzg`, `secp256k1`, `blst`, `bn` — pass-through feature gates + to the corresponding `revm` cryptographic backends +- `dev`, `memory_limit`, `optional_balance_check`, `optional_block_gas_limit`, + `optional_eip3541`, `optional_eip3607`, `optional_no_base_fee`, + `optional_fee_charge` — debugging / testing knobs forwarded to `revm` + +## Building & Testing + +From `rust/`: + +```bash +# Build +cargo build -p op-revm + +# Tests +cargo nextest run -p op-revm --all-features + +# no_std check (mirrors upstream's riscv32imac CI) +cargo build -p op-revm --target riscv32imac-unknown-none-elf --no-default-features +``` + +The no_std build is also exercised by `just check-no-std` and runs in CI on +every PR that touches `rust/**`. + +## License + +MIT — see [`LICENSE`](./LICENSE). diff --git a/rust/rust-toolchain.toml b/rust/rust-toolchain.toml index 2e7fc42a6e2..c8171d2b782 100644 --- a/rust/rust-toolchain.toml +++ b/rust/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] # /ops/docker/op-stack-go/Dockerfile must match this version. -channel = "1.92" +channel = "1.94" diff --git a/rust/typos.toml b/rust/typos.toml index b3f237d9a9f..a2706bc6ed2 100644 --- a/rust/typos.toml +++ b/rust/typos.toml @@ -7,6 +7,7 @@ extend-exclude = [ "docs/docs/dist/", "*.min.js", "op-alloy/CHANGELOG.md", + "op-revm/CHANGELOG.md", "op-reth/crates/storage/libmdbx-rs/mdbx-sys/libmdbx", "op-reth/testing/ef-tests", ] diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 00000000000..b3d5771dc5b --- /dev/null +++ b/src/api.rs @@ -0,0 +1,9 @@ +//! Optimism API types. + +pub mod builder; +pub mod default_ctx; +pub mod exec; + +pub use builder::OpBuilder; +pub use default_ctx::DefaultOp; +pub use exec::{OpContextTr, OpError}; diff --git a/src/api/builder.rs b/src/api/builder.rs new file mode 100644 index 00000000000..b4966cdc1aa --- /dev/null +++ b/src/api/builder.rs @@ -0,0 +1,45 @@ +//! Optimism builder trait [`OpBuilder`] used to build [`OpEvm`]. +use crate::{L1BlockInfo, OpSpecId, evm::OpEvm, precompiles::OpPrecompiles, transaction::OpTxTr}; +use revm::{ + Context, Database, + context::Cfg, + context_interface::{Block, JournalTr}, + handler::instructions::EthInstructions, + interpreter::interpreter::EthInterpreter, + state::EvmState, +}; + +/// Type alias for default `OpEvm` +pub type DefaultOpEvm = + OpEvm, OpPrecompiles>; + +/// Trait that allows for optimism `OpEvm` to be built. +pub trait OpBuilder: Sized { + /// Type of the context. + type Context; + + /// Build the op. + fn build_op(self) -> DefaultOpEvm; + + /// Build the op with an inspector. + fn build_op_with_inspector(self, inspector: INSP) -> DefaultOpEvm; +} + +impl OpBuilder for Context +where + BLOCK: Block, + TX: OpTxTr, + CFG: Cfg, + DB: Database, + JOURNAL: JournalTr, +{ + type Context = Self; + + fn build_op(self) -> DefaultOpEvm { + OpEvm::new(self, ()) + } + + fn build_op_with_inspector(self, inspector: INSP) -> DefaultOpEvm { + OpEvm::new(self, inspector) + } +} diff --git a/src/api/default_ctx.rs b/src/api/default_ctx.rs new file mode 100644 index 00000000000..599ebed6dea --- /dev/null +++ b/src/api/default_ctx.rs @@ -0,0 +1,47 @@ +//! Contains trait [`DefaultOp`] used to create a default context. +use crate::{L1BlockInfo, OpSpecId, OpTransaction}; +use revm::{ + Context, Journal, MainContext, + context::{BlockEnv, CfgEnv, TxEnv}, + database_interface::EmptyDB, +}; + +/// Type alias for the default context type of the `OpEvm`. +pub type OpContext = + Context, CfgEnv, DB, Journal, L1BlockInfo>; + +/// Trait that allows for a default context to be created. +pub trait DefaultOp { + /// Create a default context. + fn op() -> OpContext; +} + +impl DefaultOp for OpContext { + fn op() -> Self { + Context::mainnet() + .with_tx(OpTransaction::builder().build_fill()) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::BEDROCK)) + .with_chain(L1BlockInfo::default()) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::api::builder::OpBuilder; + use revm::{ + ExecuteEvm, + inspector::{InspectEvm, NoOpInspector}, + }; + + #[test] + fn default_run_op() { + let ctx = Context::op(); + // convert to optimism context + let mut evm = ctx.build_op_with_inspector(NoOpInspector {}); + // execute + let _ = evm.transact(OpTransaction::builder().build_fill()); + // inspect + let _ = evm.inspect_one_tx(OpTransaction::builder().build_fill()); + } +} diff --git a/src/api/exec.rs b/src/api/exec.rs new file mode 100644 index 00000000000..baddb8ae929 --- /dev/null +++ b/src/api/exec.rs @@ -0,0 +1,169 @@ +//! Implementation of the [`ExecuteEvm`] trait for the [`OpEvm`]. +use crate::{ + L1BlockInfo, OpHaltReason, OpSpecId, OpTransactionError, evm::OpEvm, handler::OpHandler, + transaction::OpTxTr, +}; +use revm::{ + DatabaseCommit, ExecuteCommitEvm, ExecuteEvm, + context::{ContextSetters, result::ExecResultAndState}, + context_interface::{ + Cfg, ContextTr, Database, JournalTr, + result::{EVMError, ExecutionResult}, + }, + handler::{ + EthFrame, Handler, PrecompileProvider, SystemCallTx, instructions::EthInstructions, + system_call::SystemCallEvm, + }, + inspector::{ + InspectCommitEvm, InspectEvm, InspectSystemCallEvm, Inspector, InspectorHandler, JournalExt, + }, + interpreter::{InterpreterResult, interpreter::EthInterpreter}, + primitives::{Address, Bytes}, + state::EvmState, +}; + +/// Type alias for Optimism context +pub trait OpContextTr: + ContextTr< + Journal: JournalTr, + Tx: OpTxTr, + Cfg: Cfg, + Chain = L1BlockInfo, + > +{ +} + +impl OpContextTr for T where + T: ContextTr< + Journal: JournalTr, + Tx: OpTxTr, + Cfg: Cfg, + Chain = L1BlockInfo, + > +{ +} + +/// Type alias for the error type of the `OpEvm`. +pub type OpError = EVMError<<::Db as Database>::Error, OpTransactionError>; + +impl ExecuteEvm + for OpEvm, PRECOMPILE> +where + CTX: OpContextTr + ContextSetters, + PRECOMPILE: PrecompileProvider, +{ + type Tx = ::Tx; + type Block = ::Block; + type State = EvmState; + type Error = OpError; + type ExecutionResult = ExecutionResult; + + fn set_block(&mut self, block: Self::Block) { + self.0.ctx.set_block(block); + } + + fn transact_one(&mut self, tx: Self::Tx) -> Result { + self.0.ctx.set_tx(tx); + let mut h = OpHandler::<_, _, EthFrame>::new(); + h.run(self) + } + + fn finalize(&mut self) -> Self::State { + self.0.ctx.journal_mut().finalize() + } + + fn replay( + &mut self, + ) -> Result, Self::Error> { + let mut h = OpHandler::<_, _, EthFrame>::new(); + h.run(self).map(|result| { + let state = self.finalize(); + ExecResultAndState::new(result, state) + }) + } +} + +impl ExecuteCommitEvm + for OpEvm, PRECOMPILE> +where + CTX: OpContextTr + ContextSetters, + PRECOMPILE: PrecompileProvider, +{ + fn commit(&mut self, state: Self::State) { + self.0.ctx.db_mut().commit(state); + } +} + +impl InspectEvm + for OpEvm, PRECOMPILE> +where + CTX: OpContextTr + ContextSetters, + INSP: Inspector, + PRECOMPILE: PrecompileProvider, +{ + type Inspector = INSP; + + fn set_inspector(&mut self, inspector: Self::Inspector) { + self.0.inspector = inspector; + } + + fn inspect_one_tx(&mut self, tx: Self::Tx) -> Result { + self.0.ctx.set_tx(tx); + let mut h = OpHandler::<_, _, EthFrame>::new(); + h.inspect_run(self) + } +} + +impl InspectCommitEvm + for OpEvm, PRECOMPILE> +where + CTX: OpContextTr + ContextSetters, + INSP: Inspector, + PRECOMPILE: PrecompileProvider, +{ +} + +impl SystemCallEvm + for OpEvm, PRECOMPILE> +where + CTX: OpContextTr + ContextSetters, + PRECOMPILE: PrecompileProvider, +{ + fn system_call_one_with_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result { + self.0.ctx.set_tx(CTX::Tx::new_system_tx_with_caller( + caller, + system_contract_address, + data, + )); + let mut h = OpHandler::<_, _, EthFrame>::new(); + h.run_system_call(self) + } +} + +impl InspectSystemCallEvm + for OpEvm, PRECOMPILE> +where + CTX: OpContextTr + ContextSetters, + INSP: Inspector, + PRECOMPILE: PrecompileProvider, +{ + fn inspect_one_system_call_with_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result { + self.0.ctx.set_tx(CTX::Tx::new_system_tx_with_caller( + caller, + system_contract_address, + data, + )); + let mut h = OpHandler::<_, _, EthFrame>::new(); + h.inspect_run_system_call(self) + } +} diff --git a/src/constants.rs b/src/constants.rs new file mode 100644 index 00000000000..556ff250e09 --- /dev/null +++ b/src/constants.rs @@ -0,0 +1,70 @@ +//! Optimism constants used in the Optimism EVM. +use revm::primitives::{Address, U256, address}; + +/// The cost of a non-zero byte in the EVM. +pub const NON_ZERO_BYTE_COST: u64 = 16; + +/// The two 4-byte Ecotone fee scalar values are packed into the same storage slot as the 8-byte +/// sequence number. Byte offset within the storage slot of the 4-byte baseFeeScalar attribute. +pub const BASE_FEE_SCALAR_OFFSET: usize = 16; +/// The two 4-byte Ecotone fee scalar values are packed into the same storage slot as the 8-byte +/// sequence number. Byte offset within the storage slot of the 4-byte blobBaseFeeScalar attribute. +pub const BLOB_BASE_FEE_SCALAR_OFFSET: usize = 20; + +/// The Isthmus operator fee scalar values are similarly packed. Byte offset within +/// the storage slot of the 4-byte operatorFeeScalar attribute. +pub const OPERATOR_FEE_SCALAR_OFFSET: usize = 20; +/// The Isthmus operator fee scalar values are similarly packed. Byte offset within +/// the storage slot of the 8-byte operatorFeeConstant attribute. +pub const OPERATOR_FEE_CONSTANT_OFFSET: usize = 24; + +/// The Jovian daFootprintGasScalar value is packed into a single storage slot. Byte offset within +/// the storage slot of the 16-byte daFootprintGasScalar attribute. +pub const DA_FOOTPRINT_GAS_SCALAR_OFFSET: usize = 18; + +/// The fixed point decimal scaling factor associated with the operator fee scalar. +/// +/// Allows users to use 6 decimal points of precision when specifying the `operator_fee_scalar`. +pub const OPERATOR_FEE_SCALAR_DECIMAL: u64 = 1_000_000; + +/// The Jovian multiplier applied to the operator fee scalar component. +pub const OPERATOR_FEE_JOVIAN_MULTIPLIER: u64 = 100; + +/// The L1 base fee slot. +pub const L1_BASE_FEE_SLOT: U256 = U256::from_limbs([1u64, 0, 0, 0]); +/// The L1 overhead slot. +pub const L1_OVERHEAD_SLOT: U256 = U256::from_limbs([5u64, 0, 0, 0]); +/// The L1 scalar slot. +pub const L1_SCALAR_SLOT: U256 = U256::from_limbs([6u64, 0, 0, 0]); + +/// [`ECOTONE_L1_BLOB_BASE_FEE_SLOT`] was added in the Ecotone upgrade and stores the L1 blobBaseFee +/// attribute. +pub const ECOTONE_L1_BLOB_BASE_FEE_SLOT: U256 = U256::from_limbs([7u64, 0, 0, 0]); + +/// As of the ecotone upgrade, this storage slot stores the 32-bit basefeeScalar and +/// blobBaseFeeScalar attributes at offsets [`BASE_FEE_SCALAR_OFFSET`] and +/// [`BLOB_BASE_FEE_SCALAR_OFFSET`] respectively. +pub const ECOTONE_L1_FEE_SCALARS_SLOT: U256 = U256::from_limbs([3u64, 0, 0, 0]); + +/// This storage slot stores the 32-bit operatorFeeScalar and operatorFeeConstant attributes at +/// offsets [`OPERATOR_FEE_SCALAR_OFFSET`] and [`OPERATOR_FEE_CONSTANT_OFFSET`] respectively. +pub const OPERATOR_FEE_SCALARS_SLOT: U256 = U256::from_limbs([8u64, 0, 0, 0]); + +/// As of the Jovian upgrade, this storage slot stores the 16-bit daFootprintGasScalar attribute at +/// offset [`DA_FOOTPRINT_GAS_SCALAR_OFFSET`]. +pub const DA_FOOTPRINT_GAS_SCALAR_SLOT: U256 = U256::from_limbs([8u64, 0, 0, 0]); + +/// An empty 64-bit set of scalar values. +pub const EMPTY_SCALARS: [u8; 8] = [0u8; 8]; + +/// The address of L1 fee recipient. +pub const L1_FEE_RECIPIENT: Address = address!("0x420000000000000000000000000000000000001A"); + +/// The address of the operator fee recipient. +pub const OPERATOR_FEE_RECIPIENT: Address = address!("0x420000000000000000000000000000000000001B"); + +/// The address of the base fee recipient. +pub const BASE_FEE_RECIPIENT: Address = address!("0x4200000000000000000000000000000000000019"); + +/// The address of the `L1Block` contract. +pub const L1_BLOCK_CONTRACT: Address = address!("0x4200000000000000000000000000000000000015"); diff --git a/src/evm.rs b/src/evm.rs new file mode 100644 index 00000000000..ecdc59157f4 --- /dev/null +++ b/src/evm.rs @@ -0,0 +1,163 @@ +//! Contains the `[OpEvm]` type and its implementation of the execution EVM traits. +use crate::{OpSpecId, precompiles::OpPrecompiles}; +use revm::{ + Database, Inspector, + context::{Cfg, ContextError, ContextSetters, Evm, FrameStack}, + context_interface::ContextTr, + handler::{ + EthFrame, EvmTr, FrameInitOrResult, ItemOrResult, PrecompileProvider, + evm::FrameTr, + instructions::{EthInstructions, InstructionProvider}, + }, + inspector::{InspectorEvmTr, JournalExt}, + interpreter::{InterpreterResult, interpreter::EthInterpreter}, +}; + +/// Optimism EVM extends the [`Evm`] type with Optimism specific types and logic. +#[derive(Debug, Clone)] +pub struct OpEvm< + CTX, + INSP, + I = EthInstructions, + P = OpPrecompiles, + F = EthFrame, +>( + /// Inner EVM type. + pub Evm, +); + +impl + Clone>>, INSP> + OpEvm, OpPrecompiles> +{ + /// Create a new Optimism EVM. + pub fn new(ctx: CTX, inspector: INSP) -> Self { + let spec: OpSpecId = ctx.cfg().spec().into(); + Self(Evm { + ctx, + inspector, + instruction: EthInstructions::new_mainnet_with_spec(spec.into()), + precompiles: OpPrecompiles::new_with_spec(spec), + frame_stack: FrameStack::new_prealloc(8), + }) + } + + /// Consumes self and returns the inner context. + pub fn into_context(self) -> CTX { + self.0.ctx + } +} + +impl OpEvm { + /// Consumed self and returns a new Evm type with given Inspector. + pub fn with_inspector(self, inspector: OINSP) -> OpEvm { + OpEvm(self.0.with_inspector(inspector)) + } + + /// Consumes self and returns a new Evm type with given Precompiles. + pub fn with_precompiles(self, precompiles: OP) -> OpEvm { + OpEvm(self.0.with_precompiles(precompiles)) + } + + /// Consumes self and returns the inner Inspector. + pub fn into_inspector(self) -> INSP { + self.0.into_inspector() + } +} + +impl InspectorEvmTr for OpEvm +where + CTX: ContextTr + ContextSetters, + I: InstructionProvider, + P: PrecompileProvider, + INSP: Inspector, +{ + type Inspector = INSP; + + #[inline] + fn all_inspector( + &self, + ) -> ( + &Self::Context, + &Self::Instructions, + &Self::Precompiles, + &FrameStack, + &Self::Inspector, + ) { + self.0.all_inspector() + } + + #[inline] + fn all_mut_inspector( + &mut self, + ) -> ( + &mut Self::Context, + &mut Self::Instructions, + &mut Self::Precompiles, + &mut FrameStack, + &mut Self::Inspector, + ) { + self.0.all_mut_inspector() + } +} + +impl EvmTr for OpEvm> +where + CTX: ContextTr, + I: InstructionProvider, + P: PrecompileProvider, +{ + type Context = CTX; + type Instructions = I; + type Precompiles = P; + type Frame = EthFrame; + + #[inline] + fn all( + &self, + ) -> (&Self::Context, &Self::Instructions, &Self::Precompiles, &FrameStack) { + self.0.all() + } + + #[inline] + fn all_mut( + &mut self, + ) -> ( + &mut Self::Context, + &mut Self::Instructions, + &mut Self::Precompiles, + &mut FrameStack, + ) { + self.0.all_mut() + } + + fn frame_init( + &mut self, + frame_input: ::FrameInit, + ) -> Result< + ItemOrResult<&mut Self::Frame, ::FrameResult>, + ContextError<<::Db as Database>::Error>, + > { + self.0.frame_init(frame_input) + } + + fn frame_run( + &mut self, + ) -> Result< + FrameInitOrResult, + ContextError<<::Db as Database>::Error>, + > { + self.0.frame_run() + } + + #[doc = " Returns the result of the frame to the caller. Frame is popped from the frame stack."] + #[doc = " Consumes the frame result or returns it if there is more frames to run."] + fn frame_return_result( + &mut self, + result: ::FrameResult, + ) -> Result< + Option<::FrameResult>, + ContextError<<::Db as Database>::Error>, + > { + self.0.frame_return_result(result) + } +} diff --git a/src/fast_lz.rs b/src/fast_lz.rs new file mode 100644 index 00000000000..67e3c4c6e86 --- /dev/null +++ b/src/fast_lz.rs @@ -0,0 +1,185 @@ +//! Contains the `[flz_compress_len]` function. + +/// Returns the length of the data after compression through `FastLZ`, based on +/// +/// +/// The u32s match op-geth's Go port: +/// +pub(crate) fn flz_compress_len(input: &[u8]) -> u32 { + let mut idx: u32 = 2; + + let idx_limit: u32 = if input.len() < 13 { 0 } else { input.len() as u32 - 13 }; + + let mut anchor = 0; + + let mut size = 0; + + let mut htab = [0; 8192]; + + while idx < idx_limit { + let mut r: u32; + let mut distance: u32; + + loop { + let seq = u24(input, idx); + let hash = hash(seq); + r = htab[hash as usize]; + htab[hash as usize] = idx; + distance = idx - r; + if idx >= idx_limit { + break; + } + idx += 1; + if distance < 8192 && seq == u24(input, r) { + break; + } + } + + if idx >= idx_limit { + break; + } + + idx -= 1; + + if idx > anchor { + size = literals(idx - anchor, size); + } + + let len = cmp(input, r + 3, idx + 3, idx_limit + 9); + size = flz_match(len, size); + + idx = set_next_hash(&mut htab, input, idx + len); + idx = set_next_hash(&mut htab, input, idx); + anchor = idx; + } + + literals(input.len() as u32 - anchor, size) +} + +const fn literals(r: u32, size: u32) -> u32 { + let size = size + 0x21 * (r / 0x20); + let r = r % 0x20; + if r != 0 { size + r + 1 } else { size } +} + +fn cmp(input: &[u8], p: u32, q: u32, r: u32) -> u32 { + let mut l = 0; + let mut r = r - q; + while l < r { + if input[(p + l) as usize] != input[(q + l) as usize] { + r = 0; + } + l += 1; + } + l +} + +const fn flz_match(l: u32, size: u32) -> u32 { + let l = l - 1; + let size = size + (3 * (l / 262)); + if l % 262 >= 6 { size + 3 } else { size + 2 } +} + +fn set_next_hash(htab: &mut [u32; 8192], input: &[u8], idx: u32) -> u32 { + htab[hash(u24(input, idx)) as usize] = idx; + idx + 1 +} + +const fn hash(v: u32) -> u16 { + let hash = (v as u64 * 2654435769) >> 19; + hash as u16 & 0x1fff +} + +fn u24(input: &[u8], idx: u32) -> u32 { + u32::from(input[idx as usize]) + + (u32::from(input[(idx + 1) as usize]) << 8) + + (u32::from(input[(idx + 2) as usize]) << 16) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::api::{builder::OpBuilder, default_ctx::DefaultOp}; + use alloy_sol_types::{SolCall, sol}; + use revm::{ + Context, ExecuteEvm, + bytecode::Bytecode, + database::{BenchmarkDB, EEADDRESS, FFADDRESS}, + primitives::{Bytes, TxKind, U256, bytes}, + }; + use rstest::rstest; + use std::vec::Vec; + + #[rstest] + #[case::empty(&[], 0)] + #[case::thousand_zeros(&[0; 1000], 21)] + #[case::thousand_forty_twos(&[42; 1000], 21)] + #[case::short_hex(&bytes!("FACADE"), 4)] + #[case::sample_contract_call(&bytes!("02f901550a758302df1483be21b88304743f94f80e51afb613d764fa61751affd3313c190a86bb870151bd62fd12adb8e41ef24f3f000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000003c1e5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000148c89ed219d02f1a5be012c689b4f5b731827bebe000000000000000000000000c001a033fd89cb37c31b2cba46b6466e040c61fc9b2a3675a7f5f493ebd5ad77c497f8a07cdf65680e238392693019b4092f610222e71b7cec06449cb922b93b6a12744e"), 202)] + #[case::base_0x5dadeb52979f29fc7a7494c43fdabc5be1d8ff404f3aafe93d729fa8e5d00769(&bytes!("b9047c02f904788221050883036ee48409c6c87383037f6f941195cf65f83b3a5768f3c496d3a05ad6412c64b78644364c5bb000b90404d123b4d80000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000f6476f90447748c19248ccaa31e6b8bfda4eb9d830f5f47df7f0998f7c2123d9e6137761b75d3184efb0f788e3b14516000000000000000000000000000000000000000000000000000044364c5bb000000000000000000000000000f38e53bd45c8225a7c94b513beadaa7afe5d222d0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084d6574614d61736b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d656852577a743347745961776343347564745657557233454c587261436746434259416b66507331696f48610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd0d83d9e840f8e27d5c2e365fd365ff1c05b2480000000000000000000000000000000000000000000000000000000000000ce40000000000000000000000000000000000000000000000000000000000000041e4480d358dbae20880960a0a464d63b06565a0c9f9b1b37aa94b522247b23ce149c81359bf4239d1a879eeb41047ec710c15f5c0f67453da59a383e6abd742971c00000000000000000000000000000000000000000000000000000000000000c001a0b57f0ff8516ea29cb26a44ac5055a5420847d1e16a8e7b03b70f0c02291ff2d5a00ad3771e5f39ccacfff0faa8c5d25ef7a1c179f79e66e828ffddcb994c8b512e"), 471)] + fn test_flz_compress_len(#[case] input: &[u8], #[case] expected: u32) { + assert_eq!(flz_compress_len(input), expected); + } + + #[test] + fn test_flz_compress_len_no_repeats() { + let mut input = Vec::new(); + let mut len = 0; + + for i in 0..256 { + input.push(i as u8); + let prev_len = len; + len = flz_compress_len(&input); + assert!(len > prev_len); + } + } + + #[rstest] + #[case::short_hex(bytes!("FACADE"))] + #[case::sample_contract_call(bytes!("02f901550a758302df1483be21b88304743f94f80e51afb613d764fa61751affd3313c190a86bb870151bd62fd12adb8e41ef24f3f000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000003c1e5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000148c89ed219d02f1a5be012c689b4f5b731827bebe000000000000000000000000c001a033fd89cb37c31b2cba46b6466e040c61fc9b2a3675a7f5f493ebd5ad77c497f8a07cdf65680e238392693019b4092f610222e71b7cec06449cb922b93b6a12744e"))] + #[case::base_0x5dadeb52979f29fc7a7494c43fdabc5be1d8ff404f3aafe93d729fa8e5d00769(bytes!("b9047c02f904788221050883036ee48409c6c87383037f6f941195cf65f83b3a5768f3c496d3a05ad6412c64b78644364c5bb000b90404d123b4d80000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000f6476f90447748c19248ccaa31e6b8bfda4eb9d830f5f47df7f0998f7c2123d9e6137761b75d3184efb0f788e3b14516000000000000000000000000000000000000000000000000000044364c5bb000000000000000000000000000f38e53bd45c8225a7c94b513beadaa7afe5d222d0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084d6574614d61736b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035697066733a2f2f516d656852577a743347745961776343347564745657557233454c587261436746434259416b66507331696f48610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cd0d83d9e840f8e27d5c2e365fd365ff1c05b2480000000000000000000000000000000000000000000000000000000000000ce40000000000000000000000000000000000000000000000000000000000000041e4480d358dbae20880960a0a464d63b06565a0c9f9b1b37aa94b522247b23ce149c81359bf4239d1a879eeb41047ec710c15f5c0f67453da59a383e6abd742971c00000000000000000000000000000000000000000000000000000000000000c001a0b57f0ff8516ea29cb26a44ac5055a5420847d1e16a8e7b03b70f0c02291ff2d5a00ad3771e5f39ccacfff0faa8c5d25ef7a1c179f79e66e828ffddcb994c8b512e"))] + #[case::base_0xfaada76a2dac09fc17f5a28d066aaabefc6d82ef6589b211ed8c9f766b070721(bytes!("b87602f873822105528304320f8409cfe5c98252089480c67432656d59144ceff962e8faf8926599bcf888011dfe52d06b633f80c001a08632f069f837aea7a28bab0affee14dda116956bd5a850a355c045d25afedd17a0084b8f273efffe17ece527116053e5781a4915ff89ab9c379f1e62c25b697687"))] + #[case::base_0x112864e9b971af6a1dac840018833c5a5a659acc187cfdaba919ad1da013678d(bytes!("b8b302f8b0822105308304320f8409cfe5c9827496944ed4e862860bed51a9570b96d89af5e1b0efefed80b844095ea7b3000000000000000000000000000000000022d473030f116ddee9f6b43ac78ba300000000000000000000000000000000000000000000015e10fb0973595fffffc001a02020e39f07917c1a852feb131c857e12478c7e88a20772b91a8bf5cee38c5aeea06055981727f9aaa3471c1af800555b35a77916c154be3f9d02ad1a63029455ab"))] + #[case::base_0x6905051352691641888d0c427fb137c5b95afb5870d5169ff014eff1d0952195(bytes!("b87202f86f8221058303dc6c8310db1f84068fa8d7838954409436af2ff952a7355c8045fcd5e88bc9f6c8257f7b8080c001a0b89e7ff3d7694109e73e7f4244e032581670313c36e48e485c9c94b853bd81d2a038ffaf8f10859ce21d1f7f7046c3d08027fb8aa15b69038f6102be97aaa1179a"))] + #[case::base_0x6a38e9a26d7202a2268de69d2d47531c1a9829867579a483fb48d78e9e0b080d(bytes!("b9049b02f904978221058201618506fc23ac008506fc23ac008306ddd0943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad80b904243593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000006641d67b00000000000000000000000000000000000000000000000000000000000000030a000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000160000000000000000000000000088487bd8c3222d64d1d0b3fa7098dcf9d94d79e000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000006669635d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fc91a3afd70395cd496c647d5a6cc9d4b2b7fad000000000000000000000000000000000000000000000000000000006641d78900000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000418661369ca026f92ff88347bd0e3625a7b5ed65071b366368c68ad7c55aed136c18659b34f9246e30a784227a53dd374fbd3d2124696808c678cd987c4e954a681b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000549e5c020c764dbfffff00000000000000000000000000000000000000000000000002e5a629c093a2b600000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002b088487bd8c3222d64d1d0b3fa7098dcf9d94d79e0027104200000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c001a014a3acef764ff6d3bb9bd81e420bfa94171a5734ab997dfbc9b41b653ce018a4a01ff5fccb01ef5c60ba3aef67d4e74f3f47312dd78bfbbff9e5090fbf2d3d62bb"))] + fn test_flz_native_evm_parity(#[case] input: Bytes) { + // This bytecode and ABI is for a contract, which wraps the LibZip library for easier fuzz + // testing. The source of this contract is here: https://github.com/danyalprout/fastlz/blob/main/src/FastLz.sol#L6-L10 + + use revm::context::TxEnv; + + use crate::OpTransaction; + sol! { + interface FastLz { + function fastLz(bytes input) external view returns (uint256); + } + } + + let contract_bytecode = Bytecode::new_raw(bytes!( + "608060405234801561001057600080fd5b506004361061002b5760003560e01c8063920a769114610030575b600080fd5b61004361003e366004610374565b610055565b60405190815260200160405180910390f35b600061006082610067565b5192915050565b60606101e0565b818153600101919050565b600082840393505b838110156100a25782810151828201511860001a1590930292600101610081565b9392505050565b825b602082106100d75782516100c0601f8361006e565b5260209290920191601f19909101906021016100ab565b81156100a25782516100ec600184038361006e565b520160010192915050565b60006001830392505b61010782106101385761012a8360ff1661012560fd6101258760081c60e0018961006e565b61006e565b935061010682039150610100565b600782106101655761015e8360ff16610125600785036101258760081c60e0018961006e565b90506100a2565b61017e8360ff166101258560081c8560051b018761006e565b949350505050565b80516101d890838303906101bc90600081901a600182901a60081b1760029190911a60101b17639e3779b90260131c611fff1690565b8060021b6040510182815160e01c1860e01b8151188152505050565b600101919050565b5060405161800038823961800081016020830180600d8551820103826002015b81811015610313576000805b50508051604051600082901a600183901a60081b1760029290921a60101b91909117639e3779b9810260111c617ffc16909101805160e081811c878603811890911b9091189091528401908183039084841061026857506102a3565b600184019350611fff821161029d578251600081901a600182901a60081b1760029190911a60101b17810361029d57506102a3565b5061020c565b8383106102b1575050610313565b600183039250858311156102cf576102cc87878886036100a9565b96505b6102e3600985016003850160038501610079565b91506102f08782846100f7565b9650506103088461030386848601610186565b610186565b915050809350610200565b5050617fe061032884848589518601036100a9565b03925050506020820180820383525b81811161034e57617fe08101518152602001610337565b5060008152602001604052919050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561038657600080fd5b813567ffffffffffffffff8082111561039e57600080fd5b818401915084601f8301126103b257600080fd5b8135818111156103c4576103c461035e565b604051601f8201601f19908116603f011681019083821181831017156103ec576103ec61035e565b8160405282815287602084870101111561040557600080fd5b82602086016020830137600092810160200192909252509594505050505056fea264697066735822122000646b2953fc4a6f501bd0456ac52203089443937719e16b3190b7979c39511264736f6c63430008190033" + )); + + let native_val = flz_compress_len(&input); + + let mut evm = + Context::op().with_db(BenchmarkDB::new_bytecode(contract_bytecode)).build_op(); + + let tx = OpTransaction::builder() + .base( + TxEnv::builder() + .caller(EEADDRESS) + .kind(TxKind::Call(FFADDRESS)) + .data(FastLz::fastLzCall::new((input,)).abi_encode().into()) + .gas_limit(3_000_000), + ) + .enveloped_tx(Some(Bytes::default())) + .build_fill(); + + let result = evm.transact_one(tx).unwrap(); + + let output = result.output().unwrap(); + let evm_val = FastLz::fastLzCall::abi_decode_returns(output).unwrap(); + + assert_eq!(U256::from(native_val), evm_val); + } +} diff --git a/src/handler.rs b/src/handler.rs new file mode 100644 index 00000000000..112e0e4de31 --- /dev/null +++ b/src/handler.rs @@ -0,0 +1,1297 @@ +//!Handler related to Optimism chain +use crate::{ + L1BlockInfo, OpHaltReason, OpSpecId, + api::exec::OpContextTr, + constants::{BASE_FEE_RECIPIENT, L1_FEE_RECIPIENT, OPERATOR_FEE_RECIPIENT}, + transaction::{OpTransactionError, OpTxTr, deposit::DEPOSIT_TRANSACTION_TYPE}, +}; +use revm::{ + context::{ + LocalContextTr, + journaled_state::{JournalCheckpoint, account::JournaledAccountTr}, + result::InvalidTransaction, + }, + context_interface::{ + Block, Cfg, ContextTr, JournalTr, Transaction, + context::take_error, + result::{EVMError, ExecutionResult, FromStringError, ResultGas}, + }, + handler::{ + EthFrame, EvmTr, FrameResult, Handler, MainnetHandler, + evm::FrameTr, + handler::EvmTrError, + post_execution::{self, reimburse_caller}, + pre_execution::{calculate_caller_fee, validate_account_nonce_and_code_with_components}, + }, + inspector::{Inspector, InspectorEvmTr, InspectorHandler}, + interpreter::{Gas, interpreter::EthInterpreter, interpreter_action::FrameInit}, + primitives::{U256, hardfork::SpecId}, +}; +use std::{boxed::Box, vec::Vec}; + +/// Optimism handler extends the [`Handler`] with Optimism specific logic. +#[derive(Debug, Clone)] +pub struct OpHandler { + /// Mainnet handler allows us to use functions from the mainnet handler inside optimism + /// handler. So we dont duplicate the logic + pub mainnet: MainnetHandler, +} + +impl OpHandler { + /// Create a new Optimism handler. + pub fn new() -> Self { + Self { mainnet: MainnetHandler::default() } + } +} + +impl Default for OpHandler { + fn default() -> Self { + Self::new() + } +} + +/// Trait to check if the error is a transaction error. +/// +/// Used in `cache_error` handler to catch deposit transaction that was halted. +pub trait IsTxError { + /// Check if the error is a transaction error. + fn is_tx_error(&self) -> bool; +} + +impl IsTxError for EVMError { + fn is_tx_error(&self) -> bool { + matches!(self, Self::Transaction(_)) + } +} + +impl Handler for OpHandler +where + EVM: EvmTr, + ERROR: EvmTrError + From + FromStringError + IsTxError, + // TODO `FrameResult` should be a generic trait. + // TODO `FrameInit` should be a generic. + FRAME: FrameTr, +{ + type Evm = EVM; + type Error = ERROR; + type HaltReason = OpHaltReason; + + fn validate_env(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> { + // Do not perform any extra validation for deposit transactions, they are pre-verified on + // L1. + let ctx = evm.ctx(); + let tx = ctx.tx(); + let tx_type = tx.tx_type(); + if tx_type == DEPOSIT_TRANSACTION_TYPE { + // Do not allow for a system transaction to be processed if Regolith is enabled. + if tx.is_system_transaction() && + evm.ctx().cfg().spec().is_enabled_in(OpSpecId::REGOLITH) + { + return Err(OpTransactionError::DepositSystemTxPostRegolith.into()); + } + return Ok(()); + } + + // Check that non-deposit transactions have enveloped_tx set + if tx.enveloped_tx().is_none() { + return Err(OpTransactionError::MissingEnvelopedTx.into()); + } + + self.mainnet.validate_env(evm) + } + + fn validate_against_state_and_deduct_caller( + &self, + evm: &mut Self::Evm, + ) -> Result<(), Self::Error> { + let (block, tx, cfg, journal, chain, _) = evm.ctx().all_mut(); + let spec = cfg.spec(); + + if tx.tx_type() == DEPOSIT_TRANSACTION_TYPE { + let basefee = block.basefee() as u128; + let blob_price = block.blob_gasprice().unwrap_or_default(); + // deposit skips max fee check and just deducts the effective balance spending. + + let mut caller = journal.load_account_with_code_mut(tx.caller())?.data; + + let effective_balance_spending = tx + .effective_balance_spending(basefee, blob_price) + .expect("Deposit transaction effective balance spending overflow") - + tx.value(); + + // Mind value should be added first before subtracting the effective balance spending. + let mut new_balance = caller + .balance() + .saturating_add(U256::from(tx.mint().unwrap_or_default())) + .saturating_sub(effective_balance_spending); + + if cfg.is_balance_check_disabled() { + // Make sure the caller's balance is at least the value of the transaction. + // this is not consensus critical, and it is used in testing. + new_balance = new_balance.max(tx.value()); + } + + // set the new balance and bump the nonce if it is a call + caller.set_balance(new_balance); + if tx.kind().is_call() { + caller.bump_nonce(); + } + + return Ok(()); + } + + // L1 block info is stored in the context for later use. + // and it will be reloaded from the database if it is not for the current block. + if chain.l2_block != Some(block.number()) { + *chain = L1BlockInfo::try_fetch(journal.db_mut(), block.number(), spec)?; + } + + let mut caller_account = journal.load_account_with_code_mut(tx.caller())?.data; + + // validates account nonce and code + validate_account_nonce_and_code_with_components(&caller_account.account().info, tx, cfg)?; + + // check additional cost and deduct it from the caller's balances + let mut balance = caller_account.account().info.balance; + + if !cfg.is_fee_charge_disabled() { + let Some(additional_cost) = chain.tx_cost_with_tx(tx, spec) else { + return Err(OpTransactionError::MissingEnvelopedTx.into()); + }; + let Some(new_balance) = balance.checked_sub(additional_cost) else { + return Err(InvalidTransaction::LackOfFundForMaxFee { + fee: Box::new(additional_cost), + balance: Box::new(balance), + } + .into()); + }; + balance = new_balance + } + + let balance = calculate_caller_fee(balance, tx, block, cfg)?; + + // make changes to the account + caller_account.set_balance(balance); + if tx.kind().is_call() { + caller_account.bump_nonce(); + } + + Ok(()) + } + + fn last_frame_result( + &mut self, + evm: &mut Self::Evm, + frame_result: &mut <::Frame as FrameTr>::FrameResult, + ) -> Result<(), Self::Error> { + let ctx = evm.ctx(); + let tx = ctx.tx(); + let is_deposit = tx.tx_type() == DEPOSIT_TRANSACTION_TYPE; + let tx_gas_limit = tx.gas_limit(); + let is_regolith = ctx.cfg().spec().is_enabled_in(OpSpecId::REGOLITH); + + let instruction_result = frame_result.interpreter_result().result; + let gas = frame_result.gas_mut(); + let remaining = gas.remaining(); + let refunded = gas.refunded(); + + // Spend the gas limit. Gas is reimbursed when the tx returns successfully. + *gas = Gas::new_spent(tx_gas_limit); + + if instruction_result.is_ok() { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (success path): + // - Deposit transactions (non-system) report their gas limit as the usage. No + // refunds. + // - Deposit transactions (system) report 0 gas used. No refunds. + // - Regular transactions report gas usage as normal. + // - Regolith (success path): + // - Deposit transactions (all) report their gas used as normal. Refunds enabled. + // - Regular transactions report their gas used as normal. + if !is_deposit || is_regolith { + // For regular transactions prior to Regolith and all transactions after + // Regolith, gas is reported as normal. + gas.erase_cost(remaining); + gas.record_refund(refunded); + } else if is_deposit && tx.is_system_transaction() { + // System transactions were a special type of deposit transaction in + // the Bedrock hardfork that did not incur any gas costs. + gas.erase_cost(tx_gas_limit); + } + } else if instruction_result.is_revert() { + // On Optimism, deposit transactions report gas usage uniquely to other + // transactions due to them being pre-paid on L1. + // + // Hardfork Behavior: + // - Bedrock (revert path): + // - Deposit transactions (all) report the gas limit as the amount of gas used on + // failure. No refunds. + // - Regular transactions receive a refund on remaining gas as normal. + // - Regolith (revert path): + // - Deposit transactions (all) report the actual gas used as the amount of gas used + // on failure. Refunds on remaining gas enabled. + // - Regular transactions receive a refund on remaining gas as normal. + if !is_deposit || is_regolith { + gas.erase_cost(remaining); + } + } + Ok(()) + } + + fn reimburse_caller( + &self, + evm: &mut Self::Evm, + frame_result: &mut <::Frame as FrameTr>::FrameResult, + ) -> Result<(), Self::Error> { + let additional_refund = if evm.ctx().tx().tx_type() != DEPOSIT_TRANSACTION_TYPE && + !evm.ctx().cfg().is_fee_charge_disabled() + { + let spec = evm.ctx().cfg().spec(); + evm.ctx().chain().operator_fee_refund(frame_result.gas(), spec) + } else { + U256::ZERO + }; + + reimburse_caller(evm.ctx(), frame_result.gas(), additional_refund).map_err(From::from) + } + + fn refund( + &self, + evm: &mut Self::Evm, + frame_result: &mut <::Frame as FrameTr>::FrameResult, + eip7702_refund: i64, + ) { + frame_result.gas_mut().record_refund(eip7702_refund); + + let is_deposit = evm.ctx().tx().tx_type() == DEPOSIT_TRANSACTION_TYPE; + let is_regolith = evm.ctx().cfg().spec().is_enabled_in(OpSpecId::REGOLITH); + + // Prior to Regolith, deposit transactions did not receive gas refunds. + let is_gas_refund_disabled = is_deposit && !is_regolith; + if !is_gas_refund_disabled { + frame_result.gas_mut().set_final_refund( + evm.ctx().cfg().spec().into_eth_spec().is_enabled_in(SpecId::LONDON), + ); + } + } + + fn reward_beneficiary( + &self, + evm: &mut Self::Evm, + frame_result: &mut <::Frame as FrameTr>::FrameResult, + ) -> Result<(), Self::Error> { + let is_deposit = evm.ctx().tx().tx_type() == DEPOSIT_TRANSACTION_TYPE; + + // Transfer fee to coinbase/beneficiary. + if is_deposit { + return Ok(()); + } + + self.mainnet.reward_beneficiary(evm, frame_result)?; + let basefee = evm.ctx().block().basefee() as u128; + + // If the transaction is not a deposit transaction, fees are paid out + // to both the Base Fee Vault as well as the L1 Fee Vault. + // Use all_mut() to simultaneously borrow tx (immutable) and chain (mutable), + // avoiding an unnecessary clone of the enveloped transaction bytes. + let (_, tx, cfg, journal, l1_block_info, _) = evm.ctx().all_mut(); + let spec = cfg.spec(); + + let Some(enveloped_tx) = tx.enveloped_tx() else { + return Err(OpTransactionError::MissingEnvelopedTx.into()); + }; + + let l1_cost = l1_block_info.calculate_tx_l1_cost(enveloped_tx, spec); + let operator_fee_cost = if spec.is_enabled_in(OpSpecId::ISTHMUS) { + l1_block_info.operator_fee_charge( + enveloped_tx, + U256::from(frame_result.gas().used()), + spec, + ) + } else { + U256::ZERO + }; + let base_fee_amount = U256::from(basefee.saturating_mul(frame_result.gas().used() as u128)); + + // Send fees to their respective recipients + for (recipient, amount) in [ + (L1_FEE_RECIPIENT, l1_cost), + (BASE_FEE_RECIPIENT, base_fee_amount), + (OPERATOR_FEE_RECIPIENT, operator_fee_cost), + ] { + journal.balance_incr(recipient, amount)?; + } + + Ok(()) + } + + fn execution_result( + &mut self, + evm: &mut Self::Evm, + frame_result: <::Frame as FrameTr>::FrameResult, + result_gas: ResultGas, + ) -> Result, Self::Error> { + take_error::(evm.ctx().error())?; + + let exec_result = post_execution::output(evm.ctx(), frame_result, result_gas) + .map_haltreason(OpHaltReason::Base); + + if exec_result.is_halt() { + // Post-regolith, if the transaction is a deposit transaction and it halts, + // we bubble up to the global return handler. The mint value will be persisted + // and the caller nonce will be incremented there. + let is_deposit = evm.ctx().tx().tx_type() == DEPOSIT_TRANSACTION_TYPE; + if is_deposit && evm.ctx().cfg().spec().is_enabled_in(OpSpecId::REGOLITH) { + return Err(ERROR::from(OpTransactionError::HaltedDepositPostRegolith)); + } + } + evm.ctx().journal_mut().commit_tx(); + evm.ctx().chain_mut().clear_tx_l1_cost(); + evm.ctx().local_mut().clear(); + evm.frame_stack().clear(); + + Ok(exec_result) + } + + fn catch_error( + &self, + evm: &mut Self::Evm, + error: Self::Error, + ) -> Result, Self::Error> { + let is_deposit = evm.ctx().tx().tx_type() == DEPOSIT_TRANSACTION_TYPE; + let is_tx_error = error.is_tx_error(); + let mut output = Err(error); + + // Deposit transaction can't fail so we manually handle it here. + if is_tx_error && is_deposit { + let ctx = evm.ctx(); + let spec = ctx.cfg().spec(); + let tx = ctx.tx(); + let caller = tx.caller(); + let mint = tx.mint(); + let is_system_tx = tx.is_system_transaction(); + let gas_limit = tx.gas_limit(); + let journal = evm.ctx().journal_mut(); + + // discard all changes of this transaction + // Default JournalCheckpoint is the first checkpoint and will wipe all changes. + journal.checkpoint_revert(JournalCheckpoint::default()); + + // If the transaction is a deposit transaction and it failed + // for any reason, the caller nonce must be bumped, and the + // gas reported must be altered depending on the Hardfork. This is + // also returned as a special Halt variant so that consumers can more + // easily distinguish between a failed deposit and a failed + // normal transaction. + + // Increment sender nonce and account balance for the mint amount. Deposits + // always persist the mint amount, even if the transaction fails. + let mut acc = journal.load_account_mut(caller)?; + acc.bump_nonce(); + acc.incr_balance(U256::from(mint.unwrap_or_default())); + + drop(acc); // Drop acc to avoid borrow checker issues. + + // We can now commit the changes. + journal.commit_tx(); + + // The gas used of a failed deposit post-regolith is the gas + // limit of the transaction. pre-regolith, it is the gas limit + // of the transaction for non system transactions and 0 for system + // transactions. + let gas_used = + if spec.is_enabled_in(OpSpecId::REGOLITH) || !is_system_tx { gas_limit } else { 0 }; + // clear the journal + output = Ok(ExecutionResult::Halt { + reason: OpHaltReason::FailedDeposit, + gas: ResultGas::new(gas_limit, gas_used, 0, 0, 0), + logs: Vec::new(), + }) + } + + // do the cleanup + evm.ctx().chain_mut().clear_tx_l1_cost(); + evm.ctx().local_mut().clear(); + evm.frame_stack().clear(); + + output + } +} + +impl InspectorHandler for OpHandler> +where + EVM: InspectorEvmTr< + Context: OpContextTr, + Frame = EthFrame, + Inspector: Inspector<<::Evm as EvmTr>::Context, EthInterpreter>, + >, + ERROR: EvmTrError + From + FromStringError + IsTxError, +{ + type IT = EthInterpreter; +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + DefaultOp, OpBuilder, OpTransaction, + api::default_ctx::OpContext, + constants::{ + BASE_FEE_SCALAR_OFFSET, ECOTONE_L1_BLOB_BASE_FEE_SLOT, ECOTONE_L1_FEE_SCALARS_SLOT, + L1_BASE_FEE_SLOT, L1_BLOCK_CONTRACT, OPERATOR_FEE_SCALARS_SLOT, + }, + }; + use alloy_primitives::uint; + use revm::{ + context::{BlockEnv, CfgEnv, Context, TxEnv}, + context_interface::result::InvalidTransaction, + database::InMemoryDB, + database_interface::EmptyDB, + handler::EthFrame, + interpreter::{CallOutcome, InstructionResult, InterpreterResult}, + primitives::{Address, B256, Bytes, bytes}, + state::AccountInfo, + }; + use rstest::rstest; + use std::boxed::Box; + + /// Creates frame result. + fn call_last_frame_return( + ctx: OpContext, + instruction_result: InstructionResult, + gas: Gas, + ) -> Gas { + let mut evm = ctx.build_op(); + + let mut exec_result = FrameResult::Call(CallOutcome::new( + InterpreterResult { result: instruction_result, output: Bytes::new(), gas }, + 0..0, + )); + + let mut handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + handler.last_frame_result(&mut evm, &mut exec_result).unwrap(); + handler.refund(&mut evm, &mut exec_result, 0); + *exec_result.gas() + } + + #[test] + fn test_revert_gas() { + let ctx = Context::op() + .with_tx(OpTransaction::builder().base(TxEnv::builder().gas_limit(100)).build_fill()) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::BEDROCK)); + + let gas = call_last_frame_return(ctx, InstructionResult::Revert, Gas::new(90)); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spent(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas() { + let ctx = Context::op() + .with_tx(OpTransaction::builder().base(TxEnv::builder().gas_limit(100)).build_fill()) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::REGOLITH)); + + let gas = call_last_frame_return(ctx, InstructionResult::Stop, Gas::new(90)); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spent(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas_with_refund() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(100)) + .source_hash(B256::from([1u8; 32])) + .build_fill(), + ) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::REGOLITH)); + + let mut ret_gas = Gas::new(90); + ret_gas.record_refund(20); + + let gas = call_last_frame_return(ctx.clone(), InstructionResult::Stop, ret_gas); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spent(), 10); + assert_eq!(gas.refunded(), 2); // min(20, 10/5) + + let gas = call_last_frame_return(ctx, InstructionResult::Revert, ret_gas); + assert_eq!(gas.remaining(), 90); + assert_eq!(gas.spent(), 10); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas_deposit_tx() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(100)) + .source_hash(B256::from([1u8; 32])) + .build_fill(), + ) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::BEDROCK)); + let gas = call_last_frame_return(ctx, InstructionResult::Stop, Gas::new(90)); + assert_eq!(gas.remaining(), 0); + assert_eq!(gas.spent(), 100); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_consume_gas_sys_deposit_tx() { + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(100)) + .source_hash(B256::from([1u8; 32])) + .is_system_transaction() + .build_fill(), + ) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::BEDROCK)); + let gas = call_last_frame_return(ctx, InstructionResult::Stop, Gas::new(90)); + assert_eq!(gas.remaining(), 100); + assert_eq!(gas.spent(), 0); + assert_eq!(gas.refunded(), 0); + } + + #[test] + fn test_commit_mint_value() { + let caller = Address::ZERO; + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { balance: U256::from(1000), ..Default::default() }, + ); + + let mut ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_fee_overhead: Some(U256::from(1_000)), + l1_base_fee_scalar: U256::from(1_000), + ..Default::default() + }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::REGOLITH)); + ctx.modify_tx(|tx| { + tx.deposit.source_hash = B256::from([1u8; 32]); + tx.deposit.mint = Some(10); + }); + + let mut evm = ctx.build_op(); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + handler.validate_against_state_and_deduct_caller(&mut evm).unwrap(); + + // Check the account balance is updated. + let account = evm.ctx().journal_mut().load_account(caller).unwrap(); + assert_eq!(account.info.balance, U256::from(1010)); + } + + #[test] + fn test_remove_l1_cost_non_deposit() { + let caller = Address::ZERO; + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { + balance: U256::from(1058), // Increased to cover L1 fees (1048) + base fees + ..Default::default() + }, + ); + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_fee_overhead: Some(U256::from(1_000)), + l1_base_fee_scalar: U256::from(1_000), + l2_block: Some(U256::from(0)), + ..Default::default() + }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::REGOLITH)) + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(100)) + .enveloped_tx(Some(bytes!("FACADE"))) + .source_hash(B256::ZERO) + .build() + .unwrap(), + ); + + let mut evm = ctx.build_op(); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + handler.validate_against_state_and_deduct_caller(&mut evm).unwrap(); + + // Check the account balance is updated. + let account = evm.ctx().journal_mut().load_account(caller).unwrap(); + assert_eq!(account.info.balance, U256::from(10)); // 1058 - 1048 = 10 + } + + #[test] + fn test_reload_l1_block_info_isthmus() { + const BLOCK_NUM: U256 = uint!(100_U256); + const L1_BASE_FEE: U256 = uint!(1_U256); + const L1_BLOB_BASE_FEE: U256 = uint!(2_U256); + const L1_BASE_FEE_SCALAR: u64 = 3; + const L1_BLOB_BASE_FEE_SCALAR: u64 = 4; + const L1_FEE_SCALARS: U256 = U256::from_limbs([ + 0, + (L1_BASE_FEE_SCALAR << (64 - BASE_FEE_SCALAR_OFFSET * 2)) | L1_BLOB_BASE_FEE_SCALAR, + 0, + 0, + ]); + const OPERATOR_FEE_SCALAR: u64 = 5; + const OPERATOR_FEE_CONST: u64 = 6; + const OPERATOR_FEE: U256 = + U256::from_limbs([OPERATOR_FEE_CONST, OPERATOR_FEE_SCALAR, 0, 0]); + + let mut db = InMemoryDB::default(); + let l1_block_contract = db.load_account(L1_BLOCK_CONTRACT).unwrap(); + l1_block_contract.storage.insert(L1_BASE_FEE_SLOT, L1_BASE_FEE); + l1_block_contract.storage.insert(ECOTONE_L1_BLOB_BASE_FEE_SLOT, L1_BLOB_BASE_FEE); + l1_block_contract.storage.insert(ECOTONE_L1_FEE_SCALARS_SLOT, L1_FEE_SCALARS); + l1_block_contract.storage.insert(OPERATOR_FEE_SCALARS_SLOT, OPERATOR_FEE); + db.insert_account_info( + Address::ZERO, + AccountInfo { balance: U256::from(1000), ..Default::default() }, + ); + + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l2_block: Some(BLOCK_NUM + U256::from(1)), // ahead by one block + ..Default::default() + }) + .with_block(BlockEnv { number: BLOCK_NUM, ..Default::default() }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::ISTHMUS)); + + let mut evm = ctx.build_op(); + + assert_ne!(evm.ctx().chain().l2_block, Some(BLOCK_NUM)); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + handler.validate_against_state_and_deduct_caller(&mut evm).unwrap(); + + assert_eq!( + *evm.ctx().chain(), + L1BlockInfo { + l2_block: Some(BLOCK_NUM), + l1_base_fee: L1_BASE_FEE, + l1_base_fee_scalar: U256::from(L1_BASE_FEE_SCALAR), + l1_blob_base_fee: Some(L1_BLOB_BASE_FEE), + l1_blob_base_fee_scalar: Some(U256::from(L1_BLOB_BASE_FEE_SCALAR)), + empty_ecotone_scalars: false, + l1_fee_overhead: None, + operator_fee_scalar: Some(U256::from(OPERATOR_FEE_SCALAR)), + operator_fee_constant: Some(U256::from(OPERATOR_FEE_CONST)), + tx_l1_cost: Some(U256::ZERO), + da_footprint_gas_scalar: None + } + ); + } + + #[test] + fn test_parse_da_footprint_gas_scalar_jovian() { + const BLOCK_NUM: U256 = uint!(100_U256); + const L1_BASE_FEE: U256 = uint!(1_U256); + const L1_BLOB_BASE_FEE: U256 = uint!(2_U256); + const L1_BASE_FEE_SCALAR: u64 = 3; + const L1_BLOB_BASE_FEE_SCALAR: u64 = 4; + const L1_FEE_SCALARS: U256 = U256::from_limbs([ + 0, + (L1_BASE_FEE_SCALAR << (64 - BASE_FEE_SCALAR_OFFSET * 2)) | L1_BLOB_BASE_FEE_SCALAR, + 0, + 0, + ]); + const OPERATOR_FEE_SCALAR: u8 = 5; + const OPERATOR_FEE_CONST: u8 = 6; + const DA_FOOTPRINT_GAS_SCALAR: u8 = 7; + let mut operator_fee_and_da_footprint = [0u8; 32]; + operator_fee_and_da_footprint[31] = OPERATOR_FEE_CONST; + operator_fee_and_da_footprint[23] = OPERATOR_FEE_SCALAR; + operator_fee_and_da_footprint[19] = DA_FOOTPRINT_GAS_SCALAR; + let operator_fee_and_da_footprint_u256 = U256::from_be_bytes(operator_fee_and_da_footprint); + + let mut db = InMemoryDB::default(); + let l1_block_contract = db.load_account(L1_BLOCK_CONTRACT).unwrap(); + l1_block_contract.storage.insert(L1_BASE_FEE_SLOT, L1_BASE_FEE); + l1_block_contract.storage.insert(ECOTONE_L1_BLOB_BASE_FEE_SLOT, L1_BLOB_BASE_FEE); + l1_block_contract.storage.insert(ECOTONE_L1_FEE_SCALARS_SLOT, L1_FEE_SCALARS); + l1_block_contract + .storage + .insert(OPERATOR_FEE_SCALARS_SLOT, operator_fee_and_da_footprint_u256); + db.insert_account_info( + Address::ZERO, + AccountInfo { balance: U256::from(6000), ..Default::default() }, + ); + + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l2_block: Some(BLOCK_NUM + U256::from(1)), // ahead by one block + operator_fee_scalar: Some(U256::from(2)), + operator_fee_constant: Some(U256::from(50)), + ..Default::default() + }) + .with_block(BlockEnv { number: BLOCK_NUM, ..Default::default() }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::JOVIAN)) + // set the operator fee to a low value + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(10)) + .enveloped_tx(Some(bytes!("FACADE"))) + .build_fill(), + ); + + let mut evm = ctx.build_op(); + + assert_ne!(evm.ctx().chain().l2_block, Some(BLOCK_NUM)); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + handler.validate_against_state_and_deduct_caller(&mut evm).unwrap(); + + assert_eq!( + *evm.ctx().chain(), + L1BlockInfo { + l2_block: Some(BLOCK_NUM), + l1_base_fee: L1_BASE_FEE, + l1_base_fee_scalar: U256::from(L1_BASE_FEE_SCALAR), + l1_blob_base_fee: Some(L1_BLOB_BASE_FEE), + l1_blob_base_fee_scalar: Some(U256::from(L1_BLOB_BASE_FEE_SCALAR)), + empty_ecotone_scalars: false, + l1_fee_overhead: None, + operator_fee_scalar: Some(U256::from(OPERATOR_FEE_SCALAR)), + operator_fee_constant: Some(U256::from(OPERATOR_FEE_CONST)), + tx_l1_cost: Some(U256::ZERO), + da_footprint_gas_scalar: Some(DA_FOOTPRINT_GAS_SCALAR as u16), + } + ); + } + + #[test] + fn test_reload_l1_block_info_regolith() { + const BLOCK_NUM: U256 = uint!(200_U256); + const L1_BASE_FEE: U256 = uint!(7_U256); + const L1_FEE_OVERHEAD: U256 = uint!(9_U256); + const L1_BASE_FEE_SCALAR: u64 = 11; + + let mut db = InMemoryDB::default(); + let l1_block_contract = db.load_account(L1_BLOCK_CONTRACT).unwrap(); + l1_block_contract.storage.insert(L1_BASE_FEE_SLOT, L1_BASE_FEE); + // Pre-ecotone bedrock/regolith slots + use crate::constants::{L1_OVERHEAD_SLOT, L1_SCALAR_SLOT}; + l1_block_contract.storage.insert(L1_OVERHEAD_SLOT, L1_FEE_OVERHEAD); + l1_block_contract.storage.insert(L1_SCALAR_SLOT, U256::from(L1_BASE_FEE_SCALAR)); + + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l2_block: Some(BLOCK_NUM + U256::from(1)), + ..Default::default() + }) + .with_block(BlockEnv { number: BLOCK_NUM, ..Default::default() }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::REGOLITH)); + + let mut evm = ctx.build_op(); + assert_ne!(evm.ctx().chain().l2_block, Some(BLOCK_NUM)); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + handler.validate_against_state_and_deduct_caller(&mut evm).unwrap(); + + assert_eq!( + *evm.ctx().chain(), + L1BlockInfo { + l2_block: Some(BLOCK_NUM), + l1_base_fee: L1_BASE_FEE, + l1_fee_overhead: Some(L1_FEE_OVERHEAD), + l1_base_fee_scalar: U256::from(L1_BASE_FEE_SCALAR), + tx_l1_cost: Some(U256::ZERO), + ..Default::default() + } + ); + } + + #[test] + fn test_reload_l1_block_info_ecotone_pre_isthmus() { + const BLOCK_NUM: U256 = uint!(300_U256); + const L1_BASE_FEE: U256 = uint!(13_U256); + const L1_BLOB_BASE_FEE: U256 = uint!(17_U256); + const L1_BASE_FEE_SCALAR: u64 = 19; + const L1_BLOB_BASE_FEE_SCALAR: u64 = 23; + const L1_FEE_SCALARS: U256 = U256::from_limbs([ + 0, + (L1_BASE_FEE_SCALAR << (64 - BASE_FEE_SCALAR_OFFSET * 2)) | L1_BLOB_BASE_FEE_SCALAR, + 0, + 0, + ]); + + let mut db = InMemoryDB::default(); + let l1_block_contract = db.load_account(L1_BLOCK_CONTRACT).unwrap(); + l1_block_contract.storage.insert(L1_BASE_FEE_SLOT, L1_BASE_FEE); + l1_block_contract.storage.insert(ECOTONE_L1_BLOB_BASE_FEE_SLOT, L1_BLOB_BASE_FEE); + l1_block_contract.storage.insert(ECOTONE_L1_FEE_SCALARS_SLOT, L1_FEE_SCALARS); + + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l2_block: Some(BLOCK_NUM + U256::from(1)), + ..Default::default() + }) + .with_block(BlockEnv { number: BLOCK_NUM, ..Default::default() }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::ECOTONE)); + + let mut evm = ctx.build_op(); + assert_ne!(evm.ctx().chain().l2_block, Some(BLOCK_NUM)); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + handler.validate_against_state_and_deduct_caller(&mut evm).unwrap(); + + assert_eq!( + *evm.ctx().chain(), + L1BlockInfo { + l2_block: Some(BLOCK_NUM), + l1_base_fee: L1_BASE_FEE, + l1_base_fee_scalar: U256::from(L1_BASE_FEE_SCALAR), + l1_blob_base_fee: Some(L1_BLOB_BASE_FEE), + l1_blob_base_fee_scalar: Some(U256::from(L1_BLOB_BASE_FEE_SCALAR)), + empty_ecotone_scalars: false, + l1_fee_overhead: None, + tx_l1_cost: Some(U256::ZERO), + ..Default::default() + } + ); + } + + #[test] + fn test_load_l1_block_info_isthmus_none() { + const BLOCK_NUM: U256 = uint!(100_U256); + const L1_BASE_FEE: U256 = uint!(1_U256); + const L1_BLOB_BASE_FEE: U256 = uint!(2_U256); + const L1_BASE_FEE_SCALAR: u64 = 3; + const L1_BLOB_BASE_FEE_SCALAR: u64 = 4; + const L1_FEE_SCALARS: U256 = U256::from_limbs([ + 0, + (L1_BASE_FEE_SCALAR << (64 - BASE_FEE_SCALAR_OFFSET * 2)) | L1_BLOB_BASE_FEE_SCALAR, + 0, + 0, + ]); + const OPERATOR_FEE_SCALAR: u64 = 5; + const OPERATOR_FEE_CONST: u64 = 6; + const OPERATOR_FEE: U256 = + U256::from_limbs([OPERATOR_FEE_CONST, OPERATOR_FEE_SCALAR, 0, 0]); + + let mut db = InMemoryDB::default(); + let l1_block_contract = db.load_account(L1_BLOCK_CONTRACT).unwrap(); + l1_block_contract.storage.insert(L1_BASE_FEE_SLOT, L1_BASE_FEE); + l1_block_contract.storage.insert(ECOTONE_L1_BLOB_BASE_FEE_SLOT, L1_BLOB_BASE_FEE); + l1_block_contract.storage.insert(ECOTONE_L1_FEE_SCALARS_SLOT, L1_FEE_SCALARS); + l1_block_contract.storage.insert(OPERATOR_FEE_SCALARS_SLOT, OPERATOR_FEE); + db.insert_account_info( + Address::ZERO, + AccountInfo { balance: U256::from(1000), ..Default::default() }, + ); + + let ctx = Context::op() + .with_db(db) + .with_block(BlockEnv { number: BLOCK_NUM, ..Default::default() }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::ISTHMUS)); + + let mut evm = ctx.build_op(); + + assert_ne!(evm.ctx().chain().l2_block, Some(BLOCK_NUM)); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + handler.validate_against_state_and_deduct_caller(&mut evm).unwrap(); + + assert_eq!( + *evm.ctx().chain(), + L1BlockInfo { + l2_block: Some(BLOCK_NUM), + l1_base_fee: L1_BASE_FEE, + l1_base_fee_scalar: U256::from(L1_BASE_FEE_SCALAR), + l1_blob_base_fee: Some(L1_BLOB_BASE_FEE), + l1_blob_base_fee_scalar: Some(U256::from(L1_BLOB_BASE_FEE_SCALAR)), + empty_ecotone_scalars: false, + l1_fee_overhead: None, + operator_fee_scalar: Some(U256::from(OPERATOR_FEE_SCALAR)), + operator_fee_constant: Some(U256::from(OPERATOR_FEE_CONST)), + tx_l1_cost: Some(U256::ZERO), + ..Default::default() + } + ); + } + + #[test] + fn test_remove_l1_cost() { + let caller = Address::ZERO; + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { balance: U256::from(1049), ..Default::default() }, + ); + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_fee_overhead: Some(U256::from(1_000)), + l1_base_fee_scalar: U256::from(1_000), + l2_block: Some(U256::from(0)), + ..Default::default() + }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::REGOLITH)) + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(100)) + .source_hash(B256::ZERO) + .enveloped_tx(Some(bytes!("FACADE"))) + .build() + .unwrap(), + ); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + // l1block cost is 1048 fee. + handler.validate_against_state_and_deduct_caller(&mut evm).unwrap(); + + // Check the account balance is updated. + let account = evm.ctx().journal_mut().load_account(caller).unwrap(); + assert_eq!(account.info.balance, U256::from(1)); + } + + #[test] + fn test_remove_operator_cost_isthmus() { + let caller = Address::ZERO; + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { balance: U256::from(151), ..Default::default() }, + ); + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + operator_fee_scalar: Some(U256::from(10_000_000)), + operator_fee_constant: Some(U256::from(50)), + l2_block: Some(U256::from(0)), + ..Default::default() + }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::ISTHMUS)) + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(10)) + .enveloped_tx(Some(bytes!("FACADE"))) + .build_fill(), + ); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + // Under Isthmus the operator fee cost is operator_fee_scalar * gas_limit / 1e6 + + // operator_fee_constant 10_000_000 * 10 / 1_000_000 + 50 = 150 + handler.validate_against_state_and_deduct_caller(&mut evm).unwrap(); + + // Check the account balance is updated. + let account = evm.ctx().journal_mut().load_account(caller).unwrap(); + assert_eq!(account.info.balance, U256::from(1)); + } + + #[test] + fn test_remove_operator_cost_jovian() { + let caller = Address::ZERO; + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { balance: U256::from(2_051), ..Default::default() }, + ); + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + operator_fee_scalar: Some(U256::from(2)), + operator_fee_constant: Some(U256::from(50)), + l2_block: Some(U256::from(0)), + ..Default::default() + }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::JOVIAN)) + .with_tx( + OpTransaction::builder() + .base(TxEnv::builder().gas_limit(10)) + .enveloped_tx(Some(bytes!("FACADE"))) + .build_fill(), + ); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + // Under Jovian the operator fee cost is operator_fee_scalar * gas_limit * 100 + + // operator_fee_constant 2 * 10 * 100 + 50 = 2_050 + handler.validate_against_state_and_deduct_caller(&mut evm).unwrap(); + + let account = evm.ctx().journal_mut().load_account(caller).unwrap(); + assert_eq!(account.info.balance, U256::from(1)); + } + + #[test] + fn test_remove_l1_cost_lack_of_funds() { + let caller = Address::ZERO; + let mut db = InMemoryDB::default(); + db.insert_account_info( + caller, + AccountInfo { balance: U256::from(48), ..Default::default() }, + ); + let ctx = Context::op() + .with_db(db) + .with_chain(L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_fee_overhead: Some(U256::from(1_000)), + l1_base_fee_scalar: U256::from(1_000), + l2_block: Some(U256::from(0)), + ..Default::default() + }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::REGOLITH)) + .modify_tx_chained(|tx| { + tx.enveloped_tx = Some(bytes!("FACADE")); + }); + + // l1block cost is 1048 fee. + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + // l1block cost is 1048 fee. + assert_eq!( + handler.validate_against_state_and_deduct_caller(&mut evm), + Err(EVMError::Transaction( + InvalidTransaction::LackOfFundForMaxFee { + fee: Box::new(U256::from(1048)), + balance: Box::new(U256::from(48)), + } + .into(), + )) + ); + } + + #[test] + fn test_validate_sys_tx() { + // mark the tx as a system transaction. + let ctx = Context::op() + .modify_tx_chained(|tx| { + tx.deposit.source_hash = B256::from([1u8; 32]); + tx.deposit.is_system_transaction = true; + }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::REGOLITH)); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + assert_eq!( + handler.validate_env(&mut evm), + Err(EVMError::Transaction(OpTransactionError::DepositSystemTxPostRegolith)) + ); + + // With BEDROCK spec. + let ctx = evm.into_context(); + let mut evm = ctx.with_cfg(CfgEnv::new_with_spec(OpSpecId::BEDROCK)).build_op(); + + // Pre-regolith system transactions should be allowed. + assert!(handler.validate_env(&mut evm).is_ok()); + } + + #[test] + fn test_validate_deposit_tx() { + // Set source hash. + let ctx = Context::op() + .modify_tx_chained(|tx| { + tx.deposit.source_hash = B256::from([1u8; 32]); + }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::REGOLITH)); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + assert!(handler.validate_env(&mut evm).is_ok()); + } + + #[test] + fn test_validate_tx_against_state_deposit_tx() { + // Set source hash. + let ctx = Context::op() + .modify_tx_chained(|tx| { + tx.deposit.source_hash = B256::from([1u8; 32]); + }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::REGOLITH)); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + // Nonce and balance checks should be skipped for deposit transactions. + assert!(handler.validate_env(&mut evm).is_ok()); + } + + #[test] + fn test_halted_deposit_tx_post_regolith() { + let ctx = Context::op() + .modify_tx_chained(|tx| { + // Set up as deposit transaction by having a deposit with source_hash + tx.deposit.source_hash = B256::from([1u8; 32]); + }) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::REGOLITH)); + + let mut evm = ctx.build_op(); + let mut handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + assert_eq!( + handler.execution_result( + &mut evm, + FrameResult::Call(CallOutcome::new( + InterpreterResult { + result: InstructionResult::OutOfGas, + output: Default::default(), + gas: Default::default(), + }, + Default::default() + )), + ResultGas::default(), + ), + Err(EVMError::Transaction(OpTransactionError::HaltedDepositPostRegolith)) + ) + } + + #[test] + fn test_tx_zero_value_touch_caller() { + let ctx = Context::op(); + + let mut evm = ctx.build_op(); + + assert!(!evm.0.ctx.journal_mut().load_account(Address::ZERO).unwrap().is_touched()); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + handler.validate_against_state_and_deduct_caller(&mut evm).unwrap(); + + assert!(evm.0.ctx.journal_mut().load_account(Address::ZERO).unwrap().is_touched()); + } + + #[rstest] + #[case::deposit(true)] + #[case::dyn_fee(false)] + fn test_operator_fee_refund(#[case] is_deposit: bool) { + const SENDER: Address = Address::ZERO; + const GAS_PRICE: u128 = 0xFF; + const OP_FEE_MOCK_PARAM: u128 = 0xFFFF; + + let ctx = Context::op() + .with_tx( + OpTransaction::builder() + .base( + TxEnv::builder().gas_price(GAS_PRICE).gas_priority_fee(None).caller(SENDER), + ) + .enveloped_tx(if is_deposit { None } else { Some(bytes!("FACADE")) }) + .source_hash(if is_deposit { B256::from([1u8; 32]) } else { B256::ZERO }) + .build_fill(), + ) + .with_cfg(CfgEnv::new_with_spec(OpSpecId::ISTHMUS)); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + // Set the operator fee scalar & constant to non-zero values in the L1 block info. + evm.ctx().chain.operator_fee_scalar = Some(U256::from(OP_FEE_MOCK_PARAM)); + evm.ctx().chain.operator_fee_constant = Some(U256::from(OP_FEE_MOCK_PARAM)); + + let mut gas = Gas::new(100); + gas.set_spent(10); + let mut exec_result = FrameResult::Call(CallOutcome::new( + InterpreterResult { + result: InstructionResult::Return, + output: Default::default(), + gas, + }, + 0..0, + )); + + // Reimburse the caller for the unspent portion of the fees. + handler.reimburse_caller(&mut evm, &mut exec_result).unwrap(); + + // Compute the expected refund amount. If the transaction is a deposit, the operator fee + // refund never applies. If the transaction is not a deposit, the operator fee + // refund is added to the refund amount. + let mut expected_refund = + U256::from(GAS_PRICE * (gas.remaining() + gas.refunded() as u64) as u128); + let op_fee_refund = evm.ctx().chain().operator_fee_refund(&gas, OpSpecId::ISTHMUS); + assert!(op_fee_refund > U256::ZERO); + + if !is_deposit { + expected_refund += op_fee_refund; + } + + // Check that the caller was reimbursed the correct amount of ETH. + let account = evm.ctx().journal_mut().load_account(SENDER).unwrap(); + assert_eq!(account.info.balance, expected_refund); + } + + #[test] + fn test_tx_low_balance_nonce_unchanged() { + let ctx = Context::op().with_tx( + OpTransaction::builder().base(TxEnv::builder().value(U256::from(1000))).build_fill(), + ); + + let mut evm = ctx.build_op(); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + let result = handler.validate_against_state_and_deduct_caller(&mut evm); + + assert!(matches!( + result.err().unwrap(), + EVMError::Transaction(OpTransactionError::Base( + InvalidTransaction::LackOfFundForMaxFee { .. } + )) + )); + assert_eq!(evm.0.ctx.journal_mut().load_account(Address::ZERO).unwrap().info.nonce, 0); + } + + #[test] + fn test_validate_missing_enveloped_tx() { + use crate::transaction::deposit::DepositTransactionParts; + + // Create a non-deposit transaction without enveloped_tx + let ctx = Context::op().with_tx(OpTransaction { + base: TxEnv::builder().build_fill(), + enveloped_tx: None, // Missing enveloped_tx for non-deposit transaction + deposit: DepositTransactionParts::default(), // No source_hash means non-deposit + }); + + let mut evm = ctx.build_op(); + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + assert_eq!( + handler.validate_env(&mut evm), + Err(EVMError::Transaction(OpTransactionError::MissingEnvelopedTx)) + ); + } +} diff --git a/src/l1block.rs b/src/l1block.rs new file mode 100644 index 00000000000..d314dfe3bf2 --- /dev/null +++ b/src/l1block.rs @@ -0,0 +1,669 @@ +//! Contains the `[L1BlockInfo]` type and its implementation. +use crate::{ + OpSpecId, + constants::{ + BASE_FEE_SCALAR_OFFSET, BLOB_BASE_FEE_SCALAR_OFFSET, DA_FOOTPRINT_GAS_SCALAR_OFFSET, + DA_FOOTPRINT_GAS_SCALAR_SLOT, ECOTONE_L1_BLOB_BASE_FEE_SLOT, ECOTONE_L1_FEE_SCALARS_SLOT, + EMPTY_SCALARS, L1_BASE_FEE_SLOT, L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT, L1_SCALAR_SLOT, + NON_ZERO_BYTE_COST, OPERATOR_FEE_CONSTANT_OFFSET, OPERATOR_FEE_JOVIAN_MULTIPLIER, + OPERATOR_FEE_SCALAR_DECIMAL, OPERATOR_FEE_SCALAR_OFFSET, OPERATOR_FEE_SCALARS_SLOT, + }, + transaction::{OpTxTr, estimate_tx_compressed_size}, +}; +use revm::{ + context_interface::cfg::gas::{NON_ZERO_BYTE_MULTIPLIER_ISTANBUL, STANDARD_TOKEN_COST}, + database_interface::Database, + interpreter::{Gas, gas::get_tokens_in_calldata_istanbul}, + primitives::U256, +}; + +/// L1 block info +/// +/// We can extract L1 epoch data from each L2 block, by looking at the `setL1BlockValues` +/// transaction data. This data is then used to calculate the L1 cost of a transaction. +/// +/// Here is the format of the `setL1BlockValues` transaction data: +/// +/// setL1BlockValues(uint64 _number, uint64 _timestamp, uint256 _basefee, bytes32 _hash, +/// uint64 _sequenceNumber, bytes32 _batcherHash, uint256 _l1FeeOverhead, uint256 _l1FeeScalar) +/// +/// For now, we only care about the fields necessary for L1 cost calculation. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct L1BlockInfo { + /// The L2 block number. If not same as the one in the context, + /// `L1BlockInfo` is not valid and will be reloaded from the database. + pub l2_block: Option, + /// The base fee of the L1 origin block. + pub l1_base_fee: U256, + /// The current L1 fee overhead. None if Ecotone is activated. + pub l1_fee_overhead: Option, + /// The current L1 fee scalar. + pub l1_base_fee_scalar: U256, + /// The current L1 blob base fee. None if Ecotone is not activated, except if + /// `empty_ecotone_scalars` is `true`. + pub l1_blob_base_fee: Option, + /// The current L1 blob base fee scalar. None if Ecotone is not activated. + pub l1_blob_base_fee_scalar: Option, + /// The operator fee scalar. None if Isthmus is not activated. + pub operator_fee_scalar: Option, + /// The operator fee constant. None if Isthmus is not activated. + pub operator_fee_constant: Option, + /// Da footprint gas scalar. Used to set the DA footprint block limit on the L2. Always null + /// prior to the Jovian hardfork. + pub da_footprint_gas_scalar: Option, + /// True if Ecotone is activated, but the L1 fee scalars have not yet been set. + pub empty_ecotone_scalars: bool, + /// Last calculated l1 fee cost. Uses as a cache between validation and pre execution stages. + pub tx_l1_cost: Option, +} + +impl L1BlockInfo { + /// Fetch the DA footprint gas scalar from the database. + pub fn fetch_da_footprint_gas_scalar(db: &mut DB) -> Result { + let da_footprint_gas_scalar_slot = + db.storage(L1_BLOCK_CONTRACT, DA_FOOTPRINT_GAS_SCALAR_SLOT)?.to_be_bytes::<32>(); + + // Extract the first 2 bytes directly as a u16 in big-endian format + let bytes = [ + da_footprint_gas_scalar_slot[DA_FOOTPRINT_GAS_SCALAR_OFFSET], + da_footprint_gas_scalar_slot[DA_FOOTPRINT_GAS_SCALAR_OFFSET + 1], + ]; + Ok(u16::from_be_bytes(bytes)) + } + + /// Try to fetch the L1 block info from the database, post-Jovian. + fn try_fetch_jovian(&mut self, db: &mut DB) -> Result<(), DB::Error> { + self.da_footprint_gas_scalar = Some(Self::fetch_da_footprint_gas_scalar(db)?); + + Ok(()) + } + + /// Try to fetch the L1 block info from the database, post-Isthmus. + fn try_fetch_isthmus(&mut self, db: &mut DB) -> Result<(), DB::Error> { + // Post-isthmus L1 block info + let operator_fee_scalars = + db.storage(L1_BLOCK_CONTRACT, OPERATOR_FEE_SCALARS_SLOT)?.to_be_bytes::<32>(); + + // The `operator_fee_scalar` is stored as a big endian u32 at + // OPERATOR_FEE_SCALAR_OFFSET. + self.operator_fee_scalar = Some(U256::from_be_slice( + operator_fee_scalars[OPERATOR_FEE_SCALAR_OFFSET..OPERATOR_FEE_SCALAR_OFFSET + 4] + .as_ref(), + )); + // The `operator_fee_constant` is stored as a big endian u64 at + // OPERATOR_FEE_CONSTANT_OFFSET. + self.operator_fee_constant = Some(U256::from_be_slice( + operator_fee_scalars[OPERATOR_FEE_CONSTANT_OFFSET..OPERATOR_FEE_CONSTANT_OFFSET + 8] + .as_ref(), + )); + + Ok(()) + } + + /// Try to fetch the L1 block info from the database, post-Ecotone. + fn try_fetch_ecotone(&mut self, db: &mut DB) -> Result<(), DB::Error> { + self.l1_blob_base_fee = Some(db.storage(L1_BLOCK_CONTRACT, ECOTONE_L1_BLOB_BASE_FEE_SLOT)?); + + let l1_fee_scalars = + db.storage(L1_BLOCK_CONTRACT, ECOTONE_L1_FEE_SCALARS_SLOT)?.to_be_bytes::<32>(); + + self.l1_base_fee_scalar = U256::from_be_slice( + l1_fee_scalars[BASE_FEE_SCALAR_OFFSET..BASE_FEE_SCALAR_OFFSET + 4].as_ref(), + ); + + let l1_blob_base_fee = U256::from_be_slice( + l1_fee_scalars[BLOB_BASE_FEE_SCALAR_OFFSET..BLOB_BASE_FEE_SCALAR_OFFSET + 4].as_ref(), + ); + self.l1_blob_base_fee_scalar = Some(l1_blob_base_fee); + + // Check if the L1 fee scalars are empty. If so, we use the Bedrock cost function. + // The L1 fee overhead is only necessary if `empty_ecotone_scalars` is true, as it was + // deprecated in Ecotone. + self.empty_ecotone_scalars = l1_blob_base_fee.is_zero() && + l1_fee_scalars[BASE_FEE_SCALAR_OFFSET..BLOB_BASE_FEE_SCALAR_OFFSET + 4] == + EMPTY_SCALARS; + self.l1_fee_overhead = self + .empty_ecotone_scalars + .then(|| db.storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT)) + .transpose()?; + + Ok(()) + } + + /// Try to fetch the L1 block info from the database. + pub fn try_fetch( + db: &mut DB, + l2_block: U256, + spec_id: OpSpecId, + ) -> Result { + // Ensure the L1 Block account is loaded into the cache. + let _ = db.basic(L1_BLOCK_CONTRACT)?; + + let mut out = Self { + l2_block: Some(l2_block), + l1_base_fee: db.storage(L1_BLOCK_CONTRACT, L1_BASE_FEE_SLOT)?, + ..Default::default() + }; + + // Post-Ecotone + if !spec_id.is_enabled_in(OpSpecId::ECOTONE) { + out.l1_base_fee_scalar = db.storage(L1_BLOCK_CONTRACT, L1_SCALAR_SLOT)?; + out.l1_fee_overhead = Some(db.storage(L1_BLOCK_CONTRACT, L1_OVERHEAD_SLOT)?); + + return Ok(out); + } + + out.try_fetch_ecotone(db)?; + + // Post-Isthmus L1 block info + if spec_id.is_enabled_in(OpSpecId::ISTHMUS) { + out.try_fetch_isthmus(db)?; + } + + // Pre-Jovian + if spec_id.is_enabled_in(OpSpecId::JOVIAN) { + out.try_fetch_jovian(db)?; + } + + Ok(out) + } + + /// Calculate the operator fee for executing this transaction. + /// + /// Introduced in isthmus. Prior to isthmus, the operator fee is always zero. + pub fn operator_fee_charge(&self, input: &[u8], gas_limit: U256, spec_id: OpSpecId) -> U256 { + // If the input is a deposit transaction or empty, the default value is zero. + if input.is_empty() || input.first() == Some(&0x7E) { + return U256::ZERO; + } + + self.operator_fee_charge_inner(gas_limit, spec_id) + } + + /// Calculate the operator fee for the given `gas`. + fn operator_fee_charge_inner(&self, gas: U256, spec_id: OpSpecId) -> U256 { + let operator_fee_scalar = + self.operator_fee_scalar.expect("Missing operator fee scalar for isthmus L1 Block"); + let operator_fee_constant = + self.operator_fee_constant.expect("Missing operator fee constant for isthmus L1 Block"); + + let product = if spec_id.is_enabled_in(OpSpecId::JOVIAN) { + gas.saturating_mul(operator_fee_scalar) + .saturating_mul(U256::from(OPERATOR_FEE_JOVIAN_MULTIPLIER)) + } else { + gas.saturating_mul(operator_fee_scalar) / U256::from(OPERATOR_FEE_SCALAR_DECIMAL) + }; + + product.saturating_add(operator_fee_constant) + } + + /// Calculate the operator fee for executing this transaction. + /// + /// Introduced in isthmus. Prior to isthmus, the operator fee is always zero. + pub fn operator_fee_refund(&self, gas: &Gas, spec_id: OpSpecId) -> U256 { + if !spec_id.is_enabled_in(OpSpecId::ISTHMUS) { + return U256::ZERO; + } + + let operator_cost_gas_limit = + self.operator_fee_charge_inner(U256::from(gas.limit()), spec_id); + let operator_cost_gas_used = self.operator_fee_charge_inner( + U256::from(gas.limit() - (gas.remaining() + gas.refunded() as u64)), + spec_id, + ); + + operator_cost_gas_limit.saturating_sub(operator_cost_gas_used) + } + + /// Calculate the data gas for posting the transaction on L1. Calldata costs 16 gas per byte + /// after compression. + /// + /// Prior to fjord, calldata costs 16 gas per non-zero byte and 4 gas per zero byte. + /// + /// Prior to regolith, an extra 68 non-zero bytes were included in the rollup data costs to + /// account for the empty signature. + pub fn data_gas(&self, input: &[u8], spec_id: OpSpecId) -> U256 { + if spec_id.is_enabled_in(OpSpecId::FJORD) { + let estimated_size = self.tx_estimated_size_fjord(input); + + return estimated_size + .saturating_mul(U256::from(NON_ZERO_BYTE_COST)) + .wrapping_div(U256::from(1_000_000)); + }; + + // tokens in calldata where non-zero bytes are priced 4 times higher than zero bytes (Same + // as in Istanbul). + let mut tokens_in_transaction_data = get_tokens_in_calldata_istanbul(input); + + // Prior to regolith, an extra 68 non zero bytes were included in the rollup data costs. + if !spec_id.is_enabled_in(OpSpecId::REGOLITH) { + tokens_in_transaction_data += 68 * NON_ZERO_BYTE_MULTIPLIER_ISTANBUL; + } + + U256::from(tokens_in_transaction_data.saturating_mul(STANDARD_TOKEN_COST)) + } + + // Calculate the estimated compressed transaction size in bytes, scaled by 1e6. + // This value is computed based on the following formula: + // max(minTransactionSize, intercept + fastlzCoef*fastlzSize) + fn tx_estimated_size_fjord(&self, input: &[u8]) -> U256 { + U256::from(estimate_tx_compressed_size(input)) + } + + /// Clears the cached L1 cost of the transaction. + pub const fn clear_tx_l1_cost(&mut self) { + self.tx_l1_cost = None; + } + + /// Calculate additional transaction cost with `OpTxTr`. + /// + /// Internally calls [`L1BlockInfo::tx_cost`]. + pub fn tx_cost_with_tx(&mut self, tx: impl OpTxTr, spec: OpSpecId) -> Option { + // account for additional cost of l1 fee and operator fee + let enveloped_tx = tx.enveloped_tx()?; + let gas_limit = U256::from(tx.gas_limit()); + Some(self.tx_cost(enveloped_tx, gas_limit, spec)) + } + + /// Calculate additional transaction cost. + #[inline] + pub fn tx_cost(&mut self, enveloped_tx: &[u8], gas_limit: U256, spec: OpSpecId) -> U256 { + // compute L1 cost + let mut additional_cost = self.calculate_tx_l1_cost(enveloped_tx, spec); + + // compute operator fee + if spec.is_enabled_in(OpSpecId::ISTHMUS) { + let operator_fee_charge = self.operator_fee_charge(enveloped_tx, gas_limit, spec); + additional_cost = additional_cost.saturating_add(operator_fee_charge); + } + + additional_cost + } + + /// Calculate the gas cost of a transaction based on L1 block data posted on L2, depending on + /// the [`OpSpecId`] passed. + pub fn calculate_tx_l1_cost(&mut self, input: &[u8], spec_id: OpSpecId) -> U256 { + if let Some(tx_l1_cost) = self.tx_l1_cost { + return tx_l1_cost; + } + // If the input is a deposit transaction or empty, the default value is zero. + let tx_l1_cost = if input.is_empty() || input.first() == Some(&0x7E) { + return U256::ZERO; + } else if spec_id.is_enabled_in(OpSpecId::FJORD) { + self.calculate_tx_l1_cost_fjord(input) + } else if spec_id.is_enabled_in(OpSpecId::ECOTONE) { + self.calculate_tx_l1_cost_ecotone(input, spec_id) + } else { + self.calculate_tx_l1_cost_bedrock(input, spec_id) + }; + + self.tx_l1_cost = Some(tx_l1_cost); + tx_l1_cost + } + + /// Calculate the gas cost of a transaction based on L1 block data posted on L2, pre-Ecotone. + fn calculate_tx_l1_cost_bedrock(&self, input: &[u8], spec_id: OpSpecId) -> U256 { + let rollup_data_gas_cost = self.data_gas(input, spec_id); + rollup_data_gas_cost + .saturating_add(self.l1_fee_overhead.unwrap_or_default()) + .saturating_mul(self.l1_base_fee) + .saturating_mul(self.l1_base_fee_scalar) + .wrapping_div(U256::from(1_000_000)) + } + + /// Calculate the gas cost of a transaction based on L1 block data posted on L2, post-Ecotone. + /// + /// [`OpSpecId::ECOTONE`] L1 cost function: + /// `(calldataGas/16)*(l1BaseFee*16*l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar)/1e6` + /// + /// We divide "calldataGas" by 16 to change from units of calldata gas to "estimated # of bytes + /// when compressed". Known as "compressedTxSize" in the spec. + /// + /// Function is actually computed as follows for better precision under integer arithmetic: + /// `calldataGas*(l1BaseFee*16*l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar)/16e6` + fn calculate_tx_l1_cost_ecotone(&self, input: &[u8], spec_id: OpSpecId) -> U256 { + // There is an edgecase where, for the very first Ecotone block (unless it is activated at + // Genesis), we must use the Bedrock cost function. To determine if this is the + // case, we can check if the Ecotone parameters are unset. + if self.empty_ecotone_scalars { + return self.calculate_tx_l1_cost_bedrock(input, spec_id); + } + + let rollup_data_gas_cost = self.data_gas(input, spec_id); + let l1_fee_scaled = self.calculate_l1_fee_scaled_ecotone(); + + l1_fee_scaled + .saturating_mul(rollup_data_gas_cost) + .wrapping_div(U256::from(1_000_000 * NON_ZERO_BYTE_COST)) + } + + /// Calculate the gas cost of a transaction based on L1 block data posted on L2, post-Fjord. + /// + /// [`OpSpecId::FJORD`] L1 cost function: + /// `estimatedSize*(baseFeeScalar*l1BaseFee*16 + blobFeeScalar*l1BlobBaseFee)/1e12` + fn calculate_tx_l1_cost_fjord(&self, input: &[u8]) -> U256 { + let l1_fee_scaled = self.calculate_l1_fee_scaled_ecotone(); + if l1_fee_scaled.is_zero() { + return U256::ZERO; + } + + let estimated_size = self.tx_estimated_size_fjord(input); + + estimated_size.saturating_mul(l1_fee_scaled).wrapping_div(U256::from(1_000_000_000_000u64)) + } + + // l1BaseFee*16*l1BaseFeeScalar + l1BlobBaseFee*l1BlobBaseFeeScalar + fn calculate_l1_fee_scaled_ecotone(&self) -> U256 { + let calldata_cost_per_byte = self + .l1_base_fee + .saturating_mul(U256::from(NON_ZERO_BYTE_COST)) + .saturating_mul(self.l1_base_fee_scalar); + let blob_cost_per_byte = self + .l1_blob_base_fee + .unwrap_or_default() + .saturating_mul(self.l1_blob_base_fee_scalar.unwrap_or_default()); + + calldata_cost_per_byte.saturating_add(blob_cost_per_byte) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use revm::primitives::{bytes, hex}; + + #[test] + fn test_data_gas_non_zero_bytes() { + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000_000), + l1_fee_overhead: Some(U256::from(1_000_000)), + l1_base_fee_scalar: U256::from(1_000_000), + ..Default::default() + }; + + // 0xFACADE = 6 nibbles = 3 bytes + // 0xFACADE = 1111 1010 . 1100 1010 . 1101 1110 + + // Pre-regolith (ie bedrock) has an extra 68 non-zero bytes + // gas cost = 3 non-zero bytes * NON_ZERO_BYTE_COST + NON_ZERO_BYTE_COST * 68 + // gas cost = 3 * 16 + 68 * 16 = 1136 + let input = bytes!("FACADE"); + let bedrock_data_gas = l1_block_info.data_gas(&input, OpSpecId::BEDROCK); + assert_eq!(bedrock_data_gas, U256::from(1136)); + + // Regolith has no added 68 non zero bytes + // gas cost = 3 * 16 = 48 + let regolith_data_gas = l1_block_info.data_gas(&input, OpSpecId::REGOLITH); + assert_eq!(regolith_data_gas, U256::from(48)); + + // Fjord has a minimum compressed size of 100 bytes + // gas cost = 100 * 16 = 1600 + let fjord_data_gas = l1_block_info.data_gas(&input, OpSpecId::FJORD); + assert_eq!(fjord_data_gas, U256::from(1600)); + } + + #[test] + fn test_data_gas_zero_bytes() { + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000_000), + l1_fee_overhead: Some(U256::from(1_000_000)), + l1_base_fee_scalar: U256::from(1_000_000), + ..Default::default() + }; + + // 0xFA00CA00DE = 10 nibbles = 5 bytes + // 0xFA00CA00DE = 1111 1010 . 0000 0000 . 1100 1010 . 0000 0000 . 1101 1110 + + // Pre-regolith (ie bedrock) has an extra 68 non-zero bytes + // gas cost = 3 non-zero * NON_ZERO_BYTE_COST + 2 * ZERO_BYTE_COST + NON_ZERO_BYTE_COST * 68 + // gas cost = 3 * 16 + 2 * 4 + 68 * 16 = 1144 + let input = bytes!("FA00CA00DE"); + let bedrock_data_gas = l1_block_info.data_gas(&input, OpSpecId::BEDROCK); + assert_eq!(bedrock_data_gas, U256::from(1144)); + + // Regolith has no added 68 non zero bytes + // gas cost = 3 * 16 + 2 * 4 = 56 + let regolith_data_gas = l1_block_info.data_gas(&input, OpSpecId::REGOLITH); + assert_eq!(regolith_data_gas, U256::from(56)); + + // Fjord has a minimum compressed size of 100 bytes + // gas cost = 100 * 16 = 1600 + let fjord_data_gas = l1_block_info.data_gas(&input, OpSpecId::FJORD); + assert_eq!(fjord_data_gas, U256::from(1600)); + } + + #[test] + fn test_calculate_tx_l1_cost() { + let mut l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_fee_overhead: Some(U256::from(1_000)), + l1_base_fee_scalar: U256::from(1_000), + ..Default::default() + }; + + let input = bytes!("FACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::REGOLITH); + assert_eq!(gas_cost, U256::from(1048)); + l1_block_info.clear_tx_l1_cost(); + + // Zero rollup data gas cost should result in zero + let input = bytes!(""); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::REGOLITH); + assert_eq!(gas_cost, U256::ZERO); + l1_block_info.clear_tx_l1_cost(); + + // Deposit transactions with the EIP-2718 type of 0x7E should result in zero + let input = bytes!("7EFACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::REGOLITH); + assert_eq!(gas_cost, U256::ZERO); + } + + #[test] + fn test_calculate_tx_l1_cost_ecotone() { + let mut l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_base_fee_scalar: U256::from(1_000), + l1_blob_base_fee: Some(U256::from(1_000)), + l1_blob_base_fee_scalar: Some(U256::from(1_000)), + l1_fee_overhead: Some(U256::from(1_000)), + ..Default::default() + }; + + // calldataGas * (l1BaseFee * 16 * l1BaseFeeScalar + l1BlobBaseFee * l1BlobBaseFeeScalar) / + // (16 * 1e6) = (16 * 3) * (1000 * 16 * 1000 + 1000 * 1000) / (16 * 1e6) + // = 51 + let input = bytes!("FACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::ECOTONE); + assert_eq!(gas_cost, U256::from(51)); + l1_block_info.clear_tx_l1_cost(); + + // Zero rollup data gas cost should result in zero + let input = bytes!(""); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::ECOTONE); + assert_eq!(gas_cost, U256::ZERO); + l1_block_info.clear_tx_l1_cost(); + + // Deposit transactions with the EIP-2718 type of 0x7E should result in zero + let input = bytes!("7EFACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::ECOTONE); + assert_eq!(gas_cost, U256::ZERO); + l1_block_info.clear_tx_l1_cost(); + + // If the scalars are empty, the bedrock cost function should be used. + l1_block_info.empty_ecotone_scalars = true; + let input = bytes!("FACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::ECOTONE); + assert_eq!(gas_cost, U256::from(1048)); + } + + #[test] + fn calculate_tx_l1_cost_ecotone() { + // rig + + // l1 block info for OP mainnet ecotone block 118024092 + // 1710374401 (ecotone timestamp) + // 1711603765 (block 118024092 timestamp) + // 1720627201 (fjord timestamp) + // + // decoded from + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from_be_bytes(hex!( + "0000000000000000000000000000000000000000000000000000000af39ac327" + )), // 47036678951 + l1_base_fee_scalar: U256::from(1368), + l1_blob_base_fee: Some(U256::from_be_bytes(hex!( + "0000000000000000000000000000000000000000000000000000000d5ea528d2" + ))), // 57422457042 + l1_blob_base_fee_scalar: Some(U256::from(810949)), + ..Default::default() + }; + + // second tx in OP mainnet ecotone block 118024092 + // + const TX: &[u8] = &hex!( + "02f8b30a832253fc8402d11f39842c8a46398301388094dc6ff44d5d932cbd77b52e5612ba0529dc6226f180b844a9059cbb000000000000000000000000d43e02db81f4d46cdf8521f623d21ea0ec7562a50000000000000000000000000000000000000000000000008ac7230489e80000c001a02947e24750723b48f886931562c55d9e07f856d8e06468e719755e18bbc3a570a0784da9ce59fd7754ea5be6e17a86b348e441348cd48ace59d174772465eadbd1" + ); + + // l1 gas used for tx and l1 fee for tx, from OP mainnet block scanner + // + let expected_l1_gas_used = U256::from(2456); + let expected_l1_fee = U256::from_be_bytes(hex!( + "000000000000000000000000000000000000000000000000000006a510bd7431" // 7306020222001 wei + )); + + // test + + let gas_used = l1_block_info.data_gas(TX, OpSpecId::ECOTONE); + + assert_eq!(gas_used, expected_l1_gas_used); + + let l1_fee = l1_block_info.calculate_tx_l1_cost_ecotone(TX, OpSpecId::ECOTONE); + + assert_eq!(l1_fee, expected_l1_fee) + } + + #[test] + fn test_calculate_tx_l1_cost_fjord() { + // l1FeeScaled = baseFeeScalar*l1BaseFee*16 + blobFeeScalar*l1BlobBaseFee + // = 1000 * 1000 * 16 + 1000 * 1000 + // = 17e6 + let mut l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1_000), + l1_base_fee_scalar: U256::from(1_000), + l1_blob_base_fee: Some(U256::from(1_000)), + l1_blob_base_fee_scalar: Some(U256::from(1_000)), + ..Default::default() + }; + + // fastLzSize = 4 + // estimatedSize = max(minTransactionSize, intercept + fastlzCoef*fastlzSize) + // = max(100e6, 836500*4 - 42585600) + // = 100e6 + let input = bytes!("FACADE"); + // l1Cost = estimatedSize * l1FeeScaled / 1e12 + // = 100e6 * 17 / 1e6 + // = 1700 + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::FJORD); + assert_eq!(gas_cost, U256::from(1700)); + l1_block_info.clear_tx_l1_cost(); + + // fastLzSize = 202 + // estimatedSize = max(minTransactionSize, intercept + fastlzCoef*fastlzSize) + // = max(100e6, 836500*202 - 42585600) + // = 126387400 + let input = bytes!( + "02f901550a758302df1483be21b88304743f94f80e51afb613d764fa61751affd3313c190a86bb870151bd62fd12adb8e41ef24f3f000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000003c1e5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000148c89ed219d02f1a5be012c689b4f5b731827bebe000000000000000000000000c001a033fd89cb37c31b2cba46b6466e040c61fc9b2a3675a7f5f493ebd5ad77c497f8a07cdf65680e238392693019b4092f610222e71b7cec06449cb922b93b6a12744e" + ); + // l1Cost = estimatedSize * l1FeeScaled / 1e12 + // = 126387400 * 17 / 1e6 + // = 2148 + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::FJORD); + assert_eq!(gas_cost, U256::from(2148)); + l1_block_info.clear_tx_l1_cost(); + + // Zero rollup data gas cost should result in zero + let input = bytes!(""); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::FJORD); + assert_eq!(gas_cost, U256::ZERO); + l1_block_info.clear_tx_l1_cost(); + + // Deposit transactions with the EIP-2718 type of 0x7E should result in zero + let input = bytes!("7EFACADE"); + let gas_cost = l1_block_info.calculate_tx_l1_cost(&input, OpSpecId::FJORD); + assert_eq!(gas_cost, U256::ZERO); + } + + #[test] + fn calculate_tx_l1_cost_fjord() { + // rig + + // L1 block info for OP mainnet fjord block 124665056 + // + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1055991687), + l1_base_fee_scalar: U256::from(5227), + l1_blob_base_fee_scalar: Some(U256::from(1014213)), + l1_blob_base_fee: Some(U256::from(1)), + ..Default::default() // L1 fee overhead (l1 gas used) deprecated since Fjord + }; + + // Second tx in OP mainnet Fjord block 124665056 + // + const TX: &[u8] = &hex!( + "02f904940a8303fba78401d6d2798401db2b6d830493e0943e6f4f7866654c18f536170780344aa8772950b680b904246a761202000000000000000000000000087000a300de7200382b55d40045000000e5d60e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000022482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b300000000000000000000000021c4928109acb0659a88ae5329b5374a3024694c0000000000000000000000000000000000000000000000049b9ca9a6943400000000000000000000000000000000000000000000000000000000000000000000000000000000000021c4928109acb0659a88ae5329b5374a3024694c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000024b6b55f250000000000000000000000000000000000000000000000049b9ca9a694340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415ec214a3950bea839a7e6fbb0ba1540ac2076acd50820e2d5ef83d0902cdffb24a47aff7de5190290769c4f0a9c6fabf63012986a0d590b1b571547a8c7050ea1b00000000000000000000000000000000000000000000000000000000000000c080a06db770e6e25a617fe9652f0958bd9bd6e49281a53036906386ed39ec48eadf63a07f47cf51a4a40b4494cf26efc686709a9b03939e20ee27e59682f5faa536667e" + ); + + // L1 gas used for tx and L1 fee for tx, from OP mainnet block scanner + // https://optimistic.etherscan.io/tx/0x1059e8004daff32caa1f1b1ef97fe3a07a8cf40508f5b835b66d9420d87c4a4a + let expected_data_gas = U256::from(4471); + let expected_l1_fee = U256::from_be_bytes(hex!( + "00000000000000000000000000000000000000000000000000000005bf1ab43d" + )); + + // test + + let data_gas = l1_block_info.data_gas(TX, OpSpecId::FJORD); + + assert_eq!(data_gas, expected_data_gas); + + let l1_fee = l1_block_info.calculate_tx_l1_cost_fjord(TX); + + assert_eq!(l1_fee, expected_l1_fee) + } + + #[test] + fn test_operator_fee_charge_formulas() { + let l1_block_info = L1BlockInfo { + operator_fee_scalar: Some(U256::from(1_000u64)), + operator_fee_constant: Some(U256::from(10u64)), + ..Default::default() + }; + + let input = [0x01u8]; + + let isthmus_fee = + l1_block_info.operator_fee_charge(&input, U256::from(1_000u64), OpSpecId::ISTHMUS); + assert_eq!(isthmus_fee, U256::from(11u64)); + + let jovian_fee = + l1_block_info.operator_fee_charge(&input, U256::from(1_000u64), OpSpecId::JOVIAN); + assert_eq!(jovian_fee, U256::from(100_000_010u64)); + } + + #[test] + fn test_operator_fee_refund() { + let gas = Gas::new(50000); + + let l1_block_info = L1BlockInfo { + l1_base_fee: U256::from(1055991687), + l1_base_fee_scalar: U256::from(5227), + operator_fee_scalar: Some(U256::from(2000)), + operator_fee_constant: Some(U256::from(5)), + ..Default::default() + }; + + let refunded = l1_block_info.operator_fee_refund(&gas, OpSpecId::ISTHMUS); + + assert_eq!(refunded, U256::from(100)) + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000000..900b524b8d7 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,29 @@ +//! Optimism-specific constants, types, and helpers. +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc as std; + +pub mod api; +pub mod constants; +pub mod evm; +pub mod fast_lz; +pub mod handler; +pub mod l1block; +pub mod precompiles; +pub mod result; +pub mod spec; +pub mod transaction; + +pub use revm; + +pub use api::{ + builder::OpBuilder, + default_ctx::{DefaultOp, OpContext}, +}; +pub use evm::OpEvm; +pub use l1block::L1BlockInfo; +pub use result::OpHaltReason; +pub use spec::*; +pub use transaction::{OpTransaction, error::OpTransactionError, estimate_tx_compressed_size}; diff --git a/src/precompiles.rs b/src/precompiles.rs new file mode 100644 index 00000000000..84702b33bdc --- /dev/null +++ b/src/precompiles.rs @@ -0,0 +1,546 @@ +//! Contains Optimism specific precompiles. +use crate::OpSpecId; +use revm::{ + context::Cfg, + context_interface::ContextTr, + handler::{EthPrecompiles, PrecompileProvider}, + interpreter::{CallInputs, InterpreterResult}, + precompile::{ + self, Precompile, PrecompileError, PrecompileId, PrecompileResult, Precompiles, bn254, + secp256r1, + }, + primitives::{Address, OnceLock, hardfork::SpecId}, +}; +use std::{boxed::Box, string::String}; + +/// Optimism precompile provider +#[derive(Debug, Clone)] +pub struct OpPrecompiles { + /// Inner precompile provider is same as Ethereums. + inner: EthPrecompiles, + /// Spec id of the precompile provider. + spec: OpSpecId, +} + +impl OpPrecompiles { + /// Create a new precompile provider with the given `OpSpec`. + #[inline] + pub fn new_with_spec(spec: OpSpecId) -> Self { + let precompiles = match spec { + spec @ (OpSpecId::BEDROCK | + OpSpecId::REGOLITH | + OpSpecId::CANYON | + OpSpecId::ECOTONE) => Precompiles::new(spec.into_eth_spec().into()), + OpSpecId::FJORD => fjord(), + OpSpecId::GRANITE | OpSpecId::HOLOCENE => granite(), + OpSpecId::ISTHMUS => isthmus(), + OpSpecId::INTEROP | OpSpecId::OSAKA | OpSpecId::JOVIAN => jovian(), + }; + + Self { inner: EthPrecompiles { precompiles, spec: SpecId::default() }, spec } + } + + /// Precompiles getter. + #[inline] + pub const fn precompiles(&self) -> &'static Precompiles { + self.inner.precompiles + } +} + +/// Returns precompiles for Fjord spec. +pub fn fjord() -> &'static Precompiles { + static INSTANCE: OnceLock = OnceLock::new(); + INSTANCE.get_or_init(|| { + let mut precompiles = Precompiles::cancun().clone(); + // RIP-7212: secp256r1 P256verify + precompiles.extend([secp256r1::P256VERIFY]); + precompiles + }) +} + +/// Returns precompiles for Granite spec. +pub fn granite() -> &'static Precompiles { + static INSTANCE: OnceLock = OnceLock::new(); + INSTANCE.get_or_init(|| { + let mut precompiles = fjord().clone(); + // Restrict bn254Pairing input size + precompiles.extend([bn254_pair::GRANITE]); + precompiles + }) +} + +/// Returns precompiles for isthmus spec. +pub fn isthmus() -> &'static Precompiles { + static INSTANCE: OnceLock = OnceLock::new(); + INSTANCE.get_or_init(|| { + let mut precompiles = granite().clone(); + // Prague bls12 precompiles + precompiles.extend(precompile::bls12_381::precompiles()); + // Isthmus bls12 precompile modifications + precompiles.extend([ + bls12_381::ISTHMUS_G1_MSM, + bls12_381::ISTHMUS_G2_MSM, + bls12_381::ISTHMUS_PAIRING, + ]); + precompiles + }) +} + +/// Returns precompiles for jovian spec. +pub fn jovian() -> &'static Precompiles { + static INSTANCE: OnceLock = OnceLock::new(); + INSTANCE.get_or_init(|| { + let mut precompiles = isthmus().clone(); + + let mut to_remove = Precompiles::default(); + to_remove.extend([ + bn254::pair::ISTANBUL, + bls12_381::ISTHMUS_G1_MSM, + bls12_381::ISTHMUS_G2_MSM, + bls12_381::ISTHMUS_PAIRING, + ]); + + // Replace the 4 variable-input precompiles with Jovian versions (reduced limits) + precompiles.difference(&to_remove); + + precompiles.extend([ + bn254_pair::JOVIAN, + bls12_381::JOVIAN_G1_MSM, + bls12_381::JOVIAN_G2_MSM, + bls12_381::JOVIAN_PAIRING, + ]); + + precompiles + }) +} + +impl PrecompileProvider for OpPrecompiles +where + CTX: ContextTr>, +{ + type Output = InterpreterResult; + + #[inline] + fn set_spec(&mut self, spec: ::Spec) -> bool { + if spec == self.spec { + return false; + } + *self = Self::new_with_spec(spec); + true + } + + #[inline] + fn run( + &mut self, + context: &mut CTX, + inputs: &CallInputs, + ) -> Result, String> { + self.inner.run(context, inputs) + } + + #[inline] + fn warm_addresses(&self) -> Box> { + self.inner.warm_addresses() + } + + #[inline] + fn contains(&self, address: &Address) -> bool { + self.inner.contains(address) + } +} + +impl Default for OpPrecompiles { + fn default() -> Self { + Self::new_with_spec(OpSpecId::JOVIAN) + } +} + +/// Bn254 pair precompile. +pub mod bn254_pair { + use super::*; + + /// Max input size for the bn254 pair precompile. + pub const GRANITE_MAX_INPUT_SIZE: usize = 112687; + /// Bn254 pair precompile. + pub const GRANITE: Precompile = + Precompile::new(PrecompileId::Bn254Pairing, bn254::pair::ADDRESS, run_pair_granite); + + /// Run the bn254 pair precompile with Optimism input limit. + pub fn run_pair_granite(input: &[u8], gas_limit: u64) -> PrecompileResult { + if input.len() > GRANITE_MAX_INPUT_SIZE { + return Err(PrecompileError::Bn254PairLength); + } + bn254::run_pair( + input, + bn254::pair::ISTANBUL_PAIR_PER_POINT, + bn254::pair::ISTANBUL_PAIR_BASE, + gas_limit, + ) + } + + /// Max input size for the bn254 pair precompile. + pub const JOVIAN_MAX_INPUT_SIZE: usize = 81_984; + /// Bn254 pair precompile. + pub const JOVIAN: Precompile = + Precompile::new(PrecompileId::Bn254Pairing, bn254::pair::ADDRESS, run_pair_jovian); + + /// Run the bn254 pair precompile with Optimism input limit. + pub fn run_pair_jovian(input: &[u8], gas_limit: u64) -> PrecompileResult { + if input.len() > JOVIAN_MAX_INPUT_SIZE { + return Err(PrecompileError::Bn254PairLength); + } + bn254::run_pair( + input, + bn254::pair::ISTANBUL_PAIR_PER_POINT, + bn254::pair::ISTANBUL_PAIR_BASE, + gas_limit, + ) + } +} + +/// `Bls12_381` precompile. +pub mod bls12_381 { + use super::*; + use revm::precompile::bls12_381_const::{G1_MSM_ADDRESS, G2_MSM_ADDRESS, PAIRING_ADDRESS}; + + /// Max input size for the g1 msm precompile. + pub const ISTHMUS_G1_MSM_MAX_INPUT_SIZE: usize = 513760; + + /// The maximum input size for the BLS12-381 g1 msm operation after the Jovian Hardfork. + pub const JOVIAN_G1_MSM_MAX_INPUT_SIZE: usize = 288_960; + + /// Max input size for the g2 msm precompile. + pub const ISTHMUS_G2_MSM_MAX_INPUT_SIZE: usize = 488448; + + /// Max input size for the g2 msm precompile after the Jovian Hardfork. + pub const JOVIAN_G2_MSM_MAX_INPUT_SIZE: usize = 278_784; + + /// Max input size for the pairing precompile. + pub const ISTHMUS_PAIRING_MAX_INPUT_SIZE: usize = 235008; + + /// Max input size for the pairing precompile after the Jovian Hardfork. + pub const JOVIAN_PAIRING_MAX_INPUT_SIZE: usize = 156_672; + + /// G1 msm precompile. + pub const ISTHMUS_G1_MSM: Precompile = + Precompile::new(PrecompileId::Bls12G1Msm, G1_MSM_ADDRESS, run_g1_msm_isthmus); + /// G2 msm precompile. + pub const ISTHMUS_G2_MSM: Precompile = + Precompile::new(PrecompileId::Bls12G2Msm, G2_MSM_ADDRESS, run_g2_msm_isthmus); + /// Pairing precompile. + pub const ISTHMUS_PAIRING: Precompile = + Precompile::new(PrecompileId::Bls12Pairing, PAIRING_ADDRESS, run_pair_isthmus); + + /// G1 msm precompile after the Jovian Hardfork. + pub const JOVIAN_G1_MSM: Precompile = + Precompile::new(PrecompileId::Bls12G1Msm, G1_MSM_ADDRESS, run_g1_msm_jovian); + /// G2 msm precompile after the Jovian Hardfork. + pub const JOVIAN_G2_MSM: Precompile = + Precompile::new(PrecompileId::Bls12G2Msm, G2_MSM_ADDRESS, run_g2_msm_jovian); + /// Pairing precompile after the Jovian Hardfork. + pub const JOVIAN_PAIRING: Precompile = + Precompile::new(PrecompileId::Bls12Pairing, PAIRING_ADDRESS, run_pair_jovian); + + /// Run the g1 msm precompile with Optimism input limit. + pub fn run_g1_msm_isthmus(input: &[u8], gas_limit: u64) -> PrecompileResult { + if input.len() > ISTHMUS_G1_MSM_MAX_INPUT_SIZE { + return Err(PrecompileError::Other( + "G1MSM input length too long for OP Stack input size limitation after the Isthmus Hardfork".into(), + )); + } + precompile::bls12_381::g1_msm::g1_msm(input, gas_limit) + } + + /// Run the g1 msm precompile with Optimism input limit. + pub fn run_g1_msm_jovian(input: &[u8], gas_limit: u64) -> PrecompileResult { + if input.len() > JOVIAN_G1_MSM_MAX_INPUT_SIZE { + return Err(PrecompileError::Other( + "G1MSM input length too long for OP Stack input size limitation after the Jovian Hardfork".into(), + )); + } + precompile::bls12_381::g1_msm::g1_msm(input, gas_limit) + } + + /// Run the g2 msm precompile with Optimism input limit. + pub fn run_g2_msm_isthmus(input: &[u8], gas_limit: u64) -> PrecompileResult { + if input.len() > ISTHMUS_G2_MSM_MAX_INPUT_SIZE { + return Err(PrecompileError::Other( + "G2MSM input length too long for OP Stack input size limitation".into(), + )); + } + precompile::bls12_381::g2_msm::g2_msm(input, gas_limit) + } + + /// Run the g2 msm precompile with Optimism input limit after the Jovian Hardfork. + pub fn run_g2_msm_jovian(input: &[u8], gas_limit: u64) -> PrecompileResult { + if input.len() > JOVIAN_G2_MSM_MAX_INPUT_SIZE { + return Err(PrecompileError::Other( + "G2MSM input length too long for OP Stack input size limitation after the Jovian Hardfork".into(), + )); + } + precompile::bls12_381::g2_msm::g2_msm(input, gas_limit) + } + + /// Run the pairing precompile with Optimism input limit. + pub fn run_pair_isthmus(input: &[u8], gas_limit: u64) -> PrecompileResult { + if input.len() > ISTHMUS_PAIRING_MAX_INPUT_SIZE { + return Err(PrecompileError::Other( + "Pairing input length too long for OP Stack input size limitation".into(), + )); + } + precompile::bls12_381::pairing::pairing(input, gas_limit) + } + + /// Run the pairing precompile with Optimism input limit after the Jovian Hardfork. + pub fn run_pair_jovian(input: &[u8], gas_limit: u64) -> PrecompileResult { + if input.len() > JOVIAN_PAIRING_MAX_INPUT_SIZE { + return Err(PrecompileError::Other( + "Pairing input length too long for OP Stack input size limitation after the Jovian Hardfork".into(), + )); + } + precompile::bls12_381::pairing::pairing(input, gas_limit) + } +} + +#[cfg(test)] +mod tests { + use crate::precompiles::bls12_381::{ + ISTHMUS_G1_MSM_MAX_INPUT_SIZE, ISTHMUS_G2_MSM_MAX_INPUT_SIZE, + ISTHMUS_PAIRING_MAX_INPUT_SIZE, JOVIAN_G1_MSM_MAX_INPUT_SIZE, JOVIAN_G2_MSM_MAX_INPUT_SIZE, + JOVIAN_PAIRING_MAX_INPUT_SIZE, run_g1_msm_isthmus, run_g1_msm_jovian, run_g2_msm_isthmus, + run_g2_msm_jovian, + }; + + use super::*; + use revm::{ + precompile::{PrecompileError, bls12_381_const}, + primitives::{Bytes, hex}, + }; + use std::vec; + + #[test] + fn test_bn254_pair() { + let input = hex::decode( + "\ + 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\ + 3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41\ + 209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7\ + 04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678\ + 2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d\ + 120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550\ + 111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c\ + 2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411\ + 198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2\ + 1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed\ + 090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b\ + 12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + ) + .unwrap(); + let expected = + hex::decode("0000000000000000000000000000000000000000000000000000000000000001") + .unwrap(); + let outcome = bn254_pair::run_pair_granite(&input, 260_000).unwrap(); + assert_eq!(outcome.bytes, expected); + + // Invalid input length + let input = hex::decode( + "\ + 1111111111111111111111111111111111111111111111111111111111111111\ + 1111111111111111111111111111111111111111111111111111111111111111\ + 111111111111111111111111111111\ + ", + ) + .unwrap(); + + let res = bn254_pair::run_pair_granite(&input, 260_000); + assert!(matches!(res, Err(PrecompileError::Bn254PairLength))); + + // Valid input length shorter than 112687 + let input = vec![1u8; 586 * bn254::PAIR_ELEMENT_LEN]; + let res = bn254_pair::run_pair_granite(&input, 260_000); + assert!(matches!(res, Err(PrecompileError::OutOfGas))); + + // Input length longer than 112687 + let input = vec![1u8; 587 * bn254::PAIR_ELEMENT_LEN]; + let res = bn254_pair::run_pair_granite(&input, 260_000); + assert!(matches!(res, Err(PrecompileError::Bn254PairLength))); + } + + #[test] + fn test_accelerated_bn254_pairing_jovian() { + const TEST_INPUT: [u8; 384] = hex!( + "2cf44499d5d27bb186308b7af7af02ac5bc9eeb6a3d147c186b21fb1b76e18da2c0f001f52110ccfe69108924926e45f0b0c868df0e7bde1fe16d3242dc715f61fb19bb476f6b9e44e2a32234da8212f61cd63919354bc06aef31e3cfaff3ebc22606845ff186793914e03e21df544c34ffe2f2f3504de8a79d9159eca2d98d92bd368e28381e8eccb5fa81fc26cf3f048eea9abfdd85d7ed3ab3698d63e4f902fe02e47887507adf0ff1743cbac6ba291e66f59be6bd763950bb16041a0a85e000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd451971ff0471b09fa93caaf13cbf443c1aede09cc4328f5a62aad45f40ec133eb4091058a3141822985733cbdddfed0fd8d6c104e9e9eff40bf5abfef9ab163bc72a23af9a5ce2ba2796c1f4e453a370eb0af8c212d9dc9acd8fc02c2e907baea223a8eb0b0996252cb548a4487da97b02422ebc0e834613f954de6c7e0afdc1fc" + ); + const EXPECTED_OUTPUT: [u8; 32] = + hex!("0000000000000000000000000000000000000000000000000000000000000001"); + + let res = bn254_pair::run_pair_jovian(TEST_INPUT.as_ref(), u64::MAX); + assert!(matches!(res, Ok(outcome) if **outcome.bytes == EXPECTED_OUTPUT)); + } + + #[test] + fn test_accelerated_bn254_pairing_bad_input_len_jovian() { + let input = [0u8; bn254_pair::JOVIAN_MAX_INPUT_SIZE + 1]; + let res = bn254_pair::run_pair_jovian(&input, u64::MAX); + assert!(matches!(res, Err(PrecompileError::Bn254PairLength))); + } + + #[test] + fn test_get_jovian_precompile_with_bad_input_len() { + let precompiles = OpPrecompiles::new_with_spec(OpSpecId::JOVIAN); + let bn254_pair_precompile = precompiles.precompiles().get(&bn254::pair::ADDRESS).unwrap(); + + let mut bad_input_len = bn254_pair::JOVIAN_MAX_INPUT_SIZE + 1; + assert!(bad_input_len < bn254_pair::GRANITE_MAX_INPUT_SIZE); + let input = vec![0u8; bad_input_len]; + + let res = bn254_pair_precompile.execute(&input, u64::MAX); + assert!(matches!(res, Err(PrecompileError::Bn254PairLength))); + + let bls12_381_g1_msm_precompile = + precompiles.precompiles().get(&bls12_381_const::G1_MSM_ADDRESS).unwrap(); + bad_input_len = bls12_381::JOVIAN_G1_MSM_MAX_INPUT_SIZE + 1; + assert!(bad_input_len < bls12_381::ISTHMUS_G1_MSM_MAX_INPUT_SIZE); + let input = vec![0u8; bad_input_len]; + let res = bls12_381_g1_msm_precompile.execute(&input, u64::MAX); + assert!( + matches!(res, Err(PrecompileError::Other(msg)) if msg.contains("input length too long")) + ); + + let bls12_381_g2_msm_precompile = + precompiles.precompiles().get(&bls12_381_const::G2_MSM_ADDRESS).unwrap(); + bad_input_len = bls12_381::JOVIAN_G2_MSM_MAX_INPUT_SIZE + 1; + assert!(bad_input_len < bls12_381::ISTHMUS_G2_MSM_MAX_INPUT_SIZE); + let input = vec![0u8; bad_input_len]; + let res = bls12_381_g2_msm_precompile.execute(&input, u64::MAX); + assert!( + matches!(res, Err(PrecompileError::Other(msg)) if msg.contains("input length too long")) + ); + + let bls12_381_pairing_precompile = + precompiles.precompiles().get(&bls12_381_const::PAIRING_ADDRESS).unwrap(); + bad_input_len = bls12_381::JOVIAN_PAIRING_MAX_INPUT_SIZE + 1; + assert!(bad_input_len < bls12_381::ISTHMUS_PAIRING_MAX_INPUT_SIZE); + let input = vec![0u8; bad_input_len]; + let res = bls12_381_pairing_precompile.execute(&input, u64::MAX); + assert!( + matches!(res, Err(PrecompileError::Other(msg)) if msg.contains("input length too long")) + ); + } + + #[test] + fn test_cancun_precompiles_in_fjord() { + // additional to cancun, fjord has p256verify + assert_eq!(fjord().difference(Precompiles::cancun()).len(), 1) + } + + #[test] + fn test_cancun_precompiles_in_granite() { + // granite has p256verify (fjord) + // granite has modification of cancun's bn254 pair (doesn't count as new precompile) + assert_eq!(granite().difference(Precompiles::cancun()).len(), 1) + } + + #[test] + fn test_prague_precompiles_in_isthmus() { + let new_prague_precompiles = Precompiles::prague().difference(Precompiles::cancun()); + + // isthmus contains all precompiles that were new in prague, without modifications + assert!(new_prague_precompiles.difference(isthmus()).is_empty()) + } + + #[test] + fn test_prague_precompiles_in_jovian() { + let new_prague_precompiles = Precompiles::prague().difference(Precompiles::cancun()); + + // jovian contains all precompiles that were new in prague, without modifications + assert!(new_prague_precompiles.difference(jovian()).is_empty()) + } + + /// All the addresses of the precompiles in isthmus should be in jovian + #[test] + fn test_isthmus_precompiles_in_jovian() { + let new_isthmus_precompiles = isthmus().difference(Precompiles::cancun()); + + // jovian contains all precompiles that were new in isthmus, without modifications + assert!(new_isthmus_precompiles.difference(jovian()).is_empty()) + } + + #[test] + fn test_default_precompiles_is_latest() { + let latest = OpPrecompiles::new_with_spec(OpSpecId::default()).inner.precompiles; + let default = OpPrecompiles::default().inner.precompiles; + assert_eq!(latest.len(), default.len()); + + let intersection = default.intersection(latest); + assert_eq!(intersection.len(), latest.len()) + } + + #[test] + fn test_g1_isthmus_max_size() { + let oversized_input = vec![0u8; ISTHMUS_G1_MSM_MAX_INPUT_SIZE + 1]; + let input = Bytes::from(oversized_input); + + let res = run_g1_msm_isthmus(&input, 260_000); + + assert!( + matches!(res, Err(PrecompileError::Other(msg)) if msg.contains("input length too long")) + ); + } + + #[test] + fn test_g1_jovian_max_size() { + let oversized_input = vec![0u8; JOVIAN_G1_MSM_MAX_INPUT_SIZE + 1]; + let input = Bytes::from(oversized_input); + + let res = run_g1_msm_jovian(&input, u64::MAX); + + assert!( + matches!(res, Err(PrecompileError::Other(msg)) if msg.contains("input length too long")) + ); + } + #[test] + fn test_g2_isthmus_max_size() { + let oversized_input = vec![0u8; ISTHMUS_G2_MSM_MAX_INPUT_SIZE + 1]; + let input = Bytes::from(oversized_input); + + let res = run_g2_msm_isthmus(&input, 260_000); + + assert!( + matches!(res, Err(PrecompileError::Other(msg)) if msg.contains("input length too long")) + ); + } + #[test] + fn test_g2_jovian_max_size() { + let oversized_input = vec![0u8; JOVIAN_G2_MSM_MAX_INPUT_SIZE + 1]; + let input = Bytes::from(oversized_input); + + let res = run_g2_msm_jovian(&input, u64::MAX); + + assert!( + matches!(res, Err(PrecompileError::Other(msg)) if msg.contains("input length too long")) + ); + } + #[test] + fn test_pair_isthmus_max_size() { + let oversized_input = vec![0u8; ISTHMUS_PAIRING_MAX_INPUT_SIZE + 1]; + let input = Bytes::from(oversized_input); + + let res = bls12_381::run_pair_isthmus(&input, 260_000); + + assert!( + matches!(res, Err(PrecompileError::Other(msg)) if msg.contains("input length too long")) + ); + } + #[test] + fn test_pair_jovian_max_size() { + let oversized_input = vec![0u8; JOVIAN_PAIRING_MAX_INPUT_SIZE + 1]; + let input = Bytes::from(oversized_input); + + let res = bls12_381::run_pair_jovian(&input, u64::MAX); + + assert!( + matches!(res, Err(PrecompileError::Other(msg)) if msg.contains("input length too long")) + ); + } +} diff --git a/src/result.rs b/src/result.rs new file mode 100644 index 00000000000..bd5ed42e363 --- /dev/null +++ b/src/result.rs @@ -0,0 +1,43 @@ +//! Contains the `[OpHaltReason]` type. +use revm::context_interface::result::HaltReason; + +/// Optimism halt reason. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum OpHaltReason { + /// Base halt reason. + Base(HaltReason), + /// Failed deposit halt reason. + FailedDeposit, +} + +impl From for OpHaltReason { + fn from(value: HaltReason) -> Self { + Self::Base(value) + } +} + +impl TryFrom for HaltReason { + type Error = OpHaltReason; + + fn try_from(value: OpHaltReason) -> Result { + match value { + OpHaltReason::Base(reason) => Ok(reason), + OpHaltReason::FailedDeposit => Err(value), + } + } +} + +#[cfg(all(test, feature = "serde"))] +mod tests { + use super::*; + use revm::context_interface::result::OutOfGasError; + + #[test] + fn test_serialize_json_op_halt_reason() { + let response = r#"{"Base":{"OutOfGas":"Basic"}}"#; + + let op_halt_reason: OpHaltReason = serde_json::from_str(response).unwrap(); + assert_eq!(op_halt_reason, HaltReason::OutOfGas(OutOfGasError::Basic).into()); + } +} diff --git a/src/spec.rs b/src/spec.rs new file mode 100644 index 00000000000..01dbf0cf05e --- /dev/null +++ b/src/spec.rs @@ -0,0 +1,248 @@ +//! Contains the `[OpSpecId]` type and its implementation. +use core::str::FromStr; +use revm::primitives::hardfork::{SpecId, UnknownHardfork, name as eth_name}; + +/// Optimism spec id. +#[repr(u8)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[allow(non_camel_case_types)] +pub enum OpSpecId { + /// Bedrock spec id. + BEDROCK = 100, + /// Regolith spec id. + REGOLITH, + /// Canyon spec id. + CANYON, + /// Ecotone spec id. + ECOTONE, + /// Fjord spec id. + FJORD, + /// Granite spec id. + GRANITE, + /// Holocene spec id. + HOLOCENE, + /// Isthmus spec id. + ISTHMUS, + /// Jovian spec id. + #[default] + JOVIAN, + /// Interop spec id. + INTEROP, + /// Osaka spec id. + OSAKA, +} + +impl OpSpecId { + /// Converts the [`OpSpecId`] into a [`SpecId`]. + pub const fn into_eth_spec(self) -> SpecId { + match self { + Self::BEDROCK | Self::REGOLITH => SpecId::MERGE, + Self::CANYON => SpecId::SHANGHAI, + Self::ECOTONE | Self::FJORD | Self::GRANITE | Self::HOLOCENE => SpecId::CANCUN, + Self::ISTHMUS | Self::JOVIAN | Self::INTEROP => SpecId::PRAGUE, + Self::OSAKA => SpecId::OSAKA, + } + } + + /// Checks if the [`OpSpecId`] is enabled in the other [`OpSpecId`]. + pub const fn is_enabled_in(self, other: Self) -> bool { + other as u8 <= self as u8 + } +} + +impl From for SpecId { + fn from(spec: OpSpecId) -> Self { + spec.into_eth_spec() + } +} + +impl FromStr for OpSpecId { + type Err = UnknownHardfork; + + fn from_str(s: &str) -> Result { + match s { + name::BEDROCK => Ok(Self::BEDROCK), + name::REGOLITH => Ok(Self::REGOLITH), + name::CANYON => Ok(Self::CANYON), + name::ECOTONE => Ok(Self::ECOTONE), + name::FJORD => Ok(Self::FJORD), + name::GRANITE => Ok(Self::GRANITE), + name::HOLOCENE => Ok(Self::HOLOCENE), + name::ISTHMUS => Ok(Self::ISTHMUS), + name::JOVIAN => Ok(Self::JOVIAN), + name::INTEROP => Ok(Self::INTEROP), + eth_name::OSAKA => Ok(Self::OSAKA), + _ => Err(UnknownHardfork), + } + } +} + +impl From for &'static str { + fn from(spec_id: OpSpecId) -> Self { + match spec_id { + OpSpecId::BEDROCK => name::BEDROCK, + OpSpecId::REGOLITH => name::REGOLITH, + OpSpecId::CANYON => name::CANYON, + OpSpecId::ECOTONE => name::ECOTONE, + OpSpecId::FJORD => name::FJORD, + OpSpecId::GRANITE => name::GRANITE, + OpSpecId::HOLOCENE => name::HOLOCENE, + OpSpecId::ISTHMUS => name::ISTHMUS, + OpSpecId::JOVIAN => name::JOVIAN, + OpSpecId::INTEROP => name::INTEROP, + OpSpecId::OSAKA => eth_name::OSAKA, + } + } +} + +/// String identifiers for Optimism hardforks +pub mod name { + /// Bedrock spec name. + pub const BEDROCK: &str = "Bedrock"; + /// Regolith spec name. + pub const REGOLITH: &str = "Regolith"; + /// Canyon spec name. + pub const CANYON: &str = "Canyon"; + /// Ecotone spec name. + pub const ECOTONE: &str = "Ecotone"; + /// Fjord spec name. + pub const FJORD: &str = "Fjord"; + /// Granite spec name. + pub const GRANITE: &str = "Granite"; + /// Holocene spec name. + pub const HOLOCENE: &str = "Holocene"; + /// Isthmus spec name. + pub const ISTHMUS: &str = "Isthmus"; + /// Jovian spec name. + pub const JOVIAN: &str = "Jovian"; + /// Interop spec name. + pub const INTEROP: &str = "Interop"; +} + +#[cfg(test)] +mod tests { + use super::*; + use std::vec; + + #[test] + fn test_op_spec_id_eth_spec_compatibility() { + // Define test cases: (OpSpecId, enabled in ETH specs, enabled in OP specs) + let test_cases = [ + ( + OpSpecId::BEDROCK, + vec![ + (SpecId::MERGE, true), + (SpecId::SHANGHAI, false), + (SpecId::CANCUN, false), + (SpecId::default(), false), + ], + vec![(OpSpecId::BEDROCK, true), (OpSpecId::REGOLITH, false)], + ), + ( + OpSpecId::REGOLITH, + vec![ + (SpecId::MERGE, true), + (SpecId::SHANGHAI, false), + (SpecId::CANCUN, false), + (SpecId::default(), false), + ], + vec![(OpSpecId::BEDROCK, true), (OpSpecId::REGOLITH, true)], + ), + ( + OpSpecId::CANYON, + vec![ + (SpecId::MERGE, true), + (SpecId::SHANGHAI, true), + (SpecId::CANCUN, false), + (SpecId::default(), false), + ], + vec![ + (OpSpecId::BEDROCK, true), + (OpSpecId::REGOLITH, true), + (OpSpecId::CANYON, true), + ], + ), + ( + OpSpecId::ECOTONE, + vec![ + (SpecId::MERGE, true), + (SpecId::SHANGHAI, true), + (SpecId::CANCUN, true), + (SpecId::default(), false), + ], + vec![ + (OpSpecId::BEDROCK, true), + (OpSpecId::REGOLITH, true), + (OpSpecId::CANYON, true), + (OpSpecId::ECOTONE, true), + ], + ), + ( + OpSpecId::FJORD, + vec![ + (SpecId::MERGE, true), + (SpecId::SHANGHAI, true), + (SpecId::CANCUN, true), + (SpecId::default(), false), + ], + vec![ + (OpSpecId::BEDROCK, true), + (OpSpecId::REGOLITH, true), + (OpSpecId::CANYON, true), + (OpSpecId::ECOTONE, true), + (OpSpecId::FJORD, true), + ], + ), + ( + OpSpecId::JOVIAN, + vec![ + (SpecId::PRAGUE, true), + (SpecId::SHANGHAI, true), + (SpecId::CANCUN, true), + (SpecId::MERGE, true), + ], + vec![ + (OpSpecId::BEDROCK, true), + (OpSpecId::REGOLITH, true), + (OpSpecId::CANYON, true), + (OpSpecId::ECOTONE, true), + (OpSpecId::FJORD, true), + (OpSpecId::HOLOCENE, true), + (OpSpecId::ISTHMUS, true), + ], + ), + ]; + + for (op_spec, eth_tests, op_tests) in test_cases { + // Test ETH spec compatibility + for (eth_spec, expected) in eth_tests { + assert_eq!( + op_spec.into_eth_spec().is_enabled_in(eth_spec), + expected, + "{:?} should {} be enabled in ETH {:?}", + op_spec, + if expected { "" } else { "not " }, + eth_spec + ); + } + + // Test OP spec compatibility + for (other_op_spec, expected) in op_tests { + assert_eq!( + op_spec.is_enabled_in(other_op_spec), + expected, + "{:?} should {} be enabled in OP {:?}", + op_spec, + if expected { "" } else { "not " }, + other_op_spec + ); + } + } + } + + #[test] + fn default_op_spec_id() { + assert_eq!(OpSpecId::default(), OpSpecId::JOVIAN); + } +} diff --git a/src/transaction.rs b/src/transaction.rs new file mode 100644 index 00000000000..702de9dfecd --- /dev/null +++ b/src/transaction.rs @@ -0,0 +1,29 @@ +//! Contains the `[OpTransaction]` type and its implementation. +pub mod abstraction; +pub mod deposit; +pub mod error; + +pub use abstraction::{OpTransaction, OpTxTr}; +pub use error::OpTransactionError; + +use crate::fast_lz::flz_compress_len; + +/// +const L1_COST_FASTLZ_COEF: u64 = 836_500; + +/// +/// Inverted to be used with `saturating_sub`. +const L1_COST_INTERCEPT: u64 = 42_585_600; + +/// +const MIN_TX_SIZE_SCALED: u64 = 100 * 1_000_000; + +/// Estimates the compressed size of a transaction. +pub fn estimate_tx_compressed_size(input: &[u8]) -> u64 { + let fastlz_size = flz_compress_len(input) as u64; + + fastlz_size + .saturating_mul(L1_COST_FASTLZ_COEF) + .saturating_sub(L1_COST_INTERCEPT) + .max(MIN_TX_SIZE_SCALED) +} diff --git a/src/transaction/abstraction.rs b/src/transaction/abstraction.rs new file mode 100644 index 00000000000..e73b31d1b74 --- /dev/null +++ b/src/transaction/abstraction.rs @@ -0,0 +1,381 @@ +//! Optimism transaction abstraction containing the `[OpTxTr]` trait and corresponding +//! `[OpTransaction]` type. +use super::deposit::{DEPOSIT_TRANSACTION_TYPE, DepositTransactionParts}; +use auto_impl::auto_impl; +use revm::{ + context::{ + TxEnv, + tx::{TxEnvBuildError, TxEnvBuilder}, + }, + context_interface::transaction::Transaction, + handler::SystemCallTx, + primitives::{Address, B256, Bytes, TxKind, U256}, +}; +use std::vec; + +/// Optimism Transaction trait. +#[auto_impl(&, &mut, Box, Arc)] +pub trait OpTxTr: Transaction { + /// Enveloped transaction bytes. + fn enveloped_tx(&self) -> Option<&Bytes>; + + /// Source hash of the deposit transaction. + fn source_hash(&self) -> Option; + + /// Mint of the deposit transaction + fn mint(&self) -> Option; + + /// Whether the transaction is a system transaction + fn is_system_transaction(&self) -> bool; + + /// Returns `true` if transaction is of type [`DEPOSIT_TRANSACTION_TYPE`]. + fn is_deposit(&self) -> bool { + self.tx_type() == DEPOSIT_TRANSACTION_TYPE + } +} + +/// Optimism transaction. +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct OpTransaction { + /// Base transaction fields. + pub base: T, + /// An enveloped EIP-2718 typed transaction + /// + /// This is used to compute the L1 tx cost using the L1 block info, as + /// opposed to requiring downstream apps to compute the cost + /// externally. + pub enveloped_tx: Option, + /// Deposit transaction parts. + pub deposit: DepositTransactionParts, +} + +impl AsRef for OpTransaction { + fn as_ref(&self) -> &T { + &self.base + } +} + +impl OpTransaction { + /// Create a new Optimism transaction. + pub fn new(base: T) -> Self { + Self { base, enveloped_tx: None, deposit: DepositTransactionParts::default() } + } +} + +impl OpTransaction { + /// Create a new Optimism transaction. + pub fn builder() -> OpTransactionBuilder { + OpTransactionBuilder::new() + } +} + +impl Default for OpTransaction { + fn default() -> Self { + Self { + base: TxEnv::default(), + enveloped_tx: Some(vec![0x00].into()), + deposit: DepositTransactionParts::default(), + } + } +} + +impl SystemCallTx for OpTransaction { + fn new_system_tx_with_caller( + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Self { + let mut tx = + Self::new(TX::new_system_tx_with_caller(caller, system_contract_address, data)); + + tx.enveloped_tx = Some(Bytes::default()); + + tx + } +} + +impl Transaction for OpTransaction { + type AccessListItem<'a> + = T::AccessListItem<'a> + where + T: 'a; + type Authorization<'a> + = T::Authorization<'a> + where + T: 'a; + + fn tx_type(&self) -> u8 { + // If this is a deposit transaction (has source_hash set), return deposit type + if self.deposit.source_hash == B256::ZERO { + self.base.tx_type() + } else { + DEPOSIT_TRANSACTION_TYPE + } + } + + fn caller(&self) -> Address { + self.base.caller() + } + + fn gas_limit(&self) -> u64 { + self.base.gas_limit() + } + + fn value(&self) -> U256 { + self.base.value() + } + + fn input(&self) -> &Bytes { + self.base.input() + } + + fn nonce(&self) -> u64 { + self.base.nonce() + } + + fn kind(&self) -> TxKind { + self.base.kind() + } + + fn chain_id(&self) -> Option { + self.base.chain_id() + } + + fn access_list(&self) -> Option>> { + self.base.access_list() + } + + fn max_priority_fee_per_gas(&self) -> Option { + self.base.max_priority_fee_per_gas() + } + + fn max_fee_per_gas(&self) -> u128 { + self.base.max_fee_per_gas() + } + + fn gas_price(&self) -> u128 { + self.base.gas_price() + } + + fn blob_versioned_hashes(&self) -> &[B256] { + self.base.blob_versioned_hashes() + } + + fn max_fee_per_blob_gas(&self) -> u128 { + self.base.max_fee_per_blob_gas() + } + + fn effective_gas_price(&self, base_fee: u128) -> u128 { + // Deposit transactions use gas_price directly + if self.tx_type() == DEPOSIT_TRANSACTION_TYPE { + return self.gas_price(); + } + self.base.effective_gas_price(base_fee) + } + + fn authorization_list_len(&self) -> usize { + self.base.authorization_list_len() + } + + fn authorization_list(&self) -> impl Iterator> { + self.base.authorization_list() + } +} + +impl OpTxTr for OpTransaction { + fn enveloped_tx(&self) -> Option<&Bytes> { + self.enveloped_tx.as_ref() + } + + fn source_hash(&self) -> Option { + if self.tx_type() != DEPOSIT_TRANSACTION_TYPE { + return None; + } + Some(self.deposit.source_hash) + } + + fn mint(&self) -> Option { + self.deposit.mint + } + + fn is_system_transaction(&self) -> bool { + self.deposit.is_system_transaction + } +} + +/// Builder for constructing [`OpTransaction`] instances +#[derive(Default, Debug)] +pub struct OpTransactionBuilder { + base: TxEnvBuilder, + enveloped_tx: Option, + deposit: DepositTransactionParts, +} + +impl OpTransactionBuilder { + /// Create a new builder with default values + pub fn new() -> Self { + Self { + base: TxEnvBuilder::new(), + enveloped_tx: None, + deposit: DepositTransactionParts::default(), + } + } + + /// Set the base transaction builder based for `TxEnvBuilder`. + pub fn base(mut self, base: TxEnvBuilder) -> Self { + self.base = base; + self + } + + /// Set the enveloped transaction bytes. + pub fn enveloped_tx(mut self, enveloped_tx: Option) -> Self { + self.enveloped_tx = enveloped_tx; + self + } + + /// Set the source hash of the deposit transaction. + pub const fn source_hash(mut self, source_hash: B256) -> Self { + self.deposit.source_hash = source_hash; + self + } + + /// Set the mint of the deposit transaction. + pub const fn mint(mut self, mint: u128) -> Self { + self.deposit.mint = Some(mint); + self + } + + /// Set the deposit transaction to be a system transaction. + pub const fn is_system_transaction(mut self) -> Self { + self.deposit.is_system_transaction = true; + self + } + + /// Set the deposit transaction to not be a system transaction. + pub const fn not_system_transaction(mut self) -> Self { + self.deposit.is_system_transaction = false; + self + } + + /// Set the deposit transaction to be a deposit transaction. + pub fn is_deposit_tx(mut self) -> Self { + self.base = self.base.tx_type(Some(DEPOSIT_TRANSACTION_TYPE)); + self + } + + /// Build the [`OpTransaction`] with default values for missing fields. + /// + /// This is useful for testing and debugging where it is not necessary to + /// have full [`OpTransaction`] instance. + /// + /// If the transaction is a deposit (either `tx_type == DEPOSIT_TRANSACTION_TYPE` or + /// `source_hash != B256::ZERO`), set the transaction type accordingly and ensure the + /// `enveloped_tx` is removed (`None`). For non-deposit transactions, ensure + /// `enveloped_tx` is set. + pub fn build_fill(mut self) -> OpTransaction { + let tx_type = self.base.get_tx_type(); + if tx_type.is_some() { + if tx_type == Some(DEPOSIT_TRANSACTION_TYPE) { + // source hash is required for deposit transactions + if self.deposit.source_hash == B256::ZERO { + self.deposit.source_hash = B256::from([1u8; 32]); + } + // deposit transactions should not carry enveloped bytes + self.enveloped_tx = None; + } else { + // enveloped is required for non-deposit transactions + self.enveloped_tx = Some(vec![0x00].into()); + } + } else if self.deposit.source_hash != B256::ZERO { + // if type is not set and source hash is set, set the transaction type to deposit + self.base = self.base.tx_type(Some(DEPOSIT_TRANSACTION_TYPE)); + // deposit transactions should not carry enveloped bytes + self.enveloped_tx = None; + } else if self.enveloped_tx.is_none() { + // if type is not set and source hash is not set, set the enveloped transaction to + // something. + self.enveloped_tx = Some(vec![0x00].into()); + } + + let base = self.base.build_fill(); + + OpTransaction { base, enveloped_tx: self.enveloped_tx, deposit: self.deposit } + } + + /// Build the [`OpTransaction`] instance, return error if the transaction is not valid. + pub fn build(mut self) -> Result, OpBuildError> { + let tx_type = self.base.get_tx_type(); + if tx_type.is_some() { + if Some(DEPOSIT_TRANSACTION_TYPE) == tx_type { + // if tx type is deposit, check if source hash is set + if self.deposit.source_hash == B256::ZERO { + return Err(OpBuildError::MissingSourceHashForDeposit); + } + } else if self.enveloped_tx.is_none() { + // enveloped is required for non-deposit transactions + return Err(OpBuildError::MissingEnvelopedTxBytes); + } + } else if self.deposit.source_hash != B256::ZERO { + // if type is not set and source hash is set, set the transaction type to deposit + self.base = self.base.tx_type(Some(DEPOSIT_TRANSACTION_TYPE)); + } else if self.enveloped_tx.is_none() { + // tx is not deposit and enveloped is required + return Err(OpBuildError::MissingEnvelopedTxBytes); + } + + let base = self.base.build()?; + + Ok(OpTransaction { base, enveloped_tx: self.enveloped_tx, deposit: self.deposit }) + } +} + +/// Error type for building [`TxEnv`] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum OpBuildError { + /// Base transaction build error + Base(TxEnvBuildError), + /// Missing enveloped transaction bytes + MissingEnvelopedTxBytes, + /// Missing source hash for deposit transaction + MissingSourceHashForDeposit, +} + +impl From for OpBuildError { + fn from(error: TxEnvBuildError) -> Self { + Self::Base(error) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use revm::{ + context_interface::Transaction, + primitives::{Address, B256}, + }; + + #[test] + fn test_deposit_transaction_fields() { + let base_tx = TxEnv::builder().gas_limit(10).gas_price(100).gas_priority_fee(Some(5)); + + let op_tx = OpTransaction::builder() + .base(base_tx) + .enveloped_tx(None) + .not_system_transaction() + .mint(0u128) + .source_hash(B256::from([1u8; 32])) + .build() + .unwrap(); + // Verify transaction type (deposit transactions should have tx_type based on OpSpecId) + // The tx_type is derived from the transaction structure, not set manually + // Verify common fields access + assert_eq!(op_tx.gas_limit(), 10); + assert_eq!(op_tx.kind(), revm::primitives::TxKind::Call(Address::ZERO)); + // Verify gas related calculations - deposit transactions use gas_price for effective gas + // price + assert_eq!(op_tx.effective_gas_price(90), 100); + assert_eq!(op_tx.max_fee_per_gas(), 100); + } +} diff --git a/src/transaction/deposit.rs b/src/transaction/deposit.rs new file mode 100644 index 00000000000..42da6e18803 --- /dev/null +++ b/src/transaction/deposit.rs @@ -0,0 +1,48 @@ +//! Contains Deposit transaction parts. +use revm::primitives::B256; + +/// Deposit transaction type. +pub const DEPOSIT_TRANSACTION_TYPE: u8 = 0x7E; + +/// Deposit transaction parts. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct DepositTransactionParts { + /// Source hash of the deposit transaction. + pub source_hash: B256, + /// Minted value of the deposit transaction. + pub mint: Option, + /// Whether the transaction is a system transaction. + pub is_system_transaction: bool, +} + +impl DepositTransactionParts { + /// Create a new deposit transaction parts. + pub const fn new(source_hash: B256, mint: Option, is_system_transaction: bool) -> Self { + Self { source_hash, mint, is_system_transaction } + } +} + +#[cfg(all(test, feature = "serde"))] +mod tests { + use super::*; + use revm::primitives::b256; + + #[test] + fn serialize_deserialize_json_deposit_tx_parts() { + let parts = DepositTransactionParts::new( + b256!("0xe927a1448525fb5d32cb50ee1408461a945ba6c39bd5cf5621407d500ecc8de9"), + Some(0x34), + false, + ); + let response = r#"{"source_hash":"0xe927a1448525fb5d32cb50ee1408461a945ba6c39bd5cf5621407d500ecc8de9","mint":52,"is_system_transaction":false}"#; + + // serialize + let json = serde_json::to_string(&parts).unwrap(); + assert_eq!(json.as_str(), response); + + // deserialize + let deposit_tx_parts: DepositTransactionParts = serde_json::from_str(response).unwrap(); + assert_eq!(deposit_tx_parts, parts); + } +} diff --git a/src/transaction/error.rs b/src/transaction/error.rs new file mode 100644 index 00000000000..375e8162c4c --- /dev/null +++ b/src/transaction/error.rs @@ -0,0 +1,124 @@ +//! Contains the `[OpTransactionError]` type. +use core::fmt::Display; +use revm::context_interface::{ + result::{EVMError, InvalidTransaction}, + transaction::TransactionError, +}; + +/// Optimism transaction validation error. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum OpTransactionError { + /// Base transaction error. + Base(InvalidTransaction), + /// System transactions are not supported post-regolith hardfork. + /// + /// Before the Regolith hardfork, there was a special field in the `Deposit` transaction + /// type that differentiated between `system` and `user` deposit transactions. This field + /// was deprecated in the Regolith hardfork, and this error is thrown if a `Deposit` transaction + /// is found with this field set to `true` after the hardfork activation. + /// + /// In addition, this error is internal, and bubbles up into an + /// [`OpHaltReason::FailedDeposit`][crate::OpHaltReason::FailedDeposit] error in the `revm` + /// handler for the consumer to easily handle. This is due to a state transition rule on OP + /// Stack chains where, if for any reason a deposit transaction fails, the transaction + /// must still be included in the block, the sender nonce is bumped, the `mint` value persists, + /// and special gas accounting rules are applied. Normally on L1, [`EVMError::Transaction`] + /// errors are cause for non-inclusion, so a special [`OpHaltReason`][crate::OpHaltReason] + /// variant was introduced to handle this case for failed deposit transactions. + DepositSystemTxPostRegolith, + /// Deposit transaction halts bubble up to the global main return handler, wiping state and + /// only increasing the nonce + persisting the mint value. + /// + /// This is a catch-all error for any deposit transaction that results in an + /// [`OpHaltReason`][crate::OpHaltReason] error post-regolith hardfork. This allows for a + /// consumer to easily handle special cases where a deposit transaction fails during + /// validation, but must still be included in the block. + /// + /// In addition, this error is internal, and bubbles up into an + /// [`OpHaltReason::FailedDeposit`][crate::OpHaltReason::FailedDeposit] error in the `revm` + /// handler for the consumer to easily handle. This is due to a state transition rule on OP + /// Stack chains where, if for any reason a deposit transaction fails, the transaction + /// must still be included in the block, the sender nonce is bumped, the `mint` value persists, + /// and special gas accounting rules are applied. Normally on L1, [`EVMError::Transaction`] + /// errors are cause for non-inclusion, so a special [`OpHaltReason`][crate::OpHaltReason] + /// variant was introduced to handle this case for failed deposit transactions. + HaltedDepositPostRegolith, + /// Missing enveloped transaction bytes for non-deposit transaction. + /// + /// Non-deposit transactions on Optimism must have `enveloped_tx` field set + /// to properly calculate L1 costs. + MissingEnvelopedTx, +} + +impl TransactionError for OpTransactionError {} + +impl Display for OpTransactionError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Base(error) => error.fmt(f), + Self::DepositSystemTxPostRegolith => { + write!(f, "deposit system transactions post regolith hardfork are not supported") + } + Self::HaltedDepositPostRegolith => { + write!( + f, + "deposit transaction halted post-regolith; error will be bubbled up to main return handler" + ) + } + Self::MissingEnvelopedTx => { + write!(f, "missing enveloped transaction bytes for non-deposit transaction") + } + } + } +} + +impl core::error::Error for OpTransactionError {} + +impl From for OpTransactionError { + fn from(value: InvalidTransaction) -> Self { + Self::Base(value) + } +} + +impl From for EVMError { + fn from(value: OpTransactionError) -> Self { + Self::Transaction(value) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::string::ToString; + + #[test] + fn test_display_op_errors() { + assert_eq!( + OpTransactionError::Base(InvalidTransaction::NonceTooHigh { tx: 2, state: 1 }) + .to_string(), + "nonce 2 too high, expected 1" + ); + assert_eq!( + OpTransactionError::DepositSystemTxPostRegolith.to_string(), + "deposit system transactions post regolith hardfork are not supported" + ); + assert_eq!( + OpTransactionError::HaltedDepositPostRegolith.to_string(), + "deposit transaction halted post-regolith; error will be bubbled up to main return handler" + ); + assert_eq!( + OpTransactionError::MissingEnvelopedTx.to_string(), + "missing enveloped transaction bytes for non-deposit transaction" + ); + } + + #[cfg(feature = "serde")] + #[test] + fn test_serialize_json_op_transaction_error() { + let response = r#""DepositSystemTxPostRegolith""#; + + let op_transaction_error: OpTransactionError = serde_json::from_str(response).unwrap(); + assert_eq!(op_transaction_error, OpTransactionError::DepositSystemTxPostRegolith); + } +}