diff --git a/.circleci/config.yml b/.circleci/config.yml index 648217dbcdf8c..9fbed7bde44d8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -162,9 +162,9 @@ jobs: description: Whether to notify on failure type: boolean default: false - mips64: - type: boolean - default: false + mips_word_size: + type: integer + default: 32 steps: - checkout - check-changed: @@ -187,28 +187,34 @@ jobs: working_directory: cannon - when: condition: - not: <> + equal: [32, <>] steps: - run: name: Cannon Go 32-bit tests command: | export SKIP_SLOW_TESTS=<> - gotestsum --format=testname --junitfile=../tmp/test-results/cannon.xml --jsonfile=../tmp/testlogs/log.json \ - -- -parallel=$(nproc) -coverpkg=github.com/ethereum-optimism/optimism/cannon/... -coverprofile=coverage.out ./... + gotestsum --format=testname --junitfile=../tmp/test-results/cannon-32.xml --jsonfile=../tmp/testlogs/log-32.json \ + -- -parallel=$(nproc) -coverpkg=github.com/ethereum-optimism/optimism/cannon/... -coverprofile=coverage-32.out ./... + working_directory: cannon + - run: + name: Upload Cannon coverage + command: codecov --verbose --clean --flags cannon-go-tests-32 -f ./coverage-32.out working_directory: cannon - when: - condition: <> + condition: + equal: [64, <>] steps: - run: name: Cannon Go 64-bit tests command: | export SKIP_SLOW_TESTS=<> - gotestsum --format=testname --junitfile=../tmp/test-results/cannon.xml --jsonfile=../tmp/testlogs/log.json \ - -- --tags=cannon64 -parallel=$(nproc) -coverpkg=github.com/ethereum-optimism/optimism/cannon/... -coverprofile=coverage.out ./... + gotestsum --format=testname --junitfile=../tmp/test-results/cannon-64.xml --jsonfile=../tmp/testlogs/log-64.json \ + -- --tags=cannon64 -parallel=$(nproc) -coverpkg=github.com/ethereum-optimism/optimism/cannon/... -coverprofile=coverage-64.out ./... + working_directory: cannon + - run: + name: Upload Cannon coverage + command: codecov --verbose --clean --flags cannon-go-tests-64 -f ./coverage-64.out working_directory: cannon - - run: - name: upload Cannon coverage - command: codecov --verbose --clean --flags cannon-go-tests - store_test_results: path: ./tmp/test-results - store_artifacts: @@ -676,6 +682,8 @@ jobs: - run: name: print forge version command: forge --version + - run-contracts-check: + command: check-kontrol-summaries-unchanged - run-contracts-check: command: semgrep-test-validity-check - run-contracts-check: @@ -684,8 +692,6 @@ jobs: command: semver-lock - run-contracts-check: command: semver-diff-check-no-build - - run-contracts-check: - command: semver-natspec-check-no-build - run-contracts-check: command: validate-deploy-configs - run-contracts-check: @@ -700,6 +706,8 @@ jobs: command: size-check - run-contracts-check: command: unused-imports-check-no-build + - run-contracts-check: + command: lint-forge-tests-check-no-build contracts-bedrock-validate-spacers: docker: @@ -745,8 +753,8 @@ jobs: description: should load in foundry artifacts type: boolean default: false - docker: - - image: <> + machine: true + resource_class: ethereum-optimism/latitude-1 steps: - checkout - check-changed: @@ -754,23 +762,10 @@ jobs: - attach_workspace: at: "." if: ${{ uses_artifacts }} - - restore_cache: - name: Restore Go modules cache - key: gomod-{{ checksum "go.sum" }} - - restore_cache: - name: Restore Go build cache - keys: - - golang-build-cache-fuzz-golang-{{ checksum "go.sum" }} - - golang-build-cache-fuzz-golang- - run: name: Fuzz command: make fuzz working_directory: "<>" - - save_cache: - name: Save Go build cache - key: golang-build-cache-fuzz-golang-{{ checksum "go.sum" }} - paths: - - "/root/.cache/go-build" go-lint: machine: true @@ -810,7 +805,7 @@ jobs: command: | echo "deb [trusted=yes] https://apt.fury.io/kurtosis-tech/ /" | sudo tee /etc/apt/sources.list.d/kurtosis.list sudo apt update - sudo apt install kurtosis-cli=1.3.0 + sudo apt install kurtosis-cli=1.4.0 kurtosis engine start - checkout - when: @@ -864,7 +859,6 @@ jobs: op-service op-supervisor op-deployer - packages/contracts-bedrock/scripts/checks/semver-natspec ) formatted_packages="" for package in "${packages[@]}"; do @@ -905,6 +899,10 @@ jobs: description: Machine resource class type: string default: ethereum-optimism/latitude-1 + skip_slow_tests: + description: Indicates that slow tests should be skipped + type: boolean + default: false machine: true resource_class: <> steps: @@ -933,6 +931,7 @@ jobs: # need to explicitly set it here to prevent Cannon from running when we don't # want it to. export OP_E2E_CANNON_ENABLED="false" + export OP_E2E_SKIP_SLOW_TEST=<> # Note: We don't use circle CI test splits because we need to split by test name, not by package. There is an additional # constraint that gotestsum does not currently (nor likely will) accept files from different packages when building. JUNIT_FILE=../tmp/test-results/<>_<>.xml JSON_LOG_FILE=../tmp/testlogs/test.log make <> @@ -1032,7 +1031,7 @@ jobs: paths: - "/root/.cache/go-build" - notify-failures-on-develop: - mentions: "@proofs-squad" + mentions: "@proofs-team" semgrep-scan: parameters: @@ -1245,10 +1244,28 @@ jobs: description: Goreleaser config file default: .goreleaser.yaml type: string - machine: true - resource_class: ethereum-optimism/latitude-1 + docker: + - image: <> + resource_class: large steps: + - setup_remote_docker + - gcp-cli/install + - gcp-oidc-authenticate: + gcp_cred_config_file_path: /root/gcp_cred_config.json + oidc_token_file_path: /root/oidc_token.json - checkout + - run: + name: Install goreleaser pro + command: | + mkdir -p /tmp/goreleaser + cd /tmp/goreleaser + curl -L -o goreleaser.tgz https://github.com/goreleaser/goreleaser-pro/releases/download/v2.4.3-pro/goreleaser-pro_Linux_x86_64.tar.gz + tar -xzvf goreleaser.tgz + mv goreleaser /usr/local/bin/goreleaser + - run: + name: Configure Docker + command: | + gcloud auth configure-docker us-docker.pkg.dev - run: name: Run goreleaser command: | @@ -1297,18 +1314,15 @@ workflows: - contracts-bedrock-validate-spacers: requires: - contracts-bedrock-build - - semgrep-scan - semgrep-scan: name: semgrep-scan-local - scan_command: semgrep scan --timeout=100 --config=./semgrep --error . + scan_command: semgrep scan --timeout=100 --config .semgrep/rules/ --error . - semgrep-scan: name: semgrep-test - scan_command: semgrep scan --test semgrep/ + scan_command: semgrep scan --test --config .semgrep/rules/ .semgrep/tests/ - go-lint - fuzz-golang: name: fuzz-golang-<> - requires: - - go-mod-download on_changes: <> matrix: parameters: @@ -1322,13 +1336,13 @@ workflows: package_name: cannon on_changes: cannon,packages/contracts-bedrock/src/cannon uses_artifacts: true - requires: ["go-mod-download", "contracts-bedrock-build"] + requires: ["contracts-bedrock-build"] - fuzz-golang: name: op-e2e-fuzz package_name: op-e2e on_changes: op-e2e,packages/contracts-bedrock/src uses_artifacts: true - requires: ["go-mod-download", "contracts-bedrock-build"] + requires: ["contracts-bedrock-build"] - go-test: name: go-test-all requires: @@ -1355,6 +1369,7 @@ workflows: name: op-e2e-fault-proof-tests module: op-e2e target: test-fault-proofs + skip_slow_tests: true requires: - contracts-bedrock-build - cannon-prestate @@ -1364,7 +1379,8 @@ workflows: - go-mod-download - go-lint - cannon-build-test-vectors - - cannon-go-lint-and-test + - cannon-go-lint-and-test-32-bit + - cannon-go-lint-and-test-64-bit - check-generated-mocks-op-node - check-generated-mocks-op-service - go-mod-download @@ -1402,10 +1418,14 @@ workflows: - check-generated-mocks-op-node - check-generated-mocks-op-service - cannon-go-lint-and-test: + name: cannon-go-lint-and-test-<>-bit requires: - contracts-bedrock-build skip_slow_tests: true notify: true + matrix: + parameters: + mips_word_size: [ 32, 64 ] - cannon-build-test-vectors - todo-issues: name: todo-issues-check @@ -1575,6 +1595,7 @@ workflows: target: test-cannon notify: true mentions: "@proofs-team" + resource_class: ethereum-optimism/latitude-fps-1 requires: - contracts-bedrock-build - cannon-prestate @@ -1604,10 +1625,14 @@ workflows: - contracts-bedrock-build: skip_pattern: test - cannon-go-lint-and-test: + name: cannon-go-lint-and-test-<>-bit requires: - contracts-bedrock-build context: - slack + matrix: + parameters: + mips_word_size: [ 32, 64 ] scheduled-docker-publish: when: diff --git a/.coderabbit.yml b/.coderabbit.yml deleted file mode 100644 index f54403cf1571e..0000000000000 --- a/.coderabbit.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: "en" -early_access: false -reviews: - high_level_summary: false - poem: false - review_status: false - collapse_walkthrough: true - path_filters: - - "!**/*.json" - path_instructions: - - path: "**.sol" - instructions: "Focus on the following areas: - - Security - - Identifying test cases which are lacking - - Removing unnecessary code - " - auto_review: - enabled: false - drafts: false - base_branches: - - "develop" - - "feat/*" -chat: - auto_reply: true diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml deleted file mode 100644 index 4c8918566485a..0000000000000 --- a/.github/actions/setup/action.yml +++ /dev/null @@ -1,7 +0,0 @@ -name: Setup -description: Common setup steps used by our workflows -runs: - using: composite - steps: - - name: Setup foundry - uses: foundry-rs/foundry-toolchain@v1 diff --git a/semgrep/sol-rules.yaml b/.semgrep/rules/sol-rules.yaml similarity index 61% rename from semgrep/sol-rules.yaml rename to .semgrep/rules/sol-rules.yaml index 3c7422c25ed3b..57dc88a3e51ed 100644 --- a/semgrep/sol-rules.yaml +++ b/.semgrep/rules/sol-rules.yaml @@ -37,7 +37,45 @@ rules: - pattern: vm.expectRevert() paths: exclude: - - packages/contracts-bedrock/test + - packages/contracts-bedrock/test/dispute/WETH98.t.sol + + - id: sol-safety-natspec-semver-match + languages: [generic] + severity: ERROR + message: Semgrep defined in contract must match natspec $VERSION1 $VERSION2 + patterns: + - pattern-either: + - pattern-regex: /// @custom:semver + (?P[0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9.]+)?)\s+string + public constant version = + "(?P[0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9.]+)?)"; + - pattern-regex: /// @custom:semver + (?P[0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9.]+)?)\s+function + version\(\) public pure virtual returns \(string memory\) + \{\s+return + "(?P[0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9.]+)?)"; + - pattern-regex: + /// @custom:semver (?P[a-zA-Z0-9.+-]+)\s+function + version\(\) public pure override returns \(string memory\) + \{\s+return string\.concat\(super\.version\(\), + "(?P[a-zA-Z0-9.+-]+)"\); + - metavariable-comparison: + comparison: $VERSION1 != $VERSION2 + metavariable: $VERSION1 + paths: + include: + - packages/contracts-bedrock/src + + - id: sol-safety-no-public-in-libraries + languages: [generic] + severity: ERROR + message: Public functions in libraries are not allowed + patterns: + - pattern-inside: | + library $LIBRARY { + ... + } + - pattern-regex: function\s+\w+\s*\([^)]*\)\s+(?:.*\s+)?(public|external)\s+.*\{ - id: sol-style-input-arg-fmt languages: [solidity] @@ -46,6 +84,9 @@ rules: pattern-regex: function\s+\w+\s*\(\s*([^)]*?\b\w+\s+(?!_)(?!memory\b)(?!calldata\b)(?!storage\b)(?!payable\b)\w+\s*(?=,|\))) paths: exclude: + - packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC721.sol + - packages/contracts-bedrock/src/universal/interfaces/IWETH98.sol + - packages/contracts-bedrock/src/dispute/interfaces/IDelayedWETH.sol - op-chain-ops/script/testdata/scripts/ScriptExample.s.sol - packages/contracts-bedrock/test - packages/contracts-bedrock/scripts/libraries/Solarray.sol @@ -64,8 +105,9 @@ rules: pattern-regex: returns\s*(\w+\s*)?\(\s*([^)]*?\b\w+\s+(?!memory\b)(?!calldata\b)(?!storage\b)(?!payable\b)\w+(?" to assert that the rule catches the code. // Use comments like "ok: " to assert that the rule does not catch the code. +/// begin SemgrepTest__sol-style-no-bare-imports +// ok: sol-style-no-bare-imports +import { SomeStruct } from "some-library.sol"; + +// ok: sol-style-no-bare-imports +import { SomeStruct, AnotherThing } from "some-library.sol"; + +// ok: sol-style-no-bare-imports +import { SomeStruct as SomeOtherStruct } from "some-library.sol"; + +// ok: sol-style-no-bare-imports +import { SomeStruct as SomeOtherStruct, AnotherThing as AnotherOtherThing } from "some-library.sol"; + +// ok: sol-style-no-bare-imports +import { SomeStruct as SomeOtherStruct, AnotherThing } from "some-library.sol"; + +// ok: sol-style-no-bare-imports +import { AnotherThing, SomeStruct as SomeOtherStruct } from "some-library.sol"; + +// ruleid: sol-style-no-bare-imports +import "some-library.sol"; +/// end SemgrepTest__sol-style-no-bare-imports + contract SemgrepTest__sol_safety_deployutils_args { function test() { // ruleid: sol-safety-deployutils-args @@ -120,6 +143,162 @@ contract SemgrepTest__sol_safety_expectrevert_no_args { } } +contract SemgrepTest__sol_safety_natspec_semver_match { + // ok: sol-safety-natspec-semver-match + /// @custom:semver 2.8.1-beta.4 + string public constant version = "2.8.1-beta.4"; + + // ok: sol-safety-natspec-semver-match + /// @custom:semver 2.8.1-beta.3 + function version() public pure virtual returns (string memory) { + return "2.8.1-beta.3"; + } + + // ok: sol-safety-natspec-semver-match + /// @custom:semver +interop-beta.1 + function version() public pure override returns (string memory) { + return string.concat(super.version(), "+interop-beta.1"); + } + + // ruleid: sol-safety-natspec-semver-match + /// @custom:semver 2.8.1-beta.5 + string public constant version = "2.8.1-beta.4"; + + // ruleid: sol-safety-natspec-semver-match + /// @custom:semver 2.8.1-beta.4 + function version() public pure virtual returns (string memory) { + return "2.8.1-beta.3"; + } + + // ruleid: sol-safety-natspec-semver-match + /// @custom:semver +interop-beta.2 + function version() public pure override returns (string memory) { + return string.concat(super.version(), "+interop-beta.1"); + } +} + +library SemgrepTest__sol_safety_no_public_in_libraries { + // ok: sol-safety-no-public-in-libraries + function test() internal { + // ... + } + + // ok: sol-safety-no-public-in-libraries + function test() private { + // ... + } + + // ok: sol-safety-no-public-in-libraries + function test(uint256 _value, address _addr) internal { + // ... + } + + // ok: sol-safety-no-public-in-libraries + function test(uint256 _value, address _addr) private { + // ... + } + + // ok: sol-safety-no-public-in-libraries + function test() internal pure returns (uint256) { + // ... + } + + // ok: sol-safety-no-public-in-libraries + function test() private pure returns (uint256) { + // ... + } + + // ok: sol-safety-no-public-in-libraries + function test() internal view returns (uint256, address) { + // ... + } + + // ok: sol-safety-no-public-in-libraries + function test() private view returns (uint256, address) { + // ... + } + + // ok: sol-safety-no-public-in-libraries + function test() internal returns (uint256 amount_, bool success_) { + // ... + } + + // ok: sol-safety-no-public-in-libraries + function test() private returns (uint256 amount_, bool success_) { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test() public { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test() external { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test() public pure { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test() external pure { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test() public view { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test() external view { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test(uint256 _value, address _addr) public { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test(uint256 _value, address _addr) external { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test() public pure returns (uint256) { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test() external pure returns (uint256) { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test() public view returns (uint256, address) { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test() external view returns (uint256, address) { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test() public returns (uint256 amount_, bool success_) { + // ... + } + + // ruleid: sol-safety-no-public-in-libraries + function test() external returns (uint256 amount_, bool success_) { + // ... + } +} + contract SemgrepTest__sol_style_input_arg_fmt { // ok: sol-style-input-arg-fmt event Test(address indexed src, address indexed guy, uint256 wad); @@ -327,9 +506,6 @@ contract SemgrepTest__sol_style_malformed_require { // ok: sol-style-malformed-require require(cond, "CHECK-L2OO-140"); - // ok: sol-style-malformed-require - require(cond); - // ok: sol-style-malformed-require require(bytes(env_).length > 0, "Config: must set DEPLOY_CONFIG_PATH to filesystem path of deploy config"); @@ -395,3 +571,13 @@ contract SemgrepTest__sol_style_malformed_revert { revert("test"); } } + +contract SemgrepTest__sol_style_enforce_require_msg { + function test() { + // ok: sol-style-enforce-require-msg + require(cond, "MyContract: test message good"); + + // ruleid: sol-style-enforce-require-msg + require(cond); + } +} diff --git a/.semgrepignore b/.semgrepignore index 0e7e4044b758b..6c3e11fae449c 100644 --- a/.semgrepignore +++ b/.semgrepignore @@ -9,7 +9,10 @@ vendor/ *.min.js # Semgrep rules folder -semgrep/ +.semgrep/ # Semgrep-action log folder .semgrep_logs/ + +# Test contracts the scripts folder +op-chain-ops/script/testdata/scripts/ \ No newline at end of file diff --git a/.snyk b/.snyk deleted file mode 100644 index 1558a7a82432a..0000000000000 --- a/.snyk +++ /dev/null @@ -1,3 +0,0 @@ -exclude: - global: - - infra/op-replica/** # snyk does not respect kustomizations, so not useful here diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0534e696ff5f7..c4e5686db99ec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,6 +10,7 @@ You can: - Report issues in this repository. Great bug reports are detailed and give clear instructions for how a developer can reproduce the problem. Write good bug reports and developers will love you. - **IMPORTANT**: If you believe your report impacts the security of this repository, refer to the canonical [Security Policy](https://github.com/ethereum-optimism/.github/blob/master/SECURITY.md) document. - Fix issues that are tagged as [`D-good-first-issue`](https://github.com/ethereum-optimism/optimism/labels/D-good-first-issue) or [`S-confirmed`](https://github.com/ethereum-optimism/optimism/labels/S-confirmed). +- Larger projects are listed on [this project board](https://github.com/orgs/ethereum-optimism/projects/31/views/9). Please talk to us if you're considering working on one of these, they may not be fully specified so it will reduce risk to discuss the approach and ensure that it's still relevant. - Help improve the [Optimism Developer Docs](https://github.com/ethereum-optimism/docs) by reporting issues, fixing typos, or adding missing sections. - Get involved in the protocol design process by joining discussions within the [OP Stack Specs](https://github.com/ethereum-optimism/specs/discussions) repository. diff --git a/Makefile b/Makefile index 641e4b11699e3..9830a3060cb22 100644 --- a/Makefile +++ b/Makefile @@ -147,8 +147,8 @@ cannon-prestate: op-program cannon ## Generates prestate using cannon and op-pro mv op-program/bin/0.json op-program/bin/prestate-proof.json .PHONY: cannon-prestate -cannon-prestate-mt: op-program cannon ## Generates prestate using cannon and op-program in the multithreaded cannon format - ./cannon/bin/cannon load-elf --type multithreaded --path op-program/bin/op-program-client.elf --out op-program/bin/prestate-mt.bin.gz --meta op-program/bin/meta-mt.json +cannon-prestate-mt: op-program cannon ## Generates prestate using cannon and op-program in the multithreaded64 cannon format + ./cannon/bin/cannon load-elf --type multithreaded64 --path op-program/bin/op-program-client64.elf --out op-program/bin/prestate-mt.bin.gz --meta op-program/bin/meta-mt.json ./cannon/bin/cannon run --proof-at '=0' --stop-at '=1' --input op-program/bin/prestate-mt.bin.gz --meta op-program/bin/meta-mt.json --proof-fmt 'op-program/bin/%d-mt.json' --output "" mv op-program/bin/0-mt.json op-program/bin/prestate-proof-mt.json .PHONY: cannon-prestate-mt @@ -164,6 +164,7 @@ mod-tidy: ## Cleans up unused dependencies in Go modules clean: ## Removes all generated files under bin/ rm -rf ./bin + cd packages/contracts-bedrock/ && forge clean .PHONY: clean nuke: clean devnet-clean ## Completely clean the project directory @@ -172,10 +173,10 @@ nuke: clean devnet-clean ## Completely clean the project directory ## Prepares for running a local devnet pre-devnet: submodules $(DEVNET_CANNON_PRESTATE_FILES) - @if ! [ -x "$(command -v geth)" ]; then \ + @if ! [ -x "$$(command -v geth)" ]; then \ make install-geth; \ fi - @if ! [ -x "$(command -v eth2-testnet-genesis)" ]; then \ + @if ! [ -x "$$(command -v eth2-testnet-genesis)" ]; then \ make install-eth2-testnet-genesis; \ fi .PHONY: pre-devnet diff --git a/README.md b/README.md index d33f920c8398b..bda740f63c2ce 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ The OP Stack is a collaborative project. By collaborating on free, open software [CONTRIBUTING.md](./CONTRIBUTING.md) contains a detailed explanation of the contributing process for this repository. Make sure to use the [Developer Quick Start](./CONTRIBUTING.md#development-quick-start) to properly set up your development environment. -[Good First Issues](https://github.com/ethereum-optimism/optimism/issues?q=is:open+is:issue+label:D-good-first-issue) are a great place to look for tasks to tackle if you're not sure where to start. +[Good First Issues](https://github.com/ethereum-optimism/optimism/issues?q=is:open+is:issue+label:D-good-first-issue) are a great place to look for tasks to tackle if you're not sure where to start, and see [CONTRIBUTING.md](./CONTRIBUTING.md) for info on larger projects. ## Security Policy and Vulnerability Reporting @@ -65,7 +65,6 @@ The Optimism Immunefi program offers up to $2,000,042 for in-scope critical vuln
 ├── docs: A collection of documents including audits and post-mortems
 ├── op-batcher: L2-Batch Submitter, submits bundles of batches to L1
-├── op-bootnode: Standalone op-node discovery bootnode
 ├── op-chain-ops: State surgery utilities
 ├── op-challenger: Dispute game challenge agent
 ├── op-e2e: End-to-End testing of all bedrock components in Go
@@ -80,8 +79,7 @@ The Optimism Immunefi program offers up to $2,000,042 for in-scope critical vuln
 ├── ops-bedrock: Bedrock devnet work
 ├── packages
 │   ├── contracts-bedrock: OP Stack smart contracts
-├── proxyd: Configurable RPC request router and proxy
-├── specs: Specs of the rollup starting at the Bedrock upgrade
+├── semgrep: Semgrep rules and tests
 
## Development and Release Process @@ -125,7 +123,7 @@ All other components and packages should be considered development components on ### Development branch The primary development branch is [`develop`](https://github.com/ethereum-optimism/optimism/tree/develop/). -`develop` contains the most up-to-date software that remains backwards compatible with the latest experimental [network deployments](https://community.optimism.io/docs/useful-tools/networks/). +`develop` contains the most up-to-date software that remains backwards compatible with the latest experimental [network deployments](https://docs.optimism.io/chain/networks). If you're making a backwards compatible change, please direct your pull request towards `develop`. **Changes to contracts within `packages/contracts-bedrock/src` are usually NOT considered backwards compatible.** diff --git a/cannon/Dockerfile.diff b/cannon/Dockerfile.diff index dcdd3587e6817..a158ef9df79bb 100644 --- a/cannon/Dockerfile.diff +++ b/cannon/Dockerfile.diff @@ -23,7 +23,7 @@ ARG GIT_DATE ARG TARGETOS TARGETARCH -FROM --platform=$BUILDPLATFORM us-docker.pkg.dev/oplabs-tools-artifacts/images/cannon:v1.1.0-alpha.1 AS cannon-v2 +FROM --platform=$BUILDPLATFORM us-docker.pkg.dev/oplabs-tools-artifacts/images/cannon:v1.1.0-alpha.4 AS cannon-v2 FROM --platform=$BUILDPLATFORM builder as cannon-verify COPY --from=cannon-v2 /usr/local/bin/cannon /usr/local/bin/cannon-v2 diff --git a/cannon/Makefile b/cannon/Makefile index 5f74904011eca..6156cd68d64e4 100644 --- a/cannon/Makefile +++ b/cannon/Makefile @@ -15,6 +15,12 @@ endif .DEFAULT_GOAL := cannon +# The MIPS64 r1 opcodes not supported by cannon. This list does not include coprocess-specific opcodes. +UNSUPPORTED_OPCODES := (dclo|dclz) + +CANNON32_FUZZTIME := 10s +CANNON64_FUZZTIME := 20s + cannon32-impl: env GO111MODULE=on GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build --tags=cannon32 -v $(LDFLAGS) -o ./bin/cannon32-impl . @@ -43,7 +49,7 @@ elf: make -C ./testdata/example elf sanitize-program: - @if ! { mips-linux-gnu-objdump -d -j .text $$GUEST_PROGRAM | awk '{print $3}' | grep -Ew -m1 '(bgezal|bltzal)'; }; then \ + @if ! { mips-linux-gnu-objdump -d -j .text $$GUEST_PROGRAM | awk '{print $3}' | grep -Ew -m1 "$(UNSUPPORTED_OPCODES)"; }; then \ echo "guest program is sanitized for unsupported instructions"; \ else \ echo "found unsupported instructions in the guest program"; \ @@ -53,9 +59,12 @@ sanitize-program: contract: cd ../packages/contracts-bedrock && forge build -test: elf contract +test: elf contract test64 go test -v ./... +test64: elf contract + go test -tags=cannon64 -run '(TestEVM.*64|TestHelloEVM|TestClaimEVM)' ./mipsevm/tests + diff-%-cannon: cannon elf $$OTHER_CANNON load-elf --type $* --path ./testdata/example/bin/hello.elf --out ./bin/prestate-other.bin.gz --meta "" ./bin/cannon load-elf --type $* --path ./testdata/example/bin/hello.elf --out ./bin/prestate.bin.gz --meta "" @@ -80,19 +89,30 @@ cannon-stf-verify: @docker build --progress plain -f Dockerfile.diff ../ fuzz: - # Common vm tests - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallBrk ./mipsevm/tests - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallMmap ./mipsevm/tests - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallExitGroup ./mipsevm/tests - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallFcntl ./mipsevm/tests - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateHintRead ./mipsevm/tests - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 20s -fuzz=FuzzStatePreimageRead ./mipsevm/tests - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateHintWrite ./mipsevm/tests - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 20s -fuzz=FuzzStatePreimageWrite ./mipsevm/tests - # Single-threaded tests - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallCloneST ./mipsevm/tests - # Multi-threaded tests - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzStateSyscallCloneMT ./mipsevm/tests + printf "%s\n" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime $(CANNON32_FUZZTIME) -fuzz=FuzzStateSyscallBrk ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime $(CANNON32_FUZZTIME) -fuzz=FuzzStateSyscallMmap ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime $(CANNON32_FUZZTIME) -fuzz=FuzzStateSyscallExitGroup ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime $(CANNON32_FUZZTIME) -fuzz=FuzzStateSyscallFcntl ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime $(CANNON32_FUZZTIME) -fuzz=FuzzStateHintRead ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 20s -fuzz=FuzzStatePreimageRead ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime $(CANNON32_FUZZTIME) -fuzz=FuzzStateHintWrite ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 20s -fuzz=FuzzStatePreimageWrite ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime $(CANNON32_FUZZTIME) -fuzz=FuzzStateSyscallCloneST ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime $(CANNON32_FUZZTIME) -fuzz=FuzzStateSyscallCloneMT ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) -tags=cannon64 -run NOTAREALTEST -v -fuzztime $(CANNON64_FUZZTIME) -fuzz=FuzzStateConsistencyMulOp ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) -tags=cannon64 -run NOTAREALTEST -v -fuzztime $(CANNON64_FUZZTIME) -fuzz=FuzzStateConsistencyMultOp ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) -tags=cannon64 -run NOTAREALTEST -v -fuzztime $(CANNON64_FUZZTIME) -fuzz=FuzzStateConsistencyMultuOp ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) --tags=cannon64 -run NOTAREALTEST -v -fuzztime $(CANNON64_FUZZTIME) -fuzz=FuzzStateSyscallBrk ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) --tags=cannon64 -run NOTAREALTEST -v -fuzztime $(CANNON64_FUZZTIME) -fuzz=FuzzStateSyscallMmap ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) --tags=cannon64 -run NOTAREALTEST -v -fuzztime $(CANNON64_FUZZTIME) -fuzz=FuzzStateSyscallExitGroup ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) --tags=cannon64 -run NOTAREALTEST -v -fuzztime $(CANNON64_FUZZTIME) -fuzz=FuzzStateSyscallFcntl ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) --tags=cannon64 -run NOTAREALTEST -v -fuzztime $(CANNON64_FUZZTIME) -fuzz=FuzzStateHintRead ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) --tags=cannon64 -run NOTAREALTEST -v -fuzztime $(CANNON64_FUZZTIME) -fuzz=FuzzStatePreimageRead ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) --tags=cannon64 -run NOTAREALTEST -v -fuzztime $(CANNON64_FUZZTIME) -fuzz=FuzzStateHintWrite ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) --tags=cannon64 -run NOTAREALTEST -v -fuzztime $(CANNON64_FUZZTIME) -fuzz=FuzzStatePreimageWrite ./mipsevm/tests" \ + "go test $(FUZZLDFLAGS) --tags=cannon64 -run NOTAREALTEST -v -fuzztime $(CANNON64_FUZZTIME) -fuzz=FuzzStateSyscallCloneMT ./mipsevm/tests" \ + | parallel -j 8 {} .PHONY: \ cannon32-impl \ diff --git a/cannon/README.md b/cannon/README.md index be1615b45f8a9..a5af5b2e7ece9 100644 --- a/cannon/README.md +++ b/cannon/README.md @@ -39,6 +39,7 @@ make cannon # Note: # - The L2 RPC is an archive L2 node on OP MAINNET. # - The L1 RPC is a non-archive RPC, also change `--l1.rpckind` to reflect the correct L1 RPC type. +# - The network flag is only suitable for specific networks(https://github.com/ethereum-optimism/superchain-registry/blob/main/chainList.json). If you are running on the devnet, please use '--l2.genesis' to supply a path to the L2 devnet genesis file. ./bin/cannon run \ --pprof.cpu \ --info-at '%10000000' \ @@ -48,7 +49,7 @@ make cannon --input ./state.bin.gz \ -- \ ../op-program/bin/op-program \ - --network op-mainnet \ + --network \ --l1 \ --l2 \ --l1.head \ diff --git a/cannon/cmd/run.go b/cannon/cmd/run.go index 19352bad7d598..615e913f1e47c 100644 --- a/cannon/cmd/run.go +++ b/cannon/cmd/run.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum-optimism/optimism/cannon/mipsevm" "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" + mipsexec "github.com/ethereum-optimism/optimism/cannon/mipsevm/exec" "github.com/ethereum-optimism/optimism/cannon/mipsevm/program" "github.com/ethereum-optimism/optimism/cannon/mipsevm/versions" preimage "github.com/ethereum-optimism/optimism/op-preimage" @@ -29,16 +30,16 @@ import ( var ( RunInputFlag = &cli.PathFlag{ Name: "input", - Usage: "path of input JSON state. Stdin if left empty.", + Usage: "path of input binary state. Stdin if left empty.", TakesFile: true, - Value: "state.json", + Value: "state.bin.gz", Required: true, } RunOutputFlag = &cli.PathFlag{ Name: "output", - Usage: "path of output JSON state. Not written if empty, use - to write to Stdout.", + Usage: "path of output binary state. Not written if empty, use - to write to Stdout.", TakesFile: true, - Value: "out.json", + Value: "out.bin.gz", Required: false, } patternHelp = "'never' (default), 'always', '=123' at exactly step 123, '%123' for every 123 steps" @@ -63,7 +64,7 @@ var ( RunSnapshotFmtFlag = &cli.StringFlag{ Name: "snapshot-fmt", Usage: "format for snapshot output file names.", - Value: "state-%d.json", + Value: "state-%d.bin.gz", Required: false, } RunStopAtFlag = &cli.GenericFlag{ @@ -279,6 +280,9 @@ func Run(ctx *cli.Context) error { if ctx.Bool(RunPProfCPU.Name) { defer profile.Start(profile.NoShutdownHook, profile.ProfilePath("."), profile.CPUProfile).Stop() } + if err := checkFlags(ctx); err != nil { + return err + } guestLogger := Logger(os.Stderr, log.LevelInfo) outLog := &mipsevm.LoggingWriter{Log: guestLogger.With("module", "guest", "stream", "stdout")} @@ -407,14 +411,16 @@ func Run(ctx *cli.Context) error { if infoAt(state) { delta := time.Since(start) + pc := state.GetPC() + insn := mipsexec.LoadSubWord(state.GetMemory(), pc, 4, false, new(mipsexec.NoopMemoryTracker)) l.Info("processing", "step", step, "pc", mipsevm.HexU32(state.GetPC()), - "insn", mipsevm.HexU32(state.GetMemory().GetUint32(state.GetPC())), + "insn", mipsevm.HexU32(insn), "ips", float64(step-startStep)/(float64(delta)/float64(time.Second)), "pages", state.GetMemory().PageCount(), "mem", state.GetMemory().Usage(), - "name", meta.LookupSymbol(state.GetPC()), + "name", meta.LookupSymbol(pc), ) } @@ -524,3 +530,17 @@ func CreateRunCommand(action cli.ActionFunc) *cli.Command { } var RunCommand = CreateRunCommand(Run) + +func checkFlags(ctx *cli.Context) error { + if output := ctx.Path(RunOutputFlag.Name); output != "" { + if !serialize.IsBinaryFile(output) { + return errors.New("invalid --output file format. Only binary file formats (ending in .bin or bin.gz) are supported") + } + } + if snapshotFmt := ctx.String(RunSnapshotFmtFlag.Name); snapshotFmt != "" { + if !serialize.IsBinaryFile(fmt.Sprintf(snapshotFmt, 0)) { + return errors.New("invalid --snapshot-fmt file format. Only binary file formats (ending in .bin or bin.gz) are supported") + } + } + return nil +} diff --git a/cannon/mipsevm/README.md b/cannon/mipsevm/README.md index df7558187992b..f01aa61510e54 100644 --- a/cannon/mipsevm/README.md +++ b/cannon/mipsevm/README.md @@ -12,8 +12,10 @@ Supported 63 instructions: | `Conditional Branch` | `beq` | Branch on equal. | | `Conditional Branch` | `bgez` | Branch on greater than or equal to zero. | | `Conditional Branch` | `bgtz` | Branch on greater than zero. | +| `Conditional Branch` | `bgezal` | Branch and link on greater than or equal to zero. | | `Conditional Branch` | `blez` | Branch on less than or equal to zero. | | `Conditional Branch` | `bltz` | Branch on less than zero. | +| `Conditional Branch` | `bltzal` | Branch and link on less than zero. | | `Conditional Branch` | `bne` | Branch on not equal. | | `Logical` | `clo` | Count leading ones. | | `Logical` | `clz` | Count leading zeros. | diff --git a/cannon/mipsevm/arch/arch32.go b/cannon/mipsevm/arch/arch32.go index 87cad3cf504d2..4f9329ef9ce3d 100644 --- a/cannon/mipsevm/arch/arch32.go +++ b/cannon/mipsevm/arch/arch32.go @@ -61,6 +61,7 @@ const ( SysPrlimit64 = 4338 SysClose = 4006 SysPread64 = 4200 + SysStat = 4106 SysFstat = 4108 SysFstat64 = 4215 SysOpenAt = 4288 @@ -79,6 +80,8 @@ const ( SysLlseek = 4140 SysMinCore = 4217 SysTgkill = 4266 + SysGetRLimit = 4076 + SysLseek = 4019 // Profiling-related syscalls SysSetITimer = 4104 SysTimerCreate = 4257 diff --git a/cannon/mipsevm/arch/arch64.go b/cannon/mipsevm/arch/arch64.go index a9b7df70c5830..b6a23f5fde9ef 100644 --- a/cannon/mipsevm/arch/arch64.go +++ b/cannon/mipsevm/arch/arch64.go @@ -25,10 +25,12 @@ const ( AddressMask = 0xFFFFFFFFFFFFFFF8 ExtMask = 0x7 - HeapStart = 0x10_00_00_00_00_00_00_00 - HeapEnd = 0x60_00_00_00_00_00_00_00 - ProgramBreak = 0x40_00_00_00_00_00_00_00 - HighMemoryStart = 0x7F_FF_FF_FF_D0_00_00_00 + // Ensure virtual address is limited to 48-bits as many user programs assume such to implement packed pointers + // limit 0x00_00_FF_FF_FF_FF_FF_FF + HeapStart = 0x00_00_10_00_00_00_00_00 + HeapEnd = 0x00_00_60_00_00_00_00_00 + ProgramBreak = 0x00_00_40_00_00_00_00_00 + HighMemoryStart = 0x00_00_7F_FF_FF_FF_F0_00 ) // MIPS64 syscall table - https://github.com/torvalds/linux/blob/3efc57369a0ce8f76bf0804f7e673982384e4ac9/arch/mips/kernel/syscalls/syscall_n64.tbl. Generate the syscall numbers using the Makefile in that directory. @@ -67,6 +69,7 @@ const ( SysPrlimit64 = 5297 SysClose = 5003 SysPread64 = 5016 + SysStat = 5004 SysFstat = 5005 SysFstat64 = UndefinedSysNr SysOpenAt = 5247 @@ -85,6 +88,8 @@ const ( SysLlseek = UndefinedSysNr SysMinCore = 5026 SysTgkill = 5225 + SysGetRLimit = 5095 + SysLseek = 5008 // Profiling-related syscalls SysSetITimer = 5036 SysTimerCreate = 5216 diff --git a/cannon/mipsevm/exec/memory.go b/cannon/mipsevm/exec/memory.go index 1601ad3052282..77c373198ddf0 100644 --- a/cannon/mipsevm/exec/memory.go +++ b/cannon/mipsevm/exec/memory.go @@ -3,6 +3,7 @@ package exec import ( "fmt" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" "github.com/ethereum-optimism/optimism/cannon/mipsevm/memory" ) @@ -37,7 +38,7 @@ func (m *MemoryTrackerImpl) TrackMemAccess(effAddr Word) { // TrackMemAccess2 creates a proof for a memory access following a call to TrackMemAccess // This is used to generate proofs for contiguous memory accesses within the same step func (m *MemoryTrackerImpl) TrackMemAccess2(effAddr Word) { - if m.memProofEnabled && m.lastMemAccess+4 != effAddr { + if m.memProofEnabled && m.lastMemAccess+arch.WordSizeBytes != effAddr { panic(fmt.Errorf("unexpected disjointed mem access at %08x, last memory access is at %08x buffered", effAddr, m.lastMemAccess)) } m.lastMemAccess = effAddr @@ -56,3 +57,7 @@ func (m *MemoryTrackerImpl) MemProof() [memory.MemProofSize]byte { func (m *MemoryTrackerImpl) MemProof2() [memory.MemProofSize]byte { return m.memProof2 } + +type NoopMemoryTracker struct{} + +func (n *NoopMemoryTracker) TrackMemAccess(Word) {} diff --git a/cannon/mipsevm/exec/mips_instructions.go b/cannon/mipsevm/exec/mips_instructions.go index af7b988c15849..c8e27e63df01b 100644 --- a/cannon/mipsevm/exec/mips_instructions.go +++ b/cannon/mipsevm/exec/mips_instructions.go @@ -2,13 +2,11 @@ package exec import ( "fmt" + "math/bits" "github.com/ethereum-optimism/optimism/cannon/mipsevm" "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" "github.com/ethereum-optimism/optimism/cannon/mipsevm/memory" - - // TODO(#12205): MIPS64 port. Replace with a custom library - u128 "lukechampine.com/uint128" ) const ( @@ -16,22 +14,33 @@ const ( OpStoreConditional = 0x38 OpLoadLinked64 = 0x34 OpStoreConditional64 = 0x3c + OpLoadDoubleLeft = 0x1A + OpLoadDoubleRight = 0x1B + + // Return address register + RegRA = 31 ) func GetInstructionDetails(pc Word, memory *memory.Memory) (insn, opcode, fun uint32) { - insn = memory.GetUint32(pc) + if pc&0x3 != 0 { + panic(fmt.Errorf("invalid pc: %x", pc)) + } + word := memory.GetWord(pc & arch.AddressMask) + insn = uint32(SelectSubWord(pc, word, 4, false)) opcode = insn >> 26 // First 6-bits fun = insn & 0x3f // Last 6-bits return insn, opcode, fun } -func ExecMipsCoreStepLogic(cpu *mipsevm.CpuScalars, registers *[32]Word, memory *memory.Memory, insn, opcode, fun uint32, memTracker MemTracker, stackTracker StackTracker) (memUpdated bool, memAddr Word, err error) { +// ExecMipsCoreStepLogic executes a MIPS instruction that isn't a syscall nor a RMW operation +// If a store operation occurred, then it returns the effective address of the store memory location. +func ExecMipsCoreStepLogic(cpu *mipsevm.CpuScalars, registers *[32]Word, memory *memory.Memory, insn, opcode, fun uint32, memTracker MemTracker, stackTracker StackTracker) (memUpdated bool, effMemAddr Word, err error) { // j-type j/jal if opcode == 2 || opcode == 3 { linkReg := Word(0) if opcode == 3 { - linkReg = 31 + linkReg = RegRA } // Take the top bits of the next PC (its 256 MB region), and concatenate with the 26-bit offset target := (cpu.NextPC & SignExtend(0xF0000000, 32)) | Word((insn&0x03FFFFFF)<<2) @@ -77,7 +86,7 @@ func ExecMipsCoreStepLogic(cpu *mipsevm.CpuScalars, registers *[32]Word, memory } if (opcode >= 4 && opcode < 8) || opcode == 1 { - err = HandleBranch(cpu, registers, opcode, insn, rtReg, rs) + err = HandleBranch(cpu, registers, opcode, insn, rtReg, rs, stackTracker) return } @@ -85,7 +94,7 @@ func ExecMipsCoreStepLogic(cpu *mipsevm.CpuScalars, registers *[32]Word, memory // memory fetch (all I-type) // we do the load for stores also mem := Word(0) - if opcode >= 0x20 { + if opcode >= 0x20 || opcode == OpLoadDoubleLeft || opcode == OpLoadDoubleRight { // M[R[rs]+SignExtImm] rs += SignExtendImmediate(insn) addr := rs & arch.AddressMask @@ -146,7 +155,7 @@ func ExecMipsCoreStepLogic(cpu *mipsevm.CpuScalars, registers *[32]Word, memory memTracker.TrackMemAccess(storeAddr) memory.SetWord(storeAddr, val) memUpdated = true - memAddr = storeAddr + effMemAddr = storeAddr } // write back the value to destination register @@ -311,10 +320,10 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem case 0x3C: // dsll32 assertMips64(insn) return rt << (((insn >> 6) & 0x1f) + 32) - case 0x3E: // dsll32 + case 0x3E: // dsrl32 assertMips64(insn) return rt >> (((insn >> 6) & 0x1f) + 32) - case 0x3F: // dsll32 + case 0x3F: // dsra32 assertMips64(insn) return Word(int64(rt) >> (((insn >> 6) & 0x1f) + 32)) default: @@ -340,56 +349,76 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem case 0x0F: // lui return SignExtend(rt<<16, 32) case 0x20: // lb - msb := uint32(arch.WordSize - 8) // 24 for 32-bit and 56 for 64-bit - return SignExtend((mem>>(msb-uint32(rs&arch.ExtMask)*8))&0xFF, 8) + return SelectSubWord(rs, mem, 1, true) case 0x21: // lh - msb := uint32(arch.WordSize - 16) // 16 for 32-bit and 48 for 64-bit - mask := Word(arch.ExtMask - 1) - return SignExtend((mem>>(msb-uint32(rs&mask)*8))&0xFFFF, 16) + return SelectSubWord(rs, mem, 2, true) case 0x22: // lwl - val := mem << ((rs & 3) * 8) - mask := Word(uint32(0xFFFFFFFF) << ((rs & 3) * 8)) - return SignExtend(((rt & ^mask)|val)&0xFFFFFFFF, 32) + if arch.IsMips32 { + val := mem << ((rs & 3) * 8) + mask := Word(uint32(0xFFFFFFFF) << ((rs & 3) * 8)) + return SignExtend(((rt & ^mask)|val)&0xFFFFFFFF, 32) + } else { + // similar to the above mips32 implementation but loads are constrained to the nearest 4-byte memory word + w := uint32(SelectSubWord(rs, mem, 4, false)) + val := w << ((rs & 3) * 8) + mask := Word(uint32(0xFFFFFFFF) << ((rs & 3) * 8)) + return SignExtend(((rt & ^mask)|Word(val))&0xFFFFFFFF, 32) + } case 0x23: // lw - // TODO(#12205): port to MIPS64 - return mem - //return SignExtend((mem>>(32-((rs&0x4)<<3)))&0xFFFFFFFF, 32) + return SelectSubWord(rs, mem, 4, true) case 0x24: // lbu - msb := uint32(arch.WordSize - 8) // 24 for 32-bit and 56 for 64-bit - return (mem >> (msb - uint32(rs&arch.ExtMask)*8)) & 0xFF + return SelectSubWord(rs, mem, 1, false) case 0x25: // lhu - msb := uint32(arch.WordSize - 16) // 16 for 32-bit and 48 for 64-bit - mask := Word(arch.ExtMask - 1) - return (mem >> (msb - uint32(rs&mask)*8)) & 0xFFFF + return SelectSubWord(rs, mem, 2, false) case 0x26: // lwr - val := mem >> (24 - (rs&3)*8) - mask := Word(uint32(0xFFFFFFFF) >> (24 - (rs&3)*8)) - return SignExtend(((rt & ^mask)|val)&0xFFFFFFFF, 32) + if arch.IsMips32 { + val := mem >> (24 - (rs&3)*8) + mask := Word(uint32(0xFFFFFFFF) >> (24 - (rs&3)*8)) + return SignExtend(((rt & ^mask)|val)&0xFFFFFFFF, 32) + } else { + // similar to the above mips32 implementation but constrained to the nearest 4-byte memory word + w := uint32(SelectSubWord(rs, mem, 4, false)) + val := w >> (24 - (rs&3)*8) + mask := uint32(0xFFFFFFFF) >> (24 - (rs&3)*8) + lwrResult := (uint32(rt) & ^mask) | val + if rs&3 == 3 { // loaded bit 31 + return SignExtend(Word(lwrResult), 32) + } else { + // NOTE: cannon64 implementation specific: We leave the upper word untouched + rtMask := uint64(0xFF_FF_FF_FF_00_00_00_00) + return (rt & Word(rtMask)) | Word(lwrResult) + } + } case 0x28: // sb - msb := uint32(arch.WordSize - 8) // 24 for 32-bit and 56 for 64-bit - val := (rt & 0xFF) << (msb - uint32(rs&arch.ExtMask)*8) - mask := ^Word(0) ^ Word(0xFF<<(msb-uint32(rs&arch.ExtMask)*8)) - return (mem & mask) | val + return UpdateSubWord(rs, mem, 1, rt) case 0x29: // sh - msb := uint32(arch.WordSize - 16) // 16 for 32-bit and 48 for 64-bit - rsMask := Word(arch.ExtMask - 1) // 2 for 32-bit and 6 for 64-bit - sl := msb - uint32(rs&rsMask)*8 - val := (rt & 0xFFFF) << sl - mask := ^Word(0) ^ Word(0xFFFF<> ((rs & 3) * 8) - mask := uint32(0xFFFFFFFF) >> ((rs & 3) * 8) - return (mem & Word(^mask)) | val + if arch.IsMips32 { + val := rt >> ((rs & 3) * 8) + mask := uint32(0xFFFFFFFF) >> ((rs & 3) * 8) + return (mem & Word(^mask)) | val + } else { + sr := (rs & 3) << 3 + val := ((rt & 0xFFFFFFFF) >> sr) << (32 - ((rs & 0x4) << 3)) + mask := (uint64(0xFFFFFFFF) >> sr) << (32 - ((rs & 0x4) << 3)) + return (mem & Word(^mask)) | val + } case 0x2b: // sw - // TODO(#12205): port to MIPS64 - return rt + return UpdateSubWord(rs, mem, 4, rt) case 0x2e: // swr - // TODO(#12205): port to MIPS64 - val := rt << (24 - (rs&3)*8) - mask := uint32(0xFFFFFFFF) << (24 - (rs&3)*8) - return (mem & Word(^mask)) | val + if arch.IsMips32 { + val := rt << (24 - (rs&3)*8) + mask := uint32(0xFFFFFFFF) << (24 - (rs&3)*8) + return (mem & Word(^mask)) | val + } else { + // similar to the above mips32 implementation but constrained to the nearest 4-byte memory word + w := uint32(SelectSubWord(rs, mem, 4, false)) + val := rt << (24 - (rs&3)*8) + mask := uint32(0xFFFFFFFF) << (24 - (rs&3)*8) + swrResult := (w & ^mask) | uint32(val) + return UpdateSubWord(rs, mem, 4, Word(swrResult)) + } // MIPS64 case 0x1A: // ldl @@ -424,15 +453,12 @@ func ExecuteMipsInstruction(insn uint32, opcode uint32, fun uint32, rs, rt, mem return mem case 0x3F: // sd assertMips64(insn) - sl := (rs & 0x7) << 3 - val := rt << sl - mask := ^Word(0) << sl - return (mem & ^mask) | val + return rt default: - panic("invalid instruction") + panic(fmt.Sprintf("invalid instruction: %x", insn)) } } - panic("invalid instruction") + panic(fmt.Sprintf("invalid instruction: %x", insn)) } func SignExtend(dat Word, idx Word) Word { @@ -446,12 +472,13 @@ func SignExtend(dat Word, idx Word) Word { } } -func HandleBranch(cpu *mipsevm.CpuScalars, registers *[32]Word, opcode uint32, insn uint32, rtReg Word, rs Word) error { +func HandleBranch(cpu *mipsevm.CpuScalars, registers *[32]Word, opcode uint32, insn uint32, rtReg Word, rs Word, stackTracker StackTracker) error { if cpu.NextPC != cpu.PC+4 { panic("branch in delay slot") } shouldBranch := false + linked := false if opcode == 4 || opcode == 5 { // beq/bne rt := registers[rtReg] shouldBranch = (rs == rt && opcode == 4) || (rs != rt && opcode == 5) @@ -463,10 +490,20 @@ func HandleBranch(cpu *mipsevm.CpuScalars, registers *[32]Word, opcode uint32, i // regimm rtv := (insn >> 16) & 0x1F if rtv == 0 { // bltz - shouldBranch = int32(rs) < 0 + shouldBranch = arch.SignedInteger(rs) < 0 + } + if rtv == 0x10 { // bltzal + shouldBranch = arch.SignedInteger(rs) < 0 + registers[31] = cpu.PC + 8 // always set regardless of branch taken + linked = true } if rtv == 1 { // bgez - shouldBranch = int32(rs) >= 0 + shouldBranch = arch.SignedInteger(rs) >= 0 + } + if rtv == 0x11 { // bgezal (i.e. bal mnemonic) + shouldBranch = arch.SignedInteger(rs) >= 0 + registers[RegRA] = cpu.PC + 8 // always set regardless of branch taken + linked = true } } @@ -474,12 +511,16 @@ func HandleBranch(cpu *mipsevm.CpuScalars, registers *[32]Word, opcode uint32, i cpu.PC = cpu.NextPC // execute the delay slot first if shouldBranch { cpu.NextPC = prevPC + 4 + (SignExtend(Word(insn&0xFFFF), 16) << 2) // then continue with the instruction the branch jumps to. + if linked { + stackTracker.PushStack(prevPC, cpu.NextPC) + } } else { cpu.NextPC = cpu.NextPC + 4 // branch not taken } return nil } +// HandleHiLo handles instructions that modify HI and LO registers. It also additionally handles doubleword variable shift operations func HandleHiLo(cpu *mipsevm.CpuScalars, registers *[32]Word, fun uint32, rs Word, rt Word, storeReg Word) error { val := Word(0) switch fun { @@ -500,9 +541,15 @@ func HandleHiLo(cpu *mipsevm.CpuScalars, registers *[32]Word, fun uint32, rs Wor cpu.HI = SignExtend(Word(acc>>32), 32) cpu.LO = SignExtend(Word(uint32(acc)), 32) case 0x1a: // div + if uint32(rt) == 0 { + panic("instruction divide by zero") + } cpu.HI = SignExtend(Word(int32(rs)%int32(rt)), 32) cpu.LO = SignExtend(Word(int32(rs)/int32(rt)), 32) case 0x1b: // divu + if uint32(rt) == 0 { + panic("instruction divide by zero") + } cpu.HI = SignExtend(Word(uint32(rs)%uint32(rt)), 32) cpu.LO = SignExtend(Word(uint32(rs)/uint32(rt)), 32) case 0x14: // dsllv @@ -515,22 +562,44 @@ func HandleHiLo(cpu *mipsevm.CpuScalars, registers *[32]Word, fun uint32, rs Wor assertMips64Fun(fun) val = Word(int64(rt) >> (rs & 0x3F)) case 0x1c: // dmult - // TODO(#12205): port to MIPS64. Is signed multiply needed for dmult assertMips64Fun(fun) - acc := u128.From64(uint64(rs)).Mul(u128.From64(uint64(rt))) - cpu.HI = Word(acc.Hi) - cpu.LO = Word(acc.Lo) + a := int64(rs) + b := int64(rt) + negative := (a < 0) != (b < 0) // set if operands have different signs + + // Handle special case for most negative value to avoid overflow in negation + absA := uint64(abs64(a)) + absB := uint64(abs64(b)) + + hi, lo := bits.Mul64(absA, absB) + if negative { + // Two's complement negation: flip all bits and add 1 + hi = ^hi + lo = ^lo + if lo == 0xFFFFFFFFFFFFFFFF { + hi++ + } + lo++ + } + cpu.HI = Word(hi) + cpu.LO = Word(lo) case 0x1d: // dmultu assertMips64Fun(fun) - acc := u128.From64(uint64(rs)).Mul(u128.From64(uint64(rt))) - cpu.HI = Word(acc.Hi) - cpu.LO = Word(acc.Lo) + hi, lo := bits.Mul64(uint64(rs), uint64(rt)) + cpu.HI = Word(hi) + cpu.LO = Word(lo) case 0x1e: // ddiv assertMips64Fun(fun) + if rt == 0 { + panic("instruction divide by zero") + } cpu.HI = Word(int64(rs) % int64(rt)) cpu.LO = Word(int64(rs) / int64(rt)) case 0x1f: // ddivu assertMips64Fun(fun) + if rt == 0 { + panic("instruction divide by zero") + } cpu.HI = rs % rt cpu.LO = rs / rt } @@ -570,46 +639,65 @@ func HandleRd(cpu *mipsevm.CpuScalars, registers *[32]Word, storeReg Word, val W return nil } -func LoadSubWord(memory *memory.Memory, addr Word, byteLength Word, signExtend bool, memoryTracker MemTracker) Word { +// LoadSubWord loads a subword of byteLength size from memory based on the low-order bits of vaddr +func LoadSubWord(memory *memory.Memory, vaddr Word, byteLength Word, signExtend bool, memoryTracker MemTracker) Word { // Pull data from memory - effAddr := (addr) & arch.AddressMask + effAddr := (vaddr) & arch.AddressMask memoryTracker.TrackMemAccess(effAddr) mem := memory.GetWord(effAddr) - // Extract a sub-word based on the low-order bits in addr - dataMask, bitOffset, bitLength := calculateSubWordMaskAndOffset(addr, byteLength) - retVal := (mem >> bitOffset) & dataMask - if signExtend { - retVal = SignExtend(retVal, bitLength) - } - - return retVal + return SelectSubWord(vaddr, mem, byteLength, signExtend) } -func StoreSubWord(memory *memory.Memory, addr Word, byteLength Word, value Word, memoryTracker MemTracker) { +// StoreSubWord stores a [Word] that has been updated by the specified value at bit positions determined by the vaddr +func StoreSubWord(memory *memory.Memory, vaddr Word, byteLength Word, value Word, memoryTracker MemTracker) { // Pull data from memory - effAddr := (addr) & arch.AddressMask + effAddr := (vaddr) & arch.AddressMask memoryTracker.TrackMemAccess(effAddr) mem := memory.GetWord(effAddr) // Modify isolated sub-word within mem - dataMask, bitOffset, _ := calculateSubWordMaskAndOffset(addr, byteLength) + newMemVal := UpdateSubWord(vaddr, mem, byteLength, value) + memory.SetWord(effAddr, newMemVal) +} + +// SelectSubWord selects a subword of byteLength size contained in memWord based on the low-order bits of vaddr +// This is the nearest subword that is naturally aligned by the specified byteLength +func SelectSubWord(vaddr Word, memWord Word, byteLength Word, signExtend bool) Word { + // Extract a sub-word based on the low-order bits in vaddr + dataMask, bitOffset, bitLength := calculateSubWordMaskAndOffset(vaddr, byteLength) + retVal := (memWord >> bitOffset) & dataMask + if signExtend { + retVal = SignExtend(retVal, bitLength) + } + return retVal +} + +// UpdateSubWord returns a [Word] that has been updated by the specified value at bit positions determined by the vaddr +func UpdateSubWord(vaddr Word, memWord Word, byteLength Word, value Word) Word { + dataMask, bitOffset, _ := calculateSubWordMaskAndOffset(vaddr, byteLength) subWordValue := dataMask & value memUpdateMask := dataMask << bitOffset - newMemVal := subWordValue<> (arch.WordSize - bitLength) - // Figure out sub-word index based on the low-order bits in addr - byteIndexMask := addr & arch.ExtMask & ^(byteLength - 1) + // Figure out sub-word index based on the low-order bits in vaddr + byteIndexMask := vaddr & arch.ExtMask & ^(byteLength - 1) maxByteShift := arch.WordSizeBytes - byteLength - byteIndex := addr & byteIndexMask + byteIndex := vaddr & byteIndexMask bitOffset = (maxByteShift - byteIndex) << 3 return dataMask, bitOffset, bitLength } + +// abs64 returns the absolute value +func abs64(x int64) int64 { + if x < 0 { + return -x + } + return x +} diff --git a/cannon/mipsevm/memory/memory.go b/cannon/mipsevm/memory/memory.go index 209d1d431e6f6..1234af4dc4b68 100644 --- a/cannon/mipsevm/memory/memory.go +++ b/cannon/mipsevm/memory/memory.go @@ -192,25 +192,6 @@ func (m *Memory) pageLookup(pageIndex Word) (*CachedPage, bool) { return p, ok } -func (m *Memory) SetUint32(addr Word, v uint32) { - // addr must be aligned to WordSizeBytes bytes - if addr&arch.ExtMask != 0 { - panic(fmt.Errorf("unaligned memory access: %x", addr)) - } - - pageIndex := addr >> PageAddrSize - pageAddr := addr & PageAddrMask - p, ok := m.pageLookup(pageIndex) - if !ok { - // allocate the page if we have not already. - // Go may mmap relatively large ranges, but we only allocate the pages just in time. - p = m.AllocPage(pageIndex) - } else { - m.invalidate(addr) // invalidate this branch of memory, now that the value changed - } - binary.BigEndian.PutUint32(p.Data[pageAddr:pageAddr+4], v) -} - // SetWord stores [arch.Word] sized values at the specified address func (m *Memory) SetWord(addr Word, v Word) { // addr must be aligned to WordSizeBytes bytes @@ -231,20 +212,6 @@ func (m *Memory) SetWord(addr Word, v Word) { arch.ByteOrderWord.PutWord(p.Data[pageAddr:pageAddr+arch.WordSizeBytes], v) } -// GetUint32 returns the first 32 bits located at the specified location. -func (m *Memory) GetUint32(addr Word) uint32 { - // addr must be aligned to 4 bytes - if addr&3 != 0 { - panic(fmt.Errorf("unaligned memory access: %x", addr)) - } - p, ok := m.pageLookup(addr >> PageAddrSize) - if !ok { - return 0 - } - pageAddr := addr & PageAddrMask - return binary.BigEndian.Uint32(p.Data[pageAddr : pageAddr+4]) -} - // GetWord reads the maximum sized value, [arch.Word], located at the specified address. // Note: Also referred to by the MIPS64 specification as a "double-word" memory access. func (m *Memory) GetWord(addr Word) Word { @@ -313,18 +280,22 @@ func (m *Memory) SetMemoryRange(addr Word, r io.Reader) error { for { pageIndex := addr >> PageAddrSize pageAddr := addr & PageAddrMask - p, ok := m.pageLookup(pageIndex) - if !ok { - p = m.AllocPage(pageIndex) - } - p.InvalidateFull() - n, err := r.Read(p.Data[pageAddr:]) + readLen := PageSize - pageAddr + chunk := make([]byte, readLen) + n, err := r.Read(chunk) if err != nil { if err == io.EOF { return nil } return err } + + p, ok := m.pageLookup(pageIndex) + if !ok { + p = m.AllocPage(pageIndex) + } + p.InvalidateFull() + copy(p.Data[pageAddr:], chunk[:n]) addr += Word(n) } } diff --git a/cannon/mipsevm/memory/memory64_test.go b/cannon/mipsevm/memory/memory64_test.go index 3bc3c34677211..203ff5f80d2f4 100644 --- a/cannon/mipsevm/memory/memory64_test.go +++ b/cannon/mipsevm/memory/memory64_test.go @@ -12,6 +12,7 @@ import ( "strings" "testing" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" "github.com/stretchr/testify/require" ) @@ -140,45 +141,72 @@ func TestMemory64ReadWrite(t *testing.T) { require.Equal(t, make([]byte, 10), res[len(res)-10:], "empty end") }) + t.Run("empty range", func(t *testing.T) { + m := NewMemory() + addr := Word(0xAABBCC00) + r := bytes.NewReader(nil) + pre := m.MerkleRoot() + preJSON, err := m.MarshalJSON() + require.NoError(t, err) + var preSerialized bytes.Buffer + require.NoError(t, m.Serialize(&preSerialized)) + + require.NoError(t, m.SetMemoryRange(addr, r)) + v := m.GetWord(0) + require.Equal(t, Word(0), v) + post := m.MerkleRoot() + require.Equal(t, pre, post) + + // Assert that there are no extra zero pages in serialization + postJSON, err := m.MarshalJSON() + require.NoError(t, err) + require.Equal(t, preJSON, postJSON) + + var postSerialized bytes.Buffer + require.NoError(t, m.Serialize(&postSerialized)) + require.Equal(t, preSerialized.Bytes(), postSerialized.Bytes()) + }) + + t.Run("range page overlap", func(t *testing.T) { + m := NewMemory() + data := bytes.Repeat([]byte{0xAA}, PageAddrSize) + require.NoError(t, m.SetMemoryRange(0, bytes.NewReader(data))) + for i := 0; i < PageAddrSize/arch.WordSizeBytes; i++ { + addr := Word(i * arch.WordSizeBytes) + require.Equal(t, Word(0xAAAAAAAA_AAAAAAAA), m.GetWord(addr)) + } + + data = []byte{0x11, 0x22, 0x33, 0x44} + require.NoError(t, m.SetMemoryRange(0, bytes.NewReader(data))) + require.Equal(t, Word(0x11223344_AAAAAAAA), m.GetWord(0)) + for i := 1; i < PageAddrSize/arch.WordSizeBytes; i++ { + addr := Word(i * arch.WordSizeBytes) + require.Equal(t, Word(0xAAAAAAAA_AAAAAAAA), m.GetWord(addr)) + } + }) + t.Run("read-write", func(t *testing.T) { m := NewMemory() m.SetWord(16, 0xAABBCCDD_EEFF1122) require.Equal(t, Word(0xAABBCCDD_EEFF1122), m.GetWord(16)) - require.Equal(t, uint32(0xAABBCCDD), m.GetUint32(16)) - require.Equal(t, uint32(0xEEFF1122), m.GetUint32(20)) m.SetWord(16, 0xAABB1CDD_EEFF1122) require.Equal(t, Word(0xAABB1CDD_EEFF1122), m.GetWord(16)) - require.Equal(t, uint32(0xAABB1CDD), m.GetUint32(16)) - require.Equal(t, uint32(0xEEFF1122), m.GetUint32(20)) m.SetWord(16, 0xAABB1CDD_EEFF1123) require.Equal(t, Word(0xAABB1CDD_EEFF1123), m.GetWord(16)) - require.Equal(t, uint32(0xAABB1CDD), m.GetUint32(16)) - require.Equal(t, uint32(0xEEFF1123), m.GetUint32(20)) }) t.Run("unaligned read", func(t *testing.T) { m := NewMemory() - m.SetWord(16, 0xAABBCCDD_EEFF1122) + m.SetWord(16, Word(0xAABBCCDD_EEFF1122)) m.SetWord(24, 0x11223344_55667788) for i := Word(17); i < 24; i++ { require.Panics(t, func() { m.GetWord(i) }) - if i != 20 { - require.Panics(t, func() { - m.GetUint32(i) - }) - } } require.Equal(t, Word(0x11223344_55667788), m.GetWord(24)) - require.Equal(t, uint32(0x11223344), m.GetUint32(24)) require.Equal(t, Word(0), m.GetWord(32)) - require.Equal(t, uint32(0), m.GetUint32(32)) require.Equal(t, Word(0xAABBCCDD_EEFF1122), m.GetWord(16)) - require.Equal(t, uint32(0xAABBCCDD), m.GetUint32(16)) - - require.Equal(t, uint32(0xEEFF1122), m.GetUint32(20)) - require.Equal(t, uint32(0x55667788), m.GetUint32(28)) }) t.Run("unaligned write", func(t *testing.T) { @@ -206,7 +234,6 @@ func TestMemory64ReadWrite(t *testing.T) { m.SetWord(23, 0x11223344) }) require.Equal(t, Word(0xAABBCCDD_EEFF1122), m.GetWord(16)) - require.Equal(t, uint32(0xAABBCCDD), m.GetUint32(16)) }) } @@ -218,7 +245,6 @@ func TestMemory64JSON(t *testing.T) { var res Memory require.NoError(t, json.Unmarshal(dat, &res)) require.Equal(t, Word(0xAABBCCDD_EEFF1122), res.GetWord(8)) - require.Equal(t, uint32(0xAABBCCDD), res.GetUint32(8)) } func TestMemory64Copy(t *testing.T) { @@ -226,6 +252,5 @@ func TestMemory64Copy(t *testing.T) { m.SetWord(0xAABBCCDD_8000, 0x000000_AABB) mcpy := m.Copy() require.Equal(t, Word(0xAABB), mcpy.GetWord(0xAABBCCDD_8000)) - require.Equal(t, uint32(0), mcpy.GetUint32(0xAABBCCDD_8000)) require.Equal(t, m.MerkleRoot(), mcpy.MerkleRoot()) } diff --git a/cannon/mipsevm/memory/memory_test.go b/cannon/mipsevm/memory/memory_test.go index 48e6b1d011043..5100de5b41596 100644 --- a/cannon/mipsevm/memory/memory_test.go +++ b/cannon/mipsevm/memory/memory_test.go @@ -12,6 +12,7 @@ import ( "strings" "testing" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" "github.com/stretchr/testify/require" ) @@ -125,7 +126,6 @@ func TestMemoryReadWrite(t *testing.T) { v := m.GetWord(i) expected := binary.BigEndian.Uint32(data[i : i+4]) require.Equalf(t, expected, v, "read at %d", i) - require.Equalf(t, expected, m.GetUint32(i), "read at %d", i) } }) @@ -140,14 +140,56 @@ func TestMemoryReadWrite(t *testing.T) { require.Equal(t, make([]byte, 10), res[len(res)-10:], "empty end") }) + t.Run("empty range", func(t *testing.T) { + m := NewMemory() + addr := Word(0xAABBCC00) + r := bytes.NewReader(nil) + pre := m.MerkleRoot() + preJSON, err := m.MarshalJSON() + require.NoError(t, err) + var preSerialized bytes.Buffer + require.NoError(t, m.Serialize(&preSerialized)) + + require.NoError(t, m.SetMemoryRange(addr, r)) + v := m.GetWord(0) + require.Equal(t, Word(0), v) + post := m.MerkleRoot() + require.Equal(t, pre, post) + + // Assert that there are no extra zero pages in serialization + postJSON, err := m.MarshalJSON() + require.NoError(t, err) + require.Equal(t, preJSON, postJSON) + + var postSerialized bytes.Buffer + require.NoError(t, m.Serialize(&postSerialized)) + require.Equal(t, preSerialized.Bytes(), postSerialized.Bytes()) + }) + + t.Run("range page overlap", func(t *testing.T) { + m := NewMemory() + data := bytes.Repeat([]byte{0xAA}, PageAddrSize) + require.NoError(t, m.SetMemoryRange(0, bytes.NewReader(data))) + for i := 0; i < PageAddrSize/arch.WordSizeBytes; i++ { + addr := Word(i * arch.WordSizeBytes) + require.Equal(t, Word(0xAAAAAAAA), m.GetWord(addr)) + } + + data = []byte{0x11, 0x22} + require.NoError(t, m.SetMemoryRange(0, bytes.NewReader(data))) + require.Equal(t, Word(0x1122_AAAA), m.GetWord(0)) + for i := 1; i < PageAddrSize/arch.WordSizeBytes; i++ { + addr := Word(i * arch.WordSizeBytes) + require.Equal(t, Word(0xAAAAAAAA), m.GetWord(addr)) + } + }) + t.Run("read-write", func(t *testing.T) { m := NewMemory() m.SetWord(12, 0xAABBCCDD) require.Equal(t, uint32(0xAABBCCDD), m.GetWord(12)) - require.Equal(t, uint32(0xAABBCCDD), m.GetUint32(12)) m.SetWord(12, 0xAABB1CDD) require.Equal(t, uint32(0xAABB1CDD), m.GetWord(12)) - require.Equal(t, uint32(0xAABB1CDD), m.GetUint32(12)) }) t.Run("unaligned read", func(t *testing.T) { @@ -156,22 +198,16 @@ func TestMemoryReadWrite(t *testing.T) { m.SetWord(16, 0x11223344) require.Panics(t, func() { m.GetWord(13) - m.GetUint32(13) }) require.Panics(t, func() { m.GetWord(14) - m.GetUint32(14) }) require.Panics(t, func() { m.GetWord(15) - m.GetUint32(15) }) require.Equal(t, uint32(0x11223344), m.GetWord(16)) - require.Equal(t, uint32(0x11223344), m.GetUint32(16)) require.Equal(t, uint32(0), m.GetWord(20)) - require.Equal(t, uint32(0), m.GetUint32(20)) require.Equal(t, uint32(0xAABBCCDD), m.GetWord(12)) - require.Equal(t, uint32(0xAABBCCDD), m.GetUint32(12)) }) t.Run("unaligned write", func(t *testing.T) { @@ -187,7 +223,6 @@ func TestMemoryReadWrite(t *testing.T) { m.SetWord(15, 0x11223344) }) require.Equal(t, uint32(0xAABBCCDD), m.GetWord(12)) - require.Equal(t, uint32(0xAABBCCDD), m.GetUint32(12)) }) } @@ -199,7 +234,6 @@ func TestMemoryJSON(t *testing.T) { var res Memory require.NoError(t, json.Unmarshal(dat, &res)) require.Equal(t, uint32(0xAABBCCDD), res.GetWord(8)) - require.Equal(t, uint32(0xAABBCCDD), res.GetUint32(8)) } func TestMemoryCopy(t *testing.T) { @@ -207,6 +241,5 @@ func TestMemoryCopy(t *testing.T) { m.SetWord(0x8000, 123) mcpy := m.Copy() require.Equal(t, Word(123), mcpy.GetWord(0x8000)) - require.Equal(t, Word(123), mcpy.GetUint32(0x8000)) require.Equal(t, m.MerkleRoot(), mcpy.MerkleRoot()) } diff --git a/cannon/mipsevm/multithreaded/instrumented_test.go b/cannon/mipsevm/multithreaded/instrumented_test.go index dd4635668458b..6c8fade9ff537 100644 --- a/cannon/mipsevm/multithreaded/instrumented_test.go +++ b/cannon/mipsevm/multithreaded/instrumented_test.go @@ -11,11 +11,12 @@ import ( "github.com/ethereum-optimism/optimism/cannon/mipsevm" "github.com/ethereum-optimism/optimism/cannon/mipsevm/memory" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/program" "github.com/ethereum-optimism/optimism/cannon/mipsevm/testutil" ) -func vmFactory(state *State, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger) mipsevm.FPVM { - return NewInstrumentedState(state, po, stdOut, stdErr, log, nil) +func vmFactory(state *State, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger, meta *program.Metadata) mipsevm.FPVM { + return NewInstrumentedState(state, po, stdOut, stdErr, log, meta) } func TestInstrumentedState_OpenMips(t *testing.T) { @@ -35,27 +36,90 @@ func TestInstrumentedState_Claim(t *testing.T) { func TestInstrumentedState_MultithreadedProgram(t *testing.T) { t.Parallel() - state, _ := testutil.LoadELFProgram(t, "../../testdata/example/bin/multithreaded.elf", CreateInitialState, false) - oracle := testutil.StaticOracle(t, []byte{}) - - var stdOutBuf, stdErrBuf bytes.Buffer - us := NewInstrumentedState(state, oracle, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr), testutil.CreateLogger(), nil) - for i := 0; i < 2_000_000; i++ { - if us.GetState().GetExited() { - break - } - _, err := us.Step(false) - require.NoError(t, err) + cases := []struct { + name string + expectedOutput []string + programName string + }{ + { + name: "wg and chan test", + expectedOutput: []string{ + "waitgroup result: 42", + "channels result: 1234", + }, + programName: "mt-wg", + }, + { + name: "mutex test", + expectedOutput: []string{ + "Mutex test passed", + }, + programName: "mt-mutex", + }, + { + name: "cond test", + expectedOutput: []string{ + "Cond test passed", + }, + programName: "mt-cond", + }, + { + name: "rwmutex test", + expectedOutput: []string{ + "RWMutex test passed", + }, + programName: "mt-rwmutex", + }, + { + name: "once test", + expectedOutput: []string{ + "Once test passed", + }, + programName: "mt-once", + }, + { + name: "map test", + expectedOutput: []string{ + "Map test passed", + }, + programName: "mt-map", + }, + { + name: "pool test", + expectedOutput: []string{ + "Pool test passed", + }, + programName: "mt-pool", + }, } - t.Logf("Completed in %d steps", state.Step) - require.True(t, state.Exited, "must complete program") - require.Equal(t, uint8(0), state.ExitCode, "exit with 0") - require.Contains(t, "waitgroup result: 42", stdErrBuf.String()) - require.Contains(t, "channels result: 1234", stdErrBuf.String()) - require.Equal(t, "", stdErrBuf.String(), "should not print any errors") -} + for _, test := range cases { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + state, _ := testutil.LoadELFProgram(t, testutil.ProgramPath(test.programName), CreateInitialState, false) + oracle := testutil.StaticOracle(t, []byte{}) + var stdOutBuf, stdErrBuf bytes.Buffer + us := NewInstrumentedState(state, oracle, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr), testutil.CreateLogger(), nil) + for i := 0; i < 5_000_000; i++ { + if us.GetState().GetExited() { + break + } + _, err := us.Step(false) + require.NoError(t, err) + } + t.Logf("Completed in %d steps", state.Step) + + require.True(t, state.Exited, "must complete program") + require.Equal(t, uint8(0), state.ExitCode, "exit with 0") + for _, expected := range test.expectedOutput { + require.Contains(t, stdOutBuf.String(), expected) + } + require.Equal(t, "", stdErrBuf.String(), "should not print any errors") + }) + } +} func TestInstrumentedState_Alloc(t *testing.T) { if os.Getenv("SKIP_SLOW_TESTS") == "true" { t.Skip("Skipping slow test because SKIP_SLOW_TESTS is enabled") @@ -78,7 +142,7 @@ func TestInstrumentedState_Alloc(t *testing.T) { test := test t.Run(test.name, func(t *testing.T) { t.Parallel() - state, meta := testutil.LoadELFProgram(t, "../../testdata/example/bin/alloc.elf", CreateInitialState, false) + state, meta := testutil.LoadELFProgram(t, testutil.ProgramPath("alloc"), CreateInitialState, false) oracle := testutil.AllocOracle(t, test.numAllocs, test.allocSize) us := NewInstrumentedState(state, oracle, os.Stdout, os.Stderr, testutil.CreateLogger(), meta) diff --git a/cannon/mipsevm/multithreaded/mips.go b/cannon/mipsevm/multithreaded/mips.go index cddf9fd590f13..b537953a31e61 100644 --- a/cannon/mipsevm/multithreaded/mips.go +++ b/cannon/mipsevm/multithreaded/mips.go @@ -168,9 +168,9 @@ func (m *InstrumentedState) handleSyscall() error { m.memoryTracker.TrackMemAccess(effAddr) m.state.Memory.SetWord(effAddr, secs) m.handleMemoryUpdate(effAddr) - m.memoryTracker.TrackMemAccess2(effAddr + 4) - m.state.Memory.SetWord(effAddr+4, nsecs) - m.handleMemoryUpdate(effAddr + 4) + m.memoryTracker.TrackMemAccess2(effAddr + arch.WordSizeBytes) + m.state.Memory.SetWord(effAddr+arch.WordSizeBytes, nsecs) + m.handleMemoryUpdate(effAddr + arch.WordSizeBytes) default: v0 = exec.SysErrorSignal v1 = exec.MipsEINVAL @@ -187,6 +187,7 @@ func (m *InstrumentedState) handleSyscall() error { case arch.SysPrlimit64: case arch.SysClose: case arch.SysPread64: + case arch.SysStat: case arch.SysFstat: case arch.SysOpenAt: case arch.SysReadlink: @@ -206,6 +207,8 @@ func (m *InstrumentedState) handleSyscall() error { case arch.SysTimerCreate: case arch.SysTimerSetTime: case arch.SysTimerDelete: + case arch.SysGetRLimit: + case arch.SysLseek: default: // These syscalls have the same values on 64-bit. So we use if-stmts here to avoid "duplicate case" compiler error for the cannon64 build if arch.IsMips32 && syscallNum == arch.SysFstat64 || syscallNum == arch.SysStat64 || syscallNum == arch.SysLlseek { @@ -221,6 +224,23 @@ func (m *InstrumentedState) handleSyscall() error { } func (m *InstrumentedState) mipsStep() error { + err := m.doMipsStep() + if err != nil { + return err + } + + m.assertPostStateChecks() + return err +} + +func (m *InstrumentedState) assertPostStateChecks() { + activeStack := m.state.getActiveThreadStack() + if len(activeStack) == 0 { + panic("post-state active thread stack is empty") + } +} + +func (m *InstrumentedState) doMipsStep() error { if m.state.Exited { return nil } @@ -313,19 +333,19 @@ func (m *InstrumentedState) mipsStep() error { } // Exec the rest of the step logic - memUpdated, memAddr, err := exec.ExecMipsCoreStepLogic(m.state.getCpuRef(), m.state.GetRegistersRef(), m.state.Memory, insn, opcode, fun, m.memoryTracker, m.stackTracker) + memUpdated, effMemAddr, err := exec.ExecMipsCoreStepLogic(m.state.getCpuRef(), m.state.GetRegistersRef(), m.state.Memory, insn, opcode, fun, m.memoryTracker, m.stackTracker) if err != nil { return err } if memUpdated { - m.handleMemoryUpdate(memAddr) + m.handleMemoryUpdate(effMemAddr) } return nil } -func (m *InstrumentedState) handleMemoryUpdate(memAddr Word) { - if memAddr == (arch.AddressMask & m.state.LLAddress) { +func (m *InstrumentedState) handleMemoryUpdate(effMemAddr Word) { + if effMemAddr == (arch.AddressMask & m.state.LLAddress) { // Reserved address was modified, clear the reservation m.clearLLMemoryReservation() } diff --git a/cannon/mipsevm/multithreaded/state_test.go b/cannon/mipsevm/multithreaded/state_test.go index 3f8954c636256..a4ed646b5325b 100644 --- a/cannon/mipsevm/multithreaded/state_test.go +++ b/cannon/mipsevm/multithreaded/state_test.go @@ -25,6 +25,10 @@ func setWitnessField(witness StateWitness, fieldOffset int, fieldData []byte) { copy(witness[start:end], fieldData) } +func setWitnessWord(witness StateWitness, fieldOffset int, value arch.Word) { + arch.ByteOrderWord.PutWord(witness[fieldOffset:], value) +} + // Run through all permutations of `exited` / `exitCode` and ensure that the // correct witness, state hash, and VM Status is produced. func TestState_EncodeWitness(t *testing.T) { @@ -70,27 +74,27 @@ func TestState_EncodeWitness(t *testing.T) { expectedWitness := make(StateWitness, STATE_WITNESS_SIZE) setWitnessField(expectedWitness, MEMROOT_WITNESS_OFFSET, memRoot[:]) setWitnessField(expectedWitness, PREIMAGE_KEY_WITNESS_OFFSET, preimageKey[:]) - setWitnessField(expectedWitness, PREIMAGE_OFFSET_WITNESS_OFFSET, []byte{0, 0, 0, byte(preimageOffset)}) - setWitnessField(expectedWitness, HEAP_WITNESS_OFFSET, []byte{0, 0, 0, byte(heap)}) + setWitnessWord(expectedWitness, PREIMAGE_OFFSET_WITNESS_OFFSET, preimageOffset) + setWitnessWord(expectedWitness, HEAP_WITNESS_OFFSET, heap) setWitnessField(expectedWitness, LL_RESERVATION_ACTIVE_OFFSET, []byte{1}) - setWitnessField(expectedWitness, LL_ADDRESS_OFFSET, []byte{0, 0, 0, byte(llAddress)}) - setWitnessField(expectedWitness, LL_OWNER_THREAD_OFFSET, []byte{0, 0, 0, byte(llThreadOwner)}) + setWitnessWord(expectedWitness, LL_ADDRESS_OFFSET, llAddress) + setWitnessWord(expectedWitness, LL_OWNER_THREAD_OFFSET, llThreadOwner) setWitnessField(expectedWitness, EXITCODE_WITNESS_OFFSET, []byte{c.exitCode}) if c.exited { setWitnessField(expectedWitness, EXITED_WITNESS_OFFSET, []byte{1}) } setWitnessField(expectedWitness, STEP_WITNESS_OFFSET, []byte{0, 0, 0, 0, 0, 0, 0, byte(step)}) setWitnessField(expectedWitness, STEPS_SINCE_CONTEXT_SWITCH_WITNESS_OFFSET, []byte{0, 0, 0, 0, 0, 0, 0, byte(stepsSinceContextSwitch)}) - setWitnessField(expectedWitness, WAKEUP_WITNESS_OFFSET, []byte{0xFF, 0xFF, 0xFF, 0xFF}) + setWitnessWord(expectedWitness, WAKEUP_WITNESS_OFFSET, ^arch.Word(0)) setWitnessField(expectedWitness, TRAVERSE_RIGHT_WITNESS_OFFSET, []byte{0}) setWitnessField(expectedWitness, LEFT_THREADS_ROOT_WITNESS_OFFSET, leftStackRoot[:]) setWitnessField(expectedWitness, RIGHT_THREADS_ROOT_WITNESS_OFFSET, rightStackRoot[:]) - setWitnessField(expectedWitness, THREAD_ID_WITNESS_OFFSET, []byte{0, 0, 0, 1}) + setWitnessWord(expectedWitness, THREAD_ID_WITNESS_OFFSET, 1) // Validate witness actualWitness, actualStateHash := state.EncodeWitness() require.Equal(t, len(actualWitness), STATE_WITNESS_SIZE, "Incorrect witness size") - require.EqualValues(t, expectedWitness[:], actualWitness[:], "Incorrect witness") + require.EqualValues(t, expectedWitness[:], actualWitness[:], "Incorrect witness: \n\tactual = \t0x%x \n\texpected = \t0x%x", actualWitness, expectedWitness) // Validate witness hash expectedStateHash := crypto.Keccak256Hash(actualWitness) expectedStateHash[0] = mipsevm.VmStatus(c.exited, c.exitCode) diff --git a/cannon/mipsevm/multithreaded/testutil/expectations.go b/cannon/mipsevm/multithreaded/testutil/expectations.go index 113a2253aa897..16971d347cb08 100644 --- a/cannon/mipsevm/multithreaded/testutil/expectations.go +++ b/cannon/mipsevm/multithreaded/testutil/expectations.go @@ -138,12 +138,6 @@ func (e *ExpectedMTState) ExpectMemoryWordWrite(addr arch.Word, val arch.Word) { e.MemoryRoot = e.expectedMemory.MerkleRoot() } -func (e *ExpectedMTState) ExpectMemoryWriteMultiple(addr arch.Word, val uint32, addr2 arch.Word, val2 uint32) { - e.expectedMemory.SetUint32(addr, val) - e.expectedMemory.SetUint32(addr2, val2) - e.MemoryRoot = e.expectedMemory.MerkleRoot() -} - func (e *ExpectedMTState) ExpectPreemption(preState *multithreaded.State) { e.ActiveThreadId = FindNextThread(preState).ThreadId e.StepsSinceLastContextSwitch = 0 diff --git a/cannon/mipsevm/program/load.go b/cannon/mipsevm/program/load.go index 3cbba07d2bcda..23a1c67b15475 100644 --- a/cannon/mipsevm/program/load.go +++ b/cannon/mipsevm/program/load.go @@ -25,7 +25,7 @@ func LoadELF[T mipsevm.FPVMState](f *elf.File, initState CreateInitialFPVMState[ s := initState(Word(f.Entry), HEAP_START) for i, prog := range f.Progs { - if prog.Type == 0x70000003 { // MIPS_ABIFLAGS + if prog.Type == elf.PT_MIPS_ABIFLAGS { continue } @@ -42,12 +42,27 @@ func LoadELF[T mipsevm.FPVMState](f *elf.File, initState CreateInitialFPVMState[ } } - // TODO(#12205) - if prog.Vaddr+prog.Memsz >= uint64(1<<32) { - return empty, fmt.Errorf("program %d out of 32-bit mem range: %x - %x (size: %x)", i, prog.Vaddr, prog.Vaddr+prog.Memsz, prog.Memsz) + if prog.Memsz == 0 { + // Nothing to do + continue + } + + // Calculate the architecture-specific last valid memory address + var lastMemoryAddr uint64 + if arch.IsMips32 { + // 32-bit virtual address space + lastMemoryAddr = (1 << 32) - 1 + } else { + // 48-bit virtual address space + lastMemoryAddr = (1 << 48) - 1 + } + + lastByteToWrite := prog.Vaddr + prog.Memsz - 1 + if lastByteToWrite > lastMemoryAddr || lastByteToWrite < prog.Vaddr { + return empty, fmt.Errorf("program %d out of memory range: %x - %x (size: %x)", i, prog.Vaddr, lastByteToWrite, prog.Memsz) } - if prog.Vaddr+prog.Memsz >= HEAP_START { - return empty, fmt.Errorf("program %d overlaps with heap: %x - %x (size: %x). The heap start offset must be reconfigured", i, prog.Vaddr, prog.Vaddr+prog.Memsz, prog.Memsz) + if lastByteToWrite >= HEAP_START { + return empty, fmt.Errorf("program %d overlaps with heap: %x - %x (size: %x). The heap start offset must be reconfigured", i, prog.Vaddr, lastByteToWrite, prog.Memsz) } if err := s.GetMemory().SetMemoryRange(Word(prog.Vaddr), r); err != nil { return empty, fmt.Errorf("failed to read program segment %d: %w", i, err) diff --git a/cannon/mipsevm/program/load_test.go b/cannon/mipsevm/program/load_test.go new file mode 100644 index 0000000000000..32660a7f655cc --- /dev/null +++ b/cannon/mipsevm/program/load_test.go @@ -0,0 +1,83 @@ +package program + +import ( + "debug/elf" + "io" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/program/testutil" +) + +func TestLoadELF(t *testing.T) { + data := []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88} + dataSize := uint64(len(data)) + lastValidAddr := uint64(HEAP_START - 1) + lastAddr := uint64(^uint32(0)) + if !arch.IsMips32 { + lastAddr = (1 << 48) - 1 + } + + tests := []struct { + name string + progType elf.ProgType + memSize uint64 + fileSize uint64 + vAddr uint64 + expectedErr string + shouldIgnore bool + }{ + {name: "Zero length segment", progType: elf.PT_LOAD, fileSize: 0, memSize: 0, vAddr: 0}, + {name: "Zero length segment, non-zero fileSize", progType: elf.PT_LOAD, fileSize: 2, memSize: 0, vAddr: 0, expectedErr: "file size (2) > mem size (0)"}, + {name: "Loadable segment, fileSize > memSize", progType: elf.PT_LOAD, fileSize: dataSize * 2, memSize: dataSize, vAddr: 0x4000, expectedErr: "file size (16) > mem size (8)"}, + {name: "Loadable segment, fileSize < memSize", progType: elf.PT_LOAD, fileSize: dataSize, memSize: dataSize * 2, vAddr: 0x4000}, + {name: "Loadable segment, fileSize == memSize", progType: elf.PT_LOAD, fileSize: dataSize, memSize: dataSize, vAddr: 0x4000}, + {name: "Loadable segment, segment out-of-range", progType: elf.PT_LOAD, fileSize: dataSize, memSize: dataSize, vAddr: lastAddr - 1, expectedErr: "out of memory range"}, + {name: "Loadable segment, segment just out-of-range", progType: elf.PT_LOAD, fileSize: dataSize, memSize: dataSize, vAddr: lastAddr - dataSize + 2, expectedErr: "out of memory range"}, + {name: "Loadable segment, segment just in-range", progType: elf.PT_LOAD, fileSize: dataSize, memSize: dataSize, vAddr: lastAddr - dataSize + 1, expectedErr: "overlaps with heap"}, + {name: "Loadable segment, segment overlaps heap", progType: elf.PT_LOAD, fileSize: dataSize, memSize: dataSize, vAddr: lastValidAddr - 1, expectedErr: "overlaps with heap"}, + {name: "Loadable segment, segment just overlaps heap", progType: elf.PT_LOAD, fileSize: dataSize, memSize: dataSize, vAddr: lastValidAddr - dataSize + 2, expectedErr: "overlaps with heap"}, + {name: "Loadable segment, segment ends just before heap", progType: elf.PT_LOAD, fileSize: dataSize, memSize: dataSize, vAddr: lastValidAddr - dataSize + 1}, + {name: "MIPS Flags segment, invalid file size", progType: elf.PT_MIPS_ABIFLAGS, fileSize: dataSize * 2, memSize: dataSize, vAddr: 0x4000, shouldIgnore: true}, + {name: "MIPS Flags segment, out-of-range", progType: elf.PT_MIPS_ABIFLAGS, fileSize: dataSize, memSize: dataSize, vAddr: lastAddr, shouldIgnore: true}, + {name: "MIPS Flags segment, overlaps heap", progType: elf.PT_MIPS_ABIFLAGS, fileSize: dataSize, memSize: dataSize, vAddr: lastValidAddr, shouldIgnore: true}, + {name: "Other segment, fileSize > memSize", progType: elf.PT_DYNAMIC, fileSize: dataSize * 2, memSize: dataSize, vAddr: 0x4000, expectedErr: "filling for non PT_LOAD segments is not supported"}, + {name: "Other segment, memSize > fileSize", progType: elf.PT_DYNAMIC, fileSize: dataSize, memSize: dataSize * 2, vAddr: 0x4000, expectedErr: "filling for non PT_LOAD segments is not supported"}, + {name: "Other segment, out-of-range", progType: elf.PT_DYNAMIC, fileSize: dataSize, memSize: dataSize, vAddr: lastAddr, expectedErr: "out of memory range"}, + {name: "Other segment, overlaps heap", progType: elf.PT_DYNAMIC, fileSize: dataSize, memSize: dataSize, vAddr: lastValidAddr, expectedErr: "overlaps with heap"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + prog, reader := testutil.MockProgWithReader(tt.progType, tt.fileSize, tt.memSize, tt.vAddr, data) + progs := []*elf.Prog{prog} + mockFile := testutil.MockELFFile(progs) + state, err := LoadELF(mockFile, testutil.MockCreateInitState) + + if tt.expectedErr != "" { + require.Error(t, err) + require.Contains(t, err.Error(), tt.expectedErr) + } else { + require.NoError(t, err) + + if tt.shouldIgnore { + // No data should be read + require.Equal(t, reader.BytesRead, 0) + } else { + // Set up memory validation data + expectedData := make([]byte, tt.memSize) + copy(expectedData, data[:]) + memReader := state.GetMemory().ReadMemoryRange(arch.Word(tt.vAddr), arch.Word(tt.memSize)) + actualData, err := io.ReadAll(memReader) + require.NoError(t, err) + + // Validate data was read into memory + require.Equal(t, reader.BytesRead, int(tt.fileSize)) + require.Equal(t, actualData, expectedData) + } + } + }) + } +} diff --git a/cannon/mipsevm/program/testutil/mocks.go b/cannon/mipsevm/program/testutil/mocks.go new file mode 100644 index 0000000000000..484527710aa52 --- /dev/null +++ b/cannon/mipsevm/program/testutil/mocks.go @@ -0,0 +1,130 @@ +package testutil + +import ( + "debug/elf" + "io" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/log" + + "github.com/ethereum-optimism/optimism/cannon/mipsevm" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/memory" +) + +// MockELFFile create a mock ELF file with custom program segments +func MockELFFile(progs []*elf.Prog) *elf.File { + return &elf.File{Progs: progs} +} + +// MockProg sets up a elf.Prog structure for testing +func MockProg(progType elf.ProgType, filesz, memsz, vaddr uint64) *elf.Prog { + return &elf.Prog{ + ProgHeader: elf.ProgHeader{ + Type: progType, + Filesz: filesz, + Memsz: memsz, + Vaddr: vaddr, + }, + } +} + +// MockProgWithReader creates an elf.Prog with a TrackableReaderAt to track reads +func MockProgWithReader(progType elf.ProgType, filesz, memsz, vaddr uint64, data []byte) (*elf.Prog, *TrackableReaderAt) { + reader := &TrackableReaderAt{data: data} + prog := MockProg(progType, filesz, memsz, vaddr) + prog.ReaderAt = io.NewSectionReader(reader, 0, int64(filesz)) + return prog, reader +} + +// TrackableReaderAt tracks the number of bytes read +type TrackableReaderAt struct { + data []byte + BytesRead int +} + +func (r *TrackableReaderAt) ReadAt(p []byte, offset int64) (int, error) { + if offset >= int64(len(r.data)) { + return 0, io.EOF + } + numBytesRead := copy(p, r.data[offset:]) + r.BytesRead += numBytesRead + if numBytesRead < len(p) { + return numBytesRead, io.EOF + } + return numBytesRead, nil +} + +// MockCreateInitState returns a mock FPVMState for testing +func MockCreateInitState(pc, heapStart arch.Word) *MockFPVMState { + return newMockFPVMState() +} + +type MockFPVMState struct { + memory *memory.Memory +} + +var _ mipsevm.FPVMState = (*MockFPVMState)(nil) + +func newMockFPVMState() *MockFPVMState { + mem := memory.NewMemory() + state := MockFPVMState{mem} + return &state +} + +func (m MockFPVMState) Serialize(out io.Writer) error { + panic("not implemented") +} + +func (m MockFPVMState) GetMemory() *memory.Memory { + return m.memory +} + +func (m MockFPVMState) GetHeap() arch.Word { + panic("not implemented") +} + +func (m MockFPVMState) GetPreimageKey() common.Hash { + panic("not implemented") +} + +func (m MockFPVMState) GetPreimageOffset() arch.Word { + panic("not implemented") +} + +func (m MockFPVMState) GetPC() arch.Word { + panic("not implemented") +} + +func (m MockFPVMState) GetCpu() mipsevm.CpuScalars { + panic("not implemented") +} + +func (m MockFPVMState) GetRegistersRef() *[32]arch.Word { + panic("not implemented") +} + +func (m MockFPVMState) GetStep() uint64 { + panic("not implemented") +} + +func (m MockFPVMState) GetExited() bool { + panic("not implemented") +} + +func (m MockFPVMState) GetExitCode() uint8 { + panic("not implemented") +} + +func (m MockFPVMState) GetLastHint() hexutil.Bytes { + panic("not implemented") +} + +func (m MockFPVMState) EncodeWitness() (witness []byte, hash common.Hash) { + panic("not implemented") +} + +func (m MockFPVMState) CreateVM(logger log.Logger, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, meta mipsevm.Metadata) mipsevm.FPVM { + panic("not implemented") +} diff --git a/cannon/mipsevm/singlethreaded/instrumented_test.go b/cannon/mipsevm/singlethreaded/instrumented_test.go index 8b4c61bd4e148..f1dfc8fae4dbe 100644 --- a/cannon/mipsevm/singlethreaded/instrumented_test.go +++ b/cannon/mipsevm/singlethreaded/instrumented_test.go @@ -1,3 +1,6 @@ +//go:build !cannon64 +// +build !cannon64 + package singlethreaded import ( @@ -7,10 +10,11 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/cannon/mipsevm" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/program" "github.com/ethereum-optimism/optimism/cannon/mipsevm/testutil" ) -func vmFactory(state *State, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger) mipsevm.FPVM { +func vmFactory(state *State, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger, meta *program.Metadata) mipsevm.FPVM { return NewInstrumentedState(state, po, stdOut, stdErr, nil) } diff --git a/cannon/mipsevm/singlethreaded/state_test.go b/cannon/mipsevm/singlethreaded/state_test.go index e0639c3dbeece..bfab4dd279885 100644 --- a/cannon/mipsevm/singlethreaded/state_test.go +++ b/cannon/mipsevm/singlethreaded/state_test.go @@ -1,3 +1,6 @@ +//go:build !cannon64 +// +build !cannon64 + package singlethreaded import ( diff --git a/cannon/mipsevm/tests/evm_common64_test.go b/cannon/mipsevm/tests/evm_common64_test.go new file mode 100644 index 0000000000000..ce12538867422 --- /dev/null +++ b/cannon/mipsevm/tests/evm_common64_test.go @@ -0,0 +1,507 @@ +//go:build cannon64 +// +build cannon64 + +package tests + +import ( + "fmt" + "os" + "testing" + + "github.com/ethereum-optimism/optimism/cannon/mipsevm/testutil" + "github.com/stretchr/testify/require" +) + +func TestEVM_SingleStep_Operators64(t *testing.T) { + cases := []operatorTestCase{ + {name: "dadd. both unsigned 32", funct: 0x2c, isImm: false, rs: Word(0x12), rt: Word(0x20), expectRes: Word(0x32)}, // dadd t0, s1, s2 + {name: "dadd. unsigned 32 and signed", funct: 0x2c, isImm: false, rs: Word(0x12), rt: Word(^uint32(0)), expectRes: Word(0x1_00_00_00_11)}, // dadd t0, s1, s2 + {name: "dadd. signed and unsigned 32", funct: 0x2c, isImm: false, rs: Word(^uint32(0)), rt: Word(0x12), expectRes: Word(0x1_00_00_00_11)}, // dadd t0, s1, s2 + {name: "dadd. unsigned 64 and unsigned 32", funct: 0x2c, isImm: false, rs: Word(0x0FFFFFFF_00000012), rt: Word(0x20), expectRes: Word(0x0FFFFFFF_00000032)}, // dadd t0, s1, s2 + {name: "dadd. unsigned 32 and signed", funct: 0x2c, isImm: false, rs: Word(12), rt: ^Word(0), expectRes: Word(11)}, // dadd t0, s1, s2 + {name: "dadd. signed and unsigned 32", funct: 0x2c, isImm: false, rs: ^Word(0), rt: Word(12), expectRes: Word(11)}, // dadd t0, s1, s2 + {name: "dadd. signed and unsigned 32. expect signed", funct: 0x2c, isImm: false, rs: ^Word(20), rt: Word(4), expectRes: ^Word(16)}, // dadd t0, s1, s2 + {name: "dadd. unsigned 32 and signed. expect signed", funct: 0x2c, isImm: false, rs: Word(4), rt: ^Word(20), expectRes: ^Word(16)}, // dadd t0, s1, s2 + {name: "dadd. both signed", funct: 0x2c, isImm: false, rs: ^Word(10), rt: ^Word(4), expectRes: ^Word(15)}, // dadd t0, s1, s2 + {name: "dadd. signed and unsigned 64. expect unsigned", funct: 0x2c, isImm: false, rs: ^Word(0), rt: Word(0x000000FF_00000000), expectRes: Word(0x000000FE_FFFFFFFF)}, // dadd t0, s1, s2 + {name: "dadd. signed and unsigned 64. expect signed", funct: 0x2c, isImm: false, rs: Word(0x80000000_00000000), rt: Word(0x40000000_00000000), expectRes: Word(0xC000000000000000)}, // dadd t0, s1, s2 + + {name: "daddu. both 32", funct: 0x2d, isImm: false, rs: Word(0x12), rt: Word(0x20), expectRes: Word(0x32)}, // daddu t0, s1, s2 + {name: "daddu. 32-bit. expect doubleword-sized", funct: 0x2d, isImm: false, rs: Word(0x12), rt: Word(^uint32(0)), expectRes: Word(0x1_00_00_00_11)}, // daddu t0, s1, s2 + {name: "daddu. 32-bit. expect double-word sized x", funct: 0x2d, isImm: false, rs: Word(^uint32(0)), rt: Word(0x12), expectRes: Word(0x1_00_00_00_11)}, // dadu t0, s1, s2 + {name: "daddu. doubleword-sized, word-sized", funct: 0x2d, isImm: false, rs: Word(0x0FFFFFFF_00000012), rt: Word(0x20), expectRes: Word(0x0FFFFFFF_00000032)}, // dadu t0, s1, s2 + {name: "daddu. overflow. rt sign bit set", funct: 0x2d, isImm: false, rs: Word(12), rt: ^Word(0), expectRes: Word(11)}, // dadu t0, s1, s2 + {name: "daddu. overflow. rs sign bit set", funct: 0x2d, isImm: false, rs: ^Word(0), rt: Word(12), expectRes: Word(11)}, // dadu t0, s1, s2 + {name: "daddu. doubleword-sized and word-sized", funct: 0x2d, isImm: false, rs: ^Word(20), rt: Word(4), expectRes: ^Word(16)}, // dadu t0, s1, s2 + {name: "daddu. word-sized and doubleword-sized", funct: 0x2d, isImm: false, rs: Word(4), rt: ^Word(20), expectRes: ^Word(16)}, // dadu t0, s1, s2 + {name: "daddu. both doubleword-sized. expect overflow", funct: 0x2d, isImm: false, rs: ^Word(10), rt: ^Word(4), expectRes: ^Word(15)}, // dadu t0, s1, s2 + + {name: "daddi word-sized", opcode: 0x18, isImm: true, rs: Word(12), rt: ^Word(0), imm: uint16(20), expectRes: Word(32)}, // daddi t0, s1, s2 + {name: "daddi doubleword-sized", opcode: 0x18, isImm: true, rs: Word(0x00000010_00000000), rt: ^Word(0), imm: uint16(0x20), expectRes: Word(0x00000010_00000020)}, // daddi t0, s1, s2 + {name: "daddi 32-bit sign", opcode: 0x18, isImm: true, rs: Word(0xFF_FF_FF_FF), rt: ^Word(0), imm: uint16(0x20), expectRes: Word(0x01_00_00_00_1F)}, // daddi t0, s1, s2 + {name: "daddi double-word signed", opcode: 0x18, isImm: true, rs: ^Word(0), rt: ^Word(0), imm: uint16(0x20), expectRes: Word(0x1F)}, // daddi t0, s1, s2 + {name: "daddi double-word signed. expect signed", opcode: 0x18, isImm: true, rs: ^Word(0x10), rt: ^Word(0), imm: uint16(0x1), expectRes: ^Word(0xF)}, // daddi t0, s1, s2 + + {name: "daddiu word-sized", opcode: 0x19, isImm: true, rs: Word(4), rt: ^Word(0), imm: uint16(40), expectRes: Word(44)}, // daddiu t0, s1, 40 + {name: "daddiu doubleword-sized", opcode: 0x19, isImm: true, rs: Word(0x00000010_00000000), rt: ^Word(0), imm: uint16(0x20), expectRes: Word(0x00000010_00000020)}, // daddiu t0, s1, 40 + {name: "daddiu 32-bit sign", opcode: 0x19, isImm: true, rs: Word(0xFF_FF_FF_FF), rt: ^Word(0), imm: uint16(0x20), expectRes: Word(0x01_00_00_00_1F)}, // daddiu t0, s1, 40 + {name: "daddiu overflow", opcode: 0x19, isImm: true, rs: ^Word(0), rt: ^Word(0), imm: uint16(0x20), expectRes: Word(0x1F)}, // daddiu t0, s1, s2 + + {name: "dsub. both unsigned 32", funct: 0x2e, isImm: false, rs: Word(0x12), rt: Word(0x1), expectRes: Word(0x11)}, // dsub t0, s1, s2 + {name: "dsub. signed and unsigned 32", funct: 0x2e, isImm: false, rs: ^Word(1), rt: Word(0x1), expectRes: Word(^uint64(2))}, // dsub t0, s1, s2 + {name: "dsub. signed and unsigned 64", funct: 0x2e, isImm: false, rs: ^Word(1), rt: Word(0x00AABBCC_00000000), expectRes: ^Word(0x00AABBCC_00000001)}, // dsub t0, s1, s2 + {name: "dsub. both signed. unsigned result", funct: 0x2e, isImm: false, rs: ^Word(1), rt: ^Word(2), expectRes: Word(1)}, // dsub t0, s1, s2 + {name: "dsub. both signed. signed result", funct: 0x2e, isImm: false, rs: ^Word(2), rt: ^Word(1), expectRes: ^Word(0)}, // dsub t0, s1, s2 + {name: "dsub. signed and zero", funct: 0x2e, isImm: false, rs: ^Word(0), rt: Word(0), expectRes: ^Word(0)}, // dsub t0, s1, s2 + + {name: "dsubu. both unsigned 32", funct: 0x2f, isImm: false, rs: Word(0x12), rt: Word(0x1), expectRes: Word(0x11)}, // dsubu t0, s1, s2 + {name: "dsubu. signed and unsigned 32", funct: 0x2f, isImm: false, rs: ^Word(1), rt: Word(0x1), expectRes: Word(^uint64(2))}, // dsubu t0, s1, s2 + {name: "dsubu. signed and unsigned 64", funct: 0x2f, isImm: false, rs: ^Word(1), rt: Word(0x00AABBCC_00000000), expectRes: ^Word(0x00AABBCC_00000001)}, // dsubu t0, s1, s2 + {name: "dsubu. both signed. unsigned result", funct: 0x2f, isImm: false, rs: ^Word(1), rt: ^Word(2), expectRes: Word(1)}, // dsubu t0, s1, s2 + {name: "dsubu. both signed. signed result", funct: 0x2f, isImm: false, rs: ^Word(2), rt: ^Word(1), expectRes: ^Word(0)}, // dsubu t0, s1, s2 + {name: "dsubu. signed and zero", funct: 0x2f, isImm: false, rs: ^Word(0), rt: Word(0), expectRes: ^Word(0)}, // dsubu t0, s1, s2 + {name: "dsubu. overflow", funct: 0x2f, isImm: false, rs: Word(0x80000000_00000000), rt: Word(0x7FFFFFFF_FFFFFFFF), expectRes: Word(0x00000000_00000001)}, // dsubu t0, s1, s2 + + // dsllv + {name: "dsllv", funct: 0x14, rt: Word(0x20), rs: Word(0), expectRes: Word(0x20)}, + {name: "dsllv", funct: 0x14, rt: Word(0x20), rs: Word(1), expectRes: Word(0x40)}, + {name: "dsllv sign", funct: 0x14, rt: Word(0x80_00_00_00_00_00_00_20), rs: Word(1), expectRes: Word(0x00_00_00_00_00_00_00_40)}, + {name: "dsllv max", funct: 0x14, rt: Word(0xFF_FF_FF_FF_FF_FF_FF_Fe), rs: Word(0x3f), expectRes: Word(0x0)}, + {name: "dsllv max almost clear", funct: 0x14, rt: Word(0x1), rs: Word(0x3f), expectRes: Word(0x80_00_00_00_00_00_00_00)}, + + // dsrlv t0, s1, s2 + {name: "dsrlv", funct: 0x16, rt: Word(0x20), rs: Word(0), expectRes: Word(0x20)}, + {name: "dsrlv", funct: 0x16, rt: Word(0x20), rs: Word(1), expectRes: Word(0x10)}, + {name: "dsrlv sign-extend", funct: 0x16, rt: Word(0x80_00_00_00_00_00_00_20), rs: Word(1), expectRes: Word(0x40_00_00_00_00_00_00_10)}, + {name: "dsrlv max", funct: 0x16, rt: Word(0x7F_FF_00_00_00_00_00_20), rs: Word(0x3f), expectRes: Word(0x0)}, + {name: "dsrlv max sign-extend", funct: 0x16, rt: Word(0x80_00_00_00_00_00_00_20), rs: Word(0x3f), expectRes: Word(0x1)}, + + // dsrav t0, s1, s2 + {name: "dsrav", funct: 0x17, rt: Word(0x20), rs: Word(0), expectRes: Word(0x20)}, + {name: "dsrav", funct: 0x17, rt: Word(0x20), rs: Word(1), expectRes: Word(0x10)}, + {name: "dsrav sign-extend", funct: 0x17, rt: Word(0x80_00_00_00_00_00_00_20), rs: Word(1), expectRes: Word(0xc0_00_00_00_00_00_00_10)}, + {name: "dsrav max", funct: 0x17, rt: Word(0x7F_FF_00_00_00_00_00_20), rs: Word(0x3f), expectRes: Word(0x0)}, + {name: "dsrav max sign-extend", funct: 0x17, rt: Word(0x80_00_00_00_00_00_00_20), rs: Word(0x3f), expectRes: Word(0xFF_FF_FF_FF_FF_FF_FF_FF)}, + } + testOperators(t, cases, false) +} + +func TestEVM_SingleStep_Bitwise64(t *testing.T) { + cases := []operatorTestCase{ + {name: "and", funct: 0x24, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(160)}, // and t0, s1, s2 + {name: "andi", opcode: 0xc, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(0)}, // andi t0, s1, 40 + {name: "or", funct: 0x25, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(1530)}, // or t0, s1, s2 + {name: "ori", opcode: 0xd, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(44)}, // ori t0, s1, 40 + {name: "xor", funct: 0x26, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(1370)}, // xor t0, s1, s2 + {name: "xori", opcode: 0xe, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(44)}, // xori t0, s1, 40 + {name: "nor", funct: 0x27, isImm: false, rs: Word(0x4b0), rt: Word(0x1ea), expectRes: Word(0xFF_FF_FF_FF_FF_FF_FA_05)}, // nor t0, s1, s2 + {name: "slt", funct: 0x2a, isImm: false, rs: 0xFF_FF_FF_FE, rt: Word(5), expectRes: Word(0)}, // slt t0, s1, s2 + {name: "slt", funct: 0x2a, isImm: false, rs: 0xFF_FF_FF_FF_FF_FF_FF_FE, rt: Word(5), expectRes: Word(1)}, // slt t0, s1, s2 + {name: "sltu", funct: 0x2b, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(0)}, // sltu t0, s1, s2 + } + testOperators(t, cases, false) +} + +func TestEVM_SingleStep_Shift64(t *testing.T) { + cases := []struct { + name string + rd Word + rt Word + sa uint32 + funct uint32 + expectRes Word + }{ + {name: "dsll", funct: 0x38, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 0, expectRes: Word(0x1)}, // dsll t8, s2, 0 + {name: "dsll", funct: 0x38, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 1, expectRes: Word(0x2)}, // dsll t8, s2, 1 + {name: "dsll", funct: 0x38, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 31, expectRes: Word(0x80_00_00_00)}, // dsll t8, s2, 31 + {name: "dsll", funct: 0x38, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_FF_00_00_00_00), sa: 1, expectRes: Word(0xFF_FF_FF_FE_00_00_00_00)}, // dsll t8, s2, 1 + {name: "dsll", funct: 0x38, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_FF_00_00_00_00), sa: 31, expectRes: Word(0x80_00_00_00_00_00_00_00)}, // dsll t8, s2, 31 + + {name: "dsrl", funct: 0x3a, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 0, expectRes: Word(0x1)}, // dsrl t8, s2, 0 + {name: "dsrl", funct: 0x3a, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 1, expectRes: Word(0x0)}, // dsrl t8, s2, 1 + {name: "dsrl", funct: 0x3a, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_FF_00_00_00_00), sa: 1, expectRes: Word(0x7F_FF_FF_FF_80_00_00_00)}, // dsrl t8, s2, 1 + {name: "dsrl", funct: 0x3a, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_FF_00_00_00_00), sa: 31, expectRes: Word(0x01_FF_FF_FF_FE)}, // dsrl t8, s2, 31 + + {name: "dsra", funct: 0x3b, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 0, expectRes: Word(0x1)}, // dsra t8, s2, 0 + {name: "dsra", funct: 0x3b, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 1, expectRes: Word(0x0)}, // dsra t8, s2, 1 + {name: "dsra", funct: 0x3b, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_FF_00_00_00_00), sa: 1, expectRes: Word(0xFF_FF_FF_FF_80_00_00_00)}, // dsra t8, s2, 1 + {name: "dsra", funct: 0x3b, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_FF_00_00_00_00), sa: 31, expectRes: Word(0xFF_FF_FF_FF_FF_FF_FF_FE)}, // dsra t8, s2, 31 + + {name: "dsll32", funct: 0x3c, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 0, expectRes: Word(0x1_00_00_00_00)}, // dsll32 t8, s2, 0 + {name: "dsll32", funct: 0x3c, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 1, expectRes: Word(0x2_00_00_00_00)}, // dsll32 t8, s2, 1 + {name: "dsll32", funct: 0x3c, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 31, expectRes: Word(0x80_00_00_00_00_00_00_00)}, // dsll32 t8, s2, 31 + {name: "dsll32", funct: 0x3c, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_FF_FF_FF_FF_FF), sa: 1, expectRes: Word(0xFF_FF_FF_FE_00_00_00_00)}, // dsll32 t8, s2, 1 + {name: "dsll32", funct: 0x3c, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_FF_FF_FF_FF_FF), sa: 31, expectRes: Word(0x80_00_00_00_00_00_00_00)}, // dsll32 t8, s2, 31 + + {name: "dsrl32", funct: 0x3e, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 0, expectRes: Word(0x0)}, // dsrl32 t8, s2, 0 + {name: "dsrl32", funct: 0x3e, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 31, expectRes: Word(0x0)}, // dsrl32 t8, s2, 31 + {name: "dsrl32", funct: 0x3e, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_FF_FF_FF_FF_FF), sa: 1, expectRes: Word(0x7F_FF_FF_FF)}, // dsrl32 t8, s2, 1 + {name: "dsrl32", funct: 0x3e, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_FF_FF_FF_FF_FF), sa: 31, expectRes: Word(0x1)}, // dsrl32 t8, s2, 31 + {name: "dsrl32", funct: 0x3e, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1_0000_0000), sa: 0, expectRes: Word(0x1)}, // dsrl32 t8, s2, 0 + {name: "dsrl32", funct: 0x3e, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1_0000_0000), sa: 31, expectRes: Word(0x0)}, // dsrl32 t8, s2, 31 + + {name: "dsra32", funct: 0x3f, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 0, expectRes: Word(0x0)}, // dsra32 t8, s2, 0 + {name: "dsra32", funct: 0x3f, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x1), sa: 1, expectRes: Word(0x0)}, // dsra32 t8, s2, 1 + {name: "dsra32", funct: 0x3f, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_FF), sa: 0, expectRes: Word(0x0)}, // dsra32 t8, s2, 0 + {name: "dsra32", funct: 0x3f, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x01_FF_FF_FF_FF), sa: 0, expectRes: Word(0x1)}, // dsra32 t8, s2, 0 + {name: "dsra32", funct: 0x3f, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_FF_FF_FF_FF_FF), sa: 1, expectRes: Word(0xFF_FF_FF_FF_FF_FF_FF_FF)}, // dsra32 t8, s2, 1 + {name: "dsra32", funct: 0x3f, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0xFF_FF_FF_00_00_00_00_00), sa: 1, expectRes: Word(0xFF_FF_FF_FF_FF_FF_FF_80)}, // dsra32 t8, s2, 1 + {name: "dsra32", funct: 0x3f, rd: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x7F_FF_FF_FF_FF_FF_FF_FF), sa: 31, expectRes: Word(0x0)}, // dsra32 t8, s2, 1 + } + + v := GetMultiThreadedTestCase(t) + for i, tt := range cases { + testName := fmt.Sprintf("%v %v", v.Name, tt.name) + t.Run(testName, func(t *testing.T) { + pc := Word(0x0) + goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPCAndNextPC(pc)) + state := goVm.GetState() + var insn uint32 + var rtReg uint32 + var rdReg uint32 + rtReg = 18 + rdReg = 8 + insn = rtReg<<16 | rdReg<<11 | tt.sa<<6 | tt.funct + state.GetRegistersRef()[rdReg] = tt.rd + state.GetRegistersRef()[rtReg] = tt.rt + testutil.StoreInstruction(state.GetMemory(), pc, insn) + step := state.GetStep() + + // Setup expectations + expected := testutil.NewExpectedState(state) + expected.ExpectStep() + expected.Registers[rdReg] = tt.expectRes + + stepWitness, err := goVm.Step(true) + require.NoError(t, err) + + // Check expectations + expected.Validate(t, state) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) + }) + } +} + +func TestEVM_SingleStep_LoadStore64(t *testing.T) { + t1 := Word(0xFF000000_00000108) + + cases := []loadStoreTestCase{ + {name: "lb 0", opcode: uint32(0x20), memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x71)}, // lb $t0, 0($t1) + {name: "lb 1", opcode: uint32(0x20), imm: 1, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x72)}, // lb $t0, 1($t1) + {name: "lb 2", opcode: uint32(0x20), imm: 2, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x73)}, // lb $t0, 2($t1) + {name: "lb 3", opcode: uint32(0x20), imm: 3, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x74)}, // lb $t0, 3($t1) + {name: "lb 4", opcode: uint32(0x20), imm: 4, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x75)}, // lb $t0, 4($t1) + {name: "lb 5", opcode: uint32(0x20), imm: 5, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x76)}, // lb $t0, 5($t1) + {name: "lb 6", opcode: uint32(0x20), imm: 6, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x77)}, // lb $t0, 6($t1) + {name: "lb 7", opcode: uint32(0x20), imm: 7, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x78)}, // lb $t0, 7($t1) + {name: "lb sign-extended 0", opcode: uint32(0x20), memVal: Word(0x81_72_73_74_75_76_77_78), expectRes: Word(0xFF_FF_FF_FF_FF_FF_FF_81)}, // lb $t0, 0($t1) + {name: "lb sign-extended 1", opcode: uint32(0x20), imm: 1, memVal: Word(0x71_82_73_74_75_76_77_78), expectRes: Word(0xFF_FF_FF_FF_FF_FF_FF_82)}, // lb $t0, 1($t1) + {name: "lb sign-extended 2", opcode: uint32(0x20), imm: 2, memVal: Word(0x71_72_83_74_75_76_77_78), expectRes: Word(0xFF_FF_FF_FF_FF_FF_FF_83)}, // lb $t0, 2($t1) + {name: "lb sign-extended 3", opcode: uint32(0x20), imm: 3, memVal: Word(0x71_72_73_84_75_76_77_78), expectRes: Word(0xFF_FF_FF_FF_FF_FF_FF_84)}, // lb $t0, 3($t1) + {name: "lb sign-extended 4", opcode: uint32(0x20), imm: 4, memVal: Word(0x71_72_73_74_85_76_77_78), expectRes: Word(0xFF_FF_FF_FF_FF_FF_FF_85)}, // lb $t0, 4($t1) + {name: "lb sign-extended 5", opcode: uint32(0x20), imm: 5, memVal: Word(0x71_72_73_74_75_86_77_78), expectRes: Word(0xFF_FF_FF_FF_FF_FF_FF_86)}, // lb $t0, 5($t1) + {name: "lb sign-extended 6", opcode: uint32(0x20), imm: 6, memVal: Word(0x71_72_73_74_75_76_87_78), expectRes: Word(0xFF_FF_FF_FF_FF_FF_FF_87)}, // lb $t0, 6($t1) + {name: "lb sign-extended 7", opcode: uint32(0x20), imm: 7, memVal: Word(0x71_72_73_74_75_76_77_88), expectRes: Word(0xFF_FF_FF_FF_FF_FF_FF_88)}, // lb $t0, 7($t1) + + {name: "lh offset=0", opcode: uint32(0x21), memVal: Word(0x11223344_55667788), expectRes: Word(0x11_22)}, // lhu $t0, 0($t1) + {name: "lh offset=0 sign-extended", opcode: uint32(0x21), memVal: Word(0x81223344_55667788), expectRes: Word(0xFF_FF_FF_FF_FF_FF_81_22)}, // lhu $t0, 0($t1) + {name: "lh offset=2", opcode: uint32(0x21), imm: 2, memVal: Word(0x11223344_55667788), expectRes: Word(0x33_44)}, // lhu $t0, 2($t1) + {name: "lh offset=2 sign-extended", opcode: uint32(0x21), imm: 2, memVal: Word(0x11228344_55667788), expectRes: Word(0xFF_FF_FF_FF_FF_FF_83_44)}, // lhu $t0, 2($t1) + {name: "lh offset=4", opcode: uint32(0x21), imm: 4, memVal: Word(0x11223344_55667788), expectRes: Word(0x55_66)}, // lhu $t0, 4($t1) + {name: "lh offset=4 sign-extended", opcode: uint32(0x21), imm: 4, memVal: Word(0x11223344_85667788), expectRes: Word(0xFF_FF_FF_FF_FF_FF_85_66)}, // lhu $t0, 4($t1) + {name: "lh offset=6", opcode: uint32(0x21), imm: 6, memVal: Word(0x11223344_55661788), expectRes: Word(0x17_88)}, // lhu $t0, 6($t1) + {name: "lh offset=6 sign-extended", opcode: uint32(0x21), imm: 6, memVal: Word(0x11223344_55668788), expectRes: Word(0xFF_FF_FF_FF_FF_FF_87_88)}, // lhu $t0, 6($t1) + + {name: "lw upper", opcode: uint32(0x23), memVal: Word(0x11223344_55667788), expectRes: Word(0x11223344)}, // lw $t0, 0($t1) + {name: "lw upper sign-extended", opcode: uint32(0x23), memVal: Word(0x81223344_55667788), expectRes: Word(0xFFFFFFFF_81223344)}, // lw $t0, 0($t1) + {name: "lw lower", opcode: uint32(0x23), imm: 4, memVal: Word(0x11223344_55667788), expectRes: Word(0x55667788)}, // lw $t0, 4($t1) + {name: "lw lower sign-extended", opcode: uint32(0x23), imm: 4, memVal: Word(0x11223344_85667788), expectRes: Word(0xFFFFFFFF_85667788)}, // lw $t0, 4($t1) + + {name: "lbu 0", opcode: uint32(0x24), memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x71)}, // lbu $t0, 0($t1) + {name: "lbu 1", opcode: uint32(0x24), imm: 1, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x72)}, // lbu $t0, 1($t1) + {name: "lbu 2", opcode: uint32(0x24), imm: 2, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x73)}, // lbu $t0, 2($t1) + {name: "lbu 3", opcode: uint32(0x24), imm: 3, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x74)}, // lbu $t0, 3($t1) + {name: "lbu 4", opcode: uint32(0x24), imm: 4, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x75)}, // lbu $t0, 4($t1) + {name: "lbu 5", opcode: uint32(0x24), imm: 5, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x76)}, // lbu $t0, 5($t1) + {name: "lbu 6", opcode: uint32(0x24), imm: 6, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x77)}, // lbu $t0, 6($t1) + {name: "lbu 7", opcode: uint32(0x24), imm: 7, memVal: Word(0x71_72_73_74_75_76_77_78), expectRes: Word(0x78)}, // lbu $t0, 7($t1) + {name: "lbu sign-extended 0", opcode: uint32(0x24), memVal: Word(0x81_72_73_74_75_76_77_78), expectRes: Word(0x81)}, // lbu $t0, 0($t1) + {name: "lbu sign-extended 1", opcode: uint32(0x24), imm: 1, memVal: Word(0x71_82_73_74_75_76_77_78), expectRes: Word(0x82)}, // lbu $t0, 1($t1) + {name: "lbu sign-extended 2", opcode: uint32(0x24), imm: 2, memVal: Word(0x71_72_83_74_75_76_77_78), expectRes: Word(0x83)}, // lbu $t0, 2($t1) + {name: "lbu sign-extended 3", opcode: uint32(0x24), imm: 3, memVal: Word(0x71_72_73_84_75_76_77_78), expectRes: Word(0x84)}, // lbu $t0, 3($t1) + {name: "lbu sign-extended 4", opcode: uint32(0x24), imm: 4, memVal: Word(0x71_72_73_74_85_76_77_78), expectRes: Word(0x85)}, // lbu $t0, 4($t1) + {name: "lbu sign-extended 5", opcode: uint32(0x24), imm: 5, memVal: Word(0x71_72_73_74_75_86_77_78), expectRes: Word(0x86)}, // lbu $t0, 5($t1) + {name: "lbu sign-extended 6", opcode: uint32(0x24), imm: 6, memVal: Word(0x71_72_73_74_75_76_87_78), expectRes: Word(0x87)}, // lbu $t0, 6($t1) + {name: "lbu sign-extended 7", opcode: uint32(0x24), imm: 7, memVal: Word(0x71_72_73_74_75_76_77_88), expectRes: Word(0x88)}, // lbu $t0, 7($t1) + + {name: "lhu offset=0", opcode: uint32(0x25), memVal: Word(0x11223344_55667788), expectRes: Word(0x11_22)}, // lhu $t0, 0($t1) + {name: "lhu offset=0 zero-extended", opcode: uint32(0x25), memVal: Word(0x81223344_55667788), expectRes: Word(0x81_22)}, // lhu $t0, 0($t1) + {name: "lhu offset=2", opcode: uint32(0x25), imm: 2, memVal: Word(0x11223344_55667788), expectRes: Word(0x33_44)}, // lhu $t0, 2($t1) + {name: "lhu offset=2 zero-extended", opcode: uint32(0x25), imm: 2, memVal: Word(0x11228344_55667788), expectRes: Word(0x83_44)}, // lhu $t0, 2($t1) + {name: "lhu offset=4", opcode: uint32(0x25), imm: 4, memVal: Word(0x11223344_55667788), expectRes: Word(0x55_66)}, // lhu $t0, 4($t1) + {name: "lhu offset=4 zero-extended", opcode: uint32(0x25), imm: 4, memVal: Word(0x11223344_85667788), expectRes: Word(0x85_66)}, // lhu $t0, 4($t1) + {name: "lhu offset=6", opcode: uint32(0x25), imm: 6, memVal: Word(0x11223344_55661788), expectRes: Word(0x17_88)}, // lhu $t0, 6($t1) + {name: "lhu offset=6 zero-extended", opcode: uint32(0x25), imm: 6, memVal: Word(0x11223344_55668788), expectRes: Word(0x87_88)}, // lhu $t0, 6($t1) + + {name: "lwl", opcode: uint32(0x22), rt: Word(0xaa_bb_cc_dd), imm: 4, memVal: Word(0x12_34_56_78), expectRes: Word(0x12_34_56_78)}, // lwl $t0, 4($t1) + {name: "lwl unaligned address", opcode: uint32(0x22), rt: Word(0xaa_bb_cc_dd), imm: 5, memVal: Word(0x12_34_56_78), expectRes: Word(0x34_56_78_dd)}, // lwl $t0, 5($t1) + {name: "lwl offset 0 sign bit 31 set", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xFF_FF_FF_FF_AA_BB_CC_DD)}, // lwl $t0, 0($t1) + {name: "lwl offset 0 sign bit 31 clear", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, memVal: Word(0x7A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x00_00_00_00_7A_BB_CC_DD)}, // lwl $t0, 0($t1) + {name: "lwl offset 1 sign bit 31 set", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xFF_FF_FF_FF_BB_CC_DD_88)}, // lwl $t0, 1($t1) + {name: "lwl offset 1 sign bit 31 clear", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, memVal: Word(0xAA_7B_CC_DD_A1_B1_C1_D1), expectRes: Word(0x00_00_00_00_7B_CC_DD_88)}, // lwl $t0, 1($t1) + {name: "lwl offset 2 sign bit 31 set", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xFF_FF_FF_FF_CC_DD_77_88)}, // lwl $t0, 2($t1) + {name: "lwl offset 2 sign bit 31 clear", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, memVal: Word(0xAA_BB_7C_DD_A1_B1_C1_D1), expectRes: Word(0x00_00_00_00_7C_DD_77_88)}, // lwl $t0, 2($t1) + {name: "lwl offset 3 sign bit 31 set", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xFF_FF_FF_FF_DD_66_77_88)}, // lwl $t0, 3($t1) + {name: "lwl offset 3 sign bit 31 clear", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, memVal: Word(0xAA_BB_CC_7D_A1_B1_C1_D1), expectRes: Word(0x00_00_00_00_7D_66_77_88)}, // lwl $t0, 3($t1) + {name: "lwl offset 4 sign bit 31 set", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xFF_FF_FF_FF_A1_B1_C1_D1)}, // lwl $t0, 4($t1) + {name: "lwl offset 4 sign bit 31 clear", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, memVal: Word(0xAA_BB_CC_DD_71_B1_C1_D1), expectRes: Word(0x00_00_00_00_71_B1_C1_D1)}, // lwl $t0, 4($t1) + {name: "lwl offset 5 sign bit 31 set", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 5, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xFF_FF_FF_FF_B1_C1_D1_88)}, // lwl $t0, 5($t1) + {name: "lwl offset 5 sign bit 31 clear", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 5, memVal: Word(0xAA_BB_CC_DD_A1_71_C1_D1), expectRes: Word(0x00_00_00_00_71_C1_D1_88)}, // lwl $t0, 5($t1) + {name: "lwl offset 6 sign bit 31 set", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xFF_FF_FF_FF_C1_D1_77_88)}, // lwl $t0, 6($t1) + {name: "lwl offset 6 sign bit 31 clear", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, memVal: Word(0xAA_BB_CC_DD_A1_B1_71_D1), expectRes: Word(0x00_00_00_00_71_D1_77_88)}, // lwl $t0, 6($t1) + {name: "lwl offset 7 sign bit 31 set", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xFF_FF_FF_FF_D1_66_77_88)}, // lwl $t0, 7($t1) + {name: "lwl offset 7 sign bit 31 clear", opcode: uint32(0x22), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_71), expectRes: Word(0x00_00_00_00_71_66_77_88)}, // lwl $t0, 7($t1) + + {name: "lwr zero-extended imm 0 sign bit 31 clear", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, memVal: Word(0x7A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_66_77_7A)}, // lwr $t0, 0($t1) + {name: "lwr zero-extended imm 0 sign bit 31 set", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_66_77_AA)}, // lwr $t0, 0($t1) + {name: "lwr zero-extended imm 1 sign bit 31 clear", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, memVal: Word(0x7A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_66_7A_BB)}, // lwr $t0, 1($t1) + {name: "lwr zero-extended imm 1 sign bit 31 set", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_66_AA_BB)}, // lwr $t0, 1($t1) + {name: "lwr zero-extended imm 2 sign bit 31 clear", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, memVal: Word(0x7A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_7A_BB_CC)}, // lwr $t0, 2($t1) + {name: "lwr zero-extended imm 2 sign bit 31 set", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_AA_BB_CC)}, // lwr $t0, 2($t1) + {name: "lwr sign-extended imm 3 sign bit 31 clear", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, memVal: Word(0x7A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x00_00_00_00_7A_BB_CC_DD)}, // lwr $t0, 3($t1) + {name: "lwr sign-extended imm 3 sign bit 31 set", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xFF_FF_FF_FF_AA_BB_CC_DD)}, // lwr $t0, 3($t1) + {name: "lwr zero-extended imm 4 sign bit 31 clear", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, memVal: Word(0xAA_BB_CC_DD_71_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_66_77_71)}, // lwr $t0, 4($t1) + {name: "lwr zero-extended imm 4 sign bit 31 set", opcode: uint32(0x26), rt: Word(0x11_22_33_44_85_66_77_88), imm: 4, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_85_66_77_A1)}, // lwr $t0, 4($t1) + {name: "lwr zero-extended imm 5 sign bit 31 clear", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 5, memVal: Word(0xAA_BB_CC_DD_71_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_66_71_B1)}, // lwr $t0, 5($t1) + {name: "lwr zero-extended imm 5 sign bit 31 set", opcode: uint32(0x26), rt: Word(0x11_22_33_44_85_66_77_88), imm: 5, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_85_66_A1_B1)}, // lwr $t0, 5($t1) + {name: "lwr zero-extended imm 6 sign bit 31 clear", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, memVal: Word(0xAA_BB_CC_DD_71_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_71_B1_C1)}, // lwr $t0, 6($t1) + {name: "lwr zero-extended imm 6 sign bit 31 set", opcode: uint32(0x26), rt: Word(0x11_22_33_44_85_66_77_88), imm: 6, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_85_A1_B1_C1)}, // lwr $t0, 6($t1) + {name: "lwr sign-extended imm 7 sign bit 31 clear", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_71_B1_C1_D1), expectRes: Word(0x00_00_00_00_71_B1_C1_D1)}, // lwr $t0, 7($t1) + {name: "lwr sign-extended imm 7 sign bit 31 set", opcode: uint32(0x26), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xFF_FF_FF_FF_A1_B1_C1_D1)}, // lwr $t0, 7($t1) + + {name: "sb offset=0", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, expectMemVal: Word(0x88_BB_CC_DD_A1_B1_C1_D1)}, // sb $t0, 0($t1) + {name: "sb offset=1", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, expectMemVal: Word(0xAA_88_CC_DD_A1_B1_C1_D1)}, // sb $t0, 1($t1) + {name: "sb offset=2", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, expectMemVal: Word(0xAA_BB_88_DD_A1_B1_C1_D1)}, // sb $t0, 2($t1) + {name: "sb offset=3", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, expectMemVal: Word(0xAA_BB_CC_88_A1_B1_C1_D1)}, // sb $t0, 3($t1) + {name: "sb offset=4", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, expectMemVal: Word(0xAA_BB_CC_DD_88_B1_C1_D1)}, // sb $t0, 4($t1) + {name: "sb offset=5", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 5, expectMemVal: Word(0xAA_BB_CC_DD_A1_88_C1_D1)}, // sb $t0, 5($t1) + {name: "sb offset=6", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, expectMemVal: Word(0xAA_BB_CC_DD_A1_B1_88_D1)}, // sb $t0, 6($t1) + {name: "sb offset=7", opcode: uint32(0x28), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, expectMemVal: Word(0xAA_BB_CC_DD_A1_B1_C1_88)}, // sb $t0, 7($t1) + + {name: "sh offset=0", opcode: uint32(0x29), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, expectMemVal: Word(0x77_88_CC_DD_A1_B1_C1_D1)}, // sh $t0, 0($t1) + {name: "sh offset=2", opcode: uint32(0x29), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, expectMemVal: Word(0xAA_BB_77_88_A1_B1_C1_D1)}, // sh $t0, 2($t1) + {name: "sh offset=4", opcode: uint32(0x29), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, expectMemVal: Word(0xAA_BB_CC_DD_77_88_C1_D1)}, // sh $t0, 4($t1) + {name: "sh offset=6", opcode: uint32(0x29), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, expectMemVal: Word(0xAA_BB_CC_DD_A1_B1_77_88)}, // sh $t0, 6($t1) + + {name: "swl offset=0", opcode: uint32(0x2a), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 0, expectMemVal: Word(0x55_66_77_88_A1_B1_C1_D1)}, // swl $t0, 0($t1) + {name: "swl offset=1", opcode: uint32(0x2a), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 1, expectMemVal: Word(0xAA_55_66_77_A1_B1_C1_D1)}, // swl $t0, 1($t1) + {name: "swl offset=2", opcode: uint32(0x2a), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 2, expectMemVal: Word(0xAA_BB_55_66_A1_B1_C1_D1)}, // swl $t0, 2($t1) + {name: "swl offset=3", opcode: uint32(0x2a), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 3, expectMemVal: Word(0xAA_BB_CC_55_A1_B1_C1_D1)}, // swl $t0, 3($t1) + {name: "swl offset=4", opcode: uint32(0x2a), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 4, expectMemVal: Word(0xAA_BB_CC_DD_55_66_77_88)}, // swl $t0, 4($t1) + {name: "swl offset=5", opcode: uint32(0x2a), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 5, expectMemVal: Word(0xAA_BB_CC_DD_A1_55_66_77)}, // swl $t0, 5($t1) + {name: "swl offset=6", opcode: uint32(0x2a), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 6, expectMemVal: Word(0xAA_BB_CC_DD_A1_B1_55_66)}, // swl $t0, 6($t1) + {name: "swl offset=7", opcode: uint32(0x2a), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 7, expectMemVal: Word(0xAA_BB_CC_DD_A1_B1_C1_55)}, // swl $t0, 7($t1) + + {name: "sw offset=0", opcode: uint32(0x2b), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 0, expectMemVal: Word(0x55_66_77_88_A1_B1_C1_D1)}, // sw $t0, 0($t1) + {name: "sw offset=4", opcode: uint32(0x2b), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 4, expectMemVal: Word(0xAA_BB_CC_DD_55_66_77_88)}, // sw $t0, 4($t1) + + {name: "swr offset=0", opcode: uint32(0x2e), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x88_BB_CC_DD_A1_B1_C1_D1)}, // swr $t0, 0($t1) + {name: "swr offset=1", opcode: uint32(0x2e), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x77_88_CC_DD_A1_B1_C1_D1)}, // swr $t0, 1($t1) + {name: "swr offset=2", opcode: uint32(0x2e), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x66_77_88_DD_A1_B1_C1_D1)}, // swr $t0, 2($t1) + {name: "swr offset=3", opcode: uint32(0x2e), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x55_66_77_88_A1_B1_C1_D1)}, // swr $t0, 3($t1) + {name: "swr offset=4", opcode: uint32(0x2e), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0xAA_BB_CC_DD_88_B1_C1_D1)}, // swr $t0, 4($t1) + {name: "swr offset=5", opcode: uint32(0x2e), rt: Word(0x11_22_33_44_55_66_77_88), imm: 5, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0xAA_BB_CC_DD_77_88_C1_D1)}, // swr $t0, 5($t1) + {name: "swr offset=6", opcode: uint32(0x2e), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0xAA_BB_CC_DD_66_77_88_D1)}, // swr $t0, 6($t1) + {name: "swr offset=7", opcode: uint32(0x2e), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0xAA_BB_CC_DD_55_66_77_88)}, // swr $t0, 7($t1) + + // 64-bit instructions + {name: "ldl offset 0 sign bit 31 set", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xAA_BB_CC_DD_A1_B1_C1_D1)}, // ldl $t0, 0($t1) + {name: "ldl offset 1 sign bit 31 set", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xBB_CC_DD_A1_B1_C1_D1_88)}, // ldl $t0, 1($t1) + {name: "ldl offset 2 sign bit 31 set", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xCC_DD_A1_B1_C1_D1_77_88)}, // ldl $t0, 2($t1) + {name: "ldl offset 3 sign bit 31 set", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xDD_A1_B1_C1_D1_66_77_88)}, // ldl $t0, 3($t1) + {name: "ldl offset 4 sign bit 31 set", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xA1_B1_C1_D1_55_66_77_88)}, // ldl $t0, 4($t1) + {name: "ldl offset 5 sign bit 31 set", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 5, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xB1_C1_D1_44_55_66_77_88)}, // ldl $t0, 5($t1) + {name: "ldl offset 6 sign bit 31 set", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xC1_D1_33_44_55_66_77_88)}, // ldl $t0, 6($t1) + {name: "ldl offset 7 sign bit 31 set", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xD1_22_33_44_55_66_77_88)}, // ldl $t0, 7($t1) + {name: "ldl offset 0 sign bit 31 clear", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, memVal: Word(0x7A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x7A_BB_CC_DD_A1_B1_C1_D1)}, // ldl $t0, 0($t1) + {name: "ldl offset 1 sign bit 31 clear", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, memVal: Word(0xAA_7B_CC_DD_A1_B1_C1_D1), expectRes: Word(0x7B_CC_DD_A1_B1_C1_D1_88)}, // ldl $t0, 1($t1) + {name: "ldl offset 2 sign bit 31 clear", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, memVal: Word(0xAA_BB_7C_DD_A1_B1_C1_D1), expectRes: Word(0x7C_DD_A1_B1_C1_D1_77_88)}, // ldl $t0, 2($t1) + {name: "ldl offset 3 sign bit 31 clear", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, memVal: Word(0xAA_BB_CC_7D_A1_B1_C1_D1), expectRes: Word(0x7D_A1_B1_C1_D1_66_77_88)}, // ldl $t0, 3($t1) + {name: "ldl offset 4 sign bit 31 clear", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, memVal: Word(0xAA_BB_CC_DD_71_B1_C1_D1), expectRes: Word(0x71_B1_C1_D1_55_66_77_88)}, // ldl $t0, 4($t1) + {name: "ldl offset 5 sign bit 31 clear", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 5, memVal: Word(0xAA_BB_CC_DD_A1_71_C1_D1), expectRes: Word(0x71_C1_D1_44_55_66_77_88)}, // ldl $t0, 5($t1) + {name: "ldl offset 6 sign bit 31 clear", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, memVal: Word(0xAA_BB_CC_DD_A1_B1_71_D1), expectRes: Word(0x71_D1_33_44_55_66_77_88)}, // ldl $t0, 6($t1) + {name: "ldl offset 7 sign bit 31 clear", opcode: uint32(0x1A), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_71), expectRes: Word(0x71_22_33_44_55_66_77_88)}, // ldl $t0, 7($t1) + + {name: "ldr offset 0 sign bit clear", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, memVal: Word(0x3A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_66_77_3A)}, // ldr $t0, 0($t1) + {name: "ldr offset 1 sign bit clear", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, memVal: Word(0x3A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_66_3A_BB)}, // ldr $t0, 1($t1) + {name: "ldr offset 2 sign bit clear", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, memVal: Word(0x3A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_3A_BB_CC)}, // ldr $t0, 2($t1) + {name: "ldr offset 3 sign bit clear", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, memVal: Word(0x3A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_3A_BB_CC_DD)}, // ldr $t0, 3($t1) + {name: "ldr offset 4 sign bit clear", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, memVal: Word(0x3A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_3A_BB_CC_DD_A1)}, // ldr $t0, 4($t1) + {name: "ldr offset 5 sign bit clear", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 5, memVal: Word(0x3A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_3A_BB_CC_DD_A1_B1)}, // ldr $t0, 5($t1) + {name: "ldr offset 6 sign bit clear", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, memVal: Word(0x3A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_3A_BB_CC_DD_A1_B1_C1)}, // ldr $t0, 6($t1) + {name: "ldr offset 7 sign bit clear", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0x3A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x3A_BB_CC_DD_A1_B1_C1_D1)}, // ldr $t0, 7($t1) + {name: "ldr offset 0 sign bit set", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_66_77_AA)}, // ldr $t0, 0($t1) + {name: "ldr offset 1 sign bit set", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_66_AA_BB)}, // ldr $t0, 1($t1) + {name: "ldr offset 2 sign bit set", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_55_AA_BB_CC)}, // ldr $t0, 2($t1) + {name: "ldr offset 3 sign bit set", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_44_AA_BB_CC_DD)}, // ldr $t0, 3($t1) + {name: "ldr offset 4 sign bit set", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_33_AA_BB_CC_DD_A1)}, // ldr $t0, 4($t1) + {name: "ldr offset 5 sign bit set", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 5, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_22_AA_BB_CC_DD_A1_B1)}, // ldr $t0, 5($t1) + {name: "ldr offset 6 sign bit set", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x11_AA_BB_CC_DD_A1_B1_C1)}, // ldr $t0, 6($t1) + {name: "ldr offset 7 sign bit set", opcode: uint32(0x1b), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0xAA_BB_CC_DD_A1_B1_C1_D1)}, // ldr $t0, 7($t1) + + {name: "lwu upper", opcode: uint32(0x27), memVal: Word(0x11223344_55667788), expectRes: Word(0x11223344)}, // lw $t0, 0($t1) + {name: "lwu upper sign", opcode: uint32(0x27), memVal: Word(0x81223344_55667788), expectRes: Word(0x81223344)}, // lw $t0, 0($t1) + {name: "lwu lower", opcode: uint32(0x27), imm: 4, memVal: Word(0x11223344_55667788), expectRes: Word(0x55667788)}, // lw $t0, 4($t1) + {name: "lwu lower sign", opcode: uint32(0x27), imm: 4, memVal: Word(0x11223344_85667788), expectRes: Word(0x85667788)}, // lw $t0, 4($t1) + + {name: "sdl offset=0", opcode: uint32(0x2c), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 0, expectMemVal: Word(0x11_22_33_44_55_66_77_88)}, // sdl $t0, 0($t1) + {name: "sdl offset=1", opcode: uint32(0x2c), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 1, expectMemVal: Word(0xAA_11_22_33_44_55_66_77)}, // sdl $t0, 1($t1) + {name: "sdl offset=2", opcode: uint32(0x2c), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 2, expectMemVal: Word(0xAA_BB_11_22_33_44_55_66)}, // sdl $t0, 2($t1) + {name: "sdl offset=3", opcode: uint32(0x2c), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 3, expectMemVal: Word(0xAA_BB_CC_11_22_33_44_55)}, // sdl $t0, 3($t1) + {name: "sdl offset=4", opcode: uint32(0x2c), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 4, expectMemVal: Word(0xAA_BB_CC_DD_11_22_33_44)}, // sdl $t0, 4($t1) + {name: "sdl offset=5", opcode: uint32(0x2c), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 5, expectMemVal: Word(0xAA_BB_CC_DD_A1_11_22_33)}, // sdl $t0, 5($t1) + {name: "sdl offset=6", opcode: uint32(0x2c), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 6, expectMemVal: Word(0xAA_BB_CC_DD_A1_B1_11_22)}, // sdl $t0, 6($t1) + {name: "sdl offset=7", opcode: uint32(0x2c), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), imm: 7, expectMemVal: Word(0xAA_BB_CC_DD_A1_B1_C1_11)}, // sdl $t0, 7($t1) + + {name: "sdr offset=0", opcode: uint32(0x2d), rt: Word(0x11_22_33_44_55_66_77_88), imm: 0, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x88_BB_CC_DD_A1_B1_C1_D1)}, // sdr $t0, 0($t1) + {name: "sdr offset=1", opcode: uint32(0x2d), rt: Word(0x11_22_33_44_55_66_77_88), imm: 1, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x77_88_CC_DD_A1_B1_C1_D1)}, // sdr $t0, 1($t1) + {name: "sdr offset=2", opcode: uint32(0x2d), rt: Word(0x11_22_33_44_55_66_77_88), imm: 2, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x66_77_88_DD_A1_B1_C1_D1)}, // sdr $t0, 2($t1) + {name: "sdr offset=3", opcode: uint32(0x2d), rt: Word(0x11_22_33_44_55_66_77_88), imm: 3, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x55_66_77_88_A1_B1_C1_D1)}, // sdr $t0, 3($t1) + {name: "sdr offset=4", opcode: uint32(0x2d), rt: Word(0x11_22_33_44_55_66_77_88), imm: 4, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x44_55_66_77_88_B1_C1_D1)}, // sdr $t0, 4($t1) + {name: "sdr offset=5", opcode: uint32(0x2d), rt: Word(0x11_22_33_44_55_66_77_88), imm: 5, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x33_44_55_66_77_88_C1_D1)}, // sdr $t0, 5($t1) + {name: "sdr offset=6", opcode: uint32(0x2d), rt: Word(0x11_22_33_44_55_66_77_88), imm: 6, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x22_33_44_55_66_77_88_D1)}, // sdr $t0, 6($t1) + {name: "sdr offset=7", opcode: uint32(0x2d), rt: Word(0x11_22_33_44_55_66_77_88), imm: 7, memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x11_22_33_44_55_66_77_88)}, // sdr $t0, 7($t1) + + {name: "ld", opcode: uint32(0x37), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0x7A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x7A_BB_CC_DD_A1_B1_C1_D1)}, // ld $t0, 0($t1) + {name: "ld signed", opcode: uint32(0x37), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0x8A_BB_CC_DD_A1_B1_C1_D1), expectRes: Word(0x8A_BB_CC_DD_A1_B1_C1_D1)}, // ld $t0, 0($t1) + + {name: "sd", opcode: uint32(0x3f), rt: Word(0x11_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x11_22_33_44_55_66_77_88)}, // sd $t0, 0($t1) + {name: "sd signed", opcode: uint32(0x3f), rt: Word(0x81_22_33_44_55_66_77_88), memVal: Word(0xAA_BB_CC_DD_A1_B1_C1_D1), expectMemVal: Word(0x81_22_33_44_55_66_77_88)}, // sd $t0, 4($t1) + } + // use a fixed base for all tests + for i := range cases { + cases[i].base = t1 + } + testLoadStore(t, cases) +} + +func TestEVM_SingleStep_MulDiv64(t *testing.T) { + cases := []mulDivTestCase{ + // dmult s1, s2 + // expected hi,lo were verified using qemu-mips + {name: "dmult 0", funct: 0x1c, rs: 0, rt: 0, expectLo: 0, expectHi: 0}, + {name: "dmult 1", funct: 0x1c, rs: 1, rt: 1, expectLo: 1, expectHi: 0}, + {name: "dmult 2", funct: 0x1c, rs: 0x01_00_00_00_00, rt: 2, expectLo: 0x02_00_00_00_00, expectHi: 0}, + {name: "dmult 3", funct: 0x1c, rs: 0x01_00_00_00_00_00_00_00, rt: 2, expectLo: 0x02_00_00_00_00_00_00_00, expectHi: 0}, + {name: "dmult 4", funct: 0x1c, rs: 0x40_00_00_00_00_00_00_00, rt: 2, expectLo: 0x80_00_00_00_00_00_00_00, expectHi: 0x0}, + {name: "dmult 5", funct: 0x1c, rs: 0x40_00_00_00_00_00_00_00, rt: 0x1000, expectLo: 0x0, expectHi: 0x4_00}, + {name: "dmult 6", funct: 0x1c, rs: 0x80_00_00_00_00_00_00_00, rt: 0x1000, expectLo: 0x0, expectHi: 0xFF_FF_FF_FF_FF_FF_F8_00}, + {name: "dmult 7", funct: 0x1c, rs: 0x80_00_00_00_00_00_00_00, rt: 0x80_00_00_00_00_00_00_00, expectLo: 0x0, expectHi: 0x40_00_00_00_00_00_00_00}, + {name: "dmult 8", funct: 0x1c, rs: 0x40_00_00_00_00_00_00_01, rt: 0x1000, expectLo: 0x1000, expectHi: 0x4_00}, + {name: "dmult 9", funct: 0x1c, rs: 0x80_00_00_00_00_00_00_80, rt: 0x80_00_00_00_00_00_00_80, expectLo: 0x4000, expectHi: 0x3F_FF_FF_FF_FF_FF_FF_80}, + {name: "dmult 10", funct: 0x1c, rs: Word(0xFF_FF_FF_FF_FF_FF_FF_FF), rt: Word(0x1), expectLo: 0xFF_FF_FF_FF_FF_FF_FF_FF, expectHi: 0xFF_FF_FF_FF_FF_FF_FF_FF}, + {name: "dmult 11", funct: 0x1c, rs: Word(0xFF_FF_FF_FF_FF_FF_FF_FF), rt: Word(0xFF_FF_FF_FF_FF_FF_FF_FF), expectLo: 0x1, expectHi: Word(0)}, + {name: "dmult 12", funct: 0x1c, rs: Word(0xFF_FF_FF_FF_FF_FF_FF_D3), rt: Word(0xAA_BB_CC_DD_A1_D1_C1_E0), expectLo: 0xFC_FC_FD_0A_8E_20_EB_A0, expectHi: 0x00_00_00_00_00_00_00_0E}, + {name: "dmult 13", funct: 0x1c, rs: Word(0x7F_FF_FF_FF_FF_FF_FF_FF), rt: Word(0xAA_BB_CC_DD_A1_D1_C1_E1), expectLo: 0xD5_44_33_22_5E_2E_3E_1F, expectHi: 0xD5_5D_E6_6E_D0_E8_E0_F0}, + {name: "dmult 14", funct: 0x1c, rs: Word(0x7F_FF_FF_FF_FF_FF_FF_FF), rt: Word(0x8F_FF_FF_FF_FF_FF_FF_FF), expectLo: 0xF0_00_00_00_00_00_00_01, expectHi: 0xC7_FF_FF_FF_FF_FF_FF_FF}, + + // dmultu s1, s2 + {name: "dmultu 0", funct: 0x1d, rs: 0, rt: 0, expectLo: 0, expectHi: 0}, + {name: "dmultu 1", funct: 0x1d, rs: 1, rt: 1, expectLo: 1, expectHi: 0}, + {name: "dmultu 2", funct: 0x1d, rs: 0x01_00_00_00_00, rt: 2, expectLo: 0x02_00_00_00_00, expectHi: 0}, + {name: "dmultu 3", funct: 0x1d, rs: 0x01_00_00_00_00_00_00_00, rt: 2, expectLo: 0x02_00_00_00_00_00_00_00, expectHi: 0}, + {name: "dmultu 4", funct: 0x1d, rs: 0x40_00_00_00_00_00_00_00, rt: 2, expectLo: 0x80_00_00_00_00_00_00_00, expectHi: 0x0}, + {name: "dmultu 5", funct: 0x1d, rs: 0x40_00_00_00_00_00_00_00, rt: 0x1000, expectLo: 0x0, expectHi: 0x4_00}, + {name: "dmultu 6", funct: 0x1d, rs: 0x80_00_00_00_00_00_00_00, rt: 0x1000, expectLo: 0x0, expectHi: 0x8_00}, + {name: "dmultu 7", funct: 0x1d, rs: 0x80_00_00_00_00_00_00_00, rt: 0x80_00_00_00_00_00_00_00, expectLo: 0x0, expectHi: 0x40_00_00_00_00_00_00_00}, + {name: "dmultu 8", funct: 0x1d, rs: 0x40_00_00_00_00_00_00_01, rt: 0x1000, expectLo: 0x1000, expectHi: 0x4_00}, + {name: "dmultu 9", funct: 0x1d, rs: 0x80_00_00_00_00_00_00_80, rt: 0x80_00_00_00_00_00_00_80, expectLo: 0x4000, expectHi: 0x40_00_00_00_00_00_00_80}, + {name: "dmultu 10", funct: 0x1d, rs: Word(0xFF_FF_FF_FF_FF_FF_FF_FF), rt: Word(0xFF_FF_FF_FF_FF_FF_FF_FF), expectLo: 0x1, expectHi: Word(0xFF_FF_FF_FF_FF_FF_FF_FE)}, + {name: "dmultu 11", funct: 0x1d, rs: Word(0xFF_FF_FF_FF_FF_FF_FF_FF), rt: Word(0xFF_FF_FF_FF_FF_FF_FF_FF), expectLo: 0x1, expectHi: 0xFF_FF_FF_FF_FF_FF_FF_FE}, + {name: "dmultu 12", funct: 0x1d, rs: Word(0xFF_FF_FF_FF_FF_FF_FF_D3), rt: Word(0xAA_BB_CC_DD_A1_D1_C1_E0), expectLo: 0xFC_FC_FD_0A_8E_20_EB_A0, expectHi: 0xAA_BB_CC_DD_A1_D1_C1_C1}, + {name: "dmultu 13", funct: 0x1d, rs: Word(0x7F_FF_FF_FF_FF_FF_FF_FF), rt: Word(0xAA_BB_CC_DD_A1_D1_C1_E1), expectLo: 0xD5_44_33_22_5E_2E_3E_1F, expectHi: 0x55_5D_E6_6E_D0_E8_E0_EF}, + {name: "dmultu 14", funct: 0x1d, rs: Word(0x7F_FF_FF_FF_FF_FF_FF_FF), rt: Word(0x8F_FF_FF_FF_FF_FF_FF_FF), expectLo: 0xF0_00_00_00_00_00_00_01, expectHi: 0x47_FF_FF_FF_FF_FF_FF_FE}, + + // ddiv rs, rt + {name: "ddiv", funct: 0x1e, rs: 0, rt: 0, panicMsg: "instruction divide by zero", revertMsg: "division by zero"}, + {name: "ddiv", funct: 0x1e, rs: 1, rt: 0, panicMsg: "instruction divide by zero", revertMsg: "division by zero"}, + {name: "ddiv", funct: 0x1e, rs: 0xFF_FF_FF_FF_FF_FF_FF_FF, rt: 0, panicMsg: "instruction divide by zero", revertMsg: "division by zero"}, + {name: "ddiv", funct: 0x1e, rs: 0, rt: 1, expectLo: 0, expectHi: 0}, + {name: "ddiv", funct: 0x1e, rs: 1, rt: 1, expectLo: 1, expectHi: 0}, + {name: "ddiv", funct: 0x1e, rs: 10, rt: 3, expectLo: 3, expectHi: 1}, + {name: "ddiv", funct: 0x1e, rs: 0x7F_FF_FF_FF_00_00_00_00, rt: 2, expectLo: 0x3F_FF_FF_FF_80_00_00_00, expectHi: 0}, + {name: "ddiv", funct: 0x1e, rs: 0xFF_FF_FF_FF_00_00_00_00, rt: 2, expectLo: 0xFF_FF_FF_FF_80_00_00_00, expectHi: 0}, + {name: "ddiv", funct: 0x1e, rs: ^Word(0), rt: ^Word(0), expectLo: 1, expectHi: 0}, + {name: "ddiv", funct: 0x1e, rs: ^Word(0), rt: 2, expectLo: 0, expectHi: ^Word(0)}, + {name: "ddiv", funct: 0x1e, rs: 0x7F_FF_FF_FF_00_00_00_00, rt: ^Word(0), expectLo: 0x80_00_00_01_00_00_00_00, expectHi: 0}, + + // ddivu + {name: "ddivu", funct: 0x1f, rs: 0, rt: 0, panicMsg: "instruction divide by zero", revertMsg: "division by zero"}, + {name: "ddivu", funct: 0x1f, rs: 1, rt: 0, panicMsg: "instruction divide by zero", revertMsg: "division by zero"}, + {name: "ddivu", funct: 0x1f, rs: 0xFF_FF_FF_FF_FF_FF_FF_FF, rt: 0, panicMsg: "instruction divide by zero", revertMsg: "division by zero"}, + {name: "ddivu", funct: 0x1f, rs: 0, rt: 1, expectLo: 0, expectHi: 0}, + {name: "ddivu", funct: 0x1f, rs: 1, rt: 1, expectLo: 1, expectHi: 0}, + {name: "ddivu", funct: 0x1f, rs: 10, rt: 3, expectLo: 3, expectHi: 1}, + {name: "ddivu", funct: 0x1f, rs: 0x7F_FF_FF_FF_00_00_00_00, rt: 2, expectLo: 0x3F_FF_FF_FF_80_00_00_00, expectHi: 0}, + {name: "ddivu", funct: 0x1f, rs: 0xFF_FF_FF_FF_00_00_00_00, rt: 2, expectLo: 0x7F_FF_FF_FF_80_00_00_00, expectHi: 0}, + {name: "ddivu", funct: 0x1f, rs: ^Word(0), rt: ^Word(0), expectLo: 1, expectHi: 0}, + {name: "ddivu", funct: 0x1f, rs: ^Word(0), rt: 2, expectLo: 0x7F_FF_FF_FF_FF_FF_FF_FF, expectHi: 1}, + {name: "ddivu", funct: 0x1f, rs: 0x7F_FF_FF_FF_00_00_00_00, rt: ^Word(0), expectLo: 0, expectHi: 0x7F_FF_FF_FF_00_00_00_00}, + + // a couple div/divu 64-bit edge cases + {name: "div lower word zero", funct: 0x1a, rs: 1, rt: 0xFF_FF_FF_FF_00_00_00_00, panicMsg: "instruction divide by zero", revertMsg: "division by zero"}, + {name: "divu lower word zero", funct: 0x1b, rs: 1, rt: 0xFF_FF_FF_FF_00_00_00_00, panicMsg: "instruction divide by zero", revertMsg: "division by zero"}, + } + + testMulDiv(t, cases, false) +} + +func TestEVM_SingleStep_Branch64(t *testing.T) { + t.Parallel() + cases := []branchTestCase{ + // blez + {name: "blez", pc: 0, opcode: 0x6, rs: 0x5, offset: 0x100, expectNextPC: 0x8}, + {name: "blez large rs", pc: 0x10, opcode: 0x6, rs: 0x7F_FF_FF_FF_FF_FF_FF_FF, offset: 0x100, expectNextPC: 0x18}, + {name: "blez zero rs", pc: 0x10, opcode: 0x6, rs: 0x0, offset: 0x100, expectNextPC: 0x414}, + {name: "blez sign rs", pc: 0x10, opcode: 0x6, rs: -1, offset: 0x100, expectNextPC: 0x414}, + {name: "blez rs only sign bit set", pc: 0x10, opcode: 0x6, rs: testutil.ToSignedInteger(0x80_00_00_00_00_00_00_00), offset: 0x100, expectNextPC: 0x414}, + {name: "blez sign-extended offset", pc: 0x10, opcode: 0x6, rs: -1, offset: 0x80_00, expectNextPC: 0xFF_FF_FF_FF_FF_FE_00_14}, + + // bgtz + {name: "bgtz", pc: 0, opcode: 0x7, rs: 0x5, offset: 0x100, expectNextPC: 0x404}, + {name: "bgtz sign-extended offset", pc: 0x10, opcode: 0x7, rs: 0x5, offset: 0x80_00, expectNextPC: 0xFF_FF_FF_FF_FF_FE_00_14}, + {name: "bgtz large rs", pc: 0x10, opcode: 0x7, rs: 0x7F_FF_FF_FF_FF_FF_FF_FF, offset: 0x100, expectNextPC: 0x414}, + {name: "bgtz zero rs", pc: 0x10, opcode: 0x7, rs: 0x0, offset: 0x100, expectNextPC: 0x18}, + {name: "bgtz sign rs", pc: 0x10, opcode: 0x7, rs: -1, offset: 0x100, expectNextPC: 0x18}, + {name: "bgtz rs only sign bit set", pc: 0x10, opcode: 0x7, rs: testutil.ToSignedInteger(0x80_00_00_00_00_00_00_00), offset: 0x100, expectNextPC: 0x18}, + + // bltz t0, $x + {name: "bltz", pc: 0, opcode: 0x1, regimm: 0x0, rs: 0x5, offset: 0x100, expectNextPC: 0x8}, + {name: "bltz large rs", pc: 0x10, opcode: 0x1, regimm: 0x0, rs: 0x7F_FF_FF_FF_FF_FF_FF_FF, offset: 0x100, expectNextPC: 0x18}, + {name: "bltz zero rs", pc: 0x10, opcode: 0x1, regimm: 0x0, rs: 0x0, offset: 0x100, expectNextPC: 0x18}, + {name: "bltz sign rs", pc: 0x10, opcode: 0x1, regimm: 0x0, rs: -1, offset: 0x100, expectNextPC: 0x414}, + {name: "bltz rs only sign bit set", pc: 0x10, opcode: 0x1, regimm: 0x0, rs: testutil.ToSignedInteger(0x80_00_00_00_00_00_00_00), offset: 0x100, expectNextPC: 0x414}, + {name: "bltz sign-extended offset", pc: 0x10, opcode: 0x1, regimm: 0x0, rs: -1, offset: 0x80_00, expectNextPC: 0xFF_FF_FF_FF_FF_FE_00_14}, + {name: "bltz large offset no-sign", pc: 0x10, opcode: 0x1, regimm: 0x0, rs: -1, offset: 0x7F_FF, expectNextPC: 0x2_00_10}, + + // bgez t0, $x + {name: "bgez", pc: 0, opcode: 0x1, regimm: 0x1, rs: 0x5, offset: 0x100, expectNextPC: 0x404}, + {name: "bgez large rs", pc: 0x10, opcode: 0x1, regimm: 0x1, rs: 0x7F_FF_FF_FF_FF_FF_FF_FF, offset: 0x100, expectNextPC: 0x414}, + {name: "bgez zero rs", pc: 0x10, opcode: 0x1, regimm: 0x1, rs: 0x0, offset: 0x100, expectNextPC: 0x414}, + {name: "bgez branch not taken", pc: 0x10, opcode: 0x1, regimm: 0x1, rs: -1, offset: 0x100, expectNextPC: 0x18}, + {name: "bgez sign-extended offset", pc: 0x10, opcode: 0x1, regimm: 0x1, rs: 1, offset: 0x80_00, expectNextPC: 0xFF_FF_FF_FF_FF_FE_00_14}, + {name: "bgez large offset no-sign", pc: 0x10, opcode: 0x1, regimm: 0x1, rs: 1, offset: 0x70_00, expectNextPC: 0x1_C0_14}, + {name: "bgez fill bit offset except sign", pc: 0x10, opcode: 0x1, regimm: 0x1, rs: 1, offset: 0x7F_FF, expectNextPC: 0x2_00_10}, + + // bgezal t0, $x + {name: "bgezal", pc: 0, opcode: 0x1, regimm: 0x11, rs: 0x5, offset: 0x100, expectNextPC: 0x404, expectLink: true}, + {name: "bgezal large rs", pc: 0x10, opcode: 0x1, regimm: 0x11, rs: 0x7F_FF_FF_FF_FF_FF_FF_FF, offset: 0x100, expectNextPC: 0x414, expectLink: true}, + {name: "bgezal zero rs", pc: 0x10, opcode: 0x1, regimm: 0x11, rs: 0x0, offset: 0x100, expectNextPC: 0x414, expectLink: true}, + {name: "bgezal branch not taken", pc: 0x10, opcode: 0x1, regimm: 0x11, rs: -1, offset: 0x100, expectNextPC: 0x18, expectLink: true}, + {name: "bgezal sign-extended offset", pc: 0x10, opcode: 0x1, regimm: 0x11, rs: 1, offset: 0x80_00, expectNextPC: 0xFF_FF_FF_FF_FF_FE_00_14, expectLink: true}, + {name: "bgezal large offset no-sign", pc: 0x10, opcode: 0x1, regimm: 0x11, rs: 1, offset: 0x70_00, expectNextPC: 0x1_C0_14, expectLink: true}, + {name: "bgezal fill bit offset except sign", pc: 0x10, opcode: 0x1, regimm: 0x11, rs: 1, offset: 0x7F_FF, expectNextPC: 0x2_00_10, expectLink: true}, + } + + testBranch(t, cases) +} diff --git a/cannon/mipsevm/tests/evm_common_test.go b/cannon/mipsevm/tests/evm_common_test.go index e204a0d96e9dc..cac15fb074e10 100644 --- a/cannon/mipsevm/tests/evm_common_test.go +++ b/cannon/mipsevm/tests/evm_common_test.go @@ -10,7 +10,6 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/tracing" "github.com/stretchr/testify/require" @@ -21,12 +20,12 @@ import ( "github.com/ethereum-optimism/optimism/cannon/mipsevm/testutil" ) -func TestEVM(t *testing.T) { +func TestEVM_OpenMIPS(t *testing.T) { + testutil.Cannon32OnlyTest(t, "Skipping MIPS32 assembly test vectors for cannon64") + testFiles, err := os.ReadDir("open_mips_tests/test/bin") require.NoError(t, err) - var tracer *tracing.Hooks // no-tracer by default, but test_util.MarkdownTracer - cases := GetMipsVersionTestCases(t) skippedTests := map[string][]string{ "multi-threaded": {"clone.bin"}, @@ -49,11 +48,7 @@ func TestEVM(t *testing.T) { // Short-circuit early for exit_group.bin exitGroup := f.Name() == "exit_group.bin" expectPanic := strings.HasSuffix(f.Name(), "panic.bin") - - evm := testutil.NewMIPSEVM(c.Contracts) - evm.SetTracer(tracer) - evm.SetLocalOracle(oracle) - testutil.LogStepFailureAtCleanup(t, evm) + validator := testutil.NewEvmValidator(t, c.StateHashFn, c.Contracts, testutil.WithLocalOracle(oracle)) fn := path.Join("open_mips_tests/test/bin", f.Name()) programMem, err := os.ReadFile(fn) @@ -86,17 +81,12 @@ func TestEVM(t *testing.T) { if exitGroup && goVm.GetState().GetExited() { break } - insn := state.GetMemory().GetUint32(state.GetPC()) + insn := testutil.GetInstruction(state.GetMemory(), state.GetPC()) t.Logf("step: %4d pc: 0x%08x insn: 0x%08x", state.GetStep(), state.GetPC(), insn) stepWitness, err := goVm.Step(true) require.NoError(t, err) - evmPost := evm.Step(t, stepWitness, curStep, c.StateHashFn) - // verify the post-state matches. - // TODO: maybe more readable to decode the evmPost state, and do attribute-wise comparison. - goPost, _ := goVm.GetState().EncodeWitness() - require.Equalf(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), - "mipsevm produced different state than EVM at step %d", state.GetStep()) + validator.ValidateEVM(t, stepWitness, curStep, goVm) } if exitGroup { require.NotEqual(t, arch.Word(testutil.EndAddr), goVm.GetState().GetPC(), "must not reach end") @@ -116,9 +106,7 @@ func TestEVM(t *testing.T) { } } -func TestEVMSingleStep_Jump(t *testing.T) { - var tracer *tracing.Hooks - +func TestEVM_SingleStep_Jump(t *testing.T) { versions := GetMipsVersionTestCases(t) cases := []struct { name string @@ -140,7 +128,7 @@ func TestEVMSingleStep_Jump(t *testing.T) { t.Run(testName, func(t *testing.T) { goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPC(tt.pc), testutil.WithNextPC(tt.nextPC)) state := goVm.GetState() - state.GetMemory().SetUint32(tt.pc, tt.insn) + testutil.StoreInstruction(state.GetMemory(), tt.pc, tt.insn) step := state.GetStep() // Setup expectations @@ -157,108 +145,70 @@ func TestEVMSingleStep_Jump(t *testing.T) { // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } } } -func TestEVMSingleStep_Operators(t *testing.T) { - var tracer *tracing.Hooks - - versions := GetMipsVersionTestCases(t) - cases := []struct { - name string - isImm bool - rs Word - rt Word - imm uint16 - funct uint32 - opcode uint32 - expectRes Word - }{ - {name: "add", funct: 0x20, isImm: false, rs: Word(12), rt: Word(20), expectRes: Word(32)}, // add t0, s1, s2 - {name: "addu", funct: 0x21, isImm: false, rs: Word(12), rt: Word(20), expectRes: Word(32)}, // addu t0, s1, s2 - {name: "addi", opcode: 0x8, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(44)}, // addi t0, s1, 40 - {name: "addi sign", opcode: 0x8, isImm: true, rs: Word(2), rt: Word(1), imm: uint16(0xfffe), expectRes: Word(0)}, // addi t0, s1, -2 - {name: "addiu", opcode: 0x9, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(44)}, // addiu t0, s1, 40 - {name: "sub", funct: 0x22, isImm: false, rs: Word(20), rt: Word(12), expectRes: Word(8)}, // sub t0, s1, s2 - {name: "subu", funct: 0x23, isImm: false, rs: Word(20), rt: Word(12), expectRes: Word(8)}, // subu t0, s1, s2 - {name: "and", funct: 0x24, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(160)}, // and t0, s1, s2 - {name: "andi", opcode: 0xc, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(0)}, // andi t0, s1, 40 - {name: "or", funct: 0x25, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(1530)}, // or t0, s1, s2 - {name: "ori", opcode: 0xd, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(44)}, // ori t0, s1, 40 - {name: "xor", funct: 0x26, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(1370)}, // xor t0, s1, s2 - {name: "xori", opcode: 0xe, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(44)}, // xori t0, s1, 40 - {name: "nor", funct: 0x27, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(4294965765)}, // nor t0, s1, s2 - {name: "slt", funct: 0x2a, isImm: false, rs: 0xFF_FF_FF_FE, rt: Word(5), expectRes: Word(1)}, // slt t0, s1, s2 - {name: "sltu", funct: 0x2b, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(0)}, // sltu t0, s1, s2 +func TestEVM_SingleStep_Operators(t *testing.T) { + cases := []operatorTestCase{ + {name: "add", funct: 0x20, isImm: false, rs: Word(12), rt: Word(20), expectRes: Word(32)}, // add t0, s1, s2 + {name: "add", funct: 0x20, isImm: false, rs: ^Word(0), rt: ^Word(0), expectRes: Word(0xFF_FF_FF_FE)}, // add t0, s1, s2 + {name: "add", funct: 0x20, isImm: false, rs: Word(0x7F_FF_FF_FF), rt: Word(0x7F_FF_FF_FF), expectRes: Word(0xFF_FF_FF_FE)}, // add t0, s1, s2 + {name: "add", funct: 0x20, isImm: false, rs: ^Word(0), rt: Word(2), expectRes: Word(1)}, // add t0, s1, s2 + {name: "add", funct: 0x20, isImm: false, rs: Word(2), rt: ^Word(0), expectRes: Word(1)}, // add t0, s1, s2 + {name: "add", funct: 0x20, isImm: false, rs: Word(0x7F_FF_FF_FF), rt: Word(1), expectRes: Word(0x80_00_00_00)}, // add t0, s1, s2 + + {name: "addu", funct: 0x21, isImm: false, rs: Word(12), rt: Word(20), expectRes: Word(32)}, // addu t0, s1, s2 + {name: "addu", funct: 0x21, isImm: false, rs: ^Word(0), rt: ^Word(0), expectRes: Word(0xFF_FF_FF_FE)}, // addu t0, s1, s2 + {name: "addu", funct: 0x21, isImm: false, rs: Word(0x7F_FF_FF_FF), rt: Word(0x7F_FF_FF_FF), expectRes: Word(0xFF_FF_FF_FE)}, // addu t0, s1, s2 + {name: "addu", funct: 0x21, isImm: false, rs: ^Word(0), rt: Word(2), expectRes: Word(1)}, // addu t0, s1, s2 + {name: "addu", funct: 0x21, isImm: false, rs: Word(0x7F_FF_FF_FF), rt: Word(1), expectRes: Word(0x80_00_00_00)}, // addu t0, s1, s2 + + {name: "addi", opcode: 0x8, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(44)}, // addi t0, s1, 40 + {name: "addi", opcode: 0x8, isImm: true, rs: ^Word(0), rt: Word(0xAA_BB_CC_DD), imm: uint16(1), expectRes: Word(0)}, // addi t0, s1, 40 + {name: "addi", opcode: 0x8, isImm: true, rs: ^Word(0), rt: Word(0xAA_BB_CC_DD), imm: uint16(0xFF_FF), expectRes: Word(0xFF_FF_FF_FE)}, // addi t0, s1, 40 + {name: "addi sign", opcode: 0x8, isImm: true, rs: Word(2), rt: Word(1), imm: uint16(0xfffe), expectRes: Word(0)}, // addi t0, s1, -2 + + {name: "addiu", opcode: 0x9, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(44)}, // addiu t0, s1, 40 + {name: "addiu", opcode: 0x9, isImm: true, rs: ^Word(0), rt: Word(0xAA_BB_CC_DD), imm: uint16(1), expectRes: Word(0)}, // addiu t0, s1, 40 + {name: "addiu", opcode: 0x9, isImm: true, rs: ^Word(0), rt: Word(0xAA_BB_CC_DD), imm: uint16(0xFF_FF), expectRes: Word(0xFF_FF_FF_FE)}, // addiu t0, s1, 40 + + {name: "sub", funct: 0x22, isImm: false, rs: Word(20), rt: Word(12), expectRes: Word(8)}, // sub t0, s1, s2 + {name: "sub", funct: 0x22, isImm: false, rs: ^Word(0), rt: Word(1), expectRes: Word(0xFF_FF_FF_FE)}, // sub t0, s1, s2 + {name: "sub", funct: 0x22, isImm: false, rs: Word(1), rt: ^Word(0), expectRes: Word(0x2)}, // sub t0, s1, s2 + + {name: "subu", funct: 0x23, isImm: false, rs: Word(20), rt: Word(12), expectRes: Word(8)}, // subu t0, s1, s2 + {name: "subu", funct: 0x23, isImm: false, rs: ^Word(0), rt: Word(1), expectRes: Word(0xFF_FF_FF_FE)}, // subu t0, s1, s2 + {name: "subu", funct: 0x23, isImm: false, rs: Word(1), rt: ^Word(0), expectRes: Word(0x2)}, // subu t0, s1, s2 } + testOperators(t, cases, true) +} - for _, v := range versions { - for i, tt := range cases { - testName := fmt.Sprintf("%v (%v)", tt.name, v.Name) - t.Run(testName, func(t *testing.T) { - goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPC(0), testutil.WithNextPC(4)) - state := goVm.GetState() - var insn uint32 - var baseReg uint32 = 17 - var rtReg uint32 - var rdReg uint32 - if tt.isImm { - rtReg = 8 - insn = tt.opcode<<26 | baseReg<<21 | rtReg<<16 | uint32(tt.imm) - state.GetRegistersRef()[rtReg] = tt.rt - state.GetRegistersRef()[baseReg] = tt.rs - } else { - rtReg = 18 - rdReg = 8 - insn = baseReg<<21 | rtReg<<16 | rdReg<<11 | tt.funct - state.GetRegistersRef()[baseReg] = tt.rs - state.GetRegistersRef()[rtReg] = tt.rt - } - state.GetMemory().SetUint32(0, insn) - step := state.GetStep() - - // Setup expectations - expected := testutil.NewExpectedState(state) - expected.Step += 1 - expected.PC = 4 - expected.NextPC = 8 - if tt.isImm { - expected.Registers[rtReg] = tt.expectRes - } else { - expected.Registers[rdReg] = tt.expectRes - } - - stepWitness, err := goVm.Step(true) - require.NoError(t, err) - - // Check expectations - expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) - }) - } +func TestEVM_SingleStep_Bitwise32(t *testing.T) { + testutil.Cannon32OnlyTest(t, "These tests are fully covered for 64-bits in TestEVM_SingleStep_Bitwise64") + // bitwise operations that use the full word size + cases := []operatorTestCase{ + {name: "and", funct: 0x24, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(160)}, // and t0, s1, s2 + {name: "andi", opcode: 0xc, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(0)}, // andi t0, s1, 40 + {name: "or", funct: 0x25, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(1530)}, // or t0, s1, s2 + {name: "ori", opcode: 0xd, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(44)}, // ori t0, s1, 40 + {name: "xor", funct: 0x26, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(1370)}, // xor t0, s1, s2 + {name: "xori", opcode: 0xe, isImm: true, rs: Word(4), rt: Word(1), imm: uint16(40), expectRes: Word(44)}, // xori t0, s1, 40 + {name: "nor", funct: 0x27, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(4294965765)}, // nor t0, s1, s2 + {name: "slt", funct: 0x2a, isImm: false, rs: 0xFF_FF_FF_FE, rt: Word(5), expectRes: Word(1)}, // slt t0, s1, s2 + {name: "sltu", funct: 0x2b, isImm: false, rs: Word(1200), rt: Word(490), expectRes: Word(0)}, // sltu t0, s1, s2 } + testOperators(t, cases, false) } -func TestEVMSingleStep_LoadStore(t *testing.T) { - var tracer *tracing.Hooks - +func TestEVM_SingleStep_LoadStore32(t *testing.T) { + testutil.Cannon32OnlyTest(t, "These tests are fully covered for 64-bits in TestEVM_SingleStep_LoadStore64") loadMemVal := Word(0x11_22_33_44) loadMemValNeg := Word(0xF1_F2_F3_F4) rtVal := Word(0xaa_bb_cc_dd) - versions := GetMipsVersionTestCases(t) - cases := []struct { - name string - rt Word - base Word - imm uint32 - opcode uint32 - memVal Word - expectMemVal Word - expectRes Word - }{ + cases := []loadStoreTestCase{ {name: "lb, offset=0", opcode: uint32(0x20), base: 0x100, imm: 0x20, memVal: loadMemVal, expectRes: 0x11}, {name: "lb, offset=1", opcode: uint32(0x20), base: 0x100, imm: 0x1, memVal: loadMemVal, expectRes: 0x22}, {name: "lb, offset=2", opcode: uint32(0x20), base: 0x100, imm: 0x2, memVal: loadMemVal, expectRes: 0x33}, @@ -295,49 +245,97 @@ func TestEVMSingleStep_LoadStore(t *testing.T) { {name: "sw", opcode: uint32(0x2b), base: 0x100, imm: 0x20, rt: rtVal, expectMemVal: 0xaa_bb_cc_dd}, {name: "swr unaligned", opcode: uint32(0x2e), base: 0x100, imm: 0x1, rt: rtVal, expectMemVal: 0xcc_dd_00_00}, } + testLoadStore(t, cases) +} + +func TestEVM_SingleStep_Lui(t *testing.T) { + versions := GetMipsVersionTestCases(t) + + cases := []struct { + name string + rtReg uint32 + imm uint32 + expectRt Word + }{ + {name: "lui unsigned", rtReg: 5, imm: 0x1234, expectRt: 0x1234_0000}, + {name: "lui signed", rtReg: 7, imm: 0x8765, expectRt: signExtend64(0x8765_0000)}, + } - var baseReg uint32 = 9 - var rtReg uint32 = 8 - for i, tt := range cases { - for _, v := range versions { + for _, v := range versions { + for i, tt := range cases { testName := fmt.Sprintf("%v (%v)", tt.name, v.Name) t.Run(testName, func(t *testing.T) { - addr := tt.base + Word(tt.imm) - effAddr := arch.AddressMask & addr - - // Setup - goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPC(0), testutil.WithNextPC(4)) + goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i))) state := goVm.GetState() - insn := tt.opcode<<26 | baseReg<<21 | rtReg<<16 | tt.imm - state.GetRegistersRef()[rtReg] = tt.rt - state.GetRegistersRef()[baseReg] = tt.base - state.GetMemory().SetUint32(0, insn) - state.GetMemory().SetWord(effAddr, tt.memVal) + insn := 0b1111<<26 | uint32(tt.rtReg)<<16 | (tt.imm & 0xFFFF) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), insn) step := state.GetStep() // Setup expectations expected := testutil.NewExpectedState(state) expected.ExpectStep() - if tt.expectMemVal != 0 { - expected.ExpectMemoryWriteWord(effAddr, tt.expectMemVal) - } else { - expected.Registers[rtReg] = tt.expectRes - } + expected.Registers[tt.rtReg] = tt.expectRt + stepWitness, err := goVm.Step(true) + require.NoError(t, err) + + // Check expectations + expected.Validate(t, state) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) + }) + } + } +} + +func TestEVM_SingleStep_CloClz(t *testing.T) { + versions := GetMipsVersionTestCases(t) + + rsReg := uint32(5) + rdReg := uint32(6) + cases := []struct { + name string + rs Word + expectedResult Word + funct uint32 + }{ + {name: "clo", rs: 0xFFFF_FFFE, expectedResult: 31, funct: 0b10_0001}, + {name: "clo", rs: 0xE000_0000, expectedResult: 3, funct: 0b10_0001}, + {name: "clo", rs: 0x8000_0000, expectedResult: 1, funct: 0b10_0001}, + {name: "clo, sign-extended", rs: signExtend64(0x8000_0000), expectedResult: 1, funct: 0b10_0001}, + {name: "clo, sign-extended", rs: signExtend64(0xF800_0000), expectedResult: 5, funct: 0b10_0001}, + {name: "clz", rs: 0x1, expectedResult: 31, funct: 0b10_0000}, + {name: "clz", rs: 0x1000_0000, expectedResult: 3, funct: 0b10_0000}, + {name: "clz", rs: 0x8000_0000, expectedResult: 0, funct: 0b10_0000}, + {name: "clz, sign-extended", rs: signExtend64(0x8000_0000), expectedResult: 0, funct: 0b10_0000}, + } - // Run vm + for _, v := range versions { + for i, tt := range cases { + testName := fmt.Sprintf("%v (%v)", tt.name, v.Name) + t.Run(testName, func(t *testing.T) { + // Set up state + goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i))) + state := goVm.GetState() + insn := 0b01_1100<<26 | rsReg<<21 | rdReg<<11 | tt.funct + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), insn) + state.GetRegistersRef()[rsReg] = tt.rs + step := state.GetStep() + + // Setup expectations + expected := testutil.NewExpectedState(state) + expected.ExpectStep() + expected.Registers[rdReg] = tt.expectedResult stepWitness, err := goVm.Step(true) require.NoError(t, err) - // Validate + // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } } } -func TestEVMSingleStep_MovzMovn(t *testing.T) { - var tracer *tracing.Hooks +func TestEVM_SingleStep_MovzMovn(t *testing.T) { versions := GetMipsVersionTestCases(t) cases := []struct { name string @@ -365,7 +363,7 @@ func TestEVMSingleStep_MovzMovn(t *testing.T) { state.GetRegistersRef()[rtReg] = t2 state.GetRegistersRef()[rsReg] = Word(0xb) state.GetRegistersRef()[rdReg] = Word(0xa) - state.GetMemory().SetUint32(0, insn) + testutil.StoreInstruction(state.GetMemory(), 0, insn) step := state.GetStep() // Setup expectations expected := testutil.NewExpectedState(state) @@ -376,7 +374,7 @@ func TestEVMSingleStep_MovzMovn(t *testing.T) { require.NoError(t, err) // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) if tt.funct == 0xa { t2 = 0x1 @@ -392,15 +390,14 @@ func TestEVMSingleStep_MovzMovn(t *testing.T) { require.NoError(t, err) // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } } } -func TestEVMSingleStep_MfhiMflo(t *testing.T) { - var tracer *tracing.Hooks +func TestEVM_SingleStep_MfhiMflo(t *testing.T) { versions := GetMipsVersionTestCases(t) cases := []struct { name string @@ -420,7 +417,7 @@ func TestEVMSingleStep_MfhiMflo(t *testing.T) { state := goVm.GetState() rdReg := uint32(8) insn := rdReg<<11 | tt.funct - state.GetMemory().SetUint32(state.GetPC(), insn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), insn) step := state.GetStep() // Setup expectations expected := testutil.NewExpectedState(state) @@ -430,36 +427,137 @@ func TestEVMSingleStep_MfhiMflo(t *testing.T) { require.NoError(t, err) // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } } } -func TestEVMSingleStep_MulDiv(t *testing.T) { - var tracer *tracing.Hooks +func TestEVM_SingleStep_MulDiv(t *testing.T) { + cases := []mulDivTestCase{ + {name: "mul", funct: uint32(0x2), opcode: uint32(28), rs: Word(5), rt: Word(2), rdReg: uint32(0x8), expectRes: Word(10)}, // mul t0, t1, t2 + {name: "mul", funct: uint32(0x2), opcode: uint32(28), rs: Word(0x1), rt: ^Word(0), rdReg: uint32(0x8), expectRes: ^Word(0)}, // mul t1, t2 + {name: "mul", funct: uint32(0x2), opcode: uint32(28), rs: Word(0xFF_FF_FF_FF), rt: Word(0xFF_FF_FF_FF), rdReg: uint32(0x8), expectRes: Word(0x1)}, // mul t1, t2 + {name: "mul", funct: uint32(0x2), opcode: uint32(28), rs: Word(0xFF_FF_FF_D3), rt: Word(0xAA_BB_CC_DD), rdReg: uint32(0x8), expectRes: Word(0xFC_FC_FD_27)}, // mul t1, t2 + + {name: "mult", funct: uint32(0x18), rs: Word(0x0F_FF_00_00), rt: Word(100), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(0x6), expectLo: Word(0x3F_9C_00_00)}, // mult t1, t2 + {name: "mult", funct: uint32(0x18), rs: Word(0x1), rt: Word(0xFF_FF_FF_FF), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(0xFF_FF_FF_FF), expectLo: Word(0xFF_FF_FF_FF)}, // mult t1, t2 + {name: "mult", funct: uint32(0x18), rs: Word(0xFF_FF_FF_FF), rt: Word(0xFF_FF_FF_FF), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(0), expectLo: Word(0x1)}, // mult t1, t2 + {name: "mult", funct: uint32(0x18), rs: Word(0xFF_FF_FF_D3), rt: Word(0xAA_BB_CC_DD), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(0xE), expectLo: Word(0xFC_FC_FD_27)}, // mult t1, t2 + + {name: "multu", funct: uint32(0x19), rs: Word(0x0F_FF_00_00), rt: Word(100), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(0x6), expectLo: Word(0x3F_9C_00_00)}, // multu t1, t2 + {name: "multu", funct: uint32(0x19), rs: Word(0x1), rt: Word(0xFF_FF_FF_FF), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(0x0), expectLo: Word(0xFF_FF_FF_FF)}, // multu t1, t2 + {name: "multu", funct: uint32(0x19), rs: Word(0xFF_FF_FF_FF), rt: Word(0xFF_FF_FF_FF), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(0xFF_FF_FF_FE), expectLo: Word(0x1)}, // multu t1, t2 + {name: "multu", funct: uint32(0x19), rs: Word(0xFF_FF_FF_D3), rt: Word(0xAA_BB_CC_DD), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(0xAA_BB_CC_BE), expectLo: Word(0xFC_FC_FD_27)}, // multu t1, t2 + {name: "multu", funct: uint32(0x19), rs: Word(0xFF_FF_FF_D3), rt: Word(0xAA_BB_CC_BE), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(0xAA_BB_CC_9F), expectLo: Word(0xFC_FD_02_9A)}, // multu t1, t2 + + {name: "div", funct: uint32(0x1a), rs: Word(5), rt: Word(2), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(1), expectLo: Word(2)}, // div t1, t2 + {name: "div by zero", funct: uint32(0x1a), rs: Word(5), rt: Word(0), rdReg: uint32(0x0), opcode: uint32(0), panicMsg: "instruction divide by zero", revertMsg: "division by zero"}, // div t1, t2 + {name: "divu", funct: uint32(0x1b), rs: Word(5), rt: Word(2), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(1), expectLo: Word(2)}, // divu t1, t2 + {name: "divu by zero", funct: uint32(0x1b), rs: Word(5), rt: Word(0), rdReg: uint32(0x0), opcode: uint32(0), panicMsg: "instruction divide by zero", revertMsg: "division by zero"}, // divu t1, t2 + } + testMulDiv(t, cases, true) +} + +func TestEVM_SingleStep_MthiMtlo(t *testing.T) { versions := GetMipsVersionTestCases(t) cases := []struct { - name string - rs Word - rt Word - funct uint32 - opcode uint32 - expectHi Word - expectLo Word - expectRes Word - rdReg uint32 - expectRevert bool - errMsg string + name string + funct uint32 + }{ + {name: "mtlo", funct: uint32(0x13)}, + {name: "mthi", funct: uint32(0x11)}, + } + val := Word(0xdeadbeef) + for _, v := range versions { + for i, tt := range cases { + testName := fmt.Sprintf("%v (%v)", tt.name, v.Name) + t.Run(testName, func(t *testing.T) { + + goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i))) + state := goVm.GetState() + rsReg := uint32(8) + insn := rsReg<<21 | tt.funct + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), insn) + state.GetRegistersRef()[rsReg] = val + step := state.GetStep() + // Setup expectations + expected := testutil.NewExpectedState(state) + expected.ExpectStep() + if tt.funct == 0x11 { + expected.HI = state.GetRegistersRef()[rsReg] + } else { + expected.LO = state.GetRegistersRef()[rsReg] + } + stepWitness, err := goVm.Step(true) + require.NoError(t, err) + // Check expectations + expected.Validate(t, state) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) + }) + } + } +} + +func TestEVM_SingleStep_BeqBne(t *testing.T) { + versions := GetMipsVersionTestCases(t) + cases := []struct { + name string + imm uint32 + opcode uint32 + rs Word + rt Word + }{ + {name: "bne", opcode: uint32(0x5), imm: uint32(0x10), rs: Word(0xaa), rt: Word(0xdeadbeef)}, // bne $t0, $t1, 16 + {name: "beq", opcode: uint32(0x4), imm: uint32(0x10), rs: Word(0xdeadbeef), rt: Word(0xdeadbeef)}, // beq $t0, $t1, 16 + } + for _, v := range versions { + for i, tt := range cases { + testName := fmt.Sprintf("%v (%v)", tt.name, v.Name) + t.Run(testName, func(t *testing.T) { + goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPC(0), testutil.WithNextPC(4)) + state := goVm.GetState() + rsReg := uint32(9) + rtReg := uint32(8) + insn := tt.opcode<<26 | rsReg<<21 | rtReg<<16 | tt.imm + state.GetRegistersRef()[rtReg] = tt.rt + state.GetRegistersRef()[rsReg] = tt.rs + testutil.StoreInstruction(state.GetMemory(), 0, insn) + step := state.GetStep() + // Setup expectations + expected := testutil.NewExpectedState(state) + expected.Step = state.GetStep() + 1 + expected.PC = state.GetCpu().NextPC + expected.NextPC = state.GetCpu().NextPC + Word(tt.imm<<2) + + stepWitness, err := goVm.Step(true) + require.NoError(t, err) + // Check expectations + expected.Validate(t, state) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) + }) + } + } + +} + +func TestEVM_SingleStep_SlSr(t *testing.T) { + versions := GetMipsVersionTestCases(t) + cases := []struct { + name string + rs Word + rt Word + rsReg uint32 + funct uint16 + expectVal Word }{ - {name: "mul", funct: uint32(0x2), rs: Word(5), rt: Word(2), opcode: uint32(28), rdReg: uint32(0x8), expectRes: Word(10), expectRevert: false}, // mul t0, t1, t2 - {name: "mult", funct: uint32(0x18), rs: Word(0x0F_FF_00_00), rt: Word(100), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(0x6), expectLo: Word(0x3F_9C_00_00), expectRevert: false}, // mult t1, t2 - {name: "multu", funct: uint32(0x19), rs: Word(0x0F_FF_00_00), rt: Word(100), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(0x6), expectLo: Word(0x3F_9C_00_00), expectRevert: false}, // multu t1, t2 - {name: "div", funct: uint32(0x1a), rs: Word(5), rt: Word(2), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(1), expectLo: Word(2), expectRevert: false}, // div t1, t2 - {name: "div by zero", funct: uint32(0x1a), rs: Word(5), rt: Word(0), rdReg: uint32(0x0), opcode: uint32(0), expectRevert: true, errMsg: "MIPS: division by zero"}, // div t1, t2 - {name: "divu", funct: uint32(0x1b), rs: Word(5), rt: Word(2), rdReg: uint32(0x0), opcode: uint32(0), expectHi: Word(1), expectLo: Word(2), expectRevert: false}, // divu t1, t2 - {name: "divu by zero", funct: uint32(0x1b), rs: Word(5), rt: Word(0), rdReg: uint32(0x0), opcode: uint32(0), expectRevert: true, errMsg: "MIPS: division by zero"}, // divu t1, t2 + {name: "sll", funct: uint16(4) << 6, rt: Word(0x20), rsReg: uint32(0x0), expectVal: Word(0x20) << uint8(4)}, // sll t0, t1, 3 + {name: "srl", funct: uint16(4)<<6 | 2, rt: Word(0x20), rsReg: uint32(0x0), expectVal: Word(0x20) >> uint8(4)}, // srl t0, t1, 3 + {name: "sra", funct: uint16(4)<<6 | 3, rt: Word(0x80_00_00_20), rsReg: uint32(0x0), expectVal: signExtend64(0xF8_00_00_02)}, // sra t0, t1, 3 + {name: "sllv", funct: uint16(4), rt: Word(0x20), rs: Word(4), rsReg: uint32(0xa), expectVal: Word(0x20) << Word(4)}, // sllv t0, t1, t2 + {name: "srlv", funct: uint16(6), rt: Word(0x20_00), rs: Word(4), rsReg: uint32(0xa), expectVal: Word(0x20_00) >> Word(4)}, // srlv t0, t1, t2 + {name: "srav", funct: uint16(7), rt: Word(0xdeafbeef), rs: Word(12), rsReg: uint32(0xa), expectVal: signExtend64(Word(0xfffdeafb))}, // srav t0, t1, t2 } for _, v := range versions { @@ -469,90 +567,73 @@ func TestEVMSingleStep_MulDiv(t *testing.T) { goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPC(0), testutil.WithNextPC(4)) state := goVm.GetState() var insn uint32 - baseReg := uint32(0x9) - rtReg := uint32(0xa) - - insn = tt.opcode<<26 | baseReg<<21 | rtReg<<16 | tt.rdReg<<11 | tt.funct + rtReg := uint32(0x9) + rdReg := uint32(0x8) + insn = tt.rsReg<<21 | rtReg<<16 | rdReg<<11 | uint32(tt.funct) state.GetRegistersRef()[rtReg] = tt.rt - state.GetRegistersRef()[baseReg] = tt.rs - state.GetMemory().SetUint32(0, insn) - - if tt.expectRevert { - proofData := v.ProofGenerator(t, goVm.GetState()) - require.Panics(t, func() { - _, _ = goVm.Step( - false) - }) - testutil.AssertEVMReverts(t, state, v.Contracts, tracer, proofData, tt.errMsg) - return - } - + state.GetRegistersRef()[tt.rsReg] = tt.rs + testutil.StoreInstruction(state.GetMemory(), 0, insn) step := state.GetStep() + // Setup expectations expected := testutil.NewExpectedState(state) expected.ExpectStep() - if tt.expectRes != 0 { - expected.Registers[tt.rdReg] = tt.expectRes - } else { - expected.HI = tt.expectHi - expected.LO = tt.expectLo - } + + expected.Registers[rdReg] = tt.expectVal stepWitness, err := goVm.Step(true) require.NoError(t, err) // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } } } -func TestEVMSingleStep_MthiMtlo(t *testing.T) { - var tracer *tracing.Hooks +func TestEVM_SingleStep_JrJalr(t *testing.T) { versions := GetMipsVersionTestCases(t) cases := []struct { - name string - funct uint32 + name string + funct uint16 + rdReg uint32 + expectLink bool }{ - {name: "mtlo", funct: uint32(0x13)}, - {name: "mthi", funct: uint32(0x11)}, + {name: "jr", funct: uint16(0x8), rdReg: uint32(0)}, // jr t0 + {name: "jalr", funct: uint16(0x9), rdReg: uint32(0x9), expectLink: true}, // jalr t1, t0 } - val := Word(0xdeadbeef) for _, v := range versions { for i, tt := range cases { testName := fmt.Sprintf("%v (%v)", tt.name, v.Name) t.Run(testName, func(t *testing.T) { - - goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i))) + goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPC(0), testutil.WithNextPC(4)) state := goVm.GetState() rsReg := uint32(8) - insn := rsReg<<21 | tt.funct - state.GetMemory().SetUint32(state.GetPC(), insn) - state.GetRegistersRef()[rsReg] = val + insn := rsReg<<21 | tt.rdReg<<11 | uint32(tt.funct) + state.GetRegistersRef()[rsReg] = Word(0x34) + testutil.StoreInstruction(state.GetMemory(), 0, insn) step := state.GetStep() // Setup expectations expected := testutil.NewExpectedState(state) - expected.ExpectStep() - if tt.funct == 0x11 { - expected.HI = state.GetRegistersRef()[rsReg] - } else { - expected.LO = state.GetRegistersRef()[rsReg] + expected.Step = state.GetStep() + 1 + expected.PC = state.GetCpu().NextPC + expected.NextPC = state.GetRegistersRef()[rsReg] + if tt.expectLink { + expected.Registers[tt.rdReg] = state.GetPC() + 8 } + stepWitness, err := goVm.Step(true) require.NoError(t, err) // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } } } func TestEVM_MMap(t *testing.T) { - var tracer *tracing.Hooks - versions := GetMipsVersionTestCases(t) cases := []struct { name string @@ -580,7 +661,7 @@ func TestEVM_MMap(t *testing.T) { goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithHeap(c.heap)) state := goVm.GetState() - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysMmap state.GetRegistersRef()[4] = c.address state.GetRegistersRef()[5] = c.size @@ -609,15 +690,13 @@ func TestEVM_MMap(t *testing.T) { // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } } } -func TestEVMSysWriteHint(t *testing.T) { - var tracer *tracing.Hooks - +func TestEVM_SysWriteHint(t *testing.T) { versions := GetMipsVersionTestCases(t) cases := []struct { name string @@ -788,7 +867,7 @@ func TestEVMSysWriteHint(t *testing.T) { err := state.GetMemory().SetMemoryRange(arch.Word(tt.memOffset), bytes.NewReader(tt.hintData)) require.NoError(t, err) - state.GetMemory().SetUint32(state.GetPC(), insn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), insn) step := state.GetStep() expected := testutil.NewExpectedState(state) @@ -804,35 +883,50 @@ func TestEVMSysWriteHint(t *testing.T) { expected.Validate(t, state) require.Equal(t, tt.expectedHints, oracle.Hints()) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } } } -func TestEVMFault(t *testing.T) { +func TestEVM_Fault(t *testing.T) { var tracer *tracing.Hooks // no-tracer by default, but see test_util.MarkdownTracer versions := GetMipsVersionTestCases(t) + + misAlignedInstructionErr := func() testutil.ErrMatcher { + if arch.IsMips32 { + // matches revert(0,0) + return testutil.CreateNoopErrorMatcher() + } else { + return testutil.CreateCustomErrorMatcher("InvalidPC()") + } + } + cases := []struct { name string + pc arch.Word nextPC arch.Word insn uint32 - errMsg string + errMsg testutil.ErrMatcher memoryProofAddresses []Word }{ - {"illegal instruction", 0, 0xFF_FF_FF_FF, "invalid instruction", []Word{0xa7ef00cc}}, - {"branch in delay-slot", 8, 0x11_02_00_03, "branch in delay slot", []Word{}}, - {"jump in delay-slot", 8, 0x0c_00_00_0c, "jump in delay slot", []Word{}}, + {name: "illegal instruction", nextPC: 0, insn: 0b111110 << 26, errMsg: testutil.CreateErrorStringMatcher("invalid instruction"), memoryProofAddresses: []Word{0x0}}, // memoryProof for the zero address at register 0 (+ imm) + {name: "branch in delay-slot", nextPC: 8, insn: 0x11_02_00_03, errMsg: testutil.CreateErrorStringMatcher("branch in delay slot")}, + {name: "jump in delay-slot", nextPC: 8, insn: 0x0c_00_00_0c, errMsg: testutil.CreateErrorStringMatcher("jump in delay slot")}, + {name: "misaligned instruction", pc: 1, nextPC: 4, insn: 0b110111_00001_00001 << 16, errMsg: misAlignedInstructionErr()}, + {name: "misaligned instruction", pc: 2, nextPC: 4, insn: 0b110111_00001_00001 << 16, errMsg: misAlignedInstructionErr()}, + {name: "misaligned instruction", pc: 3, nextPC: 4, insn: 0b110111_00001_00001 << 16, errMsg: misAlignedInstructionErr()}, + {name: "misaligned instruction", pc: 5, nextPC: 4, insn: 0b110111_00001_00001 << 16, errMsg: misAlignedInstructionErr()}, } for _, v := range versions { for _, tt := range cases { testName := fmt.Sprintf("%v (%v)", tt.name, v.Name) t.Run(testName, func(t *testing.T) { - goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithNextPC(tt.nextPC)) + goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithPC(tt.pc), testutil.WithNextPC(tt.nextPC)) state := goVm.GetState() - state.GetMemory().SetUint32(0, tt.insn) + testutil.StoreInstruction(state.GetMemory(), 0, tt.insn) // set the return address ($ra) to jump into when test completes state.GetRegistersRef()[31] = testutil.EndAddr @@ -844,43 +938,39 @@ func TestEVMFault(t *testing.T) { } } -func TestHelloEVM(t *testing.T) { +func TestEVM_HelloProgram(t *testing.T) { + if os.Getenv("SKIP_SLOW_TESTS") == "true" { + t.Skip("Skipping slow test because SKIP_SLOW_TESTS is enabled") + } + t.Parallel() - var tracer *tracing.Hooks // no-tracer by default, but see test_util.MarkdownTracer versions := GetMipsVersionTestCases(t) for _, v := range versions { v := v t.Run(v.Name, func(t *testing.T) { t.Parallel() - evm := testutil.NewMIPSEVM(v.Contracts) - evm.SetTracer(tracer) - testutil.LogStepFailureAtCleanup(t, evm) + validator := testutil.NewEvmValidator(t, v.StateHashFn, v.Contracts) var stdOutBuf, stdErrBuf bytes.Buffer - elfFile := "../../testdata/example/bin/hello.elf" + elfFile := testutil.ProgramPath("hello") goVm := v.ElfVMFactory(t, elfFile, nil, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr), testutil.CreateLogger()) state := goVm.GetState() start := time.Now() - for i := 0; i < 400_000; i++ { + for i := 0; i < 430_000; i++ { step := goVm.GetState().GetStep() if goVm.GetState().GetExited() { break } - insn := state.GetMemory().GetUint32(state.GetPC()) - if i%1000 == 0 { // avoid spamming test logs, we are executing many steps + insn := testutil.GetInstruction(state.GetMemory(), state.GetPC()) + if i%10_000 == 0 { // avoid spamming test logs, we are executing many steps t.Logf("step: %4d pc: 0x%08x insn: 0x%08x", state.GetStep(), state.GetPC(), insn) } stepWitness, err := goVm.Step(true) require.NoError(t, err) - evmPost := evm.Step(t, stepWitness, step, v.StateHashFn) - // verify the post-state matches. - // TODO: maybe more readable to decode the evmPost state, and do attribute-wise comparison. - goPost, _ := goVm.GetState().EncodeWitness() - require.Equalf(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), - "mipsevm produced different state than EVM. insn: %x", insn) + validator.ValidateEVM(t, stepWitness, step, goVm) } end := time.Now() delta := end.Sub(start) @@ -895,23 +985,23 @@ func TestHelloEVM(t *testing.T) { } } -func TestClaimEVM(t *testing.T) { +func TestEVM_ClaimProgram(t *testing.T) { + if os.Getenv("SKIP_SLOW_TESTS") == "true" { + t.Skip("Skipping slow test because SKIP_SLOW_TESTS is enabled") + } + t.Parallel() - var tracer *tracing.Hooks // no-tracer by default, but see test_util.MarkdownTracer versions := GetMipsVersionTestCases(t) for _, v := range versions { v := v t.Run(v.Name, func(t *testing.T) { t.Parallel() - evm := testutil.NewMIPSEVM(v.Contracts) - evm.SetTracer(tracer) - testutil.LogStepFailureAtCleanup(t, evm) - + validator := testutil.NewEvmValidator(t, v.StateHashFn, v.Contracts) oracle, expectedStdOut, expectedStdErr := testutil.ClaimTestOracle(t) var stdOutBuf, stdErrBuf bytes.Buffer - elfFile := "../../testdata/example/bin/claim.elf" + elfFile := testutil.ProgramPath("claim") goVm := v.ElfVMFactory(t, elfFile, oracle, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr), testutil.CreateLogger()) state := goVm.GetState() @@ -921,19 +1011,14 @@ func TestClaimEVM(t *testing.T) { break } - insn := state.GetMemory().GetUint32(state.GetPC()) - if i%1000 == 0 { // avoid spamming test logs, we are executing many steps + insn := testutil.GetInstruction(state.GetMemory(), state.GetPC()) + if i%10_000 == 0 { // avoid spamming test logs, we are executing many steps t.Logf("step: %4d pc: 0x%08x insn: 0x%08x", state.GetStep(), state.GetPC(), insn) } stepWitness, err := goVm.Step(true) require.NoError(t, err) - - evmPost := evm.Step(t, stepWitness, curStep, v.StateHashFn) - - goPost, _ := goVm.GetState().EncodeWitness() - require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), - "mipsevm produced different state than EVM") + validator.ValidateEVM(t, stepWitness, curStep, goVm) } require.True(t, state.GetExited(), "must complete program") @@ -945,42 +1030,39 @@ func TestClaimEVM(t *testing.T) { } } -func TestEntryEVM(t *testing.T) { +func TestEVM_EntryProgram(t *testing.T) { + if os.Getenv("SKIP_SLOW_TESTS") == "true" { + t.Skip("Skipping slow test because SKIP_SLOW_TESTS is enabled") + } + t.Parallel() - var tracer *tracing.Hooks // no-tracer by default, but see test_util.MarkdownTracer versions := GetMipsVersionTestCases(t) for _, v := range versions { v := v t.Run(v.Name, func(t *testing.T) { t.Parallel() - evm := testutil.NewMIPSEVM(v.Contracts) - evm.SetTracer(tracer) - testutil.LogStepFailureAtCleanup(t, evm) + validator := testutil.NewEvmValidator(t, v.StateHashFn, v.Contracts) var stdOutBuf, stdErrBuf bytes.Buffer - elfFile := "../../testdata/example/bin/entry.elf" + elfFile := testutil.ProgramPath("entry") goVm := v.ElfVMFactory(t, elfFile, nil, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr), testutil.CreateLogger()) state := goVm.GetState() start := time.Now() - for i := 0; i < 400_000; i++ { + for i := 0; i < 500_000; i++ { curStep := goVm.GetState().GetStep() if goVm.GetState().GetExited() { break } - insn := state.GetMemory().GetUint32(state.GetPC()) + insn := testutil.GetInstruction(state.GetMemory(), state.GetPC()) if i%10_000 == 0 { // avoid spamming test logs, we are executing many steps t.Logf("step: %4d pc: 0x%08x insn: 0x%08x", state.GetStep(), state.GetPC(), insn) } stepWitness, err := goVm.Step(true) require.NoError(t, err) - evmPost := evm.Step(t, stepWitness, curStep, v.StateHashFn) - // verify the post-state matches. - goPost, _ := goVm.GetState().EncodeWitness() - require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), - "mipsevm produced different state than EVM") + validator.ValidateEVM(t, stepWitness, curStep, goVm) } end := time.Now() delta := end.Sub(start) @@ -991,3 +1073,63 @@ func TestEntryEVM(t *testing.T) { }) } } + +func TestEVM_SingleStep_Branch32(t *testing.T) { + testutil.Cannon32OnlyTest(t, "These tests are fully covered for 64-bits in TestEVM_SingleStep_Branch64") + t.Parallel() + cases := []branchTestCase{ + // blez + {name: "blez", pc: 0, opcode: 0x6, rs: 0x5, offset: 0x100, expectNextPC: 0x8}, + {name: "blez large rs", pc: 0x10, opcode: 0x6, rs: 0x7F_FF_FF_FF, offset: 0x100, expectNextPC: 0x18}, + {name: "blez zero rs", pc: 0x10, opcode: 0x6, rs: 0x0, offset: 0x100, expectNextPC: 0x414}, + {name: "blez sign rs", pc: 0x10, opcode: 0x6, rs: -1, offset: 0x100, expectNextPC: 0x414}, + {name: "blez rs only sign bit set", pc: 0x10, opcode: 0x6, rs: testutil.ToSignedInteger(0x80_00_00_00), offset: 0x100, expectNextPC: 0x414}, + {name: "blez sign-extended offset", pc: 0x10, opcode: 0x6, rs: -1, offset: 0x80_00, expectNextPC: 0xFF_FE_00_14}, + + // bgtz + {name: "bgtz", pc: 0, opcode: 0x7, rs: 0x5, offset: 0x100, expectNextPC: 0x404}, + {name: "bgtz sign-extended offset", pc: 0x10, opcode: 0x7, rs: 0x5, offset: 0x80_00, expectNextPC: 0xFF_FE_00_14}, + {name: "bgtz large rs", pc: 0x10, opcode: 0x7, rs: 0x7F_FF_FF_FF, offset: 0x100, expectNextPC: 0x414}, + {name: "bgtz zero rs", pc: 0x10, opcode: 0x7, rs: 0x0, offset: 0x100, expectNextPC: 0x18}, + {name: "bgtz sign rs", pc: 0x10, opcode: 0x7, rs: -1, offset: 0x100, expectNextPC: 0x18}, + {name: "bgtz rs only sign bit set", pc: 0x10, opcode: 0x7, rs: testutil.ToSignedInteger(0x80_00_00_00), offset: 0x100, expectNextPC: 0x18}, + + // bltz t0, $x + {name: "bltz", pc: 0, opcode: 0x1, regimm: 0x0, rs: 0x5, offset: 0x100, expectNextPC: 0x8}, + {name: "bltz large rs", pc: 0x10, opcode: 0x1, regimm: 0x0, rs: 0x7F_FF_FF_FF, offset: 0x100, expectNextPC: 0x18}, + {name: "bltz zero rs", pc: 0x10, opcode: 0x1, regimm: 0x0, rs: 0x0, offset: 0x100, expectNextPC: 0x18}, + {name: "bltz sign rs", pc: 0x10, opcode: 0x1, regimm: 0x0, rs: -1, offset: 0x100, expectNextPC: 0x414}, + {name: "bltz rs only sign bit set", pc: 0x10, opcode: 0x1, regimm: 0x0, rs: testutil.ToSignedInteger(0x80_00_00_00), offset: 0x100, expectNextPC: 0x414}, + {name: "bltz sign-extended offset", pc: 0x10, opcode: 0x1, regimm: 0x0, rs: -1, offset: 0x80_00, expectNextPC: 0xFF_FE_00_14}, + {name: "bltz large offset no-sign", pc: 0x10, opcode: 0x1, regimm: 0x0, rs: -1, offset: 0x7F_FF, expectNextPC: 0x2_00_10}, + + // bltzal t0, $x + {name: "bltzal", pc: 0, opcode: 0x1, regimm: 0x10, rs: 0x5, offset: 0x100, expectNextPC: 0x8, expectLink: true}, + {name: "bltzal large rs", pc: 0x10, opcode: 0x1, regimm: 0x10, rs: 0x7F_FF_FF_FF, offset: 0x100, expectNextPC: 0x18, expectLink: true}, + {name: "bltzal zero rs", pc: 0x10, opcode: 0x1, regimm: 0x10, rs: 0x0, offset: 0x100, expectNextPC: 0x18, expectLink: true}, + {name: "bltzal sign rs", pc: 0x10, opcode: 0x1, regimm: 0x10, rs: -1, offset: 0x100, expectNextPC: 0x414, expectLink: true}, + {name: "bltzal rs only sign bit set", pc: 0x10, opcode: 0x1, regimm: 0x10, rs: testutil.ToSignedInteger(0x80_00_00_00), offset: 0x100, expectNextPC: 0x414, expectLink: true}, + {name: "bltzal sign-extended offset", pc: 0x10, opcode: 0x1, regimm: 0x10, rs: -1, offset: 0x80_00, expectNextPC: 0xFF_FE_00_14, expectLink: true}, + {name: "bltzal large offset no-sign", pc: 0x10, opcode: 0x1, regimm: 0x10, rs: -1, offset: 0x7F_FF, expectNextPC: 0x2_00_10, expectLink: true}, + + // bgez t0, $x + {name: "bgez", pc: 0, opcode: 0x1, regimm: 0x1, rs: 0x5, offset: 0x100, expectNextPC: 0x404}, + {name: "bgez large rs", pc: 0x10, opcode: 0x1, regimm: 0x1, rs: 0x7F_FF_FF_FF, offset: 0x100, expectNextPC: 0x414}, + {name: "bgez zero rs", pc: 0x10, opcode: 0x1, regimm: 0x1, rs: 0x0, offset: 0x100, expectNextPC: 0x414}, + {name: "bgez branch not taken", pc: 0x10, opcode: 0x1, regimm: 0x1, rs: -1, offset: 0x100, expectNextPC: 0x18}, + {name: "bgez sign-extended offset", pc: 0x10, opcode: 0x1, regimm: 0x1, rs: 1, offset: 0x80_00, expectNextPC: 0xFF_FE_00_14}, + {name: "bgez large offset no-sign", pc: 0x10, opcode: 0x1, regimm: 0x1, rs: 1, offset: 0x70_00, expectNextPC: 0x1_C0_14}, + {name: "bgez fill bit offset except sign", pc: 0x10, opcode: 0x1, regimm: 0x1, rs: 1, offset: 0x7F_FF, expectNextPC: 0x2_00_10}, + + // bgezal t0, $x + {name: "bgezal", pc: 0, opcode: 0x1, regimm: 0x11, rs: 0x5, offset: 0x100, expectNextPC: 0x404, expectLink: true}, + {name: "bgezal large rs", pc: 0x10, opcode: 0x1, regimm: 0x11, rs: 0x7F_FF_FF_FF, offset: 0x100, expectNextPC: 0x414, expectLink: true}, + {name: "bgezal zero rs", pc: 0x10, opcode: 0x1, regimm: 0x11, rs: 0x0, offset: 0x100, expectNextPC: 0x414, expectLink: true}, + {name: "bgezal branch not taken", pc: 0x10, opcode: 0x1, regimm: 0x11, rs: -1, offset: 0x100, expectNextPC: 0x18, expectLink: true}, + {name: "bgezal sign-extended offset", pc: 0x10, opcode: 0x1, regimm: 0x11, rs: 1, offset: 0x80_00, expectNextPC: 0xFF_FE_00_14, expectLink: true}, + {name: "bgezal large offset no-sign", pc: 0x10, opcode: 0x1, regimm: 0x11, rs: 1, offset: 0x70_00, expectNextPC: 0x1_C0_14, expectLink: true}, + {name: "bgezal fill bit offset except sign", pc: 0x10, opcode: 0x1, regimm: 0x11, rs: 1, offset: 0x7F_FF, expectNextPC: 0x2_00_10, expectLink: true}, + } + + testBranch(t, cases) +} diff --git a/cannon/mipsevm/tests/evm_multithreaded64_test.go b/cannon/mipsevm/tests/evm_multithreaded64_test.go index a8c891b1d2528..911a0d256a3c6 100644 --- a/cannon/mipsevm/tests/evm_multithreaded64_test.go +++ b/cannon/mipsevm/tests/evm_multithreaded64_test.go @@ -5,11 +5,13 @@ package tests import ( + "encoding/binary" "fmt" + "slices" "testing" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/stretchr/testify/require" + "golang.org/x/exp/maps" "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" "github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded" @@ -18,8 +20,6 @@ import ( ) func TestEVM_MT64_LL(t *testing.T) { - var tracer *tracing.Hooks - memVal := Word(0x11223344_55667788) memValNeg := Word(0xF1223344_F5667788) cases := []struct { @@ -56,7 +56,7 @@ func TestEVM_MT64_LL(t *testing.T) { step := state.GetStep() // Set up state - state.GetMemory().SetUint32(state.GetPC(), insn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), insn) state.GetMemory().SetWord(effAddr, c.memVal) state.GetRegistersRef()[baseReg] = c.base if withExistingReservation { @@ -84,15 +84,13 @@ func TestEVM_MT64_LL(t *testing.T) { // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } } func TestEVM_MT64_SC(t *testing.T) { - var tracer *tracing.Hooks - llVariations := []struct { name string llReservationStatus multithreaded.LLReservationStatus @@ -158,7 +156,7 @@ func TestEVM_MT64_SC(t *testing.T) { // Setup state state.GetCurrentThread().ThreadId = c.threadId - state.GetMemory().SetUint32(state.GetPC(), insn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), insn) state.GetRegistersRef()[baseReg] = c.base state.GetRegistersRef()[rtReg] = c.value state.LLReservationStatus = v.llReservationStatus @@ -187,15 +185,13 @@ func TestEVM_MT64_SC(t *testing.T) { // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } } func TestEVM_MT64_LLD(t *testing.T) { - var tracer *tracing.Hooks - memVal := Word(0x11223344_55667788) memValNeg := Word(0xF1223344_F5667788) cases := []struct { @@ -232,7 +228,7 @@ func TestEVM_MT64_LLD(t *testing.T) { step := state.GetStep() // Set up state - state.GetMemory().SetUint32(state.GetPC(), insn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), insn) state.GetMemory().SetWord(effAddr, c.memVal) state.GetRegistersRef()[baseReg] = c.base if withExistingReservation { @@ -260,15 +256,13 @@ func TestEVM_MT64_LLD(t *testing.T) { // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } } func TestEVM_MT64_SCD(t *testing.T) { - var tracer *tracing.Hooks - value := Word(0x11223344_55667788) llVariations := []struct { name string @@ -335,7 +329,7 @@ func TestEVM_MT64_SCD(t *testing.T) { // Setup state state.GetCurrentThread().ThreadId = c.threadId - state.GetMemory().SetUint32(state.GetPC(), insn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), insn) state.GetRegistersRef()[baseReg] = c.base state.GetRegistersRef()[rtReg] = value state.LLReservationStatus = v.llReservationStatus @@ -364,8 +358,127 @@ func TestEVM_MT64_SCD(t *testing.T) { // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } } + +func TestEVM_MT_SysRead_Preimage64(t *testing.T) { + preimageValue := make([]byte, 0, 8) + preimageValue = binary.BigEndian.AppendUint32(preimageValue, 0x12_34_56_78) + preimageValue = binary.BigEndian.AppendUint32(preimageValue, 0x98_76_54_32) + prestateMem := Word(0xEE_EE_EE_EE_FF_FF_FF_FF) + cases := []testMTSysReadPreimageTestCase{ + {name: "Aligned addr, write 1 byte", addr: 0x00_00_FF_00, count: 1, writeLen: 1, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0x12_EE_EE_EE_FF_FF_FF_FF}, + {name: "Aligned addr, write 2 byte", addr: 0x00_00_FF_00, count: 2, writeLen: 2, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0x12_34_EE_EE_FF_FF_FF_FF}, + {name: "Aligned addr, write 3 byte", addr: 0x00_00_FF_00, count: 3, writeLen: 3, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0x12_34_56_EE_FF_FF_FF_FF}, + {name: "Aligned addr, write 4 byte", addr: 0x00_00_FF_00, count: 4, writeLen: 4, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0x12_34_56_78_FF_FF_FF_FF}, + {name: "Aligned addr, write 5 byte", addr: 0x00_00_FF_00, count: 5, writeLen: 5, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0x12_34_56_78_98_FF_FF_FF}, + {name: "Aligned addr, write 6 byte", addr: 0x00_00_FF_00, count: 6, writeLen: 6, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0x12_34_56_78_98_76_FF_FF}, + {name: "Aligned addr, write 7 byte", addr: 0x00_00_FF_00, count: 7, writeLen: 7, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0x12_34_56_78_98_76_54_FF}, + {name: "Aligned addr, write 8 byte", addr: 0x00_00_FF_00, count: 8, writeLen: 8, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0x12_34_56_78_98_76_54_32}, + + {name: "1-byte misaligned addr, write 1 byte", addr: 0x00_00_FF_01, count: 1, writeLen: 1, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_12_EE_EE_FF_FF_FF_FF}, + {name: "1-byte misaligned addr, write 2 byte", addr: 0x00_00_FF_01, count: 2, writeLen: 2, preimageOffset: 9, prestateMem: prestateMem, postateMem: 0xEE_34_56_EE_FF_FF_FF_FF}, + {name: "1-byte misaligned addr, write 3 byte", addr: 0x00_00_FF_01, count: 3, writeLen: 3, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_12_34_56_FF_FF_FF_FF}, + {name: "1-byte misaligned addr, write 4 byte", addr: 0x00_00_FF_01, count: 4, writeLen: 4, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_12_34_56_78_FF_FF_FF}, + {name: "1-byte misaligned addr, write 5 byte", addr: 0x00_00_FF_01, count: 5, writeLen: 5, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_12_34_56_78_98_FF_FF}, + {name: "1-byte misaligned addr, write 6 byte", addr: 0x00_00_FF_01, count: 6, writeLen: 6, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_12_34_56_78_98_76_FF}, + {name: "1-byte misaligned addr, write 7 byte", addr: 0x00_00_FF_01, count: 7, writeLen: 7, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_12_34_56_78_98_76_54}, + + {name: "2-byte misaligned addr, write 1 byte", addr: 0x00_00_FF_02, count: 1, writeLen: 1, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_EE_12_EE_FF_FF_FF_FF}, + {name: "2-byte misaligned addr, write 2 byte", addr: 0x00_00_FF_02, count: 2, writeLen: 2, preimageOffset: 12, prestateMem: prestateMem, postateMem: 0xEE_EE_98_76_FF_FF_FF_FF}, + {name: "2-byte misaligned addr, write 2 byte", addr: 0x00_00_FF_02, count: 3, writeLen: 3, preimageOffset: 12, prestateMem: prestateMem, postateMem: 0xEE_EE_98_76_54_FF_FF_FF}, + {name: "2-byte misaligned addr, write 2 byte", addr: 0x00_00_FF_02, count: 4, writeLen: 4, preimageOffset: 12, prestateMem: prestateMem, postateMem: 0xEE_EE_98_76_54_32_FF_FF}, + + {name: "3-byte misaligned addr, write 1 byte", addr: 0x00_00_FF_03, count: 1, writeLen: 1, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_EE_EE_12_FF_FF_FF_FF}, + {name: "4-byte misaligned addr, write 1 byte", addr: 0x00_00_FF_04, count: 1, writeLen: 1, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_EE_EE_EE_12_FF_FF_FF}, + {name: "5-byte misaligned addr, write 1 byte", addr: 0x00_00_FF_05, count: 1, writeLen: 1, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_EE_EE_EE_FF_12_FF_FF}, + {name: "6-byte misaligned addr, write 1 byte", addr: 0x00_00_FF_06, count: 1, writeLen: 1, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_EE_EE_EE_FF_FF_12_FF}, + {name: "7-byte misaligned addr, write 1 byte", addr: 0x00_00_FF_07, count: 1, writeLen: 1, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_EE_EE_EE_FF_FF_FF_12}, + + {name: "Count of 0", addr: 0x00_00_FF_03, count: 0, writeLen: 0, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_EE_EE_EE_FF_FF_FF_FF}, + {name: "Count greater than 8", addr: 0x00_00_FF_00, count: 15, writeLen: 8, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0x12_34_56_78_98_76_54_32}, + {name: "Count greater than 8, unaligned", addr: 0x00_00_FF_01, count: 15, writeLen: 7, preimageOffset: 8, prestateMem: prestateMem, postateMem: 0xEE_12_34_56_78_98_76_54}, + {name: "Offset at last byte", addr: 0x00_00_FF_00, count: 8, writeLen: 1, preimageOffset: 15, prestateMem: prestateMem, postateMem: 0x32_EE_EE_EE_FF_FF_FF_FF}, + {name: "Offset just out of bounds", addr: 0x00_00_FF_00, count: 4, writeLen: 0, preimageOffset: 16, prestateMem: prestateMem, postateMem: 0xEE_EE_EE_EE_FF_FF_FF_FF, shouldPanic: true}, + {name: "Offset out of bounds", addr: 0x00_00_FF_00, count: 4, writeLen: 0, preimageOffset: 17, prestateMem: prestateMem, postateMem: 0xEE_EE_EE_EE_FF_FF_FF_FF, shouldPanic: true}, + } + testMTSysReadPreimage(t, preimageValue, cases) +} + +func TestEVM_MT_StoreOpsClearMemReservation64(t *testing.T) { + t.Parallel() + cases := []testMTStoreOpsClearMemReservationTestCase{ + {name: "Store byte", opcode: 0b10_1000, base: 0xFF_00_00_00, offset: 0x10, effAddr: 0xFF_00_00_10, preMem: ^Word(0), postMem: 0x78_FF_FF_FF_FF_FF_FF_FF}, + {name: "Store byte lower", opcode: 0b10_1000, base: 0xFF_00_00_00, offset: 0x14, effAddr: 0xFF_00_00_10, preMem: ^Word(0), postMem: 0xFF_FF_FF_FF_78_FF_FF_FF}, + {name: "Store halfword", opcode: 0b10_1001, base: 0xFF_00_00_00, offset: 0x10, effAddr: 0xFF_00_00_10, preMem: ^Word(0), postMem: 0x56_78_FF_FF_FF_FF_FF_FF}, + {name: "Store halfword lower", opcode: 0b10_1001, base: 0xFF_00_00_00, offset: 0x14, effAddr: 0xFF_00_00_10, preMem: ^Word(0), postMem: 0xFF_FF_FF_FF_56_78_FF_FF}, + {name: "Store word left", opcode: 0b10_1010, base: 0xFF_00_00_00, offset: 0x10, effAddr: 0xFF_00_00_10, preMem: ^Word(0), postMem: 0x12_34_56_78_FF_FF_FF_FF}, + {name: "Store word left lower", opcode: 0b10_1010, base: 0xFF_00_00_00, offset: 0x14, effAddr: 0xFF_00_00_10, preMem: ^Word(0), postMem: 0xFF_FF_FF_FF_12_34_56_78}, + {name: "Store word", opcode: 0b10_1011, base: 0xFF_00_00_00, offset: 0x10, effAddr: 0xFF_00_00_10, preMem: ^Word(0), postMem: 0x12_34_56_78_FF_FF_FF_FF}, + {name: "Store word lower", opcode: 0b10_1011, base: 0xFF_00_00_00, offset: 0x14, effAddr: 0xFF_00_00_10, preMem: ^Word(0), postMem: 0xFF_FF_FF_FF_12_34_56_78}, + {name: "Store word right", opcode: 0b10_1110, base: 0xFF_00_00_00, offset: 0x10, effAddr: 0xFF_00_00_10, preMem: ^Word(0), postMem: 0x78_FF_FF_FF_FF_FF_FF_FF}, + {name: "Store word right lower", opcode: 0b10_1110, base: 0xFF_00_00_00, offset: 0x14, effAddr: 0xFF_00_00_10, preMem: ^Word(0), postMem: 0xFF_FF_FF_FF_78_FF_FF_FF}, + } + testMTStoreOpsClearMemReservation(t, cases) +} + +var NoopSyscalls64 = map[string]uint32{ + "SysMunmap": 5011, + "SysGetAffinity": 5196, + "SysMadvise": 5027, + "SysRtSigprocmask": 5014, + "SysSigaltstack": 5129, + "SysRtSigaction": 5013, + "SysPrlimit64": 5297, + "SysClose": 5003, + "SysPread64": 5016, + "SysStat": 5004, + "SysFstat": 5005, + //"SysFstat64": UndefinedSysNr, + "SysOpenAt": 5247, + "SysReadlink": 5087, + "SysReadlinkAt": 5257, + "SysIoctl": 5015, + "SysEpollCreate1": 5285, + "SysPipe2": 5287, + "SysEpollCtl": 5208, + "SysEpollPwait": 5272, + "SysGetRandom": 5313, + "SysUname": 5061, + //"SysStat64": UndefinedSysNr, + "SysGetuid": 5100, + "SysGetgid": 5102, + //"SysLlseek": UndefinedSysNr, + "SysMinCore": 5026, + "SysTgkill": 5225, + "SysGetRLimit": 5095, + "SysLseek": 5008, + "SysSetITimer": 5036, + "SysTimerCreate": 5216, + "SysTimerSetTime": 5217, + "SysTimerDelete": 5220, +} + +func TestEVM_NoopSyscall64(t *testing.T) { + testNoopSyscall(t, NoopSyscalls64) +} + +func TestEVM_UnsupportedSyscall64(t *testing.T) { + t.Parallel() + + var noopSyscallNums = maps.Values(NoopSyscalls64) + var SupportedSyscalls = []uint32{arch.SysMmap, arch.SysBrk, arch.SysClone, arch.SysExitGroup, arch.SysRead, arch.SysWrite, arch.SysFcntl, arch.SysExit, arch.SysSchedYield, arch.SysGetTID, arch.SysFutex, arch.SysOpen, arch.SysNanosleep, arch.SysClockGetTime, arch.SysGetpid} + unsupportedSyscalls := make([]uint32, 0, 400) + for i := 5000; i < 5400; i++ { + candidate := uint32(i) + if slices.Contains(SupportedSyscalls, candidate) || slices.Contains(noopSyscallNums, candidate) { + continue + } + unsupportedSyscalls = append(unsupportedSyscalls, candidate) + } + + testUnsupportedSyscall(t, unsupportedSyscalls) +} diff --git a/cannon/mipsevm/tests/evm_multithreaded_test.go b/cannon/mipsevm/tests/evm_multithreaded_test.go index 813e307849dbf..1353932dd71fc 100644 --- a/cannon/mipsevm/tests/evm_multithreaded_test.go +++ b/cannon/mipsevm/tests/evm_multithreaded_test.go @@ -8,9 +8,7 @@ import ( "slices" "testing" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" "golang.org/x/exp/maps" @@ -20,14 +18,11 @@ import ( "github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded" mttestutil "github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded/testutil" "github.com/ethereum-optimism/optimism/cannon/mipsevm/testutil" - preimage "github.com/ethereum-optimism/optimism/op-preimage" ) type Word = arch.Word func TestEVM_MT_LL(t *testing.T) { - var tracer *tracing.Hooks - // Set up some test values that will be reused posValue := uint64(0xAAAA_BBBB_1122_3344) posValueRet := uint64(0x1122_3344) @@ -63,7 +58,7 @@ func TestEVM_MT_LL(t *testing.T) { // Set up state testutil.SetMemoryUint64(t, state.GetMemory(), Word(c.expectedAddr), c.memValue) - state.GetMemory().SetUint32(state.GetPC(), insn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), insn) state.GetRegistersRef()[baseReg] = Word(c.base) if withExistingReservation { state.LLReservationStatus = multithreaded.LLStatusActive32bit @@ -90,15 +85,13 @@ func TestEVM_MT_LL(t *testing.T) { // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } } func TestEVM_MT_SC(t *testing.T) { - var tracer *tracing.Hooks - // Set up some test values that will be reused memValue := uint64(0x1122_3344_5566_7788) @@ -160,7 +153,7 @@ func TestEVM_MT_SC(t *testing.T) { // Setup state testutil.SetMemoryUint64(t, state.GetMemory(), Word(c.expectedAddr), memValue) state.GetCurrentThread().ThreadId = c.threadId - state.GetMemory().SetUint32(state.GetPC(), insn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), insn) state.GetRegistersRef()[baseReg] = c.base state.GetRegistersRef()[rtReg] = Word(c.storeValue) state.LLReservationStatus = v.llReservationStatus @@ -189,45 +182,20 @@ func TestEVM_MT_SC(t *testing.T) { // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } } -func TestEVM_MT_SysRead_Preimage(t *testing.T) { - var tracer *tracing.Hooks +func TestEVM_MT_SysRead_Preimage32(t *testing.T) { + testutil.Cannon32OnlyTest(t, "These tests are fully covered for 64-bits in TestEVM_MT_SysRead_Preimage64") + t.Parallel() preimageValue := make([]byte, 0, 8) preimageValue = binary.BigEndian.AppendUint32(preimageValue, 0x12_34_56_78) preimageValue = binary.BigEndian.AppendUint32(preimageValue, 0x98_76_54_32) - - llVariations := []struct { - name string - llReservationStatus multithreaded.LLReservationStatus - matchThreadId bool - effAddrOffset Word - shouldClearReservation bool - }{ - {name: "matching reservation", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: true, shouldClearReservation: true}, - {name: "matching reservation, unaligned", llReservationStatus: multithreaded.LLStatusActive32bit, effAddrOffset: 1, matchThreadId: true, shouldClearReservation: true}, - {name: "matching reservation, diff thread", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: false, shouldClearReservation: true}, - {name: "mismatched reservation", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: true, effAddrOffset: 8, shouldClearReservation: false}, - {name: "mismatched reservation", llReservationStatus: multithreaded.LLStatusActive64bit, matchThreadId: false, effAddrOffset: 8, shouldClearReservation: false}, - {name: "no reservation, matching addr", llReservationStatus: multithreaded.LLStatusNone, matchThreadId: true, shouldClearReservation: true}, - {name: "no reservation, mismatched addr", llReservationStatus: multithreaded.LLStatusNone, matchThreadId: true, effAddrOffset: 8, shouldClearReservation: false}, - } - - cases := []struct { - name string - addr Word - count Word - writeLen Word - preimageOffset Word - prestateMem uint32 - postateMem uint32 - shouldPanic bool - }{ + cases := []testMTSysReadPreimageTestCase{ {name: "Aligned addr, write 1 byte", addr: 0x00_00_FF_00, count: 1, writeLen: 1, preimageOffset: 8, prestateMem: 0xFF_FF_FF_FF, postateMem: 0x12_FF_FF_FF}, {name: "Aligned addr, write 2 byte", addr: 0x00_00_FF_00, count: 2, writeLen: 2, preimageOffset: 8, prestateMem: 0xFF_FF_FF_FF, postateMem: 0x12_34_FF_FF}, {name: "Aligned addr, write 3 byte", addr: 0x00_00_FF_00, count: 3, writeLen: 3, preimageOffset: 8, prestateMem: 0xFF_FF_FF_FF, postateMem: 0x12_34_56_FF}, @@ -245,152 +213,26 @@ func TestEVM_MT_SysRead_Preimage(t *testing.T) { {name: "Offset just out of bounds", addr: 0x00_00_FF_00, count: 4, writeLen: 0, preimageOffset: 16, prestateMem: 0xFF_FF_FF_FF, postateMem: 0xFF_FF_FF_FF, shouldPanic: true}, {name: "Offset out of bounds", addr: 0x00_00_FF_00, count: 4, writeLen: 0, preimageOffset: 17, prestateMem: 0xFF_FF_FF_FF, postateMem: 0xFF_FF_FF_FF, shouldPanic: true}, } - for i, c := range cases { - for _, v := range llVariations { - tName := fmt.Sprintf("%v (%v)", c.name, v.name) - t.Run(tName, func(t *testing.T) { - effAddr := arch.AddressMask & c.addr - preimageKey := preimage.Keccak256Key(crypto.Keccak256Hash(preimageValue)).PreimageKey() - oracle := testutil.StaticOracle(t, preimageValue) - goVm, state, contracts := setup(t, i, oracle) - step := state.GetStep() - - // Define LL-related params - llAddress := effAddr + v.effAddrOffset - llOwnerThread := state.GetCurrentThread().ThreadId - if !v.matchThreadId { - llOwnerThread += 1 - } - // Set up state - state.PreimageKey = preimageKey - state.PreimageOffset = c.preimageOffset - state.GetRegistersRef()[2] = arch.SysRead - state.GetRegistersRef()[4] = exec.FdPreimageRead - state.GetRegistersRef()[5] = c.addr - state.GetRegistersRef()[6] = c.count - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) - state.LLReservationStatus = v.llReservationStatus - state.LLAddress = llAddress - state.LLOwnerThread = llOwnerThread - state.GetMemory().SetUint32(effAddr, c.prestateMem) - - // Setup expectations - expected := mttestutil.NewExpectedMTState(state) - expected.ExpectStep() - expected.ActiveThread().Registers[2] = c.writeLen - expected.ActiveThread().Registers[7] = 0 // no error - expected.PreimageOffset += c.writeLen - expected.ExpectMemoryWriteUint32(t, effAddr, c.postateMem) - if v.shouldClearReservation { - expected.LLReservationStatus = multithreaded.LLStatusNone - expected.LLAddress = 0 - expected.LLOwnerThread = 0 - } - - if c.shouldPanic { - require.Panics(t, func() { _, _ = goVm.Step(true) }) - testutil.AssertPreimageOracleReverts(t, preimageKey, preimageValue, c.preimageOffset, contracts, tracer) - } else { - stepWitness, err := goVm.Step(true) - require.NoError(t, err) - - // Check expectations - expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) - } - }) - } - } + testMTSysReadPreimage(t, preimageValue, cases) } -func TestEVM_MT_StoreOpsClearMemReservation(t *testing.T) { - var tracer *tracing.Hooks - - llVariations := []struct { - name string - llReservationStatus multithreaded.LLReservationStatus - matchThreadId bool - effAddrOffset Word - shouldClearReservation bool - }{ - {name: "matching reservation", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: true, shouldClearReservation: true}, - {name: "matching reservation, unaligned", llReservationStatus: multithreaded.LLStatusActive32bit, effAddrOffset: 1, matchThreadId: true, shouldClearReservation: true}, - {name: "matching reservation, 64-bit", llReservationStatus: multithreaded.LLStatusActive64bit, matchThreadId: true, shouldClearReservation: true}, - {name: "matching reservation, diff thread", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: false, shouldClearReservation: true}, - {name: "matching reservation, diff thread, 64-bit", llReservationStatus: multithreaded.LLStatusActive64bit, matchThreadId: false, shouldClearReservation: true}, - {name: "mismatched reservation", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: true, effAddrOffset: 8, shouldClearReservation: false}, - {name: "mismatched reservation, diff thread", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: false, effAddrOffset: 8, shouldClearReservation: false}, - {name: "no reservation, matching addr", llReservationStatus: multithreaded.LLStatusNone, matchThreadId: true, shouldClearReservation: true}, - {name: "no reservation, mismatched addr", llReservationStatus: multithreaded.LLStatusNone, matchThreadId: true, effAddrOffset: 8, shouldClearReservation: false}, - } - - rt := Word(0x12_34_56_78) - baseReg := 5 - rtReg := 6 - cases := []struct { - name string - opcode int - offset int - base Word - effAddr Word - preMem uint32 - postMem uint32 - }{ - {name: "Store byte", opcode: 0b10_1000, base: 0xFF_00_00_04, offset: 0xFF_00_00_08, effAddr: 0xFF_00_00_0C, preMem: 0xFF_FF_FF_FF, postMem: 0x78_FF_FF_FF}, - {name: "Store halfword", opcode: 0b10_1001, base: 0xFF_00_00_04, offset: 0xFF_00_00_08, effAddr: 0xFF_00_00_0C, preMem: 0xFF_FF_FF_FF, postMem: 0x56_78_FF_FF}, - {name: "Store word left", opcode: 0b10_1010, base: 0xFF_00_00_04, offset: 0xFF_00_00_08, effAddr: 0xFF_00_00_0C, preMem: 0xFF_FF_FF_FF, postMem: 0x12_34_56_78}, - {name: "Store word", opcode: 0b10_1011, base: 0xFF_00_00_04, offset: 0xFF_00_00_08, effAddr: 0xFF_00_00_0C, preMem: 0xFF_FF_FF_FF, postMem: 0x12_34_56_78}, - {name: "Store word right", opcode: 0b10_1110, base: 0xFF_00_00_04, offset: 0xFF_00_00_08, effAddr: 0xFF_00_00_0C, preMem: 0xFF_FF_FF_FF, postMem: 0x78_FF_FF_FF}, - } - for i, c := range cases { - for _, v := range llVariations { - tName := fmt.Sprintf("%v (%v)", c.name, v.name) - t.Run(tName, func(t *testing.T) { - insn := uint32((c.opcode << 26) | (baseReg & 0x1F << 21) | (rtReg & 0x1F << 16) | (0xFFFF & c.offset)) - goVm, state, contracts := setup(t, i, nil, testutil.WithPCAndNextPC(0x08)) - step := state.GetStep() - - // Define LL-related params - llAddress := c.effAddr + v.effAddrOffset - llOwnerThread := state.GetCurrentThread().ThreadId - if !v.matchThreadId { - llOwnerThread += 1 - } - - // Setup state - state.GetRegistersRef()[rtReg] = rt - state.GetRegistersRef()[baseReg] = c.base - state.GetMemory().SetUint32(state.GetPC(), insn) - state.GetMemory().SetUint32(c.effAddr, c.preMem) - state.LLReservationStatus = v.llReservationStatus - state.LLAddress = llAddress - state.LLOwnerThread = llOwnerThread - - // Setup expectations - expected := mttestutil.NewExpectedMTState(state) - expected.ExpectStep() - expected.ExpectMemoryWriteUint32(t, c.effAddr, c.postMem) - if v.shouldClearReservation { - expected.LLReservationStatus = multithreaded.LLStatusNone - expected.LLAddress = 0 - expected.LLOwnerThread = 0 - } - - stepWitness, err := goVm.Step(true) - require.NoError(t, err) - - // Check expectations - expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) - }) - } +func TestEVM_MT_StoreOpsClearMemReservation32(t *testing.T) { + t.Parallel() + testutil.Cannon32OnlyTest(t, "These tests are fully covered for 64-bits in TestEVM_MT_StoreOpsClearMemReservation64") + + cases := []testMTStoreOpsClearMemReservationTestCase{ + {name: "Store byte", opcode: 0b10_1000, base: 0xFF_00_00_04, offset: 0x08, effAddr: 0xFF_00_00_0C, preMem: 0xFF_FF_FF_FF, postMem: 0x78_FF_FF_FF}, + {name: "Store halfword", opcode: 0b10_1001, base: 0xFF_00_00_04, offset: 0x08, effAddr: 0xFF_00_00_0C, preMem: 0xFF_FF_FF_FF, postMem: 0x56_78_FF_FF}, + {name: "Store word left", opcode: 0b10_1010, base: 0xFF_00_00_04, offset: 0x08, effAddr: 0xFF_00_00_0C, preMem: 0xFF_FF_FF_FF, postMem: 0x12_34_56_78}, + {name: "Store word", opcode: 0b10_1011, base: 0xFF_00_00_04, offset: 0x08, effAddr: 0xFF_00_00_0C, preMem: 0xFF_FF_FF_FF, postMem: 0x12_34_56_78}, + {name: "Store word right", opcode: 0b10_1110, base: 0xFF_00_00_04, offset: 0x08, effAddr: 0xFF_00_00_0C, preMem: 0xFF_FF_FF_FF, postMem: 0x78_FF_FF_FF}, } + testMTStoreOpsClearMemReservation(t, cases) } func TestEVM_SysClone_FlagHandling(t *testing.T) { contracts := testutil.TestContractsSetup(t, testutil.MipsMultithreaded) - var tracer *tracing.Hooks cases := []struct { name string @@ -411,45 +253,37 @@ func TestEVM_SysClone_FlagHandling(t *testing.T) { for _, c := range cases { t.Run(c.name, func(t *testing.T) { state := multithreaded.CreateEmptyState() - state.Memory.SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysClone // Set syscall number state.GetRegistersRef()[4] = c.flags // Set first argument curStep := state.Step var err error var stepWitness *mipsevm.StepWitness - us := multithreaded.NewInstrumentedState(state, nil, os.Stdout, os.Stderr, nil, nil) + goVm := multithreaded.NewInstrumentedState(state, nil, os.Stdout, os.Stderr, nil, nil) if !c.valid { // The VM should exit - stepWitness, err = us.Step(true) + stepWitness, err = goVm.Step(true) require.NoError(t, err) require.Equal(t, curStep+1, state.GetStep()) - require.Equal(t, true, us.GetState().GetExited()) - require.Equal(t, uint8(mipsevm.VMStatusPanic), us.GetState().GetExitCode()) + require.Equal(t, true, goVm.GetState().GetExited()) + require.Equal(t, uint8(mipsevm.VMStatusPanic), goVm.GetState().GetExitCode()) require.Equal(t, 1, state.ThreadCount()) } else { - stepWitness, err = us.Step(true) + stepWitness, err = goVm.Step(true) require.NoError(t, err) require.Equal(t, curStep+1, state.GetStep()) - require.Equal(t, false, us.GetState().GetExited()) - require.Equal(t, uint8(0), us.GetState().GetExitCode()) + require.Equal(t, false, goVm.GetState().GetExited()) + require.Equal(t, uint8(0), goVm.GetState().GetExitCode()) require.Equal(t, 2, state.ThreadCount()) } - evm := testutil.NewMIPSEVM(contracts) - evm.SetTracer(tracer) - testutil.LogStepFailureAtCleanup(t, evm) - - evmPost := evm.Step(t, stepWitness, curStep, multithreaded.GetStateHashFn()) - goPost, _ := us.GetState().EncodeWitness() - require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), - "mipsevm produced different state than EVM") + testutil.ValidateEVM(t, stepWitness, curStep, goVm, multithreaded.GetStateHashFn(), contracts) }) } } func TestEVM_SysClone_Successful(t *testing.T) { - var tracer *tracing.Hooks cases := []struct { name string traverseRight bool @@ -464,7 +298,7 @@ func TestEVM_SysClone_Successful(t *testing.T) { goVm, state, contracts := setup(t, i, nil) mttestutil.InitializeSingleThread(i*333, state, c.traverseRight) - state.Memory.SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysClone // the syscall number state.GetRegistersRef()[4] = exec.ValidCloneFlags // a0 - first argument, clone flags state.GetRegistersRef()[5] = stackPtr // a1 - the stack pointer @@ -506,13 +340,12 @@ func TestEVM_SysClone_Successful(t *testing.T) { activeStack, inactiveStack := mttestutil.GetThreadStacks(state) require.Equal(t, 2, len(activeStack)) require.Equal(t, 0, len(inactiveStack)) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } func TestEVM_SysGetTID(t *testing.T) { - var tracer *tracing.Hooks cases := []struct { name string threadId Word @@ -527,7 +360,7 @@ func TestEVM_SysGetTID(t *testing.T) { mttestutil.InitializeSingleThread(i*789, state, false) state.GetCurrentThread().ThreadId = c.threadId - state.Memory.SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysGetTID // Set syscall number step := state.Step @@ -545,13 +378,12 @@ func TestEVM_SysGetTID(t *testing.T) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } func TestEVM_SysExit(t *testing.T) { - var tracer *tracing.Hooks cases := []struct { name string threadCount int @@ -570,7 +402,7 @@ func TestEVM_SysExit(t *testing.T) { goVm, state, contracts := setup(t, i*133, nil) mttestutil.SetupThreads(int64(i*1111), state, i%2 == 0, c.threadCount, 0) - state.Memory.SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysExit // Set syscall number state.GetRegistersRef()[4] = Word(exitCode) // The first argument (exit code) step := state.Step @@ -594,13 +426,12 @@ func TestEVM_SysExit(t *testing.T) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } func TestEVM_PopExitedThread(t *testing.T) { - var tracer *tracing.Hooks cases := []struct { name string traverseRight bool @@ -646,45 +477,44 @@ func TestEVM_PopExitedThread(t *testing.T) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } func TestEVM_SysFutex_WaitPrivate(t *testing.T) { - var tracer *tracing.Hooks + // Note: parameters are written as 64-bit values. For 32-bit architectures, these values are downcast to 32-bit cases := []struct { name string - addressParam Word - effAddr Word - targetValue Word - actualValue Word - timeout Word + addressParam uint64 + effAddr uint64 + targetValue uint64 + actualValue uint64 + timeout uint64 shouldFail bool shouldSetTimeout bool }{ - {name: "successful wait, no timeout", addressParam: 0x1234, effAddr: 0x1234, targetValue: 0x01, actualValue: 0x01}, - {name: "successful wait, no timeout, unaligned addr", addressParam: 0x1235, effAddr: 0x1234, targetValue: 0x01, actualValue: 0x01}, - {name: "memory mismatch, no timeout", addressParam: 0x1200, effAddr: 0x1200, targetValue: 0x01, actualValue: 0x02, shouldFail: true}, - {name: "memory mismatch, no timeout, unaligned", addressParam: 0x1203, effAddr: 0x1200, targetValue: 0x01, actualValue: 0x02, shouldFail: true}, - {name: "successful wait w timeout", addressParam: 0x1234, effAddr: 0x1234, targetValue: 0x01, actualValue: 0x01, timeout: 1000000, shouldSetTimeout: true}, - {name: "successful wait w timeout, unaligned", addressParam: 0x1232, effAddr: 0x1230, targetValue: 0x01, actualValue: 0x01, timeout: 1000000, shouldSetTimeout: true}, - {name: "memory mismatch w timeout", addressParam: 0x1200, effAddr: 0x1200, targetValue: 0x01, actualValue: 0x02, timeout: 2000000, shouldFail: true}, - {name: "memory mismatch w timeout, unaligned", addressParam: 0x120F, effAddr: 0x120C, targetValue: 0x01, actualValue: 0x02, timeout: 2000000, shouldFail: true}, + {name: "successful wait, no timeout", addressParam: 0xFF_FF_FF_FF_FF_FF_12_38, effAddr: 0xFF_FF_FF_FF_FF_FF_12_38, targetValue: 0xFF_FF_FF_FF_FF_FF_FF_01, actualValue: 0xFF_FF_FF_FF_FF_FF_FF_01}, + {name: "successful wait, no timeout, unaligned addr", addressParam: 0xFF_FF_FF_FF_FF_FF_12_39, effAddr: 0xFF_FF_FF_FF_FF_FF_12_38, targetValue: 0xFF_FF_FF_FF_FF_FF_FF_01, actualValue: 0xFF_FF_FF_FF_FF_FF_FF_01}, + {name: "memory mismatch, no timeout", addressParam: 0xFF_FF_FF_FF_FF_FF_12_00, effAddr: 0xFF_FF_FF_FF_FF_FF_12_00, targetValue: 0xFF_FF_FF_FF_FF_FF_FF_01, actualValue: 0xFF_FF_FF_FF_FF_FF_FF_02, shouldFail: true}, + {name: "memory mismatch, no timeout, unaligned", addressParam: 0xFF_FF_FF_FF_FF_FF_12_03, effAddr: 0xFF_FF_FF_FF_FF_FF_12_00, targetValue: 0xFF_FF_FF_FF_FF_FF_FF_01, actualValue: 0xFF_FF_FF_FF_FF_FF_FF_02, shouldFail: true}, + {name: "successful wait w timeout", addressParam: 0xFF_FF_FF_FF_FF_FF_12_38, effAddr: 0xFF_FF_FF_FF_FF_FF_12_38, targetValue: 0xFF_FF_FF_FF_FF_FF_FF_01, actualValue: 0xFF_FF_FF_FF_FF_FF_FF_01, timeout: 1000000, shouldSetTimeout: true}, + {name: "successful wait w timeout, unaligned", addressParam: 0xFF_FF_FF_FF_FF_FF_12_32, effAddr: 0xFF_FF_FF_FF_FF_FF_12_30, targetValue: 0xFF_FF_FF_FF_FF_FF_FF_01, actualValue: 0xFF_FF_FF_FF_FF_FF_FF_01, timeout: 1000000, shouldSetTimeout: true}, + {name: "memory mismatch w timeout", addressParam: 0xFF_FF_FF_FF_FF_FF_12_00, effAddr: 0xFF_FF_FF_FF_FF_FF_12_00, targetValue: 0xFF_FF_FF_FF_FF_FF_FF_01, actualValue: 0xFF_FF_FF_FF_FF_FF_FF_02, timeout: 2000000, shouldFail: true}, + {name: "memory mismatch w timeout, unaligned", addressParam: 0xFF_FF_FF_FF_FF_FF_12_0F, effAddr: 0xFF_FF_FF_FF_FF_FF_12_10, targetValue: 0xFF_FF_FF_FF_FF_FF_FF_01, actualValue: 0xFF_FF_FF_FF_FF_FF_FF_02, timeout: 2000000, shouldFail: true}, } - for i, c := range cases { t.Run(c.name, func(t *testing.T) { goVm, state, contracts := setup(t, i*1234, nil) step := state.GetStep() - state.Memory.SetUint32(state.GetPC(), syscallInsn) - state.Memory.SetWord(c.effAddr, c.actualValue) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) + state.Memory.SetWord(Word(c.effAddr), Word(c.actualValue)) state.GetRegistersRef()[2] = arch.SysFutex // Set syscall number - state.GetRegistersRef()[4] = c.addressParam + state.GetRegistersRef()[4] = Word(c.addressParam) state.GetRegistersRef()[5] = exec.FutexWaitPrivate - state.GetRegistersRef()[6] = c.targetValue - state.GetRegistersRef()[7] = c.timeout + state.GetRegistersRef()[6] = Word(c.targetValue) + state.GetRegistersRef()[7] = Word(c.timeout) // Setup expectations expected := mttestutil.NewExpectedMTState(state) @@ -697,8 +527,8 @@ func TestEVM_SysFutex_WaitPrivate(t *testing.T) { expected.ActiveThread().Registers[7] = exec.MipsEAGAIN } else { // PC and return registers should not update on success, updates happen when wait completes - expected.ActiveThread().FutexAddr = c.effAddr - expected.ActiveThread().FutexVal = c.targetValue + expected.ActiveThread().FutexAddr = Word(c.effAddr) + expected.ActiveThread().FutexVal = Word(c.targetValue) expected.ActiveThread().FutexTimeoutStep = exec.FutexNoTimeout if c.shouldSetTimeout { expected.ActiveThread().FutexTimeoutStep = step + exec.FutexTimeoutSteps + 1 @@ -706,52 +536,49 @@ func TestEVM_SysFutex_WaitPrivate(t *testing.T) { } // State transition - var err error - var stepWitness *mipsevm.StepWitness - stepWitness, err = goVm.Step(true) + stepWitness, err := goVm.Step(true) require.NoError(t, err) // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } func TestEVM_SysFutex_WakePrivate(t *testing.T) { - var tracer *tracing.Hooks + // Note: parameters are written as 64-bit values. For 32-bit architectures, these values are downcast to 32-bit cases := []struct { name string - addressParam Word - effAddr Word + addressParam uint64 + effAddr uint64 activeThreadCount int inactiveThreadCount int traverseRight bool expectTraverseRight bool }{ - {name: "Traverse right", addressParam: 0x6700, effAddr: 0x6700, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: true}, - {name: "Traverse right, unaligned addr", addressParam: 0x6789, effAddr: 0x6788, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: true}, - {name: "Traverse right, no left threads", addressParam: 0x6784, effAddr: 0x6784, activeThreadCount: 2, inactiveThreadCount: 0, traverseRight: true}, - {name: "Traverse right, no left threads, unaligned addr", addressParam: 0x678E, effAddr: 0x678C, activeThreadCount: 2, inactiveThreadCount: 0, traverseRight: true}, - {name: "Traverse right, single thread", addressParam: 0x6788, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: true}, - {name: "Traverse right, single thread, unaligned", addressParam: 0x6789, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: true}, - {name: "Traverse left", addressParam: 0x6788, effAddr: 0x6788, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: false}, - {name: "Traverse left, unaliagned", addressParam: 0x6789, effAddr: 0x6788, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: false}, - {name: "Traverse left, switch directions", addressParam: 0x6788, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 1, traverseRight: false, expectTraverseRight: true}, - {name: "Traverse left, switch directions, unaligned", addressParam: 0x6789, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 1, traverseRight: false, expectTraverseRight: true}, - {name: "Traverse left, single thread", addressParam: 0x6788, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: false, expectTraverseRight: true}, - {name: "Traverse left, single thread, unaligned", addressParam: 0x6789, effAddr: 0x6788, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: false, expectTraverseRight: true}, + {name: "Traverse right", addressParam: 0xFF_FF_FF_FF_FF_FF_67_00, effAddr: 0xFF_FF_FF_FF_FF_FF_67_00, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: true}, + {name: "Traverse right, unaligned addr", addressParam: 0xFF_FF_FF_FF_FF_FF_67_89, effAddr: 0xFF_FF_FF_FF_FF_FF_67_88, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: true}, + {name: "Traverse right, no left threads", addressParam: 0xFF_FF_FF_FF_FF_FF_67_84, effAddr: 0xFF_FF_FF_FF_FF_FF_67_84, activeThreadCount: 2, inactiveThreadCount: 0, traverseRight: true}, + {name: "Traverse right, no left threads, unaligned addr", addressParam: 0xFF_FF_FF_FF_FF_FF_67_8E, effAddr: 0xFF_FF_FF_FF_FF_FF_67_8C, activeThreadCount: 2, inactiveThreadCount: 0, traverseRight: true}, + {name: "Traverse right, single thread", addressParam: 0xFF_FF_FF_FF_FF_FF_67_88, effAddr: 0xFF_FF_FF_FF_FF_FF_67_88, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: true}, + {name: "Traverse right, single thread, unaligned", addressParam: 0xFF_FF_FF_FF_FF_FF_67_89, effAddr: 0xFF_FF_FF_FF_FF_FF_67_88, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: true}, + {name: "Traverse left", addressParam: 0xFF_FF_FF_FF_FF_FF_67_88, effAddr: 0xFF_FF_FF_FF_FF_FF_67_88, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: false}, + {name: "Traverse left, unaliagned", addressParam: 0xFF_FF_FF_FF_FF_FF_67_89, effAddr: 0xFF_FF_FF_FF_FF_FF_67_88, activeThreadCount: 2, inactiveThreadCount: 1, traverseRight: false}, + {name: "Traverse left, switch directions", addressParam: 0xFF_FF_FF_FF_FF_FF_67_88, effAddr: 0xFF_FF_FF_FF_FF_FF_67_88, activeThreadCount: 1, inactiveThreadCount: 1, traverseRight: false, expectTraverseRight: true}, + {name: "Traverse left, switch directions, unaligned", addressParam: 0xFF_FF_FF_FF_FF_FF_67_89, effAddr: 0xFF_FF_FF_FF_FF_FF_67_88, activeThreadCount: 1, inactiveThreadCount: 1, traverseRight: false, expectTraverseRight: true}, + {name: "Traverse left, single thread", addressParam: 0xFF_FF_FF_FF_FF_FF_67_88, effAddr: 0xFF_FF_FF_FF_FF_FF_67_88, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: false, expectTraverseRight: true}, + {name: "Traverse left, single thread, unaligned", addressParam: 0xFF_FF_FF_FF_FF_FF_67_89, effAddr: 0xFF_FF_FF_FF_FF_FF_67_88, activeThreadCount: 1, inactiveThreadCount: 0, traverseRight: false, expectTraverseRight: true}, } - for i, c := range cases { t.Run(c.name, func(t *testing.T) { goVm, state, contracts := setup(t, i*1122, nil) mttestutil.SetupThreads(int64(i*2244), state, c.traverseRight, c.activeThreadCount, c.inactiveThreadCount) step := state.Step - state.Memory.SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysFutex // Set syscall number - state.GetRegistersRef()[4] = c.addressParam + state.GetRegistersRef()[4] = Word(c.addressParam) state.GetRegistersRef()[5] = exec.FutexWakePrivate // Set up post-state expectations @@ -759,7 +586,7 @@ func TestEVM_SysFutex_WakePrivate(t *testing.T) { expected.ExpectStep() expected.ActiveThread().Registers[2] = 0 expected.ActiveThread().Registers[7] = 0 - expected.Wakeup = c.effAddr + expected.Wakeup = Word(c.effAddr) & arch.AddressMask // aligned for 32 and 64-bit compatibility expected.ExpectPreemption(state) expected.TraverseRight = c.expectTraverseRight if c.traverseRight != c.expectTraverseRight { @@ -769,21 +596,18 @@ func TestEVM_SysFutex_WakePrivate(t *testing.T) { } // State transition - var err error - var stepWitness *mipsevm.StepWitness - stepWitness, err = goVm.Step(true) + stepWitness, err := goVm.Step(true) require.NoError(t, err) // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } + } func TestEVM_SysFutex_UnsupportedOp(t *testing.T) { - var tracer *tracing.Hooks - // From: https://github.com/torvalds/linux/blob/5be63fc19fcaa4c236b307420483578a56986a37/include/uapi/linux/futex.h const FUTEX_PRIVATE_FLAG = 128 const FUTEX_WAIT = 0 @@ -834,7 +658,7 @@ func TestEVM_SysFutex_UnsupportedOp(t *testing.T) { goVm, state, contracts := setup(t, int(op), nil) step := state.GetStep() - state.Memory.SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysFutex // Set syscall number state.GetRegistersRef()[5] = op @@ -855,7 +679,7 @@ func TestEVM_SysFutex_UnsupportedOp(t *testing.T) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } @@ -869,7 +693,6 @@ func TestEVM_SysNanosleep(t *testing.T) { } func runPreemptSyscall(t *testing.T, syscallName string, syscallNum uint32) { - var tracer *tracing.Hooks cases := []struct { name string traverseRight bool @@ -889,7 +712,7 @@ func runPreemptSyscall(t *testing.T, syscallName string, syscallNum uint32) { goVm, state, contracts := setup(t, i*789, nil) mttestutil.SetupThreads(int64(i*3259), state, traverseRight, c.activeThreads, c.inactiveThreads) - state.Memory.SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = Word(syscallNum) // Set syscall number step := state.Step @@ -908,18 +731,16 @@ func runPreemptSyscall(t *testing.T, syscallName string, syscallNum uint32) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } } func TestEVM_SysOpen(t *testing.T) { - var tracer *tracing.Hooks - goVm, state, contracts := setup(t, 5512, nil) - state.Memory.SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysOpen // Set syscall number step := state.Step @@ -937,14 +758,13 @@ func TestEVM_SysOpen(t *testing.T) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) } func TestEVM_SysGetPID(t *testing.T) { - var tracer *tracing.Hooks goVm, state, contracts := setup(t, 1929, nil) - state.Memory.SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysGetpid // Set syscall number step := state.Step @@ -962,7 +782,7 @@ func TestEVM_SysGetPID(t *testing.T) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) } func TestEVM_SysClockGettimeMonotonic(t *testing.T) { @@ -974,8 +794,6 @@ func TestEVM_SysClockGettimeRealtime(t *testing.T) { } func testEVM_SysClockGettime(t *testing.T, clkid Word) { - var tracer *tracing.Hooks - llVariations := []struct { name string llReservationStatus multithreaded.LLReservationStatus @@ -1011,7 +829,7 @@ func testEVM_SysClockGettime(t *testing.T, clkid Word) { goVm, state, contracts := setup(t, 2101, nil) mttestutil.InitializeSingleThread(2101+i, state, i%2 == 1) effAddr := c.timespecAddr & arch.AddressMask - effAddr2 := effAddr + 4 + effAddr2 := effAddr + arch.WordSizeBytes step := state.Step // Define LL-related params @@ -1029,7 +847,7 @@ func testEVM_SysClockGettime(t *testing.T, clkid Word) { llOwnerThread = state.GetCurrentThread().ThreadId + 1 } - state.Memory.SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysClockGetTime // Set syscall number state.GetRegistersRef()[4] = clkid // a0 state.GetRegistersRef()[5] = c.timespecAddr // a1 @@ -1062,18 +880,17 @@ func testEVM_SysClockGettime(t *testing.T, clkid Word) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } } func TestEVM_SysClockGettimeNonMonotonic(t *testing.T) { - var tracer *tracing.Hooks goVm, state, contracts := setup(t, 2101, nil) timespecAddr := Word(0x1000) - state.Memory.SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysClockGetTime // Set syscall number state.GetRegistersRef()[4] = 0xDEAD // a0 - invalid clockid state.GetRegistersRef()[5] = timespecAddr // a1 @@ -1091,7 +908,7 @@ func TestEVM_SysClockGettimeNonMonotonic(t *testing.T) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) } var NoopSyscalls = map[string]uint32{ @@ -1103,6 +920,7 @@ var NoopSyscalls = map[string]uint32{ "SysPrlimit64": 4338, "SysClose": 4006, "SysPread64": 4200, + "SysStat": 4106, "SysFstat": 4108, "SysFstat64": 4215, "SysOpenAt": 4288, @@ -1121,6 +939,8 @@ var NoopSyscalls = map[string]uint32{ "SysLlseek": 4140, "SysMinCore": 4217, "SysTgkill": 4266, + "SysGetRLimit": 4076, + "SysLseek": 4019, "SysMunmap": 4091, "SysSetITimer": 4104, "SysTimerCreate": 4257, @@ -1128,69 +948,27 @@ var NoopSyscalls = map[string]uint32{ "SysTimerDelete": 4261, } -func TestEVM_NoopSyscall(t *testing.T) { - var tracer *tracing.Hooks - for noopName, noopVal := range NoopSyscalls { - t.Run(noopName, func(t *testing.T) { - goVm, state, contracts := setup(t, int(noopVal), nil) - - state.Memory.SetUint32(state.GetPC(), syscallInsn) - state.GetRegistersRef()[2] = Word(noopVal) // Set syscall number - step := state.Step - - // Set up post-state expectations - expected := mttestutil.NewExpectedMTState(state) - expected.ExpectStep() - expected.ActiveThread().Registers[2] = 0 - expected.ActiveThread().Registers[7] = 0 - - // State transition - var err error - var stepWitness *mipsevm.StepWitness - stepWitness, err = goVm.Step(true) - require.NoError(t, err) - - // Validate post-state - expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) - }) - - } +func TestEVM_NoopSyscall32(t *testing.T) { + testutil.Cannon32OnlyTest(t, "These tests are fully covered for 64-bits in TestEVM_NoopSyscall64") + testNoopSyscall(t, NoopSyscalls) } -func TestEVM_UnsupportedSyscall(t *testing.T) { +func TestEVM_UnsupportedSyscall32(t *testing.T) { + testutil.Cannon32OnlyTest(t, "These tests are fully covered for 64-bits in TestEVM_UnsupportedSyscall64") t.Parallel() - var tracer *tracing.Hooks - var NoopSyscallNums = maps.Values(NoopSyscalls) - var SupportedSyscalls = []uint32{arch.SysMmap, arch.SysBrk, arch.SysClone, arch.SysExitGroup, arch.SysRead, arch.SysWrite, arch.SysFcntl, arch.SysExit, arch.SysSchedYield, arch.SysGetTID, arch.SysFutex, arch.SysOpen, arch.SysNanosleep, arch.SysClockGetTime, arch.SysGetpid} + var noopSyscallNums = maps.Values(NoopSyscalls) + var supportedSyscalls = []uint32{arch.SysMmap, arch.SysBrk, arch.SysClone, arch.SysExitGroup, arch.SysRead, arch.SysWrite, arch.SysFcntl, arch.SysExit, arch.SysSchedYield, arch.SysGetTID, arch.SysFutex, arch.SysOpen, arch.SysNanosleep, arch.SysClockGetTime, arch.SysGetpid} unsupportedSyscalls := make([]uint32, 0, 400) for i := 4000; i < 4400; i++ { candidate := uint32(i) - if slices.Contains(SupportedSyscalls, candidate) || slices.Contains(NoopSyscallNums, candidate) { + if slices.Contains(supportedSyscalls, candidate) || slices.Contains(noopSyscallNums, candidate) { continue } unsupportedSyscalls = append(unsupportedSyscalls, candidate) } - for i, syscallNum := range unsupportedSyscalls { - testName := fmt.Sprintf("Unsupported syscallNum %v", syscallNum) - i := i - syscallNum := syscallNum - t.Run(testName, func(t *testing.T) { - t.Parallel() - goVm, state, contracts := setup(t, i*3434, nil) - // Setup basic getThreadId syscall instruction - state.Memory.SetUint32(state.GetPC(), syscallInsn) - state.GetRegistersRef()[2] = Word(syscallNum) - proofData := multiThreadedProofGenerator(t, state) - // Set up post-state expectations - require.Panics(t, func() { _, _ = goVm.Step(true) }) - - errorMessage := "MIPS2: unimplemented syscall" - testutil.AssertEVMReverts(t, state, contracts, tracer, proofData, errorMessage) - }) - } + testUnsupportedSyscall(t, unsupportedSyscalls) } func TestEVM_EmptyThreadStacks(t *testing.T) { @@ -1219,15 +997,14 @@ func TestEVM_EmptyThreadStacks(t *testing.T) { require.PanicsWithValue(t, "Active thread stack is empty", func() { _, _ = goVm.Step(false) }) - errorMessage := "MIPS2: active thread stack is empty" - testutil.AssertEVMReverts(t, state, contracts, tracer, proofCase.Proof, errorMessage) + errorMessage := "active thread stack is empty" + testutil.AssertEVMReverts(t, state, contracts, tracer, proofCase.Proof, testutil.CreateErrorStringMatcher(errorMessage)) }) } } } func TestEVM_NormalTraversalStep_HandleWaitingThread(t *testing.T) { - var tracer *tracing.Hooks cases := []struct { name string step uint64 @@ -1304,7 +1081,7 @@ func TestEVM_NormalTraversalStep_HandleWaitingThread(t *testing.T) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, c.step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, c.step, goVm, multithreaded.GetStateHashFn(), contracts) }) } @@ -1312,7 +1089,6 @@ func TestEVM_NormalTraversalStep_HandleWaitingThread(t *testing.T) { } func TestEVM_NormalTraversal_Full(t *testing.T) { - var tracer *tracing.Hooks cases := []struct { name string threadCount int @@ -1354,7 +1130,7 @@ func TestEVM_NormalTraversal_Full(t *testing.T) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) } // We should be back to the original state with only a few modifications @@ -1369,7 +1145,6 @@ func TestEVM_NormalTraversal_Full(t *testing.T) { func TestEVM_WakeupTraversalStep(t *testing.T) { addr := Word(0x1234) wakeupVal := Word(0x999) - var tracer *tracing.Hooks cases := []struct { name string wakeupAddr Word @@ -1437,13 +1212,12 @@ func TestEVM_WakeupTraversalStep(t *testing.T) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } func TestEVM_WakeupTraversal_Full(t *testing.T) { - var tracer *tracing.Hooks cases := []struct { name string threadCount int @@ -1483,7 +1257,7 @@ func TestEVM_WakeupTraversal_Full(t *testing.T) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) } // We should be back to the original state with only a few modifications @@ -1495,8 +1269,80 @@ func TestEVM_WakeupTraversal_Full(t *testing.T) { } } +func TestEVM_WakeupTraversal_WithExitedThreads(t *testing.T) { + addr := Word(0x1234) + wakeupVal := Word(0x999) + cases := []struct { + name string + wakeupAddr Word + futexAddr Word + targetVal Word + traverseRight bool + activeStackSize int + otherStackSize int + exitedThreadIdx []int + shouldClearWakeup bool + shouldPreempt bool + activeThreadFutexAddr Word + activeThreadFutexVal Word + }{ + {name: "Wakeable thread exists among exited threads", wakeupAddr: addr, futexAddr: addr, targetVal: wakeupVal + 1, traverseRight: false, activeStackSize: 3, otherStackSize: 1, exitedThreadIdx: []int{2}, shouldClearWakeup: false, shouldPreempt: true, activeThreadFutexAddr: addr + 8, activeThreadFutexVal: wakeupVal + 2}, + {name: "All threads exited", wakeupAddr: addr, futexAddr: addr, targetVal: wakeupVal, traverseRight: false, activeStackSize: 3, otherStackSize: 0, exitedThreadIdx: []int{1, 2}, shouldClearWakeup: false, shouldPreempt: true, activeThreadFutexAddr: addr + 16, activeThreadFutexVal: wakeupVal + 3}, + {name: "Exited threads, no matching futex", wakeupAddr: addr, futexAddr: addr + 4, targetVal: wakeupVal, traverseRight: false, activeStackSize: 2, otherStackSize: 1, exitedThreadIdx: []int{}, shouldClearWakeup: false, shouldPreempt: true, activeThreadFutexAddr: addr + 24, activeThreadFutexVal: wakeupVal + 4}, + {name: "Matching addr, not wakeable, with exited threads", wakeupAddr: addr, futexAddr: addr, targetVal: wakeupVal, traverseRight: true, activeStackSize: 3, otherStackSize: 0, exitedThreadIdx: []int{1}, shouldClearWakeup: false, shouldPreempt: true, activeThreadFutexAddr: addr + 32, activeThreadFutexVal: wakeupVal + 5}, + {name: "Non-waiting threads with exited threads", wakeupAddr: addr, futexAddr: exec.FutexEmptyAddr, targetVal: 0, traverseRight: false, activeStackSize: 2, otherStackSize: 1, exitedThreadIdx: []int{}, shouldClearWakeup: false, shouldPreempt: true, activeThreadFutexAddr: addr + 40, activeThreadFutexVal: wakeupVal + 6}, + } + + for i, c := range cases { + t.Run(c.name, func(t *testing.T) { + goVm, state, contracts := setup(t, i*1000, nil) + mttestutil.SetupThreads(int64(i*5000), state, c.traverseRight, c.activeStackSize, c.otherStackSize) + step := state.Step + + state.Wakeup = c.wakeupAddr + state.GetMemory().SetWord(c.wakeupAddr&arch.AddressMask, wakeupVal) + + threads := mttestutil.GetAllThreads(state) + for idx, thread := range threads { + if slices.Contains(c.exitedThreadIdx, idx) { + thread.Exited = true + } else { + thread.FutexAddr = c.futexAddr + thread.FutexVal = c.targetVal + thread.FutexTimeoutStep = exec.FutexNoTimeout + } + } + + activeThread := state.GetCurrentThread() + activeThread.Exited = true + + activeThread.FutexAddr = c.activeThreadFutexAddr + activeThread.FutexVal = c.activeThreadFutexVal + activeThread.FutexTimeoutStep = exec.FutexNoTimeout + + expected := mttestutil.NewExpectedMTState(state) + expected.Step += 1 + + if c.shouldClearWakeup { + expected.Wakeup = exec.FutexEmptyAddr + } + if c.shouldPreempt { + // Just preempt the current thread + expected.ExpectPreemption(state) + } + + // State transition + var err error + var stepWitness *mipsevm.StepWitness + stepWitness, err = goVm.Step(true) + require.NoError(t, err) + expected.Validate(t, state) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) + }) + } +} + func TestEVM_SchedQuantumThreshold(t *testing.T) { - var tracer *tracing.Hooks cases := []struct { name string stepsSinceLastContextSwitch uint64 @@ -1511,7 +1357,7 @@ func TestEVM_SchedQuantumThreshold(t *testing.T) { t.Run(c.name, func(t *testing.T) { goVm, state, contracts := setup(t, i*789, nil) // Setup basic getThreadId syscall instruction - state.Memory.SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysGetTID // Set syscall number state.StepsSinceLastContextSwitch = c.stepsSinceLastContextSwitch step := state.Step @@ -1536,7 +1382,7 @@ func TestEVM_SchedQuantumThreshold(t *testing.T) { // Validate post-state expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) }) } } diff --git a/cannon/mipsevm/tests/evm_singlethreaded_test.go b/cannon/mipsevm/tests/evm_singlethreaded_test.go index cf19a83a14cea..56c5e31c3463f 100644 --- a/cannon/mipsevm/tests/evm_singlethreaded_test.go +++ b/cannon/mipsevm/tests/evm_singlethreaded_test.go @@ -1,3 +1,6 @@ +//go:build !cannon64 +// +build !cannon64 + package tests import ( @@ -5,7 +8,6 @@ import ( "os" "testing" - "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" @@ -17,8 +19,6 @@ import ( ) func TestEVM_LL(t *testing.T) { - var tracer *tracing.Hooks - cases := []struct { name string base Word @@ -42,7 +42,7 @@ func TestEVM_LL(t *testing.T) { insn := uint32((0b11_0000 << 26) | (baseReg & 0x1F << 21) | (rtReg & 0x1F << 16) | (0xFFFF & c.offset)) goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPC(pc), testutil.WithNextPC(pc+4)) state := goVm.GetState() - state.GetMemory().SetUint32(pc, insn) + testutil.StoreInstruction(state.GetMemory(), pc, insn) state.GetMemory().SetWord(c.effAddr, c.value) state.GetRegistersRef()[baseReg] = c.base step := state.GetStep() @@ -61,14 +61,12 @@ func TestEVM_LL(t *testing.T) { // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } } func TestEVM_SC(t *testing.T) { - var tracer *tracing.Hooks - cases := []struct { name string base Word @@ -92,7 +90,7 @@ func TestEVM_SC(t *testing.T) { insn := uint32((0b11_1000 << 26) | (baseReg & 0x1F << 21) | (rtReg & 0x1F << 16) | (0xFFFF & c.offset)) goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPC(pc), testutil.WithNextPC(pc+4)) state := goVm.GetState() - state.GetMemory().SetUint32(pc, insn) + testutil.StoreInstruction(state.GetMemory(), pc, insn) state.GetRegistersRef()[baseReg] = c.base state.GetRegistersRef()[rtReg] = c.value step := state.GetStep() @@ -103,7 +101,7 @@ func TestEVM_SC(t *testing.T) { expected.PC = pc + 4 expected.NextPC = pc + 8 expectedMemory := memory.NewMemory() - expectedMemory.SetUint32(pc, insn) + testutil.StoreInstruction(expectedMemory, pc, insn) expectedMemory.SetWord(c.effAddr, c.value) expected.MemoryRoot = expectedMemory.MerkleRoot() if rtReg != 0 { @@ -115,14 +113,12 @@ func TestEVM_SC(t *testing.T) { // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } } func TestEVM_SysRead_Preimage(t *testing.T) { - var tracer *tracing.Hooks - preimageValue := make([]byte, 0, 8) preimageValue = binary.BigEndian.AppendUint32(preimageValue, 0x12_34_56_78) preimageValue = binary.BigEndian.AppendUint32(preimageValue, 0x98_76_54_32) @@ -135,8 +131,8 @@ func TestEVM_SysRead_Preimage(t *testing.T) { count Word writeLen Word preimageOffset Word - prestateMem uint32 - postateMem uint32 + prestateMem Word + postateMem Word shouldPanic bool }{ {name: "Aligned addr, write 1 byte", addr: 0x00_00_FF_00, count: 1, writeLen: 1, preimageOffset: 8, prestateMem: 0xFF_FF_FF_FF, postateMem: 0x12_FF_FF_FF}, @@ -170,8 +166,8 @@ func TestEVM_SysRead_Preimage(t *testing.T) { state.GetRegistersRef()[4] = exec.FdPreimageRead state.GetRegistersRef()[5] = c.addr state.GetRegistersRef()[6] = c.count - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) - state.GetMemory().SetUint32(effAddr, c.prestateMem) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) + state.GetMemory().SetWord(effAddr, c.prestateMem) // Setup expectations expected := testutil.NewExpectedState(state) @@ -179,18 +175,18 @@ func TestEVM_SysRead_Preimage(t *testing.T) { expected.Registers[2] = c.writeLen expected.Registers[7] = 0 // no error expected.PreimageOffset += c.writeLen - expected.ExpectMemoryWrite(effAddr, c.postateMem) + expected.ExpectMemoryWriteWord(effAddr, c.postateMem) if c.shouldPanic { require.Panics(t, func() { _, _ = goVm.Step(true) }) - testutil.AssertPreimageOracleReverts(t, preimageKey, preimageValue, c.preimageOffset, v.Contracts, tracer) + testutil.AssertPreimageOracleReverts(t, preimageKey, preimageValue, c.preimageOffset, v.Contracts) } else { stepWitness, err := goVm.Step(true) require.NoError(t, err) // Check expectations expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, tracer) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) } }) } diff --git a/cannon/mipsevm/tests/fuzz_evm_common64_test.go b/cannon/mipsevm/tests/fuzz_evm_common64_test.go new file mode 100644 index 0000000000000..d972c3a7ff260 --- /dev/null +++ b/cannon/mipsevm/tests/fuzz_evm_common64_test.go @@ -0,0 +1,134 @@ +//go:build cannon64 +// +build cannon64 + +package tests + +import ( + "os" + "testing" + + "github.com/ethereum-optimism/optimism/cannon/mipsevm/testutil" + "github.com/stretchr/testify/require" +) + +func FuzzStateConsistencyMulOp(f *testing.F) { + f.Add(int64(0x80_00_00_00), int64(0x80_00_00_00), int64(1)) + f.Add( + testutil.ToSignedInteger(uint64(0xFF_FF_FF_FF_11_22_33_44)), + testutil.ToSignedInteger(uint64(0xFF_FF_FF_FF_11_22_33_44)), + int64(1), + ) + f.Add( + testutil.ToSignedInteger(uint64(0xFF_FF_FF_FF_80_00_00_00)), + testutil.ToSignedInteger(uint64(0xFF_FF_FF_FF_80_00_00_00)), + int64(1), + ) + f.Add( + testutil.ToSignedInteger(uint64(0xFF_FF_FF_FF_FF_FF_FF_FF)), + testutil.ToSignedInteger(uint64(0xFF_FF_FF_FF_FF_FF_FF_FF)), + int64(1), + ) + + const opcode uint32 = 28 + const mulFunct uint32 = 0x2 + versions := GetMipsVersionTestCases(f) + f.Fuzz(func(t *testing.T, rs int64, rt int64, seed int64) { + for _, v := range versions { + t.Run(v.Name, func(t *testing.T) { + mulOpConsistencyCheck(t, versions, opcode, true, mulFunct, Word(rs), Word(rt), seed) + }) + } + }) +} + +func FuzzStateConsistencyMultOp(f *testing.F) { + f.Add(int64(0x80_00_00_00), int64(0x80_00_00_00), int64(1)) + f.Add( + testutil.ToSignedInteger(uint64(0xFF_FF_FF_FF_11_22_33_44)), + testutil.ToSignedInteger(uint64(0xFF_FF_FF_FF_11_22_33_44)), + int64(1), + ) + f.Add( + testutil.ToSignedInteger(uint64(0xFF_FF_FF_FF_80_00_00_00)), + testutil.ToSignedInteger(uint64(0xFF_FF_FF_FF_80_00_00_00)), + int64(1), + ) + f.Add( + testutil.ToSignedInteger(uint64(0xFF_FF_FF_FF_FF_FF_FF_FF)), + testutil.ToSignedInteger(uint64(0xFF_FF_FF_FF_FF_FF_FF_FF)), + int64(1), + ) + + const multFunct uint32 = 0x18 + versions := GetMipsVersionTestCases(f) + f.Fuzz(func(t *testing.T, rs int64, rt int64, seed int64) { + mulOpConsistencyCheck(t, versions, 0, false, multFunct, Word(rs), Word(rt), seed) + }) +} + +func FuzzStateConsistencyMultuOp(f *testing.F) { + f.Add(uint64(0x80_00_00_00), uint64(0x80_00_00_00), int64(1)) + f.Add( + uint64(0xFF_FF_FF_FF_11_22_33_44), + uint64(0xFF_FF_FF_FF_11_22_33_44), + int64(1), + ) + f.Add( + uint64(0xFF_FF_FF_FF_80_00_00_00), + uint64(0xFF_FF_FF_FF_80_00_00_00), + int64(1), + ) + f.Add( + uint64(0xFF_FF_FF_FF_FF_FF_FF_FF), + uint64(0xFF_FF_FF_FF_FF_FF_FF_FF), + int64(1), + ) + + const multuFunct uint32 = 0x19 + versions := GetMipsVersionTestCases(f) + f.Fuzz(func(t *testing.T, rs uint64, rt uint64, seed int64) { + mulOpConsistencyCheck(t, versions, 0, false, multuFunct, rs, rt, seed) + }) +} + +func mulOpConsistencyCheck( + t *testing.T, versions []VersionedVMTestCase, + opcode uint32, expectRdReg bool, funct uint32, + rs Word, rt Word, seed int64) { + for _, v := range versions { + t.Run(v.Name, func(t *testing.T) { + rsReg := uint32(17) + rtReg := uint32(18) + rdReg := uint32(0) + if expectRdReg { + rdReg = 19 + } + + insn := opcode<<26 | rsReg<<21 | rtReg<<16 | rdReg<<11 | funct + goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(seed), testutil.WithPCAndNextPC(0)) + state := goVm.GetState() + state.GetRegistersRef()[rsReg] = rs + state.GetRegistersRef()[rtReg] = rt + testutil.StoreInstruction(state.GetMemory(), 0, insn) + step := state.GetStep() + + // mere sanity checks + expected := testutil.NewExpectedState(state) + expected.ExpectStep() + + stepWitness, err := goVm.Step(true) + require.NoError(t, err) + + // use the post-state rdReg or LO and HI just so we can run sanity checks + if expectRdReg { + expected.Registers[rdReg] = state.GetRegistersRef()[rdReg] + } else { + expected.LO = state.GetCpu().LO + expected.HI = state.GetCpu().HI + } + expected.Validate(t, state) + + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) + }) + } +} diff --git a/cannon/mipsevm/tests/fuzz_evm_common_test.go b/cannon/mipsevm/tests/fuzz_evm_common_test.go index 8c7081456af86..c637cbbe19a0b 100644 --- a/cannon/mipsevm/tests/fuzz_evm_common_test.go +++ b/cannon/mipsevm/tests/fuzz_evm_common_test.go @@ -2,7 +2,6 @@ package tests import ( "bytes" - "encoding/binary" "math" "os" "testing" @@ -28,7 +27,7 @@ func FuzzStateSyscallBrk(f *testing.F) { goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(seed)) state := goVm.GetState() state.GetRegistersRef()[2] = arch.SysBrk - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) step := state.GetStep() expected := testutil.NewExpectedState(state) @@ -43,7 +42,7 @@ func FuzzStateSyscallBrk(f *testing.F) { require.False(t, stepWitness.HasPreimage()) expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, nil) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } }) @@ -68,7 +67,7 @@ func FuzzStateSyscallMmap(f *testing.F) { state.GetRegistersRef()[2] = arch.SysMmap state.GetRegistersRef()[4] = addr state.GetRegistersRef()[5] = siz - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) expected := testutil.NewExpectedState(state) expected.Step += 1 @@ -98,7 +97,7 @@ func FuzzStateSyscallMmap(f *testing.F) { require.False(t, stepWitness.HasPreimage()) expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, nil) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } }) @@ -114,7 +113,7 @@ func FuzzStateSyscallExitGroup(f *testing.F) { state := goVm.GetState() state.GetRegistersRef()[2] = arch.SysExitGroup state.GetRegistersRef()[4] = Word(exitCode) - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) step := state.GetStep() expected := testutil.NewExpectedState(state) @@ -127,7 +126,7 @@ func FuzzStateSyscallExitGroup(f *testing.F) { require.False(t, stepWitness.HasPreimage()) expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, nil) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } }) @@ -144,7 +143,7 @@ func FuzzStateSyscallFcntl(f *testing.F) { state.GetRegistersRef()[2] = arch.SysFcntl state.GetRegistersRef()[4] = fd state.GetRegistersRef()[5] = cmd - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) step := state.GetStep() expected := testutil.NewExpectedState(state) @@ -158,7 +157,7 @@ func FuzzStateSyscallFcntl(f *testing.F) { expected.Registers[2] = 0 expected.Registers[7] = 0 default: - expected.Registers[2] = 0xFF_FF_FF_FF + expected.Registers[2] = ^Word(0) expected.Registers[7] = exec.MipsEBADF } } else if cmd == 3 { @@ -170,11 +169,11 @@ func FuzzStateSyscallFcntl(f *testing.F) { expected.Registers[2] = 1 expected.Registers[7] = 0 default: - expected.Registers[2] = 0xFF_FF_FF_FF + expected.Registers[2] = ^Word(0) expected.Registers[7] = exec.MipsEBADF } } else { - expected.Registers[2] = 0xFF_FF_FF_FF + expected.Registers[2] = ^Word(0) expected.Registers[7] = exec.MipsEINVAL } @@ -183,7 +182,7 @@ func FuzzStateSyscallFcntl(f *testing.F) { require.False(t, stepWitness.HasPreimage()) expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, nil) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } }) @@ -205,7 +204,7 @@ func FuzzStateHintRead(f *testing.F) { state.GetRegistersRef()[4] = exec.FdHintRead state.GetRegistersRef()[5] = addr state.GetRegistersRef()[6] = count - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) step := state.GetStep() expected := testutil.NewExpectedState(state) @@ -220,7 +219,7 @@ func FuzzStateHintRead(f *testing.F) { require.False(t, stepWitness.HasPreimage()) expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, nil) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } }) @@ -233,7 +232,7 @@ func FuzzStatePreimageRead(f *testing.F) { t.Run(v.Name, func(t *testing.T) { effAddr := addr & arch.AddressMask pc = pc & arch.AddressMask - preexistingMemoryVal := [4]byte{0xFF, 0xFF, 0xFF, 0xFF} + preexistingMemoryVal := ^arch.Word(0) preimageValue := []byte("hello world") preimageData := testutil.AddPreimageLengthPrefix(preimageValue) if preimageOffset >= Word(len(preimageData)) || pc == effAddr { @@ -249,12 +248,12 @@ func FuzzStatePreimageRead(f *testing.F) { state.GetRegistersRef()[4] = exec.FdPreimageRead state.GetRegistersRef()[5] = addr state.GetRegistersRef()[6] = count - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) - state.GetMemory().SetUint32(effAddr, binary.BigEndian.Uint32(preexistingMemoryVal[:])) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) + state.GetMemory().SetWord(effAddr, preexistingMemoryVal) step := state.GetStep() alignment := addr & arch.ExtMask - writeLen := 4 - alignment + writeLen := arch.WordSizeBytes - alignment if count < writeLen { writeLen = count } @@ -273,9 +272,10 @@ func FuzzStatePreimageRead(f *testing.F) { expected.PreimageOffset += writeLen if writeLen > 0 { // Expect a memory write - expectedMemory := preexistingMemoryVal + var expectedMemory []byte + expectedMemory = arch.ByteOrderWord.AppendWord(expectedMemory, preexistingMemoryVal) copy(expectedMemory[alignment:], preimageData[preimageOffset:preimageOffset+writeLen]) - expected.ExpectMemoryWrite(effAddr, binary.BigEndian.Uint32(expectedMemory[:])) + expected.ExpectMemoryWriteWord(effAddr, arch.ByteOrderWord.Word(expectedMemory[:])) } stepWitness, err := goVm.Step(true) @@ -283,7 +283,7 @@ func FuzzStatePreimageRead(f *testing.F) { require.True(t, stepWitness.HasPreimage()) expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, nil) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } }) @@ -331,7 +331,7 @@ func FuzzStateHintWrite(f *testing.F) { step := state.GetStep() err := state.GetMemory().SetMemoryRange(addr, bytes.NewReader(hintData[int(lastHintLen):])) require.NoError(t, err) - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) // Set up expectations expected := testutil.NewExpectedState(state) @@ -365,7 +365,7 @@ func FuzzStateHintWrite(f *testing.F) { // Validate require.Equal(t, expectedHints, oracle.Hints()) expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, nil) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } }) @@ -382,7 +382,7 @@ func FuzzStatePreimageWrite(f *testing.F) { addr += 8 } effAddr := addr & arch.AddressMask - preexistingMemoryVal := [4]byte{0x12, 0x34, 0x56, 0x78} + preexistingMemoryVal := [8]byte{0x12, 0x34, 0x56, 0x78, 0x87, 0x65, 0x43, 0x21} preimageData := []byte("hello world") preimageKey := preimage.Keccak256Key(crypto.Keccak256Hash(preimageData)).PreimageKey() oracle := testutil.StaticOracle(t, preimageData) @@ -394,13 +394,13 @@ func FuzzStatePreimageWrite(f *testing.F) { state.GetRegistersRef()[4] = exec.FdPreimageWrite state.GetRegistersRef()[5] = addr state.GetRegistersRef()[6] = count - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) - state.GetMemory().SetUint32(effAddr, binary.BigEndian.Uint32(preexistingMemoryVal[:])) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) + state.GetMemory().SetWord(effAddr, arch.ByteOrderWord.Word(preexistingMemoryVal[:])) step := state.GetStep() expectBytesWritten := count alignment := addr & arch.ExtMask - sz := 4 - alignment + sz := arch.WordSizeBytes - alignment if sz < expectBytesWritten { expectBytesWritten = sz } @@ -425,7 +425,7 @@ func FuzzStatePreimageWrite(f *testing.F) { require.False(t, stepWitness.HasPreimage()) expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts, nil) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } }) diff --git a/cannon/mipsevm/tests/fuzz_evm_multithreaded_test.go b/cannon/mipsevm/tests/fuzz_evm_multithreaded_test.go index d898391ba4d9b..49f45a4a5f2c5 100644 --- a/cannon/mipsevm/tests/fuzz_evm_multithreaded_test.go +++ b/cannon/mipsevm/tests/fuzz_evm_multithreaded_test.go @@ -27,7 +27,7 @@ func FuzzStateSyscallCloneMT(f *testing.F) { // Setup state.NextThreadId = nextThreadId - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) state.GetRegistersRef()[2] = arch.SysClone state.GetRegistersRef()[4] = exec.ValidCloneFlags state.GetRegistersRef()[5] = stackPtr @@ -62,6 +62,6 @@ func FuzzStateSyscallCloneMT(f *testing.F) { require.False(t, stepWitness.HasPreimage()) expected.Validate(t, state) - testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), v.Contracts, nil) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), v.Contracts) }) } diff --git a/cannon/mipsevm/tests/fuzz_evm_singlethreaded_test.go b/cannon/mipsevm/tests/fuzz_evm_singlethreaded_test.go index 7d2c8ff6f28a8..375e1fec1832f 100644 --- a/cannon/mipsevm/tests/fuzz_evm_singlethreaded_test.go +++ b/cannon/mipsevm/tests/fuzz_evm_singlethreaded_test.go @@ -1,10 +1,12 @@ +//go:build !cannon64 +// +build !cannon64 + package tests import ( "os" "testing" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/require" "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" @@ -17,7 +19,7 @@ func FuzzStateSyscallCloneST(f *testing.F) { goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(seed)) state := goVm.GetState() state.GetRegistersRef()[2] = arch.SysClone - state.GetMemory().SetUint32(state.GetPC(), syscallInsn) + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) step := state.GetStep() expected := testutil.NewExpectedState(state) @@ -32,11 +34,6 @@ func FuzzStateSyscallCloneST(f *testing.F) { require.False(t, stepWitness.HasPreimage()) expected.Validate(t, state) - - evm := testutil.NewMIPSEVM(v.Contracts) - evmPost := evm.Step(t, stepWitness, step, v.StateHashFn) - goPost, _ := goVm.GetState().EncodeWitness() - require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), - "mipsevm produced different state than EVM") + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) }) } diff --git a/cannon/mipsevm/tests/testfuncs_test.go b/cannon/mipsevm/tests/testfuncs_test.go new file mode 100644 index 0000000000000..0087ab445d737 --- /dev/null +++ b/cannon/mipsevm/tests/testfuncs_test.go @@ -0,0 +1,502 @@ +package tests + +import ( + "fmt" + "os" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/exec" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded" + mttestutil "github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded/testutil" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/testutil" + preimage "github.com/ethereum-optimism/optimism/op-preimage" + "github.com/ethereum/go-ethereum/crypto" +) + +type operatorTestCase struct { + name string + isImm bool + rs Word + rt Word + imm uint16 + funct uint32 + opcode uint32 + expectRes Word +} + +func testOperators(t *testing.T, cases []operatorTestCase, mips32Insn bool) { + versions := GetMipsVersionTestCases(t) + for _, v := range versions { + for i, tt := range cases { + // sign extend inputs for 64-bit compatibility + if mips32Insn { + tt.rs = randomizeUpperWord(signExtend64(tt.rs)) + tt.rt = randomizeUpperWord(signExtend64(tt.rt)) + tt.expectRes = signExtend64(tt.expectRes) + } + + testName := fmt.Sprintf("%v (%v)", tt.name, v.Name) + t.Run(testName, func(t *testing.T) { + validator := testutil.NewEvmValidator(t, v.StateHashFn, v.Contracts) + goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPC(0), testutil.WithNextPC(4)) + state := goVm.GetState() + var insn uint32 + var baseReg uint32 = 17 + var rtReg uint32 + var rdReg uint32 + if tt.isImm { + rtReg = 8 + insn = tt.opcode<<26 | baseReg<<21 | rtReg<<16 | uint32(tt.imm) + state.GetRegistersRef()[rtReg] = tt.rt + state.GetRegistersRef()[baseReg] = tt.rs + } else { + rtReg = 18 + rdReg = 8 + insn = baseReg<<21 | rtReg<<16 | rdReg<<11 | tt.funct + state.GetRegistersRef()[baseReg] = tt.rs + state.GetRegistersRef()[rtReg] = tt.rt + } + testutil.StoreInstruction(state.GetMemory(), 0, insn) + step := state.GetStep() + + // Setup expectations + expected := testutil.NewExpectedState(state) + expected.Step += 1 + expected.PC = 4 + expected.NextPC = 8 + if tt.isImm { + expected.Registers[rtReg] = tt.expectRes + } else { + expected.Registers[rdReg] = tt.expectRes + } + + stepWitness, err := goVm.Step(true) + require.NoError(t, err) + + // Check expectations + expected.Validate(t, state) + validator.ValidateEVM(t, stepWitness, step, goVm) + }) + } + } +} + +type mulDivTestCase struct { + name string + rs Word + rt Word + funct uint32 + opcode uint32 + expectHi Word + expectLo Word + expectRes Word + rdReg uint32 + panicMsg string + revertMsg string +} + +func testMulDiv(t *testing.T, cases []mulDivTestCase, mips32Insn bool) { + versions := GetMipsVersionTestCases(t) + for _, v := range versions { + for i, tt := range cases { + if mips32Insn { + tt.rs = randomizeUpperWord(signExtend64(tt.rs)) + tt.rt = randomizeUpperWord(signExtend64(tt.rt)) + tt.expectHi = signExtend64(tt.expectHi) + tt.expectLo = signExtend64(tt.expectLo) + tt.expectRes = signExtend64(tt.expectRes) + } + + testName := fmt.Sprintf("%v (%v)", tt.name, v.Name) + t.Run(testName, func(t *testing.T) { + goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPC(0), testutil.WithNextPC(4)) + state := goVm.GetState() + var insn uint32 + baseReg := uint32(0x9) + rtReg := uint32(0xa) + + insn = tt.opcode<<26 | baseReg<<21 | rtReg<<16 | tt.rdReg<<11 | tt.funct + state.GetRegistersRef()[rtReg] = tt.rt + state.GetRegistersRef()[baseReg] = tt.rs + testutil.StoreInstruction(state.GetMemory(), 0, insn) + + if tt.panicMsg != "" { + proofData := v.ProofGenerator(t, goVm.GetState()) + require.PanicsWithValue(t, tt.panicMsg, func() { + _, _ = goVm.Step( + false) + }) + testutil.AssertEVMReverts(t, state, v.Contracts, nil, proofData, testutil.CreateErrorStringMatcher(tt.revertMsg)) + return + } + + step := state.GetStep() + // Setup expectations + expected := testutil.NewExpectedState(state) + expected.ExpectStep() + if tt.expectRes != 0 { + expected.Registers[tt.rdReg] = tt.expectRes + } else { + expected.HI = tt.expectHi + expected.LO = tt.expectLo + } + + stepWitness, err := goVm.Step(true) + require.NoError(t, err) + + // Check expectations + expected.Validate(t, state) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) + }) + } + } +} + +type loadStoreTestCase struct { + name string + rt Word + base Word + imm uint32 + opcode uint32 + memVal Word + expectMemVal Word + expectRes Word +} + +func testLoadStore(t *testing.T, cases []loadStoreTestCase) { + baseReg := uint32(9) + rtReg := uint32(8) + + v := GetMultiThreadedTestCase(t) + for i, tt := range cases { + testName := fmt.Sprintf("%v %v", v.Name, tt.name) + t.Run(testName, func(t *testing.T) { + addr := tt.base + Word(tt.imm) + effAddr := arch.AddressMask & addr + + goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPCAndNextPC(0)) + state := goVm.GetState() + + insn := tt.opcode<<26 | baseReg<<21 | rtReg<<16 | uint32(tt.imm) + state.GetRegistersRef()[rtReg] = tt.rt + state.GetRegistersRef()[baseReg] = tt.base + + testutil.StoreInstruction(state.GetMemory(), 0, insn) + state.GetMemory().SetWord(effAddr, tt.memVal) + step := state.GetStep() + + // Setup expectations + expected := testutil.NewExpectedState(state) + expected.ExpectStep() + if tt.expectMemVal != 0 { + expected.ExpectMemoryWriteWord(effAddr, tt.expectMemVal) + } else { + expected.Registers[rtReg] = tt.expectRes + } + stepWitness, err := goVm.Step(true) + require.NoError(t, err) + + // Check expectations + expected.Validate(t, state) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) + }) + } +} + +type branchTestCase struct { + name string + pc Word + expectNextPC Word + opcode uint32 + regimm uint32 + expectLink bool + rs arch.SignedInteger + offset uint16 +} + +func testBranch(t *testing.T, cases []branchTestCase) { + versions := GetMipsVersionTestCases(t) + for _, v := range versions { + for i, tt := range cases { + testName := fmt.Sprintf("%v (%v)", tt.name, v.Name) + t.Run(testName, func(t *testing.T) { + goVm := v.VMFactory(nil, os.Stdout, os.Stderr, testutil.CreateLogger(), testutil.WithRandomization(int64(i)), testutil.WithPCAndNextPC(tt.pc)) + state := goVm.GetState() + const rsReg = 8 // t0 + insn := tt.opcode<<26 | rsReg<<21 | tt.regimm<<16 | uint32(tt.offset) + testutil.StoreInstruction(state.GetMemory(), tt.pc, insn) + state.GetRegistersRef()[rsReg] = Word(tt.rs) + step := state.GetStep() + + // Setup expectations + expected := testutil.NewExpectedState(state) + expected.Step += 1 + expected.PC = state.GetCpu().NextPC + expected.NextPC = tt.expectNextPC + if tt.expectLink { + expected.Registers[31] = state.GetPC() + 8 + } + + stepWitness, err := goVm.Step(true) + require.NoError(t, err) + + // Check expectations + expected.Validate(t, state) + testutil.ValidateEVM(t, stepWitness, step, goVm, v.StateHashFn, v.Contracts) + }) + } + } +} + +type testMTStoreOpsClearMemReservationTestCase struct { + // name is the test name + name string + // opcode is the instruction opcode + opcode uint32 + // offset is the immediate offset encoded in the instruction + offset uint32 + // base is the base/rs register prestate + base Word + // effAddr is the address used to set the prestate preMem value. It is also used as the base LLAddress that can be adjusted reservation assertions + effAddr Word + // premem is the prestate value of the word located at effrAddr + preMem Word + // postMem is the expected post-state value of the word located at effAddr + postMem Word +} + +func testMTStoreOpsClearMemReservation(t *testing.T, cases []testMTStoreOpsClearMemReservationTestCase) { + llVariations := []struct { + name string + llReservationStatus multithreaded.LLReservationStatus + matchThreadId bool + effAddrOffset Word + shouldClearReservation bool + }{ + {name: "matching reservation", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: true, shouldClearReservation: true}, + {name: "matching reservation, unaligned", llReservationStatus: multithreaded.LLStatusActive32bit, effAddrOffset: 1, matchThreadId: true, shouldClearReservation: true}, + {name: "matching reservation, 64-bit", llReservationStatus: multithreaded.LLStatusActive64bit, matchThreadId: true, shouldClearReservation: true}, + {name: "matching reservation, diff thread", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: false, shouldClearReservation: true}, + {name: "matching reservation, diff thread, 64-bit", llReservationStatus: multithreaded.LLStatusActive64bit, matchThreadId: false, shouldClearReservation: true}, + {name: "mismatched reservation", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: true, effAddrOffset: 8, shouldClearReservation: false}, + {name: "mismatched reservation, diff thread", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: false, effAddrOffset: 8, shouldClearReservation: false}, + {name: "no reservation, matching addr", llReservationStatus: multithreaded.LLStatusNone, matchThreadId: true, shouldClearReservation: true}, + {name: "no reservation, mismatched addr", llReservationStatus: multithreaded.LLStatusNone, matchThreadId: true, effAddrOffset: 8, shouldClearReservation: false}, + } + + rt := Word(0x12_34_56_78) + //rt := Word(0x12_34_56_78_12_34_56_78) + baseReg := uint32(5) + rtReg := uint32(6) + for i, c := range cases { + for _, v := range llVariations { + tName := fmt.Sprintf("%v (%v)", c.name, v.name) + t.Run(tName, func(t *testing.T) { + t.Parallel() + insn := uint32((c.opcode << 26) | (baseReg & 0x1F << 21) | (rtReg & 0x1F << 16) | (0xFFFF & c.offset)) + goVm, state, contracts := setup(t, i, nil, testutil.WithPCAndNextPC(0x08)) + step := state.GetStep() + + // Define LL-related params + llAddress := c.effAddr + v.effAddrOffset + llOwnerThread := state.GetCurrentThread().ThreadId + if !v.matchThreadId { + llOwnerThread += 1 + } + + // Setup state + state.GetRegistersRef()[rtReg] = rt + state.GetRegistersRef()[baseReg] = c.base + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), insn) + state.GetMemory().SetWord(c.effAddr, c.preMem) + state.LLReservationStatus = v.llReservationStatus + state.LLAddress = llAddress + state.LLOwnerThread = llOwnerThread + + // Setup expectations + expected := mttestutil.NewExpectedMTState(state) + expected.ExpectStep() + expected.ExpectMemoryWordWrite(c.effAddr, c.postMem) + if v.shouldClearReservation { + expected.LLReservationStatus = multithreaded.LLStatusNone + expected.LLAddress = 0 + expected.LLOwnerThread = 0 + } + + stepWitness, err := goVm.Step(true) + require.NoError(t, err) + + // Check expectations + expected.Validate(t, state) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) + }) + } + } +} + +type testMTSysReadPreimageTestCase struct { + name string + addr Word + count Word + writeLen Word + preimageOffset Word + prestateMem Word + postateMem Word + shouldPanic bool +} + +func testMTSysReadPreimage(t *testing.T, preimageValue []byte, cases []testMTSysReadPreimageTestCase) { + llVariations := []struct { + name string + llReservationStatus multithreaded.LLReservationStatus + matchThreadId bool + effAddrOffset Word + shouldClearReservation bool + }{ + {name: "matching reservation", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: true, shouldClearReservation: true}, + {name: "matching reservation, unaligned", llReservationStatus: multithreaded.LLStatusActive32bit, effAddrOffset: 1, matchThreadId: true, shouldClearReservation: true}, + {name: "matching reservation, diff thread", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: false, shouldClearReservation: true}, + {name: "mismatched reservation", llReservationStatus: multithreaded.LLStatusActive32bit, matchThreadId: true, effAddrOffset: 8, shouldClearReservation: false}, + {name: "mismatched reservation", llReservationStatus: multithreaded.LLStatusActive64bit, matchThreadId: false, effAddrOffset: 8, shouldClearReservation: false}, + {name: "no reservation, matching addr", llReservationStatus: multithreaded.LLStatusNone, matchThreadId: true, shouldClearReservation: true}, + {name: "no reservation, mismatched addr", llReservationStatus: multithreaded.LLStatusNone, matchThreadId: true, effAddrOffset: 8, shouldClearReservation: false}, + } + + for i, c := range cases { + for _, v := range llVariations { + tName := fmt.Sprintf("%v (%v)", c.name, v.name) + t.Run(tName, func(t *testing.T) { + t.Parallel() + effAddr := arch.AddressMask & c.addr + preimageKey := preimage.Keccak256Key(crypto.Keccak256Hash(preimageValue)).PreimageKey() + oracle := testutil.StaticOracle(t, preimageValue) + goVm, state, contracts := setup(t, i, oracle) + step := state.GetStep() + + // Define LL-related params + llAddress := effAddr + v.effAddrOffset + llOwnerThread := state.GetCurrentThread().ThreadId + if !v.matchThreadId { + llOwnerThread += 1 + } + + // Set up state + state.PreimageKey = preimageKey + state.PreimageOffset = c.preimageOffset + state.GetRegistersRef()[2] = arch.SysRead + state.GetRegistersRef()[4] = exec.FdPreimageRead + state.GetRegistersRef()[5] = c.addr + state.GetRegistersRef()[6] = c.count + testutil.StoreInstruction(state.GetMemory(), state.GetPC(), syscallInsn) + state.LLReservationStatus = v.llReservationStatus + state.LLAddress = llAddress + state.LLOwnerThread = llOwnerThread + state.GetMemory().SetWord(effAddr, c.prestateMem) + + // Setup expectations + expected := mttestutil.NewExpectedMTState(state) + expected.ExpectStep() + expected.ActiveThread().Registers[2] = c.writeLen + expected.ActiveThread().Registers[7] = 0 // no error + expected.PreimageOffset += c.writeLen + expected.ExpectMemoryWordWrite(effAddr, c.postateMem) + if v.shouldClearReservation { + expected.LLReservationStatus = multithreaded.LLStatusNone + expected.LLAddress = 0 + expected.LLOwnerThread = 0 + } + + if c.shouldPanic { + require.Panics(t, func() { _, _ = goVm.Step(true) }) + testutil.AssertPreimageOracleReverts(t, preimageKey, preimageValue, c.preimageOffset, contracts) + } else { + stepWitness, err := goVm.Step(true) + require.NoError(t, err) + + // Check expectations + expected.Validate(t, state) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) + } + }) + } + } +} + +func testNoopSyscall(t *testing.T, syscalls map[string]uint32) { + for noopName, noopVal := range syscalls { + t.Run(noopName, func(t *testing.T) { + t.Parallel() + goVm, state, contracts := setup(t, int(noopVal), nil) + + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) + state.GetRegistersRef()[2] = Word(noopVal) // Set syscall number + step := state.Step + + // Set up post-state expectations + expected := mttestutil.NewExpectedMTState(state) + expected.ExpectStep() + expected.ActiveThread().Registers[2] = 0 + expected.ActiveThread().Registers[7] = 0 + + // State transition + stepWitness, err := goVm.Step(true) + require.NoError(t, err) + + // Validate post-state + expected.Validate(t, state) + testutil.ValidateEVM(t, stepWitness, step, goVm, multithreaded.GetStateHashFn(), contracts) + }) + } +} + +func testUnsupportedSyscall(t *testing.T, unsupportedSyscalls []uint32) { + for i, syscallNum := range unsupportedSyscalls { + testName := fmt.Sprintf("Unsupported syscallNum %v", syscallNum) + i := i + syscallNum := syscallNum + t.Run(testName, func(t *testing.T) { + t.Parallel() + goVm, state, contracts := setup(t, i*3434, nil) + // Setup basic getThreadId syscall instruction + testutil.StoreInstruction(state.Memory, state.GetPC(), syscallInsn) + state.GetRegistersRef()[2] = Word(syscallNum) + proofData := multiThreadedProofGenerator(t, state) + // Set up post-state expectations + require.Panics(t, func() { _, _ = goVm.Step(true) }) + + errorMessage := "unimplemented syscall" + testutil.AssertEVMReverts(t, state, contracts, nil, proofData, testutil.CreateErrorStringMatcher(errorMessage)) + }) + } +} + +// signExtend64 is used to sign-extend 32-bit words for 64-bit compatibility +func signExtend64(w Word) Word { + if arch.IsMips32 { + return w + } else { + return exec.SignExtend(w, 32) + } +} + +const seed = 0xdead + +var rand = testutil.NewRandHelper(seed) + +// randomizeUpperWord is used to assert that 32-bit operations use the lower word only +func randomizeUpperWord(w Word) Word { + if arch.IsMips32 { + return w + } else { + if w>>32 == 0x0 { // nolint:staticcheck + rnd := rand.Uint32() + upper := uint64(rnd) << 32 + return Word(upper | uint64(uint32(w))) + } else { + return w + } + } +} diff --git a/cannon/mipsevm/testutil/arch.go b/cannon/mipsevm/testutil/arch.go index 2efa75eafcec6..b4eb50b7e3f17 100644 --- a/cannon/mipsevm/testutil/arch.go +++ b/cannon/mipsevm/testutil/arch.go @@ -4,6 +4,7 @@ package testutil import ( "bytes" + "testing" "github.com/stretchr/testify/require" @@ -40,3 +41,16 @@ func SetMemoryUint64(t require.TestingT, mem *memory.Memory, addr Word, value ui actual := mem.GetWord(effAddr) require.Equal(t, Word(value), actual) } + +// ToSignedInteger converts the unsigend Word to a SignedInteger. +// Useful for avoiding Go compiler warnings for literals that don't fit in a signed type +func ToSignedInteger(x Word) arch.SignedInteger { + return arch.SignedInteger(x) +} + +// Cannon32OnlyTest skips the test if it's not a cannon64 build +func Cannon32OnlyTest(t testing.TB, msg string, args ...any) { + if !arch.IsMips32 { + t.Skipf(msg, args...) + } +} diff --git a/cannon/mipsevm/testutil/elf.go b/cannon/mipsevm/testutil/elf.go index b5b63cdeb1d39..3e1896963cda4 100644 --- a/cannon/mipsevm/testutil/elf.go +++ b/cannon/mipsevm/testutil/elf.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" "github.com/ethereum-optimism/optimism/cannon/mipsevm" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" "github.com/ethereum-optimism/optimism/cannon/mipsevm/program" ) @@ -26,3 +27,12 @@ func LoadELFProgram[T mipsevm.FPVMState](t require.TestingT, name string, initSt require.NoError(t, program.PatchStack(state), "add initial stack") return state, meta } + +// ProgramPath returns the appropriate ELF test program for the current architecture +func ProgramPath(programName string) string { + basename := programName + ".elf" + if !arch.IsMips32 { + basename = programName + ".64.elf" + } + return "../../testdata/example/bin/" + basename +} diff --git a/cannon/mipsevm/testutil/evm.go b/cannon/mipsevm/testutil/evm.go index 6d424ae62493e..6a4832c2953df 100644 --- a/cannon/mipsevm/testutil/evm.go +++ b/cannon/mipsevm/testutil/evm.go @@ -7,6 +7,7 @@ import ( "math/big" "os" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" "github.com/ethereum-optimism/optimism/op-chain-ops/srcmap" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/eth/tracers/logger" @@ -66,7 +67,11 @@ func loadArtifacts(version MipsVersion) (*Artifacts, error) { case MipsSingleThreaded: mips, err = artifactFS.ReadArtifact("MIPS.sol", "MIPS") case MipsMultithreaded: - mips, err = artifactFS.ReadArtifact("MIPS2.sol", "MIPS2") + if arch.IsMips32 { + mips, err = artifactFS.ReadArtifact("MIPS2.sol", "MIPS2") + } else { + mips, err = artifactFS.ReadArtifact("MIPS64.sol", "MIPS64") + } default: return nil, fmt.Errorf("Unknown MipsVersion supplied: %v", version) } @@ -167,7 +172,11 @@ func SourceMapTracer(t require.TestingT, version MipsVersion, mips *foundry.Arti case MipsSingleThreaded: mipsSrcMap, err = srcFS.SourceMap(mips, "MIPS") case MipsMultithreaded: - mipsSrcMap, err = srcFS.SourceMap(mips, "MIPS2") + if arch.IsMips32 { + mipsSrcMap, err = srcFS.SourceMap(mips, "MIPS2") + } else { + mipsSrcMap, err = srcFS.SourceMap(mips, "MIPS64") + } default: require.Fail(t, "invalid mips version") } diff --git a/cannon/mipsevm/testutil/memory.go b/cannon/mipsevm/testutil/memory.go index 7d90893d6b9f4..ca41453aaf62b 100644 --- a/cannon/mipsevm/testutil/memory.go +++ b/cannon/mipsevm/testutil/memory.go @@ -1,6 +1,12 @@ package testutil -import "encoding/binary" +import ( + "encoding/binary" + "fmt" + + "github.com/ethereum-optimism/optimism/cannon/mipsevm/exec" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/memory" +) func Uint32ToBytes(val uint32) []byte { data := make([]byte, 4) @@ -15,3 +21,18 @@ func Uint64ToBytes(val uint64) []byte { return data } + +// StoreInstruction writes a 4-byte instruction to memory +func StoreInstruction(mem *memory.Memory, pc Word, insn uint32) { + if pc&0x3 != 0 { + panic(fmt.Errorf("unaligned memory access: %x", pc)) + } + exec.StoreSubWord(mem, pc, 4, Word(insn), new(exec.NoopMemoryTracker)) +} + +func GetInstruction(mem *memory.Memory, pc Word) uint32 { + if pc&0x3 != 0 { + panic(fmt.Errorf("unaligned memory access: %x", pc)) + } + return uint32(exec.LoadSubWord(mem, pc, 4, false, new(exec.NoopMemoryTracker))) +} diff --git a/cannon/mipsevm/testutil/mips.go b/cannon/mipsevm/testutil/mips.go index 3ce38809c9aa8..0d5322c6fb6ef 100644 --- a/cannon/mipsevm/testutil/mips.go +++ b/cannon/mipsevm/testutil/mips.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" "github.com/ethereum-optimism/optimism/cannon/mipsevm" @@ -22,6 +23,9 @@ import ( preimage "github.com/ethereum-optimism/optimism/op-preimage" ) +// maxStepGas should be less than the L1 gas limit +const maxStepGas = 20_000_000 + type MIPSEVM struct { sender vm.AccountRef startingGas uint64 @@ -36,11 +40,35 @@ type MIPSEVM struct { lastPreimageOracleInput []byte } -func NewMIPSEVM(contracts *ContractMetadata) *MIPSEVM { +func newMIPSEVM(contracts *ContractMetadata, opts ...evmOption) *MIPSEVM { env, evmState := NewEVMEnv(contracts) sender := vm.AccountRef{0x13, 0x37} - startingGas := uint64(30_000_000) - return &MIPSEVM{sender, startingGas, env, evmState, contracts.Addresses, nil, contracts.Artifacts, math.MaxUint64, nil, nil} + startingGas := uint64(maxStepGas) + evm := &MIPSEVM{sender, startingGas, env, evmState, contracts.Addresses, nil, contracts.Artifacts, math.MaxUint64, nil, nil} + for _, opt := range opts { + opt(evm) + } + return evm +} + +type evmOption func(c *MIPSEVM) + +func WithSourceMapTracer(t *testing.T, ver MipsVersion) evmOption { + return func(evm *MIPSEVM) { + evm.SetSourceMapTracer(t, ver) + } +} + +func WithTracingHooks(tracer *tracing.Hooks) evmOption { + return func(evm *MIPSEVM) { + evm.SetTracer(tracer) + } +} + +func WithLocalOracle(oracle mipsevm.PreimageOracle) evmOption { + return func(evm *MIPSEVM) { + evm.SetLocalOracle(oracle) + } } func (m *MIPSEVM) SetTracer(tracer *tracing.Hooks) { @@ -170,33 +198,68 @@ func LogStepFailureAtCleanup(t *testing.T, mipsEvm *MIPSEVM) { }) } -// ValidateEVM runs a single evm step and validates against an FPVM poststate -func ValidateEVM(t *testing.T, stepWitness *mipsevm.StepWitness, step uint64, goVm mipsevm.FPVM, hashFn mipsevm.HashFn, contracts *ContractMetadata, tracer *tracing.Hooks) { - if !arch.IsMips32 { - // TODO(#12250) Re-enable EVM validation once 64-bit MIPS contracts are completed - t.Logf("WARNING: Skipping EVM validation for 64-bit MIPS") - return - } +type EvmValidator struct { + evm *MIPSEVM + hashFn mipsevm.HashFn +} - evm := NewMIPSEVM(contracts) - evm.SetTracer(tracer) +// NewEvmValidator creates a validator that can be run repeatedly across multiple steps +func NewEvmValidator(t *testing.T, hashFn mipsevm.HashFn, contracts *ContractMetadata, opts ...evmOption) *EvmValidator { + evm := newMIPSEVM(contracts, opts...) LogStepFailureAtCleanup(t, evm) - evmPost := evm.Step(t, stepWitness, step, hashFn) + return &EvmValidator{ + evm: evm, + hashFn: hashFn, + } +} + +func (v *EvmValidator) ValidateEVM(t *testing.T, stepWitness *mipsevm.StepWitness, step uint64, goVm mipsevm.FPVM) { + evmPost := v.evm.Step(t, stepWitness, step, v.hashFn) goPost, _ := goVm.GetState().EncodeWitness() require.Equal(t, hexutil.Bytes(goPost).String(), hexutil.Bytes(evmPost).String(), "mipsevm produced different state than EVM") } +// ValidateEVM runs a single evm step and validates against an FPVM poststate +func ValidateEVM(t *testing.T, stepWitness *mipsevm.StepWitness, step uint64, goVm mipsevm.FPVM, hashFn mipsevm.HashFn, contracts *ContractMetadata, opts ...evmOption) { + validator := NewEvmValidator(t, hashFn, contracts) + validator.ValidateEVM(t, stepWitness, step, goVm) +} + +type ErrMatcher func(*testing.T, []byte) + +func CreateNoopErrorMatcher() ErrMatcher { + return func(t *testing.T, ret []byte) {} +} + +// CreateErrorStringMatcher matches an Error(string) +func CreateErrorStringMatcher(expect string) ErrMatcher { + return func(t *testing.T, ret []byte) { + require.Greaterf(t, len(ret), 4, "Return data length should be greater than 4 bytes: %x", ret) + unpacked, decodeErr := abi.UnpackRevert(ret) + require.NoError(t, decodeErr, "Failed to unpack revert reason") + require.Contains(t, unpacked, expect, "Revert reason mismatch") + } +} + +// CreateCustomErrorMatcher matches a custom error given the error signature +func CreateCustomErrorMatcher(sig string) ErrMatcher { + return func(t *testing.T, ret []byte) { + expect := crypto.Keccak256([]byte(sig))[:4] + require.EqualValuesf(t, expect, ret, "return value is %x", ret) + } +} + // AssertEVMReverts runs a single evm step from an FPVM prestate and asserts that the VM panics -func AssertEVMReverts(t *testing.T, state mipsevm.FPVMState, contracts *ContractMetadata, tracer *tracing.Hooks, ProofData []byte, expectedReason string) { +func AssertEVMReverts(t *testing.T, state mipsevm.FPVMState, contracts *ContractMetadata, tracer *tracing.Hooks, ProofData []byte, matcher ErrMatcher) { encodedWitness, _ := state.EncodeWitness() stepWitness := &mipsevm.StepWitness{ State: encodedWitness, ProofData: ProofData, } input := EncodeStepInput(t, stepWitness, mipsevm.LocalContext{}, contracts.Artifacts.MIPS) - startingGas := uint64(30_000_000) + startingGas := uint64(maxStepGas) env, evmState := NewEVMEnv(contracts) env.Config.Tracer = tracer @@ -204,18 +267,14 @@ func AssertEVMReverts(t *testing.T, state mipsevm.FPVMState, contracts *Contract ret, _, err := env.Call(vm.AccountRef(sender), contracts.Addresses.MIPS, input, startingGas, common.U2560) require.EqualValues(t, err, vm.ErrExecutionReverted) - require.Greater(t, len(ret), 4, "Return data length should be greater than 4 bytes") - unpacked, decodeErr := abi.UnpackRevert(ret) - require.NoError(t, decodeErr, "Failed to unpack revert reason") - require.Equal(t, expectedReason, unpacked, "Revert reason mismatch") + matcher(t, ret) logs := evmState.Logs() require.Equal(t, 0, len(logs)) } -func AssertPreimageOracleReverts(t *testing.T, preimageKey [32]byte, preimageValue []byte, preimageOffset arch.Word, contracts *ContractMetadata, tracer *tracing.Hooks) { - evm := NewMIPSEVM(contracts) - evm.SetTracer(tracer) +func AssertPreimageOracleReverts(t *testing.T, preimageKey [32]byte, preimageValue []byte, preimageOffset arch.Word, contracts *ContractMetadata, opts ...evmOption) { + evm := newMIPSEVM(contracts, opts...) LogStepFailureAtCleanup(t, evm) evm.assertPreimageOracleReverts(t, preimageKey, preimageValue, preimageOffset) diff --git a/cannon/mipsevm/testutil/oracle.go b/cannon/mipsevm/testutil/oracle.go index 64b0f31a897c9..b5c4f7dce9151 100644 --- a/cannon/mipsevm/testutil/oracle.go +++ b/cannon/mipsevm/testutil/oracle.go @@ -67,7 +67,7 @@ func StaticPrecompileOracle(t *testing.T, precompile common.Address, requiredGas } func ClaimTestOracle(t *testing.T) (po mipsevm.PreimageOracle, stdOut string, stdErr string) { - s := uint64(1000) + s := uint64(0x00FFFFFF_00001000) a := uint64(3) b := uint64(4) diff --git a/cannon/mipsevm/testutil/state.go b/cannon/mipsevm/testutil/state.go index 10abb59be8d73..42e4b8851ac31 100644 --- a/cannon/mipsevm/testutil/state.go +++ b/cannon/mipsevm/testutil/state.go @@ -177,11 +177,6 @@ func (e *ExpectedState) ExpectStep() { e.NextPC += 4 } -func (e *ExpectedState) ExpectMemoryWrite(addr arch.Word, val uint32) { - e.expectedMemory.SetUint32(addr, val) - e.MemoryRoot = e.expectedMemory.MerkleRoot() -} - func (e *ExpectedState) ExpectMemoryWriteWord(addr arch.Word, val arch.Word) { e.expectedMemory.SetWord(addr, val) e.MemoryRoot = e.expectedMemory.MerkleRoot() diff --git a/cannon/mipsevm/testutil/vmtests.go b/cannon/mipsevm/testutil/vmtests.go index 382c608333998..333720a4ec025 100644 --- a/cannon/mipsevm/testutil/vmtests.go +++ b/cannon/mipsevm/testutil/vmtests.go @@ -16,10 +16,14 @@ import ( "github.com/ethereum-optimism/optimism/cannon/mipsevm/program" ) -type VMFactory[T mipsevm.FPVMState] func(state T, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger) mipsevm.FPVM +type VMFactory[T mipsevm.FPVMState] func(state T, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger, meta *program.Metadata) mipsevm.FPVM type StateFactory[T mipsevm.FPVMState] func() T func RunVMTests_OpenMips[T mipsevm.FPVMState](t *testing.T, stateFactory StateFactory[T], vmFactory VMFactory[T], excludedTests ...string) { + if !arch.IsMips32 { + // TODO: guard these tests by the cannon32 build tag + t.Skip("Open MIPS tests are not appropriate for cannon64") + } testFiles, err := os.ReadDir("../tests/open_mips_tests/test/bin") require.NoError(t, err) @@ -52,7 +56,7 @@ func RunVMTests_OpenMips[T mipsevm.FPVMState](t *testing.T, stateFactory StateFa // set the return address ($ra) to jump into when test completes state.GetRegistersRef()[31] = EndAddr - us := vmFactory(state, oracle, os.Stdout, os.Stderr, CreateLogger()) + us := vmFactory(state, oracle, os.Stdout, os.Stderr, CreateLogger(), nil) // Catch panics and check if they are expected defer func() { @@ -94,12 +98,13 @@ func RunVMTests_OpenMips[T mipsevm.FPVMState](t *testing.T, stateFactory StateFa } func RunVMTest_Hello[T mipsevm.FPVMState](t *testing.T, initState program.CreateInitialFPVMState[T], vmFactory VMFactory[T], doPatchGo bool) { - state, _ := LoadELFProgram(t, "../../testdata/example/bin/hello.elf", initState, doPatchGo) + state, meta := LoadELFProgram(t, ProgramPath("hello"), initState, doPatchGo) var stdOutBuf, stdErrBuf bytes.Buffer - us := vmFactory(state, nil, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr), CreateLogger()) + us := vmFactory(state, nil, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr), CreateLogger(), meta) - for i := 0; i < 400_000; i++ { + maxSteps := 430_000 + for i := 0; i < maxSteps; i++ { if us.GetState().GetExited() { break } @@ -107,7 +112,7 @@ func RunVMTest_Hello[T mipsevm.FPVMState](t *testing.T, initState program.Create require.NoError(t, err) } - require.True(t, state.GetExited(), "must complete program") + require.Truef(t, state.GetExited(), "must complete program. reached %d of max %d steps", state.GetStep(), maxSteps) require.Equal(t, uint8(0), state.GetExitCode(), "exit with 0") require.Equal(t, "hello world!\n", stdOutBuf.String(), "stdout says hello") @@ -115,12 +120,12 @@ func RunVMTest_Hello[T mipsevm.FPVMState](t *testing.T, initState program.Create } func RunVMTest_Claim[T mipsevm.FPVMState](t *testing.T, initState program.CreateInitialFPVMState[T], vmFactory VMFactory[T], doPatchGo bool) { - state, _ := LoadELFProgram(t, "../../testdata/example/bin/claim.elf", initState, doPatchGo) + state, meta := LoadELFProgram(t, ProgramPath("claim"), initState, doPatchGo) oracle, expectedStdOut, expectedStdErr := ClaimTestOracle(t) var stdOutBuf, stdErrBuf bytes.Buffer - us := vmFactory(state, oracle, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr), CreateLogger()) + us := vmFactory(state, oracle, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr), CreateLogger(), meta) for i := 0; i < 2000_000; i++ { if us.GetState().GetExited() { diff --git a/cannon/mipsevm/versions/detect_test.go b/cannon/mipsevm/versions/detect_test.go index be849269fff9b..bd1acd115eafe 100644 --- a/cannon/mipsevm/versions/detect_test.go +++ b/cannon/mipsevm/versions/detect_test.go @@ -7,10 +7,12 @@ import ( "strconv" "testing" + "github.com/stretchr/testify/require" + + "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" "github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded" "github.com/ethereum-optimism/optimism/cannon/mipsevm/singlethreaded" "github.com/ethereum-optimism/optimism/op-service/ioutil" - "github.com/stretchr/testify/require" ) const statesPath = "testdata/states" @@ -18,7 +20,7 @@ const statesPath = "testdata/states" //go:embed testdata/states var historicStates embed.FS -func TestDetectVersion(t *testing.T) { +func TestDetectVersion_fromFile(t *testing.T) { testDetection := func(t *testing.T, version StateVersion, ext string) { filename := strconv.Itoa(int(version)) + ext dir := t.TempDir() @@ -34,9 +36,6 @@ func TestDetectVersion(t *testing.T) { // Iterate all known versions to ensure we have a test case to detect every state version for _, version := range StateVersionTypes { version := version - if version == VersionMultiThreaded64 { - t.Skip("TODO(#12205)") - } t.Run(version.String(), func(t *testing.T) { testDetection(t, version, ".bin.gz") }) @@ -47,28 +46,38 @@ func TestDetectVersion(t *testing.T) { }) } } +} - // Additionally, check that the latest supported versions write new states in a way that is detected correctly - t.Run("SingleThreadedBinary", func(t *testing.T) { - state, err := NewFromState(singlethreaded.CreateEmptyState()) - require.NoError(t, err) - path := writeToFile(t, "state.bin.gz", state) - version, err := DetectVersion(path) - require.NoError(t, err) - require.Equal(t, VersionSingleThreaded2, version) - }) +// Check that the latest supported versions write new states in a way that is detected correctly +func TestDetectVersion_singleThreadedBinary(t *testing.T) { + targetVersion := VersionSingleThreaded2 + if !arch.IsMips32 { + t.Skip("Single-threaded states are not supported for 64-bit VMs") + } - t.Run("MultiThreadedBinary", func(t *testing.T) { - state, err := NewFromState(multithreaded.CreateEmptyState()) - require.NoError(t, err) - path := writeToFile(t, "state.bin.gz", state) - version, err := DetectVersion(path) - require.NoError(t, err) - require.Equal(t, VersionMultiThreaded, version) - }) + state, err := NewFromState(singlethreaded.CreateEmptyState()) + require.NoError(t, err) + path := writeToFile(t, "state.bin.gz", state) + version, err := DetectVersion(path) + require.NoError(t, err) + require.Equal(t, targetVersion, version) +} + +func TestDetectVersion_multiThreadedBinary(t *testing.T) { + targetVersion := VersionMultiThreaded + if !arch.IsMips32 { + targetVersion = VersionMultiThreaded64 + } + + state, err := NewFromState(multithreaded.CreateEmptyState()) + require.NoError(t, err) + path := writeToFile(t, "state.bin.gz", state) + version, err := DetectVersion(path) + require.NoError(t, err) + require.Equal(t, targetVersion, version) } -func TestDetectVersionInvalid(t *testing.T) { +func TestDetectVersion_invalid(t *testing.T) { t.Run("bad gzip", func(t *testing.T) { dir := t.TempDir() filename := "state.bin.gz" diff --git a/cannon/mipsevm/versions/state64_test.go b/cannon/mipsevm/versions/state64_test.go new file mode 100644 index 0000000000000..ddffd7e618a52 --- /dev/null +++ b/cannon/mipsevm/versions/state64_test.go @@ -0,0 +1,64 @@ +//go:build cannon64 +// +build cannon64 + +package versions + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ethereum-optimism/optimism/cannon/mipsevm" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded" + "github.com/ethereum-optimism/optimism/op-service/serialize" +) + +func TestNewFromState(t *testing.T) { + t.Run("multithreaded64", func(t *testing.T) { + actual, err := NewFromState(multithreaded.CreateEmptyState()) + require.NoError(t, err) + require.IsType(t, &multithreaded.State{}, actual.FPVMState) + require.Equal(t, VersionMultiThreaded64, actual.Version) + }) +} + +func TestLoadStateFromFile(t *testing.T) { + t.Run("Multithreaded64FromBinary", func(t *testing.T) { + expected, err := NewFromState(multithreaded.CreateEmptyState()) + require.NoError(t, err) + + path := writeToFile(t, "state.bin.gz", expected) + actual, err := LoadStateFromFile(path) + require.NoError(t, err) + require.Equal(t, expected, actual) + }) +} + +func TestVersionsOtherThanZeroDoNotSupportJSON(t *testing.T) { + tests := []struct { + version StateVersion + createState func() mipsevm.FPVMState + }{ + {VersionMultiThreaded64, func() mipsevm.FPVMState { return multithreaded.CreateEmptyState() }}, + } + for _, test := range tests { + test := test + t.Run(test.version.String(), func(t *testing.T) { + state, err := NewFromState(test.createState()) + require.NoError(t, err) + + dir := t.TempDir() + path := filepath.Join(dir, "test.json") + err = serialize.Write(path, state, 0o644) + require.ErrorIs(t, err, ErrJsonNotSupported) + }) + } +} + +func writeToFile(t *testing.T, filename string, data serialize.Serializable) string { + dir := t.TempDir() + path := filepath.Join(dir, filename) + require.NoError(t, serialize.Write(path, data, 0o644)) + return path +} diff --git a/cannon/mipsevm/versions/state_test.go b/cannon/mipsevm/versions/state_test.go index c9bcc7e6f165c..cf8eed639af9e 100644 --- a/cannon/mipsevm/versions/state_test.go +++ b/cannon/mipsevm/versions/state_test.go @@ -1,14 +1,18 @@ +//go:build !cannon64 +// +build !cannon64 + package versions import ( "path/filepath" "testing" + "github.com/stretchr/testify/require" + "github.com/ethereum-optimism/optimism/cannon/mipsevm" "github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded" "github.com/ethereum-optimism/optimism/cannon/mipsevm/singlethreaded" "github.com/ethereum-optimism/optimism/op-service/serialize" - "github.com/stretchr/testify/require" ) func TestNewFromState(t *testing.T) { @@ -49,10 +53,6 @@ func TestLoadStateFromFile(t *testing.T) { }) } -func TestLoadStateFromFile64(t *testing.T) { - t.Skip("TODO(#12205): Test asserting that cannon64 fails to decode a 32-bit state") -} - func TestVersionsOtherThanZeroDoNotSupportJSON(t *testing.T) { tests := []struct { version StateVersion diff --git a/cannon/mipsevm/versions/testdata/states/3.bin.gz b/cannon/mipsevm/versions/testdata/states/3.bin.gz new file mode 100644 index 0000000000000..b6f6728313a7d Binary files /dev/null and b/cannon/mipsevm/versions/testdata/states/3.bin.gz differ diff --git a/cannon/scripts/build-legacy-cannons.sh b/cannon/scripts/build-legacy-cannons.sh index 62b5438398419..3df0a43c31eac 100755 --- a/cannon/scripts/build-legacy-cannons.sh +++ b/cannon/scripts/build-legacy-cannons.sh @@ -3,7 +3,7 @@ set -euo pipefail SCRIPTS_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) # This script builds a version of the cannon executable that includes support for both current and legacy state versions. -# Each cannon release is built +# Each cannon release is built separately. TMP_DIR=$(mktemp -d) function cleanup() { diff --git a/cannon/testdata/example/Makefile b/cannon/testdata/example/Makefile index 7b3b8fdf019d2..5b0dee96eb9ad 100644 --- a/cannon/testdata/example/Makefile +++ b/cannon/testdata/example/Makefile @@ -1,7 +1,13 @@ all: elf +.PHONY: elf32 +elf32: $(patsubst %/go.mod,bin/%.elf,$(wildcard */go.mod)) + +.PHONY: elf64 +elf64: $(patsubst %/go.mod,bin/%.64.elf,$(wildcard */go.mod)) + .PHONY: elf -elf: $(patsubst %/go.mod,bin/%.elf,$(wildcard */go.mod)) +elf: elf32 elf64 .PHONY: dump dump: $(patsubst %/go.mod,bin/%.dump,$(wildcard */go.mod)) @@ -9,6 +15,9 @@ dump: $(patsubst %/go.mod,bin/%.dump,$(wildcard */go.mod)) bin: mkdir bin +bin/%.64.elf: bin + cd $(@:bin/%.64.elf=%) && GOOS=linux GOARCH=mips64 GOMIPS64=softfloat go build -o ../$@ . + # take any directory with a go mod, and build an ELF # verify output with: readelf -h bin/.elf # result is mips32, big endian, R3000 diff --git a/cannon/testdata/example/alloc/go.mod b/cannon/testdata/example/alloc/go.mod index a5dd16ce8b273..c364668acc106 100644 --- a/cannon/testdata/example/alloc/go.mod +++ b/cannon/testdata/example/alloc/go.mod @@ -1,6 +1,6 @@ module alloc -go 1.22 +go 1.22.0 toolchain go1.22.7 diff --git a/cannon/testdata/example/claim/go.mod b/cannon/testdata/example/claim/go.mod index dd76391de26ba..e3904911a172d 100644 --- a/cannon/testdata/example/claim/go.mod +++ b/cannon/testdata/example/claim/go.mod @@ -1,6 +1,6 @@ module claim -go 1.22 +go 1.22.0 toolchain go1.22.7 diff --git a/cannon/testdata/example/hello/go.mod b/cannon/testdata/example/hello/go.mod index b54bb78c6aee6..f036b5dc97fce 100644 --- a/cannon/testdata/example/hello/go.mod +++ b/cannon/testdata/example/hello/go.mod @@ -1,5 +1,5 @@ module hello -go 1.22 +go 1.22.0 -toolchain go1.22.0 +toolchain go1.22.7 diff --git a/cannon/testdata/example/multithreaded/go.mod b/cannon/testdata/example/mt-cond/go.mod similarity index 58% rename from cannon/testdata/example/multithreaded/go.mod rename to cannon/testdata/example/mt-cond/go.mod index e1bdb77a9aff6..d6d1853d5af2b 100644 --- a/cannon/testdata/example/multithreaded/go.mod +++ b/cannon/testdata/example/mt-cond/go.mod @@ -1,4 +1,4 @@ -module multithreaded +module cond go 1.22 diff --git a/cannon/testdata/example/mt-cond/main.go b/cannon/testdata/example/mt-cond/main.go new file mode 100644 index 0000000000000..2b584cec999b3 --- /dev/null +++ b/cannon/testdata/example/mt-cond/main.go @@ -0,0 +1,302 @@ +// Portions of this code are derived from code written by The Go Authors. +// See original source: https://github.com/golang/go/blob/400433af3660905ecaceaf19ddad3e6c24b141df/src/sync/cond_test.go +// +// --- Original License Notice --- +// +// Copyright 2009 The Go Authors. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +package main + +import ( + "fmt" + "os" + "reflect" + "runtime" + "sync" +) + +func main() { + TestCondSignal() + TestCondSignalGenerations() + TestCondBroadcast() + TestRace() + TestCondSignalStealing() + TestCondCopy() + + fmt.Println("Cond test passed") +} + +func TestCondSignal() { + var m sync.Mutex + c := sync.NewCond(&m) + n := 2 + running := make(chan bool, n) + awake := make(chan bool, n) + for i := 0; i < n; i++ { + go func() { + m.Lock() + running <- true + c.Wait() + awake <- true + m.Unlock() + }() + } + for i := 0; i < n; i++ { + <-running // Wait for everyone to run. + } + for n > 0 { + select { + case <-awake: + _, _ = fmt.Fprintln(os.Stderr, "goroutine not asleep") + os.Exit(1) + default: + } + m.Lock() + c.Signal() + m.Unlock() + <-awake // Will deadlock if no goroutine wakes up + select { + case <-awake: + _, _ = fmt.Fprintln(os.Stderr, "too many goroutines awake") + os.Exit(1) + default: + } + n-- + } + c.Signal() +} + +func TestCondSignalGenerations() { + var m sync.Mutex + c := sync.NewCond(&m) + n := 100 + running := make(chan bool, n) + awake := make(chan int, n) + for i := 0; i < n; i++ { + go func(i int) { + m.Lock() + running <- true + c.Wait() + awake <- i + m.Unlock() + }(i) + if i > 0 { + a := <-awake + if a != i-1 { + _, _ = fmt.Fprintf(os.Stderr, "wrong goroutine woke up: want %d, got %d\n", i-1, a) + os.Exit(1) + } + } + <-running + m.Lock() + c.Signal() + m.Unlock() + } +} + +func TestCondBroadcast() { + var m sync.Mutex + c := sync.NewCond(&m) + n := 5 + running := make(chan int, n) + awake := make(chan int, n) + exit := false + for i := 0; i < n; i++ { + go func(g int) { + m.Lock() + for !exit { + running <- g + c.Wait() + awake <- g + } + m.Unlock() + }(i) + } + for i := 0; i < n; i++ { + for i := 0; i < n; i++ { + <-running // Will deadlock unless n are running. + } + if i == n-1 { + m.Lock() + exit = true + m.Unlock() + } + select { + case <-awake: + _, _ = fmt.Fprintln(os.Stderr, "goroutine not asleep") + os.Exit(1) + default: + } + m.Lock() + c.Broadcast() + m.Unlock() + seen := make([]bool, n) + for i := 0; i < n; i++ { + g := <-awake + if seen[g] { + _, _ = fmt.Fprintln(os.Stderr, "goroutine woke up twice") + os.Exit(1) + } + seen[g] = true + } + } + select { + case <-running: + _, _ = fmt.Fprintln(os.Stderr, "goroutine still running") + os.Exit(1) + default: + } + c.Broadcast() +} + +func TestRace() { + x := 0 + c := sync.NewCond(&sync.Mutex{}) + done := make(chan bool) + go func() { + c.L.Lock() + x = 1 + c.Wait() + if x != 2 { + _, _ = fmt.Fprintln(os.Stderr, "want 2") + os.Exit(1) + } + x = 3 + c.Signal() + c.L.Unlock() + done <- true + }() + go func() { + c.L.Lock() + for { + if x == 1 { + x = 2 + c.Signal() + break + } + c.L.Unlock() + runtime.Gosched() + c.L.Lock() + } + c.L.Unlock() + done <- true + }() + go func() { + c.L.Lock() + for { + if x == 2 { + c.Wait() + if x != 3 { + _, _ = fmt.Fprintln(os.Stderr, "want 3") + os.Exit(1) + } + break + } + if x == 3 { + break + } + c.L.Unlock() + runtime.Gosched() + c.L.Lock() + } + c.L.Unlock() + done <- true + }() + <-done + <-done + <-done +} + +func TestCondSignalStealing() { + for iters := 0; iters < 5; iters++ { + var m sync.Mutex + cond := sync.NewCond(&m) + + // Start a waiter. + ch := make(chan struct{}) + go func() { + m.Lock() + ch <- struct{}{} + cond.Wait() + m.Unlock() + + ch <- struct{}{} + }() + + <-ch + m.Lock() + m.Unlock() + + // We know that the waiter is in the cond.Wait() call because we + // synchronized with it, then acquired/released the mutex it was + // holding when we synchronized. + // + // Start two goroutines that will race: one will broadcast on + // the cond var, the other will wait on it. + // + // The new waiter may or may not get notified, but the first one + // has to be notified. + done := false + go func() { + cond.Broadcast() + }() + + go func() { + m.Lock() + for !done { + cond.Wait() + } + m.Unlock() + }() + + // Check that the first waiter does get signaled. + <-ch + + // Release the second waiter in case it didn't get the + // broadcast. + m.Lock() + done = true + m.Unlock() + cond.Broadcast() + } +} + +func TestCondCopy() { + defer func() { + err := recover() + if err == nil || err.(string) != "sync.Cond is copied" { + _, _ = fmt.Fprintf(os.Stderr, "got %v, expect sync.Cond is copied", err) + os.Exit(1) + } + }() + c := sync.Cond{L: &sync.Mutex{}} + c.Signal() + var c2 sync.Cond + reflect.ValueOf(&c2).Elem().Set(reflect.ValueOf(&c).Elem()) // c2 := c, hidden from vet + c2.Signal() +} diff --git a/cannon/testdata/example/mt-map/go.mod b/cannon/testdata/example/mt-map/go.mod new file mode 100644 index 0000000000000..1d7b890f7f1ad --- /dev/null +++ b/cannon/testdata/example/mt-map/go.mod @@ -0,0 +1,5 @@ +module map + +go 1.22 + +toolchain go1.22.0 diff --git a/cannon/testdata/example/mt-map/main.go b/cannon/testdata/example/mt-map/main.go new file mode 100644 index 0000000000000..085319b88d87e --- /dev/null +++ b/cannon/testdata/example/mt-map/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "fmt" + "sync" +) + +func main() { + var m sync.Map + + m.Store("hello", "world") + m.Store("foo", "bar") + m.Store("baz", "qux") + + m.Delete("foo") + m.Load("baz") + + go func() { + m.CompareAndDelete("hello", "world") + m.LoadAndDelete("baz") + }() + + var wg sync.WaitGroup + for i := 0; i < 100; i++ { + wg.Add(1) + go func() { + m.Load("hello") + m.Load("baz") + m.Range(func(k, v interface{}) bool { + m.Load("hello") + m.Load("baz") + return true + }) + m.CompareAndSwap("hello", "world", "Go") + m.LoadOrStore("hello", "world") + wg.Done() + }() + } + + wg.Wait() + + fmt.Println("Map test passed") +} diff --git a/cannon/testdata/example/mt-mutex/go.mod b/cannon/testdata/example/mt-mutex/go.mod new file mode 100644 index 0000000000000..368cf9be0ae5d --- /dev/null +++ b/cannon/testdata/example/mt-mutex/go.mod @@ -0,0 +1,5 @@ +module mutex + +go 1.22 + +toolchain go1.22.0 diff --git a/cannon/testdata/example/mt-mutex/main.go b/cannon/testdata/example/mt-mutex/main.go new file mode 100644 index 0000000000000..4f96e5d2308df --- /dev/null +++ b/cannon/testdata/example/mt-mutex/main.go @@ -0,0 +1,82 @@ +// Portions of this code are derived from code written by The Go Authors. +// See original source: https://github.com/golang/go/blob/400433af3660905ecaceaf19ddad3e6c24b141df/src/sync/mutex_test.go +// +// --- Original License Notice --- +// +// Copyright 2009 The Go Authors. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +package main + +import ( + "fmt" + "os" + "sync" +) + +func main() { + TestMutex() +} + +func TestMutex() { + m := new(sync.Mutex) + + m.Lock() + if m.TryLock() { + _, _ = fmt.Fprintln(os.Stderr, "TryLock succeeded with mutex locked") + os.Exit(1) + } + m.Unlock() + if !m.TryLock() { + _, _ = fmt.Fprintln(os.Stderr, "TryLock failed with mutex unlocked") + os.Exit(1) + } + m.Unlock() + + c := make(chan bool) + for i := 0; i < 10; i++ { + go HammerMutex(m, 1000, c) + } + for i := 0; i < 10; i++ { + <-c + } + fmt.Println("Mutex test passed") +} + +func HammerMutex(m *sync.Mutex, loops int, cdone chan bool) { + for i := 0; i < loops; i++ { + if i%3 == 0 { + if m.TryLock() { + m.Unlock() + } + continue + } + m.Lock() + m.Unlock() + } + cdone <- true +} diff --git a/cannon/testdata/example/mt-once/go.mod b/cannon/testdata/example/mt-once/go.mod new file mode 100644 index 0000000000000..7595e1de483fa --- /dev/null +++ b/cannon/testdata/example/mt-once/go.mod @@ -0,0 +1,5 @@ +module once + +go 1.22 + +toolchain go1.22.0 diff --git a/cannon/testdata/example/mt-once/main.go b/cannon/testdata/example/mt-once/main.go new file mode 100644 index 0000000000000..3be753e2f702e --- /dev/null +++ b/cannon/testdata/example/mt-once/main.go @@ -0,0 +1,98 @@ +// Portions of this code are derived from code written by The Go Authors. +// See original source: https://github.com/golang/go/blob/400433af3660905ecaceaf19ddad3e6c24b141df/src/sync/once_test.go +// +// --- Original License Notice --- +// +// Copyright 2009 The Go Authors. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +package main + +import ( + "fmt" + "os" + "sync" +) + +func main() { + TestOnce() + TestOncePanic() + + fmt.Println("Once test passed") +} + +type one int + +func (o *one) Increment() { + *o++ +} + +func run(once *sync.Once, o *one, c chan bool) { + once.Do(func() { o.Increment() }) + if v := *o; v != 1 { + _, _ = fmt.Fprintf(os.Stderr, "once failed inside run: %d is not 1\n", v) + os.Exit(1) + } + c <- true +} + +func TestOnce() { + o := new(one) + once := new(sync.Once) + c := make(chan bool) + const N = 10 + for i := 0; i < N; i++ { + go run(once, o, c) + } + for i := 0; i < N; i++ { + <-c + } + if *o != 1 { + _, _ = fmt.Fprintf(os.Stderr, "once failed outside run: %d is not 1\n", *o) + os.Exit(1) + } +} + +func TestOncePanic() { + var once sync.Once + func() { + defer func() { + if r := recover(); r == nil { + _, _ = fmt.Fprintf(os.Stderr, "Once.Do did not panic") + os.Exit(1) + } + }() + once.Do(func() { + panic("failed") + }) + }() + + once.Do(func() { + _, _ = fmt.Fprintf(os.Stderr, "Once.Do called twice") + os.Exit(1) + }) +} diff --git a/cannon/testdata/example/mt-pool/go.mod b/cannon/testdata/example/mt-pool/go.mod new file mode 100644 index 0000000000000..f57bdf9b81e0b --- /dev/null +++ b/cannon/testdata/example/mt-pool/go.mod @@ -0,0 +1,5 @@ +module pool + +go 1.22 + +toolchain go1.22.0 diff --git a/cannon/testdata/example/mt-pool/main.go b/cannon/testdata/example/mt-pool/main.go new file mode 100644 index 0000000000000..267710f3ea3a2 --- /dev/null +++ b/cannon/testdata/example/mt-pool/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "sync" +) + +func main() { + var x sync.Pool + + x.Put(1) + x.Put(2) + + // try some concurrency! + var wg sync.WaitGroup + wg.Add(2) + go func() { + x.Put(3) + wg.Done() + }() + go func() { + x.Put(4) + wg.Done() + }() + + wg.Wait() + + wg.Add(4) + for i := 0; i < 4; i++ { + go func() { + x.Get() + wg.Done() + }() + } + wg.Wait() + + fmt.Println("Pool test passed") +} diff --git a/cannon/testdata/example/mt-rwmutex/go.mod b/cannon/testdata/example/mt-rwmutex/go.mod new file mode 100644 index 0000000000000..a0a433e911990 --- /dev/null +++ b/cannon/testdata/example/mt-rwmutex/go.mod @@ -0,0 +1,5 @@ +module rwmutex + +go 1.22 + +toolchain go1.22.0 diff --git a/cannon/testdata/example/mt-rwmutex/main.go b/cannon/testdata/example/mt-rwmutex/main.go new file mode 100644 index 0000000000000..8553bba75ef4a --- /dev/null +++ b/cannon/testdata/example/mt-rwmutex/main.go @@ -0,0 +1,226 @@ +// Portions of this code are derived from code written by The Go Authors. +// See original source: https://github.com/golang/go/blob/400433af3660905ecaceaf19ddad3e6c24b141df/src/sync/rwmutex_test.go +// +// --- Original License Notice --- +// +// Copyright 2009 The Go Authors. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +package main + +import ( + "fmt" + "os" + "runtime" + "sync" + "sync/atomic" +) + +func main() { + TestParallelReaders() + TestRLocker() + TestRWMutex() + + fmt.Println("RWMutex test passed") +} + +func parallelReader(m *sync.RWMutex, clocked, cunlock, cdone chan bool) { + m.RLock() + clocked <- true + <-cunlock + m.RUnlock() + cdone <- true +} + +func doTestParallelReaders(numReaders, gomaxprocs int) { + runtime.GOMAXPROCS(gomaxprocs) + var m sync.RWMutex + clocked := make(chan bool) + cunlock := make(chan bool) + cdone := make(chan bool) + for i := 0; i < numReaders; i++ { + go parallelReader(&m, clocked, cunlock, cdone) + } + // Wait for all parallel RLock()s to succeed. + for i := 0; i < numReaders; i++ { + <-clocked + } + for i := 0; i < numReaders; i++ { + cunlock <- true + } + // Wait for the goroutines to finish. + for i := 0; i < numReaders; i++ { + <-cdone + } +} + +func TestParallelReaders() { + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1)) + doTestParallelReaders(1, 4) + doTestParallelReaders(3, 4) + doTestParallelReaders(4, 2) +} + +func reader(rwm *sync.RWMutex, num_iterations int, activity *int32, cdone chan bool) { + for i := 0; i < num_iterations; i++ { + rwm.RLock() + n := atomic.AddInt32(activity, 1) + if n < 1 || n >= 10000 { + rwm.RUnlock() + panic(fmt.Sprintf("wlock(%d)\n", n)) + } + for i := 0; i < 100; i++ { + } + atomic.AddInt32(activity, -1) + rwm.RUnlock() + } + cdone <- true +} + +func writer(rwm *sync.RWMutex, num_iterations int, activity *int32, cdone chan bool) { + for i := 0; i < num_iterations; i++ { + rwm.Lock() + n := atomic.AddInt32(activity, 10000) + if n != 10000 { + rwm.Unlock() + panic(fmt.Sprintf("wlock(%d)\n", n)) + } + for i := 0; i < 100; i++ { + } + atomic.AddInt32(activity, -10000) + rwm.Unlock() + } + cdone <- true +} + +func HammerRWMutex(gomaxprocs, numReaders, num_iterations int) { + runtime.GOMAXPROCS(gomaxprocs) + // Number of active readers + 10000 * number of active writers. + var activity int32 + var rwm sync.RWMutex + cdone := make(chan bool) + go writer(&rwm, num_iterations, &activity, cdone) + var i int + for i = 0; i < numReaders/2; i++ { + go reader(&rwm, num_iterations, &activity, cdone) + } + go writer(&rwm, num_iterations, &activity, cdone) + for ; i < numReaders; i++ { + go reader(&rwm, num_iterations, &activity, cdone) + } + // Wait for the 2 writers and all readers to finish. + for i := 0; i < 2+numReaders; i++ { + <-cdone + } +} + +func TestRWMutex() { + var m sync.RWMutex + + m.Lock() + if m.TryLock() { + _, _ = fmt.Fprintln(os.Stderr, "TryLock succeeded with mutex locked") + os.Exit(1) + } + if m.TryRLock() { + _, _ = fmt.Fprintln(os.Stderr, "TryRLock succeeded with mutex locked") + os.Exit(1) + } + m.Unlock() + + if !m.TryLock() { + _, _ = fmt.Fprintln(os.Stderr, "TryLock failed with mutex unlocked") + os.Exit(1) + } + m.Unlock() + + if !m.TryRLock() { + _, _ = fmt.Fprintln(os.Stderr, "TryRLock failed with mutex unlocked") + os.Exit(1) + } + if !m.TryRLock() { + _, _ = fmt.Fprintln(os.Stderr, "TryRLock failed with mutex unlocked") + os.Exit(1) + } + if m.TryLock() { + _, _ = fmt.Fprintln(os.Stderr, "TryLock succeeded with mutex rlocked") + os.Exit(1) + } + m.RUnlock() + m.RUnlock() + + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(-1)) + n := 5 + + HammerRWMutex(1, 1, n) + HammerRWMutex(1, 3, n) + HammerRWMutex(1, 10, n) + HammerRWMutex(4, 1, n) + HammerRWMutex(4, 3, n) + HammerRWMutex(4, 10, n) + HammerRWMutex(10, 1, n) + HammerRWMutex(10, 3, n) + HammerRWMutex(10, 10, n) + HammerRWMutex(10, 5, n) +} + +func TestRLocker() { + var wl sync.RWMutex + var rl sync.Locker + wlocked := make(chan bool, 1) + rlocked := make(chan bool, 1) + rl = wl.RLocker() + n := 10 + go func() { + for i := 0; i < n; i++ { + rl.Lock() + rl.Lock() + rlocked <- true + wl.Lock() + wlocked <- true + } + }() + for i := 0; i < n; i++ { + <-rlocked + rl.Unlock() + select { + case <-wlocked: + _, _ = fmt.Fprintln(os.Stderr, "RLocker() didn't read-lock it") + os.Exit(1) + default: + } + rl.Unlock() + <-wlocked + select { + case <-rlocked: + _, _ = fmt.Fprintln(os.Stderr, "RLocker() didn't respect the write lock") + os.Exit(1) + default: + } + wl.Unlock() + } +} diff --git a/cannon/testdata/example/mt-wg/go.mod b/cannon/testdata/example/mt-wg/go.mod new file mode 100644 index 0000000000000..c8a518a535b5a --- /dev/null +++ b/cannon/testdata/example/mt-wg/go.mod @@ -0,0 +1,5 @@ +module wg + +go 1.22 + +toolchain go1.22.0 diff --git a/cannon/testdata/example/multithreaded/main.go b/cannon/testdata/example/mt-wg/main.go similarity index 79% rename from cannon/testdata/example/multithreaded/main.go rename to cannon/testdata/example/mt-wg/main.go index bc871f56e5248..841125c6b9252 100644 --- a/cannon/testdata/example/multithreaded/main.go +++ b/cannon/testdata/example/mt-wg/main.go @@ -2,8 +2,6 @@ package main import ( "fmt" - "os" - "runtime" "sync" "sync/atomic" ) @@ -39,8 +37,4 @@ func main() { a <- 1234 out := <-c fmt.Printf("channels result: %d\n", out) - - // try a GC! (the runtime might not have run one yet) - runtime.GC() - _, _ = os.Stdout.Write([]byte("GC complete!\n")) } diff --git a/cloudbuild.yaml b/cloudbuild.yaml deleted file mode 100644 index 2cf6dfb333bb8..0000000000000 --- a/cloudbuild.yaml +++ /dev/null @@ -1,12 +0,0 @@ -steps: - - name: 'gcr.io/kaniko-project/executor:latest' - args: - - --destination=us-central1-docker.pkg.dev/$PROJECT_ID/images/deployer-bedrock:$_TAG - - --destination=us-central1-docker.pkg.dev/$PROJECT_ID/images/deployer-bedrock:$COMMIT_SHA - - --dockerfile=./ops/docker/Dockerfile.packages - - --target=deployer-bedrock - - --cache=true - - --cache-ttl=48h - waitFor: ['-'] -options: - machineType: N1_HIGHCPU_32 diff --git a/docker-bake.hcl b/docker-bake.hcl index 50feeba66d458..b53c7add0f87a 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -206,14 +206,25 @@ target "proofs-tools" { dockerfile = "./ops/docker/proofs-tools/Dockerfile" context = "." args = { - CHALLENGER_VERSION="22d8365199b3141fcfbccc7cb9e107a71e151b0a" - KONA_VERSION="kona-client-v0.1.0-alpha.5" + CHALLENGER_VERSION="b46bffed42db3442d7484f089278d59f51503049" + KONA_VERSION="kona-client-v0.1.0-alpha.7" } target="proofs-tools" platforms = split(",", PLATFORMS) tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/proofs-tools:${tag}"] } +target "holocene-deployer" { + dockerfile = "./packages/contracts-bedrock/scripts/upgrades/holocene/upgrade.dockerfile" + context = "./packages/contracts-bedrock/scripts/upgrades/holocene" + args = { + REV = "op-contracts/v1.8.0-rc.1" + } + target="holocene-deployer" + platforms = split(",", PLATFORMS) + tags = [for tag in split(",", IMAGE_TAGS) : "${REGISTRY}/${REPOSITORY}/holocene-deployer:${tag}"] +} + target "ci-builder" { dockerfile = "./ops/docker/ci-builder/Dockerfile" context = "." diff --git a/docs/handbook/pr-guidelines.md b/docs/handbook/pr-guidelines.md index cf133ada6c57e..57913ebeaa517 100644 --- a/docs/handbook/pr-guidelines.md +++ b/docs/handbook/pr-guidelines.md @@ -46,4 +46,4 @@ This is organized by current state of PR, so it can be easily referenced frequen ### Merging PRs - **Resolve all Comments**: Comments can be resolved by (1) the PR author for nits/optionals, (2) the author or reviewer after discussions, or (3) extracting the comment into an issue to address in a future PR. For (3), ensure the new issue links to the specific comment thread. This is currently enforced by GitHub's merge requirements. -- **Other Standard Merge Requirements**: The PR must be approved by the appropriate reviewers, CI must passing, and other standard merge requirements apply. +- **Other Standard Merge Requirements**: The PR must be approved by the appropriate reviewers, CI must pass, and other standard merge requirements apply. diff --git a/docs/postmortems/2022-02-02-inflation-vuln.md b/docs/postmortems/2022-02-02-inflation-vuln.md index a755b0fdfe38f..a2a23e382303b 100644 --- a/docs/postmortems/2022-02-02-inflation-vuln.md +++ b/docs/postmortems/2022-02-02-inflation-vuln.md @@ -58,7 +58,7 @@ timeline and activities were as follows: (Using github handles as identifiers) - 2022-02-02 1625: smartcontracts receives an e-mail from saurik claiming to have found a critical - issue in L2Geth. E-mail was sent to securityoptimism.io. + issue in L2Geth. E-mail was sent to security@optimism.io. - 2022-02-02 X: saurik messaged smartcontracts on Discord to make sure we checked the e-mail since he knew we had a prior problem where security advisories went to spam. - 2022-02-02 1650: Huddle begins in #security on Slack. diff --git a/docs/security-reviews/2024_08_report-cantinacode-coinbase-fault-proofs-mips.pdf b/docs/security-reviews/2024_08_Fault-Proofs-MIPS_Cantina.pdf similarity index 100% rename from docs/security-reviews/2024_08_report-cantinacode-coinbase-fault-proofs-mips.pdf rename to docs/security-reviews/2024_08_Fault-Proofs-MIPS_Cantina.pdf diff --git a/docs/security-reviews/2024_08_report-cb-fault-proofs-non-mips.pdf b/docs/security-reviews/2024_08_Fault-Proofs-No-MIPS_Spearbit.pdf similarity index 100% rename from docs/security-reviews/2024_08_report-cb-fault-proofs-non-mips.pdf rename to docs/security-reviews/2024_08_Fault-Proofs-No-MIPS_Spearbit.pdf diff --git a/docs/security-reviews/2024_10-Cannon-FGETFD-3DocSecurity.md b/docs/security-reviews/2024_10-Cannon-FGETFD-3DocSecurity.md new file mode 100644 index 0000000000000..f157356e4905f --- /dev/null +++ b/docs/security-reviews/2024_10-Cannon-FGETFD-3DocSecurity.md @@ -0,0 +1,114 @@ +# Audit Report - OP Cannon + +| | | +| -------------- | ------------------------------------------------------------------------- | +| **Audit Date** | Oct 2nd 2024 - Oct 3rd 2024 | +| **Auditor** | 3DOC Security ([@3docSec](https://x.com/3docSec)) | +| **Version 1** | Oct 3rd 2024. | + +
+ +# Contents +- [Audit Report - OP cannon](#audit-report---op-cannon) +- [Contents](#contents) +- [Disclaimer](#disclaimer) +- [About 3DOC](#about-3doc) +- [Scope](#scope) +- [Severity Classification](#severity-classification) +- [Summary](#summary) +- [Findings](#findings) + - [Low Risk Findings (1)](#low-risk-findings-1) + - [1. Op-challenger Docker image does not include Cannon embeds](#-op-challenger-docker-image-does-not-include-cannon-embeds) + +# Disclaimer +_The following audit report is based on the information and code provided by the client, and any findings or recommendations are made solely on the basis of this information. While the Auditor has exercised due care and skill in conducting the audit, it cannot be guaranteed that all issues have been identified and that there are no undiscovered errors or vulnerabilities in the code._ + +_Furthermore, this report is not an endorsement or certification of the protocol, and the Auditor does not assume any responsibility for any losses or damages that may result from the use of the smart contracts, either in their current form or in any modified version thereof._ + +# About 3DOC +3DOC is a top ranked Smart Contract Auditor doing audits on Code4rena (www.code4rena.com), having ranked 1st in multiple contests in [solo](https://code4rena.com/@3docSec) and [team](https://code4rena.com/@RadiantLabs) audits, including the [Optimism superchain contest](https://code4rena.com/audits/2024-07-optimism-superchain) in July 2024.
+He can also be booked for conducting Private Audits. + +Contact:
+ +X: [@3DocSec](https://x.com/3DocSec) + +e-mail: [hello@3doc.fr](mailto:hello@3doc.fr) + +# Scope +The scope of the audit is the following Pull Request in the client's GitHub repository: + +https://github.com/ethereum-optimism/optimism/pull/12050 + +The change consists of a core update for supporting the `F_GETFD` syscall in the MIPS VM, [provided with this commit](https://github.com/ethereum-optimism/optimism/pull/12050/commits/7c8257d3574a2a76ab90f8129c7b532d68049944), and several additional updates accommodating the VM version bump that came with the core change. + +# Severity Classification +| Severity | Impact: High | Impact: Medium | Impact: Low | +| ---------------------- | ------------ | -------------- | ----------- | +| **Likelihood: High** | ![high] | ![high] | ![medium] | +| **Likelihood: Medium** | ![high] | ![medium] | ![low] | +| **Likelihood: Low** | ![medium] | ![low] | ![low] | + +**Impact** - the technical, economic and reputation damage of a successful attack + +**Likelihood** - the chance that a particular vulnerability is discovered and exploited + +# Summary + +| Severity | Total | +| -------------- | ----- | +| ![high] | 0 | +| ![medium] | 0 | +| ![low] | 0 | +| ![information] | 0 | + + +# Findings +## Low Risk findings (0) + +### [False positive] Op-challenger Docker image does not include Cannon embeds +#### Description +The change in scope added a new implementation of the Cannon VM, which was called `VersionSingleThreaded2`. Cannon has now three versions (`VersionSingleThreaded`, `VersionSingleThreaded2`, and `VersionMultiThreaded`). + +The op-challenger program makes use of the Cannon VM in several places via the configured `VmBin` path, which point to the `multicannon` command line. This one reads the State version from the input state and selects the right Cannon VM accordingly (`cannon/multicannon/exec.go:L81`). + +If we look at the Docker challenger image generated by the `make golang-docker` command, however, we can see it doesn't contain an `embeds` folder: + +``` +docker run -t us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger find / -name embeds +``` + +But it however has the `cannon` command pointing to the `multicannon` multiplexer: + +``` +➜ optimism git:(52d0e60c1) ✗ docker run -t us-docker.pkg.dev/oplabs-tools-artifacts/images/op-challenger cannon | head -2 +NAME: + multicannon - MIPS Fault Proof tool +➜ optimism git:(52d0e60c1) ✗ +``` + +This issue appears to be pre-existing to the changes in scope; using Docker images to run the challenger is [mentioned as option](https://docs.optimism.io/builders/chain-operators/tools/op-challenger), but only as alternative option, hence the Low risk assessed for this finding. + +#### Impact +Because of this issue, challenger instances operated in a Docker container won't be able to function properly. + +#### Recommendation +Consider modifying the Docker build chain to include the `embeds` folder. +Consider extending the current e2e test suite to cover execution from Docker images. + +#### Discussion + +> @inphi The cannon-2 implementation that supports go1.22 is now embedded into the cannon cli binary. Note that these embeds are not actual files that you can find in the docker container filesystem. But rather an embedded filesystem inside the Go binary - https://pkg.go.dev/embed. + +> @3DOC Oh yes I see that. So those are included in an embedded filesystem, I missed that + + +[high]: https://img.shields.io/badge/-HIGH-b02319 "HIGH" +[medium]: https://img.shields.io/badge/-MEDIUM-orange "MEDIUM" +[low]: https://img.shields.io/badge/-LOW-FFD700 "LOW" +[information]: https://img.shields.io/badge/-INFORMATION-darkgreen "INFORMATION" +[fixed]: https://img.shields.io/badge/-FIXED-brightgreen "FIXED" +[acknowledged]: https://img.shields.io/badge/-ACKNOWLEDGED-blue "ACKNOWLEDGED" +[disputed]: https://img.shields.io/badge/-DISPUTED-lightgrey "DISPUTED" +[reported]: https://img.shields.io/badge/-REPORTED-lightblue "REPORTED" +[partiallyfixed]: https://img.shields.io/badge/-PARTIALLY_FIXED-lightgreen "PARTIALLTY FIXED" diff --git a/docs/security-reviews/README.md b/docs/security-reviews/README.md index 79e756e43f574..265d0a65f9038 100644 --- a/docs/security-reviews/README.md +++ b/docs/security-reviews/README.md @@ -6,7 +6,7 @@ Each review is focused on a different part of the codebase, and at a different p Please see the report for the specific details. | Date | Reviewer | Focus and Scope | Report Link | Commit | Subsequent Release | -| ------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ------------------- | +|---------|----------------------| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------| -------------------------------------------- |---------------------| | 2020-10 | Trail of Bits | Rollup | [2020_10-TrailOfBits.pdf](./2020_10-Rollup-TrailOfBits.pdf) | | | | 2020-11 | Dapphub | ECDSA Wallet | [2020_11-Dapphub-ECDSA_Wallet.pdf](./2020_11-Dapphub-ECDSA_Wallet.pdf) | | | | 2021-03 | OpenZeppelin | OVM and Rollup | [2021_03-OVM_and_Rollup-OpenZeppelin.pdf](./2021_03-OVM_and_Rollup-OpenZeppelin.pdf) | | | @@ -24,8 +24,9 @@ Please see the report for the specific details. | 2023-12 | Trust | Superchain Config Upgrade: `SuperchainConfig.sol`, `L1CrossDomainMessenger.sol`, `L1ERC721Bridge.sol`, `L1StandardBridge.sol`, `OptimismPortal.sol`, `CrossDomainMessenger.sol`, `ERC721Bridge.sol`, `StandardBridge.sol` | [2023_12_SuperchainConfigUpgrade_Trust.pdf](./2023_12_SuperchainConfigUpgrade_Trust.pdf) | d1651bb22645ebd41ac4bb2ab4786f9a56fc1003 | op-contracts/v1.2.0 | | 2024-02 | Runtime Verification | Pausability | [Kontrol Verification][kontrol] | | | | 2024-02 | Cantina | MCP L1: `OptimismPortal.sol`, `L1CrossDomainMessenger.sol`, `L1StandardBridge.sol`, `L1ERC721Bridge.sol`, `OptimismMintableERC20Factory.sol`, `L2OutputOracle.sol`, `SystemConfig.sol` | [2024_02-MCP_L1-Cantina.pdf](./2024_02-MCP_L1-Cantina.pdf) | e6ef3a900c42c8722e72c2e2314027f85d12ced5 | op-contracts/v1.3.0 | -| 2024-03 | Sherlock | MCP L1 | Sherlock Optimism Fault Proofs Contest ([site](https://audits.sherlock.xyz/contests/205), [repo](https://github.com/sherlock-audit/2024-02-optimism-2024)) | | | -| 2024-08 | Spearbit | Fault proof no-MIPS: All contracts in the `packages/contracts-bedrock/src/dispute` directory | [Base Fault Proof No MIPS](./2024_08_report-cb-fault-proofs-non-mips.pdf) | 1f7081798ce2d49b8643514663d10681cb853a3d | op-contracts/v1.4.0 | -| 2024-08 | Cantina | Fault proof MIPS: `MIPS.sol` | [Base Fault Proof MIPS](./2024_08_report-cantinacode-coinbase-fault-proofs-mips.pdf) | 71b93116738ee98c9f8713b1a5dfe626ce06c1b2 | op-contracts/v1.6.0 | +| 2024-03 | Sherlock | Fault Proofs | Sherlock Optimism Fault Proofs Contest ([site](https://audits.sherlock.xyz/contests/205), [repo](https://github.com/sherlock-audit/2024-02-optimism-2024)) | | | +| 2024-08 | Cantina | Fault proof MIPS: `MIPS.sol` | [./2024_08_Fault-Proofs-MIPS_Cantina.pdf](./2024_08_Fault-Proofs-MIPS_Cantina.pdf) | 71b93116738ee98c9f8713b1a5dfe626ce06c1b2 | op-contracts/v1.4.0 | +| 2024-08 | Spearbit | Fault proof no-MIPS: All contracts in the `packages/contracts-bedrock/src/dispute` directory | [./2024_08_Fault-Proofs-No-MIPS_Spearbit.pdf](./2024_08_Fault-Proofs-No-MIPS_Spearbit.pdf) | 1f7081798ce2d49b8643514663d10681cb853a3d | op-contracts/v1.6.0 | +| 2024-10 | 3Doc Security | Fault proof MIPS: `MIPS.sol` | [./2024_10-Cannon-FGETFD-3DocSecurity.md](./2024_10-Cannon-FGETFD-3DocSecurity.md) | 52d0e60c16498ad4efec8798e3fc1b36b13f46a2 | op-contracts/v1.8.0 | [kontrol]: https://github.com/ethereum-optimism/optimism/blob/876e16ad04968f0bb641eb76f98eb77e7e1a3e16/packages/contracts-bedrock/test/kontrol/README.md diff --git a/go.mod b/go.mod index 799ac75a1e703..9696373269cd8 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/ethereum-optimism/optimism -go 1.22 +go 1.22.0 toolchain go1.22.7 @@ -14,10 +14,10 @@ require ( github.com/crate-crypto/go-kzg-4844 v1.0.0 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 - github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240910145426-b3905c89e8ac + github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20241119111730-bee358f6d6e6 github.com/ethereum/go-ethereum v1.14.11 github.com/ethstorage/da-server v0.0.0-20240925084712-169d238000e5 - github.com/fsnotify/fsnotify v1.7.0 + github.com/fsnotify/fsnotify v1.8.0 github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/google/go-cmp v0.6.0 github.com/google/gofuzz v1.2.1-0.20220503160820-4a35382e8fc8 @@ -29,15 +29,15 @@ require ( github.com/ipfs/go-datastore v0.6.0 github.com/ipfs/go-ds-leveldb v0.5.0 github.com/klauspost/compress v1.17.11 - github.com/kurtosis-tech/kurtosis/api/golang v1.3.1 + github.com/kurtosis-tech/kurtosis/api/golang v1.4.1 github.com/libp2p/go-libp2p v0.36.2 github.com/libp2p/go-libp2p-mplex v0.9.0 github.com/libp2p/go-libp2p-pubsub v0.12.0 github.com/libp2p/go-libp2p-testing v0.12.0 github.com/mattn/go-isatty v0.0.20 - github.com/minio/minio-go/v7 v7.0.78 + github.com/minio/minio-go/v7 v7.0.80 github.com/multiformats/go-base32 v0.1.0 - github.com/multiformats/go-multiaddr v0.13.0 + github.com/multiformats/go-multiaddr v0.14.0 github.com/multiformats/go-multiaddr-dns v0.4.0 github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 @@ -48,11 +48,10 @@ require ( github.com/stretchr/testify v1.9.0 github.com/urfave/cli/v2 v2.27.5 golang.org/x/crypto v0.28.0 - golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa - golang.org/x/sync v0.8.0 + golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c + golang.org/x/sync v0.9.0 golang.org/x/term v0.25.0 golang.org/x/time v0.7.0 - lukechampine.com/uint128 v1.3.0 ) require ( @@ -96,7 +95,7 @@ require ( github.com/ethereum/c-kzg-4844 v1.0.0 // indirect github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect github.com/fatih/color v1.16.0 // indirect - github.com/felixge/fgprof v0.9.3 // indirect + github.com/felixge/fgprof v0.9.5 // indirect github.com/ferranbt/fastssz v0.1.2 // indirect github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect @@ -112,10 +111,10 @@ require ( github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect + github.com/google/pprof v0.0.0-20241009165004-a3522334989c // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/graph-gophers/graphql-go v1.3.0 // indirect @@ -235,11 +234,11 @@ require ( go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/mod v0.20.0 // indirect + golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.30.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/text v0.19.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/tools v0.26.0 // indirect google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect @@ -252,7 +251,7 @@ require ( rsc.io/tmplfunc v0.0.3 // indirect ) -replace github.com/ethereum/go-ethereum v1.14.11 => github.com/ethstorage/op-geth v0.0.0-20241104121054-4ce1fe470a0a +replace github.com/ethereum/go-ethereum => github.com/ethstorage/op-geth v0.0.0-20241119141951-58ef82debf4f // replace github.com/ethereum/go-ethereum => ../op-geth diff --git a/go.sum b/go.sum index 6d6a02af1f03c..8af2569f41096 100644 --- a/go.sum +++ b/go.sum @@ -89,12 +89,18 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= +github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs= +github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= @@ -181,21 +187,22 @@ github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/u github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= -github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240910145426-b3905c89e8ac h1:hCIrLuOPV3FJfMDvXeOhCC3uQNvFoMIIlkT2mN2cfeg= -github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240910145426-b3905c89e8ac/go.mod h1:XaVXL9jg8BcyOeugECgIUGa9Y3DjYJj71RHmb5qon6M= +github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20241119111730-bee358f6d6e6 h1:+AIYWDX7FeWRLnBVqPiwireTacLLGGww1slGyv+YN0o= +github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20241119111730-bee358f6d6e6/go.mod h1:9feO8jcL5OZ1tvRjEfNAHz4Aggvd6373l+ZxmZZAyZs= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A= github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/ethstorage/da-server v0.0.0-20240925084712-169d238000e5 h1:pxtnGOGOChxCETGUg2yEIC3nfB5C7ZWzblm4/JE7108= github.com/ethstorage/da-server v0.0.0-20240925084712-169d238000e5/go.mod h1:QfuYw2wCpbpW7k+Fwq4s9EMWNu40XDc1KKJICPaNUgQ= -github.com/ethstorage/op-geth v0.0.0-20241104121054-4ce1fe470a0a h1:z3RaOLiI2nT/orhrycjFMOcpNf+OzHRf1tpyMHfCjgo= -github.com/ethstorage/op-geth v0.0.0-20241104121054-4ce1fe470a0a/go.mod h1:7S4pp8KHBmEmKkRjL1BPOc6jY9hW+64YeMUjR3RVLw4= +github.com/ethstorage/op-geth v0.0.0-20241119141951-58ef82debf4f h1:W4x6Kb6DwXpf0P2/+iTG3ZFxkylb5YXGm7XgIknPbXY= +github.com/ethstorage/op-geth v0.0.0-20241119141951-58ef82debf4f/go.mod h1:dITJzx1KXsV2KusscsktidEb00blTSyFhalq8CjfsUY= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= -github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= +github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY= +github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk= github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= @@ -208,8 +215,8 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= @@ -244,6 +251,9 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -256,8 +266,8 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= +github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -301,8 +311,9 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= -github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20241009165004-a3522334989c h1:NDovD0SMpBYXlE1zJmS1q55vWB/fUQBcPAqAboZSccA= +github.com/google/pprof v0.0.0-20241009165004-a3522334989c/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -365,6 +376,7 @@ github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFck github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= @@ -396,6 +408,7 @@ github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZl github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -429,8 +442,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kurtosis-tech/kurtosis-portal/api/golang v0.0.0-20230818182330-1a86869414d2 h1:izciXrFyFR+ihJ7nLTOkoIX5GzBPIp8gVKlw94gIc98= github.com/kurtosis-tech/kurtosis-portal/api/golang v0.0.0-20230818182330-1a86869414d2/go.mod h1:bWSMQK3WHVTGHX9CjxPAb/LtzcmfOxID2wdzakSWQxo= -github.com/kurtosis-tech/kurtosis/api/golang v1.3.1 h1:EBvFnz/mfiIw9a4q3ivBJiapqUiFHanAQh/Cv/jLzV4= -github.com/kurtosis-tech/kurtosis/api/golang v1.3.1/go.mod h1:9T22P7Vv3j5g6sbm78DxHQ4s9C4Cj3s9JjFQ7DFyYpM= +github.com/kurtosis-tech/kurtosis/api/golang v1.4.1 h1:V/T5k7t1iKgFof1cGhyLh396YKdTehUqO97AsTPDy+k= +github.com/kurtosis-tech/kurtosis/api/golang v1.4.1/go.mod h1:9T22P7Vv3j5g6sbm78DxHQ4s9C4Cj3s9JjFQ7DFyYpM= github.com/kurtosis-tech/kurtosis/contexts-config-store v0.0.0-20230818184218-f4e3e773463b h1:hMoIM99QKcYQqsnK4AF7Lovi9ZD9ac6lZLZ5D/jx2x8= github.com/kurtosis-tech/kurtosis/contexts-config-store v0.0.0-20230818184218-f4e3e773463b/go.mod h1:4pFdrRwDz5R+Fov2ZuTaPhAVgjA2jhGh1Izf832sX7A= github.com/kurtosis-tech/kurtosis/grpc-file-transfer/golang v0.0.0-20230803130419-099ee7a4e3dc h1:7IlEpSehmWcNXOFpNP24Cu5HQI3af7GCBQw//m+LnvQ= @@ -445,6 +458,7 @@ github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4F github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= @@ -475,6 +489,7 @@ github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= @@ -511,8 +526,8 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4S github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.78 h1:LqW2zy52fxnI4gg8C2oZviTaKHcBV36scS+RzJnxUFs= -github.com/minio/minio-go/v7 v7.0.78/go.mod h1:84gmIilaX4zcvAWWzJ5Z1WI5axN+hAbM5w25xf8xvC0= +github.com/minio/minio-go/v7 v7.0.80 h1:2mdUHXEykRdY/BigLt3Iuu1otL0JTogT0Nmltg0wujk= +github.com/minio/minio-go/v7 v7.0.80/go.mod h1:84gmIilaX4zcvAWWzJ5Z1WI5axN+hAbM5w25xf8xvC0= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= @@ -536,8 +551,8 @@ github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYg github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.13.0 h1:BCBzs61E3AGHcYYTv8dqRH43ZfyrqM8RXVPT8t13tLQ= -github.com/multiformats/go-multiaddr v0.13.0/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= +github.com/multiformats/go-multiaddr v0.14.0 h1:bfrHrJhrRuh/NXH5mCnemjpbGjzRw/b+tJFOD41g2tU= +github.com/multiformats/go-multiaddr v0.14.0/go.mod h1:6EkVAxtznq2yC3QT5CM1UTAwG0GTP3EWAIcjHuzQ+r4= github.com/multiformats/go-multiaddr-dns v0.4.0 h1:P76EJ3qzBXpUXZ3twdCDx/kvagMsNo0LMFXpyms/zgU= github.com/multiformats/go-multiaddr-dns v0.4.0/go.mod h1:7hfthtB4E4pQwirrz+J0CcDUfbWzTqEzVyYKKIKpgkc= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= @@ -595,6 +610,7 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= @@ -848,8 +864,8 @@ golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1m golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= -golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -862,8 +878,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -913,8 +929,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1023,8 +1039,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1096,8 +1112,6 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= -lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= -lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= diff --git a/interop-devnet/create-chains.sh b/interop-devnet/create-chains.sh new file mode 100755 index 0000000000000..506682099154e --- /dev/null +++ b/interop-devnet/create-chains.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +set -eu + +# Run this with workdir set as root of the repo +if [ -f "../versions.json" ]; then + echo "Running create-chains script." +else + echo "Cannot run create-chains script, must be in interop-devnet dir, but currently in:" + pwd + exit 1 +fi + +# Navigate to repository root +cd .. + +# Check if already created +if [ -d ".devnet-interop" ]; then + echo "Already created chains." + exit 1 +else + echo "Creating new interop devnet chain configs" +fi + +export OP_INTEROP_MNEMONIC="test test test test test test test test test test test junk" + +go run ./op-node/cmd interop dev-setup \ + --artifacts-dir=packages/contracts-bedrock/forge-artifacts \ + --foundry-dir=packages/contracts-bedrock \ + --l1.chainid=900100 \ + --l2.chainids=900200,900201 \ + --out-dir=".devnet-interop" \ + --log.format=logfmt \ + --log.level=info + +# create L1 CL genesis +eth2-testnet-genesis deneb \ + --config=./ops-bedrock/beacon-data/config.yaml \ + --preset-phase0=minimal \ + --preset-altair=minimal \ + --preset-bellatrix=minimal \ + --preset-capella=minimal \ + --preset-deneb=minimal \ + --eth1-config=.devnet-interop/genesis/l1/genesis.json \ + --state-output=.devnet-interop/genesis/l1/beaconstate.ssz \ + --tranches-dir=.devnet-interop/genesis/l1/tranches \ + --mnemonics=./ops-bedrock/mnemonics.yaml \ + --eth1-withdrawal-address=0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ + --eth1-match-genesis-time + +echo "Writing env files now..." + +# write env files for each L2 service + +chain_env=".devnet-interop/env/l2/900200" +mkdir -p "$chain_env" +key_cmd="go run ./op-node/cmd interop devkey secret --domain=chain-operator --chainid=900200" +# op-node +echo "OP_NODE_P2P_SEQUENCER_KEY=$($key_cmd --name=sequencer-p2p)" >> "$chain_env/op-node.env" +# proposer +echo "OP_PROPOSER_PRIVATE_KEY=$($key_cmd --name=proposer)" >> "$chain_env/op-proposer.env" +echo "OP_PROPOSER_GAME_FACTORY_ADDRESS=$(jq -r .DisputeGameFactoryProxy .devnet-interop/deployments/l2/900200/addresses.json)" >> "$chain_env/op-proposer.env" +# batcher +echo "OP_BATCHER_PRIVATE_KEY=$($key_cmd --name=batcher)" >> "$chain_env/op-batcher.env" + +chain_env=".devnet-interop/env/l2/900201" +mkdir -p "$chain_env" +key_cmd="go run ./op-node/cmd interop devkey secret --domain=chain-operator --chainid=900201" +# op-node +echo "OP_NODE_P2P_SEQUENCER_KEY=$($key_cmd --name=sequencer-p2p)" >> "$chain_env/op-node.env" +# proposer +echo "OP_PROPOSER_PRIVATE_KEY=$($key_cmd --name=proposer)" >> "$chain_env/op-proposer.env" +echo "OP_PROPOSER_GAME_FACTORY_ADDRESS=$(jq -r .DisputeGameFactoryProxy .devnet-interop/deployments/l2/900201/addresses.json)" >> "$chain_env/op-proposer.env" +# batcher +echo "OP_BATCHER_PRIVATE_KEY=$($key_cmd --name=batcher)" >> "$chain_env/op-batcher.env" + +echo "Interop devnet setup is complete!" diff --git a/interop-devnet/depset.json b/interop-devnet/depset.json new file mode 100644 index 0000000000000..6f3600b1d2965 --- /dev/null +++ b/interop-devnet/depset.json @@ -0,0 +1,14 @@ +{ + "dependencies": { + "900200": { + "chainIndex": "900200", + "activationTime": 0, + "historyMinTime": 0 + }, + "900201": { + "chainIndex": "900201", + "activationTime": 0, + "historyMinTime": 0 + } + } +} diff --git a/interop-devnet/docker-compose.yml b/interop-devnet/docker-compose.yml new file mode 100644 index 0000000000000..de97c9967b648 --- /dev/null +++ b/interop-devnet/docker-compose.yml @@ -0,0 +1,397 @@ +# This Compose file is expected to be used with the devnet-up.sh script. +# The volumes below mount the configs generated by the script into each +# service. + +volumes: + l1_data: + l1_bn_data: + l1_vc_data: + l2_a_data: + safedb_a_data: + l2_b_data: + safedb_b_data: + supervisor_data: + op_log_a: + op_log_b: + +services: + + l1: + build: + context: ../ops-bedrock + dockerfile: l1-geth.Dockerfile + ports: + - "8545:8545" + - "8546:8546" + - "7060:6060" + volumes: + - "l1_data:/db" + - "${PWD}/../.devnet-interop/genesis/l1/genesis.json:/genesis.json" + - "${PWD}/../ops-bedrock/test-jwt-secret.txt:/config/jwt-secret.txt" + environment: + GETH_MINER_RECOMMIT: 100ms + + l1-bn: + depends_on: + - l1 + build: + context: ../ops-bedrock + dockerfile: l1-lighthouse.Dockerfile + ports: + - "9000:9000" + - "5052:5052" + volumes: + - "l1_bn_data:/db" + - "${PWD}/../ops-bedrock/test-jwt-secret.txt:/config/jwt-secret.txt" + - "${PWD}/../ops-bedrock/beacon-data/config.yaml:/genesis/config.yaml" + - "${PWD}/../ops-bedrock/beacon-data/deposit_contract_block.txt:/genesis/deposit_contract_block.txt" + - "${PWD}/../.devnet-interop/genesis/l1/beaconstate.ssz:/genesis/genesis.ssz" + environment: + LH_EXECUTION_ENDPOINT: "http://l1:8551" + entrypoint: + - "/bin/sh" + - "/entrypoint-bn.sh" + + l1-vc: + depends_on: + - l1 + - l1-bn + build: + context: ../ops-bedrock + dockerfile: l1-lighthouse.Dockerfile + volumes: + - "l1_vc_data:/db" + - "${PWD}/../ops-bedrock/beacon-data/data/keys:/validator_setup/validators" + - "${PWD}/../ops-bedrock/beacon-data/data/secrets:/validator_setup/secrets" + - "${PWD}/../ops-bedrock/beacon-data/config.yaml:/genesis/config.yaml" + - "${PWD}/../ops-bedrock/beacon-data/deposit_contract_block.txt:/genesis/deposit_contract_block.txt" + - "${PWD}/../.devnet-interop/genesis/l1/beaconstate.ssz:/genesis/genesis.ssz" + environment: + LH_BEACON_NODES: "http://l1-bn:5052/" + entrypoint: + - "/bin/sh" + - "/entrypoint-vc.sh" + + op-supervisor: + depends_on: + - l1 + build: + context: ../ + dockerfile: ops/docker/op-stack-go/Dockerfile + target: op-supervisor-target + ports: + - "9045:8545" + volumes: + - "supervisor_data:/db" + - "./depset.json:/depset.json" + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-supervisor:devnet + command: > + op-supervisor + --datadir="/db" + --dependency-set="/depset.json" + --l2-rpcs="" + --rpc.addr="0.0.0.0" + --rpc.port=8545 + --rpc.enable-admin + --l2-rpcs="ws://l2-a:8546,ws://l2-b:8546" + environment: + OP_SUPERVISOR_METRICS_ENABLED: "true" + + l2-a: + depends_on: + - op-supervisor + build: + context: ../ops-bedrock/ + dockerfile: l2-op-geth-interop.Dockerfile + ports: + - "9145:8545" + - "8160:6060" + volumes: + - "l2_a_data:/db" + - "${PWD}/../.devnet-interop/genesis/l2/900200/genesis.json:/genesis.json" + - "${PWD}/../ops-bedrock/test-jwt-secret.txt:/config/jwt-secret.txt" + entrypoint: # pass the L2 specific flags by overriding the entry-point and adding extra arguments + - "/bin/sh" + - "/entrypoint.sh" + environment: + GETH_MINER_RECOMMIT: 100ms + GETH_ROLLUP_INTEROPRPC: "ws://op-supervisor:8545" + + l2-b: + depends_on: + - op-supervisor + build: + context: ../ops-bedrock/ + dockerfile: l2-op-geth-interop.Dockerfile + ports: + - "9245:8545" + - "8260:6060" + volumes: + - "l2_b_data:/db" + - "${PWD}/../.devnet-interop/genesis/l2/900201/genesis.json:/genesis.json" + - "${PWD}/../ops-bedrock/test-jwt-secret.txt:/config/jwt-secret.txt" + entrypoint: # pass the L2 specific flags by overriding the entry-point and adding extra arguments + - "/bin/sh" + - "/entrypoint.sh" + environment: + GETH_MINER_RECOMMIT: 100ms + GETH_ROLLUP_INTEROPRPC: "ws://op-supervisor:8545" + + op-node-a: + depends_on: + - l1 + - l1-bn + - l1-vc + - l2-a + - op-supervisor + build: + context: ../ + dockerfile: ops/docker/op-stack-go/Dockerfile + target: op-node-target + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-node:devnet + command: > + op-node + --l1=ws://l1:8546 + --l1.beacon=http://l1-bn:5052 + --l1.epoch-poll-interval=12s + --l1.http-poll-interval=6s + --l2=http://l2-a:8551 + --l2.jwt-secret=/config/jwt-secret.txt + --supervisor=http://op-supervisor:8545 + --sequencer.enabled + --sequencer.l1-confs=0 + --verifier.l1-confs=0 + --rollup.config=/rollup.json + --rpc.addr=0.0.0.0 + --rpc.port=8545 + --p2p.listen.ip=0.0.0.0 + --p2p.listen.tcp=9003 + --p2p.listen.udp=9003 + --p2p.scoring.peers=light + --p2p.ban.peers=true + --metrics.enabled + --metrics.addr=0.0.0.0 + --metrics.port=7300 + --pprof.enabled + --rpc.enable-admin + --safedb.path=/db + ports: + - "7145:8545" + - "9103:9003" + - "7100:7300" + - "6160:6060" + volumes: + - "safedb_a_data:/db" + - "${PWD}/../ops-bedrock/test-jwt-secret.txt:/config/jwt-secret.txt" + - "${PWD}/../.devnet-interop/genesis/l2/900200/rollup.json:/rollup.json" + - op_log_a:/op_log + env_file: + - "${PWD}/../.devnet-interop/env/l2/900200/op-node.env" + + op-node-b: + depends_on: + - l1 + - l1-bn + - l1-vc + - l2-b + - op-supervisor + build: + context: ../ + dockerfile: ops/docker/op-stack-go/Dockerfile + target: op-node-target + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-node:devnet + command: > + op-node + --l1=ws://l1:8546 + --l1.beacon=http://l1-bn:5052 + --l1.epoch-poll-interval=12s + --l1.http-poll-interval=6s + --l2=http://l2-b:8551 + --l2.jwt-secret=/config/jwt-secret.txt + --supervisor=http://op-supervisor:8545 + --sequencer.enabled + --sequencer.l1-confs=0 + --verifier.l1-confs=0 + --rollup.config=/rollup.json + --rpc.addr=0.0.0.0 + --rpc.port=8545 + --p2p.listen.ip=0.0.0.0 + --p2p.listen.tcp=9003 + --p2p.listen.udp=9003 + --p2p.scoring.peers=light + --p2p.ban.peers=true + --metrics.enabled + --metrics.addr=0.0.0.0 + --metrics.port=7300 + --pprof.enabled + --rpc.enable-admin + --safedb.path=/db + ports: + - "7245:8545" + - "9203:9003" + - "7200:7300" + - "6260:6060" + volumes: + - "safedb_b_data:/db" + - "${PWD}/../ops-bedrock/test-jwt-secret.txt:/config/jwt-secret.txt" + - "${PWD}/../.devnet-interop/genesis/l2/900201/rollup.json:/rollup.json" + - op_log_b:/op_log + env_file: + - "${PWD}/../.devnet-interop/env/l2/900201/op-node.env" + + op-proposer-a: + depends_on: + - l1 + - op-node-a + build: + context: ../ + dockerfile: ops/docker/op-stack-go/Dockerfile + target: op-proposer-target + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-proposer:devnet + ports: + - "6162:6060" + - "7102:7300" + - "6146:8545" + environment: + OP_PROPOSER_L1_ETH_RPC: http://l1:8545 + OP_PROPOSER_ROLLUP_RPC: http://op-node-a:8545 + OP_PROPOSER_POLL_INTERVAL: 1s + OP_PROPOSER_NUM_CONFIRMATIONS: 1 + OP_PROPOSER_GAME_TYPE: "254" + OP_PROPOSER_PROPOSAL_INTERVAL: "12s" + OP_PROPOSER_PPROF_ENABLED: "true" + OP_PROPOSER_METRICS_ENABLED: "true" + OP_PROPOSER_ALLOW_NON_FINALIZED: "true" + OP_PROPOSER_RPC_ENABLE_ADMIN: "true" + env_file: + - "${PWD}/../.devnet-interop/env/l2/900200/op-proposer.env" + + op-proposer-b: + depends_on: + - l1 + - op-node-b + build: + context: ../ + dockerfile: ops/docker/op-stack-go/Dockerfile + target: op-proposer-target + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-proposer:devnet + ports: + - "6262:6060" + - "7202:7300" + - "6246:8545" + environment: + OP_PROPOSER_L1_ETH_RPC: http://l1:8545 + OP_PROPOSER_ROLLUP_RPC: http://op-node-b:8545 + OP_PROPOSER_POLL_INTERVAL: 1s + OP_PROPOSER_NUM_CONFIRMATIONS: 1 + OP_PROPOSER_GAME_TYPE: "254" + OP_PROPOSER_PROPOSAL_INTERVAL: "12s" + OP_PROPOSER_PPROF_ENABLED: "true" + OP_PROPOSER_METRICS_ENABLED: "true" + OP_PROPOSER_ALLOW_NON_FINALIZED: "true" + OP_PROPOSER_RPC_ENABLE_ADMIN: "true" + env_file: + - "${PWD}/../.devnet-interop/env/l2/900201/op-proposer.env" + + op-batcher-a: + depends_on: + - l1 + - l2-a + - op-node-a + build: + context: ../ + dockerfile: ops/docker/op-stack-go/Dockerfile + target: op-batcher-target + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-batcher:devnet + ports: + - "6161:6060" + - "7101:7300" + - "6145:8545" + environment: + OP_BATCHER_L1_ETH_RPC: http://l1:8545 + OP_BATCHER_L2_ETH_RPC: http://l2-a:8545 + OP_BATCHER_ROLLUP_RPC: http://op-node-a:8545 + OP_BATCHER_MAX_CHANNEL_DURATION: 2 + OP_BATCHER_SUB_SAFETY_MARGIN: 4 # SWS is 15, ChannelTimeout is 40 + OP_BATCHER_POLL_INTERVAL: 1s + OP_BATCHER_NUM_CONFIRMATIONS: 1 + OP_BATCHER_PPROF_ENABLED: "true" + OP_BATCHER_METRICS_ENABLED: "true" + OP_BATCHER_RPC_ENABLE_ADMIN: "true" + OP_BATCHER_BATCH_TYPE: + # uncomment to use blobs + # OP_BATCHER_DATA_AVAILABILITY_TYPE: blobs + env_file: + - "${PWD}/../.devnet-interop/env/l2/900200/op-batcher.env" + + op-batcher-b: + depends_on: + - l1 + - l2-b + - op-node-b + build: + context: ../ + dockerfile: ops/docker/op-stack-go/Dockerfile + target: op-batcher-target + image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-batcher:devnet + ports: + - "6261:6060" + - "7201:7300" + - "6245:8545" + environment: + OP_BATCHER_L1_ETH_RPC: http://l1:8545 + OP_BATCHER_L2_ETH_RPC: http://l2-b:8545 + OP_BATCHER_ROLLUP_RPC: http://op-node-b:8545 + OP_BATCHER_MAX_CHANNEL_DURATION: 2 + OP_BATCHER_SUB_SAFETY_MARGIN: 4 # SWS is 15, ChannelTimeout is 40 + OP_BATCHER_POLL_INTERVAL: 1s + OP_BATCHER_NUM_CONFIRMATIONS: 1 + OP_BATCHER_PPROF_ENABLED: "true" + OP_BATCHER_METRICS_ENABLED: "true" + OP_BATCHER_RPC_ENABLE_ADMIN: "true" + OP_BATCHER_BATCH_TYPE: + # uncomment to use blobs + # OP_BATCHER_DATA_AVAILABILITY_TYPE: blobs + env_file: + - "${PWD}/../.devnet-interop/env/l2/900201/op-batcher.env" + + grafana: + image: grafana/grafana:11.1.0 + restart: unless-stopped + env_file: + - monitoring/grafana.env + volumes: + - ./monitoring/grafana/provisioning/:/etc/grafana/provisioning/:ro + - ./monitoring/grafana/dashboards:/var/lib/grafana/dashboards + # - grafana_data:/var/lib/grafana + ports: + - 3300:3000 + + prometheus: + image: prom/prometheus:latest + restart: unless-stopped + volumes: + - ./monitoring/prometheus:/etc/prometheus + # - prometheus_data:/prometheus + ports: + - 3090:9090 + command: --config.file=/etc/prometheus/prometheus.yml --log.level=debug + + loki: + image: grafana/loki:3.1.1 + restart: unless-stopped + volumes: + - ./monitoring/loki:/etc/loki + ports: + - 3200:3200 + command: -config.file=/etc/loki/config.yaml + + promtail: + image: grafana/promtail:3.1.1 + restart: unless-stopped + volumes: + # uncomment to scrape system logs + # - /var/log:/var/log + - ./monitoring/promtail:/etc/promtail + - /var/run/docker.sock:/var/run/docker.sock # Mount Docker socket to read container logs + command: -config.file=/etc/promtail/config.yaml diff --git a/interop-devnet/justfile b/interop-devnet/justfile new file mode 100644 index 0000000000000..6af11ccc8fb8c --- /dev/null +++ b/interop-devnet/justfile @@ -0,0 +1,40 @@ + +devnet-setup: + bash create-chains.sh + +devnet-build-images: + PWD="$(pwd)" DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 \ + docker compose build --progress plain \ + --build-arg GIT_COMMIT={git_commit} \ + --build-arg GIT_DATE={git_date} + +devnet-up: + docker compose up -d l1 l1-bn l1-vc + + docker compose up -d \ + op-supervisor \ + op-node-a op-batcher-a op-proposer-a \ + op-node-b op-batcher-b op-proposer-b + +devnet-down: + # stops services, does not remove containers/networks + docker compose stop + +devnet-metrics-up: + docker compose up -d prometheus grafana loki promtail + +devnet-metrics-down: + docker compose down -d prometheus grafana loki promtail + +devnet-clean: + # Stops services, and removes containers/networks + docker compose down + # Now manually clean up the related images and volumes + # Note: `justfile` interprets the curly brackets. So we escape them, by wrapping it with more, as a string, like Jinja2. + docker image ls 'interop-devnet*' --format='{{ '{{.Repository}}' }}' | xargs -r docker rmi + docker volume ls --filter name=interop-devnet --format='{{ '{{.Name}}' }}' | xargs -r docker volume rm + # docker compose down needs the env files before being able to shut down, so remove the devnet config resources last + rm -rf ../.devnet-interop + +devnet-logs: + docker compose logs -f diff --git a/interop-devnet/monitoring/grafana.env b/interop-devnet/monitoring/grafana.env new file mode 100644 index 0000000000000..3a7446dfccfaf --- /dev/null +++ b/interop-devnet/monitoring/grafana.env @@ -0,0 +1 @@ +GF_SECURITY_ADMIN_PASSWORD=admin diff --git a/interop-devnet/monitoring/grafana/dashboards/op_stack_compose_dashboard.json b/interop-devnet/monitoring/grafana/dashboards/op_stack_compose_dashboard.json new file mode 100644 index 0000000000000..c3d34c9d8a56d --- /dev/null +++ b/interop-devnet/monitoring/grafana/dashboards/op_stack_compose_dashboard.json @@ -0,0 +1,2203 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 31, + "panels": [], + "title": "Logs", + "type": "row" + }, + { + "datasource": { + "type": "loki", + "uid": "loki-datasource" + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 24, + "options": { + "dedupStrategy": "none", + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": false + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "loki-datasource" + }, + "expr": "{container=\"ops-bedrock-op-batcher-1\"}", + "queryType": "range", + "refId": "A" + } + ], + "title": "Batcher Logs", + "type": "logs" + }, + { + "datasource": { + "type": "loki", + "uid": "loki-datasource" + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 32, + "options": { + "dedupStrategy": "none", + "enableLogDetails": true, + "prettifyLogMessage": false, + "showCommonLabels": false, + "showLabels": false, + "showTime": false, + "sortOrder": "Descending", + "wrapLogMessage": false + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "loki-datasource" + }, + "editorMode": "code", + "expr": "{container=\"ops-bedrock-op-proposer-1\"}", + "queryType": "range", + "refId": "A" + } + ], + "title": "Proposer Logs", + "type": "logs" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 14, + "panels": [], + "title": "Batcher", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 22 + }, + "id": 20, + "interval": "2s", + "options": { + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_pending_blocks_count", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "pending_blocks_count {{stage}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Number of pending blocks, not added to a channel yet.", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 22 + }, + "id": 19, + "interval": "2s", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_input_bytes", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "input {{stage}}", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_output_bytes", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "output", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Total number of input/output bytes per channel.", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 17, + "interval": "2s", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_pending_blocks_bytes_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "exemplar": false, + "expr": "op_batcher_default_pending_blocks_bytes_current", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Total size of transactions in pending blocks as they are fetched from L2", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 16, + "interval": "2s", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_blocks_added_count", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Total number of blocks added to current channel.", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 38 + }, + "id": 18, + "interval": "2s", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_channel_num_frames", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Total number of frames of closed channel.", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 12, + "x": 12, + "y": 38 + }, + "id": 25, + "interval": "2s", + "options": { + "displayMode": "basic", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_blob_used_bytes_bucket", + "format": "heatmap", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Blob sizes", + "type": "bargauge" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 50 + }, + "id": 26, + "panels": [], + "title": "Batcher txmgr", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 51 + }, + "id": 21, + "interval": "2s", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_txmgr_last_confirm_unix", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_txmgr_last_publish_unix", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "B", + "useBackend": false + } + ], + "title": "Batcher Tx Publish/Confirm Times", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "description": "TODO: batcher_tx_total is 2x txs sent b/c of bug. See https://github.com/ethereum-optimism/optimism/pull/11438", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 51 + }, + "id": 15, + "interval": "2s", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_batcher_tx_total", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_txmgr_confirm_total", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "B", + "useBackend": false + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_txmgr_current_nonce", + "fullMetaSearch": false, + "hide": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "C", + "useBackend": false + } + ], + "title": "Batcher Txs", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 59 + }, + "id": 23, + "interval": "2s", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_txmgr_pending_txs", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Batcher Pending Txs", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 59 + }, + "id": 22, + "interval": "2s", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_txmgr_tx_confirmed_latency_ms", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Tx confirmation latency", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 67 + }, + "id": 6, + "panels": [], + "title": "Sequencer", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 0, + "y": 68 + }, + "id": 7, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": { + "valueSize": 54 + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_node_default_refs_number{type=\"l2_unsafe\", layer=\"l2\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "L2 Unsafe Block", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 5, + "y": 68 + }, + "id": 10, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": { + "valueSize": 54 + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_node_default_refs_number{type=\"l2_safe\", layer=\"l2\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "L2 Safe Block", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 10, + "y": 68 + }, + "id": 9, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": { + "valueSize": 54 + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_node_default_refs_number{type=\"l2_finalized\", layer=\"l2\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "L2 Finalized Block", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "displayName", + "value": "Balance" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 9, + "x": 15, + "y": 68 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hoverProximity": -46, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "rate(op_node_default_l1_reorg_depth_count[$__rate_interval])", + "fullMetaSearch": false, + "includeNullMetadata": false, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "L1 Reorg Count", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 0, + "y": 72 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": { + "valueSize": 54 + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_node_default_refs_number{type=\"l1_head\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "L1 Head", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 5, + "y": 72 + }, + "id": 11, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": { + "valueSize": 54 + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_node_default_refs_number{type=\"l1_safe\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "L1 Safe Block", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 10, + "y": 72 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": { + "valueSize": 54 + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_node_default_refs_number{type=\"l1_finalized\"}", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "L1 Finalized Block", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 76 + }, + "id": 5, + "panels": [], + "title": "Balances", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 4, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 77 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": { + "valueSize": 54 + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_balance", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Batcher Balance", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 4, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 80 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "text": { + "valueSize": 54 + }, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_proposer_default_balance", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Proposer Balance", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "displayName", + "value": "Balance" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 83 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hoverProximity": -46, + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_batcher_default_balance", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Batcher Balance", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "displayName", + "value": "Balance" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 83 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "ddshms3dlineoe" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "op_proposer_default_balance", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Proposer Balance", + "type": "timeseries" + } + ], + "refresh": "10s", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "OP Stack Compose", + "uid": "ddshn0bgt86ioc", + "version": 1, + "weekStart": "" +} diff --git a/interop-devnet/monitoring/grafana/provisioning/dashboards/all.yml b/interop-devnet/monitoring/grafana/provisioning/dashboards/all.yml new file mode 100644 index 0000000000000..e281a1e592c8c --- /dev/null +++ b/interop-devnet/monitoring/grafana/provisioning/dashboards/all.yml @@ -0,0 +1,11 @@ +apiVersion: 1 + +providers: + - name: 'default' + orgId: 1 + folder: '' + type: file + disableDeletion: true + editable: true + options: + path: /var/lib/grafana/dashboards diff --git a/interop-devnet/monitoring/grafana/provisioning/datasources/all.yml b/interop-devnet/monitoring/grafana/provisioning/datasources/all.yml new file mode 100644 index 0000000000000..8a97e63640d4a --- /dev/null +++ b/interop-devnet/monitoring/grafana/provisioning/datasources/all.yml @@ -0,0 +1,24 @@ +apiVersion: 1 + +deleteDatasources: + - name: "Prometheus" + +datasources: + - access: "proxy" + editable: true + is_default: true + name: "Prometheus" + uid: "ddshms3dlineoe" + org_id: 1 + type: "prometheus" + url: "http://prometheus:9090" + version: 1 + + - access: "proxy" + editable: true + name: "Loki" + uid: "loki-datasource" + org_id: 1 + type: "loki" + url: "http://loki:3200" + version: 1 diff --git a/interop-devnet/monitoring/loki/config.yaml b/interop-devnet/monitoring/loki/config.yaml new file mode 100644 index 0000000000000..f5350cfc2444f --- /dev/null +++ b/interop-devnet/monitoring/loki/config.yaml @@ -0,0 +1,29 @@ +auth_enabled: false + +server: + http_listen_port: 3200 + +common: + instance_addr: 127.0.0.1 + path_prefix: /loki + storage: + filesystem: + chunks_directory: /loki/chunks + rules_directory: /loki/rules + replication_factor: 1 + ring: + kvstore: + store: inmemory + +schema_config: + configs: + - from: 2020-10-24 + store: tsdb + object_store: filesystem + schema: v13 + index: + prefix: index_ + period: 24h + +analytics: + reporting_enabled: false diff --git a/interop-devnet/monitoring/prometheus/prometheus.yml b/interop-devnet/monitoring/prometheus/prometheus.yml new file mode 100644 index 0000000000000..c2a7e6fe3a628 --- /dev/null +++ b/interop-devnet/monitoring/prometheus/prometheus.yml @@ -0,0 +1,43 @@ +global: + scrape_interval: 4s + evaluation_interval: 15s + +scrape_configs: + - job_name: "l1-geth" + static_configs: + - targets: ["l1:6060"] + metrics_path: /debug/metrics/prometheus + + - job_name: "l2-a-geth" + static_configs: + - targets: ["l2-a:6060"] + metrics_path: /debug/metrics/prometheus + - job_name: "l2-b-geth" + static_configs: + - targets: ["l2-b:6060"] + metrics_path: /debug/metrics/prometheus + + - job_name: "op-node-a" + static_configs: + - targets: ["op-node-a:7300"] + - job_name: "op-node-b" + static_configs: + - targets: ["op-node-b:7300"] + + - job_name: "op-batcher-a" + static_configs: + - targets: ["op-batcher-a:7300"] + - job_name: "op-batcher-b" + static_configs: + - targets: ["op-batcher-b:7300"] + + - job_name: "op-proposer-a" + static_configs: + - targets: ["op-proposer-a:7300"] + - job_name: "op-proposer-b" + static_configs: + - targets: ["op-proposer-b:7300"] + + - job_name: "op-supervisor" + static_configs: + - targets: ["op-supervisor:7300"] diff --git a/interop-devnet/monitoring/promtail/config.yaml b/interop-devnet/monitoring/promtail/config.yaml new file mode 100644 index 0000000000000..60116fb463f62 --- /dev/null +++ b/interop-devnet/monitoring/promtail/config.yaml @@ -0,0 +1,32 @@ +server: + http_listen_port: 9080 + grpc_listen_port: 0 + +positions: + filename: /tmp/positions.yaml + +clients: + - url: http://loki:3200/loki/api/v1/push + +scrape_configs: + # Uncomment to scrape system logs + # - job_name: system + # static_configs: + # - targets: + # - localhost + # labels: + # job: varlogs + # __path__: /var/log/*log + # This scrapes docker container logs + # copied from https://stackoverflow.com/questions/74776432/with-promtail-how-do-i-only-keep-log-messages-for-specified-docker-containers + - job_name: docker + docker_sd_configs: + - host: unix:///var/run/docker.sock + filters: + - name: name + # Filter logging to just our containers + values: ["op-batcher-*", "op-proposer-*", "op-node-*", "op-supervisor-*", "l1-*", "l1-bn-*", "l1-vc-*", "l2-a-*", "l2-b-*"] + relabel_configs: + - source_labels: ["__meta_docker_container_name"] + regex: "/(.*)" + target_label: "container" diff --git a/justfile b/justfile index 57d7fa5da2183..6438ba36197aa 100644 --- a/justfile +++ b/justfile @@ -3,14 +3,14 @@ issues: # Runs semgrep on the entire monorepo. semgrep: - semgrep scan --config=semgrep --error . + semgrep scan --config .semgrep/rules/ --error . # Runs semgrep tests. semgrep-test: - semgrep scan --test semgrep/ + semgrep scan --test --config .semgrep/rules/ .semgrep/tests/ lint-shellcheck: - find . -type f -name '*.sh' -not -path '*/node_modules/*' -not -path './packages/contracts-bedrock/lib/*' -not -path './packages/contracts-bedrock/kout*/*' -exec sh -c 'echo \"Checking $1\"; shellcheck \"$1\"' _ {} \\; + find . -type f -name '*.sh' -not -path '*/node_modules/*' -not -path './packages/contracts-bedrock/lib/*' -not -path './packages/contracts-bedrock/kout*/*' -exec sh -c 'echo "Checking $1"; shellcheck "$1"' _ {} \; install-foundry: curl -L https://foundry.paradigm.xyz | bash && just update-foundry @@ -19,7 +19,7 @@ update-foundry: bash ./ops/scripts/install-foundry.sh check-foundry: - bash ./packages/contracts-bedrock/scripts/checks/check-foundry-install.sh + bash ./ops/scripts/check-foundry.sh install-kontrol: curl -L https://kframework.org/install | bash && just update-kontrol @@ -61,4 +61,4 @@ check-semgrep: [ "$(just print-semgrep)" = "$(jq -r .semgrep < versions.json)" ] && echo '✓ semgrep versions match' || (echo '✗ semgrep version mismatch. Run `just upgrade-semgrep` to upgrade.' && exit 1) upgrade-semgrep: - jq '.semgrep = $v' --arg v $(just print-semgrep) <<<$(cat versions.json) > versions.json + pip3 install semgrep=="$(jq -r .semgrep < versions.json)" diff --git a/op-alt-da/commitment.go b/op-alt-da/commitment.go index cc5829ad4dc64..a6fa5424665b1 100644 --- a/op-alt-da/commitment.go +++ b/op-alt-da/commitment.go @@ -108,7 +108,7 @@ func (c Keccak256Commitment) CommitmentType() CommitmentType { return Keccak256CommitmentType } -// Encode adds a commitment type prefix self describing the commitment. +// Encode adds a commitment type prefix that describes the commitment. func (c Keccak256Commitment) Encode() []byte { return append([]byte{byte(Keccak256CommitmentType)}, c...) } diff --git a/op-batcher/Makefile b/op-batcher/Makefile index 8e680ec2bec12..22bb7a6138610 100644 --- a/op-batcher/Makefile +++ b/op-batcher/Makefile @@ -34,14 +34,16 @@ test: go test -v ./... fuzz: - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzChannelConfig_CheckTimeout ./batcher - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDurationZero ./batcher - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDurationTimeoutMaxChannelDuration ./batcher - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDurationTimeoutZeroMaxChannelDuration ./batcher - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzChannelCloseTimeout ./batcher - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzChannelZeroCloseTimeout ./batcher - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzSeqWindowClose ./batcher - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzSeqWindowZeroTimeoutClose ./batcher + printf "%s\n" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzChannelConfig_CheckTimeout ./batcher" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDurationZero ./batcher" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDurationTimeoutMaxChannelDuration ./batcher" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDurationTimeoutZeroMaxChannelDuration ./batcher" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzChannelCloseTimeout ./batcher" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzChannelZeroCloseTimeout ./batcher" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzSeqWindowClose ./batcher" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzSeqWindowZeroTimeoutClose ./batcher" \ + | parallel -j 8 {} .PHONY: \ op-batcher \ diff --git a/op-batcher/architecture.png b/op-batcher/architecture.png new file mode 100644 index 0000000000000..0eab940fbb522 Binary files /dev/null and b/op-batcher/architecture.png differ diff --git a/op-batcher/batcher/channel.go b/op-batcher/batcher/channel.go index dd0827d4686cd..9ae52be405dc1 100644 --- a/op-batcher/batcher/channel.go +++ b/op-batcher/batcher/channel.go @@ -49,10 +49,10 @@ func newChannel(log log.Logger, metr metrics.Metricer, cfg ChannelConfig, rollup func (c *channel) TxFailed(id string) { if data, ok := c.pendingTransactions[id]; ok { c.log.Trace("marked transaction as failed", "id", id) - // Note: when the batcher is changed to send multiple frames per tx, - // this needs to be changed to iterate over all frames of the tx data - // and re-queue them. - c.channelBuilder.PushFrames(data.Frames()...) + // Rewind to the first frame of the failed tx + // -- the frames are ordered, and we want to send them + // all again. + c.channelBuilder.RewindFrameCursor(data.Frames()[0]) delete(c.pendingTransactions, id) } else { c.log.Warn("unknown transaction marked as failed", "id", id) @@ -61,18 +61,16 @@ func (c *channel) TxFailed(id string) { c.metr.RecordBatchTxFailed() } -// TxConfirmed marks a transaction as confirmed on L1. Unfortunately even if all frames in -// a channel have been marked as confirmed on L1 the channel may be invalid & need to be -// resubmitted. -// This function may reset the pending channel if the pending channel has timed out. -func (c *channel) TxConfirmed(id string, inclusionBlock eth.BlockID) (bool, []*types.Block) { +// TxConfirmed marks a transaction as confirmed on L1. Returns a bool indicating +// whether the channel timed out on chain. +func (c *channel) TxConfirmed(id string, inclusionBlock eth.BlockID) bool { c.metr.RecordBatchTxSubmitted() c.log.Debug("marked transaction as confirmed", "id", id, "block", inclusionBlock) if _, ok := c.pendingTransactions[id]; !ok { c.log.Warn("unknown transaction marked as confirmed", "id", id, "block", inclusionBlock) // TODO: This can occur if we clear the channel while there are still pending transactions // We need to keep track of stale transactions instead - return false, nil + return false } delete(c.pendingTransactions, id) c.confirmedTransactions[id] = inclusionBlock @@ -82,21 +80,20 @@ func (c *channel) TxConfirmed(id string, inclusionBlock eth.BlockID) (bool, []*t c.minInclusionBlock = min(c.minInclusionBlock, inclusionBlock.Number) c.maxInclusionBlock = max(c.maxInclusionBlock, inclusionBlock.Number) + if c.isFullySubmitted() { + c.metr.RecordChannelFullySubmitted(c.ID()) + c.log.Info("Channel is fully submitted", "id", c.ID(), "min_inclusion_block", c.minInclusionBlock, "max_inclusion_block", c.maxInclusionBlock) + } + // If this channel timed out, put the pending blocks back into the local saved blocks // and then reset this state so it can try to build a new channel. if c.isTimedOut() { c.metr.RecordChannelTimedOut(c.ID()) c.log.Warn("Channel timed out", "id", c.ID(), "min_inclusion_block", c.minInclusionBlock, "max_inclusion_block", c.maxInclusionBlock) - return true, c.channelBuilder.Blocks() - } - // If we are done with this channel, record that. - if c.isFullySubmitted() { - c.metr.RecordChannelFullySubmitted(c.ID()) - c.log.Info("Channel is fully submitted", "id", c.ID(), "min_inclusion_block", c.minInclusionBlock, "max_inclusion_block", c.maxInclusionBlock) - return true, nil + return true } - return false, nil + return false } // Timeout returns the channel timeout L1 block number. If there is no timeout set, it returns 0. @@ -136,7 +133,7 @@ func (c *channel) ID() derive.ChannelID { func (c *channel) NextTxData() txData { nf := c.cfg.MaxFramesPerTx() txdata := txData{frames: make([]frameData, 0, nf), asBlob: c.cfg.UseBlobs} - for i := 0; i < nf && c.channelBuilder.HasFrame(); i++ { + for i := 0; i < nf && c.channelBuilder.HasPendingFrame(); i++ { frame := c.channelBuilder.NextFrame() txdata.frames = append(txdata.frames, frame) } @@ -151,7 +148,7 @@ func (c *channel) NextTxData() txData { func (c *channel) HasTxData() bool { if c.IsFull() || // If the channel is full, we should start to submit it !c.cfg.UseBlobs { // If using calldata, we only send one frame per tx - return c.channelBuilder.HasFrame() + return c.channelBuilder.HasPendingFrame() } // Collect enough frames if channel is not full yet return c.channelBuilder.PendingFrames() >= int(c.cfg.MaxFramesPerTx()) diff --git a/op-batcher/batcher/channel_builder.go b/op-batcher/batcher/channel_builder.go index ae1fb03d28417..597b5ed3e1443 100644 --- a/op-batcher/batcher/channel_builder.go +++ b/op-batcher/batcher/channel_builder.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/queue" "github.com/ethereum/go-ethereum/core/types" ) @@ -65,7 +66,7 @@ type ChannelBuilder struct { // current channel co derive.ChannelOut // list of blocks in the channel. Saved in case the channel must be rebuilt - blocks []*types.Block + blocks queue.Queue[*types.Block] // latestL1Origin is the latest L1 origin of all the L2 blocks that have been added to the channel latestL1Origin eth.BlockID // oldestL1Origin is the oldest L1 origin of all the L2 blocks that have been added to the channel @@ -75,7 +76,12 @@ type ChannelBuilder struct { // oldestL2 is the oldest L2 block of all the L2 blocks that have been added to the channel oldestL2 eth.BlockID // frames data queue, to be send as txs - frames []frameData + frames queue.Queue[frameData] + // frameCursor tracks which frames in the queue were submitted + // frames[frameCursor] is the next unsubmitted (pending) frame + // frameCursor = len(frames) is reserved for when + // there are no pending (next unsubmitted) frames + frameCursor int // total frames counter numFrames int // total amount of output data of all frames created yet @@ -190,7 +196,7 @@ func (c *ChannelBuilder) AddBlock(block *types.Block) (*derive.L1BlockInfo, erro return l1info, fmt.Errorf("adding block to channel out: %w", err) } - c.blocks = append(c.blocks, block) + c.blocks.Enqueue(block) c.updateSwTimeout(l1info.Number) if l1info.Number > c.latestL1Origin.Number { @@ -312,11 +318,11 @@ func (c *ChannelBuilder) setFullErr(err error) { } // OutputFrames creates new frames with the channel out. It should be called -// after AddBlock and before iterating over available frames with HasFrame and +// after AddBlock and before iterating over pending frames with HasFrame and // NextFrame. // // If the channel isn't full yet, it will conservatively only -// pull readily available frames from the compression output. +// pull pending frames from the compression output. // If it is full, the channel is closed and all remaining // frames will be created, possibly with a small leftover frame. func (c *ChannelBuilder) OutputFrames() error { @@ -387,7 +393,7 @@ func (c *ChannelBuilder) outputFrame() error { id: frameID{chID: c.co.ID(), frameNumber: fn}, data: buf.Bytes(), } - c.frames = append(c.frames, frame) + c.frames.Enqueue(frame) c.numFrames++ c.outputBytes += len(frame.data) return err // possibly io.EOF (last frame) @@ -402,46 +408,47 @@ func (c *ChannelBuilder) Close() { } // TotalFrames returns the total number of frames that were created in this channel so far. -// It does not decrease when the frames queue is being emptied. func (c *ChannelBuilder) TotalFrames() int { return c.numFrames } -// HasFrame returns whether there's any available frame. If true, it can be -// popped using NextFrame(). +// HasPendingFrame returns whether there's any pending frame. If true, it can be +// dequeued using NextFrame(). // // Call OutputFrames before to create new frames from the channel out // compression pipeline. -func (c *ChannelBuilder) HasFrame() bool { - return len(c.frames) > 0 +func (c *ChannelBuilder) HasPendingFrame() bool { + return c.frameCursor < c.frames.Len() } // PendingFrames returns the number of pending frames in the frames queue. -// It is larger zero iff HasFrame() returns true. +// It is larger than zero iff HasFrame() returns true. func (c *ChannelBuilder) PendingFrames() int { - return len(c.frames) + return c.frames.Len() - c.frameCursor } -// NextFrame dequeues the next available frame. -// HasFrame must be called prior to check if there's a next frame available. +// NextFrame returns the next pending frame and increments the frameCursor +// HasFrame must be called prior to check if there a next pending frame exists. // Panics if called when there's no next frame. func (c *ChannelBuilder) NextFrame() frameData { - if len(c.frames) == 0 { + if len(c.frames) <= c.frameCursor { panic("no next frame") } - - f := c.frames[0] - c.frames = c.frames[1:] + f := c.frames[c.frameCursor] + c.frameCursor++ return f } -// PushFrames adds the frames back to the internal frames queue. Panics if not of -// the same channel. -func (c *ChannelBuilder) PushFrames(frames ...frameData) { - for _, f := range frames { - if f.id.chID != c.ID() { - panic("wrong channel") - } - c.frames = append(c.frames, f) +// RewindFrameCursor moves the frameCursor to point at the supplied frame +// only if it is ahead of it. +// Panics if the frame is not in this channel. +func (c *ChannelBuilder) RewindFrameCursor(frame frameData) { + if c.frames.Len() <= int(frame.id.frameNumber) || + len(c.frames[frame.id.frameNumber].data) != len(frame.data) || + c.frames[frame.id.frameNumber].id.chID != frame.id.chID { + panic("cannot rewind to unknown frame") + } + if c.frameCursor > int(frame.id.frameNumber) { + c.frameCursor = int(frame.id.frameNumber) } } diff --git a/op-batcher/batcher/channel_builder_test.go b/op-batcher/batcher/channel_builder_test.go index 957f9ae597395..6994186b7f072 100644 --- a/op-batcher/batcher/channel_builder_test.go +++ b/op-batcher/batcher/channel_builder_test.go @@ -299,6 +299,7 @@ func TestChannelBuilderBatchType(t *testing.T) { {"ChannelBuilder_PendingFrames_TotalFrames", ChannelBuilder_PendingFrames_TotalFrames}, {"ChannelBuilder_InputBytes", ChannelBuilder_InputBytes}, {"ChannelBuilder_OutputBytes", ChannelBuilder_OutputBytes}, + {"ChannelBuilder_OutputWrongFramePanic", ChannelBuilder_OutputWrongFramePanic}, } for _, test := range tests { test := test @@ -340,7 +341,7 @@ func TestChannelBuilder_NextFrame(t *testing.T) { }, data: expectedBytes, } - cb.PushFrames(frameData) + cb.frames = append(cb.frames, frameData) // There should only be 1 frame in the channel builder require.Equal(t, 1, cb.PendingFrames()) @@ -355,7 +356,7 @@ func TestChannelBuilder_NextFrame(t *testing.T) { require.PanicsWithValue(t, "no next frame", func() { cb.NextFrame() }) } -// TestChannelBuilder_OutputWrongFramePanic tests that a panic is thrown when a frame is pushed with an invalid frame id +// TestChannelBuilder_OutputWrongFramePanic tests that a panic is thrown when we try to rewind the cursor with an invalid frame id func ChannelBuilder_OutputWrongFramePanic(t *testing.T, batchType uint) { channelConfig := defaultTestChannelConfig() channelConfig.BatchType = batchType @@ -377,7 +378,7 @@ func ChannelBuilder_OutputWrongFramePanic(t *testing.T, batchType uint) { // The frame push should panic since we constructed a new channel out // so the channel out id won't match - require.PanicsWithValue(t, "wrong channel", func() { + require.PanicsWithValue(t, "cannot rewind to unknown frame", func() { frame := frameData{ id: frameID{ chID: co.ID(), @@ -385,7 +386,7 @@ func ChannelBuilder_OutputWrongFramePanic(t *testing.T, batchType uint) { }, data: buf.Bytes(), } - cb.PushFrames(frame) + cb.RewindFrameCursor(frame) }) } @@ -625,11 +626,11 @@ func TestChannelBuilder_FullShadowCompressor(t *testing.T) { require.NoError(cb.OutputFrames()) - require.True(cb.HasFrame()) + require.True(cb.HasPendingFrame()) f := cb.NextFrame() require.Less(len(f.data), int(cfg.MaxFrameSize)) // would fail without fix, full frame - require.False(cb.HasFrame(), "no leftover frame expected") // would fail without fix + require.False(cb.HasPendingFrame(), "no leftover frame expected") // would fail without fix } func ChannelBuilder_AddBlock(t *testing.T, batchType uint) { @@ -656,8 +657,8 @@ func ChannelBuilder_AddBlock(t *testing.T, batchType uint) { expectedInputBytes = 47 } require.Equal(t, expectedInputBytes, cb.co.InputBytes()) - require.Equal(t, 1, len(cb.blocks)) - require.Equal(t, 0, len(cb.frames)) + require.Equal(t, 1, cb.blocks.Len()) + require.Equal(t, 0, cb.frames.Len()) require.True(t, cb.IsFull()) // Since the channel output is full, the next call to AddBlock @@ -858,7 +859,7 @@ func ChannelBuilder_PendingFrames_TotalFrames(t *testing.T, batchType uint) { // empty queue for pf := nf - 1; pf >= 0; pf-- { - require.True(cb.HasFrame()) + require.True(cb.HasPendingFrame()) _ = cb.NextFrame() require.Equal(cb.PendingFrames(), pf) require.Equal(cb.TotalFrames(), nf) @@ -932,7 +933,7 @@ func ChannelBuilder_OutputBytes(t *testing.T, batchType uint) { require.Greater(cb.PendingFrames(), 1) var flen int - for cb.HasFrame() { + for cb.HasPendingFrame() { f := cb.NextFrame() flen += len(f.data) } diff --git a/op-batcher/batcher/channel_config_test.go b/op-batcher/batcher/channel_config_test.go index d7f3c2cc5ea5f..3621fa78525f6 100644 --- a/op-batcher/batcher/channel_config_test.go +++ b/op-batcher/batcher/channel_config_test.go @@ -51,7 +51,7 @@ func TestChannelConfig_Check(t *testing.T) { } for i := 0; i < derive.FrameV0OverHeadSize; i++ { expectedErr := fmt.Sprintf("max frame size %d is less than the minimum 23", i) - i := i // need to udpate Go version... + i := i // need to update Go version... tests = append(tests, test{ input: func() ChannelConfig { cfg := defaultTestChannelConfig() diff --git a/op-batcher/batcher/channel_manager.go b/op-batcher/batcher/channel_manager.go index 887c51f4ebf20..81ee0fb35a51b 100644 --- a/op-batcher/batcher/channel_manager.go +++ b/op-batcher/batcher/channel_manager.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io" + "math" "sync" "github.com/ethereum-optimism/optimism/op-batcher/metrics" @@ -38,8 +39,13 @@ type channelManager struct { // All blocks since the last request for new tx data. blocks queue.Queue[*types.Block] - // The latest L1 block from all the L2 blocks in the most recently closed channel - l1OriginLastClosedChannel eth.BlockID + // blockCursor is an index into blocks queue. It points at the next block + // to build a channel with. blockCursor = len(blocks) is reserved for when + // there are no blocks ready to build with. + blockCursor int + // The latest L1 block from all the L2 blocks in the most recently submitted channel. + // Used to track channel duration timeouts. + l1OriginLastSubmittedChannel eth.BlockID // The default ChannelConfig to use for the next channel defaultCfg ChannelConfig // last block hash - for reorg detection @@ -51,9 +57,6 @@ type channelManager struct { channelQueue []*channel // used to lookup channels by tx ID upon tx success / failure txChannels map[string]*channel - - // if set to true, prevents production of any new channel frames - closed bool } func NewChannelManager(log log.Logger, metr metrics.Metricer, cfgProvider ChannelConfigProvider, rollupCfg *rollup.Config) *channelManager { @@ -74,19 +77,23 @@ func (s *channelManager) SetChannelOutFactory(outFactory ChannelOutFactory) { // Clear clears the entire state of the channel manager. // It is intended to be used before launching op-batcher and after an L2 reorg. -func (s *channelManager) Clear(l1OriginLastClosedChannel eth.BlockID) { +func (s *channelManager) Clear(l1OriginLastSubmittedChannel eth.BlockID) { s.mu.Lock() defer s.mu.Unlock() s.log.Trace("clearing channel manager state") s.blocks.Clear() - s.l1OriginLastClosedChannel = l1OriginLastClosedChannel + s.blockCursor = 0 + s.l1OriginLastSubmittedChannel = l1OriginLastSubmittedChannel s.tip = common.Hash{} - s.closed = false s.currentChannel = nil s.channelQueue = nil s.txChannels = make(map[string]*channel) } +func (s *channelManager) pendingBlocks() int { + return s.blocks.Len() - s.blockCursor +} + // TxFailed records a transaction as failed. It will attempt to resubmit the data // in the failed transaction. func (s *channelManager) TxFailed(_id txID) { @@ -96,31 +103,21 @@ func (s *channelManager) TxFailed(_id txID) { if channel, ok := s.txChannels[id]; ok { delete(s.txChannels, id) channel.TxFailed(id) - if s.closed && channel.NoneSubmitted() { - s.log.Info("Channel has no submitted transactions, clearing for shutdown", "chID", channel.ID()) - s.removePendingChannel(channel) - } } else { s.log.Warn("transaction from unknown channel marked as failed", "id", id) } } -// TxConfirmed marks a transaction as confirmed on L1. Unfortunately even if all frames in -// a channel have been marked as confirmed on L1 the channel may be invalid & need to be -// resubmitted. -// This function may reset the pending channel if the pending channel has timed out. +// TxConfirmed marks a transaction as confirmed on L1. Only if the channel timed out +// the channelManager's state is modified. func (s *channelManager) TxConfirmed(_id txID, inclusionBlock eth.BlockID) { s.mu.Lock() defer s.mu.Unlock() id := _id.String() if channel, ok := s.txChannels[id]; ok { delete(s.txChannels, id) - done, blocks := channel.TxConfirmed(id, inclusionBlock) - if done { - s.removePendingChannel(channel) - if len(blocks) > 0 { - s.blocks.Prepend(blocks...) - } + if timedOut := channel.TxConfirmed(id, inclusionBlock); timedOut { + s.handleChannelInvalidated(channel) } } else { s.log.Warn("transaction from unknown channel marked as confirmed", "id", id) @@ -129,23 +126,48 @@ func (s *channelManager) TxConfirmed(_id txID, inclusionBlock eth.BlockID) { s.log.Debug("marked transaction as confirmed", "id", id, "block", inclusionBlock) } -// removePendingChannel removes the given completed channel from the manager's state. -func (s *channelManager) removePendingChannel(channel *channel) { - if s.currentChannel == channel { - s.currentChannel = nil +// rewindToBlock updates the blockCursor to point at +// the block with the supplied hash, only if that block exists +// in the block queue and the blockCursor is ahead of it. +// Panics if the block is not in state. +func (s *channelManager) rewindToBlock(block eth.BlockID) { + idx := block.Number - s.blocks[0].Number().Uint64() + if s.blocks[idx].Hash() == block.Hash && idx < uint64(s.blockCursor) { + s.blockCursor = int(idx) + } else { + panic("tried to rewind to nonexistent block") } - index := -1 - for i, c := range s.channelQueue { - if c == channel { - index = i - break +} + +// handleChannelInvalidated rewinds the channelManager's blockCursor +// to point at the first block added to the provided channel, +// and removes the channel from the channelQueue, along with +// any channels which are newer than the provided channel. +func (s *channelManager) handleChannelInvalidated(c *channel) { + if len(c.channelBuilder.blocks) > 0 { + // This is usually true, but there is an edge case + // where a channel timed out before any blocks got added. + // In that case we end up with an empty frame (header only), + // and there are no blocks to requeue. + blockID := eth.ToBlockID(c.channelBuilder.blocks[0]) + for _, block := range c.channelBuilder.blocks { + s.metr.RecordL2BlockInPendingQueue(block) } + s.rewindToBlock(blockID) + } else { + s.log.Debug("channelManager.handleChanneInvalidated: channel had no blocks") } - if index < 0 { - s.log.Warn("channel not found in channel queue", "id", channel.ID()) - return + + // Trim provided channel and any older channels: + for i := range s.channelQueue { + if s.channelQueue[i] == c { + s.channelQueue = s.channelQueue[:i] + break + } } - s.channelQueue = append(s.channelQueue[:index], s.channelQueue[index+1:]...) + + // We want to start writing to a new channel, so reset currentChannel. + s.currentChannel = nil } // nextTxData dequeues frames from the channel and returns them encoded in a transaction. @@ -156,6 +178,12 @@ func (s *channelManager) nextTxData(channel *channel) (txData, error) { return txData{}, io.EOF // TODO: not enough data error instead } tx := channel.NextTxData() + + // update s.l1OriginLastSubmittedChannel so that the next + // channel's duration timeout will trigger properly + if channel.LatestL1Origin().Number > s.l1OriginLastSubmittedChannel.Number { + s.l1OriginLastSubmittedChannel = channel.LatestL1Origin() + } s.txChannels[tx.ID().String()] = channel return tx, nil } @@ -196,7 +224,16 @@ func (s *channelManager) TxData(l1Head eth.BlockID) (txData, error) { s.log.Info("Recomputing optimal ChannelConfig: changing DA type and requeing blocks...", "useBlobsBefore", s.defaultCfg.UseBlobs, "useBlobsAfter", newCfg.UseBlobs) - s.Requeue(newCfg) + + // Invalidate the channel so its blocks + // get requeued: + s.handleChannelInvalidated(channel) + + // Set the defaultCfg so new channels + // pick up the new ChannelConfig + s.defaultCfg = newCfg + + // Try again to get data to send on chain. channel, err = s.getReadyChannel(l1Head) if err != nil { return emptyTxData, err @@ -227,14 +264,9 @@ func (s *channelManager) getReadyChannel(l1Head eth.BlockID) (*channel, error) { return firstWithTxData, nil } - if s.closed { - return nil, io.EOF - } - // No pending tx data, so we have to add new blocks to the channel - // If we have no saved blocks, we will not be able to create valid frames - if s.blocks.Len() == 0 { + if s.pendingBlocks() == 0 { return nil, io.EOF } @@ -280,7 +312,7 @@ func (s *channelManager) ensureChannelWithSpace(l1Head eth.BlockID) error { return fmt.Errorf("creating channel out: %w", err) } - pc := newChannel(s.log, s.metr, cfg, s.rollupCfg, s.l1OriginLastClosedChannel.Number, channelOut) + pc := newChannel(s.log, s.metr, cfg, s.rollupCfg, s.l1OriginLastSubmittedChannel.Number, channelOut) s.currentChannel = pc s.channelQueue = append(s.channelQueue, pc) @@ -288,8 +320,8 @@ func (s *channelManager) ensureChannelWithSpace(l1Head eth.BlockID) error { s.log.Info("Created channel", "id", pc.ID(), "l1Head", l1Head, - "l1OriginLastClosedChannel", s.l1OriginLastClosedChannel, - "blocks_pending", s.blocks.Len(), + "blocks_pending", s.pendingBlocks(), + "l1OriginLastSubmittedChannel", s.l1OriginLastSubmittedChannel, "batch_type", cfg.BatchType, "compression_algo", cfg.CompressorConfig.CompressionAlgo, "target_num_frames", cfg.TargetNumFrames, @@ -320,7 +352,7 @@ func (s *channelManager) processBlocks() error { latestL2ref eth.L2BlockRef ) - for i := 0; ; i++ { + for i := s.blockCursor; ; i++ { block, ok := s.blocks.PeekN(i) if !ok { break @@ -344,7 +376,7 @@ func (s *channelManager) processBlocks() error { } } - _, _ = s.blocks.DequeueN(blocksAdded) + s.blockCursor += blocksAdded s.metr.RecordL2BlocksAdded(latestL2ref, blocksAdded, @@ -353,7 +385,7 @@ func (s *channelManager) processBlocks() error { s.currentChannel.ReadyBytes()) s.log.Debug("Added blocks to channel", "blocks_added", blocksAdded, - "blocks_pending", s.blocks.Len(), + "blocks_pending", s.pendingBlocks(), "channel_full", s.currentChannel.IsFull(), "input_bytes", s.currentChannel.InputBytes(), "ready_bytes", s.currentChannel.ReadyBytes(), @@ -370,15 +402,10 @@ func (s *channelManager) outputFrames() error { return nil } - lastClosedL1Origin := s.currentChannel.LatestL1Origin() - if lastClosedL1Origin.Number > s.l1OriginLastClosedChannel.Number { - s.l1OriginLastClosedChannel = lastClosedL1Origin - } - inBytes, outBytes := s.currentChannel.InputBytes(), s.currentChannel.OutputBytes() s.metr.RecordChannelClosed( s.currentChannel.ID(), - s.blocks.Len(), + s.pendingBlocks(), s.currentChannel.TotalFrames(), inBytes, outBytes, @@ -392,17 +419,16 @@ func (s *channelManager) outputFrames() error { s.log.Info("Channel closed", "id", s.currentChannel.ID(), - "blocks_pending", s.blocks.Len(), + "blocks_pending", s.pendingBlocks(), "num_frames", s.currentChannel.TotalFrames(), "input_bytes", inBytes, "output_bytes", outBytes, "oldest_l1_origin", s.currentChannel.OldestL1Origin(), - "l1_origin", lastClosedL1Origin, + "l1_origin", s.currentChannel.LatestL1Origin(), "oldest_l2", s.currentChannel.OldestL2(), "latest_l2", s.currentChannel.LatestL2(), "full_reason", s.currentChannel.FullErr(), "compr_ratio", comprRatio, - "latest_l1_origin", s.l1OriginLastClosedChannel, ) return nil } @@ -438,82 +464,104 @@ func l2BlockRefFromBlockAndL1Info(block *types.Block, l1info *derive.L1BlockInfo var ErrPendingAfterClose = errors.New("pending channels remain after closing channel-manager") -// Close clears any pending channels that are not in-flight already, to leave a clean derivation state. -// Close then marks the remaining current open channel, if any, as "full" so it can be submitted as well. -// Close does NOT immediately output frames for the current remaining channel: -// as this might error, due to limitations on a single channel. -// Instead, this is part of the pending-channel submission work: after closing, -// the caller SHOULD drain pending channels by generating TxData repeatedly until there is none left (io.EOF). -// A ErrPendingAfterClose error will be returned if there are any remaining pending channels to submit. -func (s *channelManager) Close() error { - s.mu.Lock() - defer s.mu.Unlock() - if s.closed { - return nil +// pruneSafeBlocks dequeues blocks from the internal blocks queue +// if they have now become safe. +func (s *channelManager) pruneSafeBlocks(newSafeHead eth.L2BlockRef) { + oldestBlock, ok := s.blocks.Peek() + if !ok { + // no blocks to prune + return } - s.closed = true - s.log.Info("Channel manager is closing") - - // Any pending state can be proactively cleared if there are no submitted transactions - for _, ch := range s.channelQueue { - if ch.NoneSubmitted() { - s.log.Info("Channel has no past or pending submission - dropping", "id", ch.ID()) - s.removePendingChannel(ch) - } else { - s.log.Info("Channel is in-flight and will need to be submitted after close", "id", ch.ID(), "confirmed", len(ch.confirmedTransactions), "pending", len(ch.pendingTransactions)) - } + if newSafeHead.Number+1 == oldestBlock.NumberU64() { + // no blocks to prune + return } - s.log.Info("Reviewed all pending channels on close", "remaining", len(s.channelQueue)) - if s.currentChannel == nil { - return nil + if newSafeHead.Number+1 < oldestBlock.NumberU64() { + // This could happen if there was an L1 reorg. + s.log.Warn("safe head reversed, clearing channel manager state", + "oldestBlock", eth.ToBlockID(oldestBlock), + "newSafeBlock", newSafeHead) + // We should restart work from the new safe head, + // and therefore prune all the blocks. + s.Clear(newSafeHead.L1Origin) + return } - // If the channel is already full, we don't need to close it or output frames. - // This would already have happened in TxData. - if !s.currentChannel.IsFull() { - // Force-close the remaining open channel early (if not already closed): - // it will be marked as "full" due to service termination. - s.currentChannel.Close() + numBlocksToDequeue := newSafeHead.Number + 1 - oldestBlock.NumberU64() - // Final outputFrames call in case there was unflushed data in the compressor. - if err := s.outputFrames(); err != nil { - return fmt.Errorf("outputting frames during close: %w", err) - } + if numBlocksToDequeue > uint64(s.blocks.Len()) { + // This could happen if the batcher restarted. + // The sequencer may have derived the safe chain + // from channels sent by a previous batcher instance. + s.log.Warn("safe head above unsafe head, clearing channel manager state", + "unsafeBlock", eth.ToBlockID(s.blocks[s.blocks.Len()-1]), + "newSafeBlock", newSafeHead) + // We should restart work from the new safe head, + // and therefore prune all the blocks. + s.Clear(newSafeHead.L1Origin) + return } - if s.currentChannel.HasTxData() { - // Make it clear to the caller that there is remaining pending work. - return ErrPendingAfterClose + if s.blocks[numBlocksToDequeue-1].Hash() != newSafeHead.Hash { + s.log.Warn("safe chain reorg, clearing channel manager state", + "existingBlock", eth.ToBlockID(s.blocks[numBlocksToDequeue-1]), + "newSafeBlock", newSafeHead) + // We should restart work from the new safe head, + // and therefore prune all the blocks. + s.Clear(newSafeHead.L1Origin) + return + } + + // This shouldn't return an error because + // We already checked numBlocksToDequeue <= s.blocks.Len() + _, _ = s.blocks.DequeueN(int(numBlocksToDequeue)) + s.blockCursor -= int(numBlocksToDequeue) + + if s.blockCursor < 0 { + panic("negative blockCursor") } - return nil } -// Requeue rebuilds the channel manager state by -// rewinding blocks back from the channel queue, and setting the defaultCfg. -func (s *channelManager) Requeue(newCfg ChannelConfig) { - newChannelQueue := []*channel{} - blocksToRequeue := []*types.Block{} - for _, channel := range s.channelQueue { - if !channel.NoneSubmitted() { - newChannelQueue = append(newChannelQueue, channel) - continue +// pruneChannels dequeues channels from the internal channels queue +// if they were built using blocks which are now safe +func (s *channelManager) pruneChannels(newSafeHead eth.L2BlockRef) { + i := 0 + for _, ch := range s.channelQueue { + if ch.LatestL2().Number > newSafeHead.Number { + break } - blocksToRequeue = append(blocksToRequeue, channel.channelBuilder.Blocks()...) + i++ } + s.channelQueue = s.channelQueue[i:] +} - // We put the blocks back at the front of the queue: - s.blocks.Prepend(blocksToRequeue...) - - for _, b := range blocksToRequeue { - s.metr.RecordL2BlockInPendingQueue(b) +// PendingDABytes returns the current number of bytes pending to be written to the DA layer (from blocks fetched from L2 +// but not yet in a channel). +func (s *channelManager) PendingDABytes() int64 { + f := s.metr.PendingDABytes() + if f >= math.MaxInt64 { + return math.MaxInt64 } + if f <= math.MinInt64 { + return math.MinInt64 + } + return int64(f) +} - // Channels which where already being submitted are put back - s.channelQueue = newChannelQueue - s.currentChannel = nil - // Setting the defaultCfg will cause new channels - // to pick up the new ChannelConfig - s.defaultCfg = newCfg +// CheckExpectedProgress uses the supplied syncStatus to infer +// whether the node providing the status has made the expected +// safe head progress given fully submitted channels held in +// state. +func (m *channelManager) CheckExpectedProgress(syncStatus eth.SyncStatus) error { + for _, ch := range m.channelQueue { + if ch.isFullySubmitted() && // This implies a number of l1 confirmations has passed, depending on how the txmgr was configured + !ch.isTimedOut() && + syncStatus.CurrentL1.Number > ch.maxInclusionBlock && + syncStatus.SafeL2.Number < ch.LatestL2().Number { + return errors.New("safe head did not make expected progress") + } + } + return nil } diff --git a/op-batcher/batcher/channel_manager_test.go b/op-batcher/batcher/channel_manager_test.go index 8dcb0745c1642..32aae1b06dd1e 100644 --- a/op-batcher/batcher/channel_manager_test.go +++ b/op-batcher/batcher/channel_manager_test.go @@ -40,10 +40,6 @@ func TestChannelManagerBatchType(t *testing.T) { {"ChannelManagerReturnsErrReorgWhenDrained", ChannelManagerReturnsErrReorgWhenDrained}, {"ChannelManager_Clear", ChannelManager_Clear}, {"ChannelManager_TxResend", ChannelManager_TxResend}, - {"ChannelManagerCloseBeforeFirstUse", ChannelManagerCloseBeforeFirstUse}, - {"ChannelManagerCloseNoPendingChannel", ChannelManagerCloseNoPendingChannel}, - {"ChannelManagerClosePendingChannel", ChannelManagerClosePendingChannel}, - {"ChannelManagerCloseAllTxsFailed", ChannelManagerCloseAllTxsFailed}, } for _, test := range tests { test := test @@ -130,7 +126,7 @@ func ChannelManager_Clear(t *testing.T, batchType uint) { // Channel Manager state should be empty by default require.Empty(m.blocks) - require.Equal(eth.BlockID{}, m.l1OriginLastClosedChannel) + require.Equal(eth.BlockID{}, m.l1OriginLastSubmittedChannel) require.Equal(common.Hash{}, m.tip) require.Nil(m.currentChannel) require.Empty(m.channelQueue) @@ -154,15 +150,14 @@ func ChannelManager_Clear(t *testing.T, batchType uint) { // Process the blocks // We should have a pending channel with 1 frame - // and no more blocks since processBlocks consumes - // the list + require.NoError(m.processBlocks()) require.NoError(m.currentChannel.channelBuilder.co.Flush()) require.NoError(m.outputFrames()) _, err := m.nextTxData(m.currentChannel) require.NoError(err) - require.NotNil(m.l1OriginLastClosedChannel) - require.Len(m.blocks, 0) + require.Equal(m.blockCursor, len(m.blocks)) + require.NotNil(m.l1OriginLastSubmittedChannel) require.Equal(newL1Tip, m.tip) require.Len(m.currentChannel.pendingTransactions, 1) @@ -173,7 +168,7 @@ func ChannelManager_Clear(t *testing.T, batchType uint) { ParentHash: a.Hash(), }, nil, nil, nil) require.NoError(m.AddL2Block(b)) - require.Len(m.blocks, 1) + require.Equal(m.blockCursor, len(m.blocks)-1) require.Equal(b.Hash(), m.tip) safeL1Origin := eth.BlockID{ @@ -184,7 +179,7 @@ func ChannelManager_Clear(t *testing.T, batchType uint) { // Check that the entire channel manager state cleared require.Empty(m.blocks) - require.Equal(uint64(123), m.l1OriginLastClosedChannel.Number) + require.Equal(uint64(123), m.l1OriginLastSubmittedChannel.Number) require.Equal(common.Hash{}, m.tip) require.Nil(m.currentChannel) require.Empty(m.channelQueue) @@ -228,220 +223,6 @@ func ChannelManager_TxResend(t *testing.T, batchType uint) { require.Len(fs, 1) } -// ChannelManagerCloseBeforeFirstUse ensures that the channel manager -// will not produce any frames if closed immediately. -func ChannelManagerCloseBeforeFirstUse(t *testing.T, batchType uint) { - require := require.New(t) - rng := rand.New(rand.NewSource(time.Now().UnixNano())) - log := testlog.Logger(t, log.LevelCrit) - m := NewChannelManager(log, metrics.NoopMetrics, - channelManagerTestConfig(10000, batchType), - defaultTestRollupConfig, - ) - m.Clear(eth.BlockID{}) - - a := derivetest.RandomL2BlockWithChainId(rng, 4, defaultTestRollupConfig.L2ChainID) - - require.NoError(m.Close(), "Expected to close channel manager gracefully") - - err := m.AddL2Block(a) - require.NoError(err, "Failed to add L2 block") - - _, err = m.TxData(eth.BlockID{}) - require.ErrorIs(err, io.EOF, "Expected closed channel manager to contain no tx data") -} - -// ChannelManagerCloseNoPendingChannel ensures that the channel manager -// can gracefully close with no pending channels, and will not emit any new -// channel frames. -func ChannelManagerCloseNoPendingChannel(t *testing.T, batchType uint) { - require := require.New(t) - log := testlog.Logger(t, log.LevelCrit) - cfg := channelManagerTestConfig(10000, batchType) - cfg.CompressorConfig.TargetOutputSize = 1 // full on first block - cfg.ChannelTimeout = 1000 - m := NewChannelManager(log, metrics.NoopMetrics, cfg, defaultTestRollupConfig) - m.Clear(eth.BlockID{}) - a := newMiniL2Block(0) - b := newMiniL2BlockWithNumberParent(0, big.NewInt(1), a.Hash()) - - err := m.AddL2Block(a) - require.NoError(err, "Failed to add L2 block") - - txdata, err := m.TxData(eth.BlockID{}) - require.NoError(err, "Expected channel manager to return valid tx data") - - m.TxConfirmed(txdata.ID(), eth.BlockID{}) - - _, err = m.TxData(eth.BlockID{}) - require.ErrorIs(err, io.EOF, "Expected channel manager to EOF") - - require.NoError(m.Close(), "Expected to close channel manager gracefully") - - err = m.AddL2Block(b) - require.NoError(err, "Failed to add L2 block") - - _, err = m.TxData(eth.BlockID{}) - require.ErrorIs(err, io.EOF, "Expected closed channel manager to return no new tx data") -} - -// ChannelManagerClosePendingChannel ensures that the channel manager -// can gracefully close with a pending channel, and will not produce any -// new channel frames after this point. -func ChannelManagerClosePendingChannel(t *testing.T, batchType uint) { - require := require.New(t) - // The number of batch txs depends on compression of the random data, hence the static test RNG seed. - // Example of different RNG seed that creates less than 2 frames: 1698700588902821588 - rng := rand.New(rand.NewSource(123)) - log := testlog.Logger(t, log.LevelError) - cfg := channelManagerTestConfig(10_000, batchType) - cfg.ChannelTimeout = 1000 - m := NewChannelManager(log, metrics.NoopMetrics, cfg, defaultTestRollupConfig) - m.Clear(eth.BlockID{}) - - numTx := 20 // Adjust number of txs to make 2 frames - a := derivetest.RandomL2BlockWithChainId(rng, numTx, defaultTestRollupConfig.L2ChainID) - - err := m.AddL2Block(a) - require.NoError(err, "Failed to add L2 block") - - txdata, err := m.TxData(eth.BlockID{}) - require.NoError(err, "Expected channel manager to produce valid tx data") - log.Info("generated first tx data", "len", txdata.Len()) - - m.TxConfirmed(txdata.ID(), eth.BlockID{}) - - require.ErrorIs(m.Close(), ErrPendingAfterClose, "Expected channel manager to error on close because of pending tx data") - - txdata, err = m.TxData(eth.BlockID{}) - require.NoError(err, "Expected channel manager to produce tx data from remaining L2 block data") - log.Info("generated more tx data", "len", txdata.Len()) - - m.TxConfirmed(txdata.ID(), eth.BlockID{}) - - _, err = m.TxData(eth.BlockID{}) - require.ErrorIs(err, io.EOF, "Expected channel manager to have no more tx data") - - _, err = m.TxData(eth.BlockID{}) - require.ErrorIs(err, io.EOF, "Expected closed channel manager to produce no more tx data") -} - -// ChannelManager_Close_PartiallyPendingChannel ensures that the channel manager -// can gracefully close with a pending channel, where a block is still waiting -// inside the compressor to be flushed. -// -// This test runs only for singular batches on purpose. -// The SpanChannelOut writes full span batches to the compressor for -// every new block that's added, so NonCompressor cannot be used to -// set up a scenario where data is only partially flushed. -// Couldn't get the test to work even with modifying NonCompressor -// to flush half-way through writing to the compressor... -func TestChannelManager_Close_PartiallyPendingChannel(t *testing.T) { - require := require.New(t) - // The number of batch txs depends on compression of the random data, hence the static test RNG seed. - // Example of different RNG seed that creates less than 2 frames: 1698700588902821588 - rng := rand.New(rand.NewSource(123)) - log := testlog.Logger(t, log.LevelError) - cfg := ChannelConfig{ - MaxFrameSize: 2200, - ChannelTimeout: 1000, - TargetNumFrames: 100, - } - cfg.InitNoneCompressor() - m := NewChannelManager(log, metrics.NoopMetrics, cfg, defaultTestRollupConfig) - m.Clear(eth.BlockID{}) - - numTx := 3 // Adjust number of txs to make 2 frames - a := derivetest.RandomL2BlockWithChainId(rng, numTx, defaultTestRollupConfig.L2ChainID) - b := derivetest.RandomL2BlockWithChainId(rng, numTx, defaultTestRollupConfig.L2ChainID) - bHeader := b.Header() - bHeader.Number = new(big.Int).Add(a.Number(), big.NewInt(1)) - bHeader.ParentHash = a.Hash() - b = b.WithSeal(bHeader) - - require.NoError(m.AddL2Block(a), "adding 1st L2 block") - require.NoError(m.AddL2Block(b), "adding 2nd L2 block") - - // Inside TxData, the two blocks queued above are written to the compressor. - // The NonCompressor will flush the first, but not the second block, when - // adding the second block, setting up the test with a partially flushed - // compressor. - txdata, err := m.TxData(eth.BlockID{}) - require.NoError(err, "Expected channel manager to produce valid tx data") - log.Info("generated first tx data", "len", txdata.Len()) - - m.TxConfirmed(txdata.ID(), eth.BlockID{}) - - // ensure no new ready data before closing - _, err = m.TxData(eth.BlockID{}) - require.ErrorIs(err, io.EOF, "Expected unclosed channel manager to only return a single frame") - - require.ErrorIs(m.Close(), ErrPendingAfterClose, "Expected channel manager to error on close because of pending tx data") - require.NotNil(m.currentChannel) - require.ErrorIs(m.currentChannel.FullErr(), ErrTerminated, "Expected current channel to be terminated by Close") - - txdata, err = m.TxData(eth.BlockID{}) - require.NoError(err, "Expected channel manager to produce tx data from remaining L2 block data") - log.Info("generated more tx data", "len", txdata.Len()) - - m.TxConfirmed(txdata.ID(), eth.BlockID{}) - - _, err = m.TxData(eth.BlockID{}) - require.ErrorIs(err, io.EOF, "Expected closed channel manager to produce no more tx data") -} - -// ChannelManagerCloseAllTxsFailed ensures that the channel manager -// can gracefully close after producing transaction frames if none of these -// have successfully landed on chain. -func ChannelManagerCloseAllTxsFailed(t *testing.T, batchType uint) { - require := require.New(t) - rng := rand.New(rand.NewSource(1357)) - log := testlog.Logger(t, log.LevelCrit) - cfg := channelManagerTestConfig(100, batchType) - cfg.TargetNumFrames = 1000 - cfg.InitNoneCompressor() - m := NewChannelManager(log, metrics.NoopMetrics, cfg, defaultTestRollupConfig) - m.Clear(eth.BlockID{}) - - a := derivetest.RandomL2BlockWithChainId(rng, 1000, defaultTestRollupConfig.L2ChainID) - - err := m.AddL2Block(a) - require.NoError(err, "Failed to add L2 block") - - drainTxData := func() (txdatas []txData) { - for { - txdata, err := m.TxData(eth.BlockID{}) - if err == io.EOF { - return - } - require.NoError(err, "Expected channel manager to produce valid tx data") - txdatas = append(txdatas, txdata) - } - } - - txdatas := drainTxData() - require.NotEmpty(txdatas) - - for _, txdata := range txdatas { - m.TxFailed(txdata.ID()) - } - - // Show that this data will continue to be emitted as long as the transaction - // fails and the channel manager is not closed - txdatas1 := drainTxData() - require.NotEmpty(txdatas) - require.ElementsMatch(txdatas, txdatas1, "expected same txdatas on re-attempt") - - for _, txdata := range txdatas1 { - m.TxFailed(txdata.ID()) - } - - require.NoError(m.Close(), "Expected to close channel manager gracefully") - - _, err = m.TxData(eth.BlockID{}) - require.ErrorIs(err, io.EOF, "Expected closed channel manager to produce no more tx data") -} - func TestChannelManager_ChannelCreation(t *testing.T) { l := testlog.Logger(t, log.LevelCrit) const maxChannelDuration = 15 @@ -475,7 +256,7 @@ func TestChannelManager_ChannelCreation(t *testing.T) { t.Run(test.name, func(t *testing.T) { m := NewChannelManager(l, metrics.NoopMetrics, cfg, defaultTestRollupConfig) - m.l1OriginLastClosedChannel = test.safeL1Block + m.l1OriginLastSubmittedChannel = test.safeL1Block require.Nil(t, m.currentChannel) require.NoError(t, m.ensureChannelWithSpace(eth.BlockID{})) @@ -543,10 +324,12 @@ func TestChannelManager_TxData(t *testing.T) { // * One when the channelManager was created // * One when the channel is about to be submitted - // * Potentially one more if the replacement channel is about to be submitted, - // this only happens when going from calldata->blobs because - // the channel is no longer ready to send until more data - // is added. + // * Potentially one more when the replacement channel + // is not immediately ready to be submitted, but later + // becomes ready after more data is added. + // This only happens when going from calldata->blobs because + // the channel is not immediately ready to send until more data + // is added due to blob channels having greater capacity. numExpectedAssessments int } @@ -591,7 +374,7 @@ func TestChannelManager_TxData(t *testing.T) { // we get some data to submit var data txData for { - m.blocks = []*types.Block{blockA} + m.blocks = append(m.blocks, blockA) data, err = m.TxData(eth.BlockID{}) if err == nil && data.Len() > 0 { break @@ -609,16 +392,15 @@ func TestChannelManager_TxData(t *testing.T) { } -// TestChannelManager_Requeue seeds the channel manager with blocks, +// TestChannelManager_handleChannelInvalidated seeds the channel manager with blocks, // takes a state snapshot, triggers the blocks->channels pipeline, -// and then calls Requeue. Finally, it asserts the channel manager's -// state is equal to the snapshot. It repeats this for a channel -// which has a pending transaction and verifies that Requeue is then -// a noop. -func TestChannelManager_Requeue(t *testing.T) { +// and then calls handleChannelInvalidated. It asserts on the final state of +// the channel manager. +func TestChannelManager_handleChannelInvalidated(t *testing.T) { l := testlog.Logger(t, log.LevelCrit) cfg := channelManagerTestConfig(100, derive.SingularBatchType) - m := NewChannelManager(l, metrics.NoopMetrics, cfg, defaultTestRollupConfig) + metrics := new(metrics.TestMetrics) + m := NewChannelManager(l, metrics, cfg, defaultTestRollupConfig) // Seed channel manager with blocks rng := rand.New(rand.NewSource(99)) @@ -631,42 +413,197 @@ func TestChannelManager_Requeue(t *testing.T) { m.blocks = stateSnapshot require.Empty(t, m.channelQueue) + // Place an old channel in the queue. + // This channel should not be affected by + // a requeue or a later channel timing out. + oldChannel := newChannel(l, nil, m.defaultCfg, defaultTestRollupConfig, 0, nil) + oldChannel.Close() + m.channelQueue = []*channel{oldChannel} + require.Len(t, m.channelQueue, 1) + + // Setup initial metrics + metrics.RecordL2BlockInPendingQueue(blockA) + metrics.RecordL2BlockInPendingQueue(blockB) + pendingBytesBefore := metrics.PendingBlocksBytesCurrent + // Trigger the blocks -> channelQueue data pipelining require.NoError(t, m.ensureChannelWithSpace(eth.BlockID{})) - require.NotEmpty(t, m.channelQueue) + require.Len(t, m.channelQueue, 2) require.NoError(t, m.processBlocks()) // Assert that at least one block was processed into the channel - require.NotContains(t, m.blocks, blockA) + require.Equal(t, 1, m.blockCursor) + + // Check metric decreased + metricsDelta := metrics.PendingBlocksBytesCurrent - pendingBytesBefore + require.Negative(t, metricsDelta) + + l1OriginBefore := m.l1OriginLastSubmittedChannel - // Call the function we are testing - m.Requeue(m.defaultCfg) + m.handleChannelInvalidated(m.currentChannel) // Ensure we got back to the state above require.Equal(t, m.blocks, stateSnapshot) - require.Empty(t, m.channelQueue) + require.Contains(t, m.channelQueue, oldChannel) + require.Len(t, m.channelQueue, 1) + + // Check metric came back up to previous value + require.Equal(t, pendingBytesBefore, metrics.PendingBlocksBytesCurrent) + + // Ensure the l1OridingLastSubmittedChannel was + // not changed. This ensures the next channel + // has its duration timeout deadline computed + // properly. + require.Equal(t, l1OriginBefore, m.l1OriginLastSubmittedChannel) // Trigger the blocks -> channelQueue data pipelining again require.NoError(t, m.ensureChannelWithSpace(eth.BlockID{})) require.NotEmpty(t, m.channelQueue) require.NoError(t, m.processBlocks()) +} - // Assert that at least one block was processed into the channel - require.NotContains(t, m.blocks, blockA) +func TestChannelManager_PruneBlocks(t *testing.T) { + l := testlog.Logger(t, log.LevelDebug) + cfg := channelManagerTestConfig(100, derive.SingularBatchType) + m := NewChannelManager(l, metrics.NoopMetrics, cfg, defaultTestRollupConfig) - // Now mark the 0th channel in the queue as already - // starting to send on chain - channel0 := m.channelQueue[0] - channel0.pendingTransactions["foo"] = txData{} - require.False(t, channel0.NoneSubmitted()) + a := types.NewBlock(&types.Header{ + Number: big.NewInt(0), + }, nil, nil, nil) + b := types.NewBlock(&types.Header{ // This will shortly become the safe head + Number: big.NewInt(1), + ParentHash: a.Hash(), + }, nil, nil, nil) + c := types.NewBlock(&types.Header{ + Number: big.NewInt(2), + ParentHash: b.Hash(), + }, nil, nil, nil) + + require.NoError(t, m.AddL2Block(a)) + m.blockCursor += 1 + require.NoError(t, m.AddL2Block(b)) + m.blockCursor += 1 + require.NoError(t, m.AddL2Block(c)) + m.blockCursor += 1 + + // Normal path + m.pruneSafeBlocks(eth.L2BlockRef{ + Hash: b.Hash(), + Number: b.NumberU64(), + }) + require.Equal(t, queue.Queue[*types.Block]{c}, m.blocks) + + // Safe chain didn't move, nothing to prune + m.pruneSafeBlocks(eth.L2BlockRef{ + Hash: b.Hash(), + Number: b.NumberU64(), + }) + require.Equal(t, queue.Queue[*types.Block]{c}, m.blocks) - // Call the function we are testing - m.Requeue(m.defaultCfg) + // Safe chain moved beyond the blocks we had + // state should be cleared + m.pruneSafeBlocks(eth.L2BlockRef{ + Hash: c.Hash(), + Number: uint64(99), + }) + require.Equal(t, queue.Queue[*types.Block]{}, m.blocks) + + // No blocks to prune, NOOP + m.pruneSafeBlocks(eth.L2BlockRef{ + Hash: c.Hash(), + Number: c.NumberU64(), + }) + require.Equal(t, queue.Queue[*types.Block]{}, m.blocks) - // The requeue shouldn't affect the pending channel - require.Contains(t, m.channelQueue, channel0) + // Put another block in + d := types.NewBlock(&types.Header{ + Number: big.NewInt(3), + ParentHash: c.Hash(), + }, nil, nil, nil) + require.NoError(t, m.AddL2Block(d)) + m.blockCursor += 1 + + // Safe chain reorg + // state should be cleared + m.pruneSafeBlocks(eth.L2BlockRef{ + Hash: a.Hash(), + Number: uint64(3), + }) + require.Equal(t, queue.Queue[*types.Block]{}, m.blocks) + + // Put another block in + require.NoError(t, m.AddL2Block(d)) + m.blockCursor += 1 + + // Safe chain reversed + // state should be cleared + m.pruneSafeBlocks(eth.L2BlockRef{ + Hash: a.Hash(), // unused + Number: uint64(1), + }) + require.Equal(t, queue.Queue[*types.Block]{}, m.blocks) + +} + +func TestChannelManager_PruneChannels(t *testing.T) { + l := testlog.Logger(t, log.LevelCrit) + cfg := channelManagerTestConfig(100, derive.SingularBatchType) + cfg.InitNoneCompressor() + m := NewChannelManager(l, metrics.NoopMetrics, cfg, defaultTestRollupConfig) + + A, err := newChannelWithChannelOut(l, metrics.NoopMetrics, cfg, m.rollupCfg, 0) + require.NoError(t, err) + B, err := newChannelWithChannelOut(l, metrics.NoopMetrics, cfg, m.rollupCfg, 0) + require.NoError(t, err) + C, err := newChannelWithChannelOut(l, metrics.NoopMetrics, cfg, m.rollupCfg, 0) + require.NoError(t, err) + + m.channelQueue = []*channel{A, B, C} + + numTx := 1 + rng := rand.New(rand.NewSource(123)) + a0 := derivetest.RandomL2BlockWithChainId(rng, numTx, defaultTestRollupConfig.L2ChainID) + a0 = a0.WithSeal(&types.Header{Number: big.NewInt(0)}) + a1 := derivetest.RandomL2BlockWithChainId(rng, numTx, defaultTestRollupConfig.L2ChainID) + a1 = a1.WithSeal(&types.Header{Number: big.NewInt(1)}) + b2 := derivetest.RandomL2BlockWithChainId(rng, numTx, defaultTestRollupConfig.L2ChainID) + b2 = b2.WithSeal(&types.Header{Number: big.NewInt(2)}) + b3 := derivetest.RandomL2BlockWithChainId(rng, numTx, defaultTestRollupConfig.L2ChainID) + b3 = b3.WithSeal(&types.Header{Number: big.NewInt(3)}) + c4 := derivetest.RandomL2BlockWithChainId(rng, numTx, defaultTestRollupConfig.L2ChainID) + c4 = c4.WithSeal(&types.Header{Number: big.NewInt(4)}) + + _, err = A.AddBlock(a0) + require.NoError(t, err) + _, err = A.AddBlock(a1) + require.NoError(t, err) + + _, err = B.AddBlock(b2) + require.NoError(t, err) + _, err = B.AddBlock(b3) + require.NoError(t, err) + + _, err = C.AddBlock(c4) + require.NoError(t, err) + + m.pruneChannels(eth.L2BlockRef{ + Number: uint64(3), + }) + + require.Equal(t, []*channel{C}, m.channelQueue) + + m.pruneChannels(eth.L2BlockRef{ + Number: uint64(4), + }) + + require.Equal(t, []*channel{}, m.channelQueue) + + m.pruneChannels(eth.L2BlockRef{ + Number: uint64(4), + }) + + require.Equal(t, []*channel{}, m.channelQueue) - require.NotContains(t, m.blocks, blockA) } func TestChannelManager_ChannelOutFactory(t *testing.T) { type ChannelOutWrapper struct { @@ -690,3 +627,57 @@ func TestChannelManager_ChannelOutFactory(t *testing.T) { require.IsType(t, &ChannelOutWrapper{}, m.currentChannel.channelBuilder.co) } + +func TestChannelManager_CheckExpectedProgress(t *testing.T) { + l := testlog.Logger(t, log.LevelCrit) + cfg := channelManagerTestConfig(100, derive.SingularBatchType) + cfg.InitNoneCompressor() + m := NewChannelManager(l, metrics.NoopMetrics, cfg, defaultTestRollupConfig) + + channelMaxInclusionBlockNumber := uint64(3) + channelLatestSafeBlockNumber := uint64(11) + + // Prepare a (dummy) fully submitted channel + // with + // maxInclusionBlock and latest safe block number as above + A, err := newChannelWithChannelOut(l, metrics.NoopMetrics, cfg, m.rollupCfg, 0) + require.NoError(t, err) + rng := rand.New(rand.NewSource(123)) + a0 := derivetest.RandomL2BlockWithChainId(rng, 1, defaultTestRollupConfig.L2ChainID) + a0 = a0.WithSeal(&types.Header{Number: big.NewInt(int64(channelLatestSafeBlockNumber))}) + _, err = A.AddBlock(a0) + require.NoError(t, err) + A.maxInclusionBlock = channelMaxInclusionBlockNumber + A.Close() + A.channelBuilder.frames = nil + A.channelBuilder.frameCursor = 0 + require.True(t, A.isFullySubmitted()) + + m.channelQueue = append(m.channelQueue, A) + + // The current L1 number implies that + // channel A above should have been derived + // from, so we expect safe head to progress to + // the channelLatestSafeBlockNumber. + // Since the safe head moved to 11, there is no error: + ss := eth.SyncStatus{ + CurrentL1: eth.L1BlockRef{Number: channelMaxInclusionBlockNumber + 1}, + SafeL2: eth.L2BlockRef{Number: channelLatestSafeBlockNumber}, + } + err = m.CheckExpectedProgress(ss) + require.NoError(t, err) + + // If the currentL1 is as above but the + // safe head is less than channelLatestSafeBlockNumber, + // the method should return an error: + ss.SafeL2 = eth.L2BlockRef{Number: channelLatestSafeBlockNumber - 1} + err = m.CheckExpectedProgress(ss) + require.Error(t, err) + + // If the safe head is still less than channelLatestSafeBlockNumber + // but the currentL1 is _equal_ to the channelMaxInclusionBlockNumber + // there should be no error as that block is still being derived from: + ss.CurrentL1 = eth.L1BlockRef{Number: channelMaxInclusionBlockNumber} + err = m.CheckExpectedProgress(ss) + require.NoError(t, err) +} diff --git a/op-batcher/batcher/channel_test.go b/op-batcher/batcher/channel_test.go index 0aad780131c72..b36ce9311bcea 100644 --- a/op-batcher/batcher/channel_test.go +++ b/op-batcher/batcher/channel_test.go @@ -113,7 +113,7 @@ func TestChannelManager_NextTxData(t *testing.T) { frameNumber: uint16(0), }, } - channel.channelBuilder.PushFrames(frame) + channel.channelBuilder.frames = append(channel.channelBuilder.frames, frame) require.Equal(t, 1, channel.PendingFrames()) // Now the nextTxData function should return the frame @@ -142,7 +142,7 @@ func TestChannel_NextTxData_singleFrameTx(t *testing.T) { mockframes := makeMockFrameDatas(chID, n+1) // put multiple frames into channel, but less than target - ch.channelBuilder.PushFrames(mockframes[:n-1]...) + ch.channelBuilder.frames = mockframes[:n-1] requireTxData := func(i int) { require.True(ch.HasTxData(), "expected tx data %d", i) @@ -160,7 +160,7 @@ func TestChannel_NextTxData_singleFrameTx(t *testing.T) { require.False(ch.HasTxData()) // put in last two - ch.channelBuilder.PushFrames(mockframes[n-1 : n+1]...) + ch.channelBuilder.frames = append(ch.channelBuilder.frames, mockframes[n-1:n+1]...) for i := n - 1; i < n+1; i++ { requireTxData(i) } @@ -183,11 +183,11 @@ func TestChannel_NextTxData_multiFrameTx(t *testing.T) { mockframes := makeMockFrameDatas(chID, n+1) // put multiple frames into channel, but less than target - ch.channelBuilder.PushFrames(mockframes[:n-1]...) + ch.channelBuilder.frames = append(ch.channelBuilder.frames, mockframes[:n-1]...) require.False(ch.HasTxData()) // put in last two - ch.channelBuilder.PushFrames(mockframes[n-1 : n+1]...) + ch.channelBuilder.frames = append(ch.channelBuilder.frames, mockframes[n-1:n+1]...) require.True(ch.HasTxData()) txdata := ch.NextTxData() require.Len(txdata.frames, n) @@ -240,7 +240,8 @@ func TestChannelTxConfirmed(t *testing.T) { frameNumber: uint16(0), }, } - m.currentChannel.channelBuilder.PushFrames(frame) + m.currentChannel.channelBuilder.frames = append(m.currentChannel.channelBuilder.frames, frame) + require.Equal(t, 1, m.currentChannel.PendingFrames()) returnedTxData, err := m.nextTxData(m.currentChannel) expectedTxData := singleFrameTxData(frame) @@ -291,7 +292,7 @@ func TestChannelTxFailed(t *testing.T) { frameNumber: uint16(0), }, } - m.currentChannel.channelBuilder.PushFrames(frame) + m.currentChannel.channelBuilder.frames = append(m.currentChannel.channelBuilder.frames, frame) require.Equal(t, 1, m.currentChannel.PendingFrames()) returnedTxData, err := m.nextTxData(m.currentChannel) expectedTxData := singleFrameTxData(frame) diff --git a/op-batcher/batcher/config.go b/op-batcher/batcher/config.go index ac8bad7791a78..82be687af325a 100644 --- a/op-batcher/batcher/config.go +++ b/op-batcher/batcher/config.go @@ -96,6 +96,19 @@ type CLIConfig struct { // ActiveSequencerCheckDuration is the duration between checks to determine the active sequencer endpoint. ActiveSequencerCheckDuration time.Duration + // ThrottleInterval is the interval between notifying the block builder of the latest DA throttling state, or 0 to + // disable notifications entirely (only recommended for testing). + ThrottleInterval time.Duration + // ThrottleThreshold is the number of pending bytes beyond which the batcher will start throttling future bytes + // written to DA. + ThrottleThreshold uint64 + // ThrottleTxSize is the DA size of a transaction to start throttling when we are over the throttling threshold. + ThrottleTxSize uint64 + // ThrottleBlockSize is the total per-block DA limit to start imposing on block building when we are over the throttling threshold. + ThrottleBlockSize uint64 + // ThrottleAlwaysBlockSize is the total per-block DA limit to always imposing on block building. + ThrottleAlwaysBlockSize uint64 + // TestUseMaxTxSizeForBlobs allows to set the blob size with MaxL1TxSize. // Should only be used for testing purposes. TestUseMaxTxSizeForBlobs bool @@ -195,5 +208,10 @@ func NewConfig(ctx *cli.Context) *CLIConfig { PprofConfig: oppprof.ReadCLIConfig(ctx), RPC: oprpc.ReadCLIConfig(ctx), AltDA: altda.ReadCLIConfig(ctx), + ThrottleThreshold: ctx.Uint64(flags.ThrottleThresholdFlag.Name), + ThrottleInterval: ctx.Duration(flags.ThrottleIntervalFlag.Name), + ThrottleTxSize: ctx.Uint64(flags.ThrottleTxSizeFlag.Name), + ThrottleBlockSize: ctx.Uint64(flags.ThrottleBlockSizeFlag.Name), + ThrottleAlwaysBlockSize: ctx.Uint64(flags.ThrottleAlwaysBlockSizeFlag.Name), } } diff --git a/op-batcher/batcher/config_test.go b/op-batcher/batcher/config_test.go index 4b90ebaccb688..9ce1ab4628fa3 100644 --- a/op-batcher/batcher/config_test.go +++ b/op-batcher/batcher/config_test.go @@ -38,8 +38,11 @@ func validBatcherConfig() batcher.CLIConfig { MetricsConfig: metrics.DefaultCLIConfig(), PprofConfig: oppprof.DefaultCLIConfig(), // The compressor config is not checked in config.Check() - RPC: rpc.DefaultCLIConfig(), - CompressionAlgo: derive.Zlib, + RPC: rpc.DefaultCLIConfig(), + CompressionAlgo: derive.Zlib, + ThrottleThreshold: 0, // no DA throttling + ThrottleInterval: 12 * time.Second, + ThrottleTxSize: 0, } } diff --git a/op-batcher/batcher/driver.go b/op-batcher/batcher/driver.go index fdf746336aced..7e05c10e8dad3 100644 --- a/op-batcher/batcher/driver.go +++ b/op-batcher/batcher/driver.go @@ -11,6 +11,16 @@ import ( "sync/atomic" "time" + "golang.org/x/sync/errgroup" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" + altda "github.com/ethereum-optimism/optimism/op-alt-da" "github.com/ethereum-optimism/optimism/op-batcher/metrics" "github.com/ethereum-optimism/optimism/op-node/rollup" @@ -18,12 +28,6 @@ import ( "github.com/ethereum-optimism/optimism/op-service/dial" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/txmgr" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/txpool" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - "golang.org/x/sync/errgroup" ) var ( @@ -36,6 +40,7 @@ var ( }, }, } + SetMaxDASizeMethod = "miner_setMaxDASize" ) type txRef struct { @@ -103,11 +108,13 @@ type BatchSubmitter struct { killCtx context.Context cancelKillCtx context.CancelFunc + l2BlockAdded chan struct{} // notifies the throttling loop whenever an l2 block is added + mutex sync.Mutex running bool txpoolMutex sync.Mutex // guards txpoolState and txpoolBlockedBlob - txpoolState int + txpoolState TxPoolState txpoolBlockedBlob bool // lastStoredBlock is the last block loaded into `state`. If it is empty it should be set to the l2 safe head. @@ -157,8 +164,20 @@ func (l *BatchSubmitter) StartBatchSubmitting() error { } } - l.wg.Add(1) - go l.loop() + receiptsCh := make(chan txmgr.TxReceipt[txRef]) + receiptsLoopCtx, cancelReceiptsLoopCtx := context.WithCancel(context.Background()) + throttlingLoopCtx, cancelThrottlingLoopCtx := context.WithCancel(context.Background()) + + // DA throttling loop should always be started except for testing (indicated by ThrottleInterval == 0) + if l.Config.ThrottleInterval > 0 { + l.wg.Add(1) + go l.throttlingLoop(throttlingLoopCtx) + } else { + l.Log.Warn("Throttling loop is DISABLED due to 0 throttle-interval. This should not be disabled in prod.") + } + l.wg.Add(2) + go l.processReceiptsLoop(receiptsLoopCtx, receiptsCh) // receives from receiptsCh + go l.mainLoop(l.shutdownCtx, receiptsCh, cancelReceiptsLoopCtx, cancelThrottlingLoopCtx) // sends on receiptsCh l.Log.Info("Batch Submitter started") return nil @@ -237,11 +256,12 @@ func (l *BatchSubmitter) StopBatchSubmitting(ctx context.Context) error { // 2. Check if the sync status is valid or if we are all the way up to date // 3. Check if it needs to initialize state OR it is lagging (todo: lagging just means race condition?) // 4. Load all new blocks into the local state. +// 5. Dequeue blocks from local state which are now safe. // // If there is a reorg, it will reset the last stored block but not clear the internal state so // the state can be flushed to L1. -func (l *BatchSubmitter) loadBlocksIntoState(ctx context.Context) error { - start, end, err := l.calculateL2BlockRangeToStore(ctx) +func (l *BatchSubmitter) loadBlocksIntoState(syncStatus eth.SyncStatus, ctx context.Context) error { + start, end, err := l.calculateL2BlockRangeToStore(syncStatus) if err != nil { l.Log.Warn("Error calculating L2 block range", "err", err) return err @@ -294,16 +314,20 @@ func (l *BatchSubmitter) loadBlockIntoState(ctx context.Context, blockNumber uin return nil, fmt.Errorf("adding L2 block to state: %w", err) } + // notify the throttling loop it may be time to initiate throttling without blocking + select { + case l.l2BlockAdded <- struct{}{}: + default: + } + l.Log.Info("Added L2 block to local state", "block", eth.ToBlockID(block), "tx_count", len(block.Transactions()), "time", block.Time()) return block, nil } -// calculateL2BlockRangeToStore determines the range (start,end] that should be loaded into the local state. -// It also takes care of initializing some local state (i.e. will modify l.lastStoredBlock in certain conditions) -func (l *BatchSubmitter) calculateL2BlockRangeToStore(ctx context.Context) (eth.BlockID, eth.BlockID, error) { +func (l *BatchSubmitter) getSyncStatus(ctx context.Context) (*eth.SyncStatus, error) { rollupClient, err := l.EndpointProvider.RollupClient(ctx) if err != nil { - return eth.BlockID{}, eth.BlockID{}, fmt.Errorf("getting rollup client: %w", err) + return nil, fmt.Errorf("getting rollup client: %w", err) } var ( @@ -321,7 +345,7 @@ func (l *BatchSubmitter) calculateL2BlockRangeToStore(ctx context.Context) (eth. // Ensure that we have the sync status if err != nil { - return eth.BlockID{}, eth.BlockID{}, fmt.Errorf("failed to get sync status: %w", err) + return nil, fmt.Errorf("failed to get sync status: %w", err) } // If we have a head, break out of the loop @@ -338,10 +362,21 @@ func (l *BatchSubmitter) calculateL2BlockRangeToStore(ctx context.Context) (eth. // Reset timer to tick of the new backoff time again timer.Reset(backoff) case <-ctx.Done(): - return eth.BlockID{}, eth.BlockID{}, ctx.Err() + return nil, ctx.Err() } } + return syncStatus, nil +} + +// calculateL2BlockRangeToStore determines the range (start,end] that should be loaded into the local state. +// It also takes care of initializing some local state (i.e. will modify l.lastStoredBlock in certain conditions +// as well as garbage collecting blocks which became safe) +func (l *BatchSubmitter) calculateL2BlockRangeToStore(syncStatus eth.SyncStatus) (eth.BlockID, eth.BlockID, error) { + if syncStatus.HeadL1 == (eth.L1BlockRef{}) { + return eth.BlockID{}, eth.BlockID{}, errors.New("empty sync status") + } + // Check last stored to see if it needs to be set on startup OR set if is lagged behind. // It lagging implies that the op-node processed some batches that were submitted prior to the current instance of the batcher being alive. if l.lastStoredBlock == (eth.BlockID{}) { @@ -371,6 +406,8 @@ func (l *BatchSubmitter) calculateL2BlockRangeToStore(ctx context.Context) (eth. // Submitted batch, but it is not valid // Missed L2 block somehow. +type TxPoolState int + const ( // Txpool states. Possible state transitions: // TxpoolGood -> TxpoolBlocked: @@ -380,15 +417,30 @@ const ( // send a cancellation transaction. // TxpoolCancelPending -> TxpoolGood: // happens once the cancel transaction completes, whether successfully or in error. - TxpoolGood int = iota + TxpoolGood TxPoolState = iota TxpoolBlocked TxpoolCancelPending ) -func (l *BatchSubmitter) loop() { +// setTxPoolState locks the mutex, sets the parameters to the supplied ones, and release the mutex. +func (l *BatchSubmitter) setTxPoolState(txPoolState TxPoolState, txPoolBlockedBlob bool) { + l.txpoolMutex.Lock() + l.txpoolState = txPoolState + l.txpoolBlockedBlob = txPoolBlockedBlob + l.txpoolMutex.Unlock() +} + +// mainLoop periodically: +// - polls the sequencer, +// - prunes the channel manager state (i.e. safe blocks) +// - loads unsafe blocks from the sequencer +// - drives the creation of channels and frames +// - sends transactions to the DA layer +func (l *BatchSubmitter) mainLoop(ctx context.Context, receiptsCh chan txmgr.TxReceipt[txRef], receiptsLoopCancel, throttlingLoopCancel context.CancelFunc) { defer l.wg.Done() + defer receiptsLoopCancel() + defer throttlingLoopCancel() - receiptsCh := make(chan txmgr.TxReceipt[txRef]) queue := txmgr.NewQueue[txRef](l.killCtx, l.Txmgr, l.Config.MaxPendingTransactions) daGroup := &errgroup.Group{} // errgroup with limit of 0 means no goroutine is able to run concurrently, @@ -397,105 +449,154 @@ func (l *BatchSubmitter) loop() { daGroup.SetLimit(int(l.Config.MaxConcurrentDARequests)) } - // start the receipt/result processing loop - receiptLoopDone := make(chan struct{}) - defer close(receiptLoopDone) // shut down receipt loop - l.txpoolMutex.Lock() l.txpoolState = TxpoolGood l.txpoolMutex.Unlock() - go func() { - for { - select { - case r := <-receiptsCh: - l.txpoolMutex.Lock() - if errors.Is(r.Err, txpool.ErrAlreadyReserved) && l.txpoolState == TxpoolGood { - l.txpoolState = TxpoolBlocked - l.txpoolBlockedBlob = r.ID.isBlob - l.Log.Info("incompatible tx in txpool", "is_blob", r.ID.isBlob) - } else if r.ID.isCancel && l.txpoolState == TxpoolCancelPending { - // Set state to TxpoolGood even if the cancellation transaction ended in error - // since the stuck transaction could have cleared while we were waiting. - l.txpoolState = TxpoolGood - l.Log.Info("txpool may no longer be blocked", "err", r.Err) - } - l.txpoolMutex.Unlock() - l.Log.Info("Handling receipt", "id", r.ID) - l.handleReceipt(r) - case <-receiptLoopDone: - l.Log.Info("Receipt processing loop done") - return - } - } - }() + + l.l2BlockAdded = make(chan struct{}) + defer close(l.l2BlockAdded) ticker := time.NewTicker(l.Config.PollInterval) defer ticker.Stop() - publishAndWait := func() { - l.publishStateToL1(queue, receiptsCh, daGroup) - if !l.Txmgr.IsClosed() { - if l.Config.UseAltDA { - l.Log.Info("Waiting for altDA writes to complete...") - err := daGroup.Wait() - if err != nil { - l.Log.Error("Error returned by one of the altda goroutines waited on", "err", err) - } - } - l.Log.Info("Waiting for L1 txs to be confirmed...") - err := queue.Wait() - if err != nil { - l.Log.Error("Error returned by one of the txmgr goroutines waited on", "err", err) - } - } else { - l.Log.Info("Txmgr is closed, remaining channel data won't be sent") - } - } - for { select { case <-ticker.C: + if !l.checkTxpool(queue, receiptsCh) { continue } - if err := l.loadBlocksIntoState(l.shutdownCtx); errors.Is(err, ErrReorg) { - err := l.state.Close() - if err != nil { - if errors.Is(err, ErrPendingAfterClose) { - l.Log.Warn("Closed channel manager to handle L2 reorg with pending channel(s) remaining - submitting") - } else { - l.Log.Error("Error closing the channel manager to handle a L2 reorg", "err", err) - } - } - // on reorg we want to publish all pending state then wait until each result clears before resetting - // the state. - publishAndWait() - l.clearState(l.shutdownCtx) + + syncStatus, err := l.getSyncStatus(l.shutdownCtx) + if err != nil { + l.Log.Warn("could not get sync status", "err", err) continue } - l.publishStateToL1(queue, receiptsCh, daGroup) - case <-l.shutdownCtx.Done(): - if l.Txmgr.IsClosed() { - l.Log.Info("Txmgr is closed, remaining channel data won't be sent") - return - } - // This removes any never-submitted pending channels, so these do not have to be drained with transactions. - // Any remaining unfinished channel is terminated, so its data gets submitted. - err := l.state.Close() + + l.state.pruneSafeBlocks(syncStatus.SafeL2) + l.state.pruneChannels(syncStatus.SafeL2) + + err = l.state.CheckExpectedProgress(*syncStatus) if err != nil { - if errors.Is(err, ErrPendingAfterClose) { - l.Log.Warn("Closed channel manager on shutdown with pending channel(s) remaining - submitting") - } else { - l.Log.Error("Error closing the channel manager on shutdown", "err", err) - } + l.Log.Warn("error checking expected progress, clearing state and waiting for node sync", "err", err) + l.waitNodeSyncAndClearState() + continue + } + + if err := l.loadBlocksIntoState(*syncStatus, l.shutdownCtx); errors.Is(err, ErrReorg) { + l.Log.Warn("error loading blocks, clearing state and waiting for node sync", "err", err) + l.waitNodeSyncAndClearState() + continue + } + + l.publishStateToL1(queue, receiptsCh, daGroup, l.Config.PollInterval) + case <-ctx.Done(): + l.Log.Warn("main loop returning") + return + } + } +} + +// processReceiptsLoop handles transaction receipts from the DA layer +func (l *BatchSubmitter) processReceiptsLoop(ctx context.Context, receiptsCh chan txmgr.TxReceipt[txRef]) { + defer l.wg.Done() + l.Log.Info("Starting receipts processing loop") + for { + select { + case r := <-receiptsCh: + if errors.Is(r.Err, txpool.ErrAlreadyReserved) && l.txpoolState == TxpoolGood { + l.setTxPoolState(TxpoolBlocked, r.ID.isBlob) + l.Log.Warn("incompatible tx in txpool", "id", r.ID, "is_blob", r.ID.isBlob) + } else if r.ID.isCancel && l.txpoolState == TxpoolCancelPending { + // Set state to TxpoolGood even if the cancellation transaction ended in error + // since the stuck transaction could have cleared while we were waiting. + l.setTxPoolState(TxpoolGood, l.txpoolBlockedBlob) + l.Log.Info("txpool may no longer be blocked", "err", r.Err) } - publishAndWait() - l.Log.Info("Finished publishing all remaining channel data") + l.Log.Info("Handling receipt", "id", r.ID) + l.handleReceipt(r) + case <-ctx.Done(): + l.Log.Info("Receipt processing loop done") return } } } +// throttlingLoop monitors the backlog in bytes we need to make available, and appropriately enables or disables +// throttling of incoming data prevent the backlog from growing too large. By looping & calling the miner API setter +// continuously, we ensure the engine currently in use is always going to be reset to the proper throttling settings +// even in the event of sequencer failover. +func (l *BatchSubmitter) throttlingLoop(ctx context.Context) { + defer l.wg.Done() + l.Log.Info("Starting DA throttling loop") + ticker := time.NewTicker(l.Config.ThrottleInterval) + defer ticker.Stop() + + updateParams := func() { + ctx, cancel := context.WithTimeout(l.shutdownCtx, l.Config.NetworkTimeout) + defer cancel() + cl, err := l.EndpointProvider.EthClient(ctx) + if err != nil { + l.Log.Error("Can't reach sequencer execution RPC", "err", err) + return + } + pendingBytes := l.state.PendingDABytes() + maxTxSize := uint64(0) + maxBlockSize := l.Config.ThrottleAlwaysBlockSize + if pendingBytes > int64(l.Config.ThrottleThreshold) { + l.Log.Warn("Pending bytes over limit, throttling DA", "bytes", pendingBytes, "limit", l.Config.ThrottleThreshold) + maxTxSize = l.Config.ThrottleTxSize + if maxBlockSize == 0 || (l.Config.ThrottleBlockSize != 0 && l.Config.ThrottleBlockSize < maxBlockSize) { + maxBlockSize = l.Config.ThrottleBlockSize + } + } + var ( + success bool + rpcErr rpc.Error + ) + if err := cl.Client().CallContext( + ctx, &success, SetMaxDASizeMethod, hexutil.Uint64(maxTxSize), hexutil.Uint64(maxBlockSize), + ); errors.As(err, &rpcErr) && eth.ErrorCode(rpcErr.ErrorCode()).IsGenericRPCError() { + l.Log.Error("SetMaxDASize rpc unavailable or broken, shutting down. Either enable it or disable throttling.", "err", err) + // We'd probably hit this error right after startup, so a short shutdown duration should suffice. + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + // Always returns nil. An error is only returned to expose this function as an RPC. + _ = l.StopBatchSubmitting(ctx) + return + } else if err != nil { + l.Log.Error("SetMaxDASize rpc failed, retrying.", "err", err) + return + } + if !success { + l.Log.Error("Result of SetMaxDASize was false, retrying.") + } + } + + for { + select { + case <-l.l2BlockAdded: + updateParams() + case <-ticker.C: + updateParams() + case <-ctx.Done(): + l.Log.Info("DA throttling loop done") + return + } + } +} + +func (l *BatchSubmitter) waitNodeSyncAndClearState() { + // Wait for any in flight transactions + // to be ingested by the node before + // we start loading blocks again. + err := l.waitNodeSync() + if err != nil { + l.Log.Warn("error waiting for node sync", "err", err) + } + l.clearState(l.shutdownCtx) +} + // waitNodeSync Check to see if there was a batcher tx sent recently that // still needs more block confirmations before being considered finalized func (l *BatchSubmitter) waitNodeSync() error { @@ -528,9 +629,11 @@ func (l *BatchSubmitter) waitNodeSync() error { return dial.WaitRollupSync(l.shutdownCtx, l.Log, rollupClient, l1TargetBlock, time.Second*12) } -// publishStateToL1 queues up all pending TxData to be published to the L1, returning when there is -// no more data to queue for publishing or if there was an error queing the data. -func (l *BatchSubmitter) publishStateToL1(queue *txmgr.Queue[txRef], receiptsCh chan txmgr.TxReceipt[txRef], daGroup *errgroup.Group) { +// publishStateToL1 queues up all pending TxData to be published to the L1, returning when there is no more data to +// queue for publishing or if there was an error queing the data. maxDuration tells this function to return from state +// publishing after this amount of time has been exceeded even if there is more data remaining. +func (l *BatchSubmitter) publishStateToL1(queue *txmgr.Queue[txRef], receiptsCh chan txmgr.TxReceipt[txRef], daGroup *errgroup.Group, maxDuration time.Duration) { + start := time.Now() for { // if the txmgr is closed, we stop the transaction sending if l.Txmgr.IsClosed() { @@ -548,6 +651,10 @@ func (l *BatchSubmitter) publishStateToL1(queue *txmgr.Queue[txRef], receiptsCh } return } + if time.Since(start) > maxDuration { + l.Log.Warn("Aborting state publishing, max duration exceeded") + return + } } } diff --git a/op-batcher/batcher/driver_test.go b/op-batcher/batcher/driver_test.go index 5ce0983bfe1a7..f4e39e22cee2e 100644 --- a/op-batcher/batcher/driver_test.go +++ b/op-batcher/batcher/driver_test.go @@ -86,7 +86,6 @@ func TestBatchSubmitter_SafeL1Origin(t *testing.T) { t.Run(tt.name, func(t *testing.T) { if tt.failsToFetchSyncStatus { ep.rollupClient.ExpectSyncStatus(ð.SyncStatus{}, errors.New("failed to fetch sync status")) - } else { ep.rollupClient.ExpectSyncStatus(ð.SyncStatus{ SafeL2: eth.L2BlockRef{ @@ -107,7 +106,6 @@ func TestBatchSubmitter_SafeL1Origin(t *testing.T) { } }) } - } func TestBatchSubmitter_SafeL1Origin_FailsToResolveRollupClient(t *testing.T) { diff --git a/op-batcher/batcher/service.go b/op-batcher/batcher/service.go index 90a85cc4ee480..1b150642261f2 100644 --- a/op-batcher/batcher/service.go +++ b/op-batcher/batcher/service.go @@ -44,6 +44,11 @@ type BatcherConfig struct { WaitNodeSync bool CheckRecentTxsDepth int + + // For throttling DA. See CLIConfig in config.go for details on these parameters. + ThrottleThreshold, ThrottleTxSize uint64 + ThrottleBlockSize, ThrottleAlwaysBlockSize uint64 + ThrottleInterval time.Duration } // BatcherService represents a full batch-submitter instance and its resources, @@ -101,6 +106,13 @@ func (bs *BatcherService) initFromCLIConfig(ctx context.Context, version string, bs.NetworkTimeout = cfg.TxMgrConfig.NetworkTimeout bs.CheckRecentTxsDepth = cfg.CheckRecentTxsDepth bs.WaitNodeSync = cfg.WaitNodeSync + + bs.ThrottleThreshold = cfg.ThrottleThreshold + bs.ThrottleTxSize = cfg.ThrottleTxSize + bs.ThrottleBlockSize = cfg.ThrottleBlockSize + bs.ThrottleAlwaysBlockSize = cfg.ThrottleAlwaysBlockSize + bs.ThrottleInterval = cfg.ThrottleInterval + if err := bs.initRPCClients(ctx, cfg); err != nil { return err } @@ -457,3 +469,13 @@ func (bs *BatcherService) TestDriver() *TestBatchSubmitter { BatchSubmitter: bs.driver, } } + +// ThrottlingTestDriver returns a handler for the batch-submitter driver element that is in "always throttle" mode, for +// use only in testing. +func (bs *BatcherService) ThrottlingTestDriver() *TestBatchSubmitter { + tbs := &TestBatchSubmitter{ + BatchSubmitter: bs.driver, + } + tbs.BatchSubmitter.state.metr = new(metrics.ThrottlingMetrics) + return tbs +} diff --git a/op-batcher/flags/flags.go b/op-batcher/flags/flags.go index 3fe66f33981be..d5681ea872344 100644 --- a/op-batcher/flags/flags.go +++ b/op-batcher/flags/flags.go @@ -156,6 +156,36 @@ var ( Value: false, EnvVars: prefixEnvVars("WAIT_NODE_SYNC"), } + ThrottleIntervalFlag = &cli.DurationFlag{ + Name: "throttle-interval", + Usage: "Interval between potential DA throttling actions. Zero disables throttling.", + Value: 2 * time.Second, + EnvVars: prefixEnvVars("THROTTLE_INTERVAL"), + } + ThrottleThresholdFlag = &cli.IntFlag{ + Name: "throttle-threshold", + Usage: "The threshold on pending-blocks-bytes-current beyond which the batcher will instruct the block builder to start throttling transactions with larger DA demands", + Value: 1_000_000, + EnvVars: prefixEnvVars("THROTTLE_THRESHOLD"), + } + ThrottleTxSizeFlag = &cli.IntFlag{ + Name: "throttle-tx-size", + Usage: "The DA size of transactions to start throttling when we are over the throttle threshold", + Value: 300, // most transactions compress to under 300 bytes. TODO: compute exact distribution + EnvVars: prefixEnvVars("THROTTLE_TX_SIZE"), + } + ThrottleBlockSizeFlag = &cli.IntFlag{ + Name: "throttle-block-size", + Usage: "The total DA limit to start imposing on block building when we are over the throttle threshold", + Value: 21_000, // at least 70 transactions per block of up to 300 compressed bytes each. + EnvVars: prefixEnvVars("THROTTLE_BLOCK_SIZE"), + } + ThrottleAlwaysBlockSizeFlag = &cli.IntFlag{ + Name: "throttle-always-block-size", + Usage: "The total DA limit to start imposing on block building at all times", + Value: 130_000, // should be larger than the builder's max-l2-tx-size to prevent endlessly throttling some txs + EnvVars: prefixEnvVars("THROTTLE_ALWAYS_BLOCK_SIZE"), + } // Legacy Flags SequencerHDPathFlag = txmgr.SequencerHDPathFlag ) @@ -184,6 +214,11 @@ var optionalFlags = []cli.Flag{ DataAvailabilityTypeFlag, ActiveSequencerCheckDurationFlag, CompressionAlgoFlag, + ThrottleThresholdFlag, + ThrottleIntervalFlag, + ThrottleTxSizeFlag, + ThrottleBlockSizeFlag, + ThrottleAlwaysBlockSizeFlag, } func init() { diff --git a/op-batcher/metrics/metrics.go b/op-batcher/metrics/metrics.go index 417f927ee6f61..6443e489bd465 100644 --- a/op-batcher/metrics/metrics.go +++ b/op-batcher/metrics/metrics.go @@ -2,6 +2,7 @@ package metrics import ( "io" + "sync/atomic" "github.com/prometheus/client_golang/prometheus" @@ -49,6 +50,8 @@ type Metricer interface { RecordBlobUsedBytes(num int) Document() []opmetrics.DocumentedMetric + + PendingDABytes() float64 } type Metrics struct { @@ -69,7 +72,11 @@ type Metrics struct { pendingBlocksCount prometheus.GaugeVec pendingBlocksBytesTotal prometheus.Counter pendingBlocksBytesCurrent prometheus.Gauge - blocksAddedCount prometheus.Gauge + + pendingDABytes int64 + pendingDABytesGaugeFunc prometheus.GaugeFunc + + blocksAddedCount prometheus.Gauge channelInputBytes prometheus.GaugeVec channelReadyBytes prometheus.Gauge @@ -99,7 +106,7 @@ func NewMetrics(procName string) *Metrics { registry := opmetrics.NewRegistry() factory := opmetrics.With(registry) - return &Metrics{ + m := &Metrics{ ns: ns, registry: registry, factory: factory, @@ -143,7 +150,6 @@ func NewMetrics(procName string) *Metrics { Name: "blocks_added_count", Help: "Total number of blocks added to current channel.", }), - channelInputBytes: *factory.NewGaugeVec(prometheus.GaugeOpts{ Namespace: ns, Name: "input_bytes", @@ -194,6 +200,13 @@ func NewMetrics(procName string) *Metrics { batcherTxEvs: opmetrics.NewEventVec(factory, ns, "", "batcher_tx", "BatcherTx", []string{"stage"}), } + m.pendingDABytesGaugeFunc = factory.NewGaugeFunc(prometheus.GaugeOpts{ + Namespace: ns, + Name: "pending_da_bytes", + Help: "The estimated amount of data currently pending to be written to the DA layer (from blocks fetched from L2 but not yet in a channel).", + }, m.PendingDABytes) + + return m } func (m *Metrics) Registry() *prometheus.Registry { @@ -204,6 +217,12 @@ func (m *Metrics) Document() []opmetrics.DocumentedMetric { return m.factory.Document() } +// PendingDABytes returns the current number of bytes pending to be written to the DA layer (from blocks fetched from L2 +// but not yet in a channel). +func (m *Metrics) PendingDABytes() float64 { + return float64(atomic.LoadInt64(&m.pendingDABytes)) +} + func (m *Metrics) StartBalanceMetrics(l log.Logger, client *ethclient.Client, account common.Address) io.Closer { return opmetrics.LaunchBalanceMetrics(l, m.registry, m.ns, client, account) } @@ -278,14 +297,16 @@ func (m *Metrics) RecordChannelClosed(id derive.ChannelID, numPendingBlocks int, } func (m *Metrics) RecordL2BlockInPendingQueue(block *types.Block) { - size := float64(estimateBatchSize(block)) - m.pendingBlocksBytesTotal.Add(size) - m.pendingBlocksBytesCurrent.Add(size) + daSize, rawSize := estimateBatchSize(block) + m.pendingBlocksBytesTotal.Add(float64(rawSize)) + m.pendingBlocksBytesCurrent.Add(float64(rawSize)) + atomic.AddInt64(&m.pendingDABytes, int64(daSize)) } func (m *Metrics) RecordL2BlockInChannel(block *types.Block) { - size := float64(estimateBatchSize(block)) - m.pendingBlocksBytesCurrent.Add(-1 * size) + daSize, rawSize := estimateBatchSize(block) + m.pendingBlocksBytesCurrent.Add(-1.0 * float64(rawSize)) + atomic.AddInt64(&m.pendingDABytes, -1*int64(daSize)) // Refer to RecordL2BlocksAdded to see the current + count of bytes added to a channel } @@ -318,16 +339,22 @@ func (m *Metrics) RecordBlobUsedBytes(num int) { m.blobUsedBytes.Observe(float64(num)) } -// estimateBatchSize estimates the size of the batch -func estimateBatchSize(block *types.Block) uint64 { - size := uint64(70) // estimated overhead of batch metadata +// estimateBatchSize returns the estimated size of the block in a batch both with compression ('daSize') and without +// ('rawSize'). +func estimateBatchSize(block *types.Block) (daSize, rawSize uint64) { + daSize = uint64(70) // estimated overhead of batch metadata + rawSize = uint64(70) for _, tx := range block.Transactions() { - // Don't include deposit transactions in the batch. + // Deposit transactions are not included in batches if tx.IsDepositTx() { continue } + bigSize := tx.RollupCostData().EstimatedDASize() + if bigSize.IsUint64() { // this should always be true, but if not just ignore + daSize += bigSize.Uint64() + } // Add 2 for the overhead of encoding the tx bytes in a RLP list - size += tx.Size() + 2 + rawSize += tx.Size() + 2 } - return size + return } diff --git a/op-batcher/metrics/noop.go b/op-batcher/metrics/noop.go index 36594efe47c77..92711ee883d93 100644 --- a/op-batcher/metrics/noop.go +++ b/op-batcher/metrics/noop.go @@ -2,6 +2,7 @@ package metrics import ( "io" + "math" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -46,3 +47,16 @@ func (*noopMetrics) RecordBlobUsedBytes(int) {} func (*noopMetrics) StartBalanceMetrics(log.Logger, *ethclient.Client, common.Address) io.Closer { return nil } +func (nm *noopMetrics) PendingDABytes() float64 { + return 0.0 +} + +// ThrottlingMetrics is a noopMetrics that always returns a max value for PendingDABytes, to use in testing batcher +// backlog throttling. +type ThrottlingMetrics struct { + noopMetrics +} + +func (nm *ThrottlingMetrics) PendingDABytes() float64 { + return math.MaxFloat64 +} diff --git a/op-batcher/metrics/test.go b/op-batcher/metrics/test.go new file mode 100644 index 0000000000000..76c365ea7e2b0 --- /dev/null +++ b/op-batcher/metrics/test.go @@ -0,0 +1,22 @@ +package metrics + +import ( + "github.com/ethereum/go-ethereum/core/types" +) + +type TestMetrics struct { + noopMetrics + PendingBlocksBytesCurrent float64 +} + +var _ Metricer = new(TestMetrics) + +func (m *TestMetrics) RecordL2BlockInPendingQueue(block *types.Block) { + _, rawSize := estimateBatchSize(block) + m.PendingBlocksBytesCurrent += float64(rawSize) + +} +func (m *TestMetrics) RecordL2BlockInChannel(block *types.Block) { + _, rawSize := estimateBatchSize(block) + m.PendingBlocksBytesCurrent -= float64(rawSize) +} diff --git a/op-batcher/readme.md b/op-batcher/readme.md new file mode 100644 index 0000000000000..ba547845f0999 --- /dev/null +++ b/op-batcher/readme.md @@ -0,0 +1,88 @@ +# op-batcher + +The `op-batcher` is responsible for ensuring data availability. See the [specs](https://specs.optimism.io/protocol/batcher.html). + + +## Interactions & Dependencies +The `op-batcher` works together with the [sequencer](../op-node/) (which it reads unsafe blocks from), the data availability layer (e.g. Layer 1 or an [Alt DA](../op-alt-da/) layer, which it posts data to), and the [derivation pipeline](../op-node/) (which reads the data from the DA layer and progresses the safe chain). + +It depends directly on some code shared with the derivation pipeline, namely the [`ChannelOut`](../op-node/rollup/derive/channel_out.go) implementation(s). It also depends directly on the shared [txmgr](../op-service/txmgr/) module. + +## Testing +The batcher has a suite of unit test which can be triggered by running +``` +go test ./... +``` +from this directory. There are also end-to-end tests in [`op-e2e`](../op-e2e/) which integrate the batcher. + +## Architecture + +The architecture of this batcher implementation is shown on the left side of the following diagram: + +![architecture](./architecture.png) + +Batch submitting (writing to the DA layer, in the middle of the diagram) works together with the derivation pipeline (on the right side of the diagram, reading from the DA layer) to progress the safe chain. + +The philosophy behind the current architecture is: +* Blocks, channels and frames are kept around for as long as they might be needed, and discarded as soon as they are not needed. They are not moved from one part of state to another. +* We retain block data in a strict order for as long as necessary. We only garbage collect frames, channels and blocks when the safe head moves sufficiently and those structures have done their job. +* When something goes wrong, we rewind the state cursors by the minimal amount we need to get going again. + + +### Happy path + +In the happy path, the batcher periodically: +1. Enqueues unsafe blocks and dequeues safe blocks from the sequencer to its internal state. +2. Enqueues a new channel, if necessary. +3. Processes some unprocessed blocks into the current channel, triggers the compression of the block data and the creation of frames. +4. Sends frames from the channel queue to the DA layer as (e.g. to Ethereum L1 as calldata or blob transactions). +5. If there is more transaction data to send, go to 2. Else wait for a tick and go to 1. + + +The `blockCursor` state variable tracks the next unprocessed block. +In each channel, the `frameCursor` tracks the next unsent frame. + + +### Reorgs +When an L2 unsafe reorg is detected, the batch submitter will reset its state, and wait for any in flight transactions to be ingested by the verifier nodes before starting work again. + +### Tx Failed +When a Tx fails, an asynchronous receipts handler is triggered. The channel from whence the Tx's frames came has its `frameCursor` rewound, so that all the frames can be resubmitted in order. + +### Channel Times Out +When a Tx is confirmed, an asynchronous receipts handler is triggered. We only update the batcher's state if the channel timed out on chain. In that case, the `blockCursor` is rewound to the first block added to that channel, and the channel queue is cleared out. This allows the batcher to start fresh building a new channel starting from the same block -- it does not need to refetch blocks from the sequencer. + +## Design Principles and Optimization Targets +At the current time, the batcher should be optimized for correctness, simplicity and robustness. It is considered preferable to prioritize these properties, even at the expense of other potentially desirable properties such as frugality. For example, it is preferable to have the batcher resubmit some data from time to time ("wasting" money on data availability costs) instead of avoiding that by e.g. adding some persistent state to the batcher. + +The batcher can almost always recover from unforeseen situations by being restarted. + + +Some complexity is permitted, however, for handling data availability switching, so that the batcher is not wasting money for longer periods of time. + +### Data Availability Backlog + +A chain can potentially experience an influx of large transactions whose data availability requirements exceed the total +throughput of the data availability layer. While this situation might resolve on its own in the long term through the +data availability pricing mechanism, in practice this feedback loop is too slow to prevent a very large backlog of data +from being produced, even at a relatively low cost to whomever is submitting the large transactions. In such +circumstances, the safe head can fall significantly behind the unsafe head, and the time between seeing a transaction +(and charging it a given L1 data fee) and actually posting the transaction to the data availability layer grows larger +and larger. Because DA costs can rise quickly during such an event, the batcher can end up paying far more to post the +transaction to the DA layer than what can be recovered from the transaction's data fee. + +To prevent a significant DA backlog, the batcher can instruct the block builder (via op-geth's miner RPC API) to impose +thresholds on the total DA requirements of a single block, and/or the maximum DA requirement of any single +transaction. In the happy case, the batcher instructs the block builder to impose a block-level DA limit of +OP_BATCHER_THROTTLE_ALWAYS_BLOCK_SIZE, and imposes no additional limit on the DA requirements of a single +transaction. But in the case of a DA backlog (as defined by OP_BATCHER_THROTTLE_THRESHOLD), the batcher instructs the +block builder to instead impose a (tighter) block level limit of OP_BATCHER_THROTTLE_BLOCK_SIZE, and a single +transaction limit of OP_BATCHER_THROTTLE_TRANSACTION_SIZE. + +## Known issues and future work + +Link to [open issues with the `op-batcher` tag](https://github.com/ethereum-optimism/optimism/issues?q=is%3Aopen+is%3Aissue+label%3AA-op-batcher). + +The batcher launches L1 transactions in parallel so that it can achieve higher throughput, particularly in situations where there is a large backlog of data which needs to be posted. Sometimes, transactions can get stuck in the L1 mempool. The batcher does have functionality to clear these stuck transactions, but it is not completely reliable. + +The automatic data availability switching behavior is a somewhat new feature which may still have some bugs in it. diff --git a/op-bootnode/.gitignore b/op-bootnode/.gitignore deleted file mode 100644 index ba077a4031add..0000000000000 --- a/op-bootnode/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bin diff --git a/op-bootnode/Makefile b/op-bootnode/Makefile deleted file mode 100644 index f9f276e9ed113..0000000000000 --- a/op-bootnode/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -GITCOMMIT ?= $(shell git rev-parse HEAD) -GITDATE ?= $(shell git show -s --format='%ct') -VERSION ?= v0.0.0 - -LDFLAGSSTRING +=-X main.GitCommit=$(GITCOMMIT) -LDFLAGSSTRING +=-X main.GitDate=$(GITDATE) -LDFLAGSSTRING +=-X main.Version=$(VERSION) -LDFLAGS := -ldflags "$(LDFLAGSSTRING)" - -op-bootnode: - env GO111MODULE=on GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -v $(LDFLAGS) -o ./bin/op-bootnode ./cmd - -clean: - rm -f bin/op-bootnode - -test: - go test -v ./... - -.PHONY: \ - op-bootnode \ - clean \ - test diff --git a/op-bootnode/bootnode/entrypoint.go b/op-bootnode/bootnode/entrypoint.go deleted file mode 100644 index 0c33383c70c7b..0000000000000 --- a/op-bootnode/bootnode/entrypoint.go +++ /dev/null @@ -1,134 +0,0 @@ -package bootnode - -import ( - "context" - "errors" - "fmt" - - "github.com/libp2p/go-libp2p/core/peer" - "github.com/urfave/cli/v2" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/rpc" - - opnode "github.com/ethereum-optimism/optimism/op-node" - "github.com/ethereum-optimism/optimism/op-node/metrics" - "github.com/ethereum-optimism/optimism/op-node/p2p" - p2pcli "github.com/ethereum-optimism/optimism/op-node/p2p/cli" - "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-service/ctxinterrupt" - "github.com/ethereum-optimism/optimism/op-service/eth" - oplog "github.com/ethereum-optimism/optimism/op-service/log" - opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" - oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" -) - -type gossipNoop struct{} - -func (g *gossipNoop) OnUnsafeL2Payload(_ context.Context, _ peer.ID, _ *eth.ExecutionPayloadEnvelope) error { - return nil -} - -type gossipConfig struct{} - -func (g *gossipConfig) P2PSequencerAddress() common.Address { - return common.Address{} -} - -type l2Chain struct{} - -func (l *l2Chain) PayloadByNumber(_ context.Context, _ uint64) (*eth.ExecutionPayloadEnvelope, error) { - return nil, errors.New("P2P req/resp is not supported in bootnodes") -} - -func Main(cliCtx *cli.Context) error { - log.Info("Initializing bootnode") - logCfg := oplog.ReadCLIConfig(cliCtx) - logger := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg) - oplog.SetGlobalLogHandler(logger.Handler()) - m := metrics.NewMetrics("default") - ctx := context.Background() - - config, err := opnode.NewRollupConfigFromCLI(logger, cliCtx) - if err != nil { - return err - } - if err = validateConfig(config); err != nil { - return err - } - - p2pConfig, err := p2pcli.NewConfig(cliCtx, config) - if err != nil { - return fmt.Errorf("failed to load p2p config: %w", err) - } - if p2pConfig.EnableReqRespSync { - logger.Warn("req-resp sync is enabled, bootnode does not support this feature") - p2pConfig.EnableReqRespSync = false - } - - p2pNode, err := p2p.NewNodeP2P(ctx, config, logger, p2pConfig, &gossipNoop{}, &l2Chain{}, &gossipConfig{}, m, false) - if err != nil || p2pNode == nil { - return err - } - if p2pNode.Dv5Udp() == nil { - return fmt.Errorf("uninitialized discovery service") - } - - rpcCfg := oprpc.ReadCLIConfig(cliCtx) - if err := rpcCfg.Check(); err != nil { - return fmt.Errorf("failed to validate RPC config") - } - rpcServer := oprpc.NewServer(rpcCfg.ListenAddr, rpcCfg.ListenPort, "", oprpc.WithLogger(logger)) - if rpcCfg.EnableAdmin { - logger.Info("Admin RPC enabled but does nothing for the bootnode") - } - rpcServer.AddAPI(rpc.API{ - Namespace: p2p.NamespaceRPC, - Version: "", - Service: p2p.NewP2PAPIBackend(p2pNode, logger, m), - Authenticated: false, - }) - if err := rpcServer.Start(); err != nil { - return fmt.Errorf("failed to start the RPC server") - } - defer func() { - if err := rpcServer.Stop(); err != nil { - log.Error("failed to stop RPC server", "err", err) - } - }() - - go p2pNode.DiscoveryProcess(ctx, logger, config, p2pConfig.TargetPeers()) - - metricsCfg := opmetrics.ReadCLIConfig(cliCtx) - if metricsCfg.Enabled { - log.Debug("starting metrics server", "addr", metricsCfg.ListenAddr, "port", metricsCfg.ListenPort) - metricsSrv, err := m.StartServer(metricsCfg.ListenAddr, metricsCfg.ListenPort) - if err != nil { - return fmt.Errorf("failed to start metrics server: %w", err) - } - defer func() { - if err := metricsSrv.Stop(context.Background()); err != nil { - log.Error("failed to stop metrics server", "err", err) - } - }() - log.Info("started metrics server", "addr", metricsSrv.Addr()) - m.RecordUp() - } - - return ctxinterrupt.Wait(ctx) -} - -// validateConfig ensures the minimal config required to run a bootnode -func validateConfig(config *rollup.Config) error { - if config.L2ChainID == nil || config.L2ChainID.Uint64() == 0 { - return errors.New("chain ID is not set") - } - if config.Genesis.L2Time <= 0 { - return errors.New("genesis timestamp is not set") - } - if config.BlockTime <= 0 { - return errors.New("block time is not set") - } - return nil -} diff --git a/op-bootnode/cmd/main.go b/op-bootnode/cmd/main.go deleted file mode 100644 index 1dbc82010cfc1..0000000000000 --- a/op-bootnode/cmd/main.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "os" - - "github.com/ethereum/go-ethereum/log" - "github.com/urfave/cli/v2" - - "github.com/ethereum-optimism/optimism/op-bootnode/bootnode" - "github.com/ethereum-optimism/optimism/op-bootnode/flags" - oplog "github.com/ethereum-optimism/optimism/op-service/log" -) - -func main() { - oplog.SetupDefaults() - - app := cli.NewApp() - app.Flags = flags.Flags - app.Name = "bootnode" - app.Usage = "Rollup Bootnode" - app.Description = "Broadcasts incoming P2P peers to each other, enabling peer bootstrapping." - app.Action = bootnode.Main - - err := app.Run(os.Args) - if err != nil { - log.Crit("Application failed", "message", err) - } -} diff --git a/op-bootnode/flags/flags.go b/op-bootnode/flags/flags.go deleted file mode 100644 index 5fbe0d538b33c..0000000000000 --- a/op-bootnode/flags/flags.go +++ /dev/null @@ -1,25 +0,0 @@ -package flags - -import ( - "github.com/urfave/cli/v2" - - "github.com/ethereum-optimism/optimism/op-node/flags" - opflags "github.com/ethereum-optimism/optimism/op-service/flags" - oplog "github.com/ethereum-optimism/optimism/op-service/log" - opmetrics "github.com/ethereum-optimism/optimism/op-service/metrics" - oprpc "github.com/ethereum-optimism/optimism/op-service/rpc" -) - -const envVarPrefix = "OP_BOOTNODE" - -var Flags = []cli.Flag{ - opflags.CLINetworkFlag(envVarPrefix, ""), - opflags.CLIRollupConfigFlag(envVarPrefix, ""), -} - -func init() { - Flags = append(Flags, flags.P2PFlags(envVarPrefix)...) - Flags = append(Flags, opmetrics.CLIFlags(envVarPrefix)...) - Flags = append(Flags, oplog.CLIFlags(envVarPrefix)...) - Flags = append(Flags, oprpc.CLIFlags(envVarPrefix)...) -} diff --git a/op-chain-ops/Makefile b/op-chain-ops/Makefile index 6c4b576528554..ad595b65e367f 100644 --- a/op-chain-ops/Makefile +++ b/op-chain-ops/Makefile @@ -36,17 +36,19 @@ test: go test ./... op-deployer: - GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) CGO_ENABLED=0 go build -v $(LDFLAGS) -o ./bin/op-deployer ./cmd/op-deployer/main.go + GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) CGO_ENABLED=0 go build -v $(LDFLAGS) -o ./bin/op-deployer ../op-deployer/cmd/op-deployer/main.go fuzz: - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzEncodeDecodeWithdrawal ./crossdomain - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzEncodeDecodeLegacyWithdrawal ./crossdomain - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzAliasing ./crossdomain - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzVersionedNonce ./crossdomain + printf "%s\n" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzEncodeDecodeWithdrawal ./crossdomain" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzEncodeDecodeLegacyWithdrawal ./crossdomain" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzAliasing ./crossdomain" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzVersionedNonce ./crossdomain" \ + | parallel -j 8 {} sync-standard-version: curl -Lo ./deployer/opcm/standard-versions-mainnet.toml https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/refs/heads/main/validation/standard/standard-versions-mainnet.toml curl -Lo ./deployer/opcm/standard-versions-sepolia.toml https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/refs/heads/main/validation/standard/standard-versions-sepolia.toml -.PHONY: test fuzz op-deployer sync-standard-version \ No newline at end of file +.PHONY: test fuzz op-deployer sync-standard-version diff --git a/op-chain-ops/cmd/deposit-hash/main.go b/op-chain-ops/cmd/deposit-hash/main.go new file mode 100644 index 0000000000000..9166a0667c090 --- /dev/null +++ b/op-chain-ops/cmd/deposit-hash/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "context" + "flag" + "fmt" + + "github.com/ethereum-optimism/optimism/op-node/rollup/derive" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" +) + +func main() { + var rpcURL, txHash string + flag.StringVar(&rpcURL, "rpc", "", "L1 RPC URL") + flag.StringVar(&txHash, "tx", "", "Deposit transaction hash on L1") + flag.Parse() + + depositLogTopic := common.HexToHash("0xb3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c32") + + ethClient, err := ethclient.Dial(rpcURL) + if err != nil { + log.Crit("Error creating RPC", "err", err) + } + + l1Receipt, err := ethClient.TransactionReceipt(context.TODO(), common.HexToHash(txHash)) + if err != nil { + log.Crit("Error fetching transaction", "err", err) + } + + for _, ethLog := range l1Receipt.Logs { + if ethLog.Topics[0].String() == depositLogTopic.String() { + + reconstructedDep, err := derive.UnmarshalDepositLogEvent(ethLog) + if err != nil { + log.Crit("Failed to parse deposit event ", "err", err) + } + tx := types.NewTx(reconstructedDep) + fmt.Println("L2 Tx Hash", tx.Hash().String()) + } + } +} diff --git a/op-chain-ops/devkeys/devkeys.go b/op-chain-ops/devkeys/devkeys.go index d0526c8c1d3a4..fdb151e4e6fcf 100644 --- a/op-chain-ops/devkeys/devkeys.go +++ b/op-chain-ops/devkeys/devkeys.go @@ -93,6 +93,21 @@ func (role SuperchainOperatorRole) Key(chainID *big.Int) Key { } } +func (role *SuperchainOperatorRole) UnmarshalText(data []byte) error { + v := string(data) + for i := SuperchainOperatorRole(0); i < 20; i++ { + if i.String() == v { + *role = i + return nil + } + } + return fmt.Errorf("unknown superchain operator role %q", v) +} + +func (role *SuperchainOperatorRole) MarshalText() ([]byte, error) { + return []byte(role.String()), nil +} + // SuperchainOperatorKey is an account specific to an OperationRole of a given OP-Stack chain. type SuperchainOperatorKey struct { ChainID *big.Int @@ -181,6 +196,21 @@ func (role ChainOperatorRole) Key(chainID *big.Int) Key { } } +func (role *ChainOperatorRole) UnmarshalText(data []byte) error { + v := string(data) + for i := ChainOperatorRole(0); i < 20; i++ { + if i.String() == v { + *role = i + return nil + } + } + return fmt.Errorf("unknown chain operator role %q", v) +} + +func (role *ChainOperatorRole) MarshalText() ([]byte, error) { + return []byte(role.String()), nil +} + // ChainOperatorKey is an account specific to an OperationRole of a given OP-Stack chain. type ChainOperatorKey struct { ChainID *big.Int diff --git a/op-chain-ops/genesis/config.go b/op-chain-ops/genesis/config.go index e2b1f6077cb52..bfda8ac016bb6 100644 --- a/op-chain-ops/genesis/config.go +++ b/op-chain-ops/genesis/config.go @@ -373,6 +373,81 @@ func offsetToUpgradeTime(offset *hexutil.Uint64, genesisTime uint64) *uint64 { return &v } +func (d *UpgradeScheduleDeployConfig) ForkTimeOffset(fork rollup.ForkName) *uint64 { + switch fork { + case rollup.Regolith: + return (*uint64)(d.L2GenesisRegolithTimeOffset) + case rollup.Canyon: + return (*uint64)(d.L2GenesisCanyonTimeOffset) + case rollup.Delta: + return (*uint64)(d.L2GenesisDeltaTimeOffset) + case rollup.Ecotone: + return (*uint64)(d.L2GenesisEcotoneTimeOffset) + case rollup.Fjord: + return (*uint64)(d.L2GenesisFjordTimeOffset) + case rollup.Granite: + return (*uint64)(d.L2GenesisGraniteTimeOffset) + case rollup.Holocene: + return (*uint64)(d.L2GenesisHoloceneTimeOffset) + case rollup.Interop: + return (*uint64)(d.L2GenesisInteropTimeOffset) + default: + panic(fmt.Sprintf("unknown fork: %s", fork)) + } +} + +func (d *UpgradeScheduleDeployConfig) SetForkTimeOffset(fork rollup.ForkName, offset *uint64) { + switch fork { + case rollup.Regolith: + d.L2GenesisRegolithTimeOffset = (*hexutil.Uint64)(offset) + case rollup.Canyon: + d.L2GenesisCanyonTimeOffset = (*hexutil.Uint64)(offset) + case rollup.Delta: + d.L2GenesisDeltaTimeOffset = (*hexutil.Uint64)(offset) + case rollup.Ecotone: + d.L2GenesisEcotoneTimeOffset = (*hexutil.Uint64)(offset) + case rollup.Fjord: + d.L2GenesisFjordTimeOffset = (*hexutil.Uint64)(offset) + case rollup.Granite: + d.L2GenesisGraniteTimeOffset = (*hexutil.Uint64)(offset) + case rollup.Holocene: + d.L2GenesisHoloceneTimeOffset = (*hexutil.Uint64)(offset) + case rollup.Interop: + d.L2GenesisInteropTimeOffset = (*hexutil.Uint64)(offset) + default: + panic(fmt.Sprintf("unknown fork: %s", fork)) + } +} + +var scheduleableForks = rollup.ForksFrom(rollup.Regolith) + +// ActivateForkAtOffset activates the given fork at the given offset. Previous forks are activated +// at genesis and later forks are deactivated. +// If multiple forks should be activated at a later time than genesis, first call +// ActivateForkAtOffset with the earliest fork and then SetForkTimeOffset to individually set later +// forks. +func (d *UpgradeScheduleDeployConfig) ActivateForkAtOffset(fork rollup.ForkName, offset uint64) { + if !rollup.IsValidFork(fork) || fork == rollup.Bedrock { + panic(fmt.Sprintf("invalid fork: %s", fork)) + } + ts := new(uint64) + for i, f := range scheduleableForks { + if f == fork { + d.SetForkTimeOffset(fork, &offset) + ts = nil + } else { + d.SetForkTimeOffset(scheduleableForks[i], ts) + } + } +} + +// ActivateForkAtGenesis activates the given fork, and all previous forks, at genesis. +// Later forks are deactivated. +// See also [ActivateForkAtOffset]. +func (d *UpgradeScheduleDeployConfig) ActivateForkAtGenesis(fork rollup.ForkName) { + d.ActivateForkAtOffset(fork, 0) +} + func (d *UpgradeScheduleDeployConfig) RegolithTime(genesisTime uint64) *uint64 { return offsetToUpgradeTime(d.L2GenesisRegolithTimeOffset, genesisTime) } @@ -417,7 +492,6 @@ func (d *UpgradeScheduleDeployConfig) L2BlobTime(genesisTime uint64) *uint64 { } func (d *UpgradeScheduleDeployConfig) AllocMode(genesisTime uint64) L2AllocsMode { - forks := d.forks() for i := len(forks) - 1; i >= 0; i-- { if forkTime := offsetToUpgradeTime(forks[i].L2GenesisTimeOffset, genesisTime); forkTime != nil && *forkTime == 0 { @@ -538,18 +612,18 @@ func (d *L2CoreDeployConfig) Check(log log.Logger) error { // AltDADeployConfig configures optional AltDA functionality. type AltDADeployConfig struct { // UseAltDA is a flag that indicates if the system is using op-alt-da - UseAltDA bool `json:"useAltDA"` + UseAltDA bool `json:"useAltDA" toml:"useAltDA"` // DACommitmentType specifies the allowed commitment - DACommitmentType string `json:"daCommitmentType"` + DACommitmentType string `json:"daCommitmentType" toml:"daCommitmentType"` // DAChallengeWindow represents the block interval during which the availability of a data commitment can be challenged. - DAChallengeWindow uint64 `json:"daChallengeWindow"` + DAChallengeWindow uint64 `json:"daChallengeWindow" toml:"daChallengeWindow"` // DAResolveWindow represents the block interval during which a data availability challenge can be resolved. - DAResolveWindow uint64 `json:"daResolveWindow"` + DAResolveWindow uint64 `json:"daResolveWindow" toml:"daResolveWindow"` // DABondSize represents the required bond size to initiate a data availability challenge. - DABondSize uint64 `json:"daBondSize"` + DABondSize uint64 `json:"daBondSize" toml:"daBondSize"` // DAResolverRefundPercentage represents the percentage of the resolving cost to be refunded to the resolver // such as 100 means 100% refund. - DAResolverRefundPercentage uint64 `json:"daResolverRefundPercentage"` + DAResolverRefundPercentage uint64 `json:"daResolverRefundPercentage" toml:"daResolverRefundPercentage"` } var _ ConfigChecker = (*AltDADeployConfig)(nil) diff --git a/op-chain-ops/genesis/config_test.go b/op-chain-ops/genesis/config_test.go index d272d7afd2e53..47ffc46508220 100644 --- a/op-chain-ops/genesis/config_test.go +++ b/op-chain-ops/genesis/config_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/require" + "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/testlog" ) @@ -45,7 +46,10 @@ func TestRegolithTimeZero(t *testing.T) { config := &DeployConfig{ L2InitializationConfig: L2InitializationConfig{ UpgradeScheduleDeployConfig: UpgradeScheduleDeployConfig{ - L2GenesisRegolithTimeOffset: ®olithOffset}}} + L2GenesisRegolithTimeOffset: ®olithOffset, + }, + }, + } require.Equal(t, uint64(0), *config.RegolithTime(1234)) } @@ -54,7 +58,10 @@ func TestRegolithTimeAsOffset(t *testing.T) { config := &DeployConfig{ L2InitializationConfig: L2InitializationConfig{ UpgradeScheduleDeployConfig: UpgradeScheduleDeployConfig{ - L2GenesisRegolithTimeOffset: ®olithOffset}}} + L2GenesisRegolithTimeOffset: ®olithOffset, + }, + }, + } require.Equal(t, uint64(1500+5000), *config.RegolithTime(5000)) } @@ -63,7 +70,10 @@ func TestCanyonTimeZero(t *testing.T) { config := &DeployConfig{ L2InitializationConfig: L2InitializationConfig{ UpgradeScheduleDeployConfig: UpgradeScheduleDeployConfig{ - L2GenesisCanyonTimeOffset: &canyonOffset}}} + L2GenesisCanyonTimeOffset: &canyonOffset, + }, + }, + } require.Equal(t, uint64(0), *config.CanyonTime(1234)) } @@ -72,7 +82,10 @@ func TestCanyonTimeOffset(t *testing.T) { config := &DeployConfig{ L2InitializationConfig: L2InitializationConfig{ UpgradeScheduleDeployConfig: UpgradeScheduleDeployConfig{ - L2GenesisCanyonTimeOffset: &canyonOffset}}} + L2GenesisCanyonTimeOffset: &canyonOffset, + }, + }, + } require.Equal(t, uint64(1234+1500), *config.CanyonTime(1234)) } @@ -124,3 +137,41 @@ func TestL1Deployments(t *testing.T) { // One that doesn't exist returns empty string require.Equal(t, "", deployments.GetName(common.Address{19: 0xff})) } + +// This test guarantees that getters and setters for all forks are present. +func TestUpgradeScheduleDeployConfig_ForkGettersAndSetters(t *testing.T) { + var d UpgradeScheduleDeployConfig + for i, fork := range rollup.ForksFrom(rollup.Regolith) { + require.Nil(t, d.ForkTimeOffset(fork)) + offset := uint64(i * 42) + d.SetForkTimeOffset(fork, &offset) + require.Equal(t, offset, *d.ForkTimeOffset(fork)) + } +} + +func TestUpgradeScheduleDeployConfig_ActivateForkAtOffset(t *testing.T) { + var d UpgradeScheduleDeployConfig + ts := uint64(42) + t.Run("invalid", func(t *testing.T) { + require.Panics(t, func() { d.ActivateForkAtOffset(rollup.Bedrock, ts) }) + }) + + t.Run("regolith", func(t *testing.T) { + d.ActivateForkAtOffset(rollup.Regolith, ts) + require.EqualValues(t, &ts, d.L2GenesisRegolithTimeOffset) + for _, fork := range scheduleableForks[1:] { + require.Nil(t, d.ForkTimeOffset(fork)) + } + }) + + t.Run("ecotone", func(t *testing.T) { + d.ActivateForkAtOffset(rollup.Ecotone, ts) + require.EqualValues(t, &ts, d.L2GenesisEcotoneTimeOffset) + for _, fork := range scheduleableForks[:3] { + require.Zero(t, *d.ForkTimeOffset(fork)) + } + for _, fork := range scheduleableForks[4:] { + require.Nil(t, d.ForkTimeOffset(fork)) + } + }) +} diff --git a/op-chain-ops/interopgen/configs.go b/op-chain-ops/interopgen/configs.go index 942588a9929cc..948d9daa30533 100644 --- a/op-chain-ops/interopgen/configs.go +++ b/op-chain-ops/interopgen/configs.go @@ -35,7 +35,7 @@ type SuperFaultProofConfig struct { } type OPCMImplementationsConfig struct { - Release string + L1ContractsRelease string FaultProof SuperFaultProofConfig diff --git a/op-chain-ops/interopgen/deploy.go b/op-chain-ops/interopgen/deploy.go index 83c241fdc0139..e915b724e10b6 100644 --- a/op-chain-ops/interopgen/deploy.go +++ b/op-chain-ops/interopgen/deploy.go @@ -5,6 +5,8 @@ import ( "fmt" "math/big" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" "github.com/ethereum/go-ethereum/common" @@ -168,12 +170,11 @@ func DeploySuperchainToL1(l1Host *script.Host, superCfg *SuperchainConfig) (*Sup ProofMaturityDelaySeconds: superCfg.Implementations.FaultProof.ProofMaturityDelaySeconds, DisputeGameFinalityDelaySeconds: superCfg.Implementations.FaultProof.DisputeGameFinalityDelaySeconds, MipsVersion: superCfg.Implementations.FaultProof.MipsVersion, - Release: superCfg.Implementations.Release, + L1ContractsRelease: superCfg.Implementations.L1ContractsRelease, SuperchainConfigProxy: superDeployment.SuperchainConfigProxy, ProtocolVersionsProxy: superDeployment.ProtocolVersionsProxy, - OpcmProxyOwner: superDeployment.SuperchainProxyAdmin, UseInterop: superCfg.Implementations.UseInterop, - StandardVersionsToml: opcm.StandardVersionsMainnetData, + StandardVersionsToml: standard.VersionsMainnetData, }) if err != nil { return nil, fmt.Errorf("failed to deploy Implementations contracts: %w", err) @@ -198,7 +199,7 @@ func DeployL2ToL1(l1Host *script.Host, superCfg *SuperchainConfig, superDeployme l1Host.SetTxOrigin(cfg.Deployer) - output, err := opcm.DeployOPChain(l1Host, opcm.DeployOPChainInput{ + output, err := opcm.DeployOPChainV160(l1Host, opcm.DeployOPChainInputV160{ OpChainProxyAdminOwner: cfg.ProxyAdminOwner, SystemConfigOwner: cfg.SystemConfigOwner, Batcher: cfg.BatchSenderAddress, @@ -208,7 +209,7 @@ func DeployL2ToL1(l1Host *script.Host, superCfg *SuperchainConfig, superDeployme BasefeeScalar: cfg.GasPriceOracleBaseFeeScalar, BlobBaseFeeScalar: cfg.GasPriceOracleBlobBaseFeeScalar, L2ChainId: new(big.Int).SetUint64(cfg.L2ChainID), - OpcmProxy: superDeployment.OpcmProxy, + Opcm: superDeployment.Opcm, SaltMixer: cfg.SaltMixer, GasLimit: cfg.GasLimit, DisputeGameType: cfg.DisputeGameType, diff --git a/op-chain-ops/interopgen/deployments.go b/op-chain-ops/interopgen/deployments.go index ba18fbfdf9bde..f98a0554d8709 100644 --- a/op-chain-ops/interopgen/deployments.go +++ b/op-chain-ops/interopgen/deployments.go @@ -9,8 +9,7 @@ type L1Deployment struct { } type Implementations struct { - OpcmProxy common.Address `json:"OPCMProxy"` - OpcmImpl common.Address `json:"OPCMImpl"` + Opcm common.Address `json:"OPCM"` DelayedWETHImpl common.Address `json:"DelayedWETHImpl"` OptimismPortalImpl common.Address `json:"OptimismPortalImpl"` PreimageOracleSingleton common.Address `json:"PreimageOracleSingleton"` diff --git a/op-chain-ops/interopgen/recipe.go b/op-chain-ops/interopgen/recipe.go index fb76709be6639..e70c69e9f481a 100644 --- a/op-chain-ops/interopgen/recipe.go +++ b/op-chain-ops/interopgen/recipe.go @@ -4,7 +4,7 @@ import ( "fmt" "math/big" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -69,7 +69,7 @@ func (r *InteropDevRecipe) Build(addrs devkeys.Addresses) (*WorldConfig, error) ProtocolVersionsOwner: superchainProtocolVersionsOwner, Deployer: superchainDeployer, Implementations: OPCMImplementationsConfig{ - Release: "dev", + L1ContractsRelease: "dev", FaultProof: SuperFaultProofConfig{ WithdrawalDelaySeconds: big.NewInt(604800), MinProposalSizeBytes: big.NewInt(10000), @@ -79,7 +79,7 @@ func (r *InteropDevRecipe) Build(addrs devkeys.Addresses) (*WorldConfig, error) MipsVersion: big.NewInt(1), }, UseInterop: true, - StandardVersionsToml: opcm.StandardVersionsMainnetData, + StandardVersionsToml: standard.VersionsMainnetData, }, SuperchainL1DeployConfig: genesis.SuperchainL1DeployConfig{ RequiredProtocolVersion: params.OPStackSupport, @@ -109,6 +109,7 @@ func prefundL2Accounts(l1Cfg *L1Config, l2Cfg *L2Config, addrs devkeys.Addresses l1Cfg.Prefund[l2Cfg.BatchSenderAddress] = Ether(10_000_000) l1Cfg.Prefund[l2Cfg.Deployer] = Ether(10_000_000) l1Cfg.Prefund[l2Cfg.FinalSystemOwner] = Ether(10_000_000) + l1Cfg.Prefund[l2Cfg.SystemConfigOwner] = Ether(10_000_000) proposer, err := addrs.Address(devkeys.ChainOperatorKey{ ChainID: new(big.Int).SetUint64(l2Cfg.L2ChainID), Role: devkeys.ProposerRole, diff --git a/op-chain-ops/script/addresses/addresses.go b/op-chain-ops/script/addresses/addresses.go new file mode 100644 index 0000000000000..76895e203e376 --- /dev/null +++ b/op-chain-ops/script/addresses/addresses.go @@ -0,0 +1,20 @@ +package addresses + +import "github.com/ethereum/go-ethereum/common" + +var ( + // DefaultSenderAddr is known as DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller")))) + DefaultSenderAddr = common.HexToAddress("0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38") + // DefaultScriptAddr is the address of the initial executing script, computed from: + // cast compute-address --nonce 1 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38 + DefaultScriptAddr = common.HexToAddress("0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496") + // VMAddr is known as VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); + VMAddr = common.HexToAddress("0x7109709ECfa91a80626fF3989D68f67F5b1DD12D") + // ConsoleAddr is known as CONSOLE, "console.log" in ascii. + // Utils like console.sol and console2.sol work by executing a staticcall to this address. + ConsoleAddr = common.HexToAddress("0x000000000000000000636F6e736F6c652e6c6f67") + // ScriptDeployer is used for temporary scripts address(uint160(uint256(keccak256("op-stack script deployer")))) + ScriptDeployer = common.HexToAddress("0x76Ce131128F3616871f8CDA86d18fAB44E4d0D8B") + // ForgeDeployer is used by some scripts as a default deployer address, e.g. makeAddr("deployer") + ForgeDeployer = common.HexToAddress("0xaE0bDc4eEAC5E950B67C6819B118761CaAF61946") +) diff --git a/op-chain-ops/script/cheatcodes.go b/op-chain-ops/script/cheatcodes.go index 07755e527314b..46e2bc4e314c4 100644 --- a/op-chain-ops/script/cheatcodes.go +++ b/op-chain-ops/script/cheatcodes.go @@ -1,8 +1,45 @@ package script +import ( + "fmt" + + "github.com/ethereum/go-ethereum/core/vm" +) + // CheatCodesPrecompile implements the Forge vm cheatcodes. // Note that forge-std wraps these cheatcodes, // and provides additional convenience functions that use these cheatcodes. type CheatCodesPrecompile struct { h *Host } + +// AccessControlledPrecompile wraps a precompile, +// and checks that the caller has cheatcode access. +type AccessControlledPrecompile struct { + h *Host + inner vm.PrecompiledContract +} + +var _ vm.PrecompiledContract = (*AccessControlledPrecompile)(nil) + +func (c *AccessControlledPrecompile) RequiredGas(input []byte) uint64 { + // call-frame is not open yet, and prank is ignored for cheatcode access-checking. + accessor := c.h.SelfAddress() + _, ok := c.h.allowedCheatcodes[accessor] + if !ok { + // Don't just return infinite gas, we can allow it to run, + // and then revert with a proper error message. + return 0 + } + return c.inner.RequiredGas(input) +} + +func (c *AccessControlledPrecompile) Run(input []byte) ([]byte, error) { + // call-frame is not open yet, and prank is ignored for cheatcode access-checking. + accessor := c.h.SelfAddress() + if !c.h.AllowedCheatcodes(accessor) { + c.h.log.Error("Cheatcode access denied!", "caller", accessor, "label", c.h.labels[accessor]) + return encodeRevert(fmt.Errorf("call by %s to cheatcode precompile is not allowed", accessor)) + } + return c.inner.Run(input) +} diff --git a/op-chain-ops/script/cheatcodes_environment.go b/op-chain-ops/script/cheatcodes_environment.go index 92baa429010eb..55584c835db05 100644 --- a/op-chain-ops/script/cheatcodes_environment.go +++ b/op-chain-ops/script/cheatcodes_environment.go @@ -67,6 +67,10 @@ func (c *CheatCodesPrecompile) Load(account common.Address, slot [32]byte) [32]b // Etch implements https://book.getfoundry.sh/cheatcodes/etch func (c *CheatCodesPrecompile) Etch(who common.Address, code []byte) { c.h.state.SetCode(who, bytes.Clone(code)) // important to clone; geth EVM will reuse the calldata memory. + if len(code) > 0 { + // if we're not just zeroing out the account: allow it to access cheatcodes + c.h.AllowCheatcodes(who) + } } // Deal implements https://book.getfoundry.sh/cheatcodes/deal diff --git a/op-chain-ops/script/cheatcodes_forking.go b/op-chain-ops/script/cheatcodes_forking.go new file mode 100644 index 0000000000000..44ba66f8a9582 --- /dev/null +++ b/op-chain-ops/script/cheatcodes_forking.go @@ -0,0 +1,161 @@ +package script + +import ( + "errors" + "fmt" + "math/big" + + "github.com/holiman/uint256" + + "github.com/ethereum/go-ethereum/common" + + "github.com/ethereum-optimism/optimism/op-chain-ops/script/forking" +) + +func (c *CheatCodesPrecompile) CreateFork_31ba3498(urlOrAlias string) (*big.Int, error) { + return c.createFork(ForkWithURLOrAlias(urlOrAlias)) +} + +func (c *CheatCodesPrecompile) CreateFork_6ba3ba2b(urlOrAlias string, block *big.Int) (*big.Int, error) { + return c.createFork(ForkWithURLOrAlias(urlOrAlias), ForkWithBlockNumberU256(block)) +} + +func (c *CheatCodesPrecompile) CreateFork_7ca29682(urlOrAlias string, txHash common.Hash) (*big.Int, error) { + return c.createFork(ForkWithURLOrAlias(urlOrAlias), ForkWithTransaction(txHash)) +} + +// createFork implements vm.createFork: +// https://book.getfoundry.sh/cheatcodes/create-fork +func (c *CheatCodesPrecompile) createFork(opts ...ForkOption) (*big.Int, error) { + src, err := c.h.onFork(opts...) + if err != nil { + return nil, fmt.Errorf("failed to setup fork source: %w", err) + } + id, err := c.h.state.CreateFork(src) + if err != nil { + return nil, fmt.Errorf("failed to create fork: %w", err) + } + return id.U256().ToBig(), nil +} + +func (c *CheatCodesPrecompile) CreateSelectFork_98680034(urlOrAlias string) (*big.Int, error) { + return c.createSelectFork(ForkWithURLOrAlias(urlOrAlias)) +} + +func (c *CheatCodesPrecompile) CreateSelectFork_71ee464d(urlOrAlias string, block *big.Int) (*big.Int, error) { + return c.createSelectFork(ForkWithURLOrAlias(urlOrAlias), ForkWithBlockNumberU256(block)) +} + +func (c *CheatCodesPrecompile) CreateSelectFork_84d52b7a(urlOrAlias string, txHash common.Hash) (*big.Int, error) { + return c.createSelectFork(ForkWithURLOrAlias(urlOrAlias), ForkWithTransaction(txHash)) +} + +// createSelectFork implements vm.createSelectFork: +// https://book.getfoundry.sh/cheatcodes/create-select-fork +func (c *CheatCodesPrecompile) createSelectFork(opts ...ForkOption) (*big.Int, error) { + return c.h.CreateSelectFork(opts...) +} + +// ActiveFork implements vm.activeFork: +// https://book.getfoundry.sh/cheatcodes/active-fork +func (c *CheatCodesPrecompile) ActiveFork() (*uint256.Int, error) { + id, active := c.h.state.ActiveFork() + if !active { + return nil, errors.New("no active fork") + } + return id.U256(), nil +} + +// convenience method, to repeat the same URLOrAlias as the given fork when setting up a new fork +func (c *CheatCodesPrecompile) forkURLOption(id forking.ForkID) ForkOption { + return func(cfg *ForkConfig) error { + urlOrAlias, err := c.h.state.ForkURLOrAlias(id) + if err != nil { + return err + } + return ForkWithURLOrAlias(urlOrAlias)(cfg) + } +} + +func (c *CheatCodesPrecompile) RollFork_d9bbf3a1(block *big.Int) error { + id, ok := c.h.state.ActiveFork() + if !ok { + return errors.New("no active fork") + } + return c.rollFork(id, c.forkURLOption(id), ForkWithBlockNumberU256(block)) +} + +func (c *CheatCodesPrecompile) RollFork_0f29772b(txHash common.Hash) error { + id, ok := c.h.state.ActiveFork() + if !ok { + return errors.New("no active fork") + } + return c.rollFork(id, c.forkURLOption(id), ForkWithTransaction(txHash)) +} + +func (c *CheatCodesPrecompile) RollFork_d74c83a4(forkID *big.Int, block *big.Int) error { + id := forking.ForkIDFromBig(forkID) + return c.rollFork(id, c.forkURLOption(id), ForkWithBlockNumberU256(block)) +} + +func (c *CheatCodesPrecompile) RollFork_f2830f7b(forkID *uint256.Int, txHash common.Hash) error { + id := forking.ForkID(*forkID) + return c.rollFork(id, c.forkURLOption(id), ForkWithTransaction(txHash)) +} + +// rollFork implements vm.rollFork: +// https://book.getfoundry.sh/cheatcodes/roll-fork +func (c *CheatCodesPrecompile) rollFork(id forking.ForkID, opts ...ForkOption) error { + src, err := c.h.onFork(opts...) + if err != nil { + return fmt.Errorf("cannot setup fork source for roll-fork change: %w", err) + } + return c.h.state.ResetFork(id, src) +} + +// MakePersistent_57e22dde implements vm.makePersistent: +// https://book.getfoundry.sh/cheatcodes/make-persistent +func (c *CheatCodesPrecompile) MakePersistent_57e22dde(account0 common.Address) { + c.h.state.MakePersistent(account0) +} + +func (c *CheatCodesPrecompile) MakePersistent_4074e0a8(account0, account1 common.Address) { + c.h.state.MakePersistent(account0) + c.h.state.MakePersistent(account1) +} + +func (c *CheatCodesPrecompile) MakePersistent_efb77a75(account0, account1, account2 common.Address) { + c.h.state.MakePersistent(account0) + c.h.state.MakePersistent(account1) + c.h.state.MakePersistent(account2) +} + +func (c *CheatCodesPrecompile) MakePersistent_1d9e269e(accounts []common.Address) { + for _, addr := range accounts { + c.h.state.MakePersistent(addr) + } +} + +// RevokePersistent_997a0222 implements vm.revokePersistent: +// https://book.getfoundry.sh/cheatcodes/revoke-persistent +func (c *CheatCodesPrecompile) RevokePersistent_997a0222(addr common.Address) { + c.h.state.RevokePersistent(addr) +} + +func (c *CheatCodesPrecompile) RevokePersistent_3ce969e6(addrs []common.Address) { + for _, addr := range addrs { + c.h.state.RevokePersistent(addr) + } +} + +// IsPersistent implements vm.isPersistent: +// https://book.getfoundry.sh/cheatcodes/is-persistent +func (c *CheatCodesPrecompile) IsPersistent(addr common.Address) bool { + return c.h.state.IsPersistent(addr) +} + +// AllowCheatcodes implements vm.allowCheatcodes: +// https://book.getfoundry.sh/cheatcodes/allow-cheatcodes +func (c *CheatCodesPrecompile) AllowCheatcodes(addr common.Address) { + c.h.AllowCheatcodes(addr) +} diff --git a/op-chain-ops/script/cheatcodes_utilities.go b/op-chain-ops/script/cheatcodes_utilities.go index 022befa606275..4f7606d7e4fba 100644 --- a/op-chain-ops/script/cheatcodes_utilities.go +++ b/op-chain-ops/script/cheatcodes_utilities.go @@ -233,6 +233,17 @@ func (c *CheatCodesPrecompile) ParseTomlAddress_65e7c844(tomlStr string, key str panic("should never get here") } +func (c *CheatCodesPrecompile) ComputeCreate2Address_890c283b(salt, codeHash [32]byte) (common.Address, error) { + data := make([]byte, 1+20+32+32) + data[0] = 0xff + copy(data[1:], DeterministicDeployerAddress.Bytes()) + copy(data[1+20:], salt[:]) + copy(data[1+20+32:], codeHash[:]) + finalHash := crypto.Keccak256(data) + // Take the last 20 bytes of the hash to get the address + return common.BytesToAddress(finalHash[12:]), nil +} + // unsupported //func (c *CheatCodesPrecompile) CreateWallet() {} diff --git a/op-chain-ops/script/cheatcodes_utilities_test.go b/op-chain-ops/script/cheatcodes_utilities_test.go index 23936a10e344e..4870ec8129dbd 100644 --- a/op-chain-ops/script/cheatcodes_utilities_test.go +++ b/op-chain-ops/script/cheatcodes_utilities_test.go @@ -57,3 +57,14 @@ func TestParseTomlAddress(t *testing.T) { require.NoError(t, err) require.Equal(t, common.HexToAddress("0xff4ce7b6a91a35c31d7d62b327d19617c8da6f23"), addr) } + +func TestComputeCreate2Address(t *testing.T) { + c := &CheatCodesPrecompile{} + var salt [32]byte + salt[31] = 'S' + var codeHash [32]byte + codeHash[31] = 'C' + addr, err := c.ComputeCreate2Address_890c283b(salt, codeHash) + require.NoError(t, err) + require.EqualValues(t, common.HexToAddress("0x2f29AF1b5a7083bf98C4A89976c2f17FF980735f"), addr) +} diff --git a/op-chain-ops/script/console_test.go b/op-chain-ops/script/console_test.go index d67f5efc0f5f5..70b78828b5d68 100644 --- a/op-chain-ops/script/console_test.go +++ b/op-chain-ops/script/console_test.go @@ -7,6 +7,8 @@ import ( "math/rand" // nosemgrep "testing" + "github.com/ethereum-optimism/optimism/op-chain-ops/script/addresses" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/log" @@ -62,8 +64,8 @@ func TestFormatter(t *testing.T) { require.Equal(t, "4.2", consoleFormat("%8e", big.NewInt(420000000))) require.Equal(t, "foo true bar false", consoleFormat("foo %s bar %s", true, false)) require.Equal(t, "foo 1 bar 0", consoleFormat("foo %d bar %d", true, false)) - require.Equal(t, "sender: "+DefaultSenderAddr.String(), - consoleFormat("sender: %s", DefaultSenderAddr)) + require.Equal(t, "sender: "+addresses.DefaultSenderAddr.String(), + consoleFormat("sender: %s", addresses.DefaultSenderAddr)) require.Equal(t, "long 0.000000000000000042 number", consoleFormat("long %18e number", big.NewInt(42))) require.Equal(t, "long 4200.000000000000000003 number", consoleFormat("long %18e number", new(big.Int).Add(new(big.Int).Mul( diff --git a/op-chain-ops/script/context.go b/op-chain-ops/script/context.go index a6baad7cce666..fbb3704688e3f 100644 --- a/op-chain-ops/script/context.go +++ b/op-chain-ops/script/context.go @@ -3,24 +3,9 @@ package script import ( "math/big" - "github.com/ethereum/go-ethereum/common" -) + "github.com/ethereum-optimism/optimism/op-chain-ops/script/addresses" -var ( - // DefaultSenderAddr is known as DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller")))) - DefaultSenderAddr = common.HexToAddress("0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38") - // DefaultScriptAddr is the address of the initial executing script, computed from: - // cast compute-address --nonce 1 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38 - DefaultScriptAddr = common.HexToAddress("0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496") - // VMAddr is known as VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); - VMAddr = common.HexToAddress("0x7109709ECfa91a80626fF3989D68f67F5b1DD12D") - // ConsoleAddr is known as CONSOLE, "console.log" in ascii. - // Utils like console.sol and console2.sol work by executing a staticcall to this address. - ConsoleAddr = common.HexToAddress("0x000000000000000000636F6e736F6c652e6c6f67") - // ScriptDeployer is used for temporary scripts address(uint160(uint256(keccak256("op-stack script deployer")))) - ScriptDeployer = common.HexToAddress("0x76Ce131128F3616871f8CDA86d18fAB44E4d0D8B") - // ForgeDeployer is used by some scripts as a default deployer address, e.g. makeAddr("deployer") - ForgeDeployer = common.HexToAddress("0xaE0bDc4eEAC5E950B67C6819B118761CaAF61946") + "github.com/ethereum/go-ethereum/common" ) const ( @@ -42,8 +27,8 @@ type Context struct { var DefaultContext = Context{ ChainID: big.NewInt(1337), - Sender: DefaultSenderAddr, - Origin: DefaultSenderAddr, + Sender: addresses.DefaultSenderAddr, + Origin: addresses.DefaultSenderAddr, FeeRecipient: common.Address{}, GasLimit: DefaultFoundryGasLimit, BlockNum: 0, diff --git a/op-chain-ops/script/fork.go b/op-chain-ops/script/fork.go new file mode 100644 index 0000000000000..8954a9984a35c --- /dev/null +++ b/op-chain-ops/script/fork.go @@ -0,0 +1,60 @@ +package script + +import ( + "fmt" + "math/big" + + "github.com/ethereum-optimism/optimism/op-chain-ops/script/forking" + "github.com/ethereum/go-ethereum/common" +) + +// ForkOption modifies a ForkConfig, and can be used by Host internals, +// like the forking cheatcodes, to customize the forking action. +type ForkOption func(cfg *ForkConfig) error + +// ForkHook is a callback to the user of the Host, +// to translate an intent to fork into a source of data that can be forked with. +type ForkHook func(opts *ForkConfig) (forking.ForkSource, error) + +// ForkConfig is a bundle of data to express a fork intent +type ForkConfig struct { + URLOrAlias string + BlockNumber *uint64 // latest if nil + Transaction *common.Hash // up to pre-state of given transaction +} + +func ForkWithURLOrAlias(urlOrAlias string) ForkOption { + return func(cfg *ForkConfig) error { + cfg.URLOrAlias = urlOrAlias + return nil + } +} + +func ForkWithBlockNumberU256(num *big.Int) ForkOption { + return func(cfg *ForkConfig) error { + if !num.IsUint64() { + return fmt.Errorf("block number %s is too large", num.String()) + } + v := num.Uint64() + cfg.BlockNumber = &v + return nil + } +} + +func ForkWithTransaction(txHash common.Hash) ForkOption { + return func(cfg *ForkConfig) error { + cfg.Transaction = &txHash + return nil + } +} + +// onFork is called by script-internals to translate a fork-intent into forks data-source. +func (h *Host) onFork(opts ...ForkOption) (forking.ForkSource, error) { + cfg := &ForkConfig{} + for _, opt := range opts { + if err := opt(cfg); err != nil { + return nil, err + } + } + return h.hooks.OnFork(cfg) +} diff --git a/op-chain-ops/script/forking/cache.go b/op-chain-ops/script/forking/cache.go new file mode 100644 index 0000000000000..c9fec7bda96f5 --- /dev/null +++ b/op-chain-ops/script/forking/cache.go @@ -0,0 +1,103 @@ +package forking + +import ( + lru "github.com/hashicorp/golang-lru/v2" + "github.com/holiman/uint256" + + "github.com/ethereum/go-ethereum/common" +) + +type storageKey struct { + Addr common.Address + Slot common.Hash +} + +// CachedSource wraps a ForkSource, and caches the retrieved data for faster repeat-queries. +// The ForkSource should be immutable (as per the StateRoot value). +// All cache data accumulates in-memory in LRU collections per data type. +type CachedSource struct { + stateRoot common.Hash + src ForkSource + + nonces *lru.Cache[common.Address, uint64] + balances *lru.Cache[common.Address, *uint256.Int] + storage *lru.Cache[storageKey, common.Hash] + code *lru.Cache[common.Address, []byte] +} + +var _ ForkSource = (*CachedSource)(nil) + +func mustNewLRU[K comparable, V any](size int) *lru.Cache[K, V] { + out, err := lru.New[K, V](size) + if err != nil { + panic(err) // bad size parameter may produce an error + } + return out +} + +func Cache(src ForkSource) *CachedSource { + return &CachedSource{ + stateRoot: src.StateRoot(), + src: src, + nonces: mustNewLRU[common.Address, uint64](1000), + balances: mustNewLRU[common.Address, *uint256.Int](1000), + storage: mustNewLRU[storageKey, common.Hash](1000), + code: mustNewLRU[common.Address, []byte](100), + } +} + +func (c *CachedSource) URLOrAlias() string { + return c.src.URLOrAlias() +} + +func (c *CachedSource) StateRoot() common.Hash { + return c.stateRoot +} + +func (c *CachedSource) Nonce(addr common.Address) (uint64, error) { + if v, ok := c.nonces.Get(addr); ok { + return v, nil + } + v, err := c.src.Nonce(addr) + if err != nil { + return 0, err + } + c.nonces.Add(addr, v) + return v, nil +} + +func (c *CachedSource) Balance(addr common.Address) (*uint256.Int, error) { + if v, ok := c.balances.Get(addr); ok { + return v.Clone(), nil + } + v, err := c.src.Balance(addr) + if err != nil { + return nil, err + } + c.balances.Add(addr, v) + return v.Clone(), nil +} + +func (c *CachedSource) StorageAt(addr common.Address, key common.Hash) (common.Hash, error) { + if v, ok := c.storage.Get(storageKey{Addr: addr, Slot: key}); ok { + return v, nil + } + v, err := c.src.StorageAt(addr, key) + if err != nil { + return common.Hash{}, err + } + c.storage.Add(storageKey{Addr: addr, Slot: key}, v) + return v, nil +} + +func (c *CachedSource) Code(addr common.Address) ([]byte, error) { + if v, ok := c.code.Get(addr); ok { + return v, nil + } + v, err := c.src.Code(addr) + if err != nil { + return nil, err + } + c.code.Add(addr, v) + return v, nil +} diff --git a/op-chain-ops/script/forking/cache_test.go b/op-chain-ops/script/forking/cache_test.go new file mode 100644 index 0000000000000..7ed4f97450421 --- /dev/null +++ b/op-chain-ops/script/forking/cache_test.go @@ -0,0 +1,196 @@ +package forking + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/holiman/uint256" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +// MockForkSource implements ForkSource interface for testing +type MockForkSource struct { + mock.Mock +} + +func (m *MockForkSource) URLOrAlias() string { + args := m.Called() + return args.String(0) +} + +func (m *MockForkSource) StateRoot() common.Hash { + args := m.Called() + return args.Get(0).(common.Hash) +} + +func (m *MockForkSource) Nonce(addr common.Address) (uint64, error) { + args := m.Called(addr) + return args.Get(0).(uint64), args.Error(1) +} + +func (m *MockForkSource) Balance(addr common.Address) (*uint256.Int, error) { + args := m.Called(addr) + if args.Get(0) == nil { + return nil, args.Error(1) + } + return args.Get(0).(*uint256.Int), args.Error(1) +} + +func (m *MockForkSource) StorageAt(addr common.Address, key common.Hash) (common.Hash, error) { + args := m.Called(addr, key) + return args.Get(0).(common.Hash), args.Error(1) +} + +func (m *MockForkSource) Code(addr common.Address) ([]byte, error) { + args := m.Called(addr) + return args.Get(0).([]byte), args.Error(1) +} + +func setupCache(t *testing.T) (*CachedSource, *MockForkSource) { + mockSource := new(MockForkSource) + stateRoot := common.HexToHash("0x1234") + mockSource.On("StateRoot").Return(stateRoot) + mockSource.On("URLOrAlias").Return("test_source") + + cached := Cache(mockSource) + require.NotNil(t, cached) + require.Equal(t, stateRoot, cached.StateRoot()) + require.Equal(t, "test_source", cached.URLOrAlias()) + + return cached, mockSource +} + +func TestCachedSource_Nonce(t *testing.T) { + cached, mockSource := setupCache(t) + addr := common.HexToAddress("0x1234") + expectedNonce := uint64(42) + + // First call should hit the source + mockSource.On("Nonce", addr).Return(expectedNonce, nil).Once() + + nonce, err := cached.Nonce(addr) + require.NoError(t, err) + require.Equal(t, expectedNonce, nonce) + + // Second call should use cache + nonce, err = cached.Nonce(addr) + require.NoError(t, err) + require.Equal(t, expectedNonce, nonce) + + mockSource.AssertNumberOfCalls(t, "Nonce", 1) +} + +func TestCachedSource_Balance(t *testing.T) { + cached, mockSource := setupCache(t) + addr := common.HexToAddress("0x5678") + expectedBalance := uint256.NewInt(1000) + + // First call should hit the source + mockSource.On("Balance", addr).Return(expectedBalance, nil).Once() + + balance, err := cached.Balance(addr) + require.NoError(t, err) + require.Equal(t, expectedBalance, balance) + + // Second call should use cache + balance, err = cached.Balance(addr) + require.NoError(t, err) + require.Equal(t, expectedBalance, balance) + + // Verify the returned balance is a clone + balance.Add(balance, uint256.NewInt(1)) + cachedBalance, _ := cached.Balance(addr) + require.Equal(t, expectedBalance, cachedBalance) + + mockSource.AssertNumberOfCalls(t, "Balance", 1) +} + +func TestCachedSource_Storage(t *testing.T) { + cached, mockSource := setupCache(t) + addr := common.HexToAddress("0x9abc") + slot := common.HexToHash("0xdef0") + expectedValue := common.HexToHash("0x1234") + + // First call should hit the source + mockSource.On("StorageAt", addr, slot).Return(expectedValue, nil).Once() + + value, err := cached.StorageAt(addr, slot) + require.NoError(t, err) + require.Equal(t, expectedValue, value) + + // Second call should use cache + value, err = cached.StorageAt(addr, slot) + require.NoError(t, err) + require.Equal(t, expectedValue, value) + + mockSource.AssertNumberOfCalls(t, "StorageAt", 1) +} + +func TestCachedSource_Code(t *testing.T) { + cached, mockSource := setupCache(t) + addr := common.HexToAddress("0xdef0") + expectedCode := []byte{1, 2, 3, 4} + + // First call should hit the source + mockSource.On("Code", addr).Return(expectedCode, nil).Once() + + code, err := cached.Code(addr) + require.NoError(t, err) + require.Equal(t, expectedCode, code) + + // Second call should use cache + code, err = cached.Code(addr) + require.NoError(t, err) + require.Equal(t, expectedCode, code) + + mockSource.AssertNumberOfCalls(t, "Code", 1) +} + +func TestCachedSource_CacheEviction(t *testing.T) { + cached, mockSource := setupCache(t) + + // Test nonce cache eviction + for i := 0; i < 1001; i++ { // Cache size is 1000 + addr := common.BigToAddress(big.NewInt(int64(i))) + mockSource.On("Nonce", addr).Return(uint64(i), nil).Once() + _, _ = cached.Nonce(addr) + } + + // This should cause first address to be evicted + firstAddr := common.BytesToAddress([]byte{0}) + mockSource.On("Nonce", firstAddr).Return(uint64(0), nil).Once() + _, _ = cached.Nonce(firstAddr) + + mockSource.AssertNumberOfCalls(t, "Nonce", 1002) // 1001 + 1 for evicted key +} + +func TestCachedSource_MultipleStorageSlots(t *testing.T) { + cached, mockSource := setupCache(t) + addr := common.HexToAddress("0xabcd") + slot1 := common.HexToHash("0x1111") + slot2 := common.HexToHash("0x2222") + value1 := common.HexToHash("0x3333") + value2 := common.HexToHash("0x4444") + + mockSource.On("StorageAt", addr, slot1).Return(value1, nil).Once() + mockSource.On("StorageAt", addr, slot2).Return(value2, nil).Once() + + // Different slots should trigger separate cache entries + val1, err := cached.StorageAt(addr, slot1) + require.NoError(t, err) + require.Equal(t, value1, val1) + + val2, err := cached.StorageAt(addr, slot2) + require.NoError(t, err) + require.Equal(t, value2, val2) + + // Verify both are cached + val1Again, _ := cached.StorageAt(addr, slot1) + val2Again, _ := cached.StorageAt(addr, slot2) + require.Equal(t, value1, val1Again) + require.Equal(t, value2, val2Again) + + mockSource.AssertNumberOfCalls(t, "StorageAt", 2) +} diff --git a/op-chain-ops/script/forking/db.go b/op-chain-ops/script/forking/db.go new file mode 100644 index 0000000000000..0a073500d247c --- /dev/null +++ b/op-chain-ops/script/forking/db.go @@ -0,0 +1,119 @@ +package forking + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/triedb/pathdb" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/state/snapshot" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/trie/utils" + "github.com/ethereum/go-ethereum/triedb" +) + +// ForkDB is a virtual state database: it wraps a forked accounts trie, +// and can maintain a state diff, so we can mutate the forked state, +// and even finalize state changes (so we can accurately measure things like cold storage gas cost). +type ForkDB struct { + active *ForkedAccountsTrie +} + +// Reader for read-only access to a known state. All cold reads go through this. +// So the state-DB creates one initially, and then holds on to it. +// The diff will be overlayed on the reader still. To get rid of the diff, it has to be explicitly cleared. +// Warning: diffs applied to the original state that the reader wraps will be visible. +// Geth StateDB is meant to be reinitialized after committing state. +func (f *ForkDB) Reader(root common.Hash) (state.Reader, error) { + if root != f.active.stateRoot { + return nil, fmt.Errorf("current state is at %s, cannot open state at %s", f.active.stateRoot, root) + } + return &forkStateReader{ + f.active, + }, nil +} + +func (f *ForkDB) Snapshot() *snapshot.Tree { + return nil +} + +var _ state.Database = (*ForkDB)(nil) + +func NewForkDB(source ForkSource) *ForkDB { + return &ForkDB{active: &ForkedAccountsTrie{ + stateRoot: source.StateRoot(), + src: source, + diff: NewExportDiff(), + }} +} + +// fakeRoot is just a marker; every account we load into the fork-db has this storage-root. +// When opening a storage-trie, we sanity-check we have this root, or an empty trie. +// And then just return the same global trie view for storage reads/writes. +// It needs to be set to EmptyRootHash to avoid contract collision errors when +// deploying contracts, since Geth checks the storage root prior to deployment. +var fakeRoot = types.EmptyRootHash + +func (f *ForkDB) OpenTrie(root common.Hash) (state.Trie, error) { + if f.active.stateRoot != root { + return nil, fmt.Errorf("active fork is at %s, but tried to open %s", f.active.stateRoot, root) + } + return f.active, nil +} + +func (f *ForkDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie state.Trie) (state.Trie, error) { + if f.active.stateRoot != stateRoot { + return nil, fmt.Errorf("active fork is at %s, but tried to open account %s of state %s", f.active.stateRoot, address, stateRoot) + } + if _, ok := trie.(*ForkedAccountsTrie); !ok { + return nil, fmt.Errorf("ForkDB tried to open non-fork storage-trie %v", trie) + } + if root != fakeRoot && root != types.EmptyRootHash { + return nil, fmt.Errorf("ForkDB unexpectedly was queried with real looking storage root: %s", root) + } + return f.active, nil +} + +func (f *ForkDB) CopyTrie(trie state.Trie) state.Trie { + if st, ok := trie.(*ForkedAccountsTrie); ok { + return st.Copy() + } + panic(fmt.Errorf("ForkDB tried to copy non-fork trie %v", trie)) +} + +func (f *ForkDB) ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) { + return f.active.ContractCode(addr, codeHash) +} + +func (f *ForkDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) { + return f.active.ContractCodeSize(addr, codeHash) +} + +func (f *ForkDB) DiskDB() ethdb.KeyValueStore { + panic("DiskDB() during active Fork is not supported") +} + +func (f *ForkDB) PointCache() *utils.PointCache { + panic("PointCache() is not supported") +} + +func (f *ForkDB) TrieDB() *triedb.Database { + // The TrieDB is unused, but geth does use to check if Verkle is activated. + // So we have to create a read-only dummy one, to communicate that verkle really is disabled. + diskDB := rawdb.NewMemoryDatabase() + tdb := triedb.NewDatabase(diskDB, &triedb.Config{ + Preimages: false, + IsVerkle: false, + HashDB: nil, + PathDB: &pathdb.Config{ + StateHistory: 0, + CleanCacheSize: 0, + DirtyCacheSize: 0, + ReadOnly: true, + }, + }) + return tdb +} diff --git a/op-chain-ops/script/forking/diff.go b/op-chain-ops/script/forking/diff.go new file mode 100644 index 0000000000000..c46b2704dc85e --- /dev/null +++ b/op-chain-ops/script/forking/diff.go @@ -0,0 +1,88 @@ +package forking + +import ( + "bytes" + "maps" + + "github.com/holiman/uint256" + + "github.com/ethereum/go-ethereum/common" +) + +// AccountDiff represents changes to an account. Unchanged values of the account are not included. +type AccountDiff struct { + // Nonce change. + // No diff if nil. + Nonce *uint64 `json:"nonce"` + + // Balance change. + // No diff if nil. + Balance *uint256.Int `json:"balance"` + + // Storage changes. + // No diff if not present in map. Deletions are zero-value entries. + Storage map[common.Hash]common.Hash `json:"storage"` + + // CodeHash, for lookup of contract bytecode in the code diff map. + // No code-diff if nil. + CodeHash *common.Hash `json:"codeHash"` +} + +func (d *AccountDiff) Copy() *AccountDiff { + var out AccountDiff + if d.Nonce != nil { + v := *d.Nonce // copy the value + out.Nonce = &v + } + if d.Balance != nil { + out.Balance = d.Balance.Clone() + } + if d.Storage != nil { + out.Storage = maps.Clone(d.Storage) + } + if d.CodeHash != nil { + h := *d.CodeHash + out.CodeHash = &h + } + return &out +} + +type ExportDiff struct { + // Accounts diff. Deleted accounts are set to nil. + // Warning: this only contains finalized state changes. + // The state itself holds on to non-flushed changes. + Account map[common.Address]*AccountDiff `json:"account"` + + // Stores new contract codes by code-hash + Code map[common.Hash][]byte `json:"code"` +} + +func NewExportDiff() *ExportDiff { + return &ExportDiff{ + Account: make(map[common.Address]*AccountDiff), + Code: make(map[common.Hash][]byte), + } +} + +func (ed *ExportDiff) Copy() *ExportDiff { + out := &ExportDiff{ + Account: make(map[common.Address]*AccountDiff), + Code: make(map[common.Hash][]byte), + } + for addr, acc := range ed.Account { + out.Account[addr] = acc.Copy() + } + for addr, code := range ed.Code { + out.Code[addr] = bytes.Clone(code) + } + return out +} + +func (ed *ExportDiff) Any() bool { + return len(ed.Code) > 0 || len(ed.Account) > 0 +} + +func (ed *ExportDiff) Clear() { + ed.Account = make(map[common.Address]*AccountDiff) + ed.Code = make(map[common.Hash][]byte) +} diff --git a/op-chain-ops/script/forking/forking_test.go b/op-chain-ops/script/forking/forking_test.go new file mode 100644 index 0000000000000..e6e62c19fc19c --- /dev/null +++ b/op-chain-ops/script/forking/forking_test.go @@ -0,0 +1,291 @@ +package forking + +import ( + "bytes" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/holiman/uint256" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/triedb" + "github.com/ethereum/go-ethereum/triedb/hashdb" +) + +type TestForkSource struct { + urlOrAlias string + stateRoot common.Hash + nonces map[common.Address]uint64 + balances map[common.Address]*uint256.Int + storage map[common.Address]map[common.Hash]common.Hash + code map[common.Address][]byte +} + +func (t TestForkSource) URLOrAlias() string { + return t.urlOrAlias +} + +func (t TestForkSource) StateRoot() common.Hash { + return t.stateRoot +} + +func (t TestForkSource) Nonce(addr common.Address) (uint64, error) { + return t.nonces[addr], nil +} + +func (t TestForkSource) Balance(addr common.Address) (*uint256.Int, error) { + b, ok := t.balances[addr] + if !ok { + return uint256.NewInt(0), nil + } + return b.Clone(), nil +} + +func (t TestForkSource) StorageAt(addr common.Address, key common.Hash) (common.Hash, error) { + storage, ok := t.storage[addr] + if !ok { + return common.Hash{}, nil + } + return storage[key], nil +} + +func (t TestForkSource) Code(addr common.Address) ([]byte, error) { + return t.code[addr], nil +} + +var _ ForkSource = (*TestForkSource)(nil) + +func TestForking(t *testing.T) { + // create regular DB + rawDB := rawdb.NewMemoryDatabase() + stateDB := state.NewDatabase(triedb.NewDatabase(rawDB, &triedb.Config{ + Preimages: true, // To be able to iterate the state we need the Preimages + IsVerkle: false, + HashDB: hashdb.Defaults, + PathDB: nil, + }), nil) + baseState, err := state.New(types.EmptyRootHash, stateDB) + if err != nil { + panic(fmt.Errorf("failed to create memory state db: %w", err)) + } + forkState := NewForkableState(baseState) + + // No active fork yet + id, active := forkState.ActiveFork() + require.False(t, active) + require.Equal(t, ForkID{}, id) + + name, err := forkState.ForkURLOrAlias(ForkID{}) + require.ErrorContains(t, err, "default") + require.Equal(t, "", name) + + alice := common.Address(bytes.Repeat([]byte{0xaa}, 20)) + bob := common.Address(bytes.Repeat([]byte{0xbb}, 20)) + + forkState.CreateAccount(alice) + forkState.SetNonce(alice, 3) + forkState.AddBalance(alice, uint256.NewInt(123), tracing.BalanceChangeUnspecified) + // Check if writes worked + require.Equal(t, uint64(123), forkState.GetBalance(alice).Uint64()) + require.Equal(t, uint64(3), forkState.GetNonce(alice)) + // No active fork yet, balance change should be applied to underlying base-state + require.Equal(t, uint64(123), baseState.GetBalance(alice).Uint64()) + require.Equal(t, uint64(3), baseState.GetNonce(alice)) + + src1 := &TestForkSource{ + urlOrAlias: "src 1", + stateRoot: crypto.Keccak256Hash([]byte("test fork state 1")), + nonces: map[common.Address]uint64{ + alice: uint64(42), + bob: uint64(1000), + }, + balances: make(map[common.Address]*uint256.Int), + storage: make(map[common.Address]map[common.Hash]common.Hash), + code: make(map[common.Address][]byte), + } + forkA, err := forkState.CreateSelectFork(src1) + require.NoError(t, err) + // Check that we selected A + id, active = forkState.ActiveFork() + require.True(t, active) + require.Equal(t, forkA, id) + name, err = forkState.ForkURLOrAlias(forkA) + require.NoError(t, err) + require.Equal(t, "src 1", name) + + // the fork has a different nonce for alice + require.Equal(t, uint64(42), forkState.GetNonce(alice)) + // the fork has Bob, which didn't exist thus far + require.Equal(t, uint64(1000), forkState.GetNonce(bob)) + + // Apply a diff change on top of the fork + forkState.SetNonce(bob, 99999) + + // Now unselect the fork, going back to the default again. + require.NoError(t, forkState.SelectFork(ForkID{})) + // No longer active fork + id, active = forkState.ActiveFork() + require.False(t, active) + require.Equal(t, ForkID{}, id) + + // Check that things are back to normal + require.Equal(t, uint64(3), forkState.GetNonce(alice)) + require.Equal(t, uint64(0), forkState.GetNonce(bob)) + + // Make a change to the base-state, to see if it survives going back to the fork. + forkState.SetNonce(bob, 5) + + // Re-select the fork, see if the changes come back, including the diff we made + require.NoError(t, forkState.SelectFork(forkA)) + require.Equal(t, uint64(42), forkState.GetNonce(alice)) + require.Equal(t, uint64(99999), forkState.GetNonce(bob)) + + // This change will continue to be visible across forks, + // alice is going to be persistent. + forkState.SetNonce(alice, 777) + + // Now make Alice persistent, see if we can get the original value + forkState.MakePersistent(alice) + + // Activate a fork, to see if alice is really persistent + src2 := &TestForkSource{ + urlOrAlias: "src 2", + stateRoot: crypto.Keccak256Hash([]byte("test fork state 2")), + nonces: map[common.Address]uint64{ + alice: uint64(2222), + bob: uint64(222), + }, + balances: make(map[common.Address]*uint256.Int), + storage: make(map[common.Address]map[common.Hash]common.Hash), + code: make(map[common.Address][]byte), + } + tmpFork, err := forkState.CreateSelectFork(src2) + require.NoError(t, err) + require.Equal(t, uint64(777), forkState.GetNonce(alice), "persistent original value") + // While bob is still read from the fork + require.Equal(t, uint64(222), forkState.GetNonce(bob), "bob is forked") + + // Mutate both, and undo the fork, to test if the persistent change is still there in non-fork mode + forkState.SetNonce(alice, 1001) // this mutates forkA, because alice was made persistent there + forkState.SetNonce(bob, 1002) + require.NoError(t, forkState.SelectFork(ForkID{})) + require.Equal(t, uint64(1001), forkState.GetNonce(alice), "alice is persistent") + require.Equal(t, uint64(5), forkState.GetNonce(bob), "bob is not persistent") + + // Stop alice persistence. Forks can now override it again. + forkState.RevokePersistent(alice) + // This foundry behavior is unspecified/undocumented. + // Not sure if correctly doing it by dropping the previously persisted state if it comes from another fork. + require.Equal(t, uint64(3), forkState.GetNonce(alice)) + require.Equal(t, uint64(3), baseState.GetNonce(alice)) + require.Equal(t, uint64(5), forkState.GetNonce(bob)) + + // Create another fork, don't select it immediately + src3 := &TestForkSource{ + urlOrAlias: "src 3", + stateRoot: crypto.Keccak256Hash([]byte("test fork state 3")), + nonces: map[common.Address]uint64{ + alice: uint64(3333), + }, + balances: make(map[common.Address]*uint256.Int), + storage: make(map[common.Address]map[common.Hash]common.Hash), + code: make(map[common.Address][]byte), + } + forkB, err := forkState.CreateFork(src3) + require.NoError(t, err) + + id, active = forkState.ActiveFork() + require.False(t, active) + require.Equal(t, ForkID{}, id) + + // forkA is still bound to src 1 + name, err = forkState.ForkURLOrAlias(forkA) + require.NoError(t, err) + require.Equal(t, "src 1", name) + // tmpFork is still bound to src 2 + name, err = forkState.ForkURLOrAlias(tmpFork) + require.NoError(t, err) + require.Equal(t, "src 2", name) + // forkB is on src 3 + name, err = forkState.ForkURLOrAlias(forkB) + require.NoError(t, err) + require.Equal(t, "src 3", name) + + require.Equal(t, uint64(3), forkState.GetNonce(alice), "not forked yet") + require.NoError(t, forkState.SelectFork(forkB)) + id, active = forkState.ActiveFork() + require.True(t, active) + require.Equal(t, forkB, id) + + // check if successfully forked now + require.Equal(t, uint64(3333), forkState.GetNonce(alice), "fork B active now") + // Bob is not in this fork. But that doesn't mean the base-state should be used. + require.Equal(t, uint64(0), forkState.GetNonce(bob)) + + // See if we can go from B straight to A + require.NoError(t, forkState.SelectFork(forkA)) + require.Equal(t, uint64(1001), forkState.GetNonce(alice), "alice from A says hi") + // And back to B + require.NoError(t, forkState.SelectFork(forkB)) + require.Equal(t, uint64(3333), forkState.GetNonce(alice), "alice from B says hi") + + // And a fork on top of a fork; forks don't stack, they are their own individual contexts. + src4 := &TestForkSource{ + urlOrAlias: "src 4", + stateRoot: crypto.Keccak256Hash([]byte("test fork state 4")), + nonces: map[common.Address]uint64{ + bob: uint64(9000), + }, + balances: make(map[common.Address]*uint256.Int), + storage: make(map[common.Address]map[common.Hash]common.Hash), + code: make(map[common.Address][]byte), + } + forkC, err := forkState.CreateSelectFork(src4) + require.NoError(t, err) + // No alice in this fork. + require.Equal(t, uint64(0), forkState.GetNonce(alice)) + // But bob is set + require.Equal(t, uint64(9000), forkState.GetNonce(bob)) + + // Put in some mutations, for the fork-diff testing + forkState.SetNonce(alice, 1234) + forkState.SetBalance(alice, uint256.NewInt(100_000), tracing.BalanceChangeUnspecified) + forkState.SetState(alice, common.Hash{4}, common.Hash{42}) + forkState.SetState(alice, common.Hash{5}, common.Hash{100}) + forkState.SetCode(alice, []byte("hello world")) + + // Check the name + name, err = forkState.ForkURLOrAlias(forkC) + require.NoError(t, err) + require.Equal(t, "src 4", name) + + // Now test our fork-diff exporting: + // it needs to reflect the changes we made to the fork, but not other fork contents. + forkADiff, err := forkState.ExportDiff(forkA) + require.NoError(t, err) + require.NotNil(t, forkADiff.Account[alice]) + require.Equal(t, uint64(1001), *forkADiff.Account[alice].Nonce) + require.Equal(t, uint64(99999), *forkADiff.Account[bob].Nonce) + + forkBDiff, err := forkState.ExportDiff(forkB) + require.NoError(t, err) + require.Len(t, forkBDiff.Account, 0, "no changes to fork B") + + forkCDiff, err := forkState.ExportDiff(forkC) + require.NoError(t, err) + require.Contains(t, forkCDiff.Account, alice) + require.NotContains(t, forkCDiff.Account, bob) + require.Equal(t, uint64(1234), *forkCDiff.Account[alice].Nonce) + require.Equal(t, uint64(100_000), forkCDiff.Account[alice].Balance.Uint64()) + require.Equal(t, common.Hash{42}, forkCDiff.Account[alice].Storage[common.Hash{4}]) + require.Equal(t, common.Hash{100}, forkCDiff.Account[alice].Storage[common.Hash{5}]) + require.Equal(t, crypto.Keccak256Hash([]byte("hello world")), *forkCDiff.Account[alice].CodeHash) + require.Equal(t, []byte("hello world"), forkCDiff.Code[*forkCDiff.Account[alice].CodeHash]) +} diff --git a/op-chain-ops/script/forking/iface.go b/op-chain-ops/script/forking/iface.go new file mode 100644 index 0000000000000..2e1c29031be17 --- /dev/null +++ b/op-chain-ops/script/forking/iface.go @@ -0,0 +1,52 @@ +package forking + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/holiman/uint256" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" +) + +type VMStateDB interface { + vm.StateDB + Finalise(deleteEmptyObjects bool) + // SetBalance sets the balance of an account. Not part of the geth VM StateDB interface (add/sub balance are). + SetBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) +} + +// ForkID is an identifier of a fork +type ForkID uint256.Int + +func ForkIDFromBig(b *big.Int) ForkID { + return ForkID(*uint256.MustFromBig(b)) +} + +// U256 returns a uint256 copy of the fork ID, for usage inside the EVM. +func (id *ForkID) U256() *uint256.Int { + return new(uint256.Int).Set((*uint256.Int)(id)) +} + +func (id ForkID) String() string { + return (*uint256.Int)(&id).String() +} + +// ForkSource is a read-only source for ethereum state, +// that can be used to fork a ForkableState. +type ForkSource interface { + // URLOrAlias returns the URL or alias that the fork uses. This is not unique to a single fork. + URLOrAlias() string + // StateRoot returns the accounts-trie root of the committed-to state. + // This root must never change. + StateRoot() common.Hash + // Nonce returns 0, without error, if the account does not exist. + Nonce(addr common.Address) (uint64, error) + // Balance returns 0, without error, if the account does not exist. + Balance(addr common.Address) (*uint256.Int, error) + // StorageAt returns a zeroed hash, without error, if the storage does not exist. + StorageAt(addr common.Address, key common.Hash) (common.Hash, error) + // Code returns an empty byte slice, without error, if no code exists. + Code(addr common.Address) ([]byte, error) +} diff --git a/op-chain-ops/script/forking/reader.go b/op-chain-ops/script/forking/reader.go new file mode 100644 index 0000000000000..d943ddf14449a --- /dev/null +++ b/op-chain-ops/script/forking/reader.go @@ -0,0 +1,36 @@ +package forking + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" +) + +// forkStateReader implements the state.Reader abstraction, +// for read-only access to a state-trie at a particular state-root. +type forkStateReader struct { + trie *ForkedAccountsTrie +} + +var _ state.Reader = (*forkStateReader)(nil) + +func (f *forkStateReader) Account(addr common.Address) (*types.StateAccount, error) { + acc, err := f.trie.GetAccount(addr) + if err != nil { + return nil, err + } + // We copy because the Reader interface defines that it should be safe to modify after returning. + return acc.Copy(), nil +} + +func (f *forkStateReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { + v, err := f.trie.GetStorage(addr, slot[:]) + if err != nil { + return common.Hash{}, err + } + return common.Hash(v), nil +} + +func (f *forkStateReader) Copy() state.Reader { + return f +} diff --git a/op-chain-ops/script/forking/rpc.go b/op-chain-ops/script/forking/rpc.go new file mode 100644 index 0000000000000..501c0fd6e372d --- /dev/null +++ b/op-chain-ops/script/forking/rpc.go @@ -0,0 +1,140 @@ +package forking + +import ( + "context" + "fmt" + "time" + + "github.com/holiman/uint256" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + + "github.com/ethereum-optimism/optimism/op-service/retry" +) + +type RPCClient interface { + CallContext(ctx context.Context, result any, method string, args ...any) error +} + +type RPCSource struct { + stateRoot common.Hash + blockHash common.Hash + + maxAttempts int + timeout time.Duration + strategy retry.Strategy + + ctx context.Context + cancel context.CancelFunc + + client RPCClient + urlOrAlias string +} + +var _ ForkSource = (*RPCSource)(nil) + +func RPCSourceByNumber(urlOrAlias string, cl RPCClient, num uint64) (*RPCSource, error) { + src := newRPCSource(urlOrAlias, cl) + err := src.init(hexutil.Uint64(num)) + return src, err +} + +func RPCSourceByHash(urlOrAlias string, cl RPCClient, h common.Hash) (*RPCSource, error) { + src := newRPCSource(urlOrAlias, cl) + err := src.init(h) + return src, err +} + +func newRPCSource(urlOrAlias string, cl RPCClient) *RPCSource { + ctx, cancel := context.WithCancel(context.Background()) + return &RPCSource{ + maxAttempts: 10, + timeout: time.Second * 10, + strategy: retry.Exponential(), + ctx: ctx, + cancel: cancel, + client: cl, + urlOrAlias: urlOrAlias, + } +} + +type Header struct { + StateRoot common.Hash `json:"stateRoot"` + BlockHash common.Hash `json:"hash"` +} + +func (r *RPCSource) init(id any) error { + head, err := retry.Do[*Header](r.ctx, r.maxAttempts, r.strategy, func() (*Header, error) { + var result *Header + err := r.client.CallContext(r.ctx, &result, "eth_getBlockByNumber", id, false) + if err == nil && result == nil { + err = ethereum.NotFound + } + return result, err + }) + if err != nil { + return fmt.Errorf("failed to initialize RPC fork source around block %v: %w", id, err) + } + r.blockHash = head.BlockHash + r.stateRoot = head.StateRoot + return nil +} + +func (c *RPCSource) URLOrAlias() string { + return c.urlOrAlias +} + +func (r *RPCSource) BlockHash() common.Hash { + return r.blockHash +} + +func (r *RPCSource) StateRoot() common.Hash { + return r.stateRoot +} + +func (r *RPCSource) Nonce(addr common.Address) (uint64, error) { + return retry.Do[uint64](r.ctx, r.maxAttempts, r.strategy, func() (uint64, error) { + ctx, cancel := context.WithTimeout(r.ctx, r.timeout) + defer cancel() + var result hexutil.Uint64 + err := r.client.CallContext(ctx, &result, "eth_getTransactionCount", addr, r.blockHash) + return uint64(result), err + }) +} + +func (r *RPCSource) Balance(addr common.Address) (*uint256.Int, error) { + return retry.Do[*uint256.Int](r.ctx, r.maxAttempts, r.strategy, func() (*uint256.Int, error) { + ctx, cancel := context.WithTimeout(r.ctx, r.timeout) + defer cancel() + var result hexutil.U256 + err := r.client.CallContext(ctx, &result, "eth_getBalance", addr, r.blockHash) + return (*uint256.Int)(&result), err + }) +} + +func (r *RPCSource) StorageAt(addr common.Address, key common.Hash) (common.Hash, error) { + return retry.Do[common.Hash](r.ctx, r.maxAttempts, r.strategy, func() (common.Hash, error) { + ctx, cancel := context.WithTimeout(r.ctx, r.timeout) + defer cancel() + var result common.Hash + err := r.client.CallContext(ctx, &result, "eth_getStorageAt", addr, key, r.blockHash) + return result, err + }) +} + +func (r *RPCSource) Code(addr common.Address) ([]byte, error) { + return retry.Do[[]byte](r.ctx, r.maxAttempts, r.strategy, func() ([]byte, error) { + ctx, cancel := context.WithTimeout(r.ctx, r.timeout) + defer cancel() + var result hexutil.Bytes + err := r.client.CallContext(ctx, &result, "eth_getCode", addr, r.blockHash) + return result, err + }) +} + +// Close stops any ongoing RPC requests by cancelling the RPC context +func (r *RPCSource) Close() { + r.cancel() +} diff --git a/op-chain-ops/script/forking/rpc_test.go b/op-chain-ops/script/forking/rpc_test.go new file mode 100644 index 0000000000000..9f23e957b1e99 --- /dev/null +++ b/op-chain-ops/script/forking/rpc_test.go @@ -0,0 +1,210 @@ +package forking + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/ethereum-optimism/optimism/op-service/retry" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/holiman/uint256" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +// MockRPCClient implements RPCClient interface for testing +type MockRPCClient struct { + mock.Mock +} + +func (m *MockRPCClient) CallContext(ctx context.Context, result any, method string, args ...any) error { + return m.Called(ctx, result, method, args).Error(0) +} + +func TestRPCSourceInitialization(t *testing.T) { + mockClient := new(MockRPCClient) + expectedStateRoot := common.HexToHash("0x1234") + expectedBlockHash := common.HexToHash("0x5678") + + t.Run("initialization by block number", func(t *testing.T) { + mockClient.On("CallContext", mock.Anything, mock.AnythingOfType("**forking.Header"), + "eth_getBlockByNumber", []any{hexutil.Uint64(123), false}). + Run(func(args mock.Arguments) { + result := args.Get(1).(**Header) + *result = &Header{ + StateRoot: expectedStateRoot, + BlockHash: expectedBlockHash, + } + }). + Return(nil).Once() + + source, err := RPCSourceByNumber("test_url", mockClient, 123) + require.NoError(t, err) + require.Equal(t, expectedStateRoot, source.StateRoot()) + require.Equal(t, expectedBlockHash, source.BlockHash()) + }) + + t.Run("initialization by block hash", func(t *testing.T) { + blockHash := common.HexToHash("0xabcd") + mockClient.On("CallContext", mock.Anything, mock.AnythingOfType("**forking.Header"), + "eth_getBlockByNumber", []any{blockHash, false}). + Run(func(args mock.Arguments) { + result := args.Get(1).(**Header) + *result = &Header{ + StateRoot: expectedStateRoot, + BlockHash: expectedBlockHash, + } + }). + Return(nil).Once() + + source, err := RPCSourceByHash("test_url", mockClient, blockHash) + require.NoError(t, err) + require.Equal(t, expectedStateRoot, source.StateRoot()) + require.Equal(t, expectedBlockHash, source.BlockHash()) + }) + + t.Run("initialization failure", func(t *testing.T) { + mockClient.On("CallContext", mock.Anything, mock.AnythingOfType("**forking.Header"), + "eth_getBlockByNumber", []any{hexutil.Uint64(999), false}). + Return(ethereum.NotFound).Times(2) + + src := newRPCSource("test_url", mockClient) + strategy := retry.Exponential() + strategy.(*retry.ExponentialStrategy).Max = 100 * time.Millisecond + src.strategy = strategy + src.maxAttempts = 2 + require.Error(t, src.init(hexutil.Uint64(999))) + }) +} + +func TestRPCSourceDataRetrieval(t *testing.T) { + mockClient := new(MockRPCClient) + testAddr := common.HexToAddress("0x1234567890123456789012345678901234567890") + blockHash := common.HexToHash("0xabcd") + + source := &RPCSource{ + blockHash: blockHash, + client: mockClient, + ctx: context.Background(), + strategy: retry.Exponential(), + maxAttempts: 10, + timeout: time.Second * 10, + } + + t.Run("get nonce", func(t *testing.T) { + expectedNonce := uint64(5) + mockClient.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Uint64"), + "eth_getTransactionCount", []any{testAddr, blockHash}). + Run(func(args mock.Arguments) { + result := args.Get(1).(*hexutil.Uint64) + *result = hexutil.Uint64(expectedNonce) + }). + Return(nil).Once() + + nonce, err := source.Nonce(testAddr) + require.NoError(t, err) + require.Equal(t, expectedNonce, nonce) + }) + + t.Run("get balance", func(t *testing.T) { + expectedBalance := uint256.NewInt(1000) + mockClient.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.U256"), + "eth_getBalance", []any{testAddr, blockHash}). + Run(func(args mock.Arguments) { + result := args.Get(1).(*hexutil.U256) + *(*uint256.Int)(result) = *expectedBalance + }). + Return(nil).Once() + + balance, err := source.Balance(testAddr) + require.NoError(t, err) + require.Equal(t, expectedBalance, balance) + }) + + t.Run("get storage", func(t *testing.T) { + storageKey := common.HexToHash("0x1234") + expectedValue := common.HexToHash("0x5678") + mockClient.On("CallContext", mock.Anything, mock.AnythingOfType("*common.Hash"), + "eth_getStorageAt", []any{testAddr, storageKey, blockHash}). + Run(func(args mock.Arguments) { + result := args.Get(1).(*common.Hash) + *result = expectedValue + }). + Return(nil).Once() + + value, err := source.StorageAt(testAddr, storageKey) + require.NoError(t, err) + require.Equal(t, expectedValue, value) + }) + + t.Run("get code", func(t *testing.T) { + expectedCode := []byte{1, 2, 3, 4} + mockClient.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), + "eth_getCode", []any{testAddr, blockHash}). + Run(func(args mock.Arguments) { + result := args.Get(1).(*hexutil.Bytes) + *result = expectedCode + }). + Return(nil).Once() + + code, err := source.Code(testAddr) + require.NoError(t, err) + require.Equal(t, expectedCode, code) + }) +} + +func TestRPCSourceRetry(t *testing.T) { + mockClient := new(MockRPCClient) + testAddr := common.HexToAddress("0x1234") + blockHash := common.HexToHash("0xabcd") + strategy := retry.Exponential() + strategy.(*retry.ExponentialStrategy).Max = 100 * time.Millisecond + + source := &RPCSource{ + blockHash: blockHash, + client: mockClient, + ctx: context.Background(), + strategy: strategy, + maxAttempts: 3, + timeout: time.Second * 10, + } + + t.Run("retry on temporary error", func(t *testing.T) { + tempError := errors.New("temporary network error") + + // Fail twice, succeed on third attempt + mockClient.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Uint64"), + "eth_getTransactionCount", []any{testAddr, blockHash}). + Return(tempError).Times(2) + + mockClient.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Uint64"), + "eth_getTransactionCount", []any{testAddr, blockHash}). + Run(func(args mock.Arguments) { + result := args.Get(1).(*hexutil.Uint64) + *result = hexutil.Uint64(5) + }). + Return(nil).Once() + + nonce, err := source.Nonce(testAddr) + require.NoError(t, err) + require.Equal(t, uint64(5), nonce) + }) +} + +func TestRPCSourceClose(t *testing.T) { + mockClient := new(MockRPCClient) + source := newRPCSource("test_url", mockClient) + + // Verify context is active before close + require.NoError(t, source.ctx.Err()) + + source.Close() + + // Verify context is cancelled after close + require.Error(t, source.ctx.Err()) + require.Equal(t, context.Canceled, source.ctx.Err()) +} diff --git a/op-chain-ops/script/forking/state.go b/op-chain-ops/script/forking/state.go new file mode 100644 index 0000000000000..c3b6da1e32366 --- /dev/null +++ b/op-chain-ops/script/forking/state.go @@ -0,0 +1,391 @@ +package forking + +import ( + "errors" + "fmt" + + "github.com/ethereum-optimism/optimism/op-chain-ops/script/addresses" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/stateless" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie/utils" + "github.com/holiman/uint256" +) + +type forkStateEntry struct { + state *state.StateDB +} + +func (fe *forkStateEntry) DB() *ForkDB { + return fe.state.Database().(*ForkDB) +} + +// ForkableState implements the vm.StateDB interface, +// and a few other methods as defined in the VMStateDB interface. +// This state can be forked in-place, +// swapping over operations to route to in-memory states that wrap fork sources. +type ForkableState struct { + selected VMStateDB + + activeFork ForkID + forks map[ForkID]*forkStateEntry + + // persistent accounts will override any interactions + // to be directly with the forkID that was active at the time it was made persistent, + // rather than whatever fork is currently active. + persistent map[common.Address]ForkID + + fallback VMStateDB + + idCounter uint64 +} + +var _ VMStateDB = (*ForkableState)(nil) + +func NewForkableState(base VMStateDB) *ForkableState { + return &ForkableState{ + selected: base, + activeFork: ForkID{}, + forks: make(map[ForkID]*forkStateEntry), + persistent: map[common.Address]ForkID{ + addresses.DefaultSenderAddr: ForkID{}, + addresses.VMAddr: ForkID{}, + addresses.ConsoleAddr: ForkID{}, + }, + fallback: base, + idCounter: 0, + } +} + +// ExportDiff exports a state diff. Warning: diffs are like flushed states. +// So we flush the state, making all the contents cold, losing transient storage, etc. +func (fst *ForkableState) ExportDiff(id ForkID) (*ExportDiff, error) { + if id == (ForkID{}) { + return nil, errors.New("default no-fork state does not have an exportable diff") + } + f, ok := fst.forks[id] + if !ok { + return nil, fmt.Errorf("unknown fork %q", id) + } + // Finalize the state content, so we can get an accurate diff. + f.state.IntermediateRoot(true) + tr := f.state.GetTrie() + ft, ok := tr.(*ForkedAccountsTrie) + if !ok { + return nil, fmt.Errorf("forked state trie is unexpectedly not a ForkedAccountsTrie: %T", tr) + } + diff := ft.ExportDiff() + // Now re-init the state, so we can use it again (albeit it cold). + forkDB := &ForkDB{active: ft} + st, err := state.New(forkDB.active.stateRoot, forkDB) + if err != nil { + return nil, fmt.Errorf("failed to construct fork state: %w", err) + } + fst.forks[id].state = st + if fst.activeFork == id { + fst.selected = st + } + return diff, nil +} + +// CreateSelectFork is like vm.createSelectFork, it creates a fork, and selects it immediately. +func (fst *ForkableState) CreateSelectFork(source ForkSource) (ForkID, error) { + id, err := fst.CreateFork(source) + if err != nil { + return id, err + } + return id, fst.SelectFork(id) +} + +// CreateFork is like vm.createFork, it creates a fork, but does not select it yet. +func (fst *ForkableState) CreateFork(source ForkSource) (ForkID, error) { + fst.idCounter += 1 // increment first, don't use ID 0 + id := ForkID(*uint256.NewInt(fst.idCounter)) + _, ok := fst.forks[id] + if ok { // sanity check our ID counter is consistent with the tracked forks + return id, fmt.Errorf("cannot create fork, fork %q already exists", id) + } + forkDB := NewForkDB(source) + st, err := state.New(forkDB.active.stateRoot, forkDB) + if err != nil { + return id, fmt.Errorf("failed to construct fork state: %w", err) + } + fst.forks[id] = &forkStateEntry{ + state: st, + } + return id, nil +} + +// SelectFork is like vm.selectFork, it activates the usage of a previously created fork. +func (fst *ForkableState) SelectFork(id ForkID) error { + if id == (ForkID{}) { + fst.selected = fst.fallback + fst.activeFork = ForkID{} + return nil + } + f, ok := fst.forks[id] + if !ok { + return fmt.Errorf("cannot select fork, fork %q is unknown", id) + } + fst.selected = f.state + fst.activeFork = id + return nil +} + +// ResetFork resets the fork to be coupled to the given fork-source. +// Any ephemeral state changes (transient storage, warm s-loads, etc.) +// as well as any uncommitted state, as well as any previously flushed diffs, will be lost. +func (fst *ForkableState) ResetFork(id ForkID, src ForkSource) error { + if id == (ForkID{}) { + return errors.New("default no-fork state cannot change its ForkSource") + } + f, ok := fst.forks[id] + if !ok { + return fmt.Errorf("unknown fork %q", id) + } + // Now create a new state + forkDB := NewForkDB(src) + st, err := state.New(src.StateRoot(), forkDB) + if err != nil { + return fmt.Errorf("failed to construct fork state: %w", err) + } + f.state = st + if fst.activeFork == id { + fst.selected = st + } + return nil +} + +// ActiveFork returns the ID current active fork, or active == false if no fork is active. +func (fst *ForkableState) ActiveFork() (id ForkID, active bool) { + return fst.activeFork, fst.activeFork != (ForkID{}) +} + +// ForkURLOrAlias returns the URL or alias that the fork was configured with as source. +// Returns an error if no fork is active +func (fst *ForkableState) ForkURLOrAlias(id ForkID) (string, error) { + if id == (ForkID{}) { + return "", errors.New("default no-fork state does not have an URL or Alias") + } + f, ok := fst.forks[id] + if !ok { + return "", fmt.Errorf("unknown fork %q", id) + } + return f.DB().active.src.URLOrAlias(), nil +} + +// SubstituteBaseState substitutes in a fallback state. +func (fst *ForkableState) SubstituteBaseState(base VMStateDB) { + fst.fallback = base + // If the fallback is currently selected, also updated the fallback. + if fst.activeFork == (ForkID{}) { + fst.selected = base + } +} + +// MakePersistent is like vm.makePersistent, it maintains this account context across all forks. +// It does not make the account of a fork persistent, it makes an account override what might be in a fork. +func (fst *ForkableState) MakePersistent(addr common.Address) { + fst.persistent[addr] = fst.activeFork +} + +// MakeExcluded excludes an account from forking. This is useful for things like scripts, which +// should always use the fallback state. +func (fst *ForkableState) MakeExcluded(addr common.Address) { + fst.persistent[addr] = ForkID{} +} + +// RevokePersistent is like vm.revokePersistent, it undoes a previous vm.makePersistent. +func (fst *ForkableState) RevokePersistent(addr common.Address) { + delete(fst.persistent, addr) +} + +// RevokeExcluded undoes MakeExcluded. It will panic if the account was marked as +// persistent in a different fork. +func (fst *ForkableState) RevokeExcluded(addr common.Address) { + forkID, ok := fst.persistent[addr] + if ok && forkID != (ForkID{}) { + panic(fmt.Sprintf("cannot revoke excluded account %s since it was made persistent in fork %q", addr, forkID)) + } + delete(fst.persistent, addr) +} + +// IsPersistent is like vm.isPersistent, it checks if an account persists across forks. +func (fst *ForkableState) IsPersistent(addr common.Address) bool { + _, ok := fst.persistent[addr] + return ok +} + +func (fst *ForkableState) stateFor(addr common.Address) VMStateDB { + // if forked, check if we persisted this account across forks + persistedForkID, ok := fst.persistent[addr] + if ok { + if persistedForkID == (ForkID{}) { + return fst.fallback + } + return fst.forks[persistedForkID].state + } + // This may be the fallback state, if no fork is active. + return fst.selected +} + +// Finalise finalises the state by removing the destructed objects and clears +// the journal as well as the refunds. Finalise, however, will not push any updates +// into the tries just yet. +// +// The changes will be flushed to the underlying DB. +// A *ForkDB if the state is currently forked. +func (fst *ForkableState) Finalise(deleteEmptyObjects bool) { + fst.selected.Finalise(deleteEmptyObjects) +} + +func (fst *ForkableState) CreateAccount(address common.Address) { + fst.stateFor(address).CreateAccount(address) +} + +func (fst *ForkableState) CreateContract(address common.Address) { + fst.stateFor(address).CreateContract(address) +} + +func (fst *ForkableState) SubBalance(address common.Address, u *uint256.Int, reason tracing.BalanceChangeReason) { + fst.stateFor(address).SubBalance(address, u, reason) +} + +func (fst *ForkableState) AddBalance(address common.Address, u *uint256.Int, reason tracing.BalanceChangeReason) { + fst.stateFor(address).AddBalance(address, u, reason) +} + +func (fst *ForkableState) GetBalance(address common.Address) *uint256.Int { + return fst.stateFor(address).GetBalance(address) +} + +func (fst *ForkableState) GetNonce(address common.Address) uint64 { + return fst.stateFor(address).GetNonce(address) +} + +func (fst *ForkableState) SetNonce(address common.Address, u uint64) { + fst.stateFor(address).SetNonce(address, u) +} + +func (fst *ForkableState) GetCodeHash(address common.Address) common.Hash { + return fst.stateFor(address).GetCodeHash(address) +} + +func (fst *ForkableState) GetCode(address common.Address) []byte { + return fst.stateFor(address).GetCode(address) +} + +func (fst *ForkableState) SetCode(address common.Address, bytes []byte) { + fst.stateFor(address).SetCode(address, bytes) +} + +func (fst *ForkableState) GetCodeSize(address common.Address) int { + return fst.stateFor(address).GetCodeSize(address) +} + +func (fst *ForkableState) AddRefund(u uint64) { + fst.selected.AddRefund(u) +} + +func (fst *ForkableState) SubRefund(u uint64) { + fst.selected.SubRefund(u) +} + +func (fst *ForkableState) GetRefund() uint64 { + return fst.selected.GetRefund() +} + +func (fst *ForkableState) GetCommittedState(address common.Address, hash common.Hash) common.Hash { + return fst.stateFor(address).GetCommittedState(address, hash) +} + +func (fst *ForkableState) GetState(address common.Address, k common.Hash) common.Hash { + return fst.stateFor(address).GetState(address, k) +} + +func (fst *ForkableState) SetState(address common.Address, k common.Hash, v common.Hash) { + fst.stateFor(address).SetState(address, k, v) +} + +func (fst *ForkableState) GetStorageRoot(addr common.Address) common.Hash { + return fst.stateFor(addr).GetStorageRoot(addr) +} + +func (fst *ForkableState) GetTransientState(addr common.Address, key common.Hash) common.Hash { + return fst.stateFor(addr).GetTransientState(addr, key) +} + +func (fst *ForkableState) SetTransientState(addr common.Address, key, value common.Hash) { + fst.stateFor(addr).SetTransientState(addr, key, value) +} + +func (fst *ForkableState) SelfDestruct(address common.Address) { + fst.stateFor(address).SelfDestruct(address) +} + +func (fst *ForkableState) HasSelfDestructed(address common.Address) bool { + return fst.stateFor(address).HasSelfDestructed(address) +} + +func (fst *ForkableState) Selfdestruct6780(address common.Address) { + fst.stateFor(address).Selfdestruct6780(address) +} + +func (fst *ForkableState) Exist(address common.Address) bool { + return fst.stateFor(address).Exist(address) +} + +func (fst *ForkableState) Empty(address common.Address) bool { + return fst.stateFor(address).Empty(address) +} + +func (fst *ForkableState) AddressInAccessList(addr common.Address) bool { + return fst.stateFor(addr).AddressInAccessList(addr) +} + +func (fst *ForkableState) SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool) { + return fst.stateFor(addr).SlotInAccessList(addr, slot) +} + +func (fst *ForkableState) AddAddressToAccessList(addr common.Address) { + fst.stateFor(addr).AddAddressToAccessList(addr) +} + +func (fst *ForkableState) AddSlotToAccessList(addr common.Address, slot common.Hash) { + fst.stateFor(addr).AddSlotToAccessList(addr, slot) +} + +func (fst *ForkableState) PointCache() *utils.PointCache { + return fst.selected.PointCache() +} + +func (fst *ForkableState) Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) { + fst.selected.Prepare(rules, sender, coinbase, dest, precompiles, txAccesses) +} + +func (fst *ForkableState) RevertToSnapshot(i int) { + fst.selected.RevertToSnapshot(i) +} + +func (fst *ForkableState) Snapshot() int { + return fst.selected.Snapshot() +} + +func (fst *ForkableState) AddLog(log *types.Log) { + fst.selected.AddLog(log) +} + +func (fst *ForkableState) AddPreimage(hash common.Hash, img []byte) { + fst.selected.AddPreimage(hash, img) +} + +func (fst *ForkableState) Witness() *stateless.Witness { + return fst.selected.Witness() +} + +func (fst *ForkableState) SetBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) { + fst.stateFor(addr).SetBalance(addr, amount, reason) +} diff --git a/op-chain-ops/script/forking/trie.go b/op-chain-ops/script/forking/trie.go new file mode 100644 index 0000000000000..3af50bad973bd --- /dev/null +++ b/op-chain-ops/script/forking/trie.go @@ -0,0 +1,223 @@ +package forking + +import ( + "errors" + "fmt" + + "github.com/holiman/uint256" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/trienode" +) + +type ForkedAccountsTrie struct { + // stateRoot that this diff is based on top of + stateRoot common.Hash + + // source to retrieve data from when it's not in the diff + src ForkSource + + diff *ExportDiff +} + +var _ state.Trie = (*ForkedAccountsTrie)(nil) + +func (f *ForkedAccountsTrie) Copy() *ForkedAccountsTrie { + return &ForkedAccountsTrie{ + stateRoot: f.stateRoot, + diff: f.diff.Copy(), + } +} + +func (f *ForkedAccountsTrie) ExportDiff() *ExportDiff { + return f.diff.Copy() +} + +func (f *ForkedAccountsTrie) HasDiff() bool { + return len(f.diff.Code) > 0 || len(f.diff.Account) > 0 +} + +// ClearDiff clears the flushed changes. This does not clear the warm state changes. +// To fully clear, first Finalise the forked state that uses this trie, and then clear the diff. +func (f *ForkedAccountsTrie) ClearDiff() { + f.diff.Clear() +} + +// ContractCode is not directly part of the vm.State interface, +// but is used by the ForkDB to retrieve the contract code. +func (f *ForkedAccountsTrie) ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) { + diffAcc, ok := f.diff.Account[addr] + if ok { + if diffAcc.CodeHash != nil && *diffAcc.CodeHash != codeHash { + return nil, fmt.Errorf("account code changed to %s, cannot get code %s of account %s", *diffAcc.CodeHash, codeHash, addr) + } + if code, ok := f.diff.Code[codeHash]; ok { + return code, nil + } + // if not in codeDiff, the actual code has not changed. + } + code, err := f.src.Code(addr) + if err != nil { + return nil, fmt.Errorf("failed to retrieve code: %w", err) + } + // sanity-check the retrieved code matches the expected codehash + if h := crypto.Keccak256Hash(code); h != codeHash { + return nil, fmt.Errorf("retrieved code of %s hashed to %s, but expected %s", addr, h, codeHash) + } + return code, nil +} + +// ContractCodeSize is not directly part of the vm.State interface, +// but is used by the ForkDB to retrieve the contract code-size. +func (f *ForkedAccountsTrie) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) { + code, err := f.ContractCode(addr, codeHash) + if err != nil { + return 0, fmt.Errorf("cannot get contract code to determine code size: %w", err) + } + return len(code), nil +} + +func (f *ForkedAccountsTrie) GetKey(bytes []byte) []byte { + panic("arbitrary key lookups on ForkedAccountsTrie are not supported") +} + +func (f *ForkedAccountsTrie) GetAccount(address common.Address) (*types.StateAccount, error) { + acc := &types.StateAccount{ + Nonce: 0, + Balance: nil, + Root: fakeRoot, + CodeHash: nil, + } + diffAcc := f.diff.Account[address] + if diffAcc != nil && diffAcc.Nonce != nil { + acc.Nonce = *diffAcc.Nonce + } else { + v, err := f.src.Nonce(address) + if err != nil { + return nil, fmt.Errorf("failed to retrieve nonce of account %s: %w", address, err) + } + acc.Nonce = v + } + if diffAcc != nil && diffAcc.Balance != nil { + acc.Balance = new(uint256.Int).Set(diffAcc.Balance) + } else { + v, err := f.src.Balance(address) + if err != nil { + return nil, fmt.Errorf("failed to retrieve balance of account %s: %w", address, err) + } + acc.Balance = new(uint256.Int).Set(v) + } + if diffAcc != nil && diffAcc.CodeHash != nil { + cpy := *diffAcc.CodeHash + acc.CodeHash = cpy.Bytes() + } else { + v, err := f.src.Code(address) + if err != nil { + return nil, fmt.Errorf("failed to retrieve code of account %s: %w", address, err) + } + acc.CodeHash = crypto.Keccak256Hash(v).Bytes() + } + return acc, nil +} + +func (f *ForkedAccountsTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) { + k := common.BytesToHash(key) + diffAcc, ok := f.diff.Account[addr] + if ok { // if there is a diff, try and see if it contains a storage diff + v, ok := diffAcc.Storage[k] + if ok { // if the storage has changed, return that change + return v.Bytes(), nil + } + } + v, err := f.src.StorageAt(addr, k) + if err != nil { + return nil, err + } + return v.Bytes(), nil +} + +func (f *ForkedAccountsTrie) UpdateAccount(address common.Address, account *types.StateAccount, codeLen int) error { + // Ignored, account contains the code details we need. + // Also see the trie.StateTrie of geth itself, which ignores this arg too. + _ = codeLen + + nonce := account.Nonce + b := account.Balance.Clone() + codeHash := common.BytesToHash(account.CodeHash) + out := &AccountDiff{ + Nonce: &nonce, + Balance: b, + Storage: nil, + CodeHash: &codeHash, + } + // preserve the storage diff + if diffAcc, ok := f.diff.Account[address]; ok { + out.Storage = diffAcc.Storage + } + f.diff.Account[address] = out + return nil +} + +func (f *ForkedAccountsTrie) UpdateStorage(addr common.Address, key, value []byte) error { + diffAcc, ok := f.diff.Account[addr] + if !ok { + diffAcc = &AccountDiff{} + f.diff.Account[addr] = diffAcc + } + if diffAcc.Storage == nil { + diffAcc.Storage = make(map[common.Hash]common.Hash) + } + k := common.BytesToHash(key) + v := common.BytesToHash(value) + diffAcc.Storage[k] = v + return nil +} + +func (f *ForkedAccountsTrie) DeleteAccount(address common.Address) error { + f.diff.Account[address] = nil + return nil +} + +func (f *ForkedAccountsTrie) DeleteStorage(addr common.Address, key []byte) error { + return f.UpdateStorage(addr, key, nil) +} + +func (f *ForkedAccountsTrie) UpdateContractCode(addr common.Address, codeHash common.Hash, code []byte) error { + diffAcc, ok := f.diff.Account[addr] + if !ok { + diffAcc = &AccountDiff{} + f.diff.Account[addr] = diffAcc + } + diffAcc.CodeHash = &codeHash + f.diff.Code[codeHash] = code + return nil +} + +func (f *ForkedAccountsTrie) Hash() common.Hash { + return f.stateRoot +} + +func (f *ForkedAccountsTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { + panic("cannot commit state-changes of a forked trie") +} + +func (f *ForkedAccountsTrie) Witness() map[string]struct{} { + panic("witness generation of a ForkedAccountsTrie is not supported") +} + +func (f *ForkedAccountsTrie) NodeIterator(startKey []byte) (trie.NodeIterator, error) { + return nil, errors.New("node iteration of a ForkedAccountsTrie is not supported") +} + +func (f *ForkedAccountsTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error { + return errors.New("proving of a ForkedAccountsTrie is not supported") +} + +func (f *ForkedAccountsTrie) IsVerkle() bool { + return false +} diff --git a/op-chain-ops/script/forking/trie_test.go b/op-chain-ops/script/forking/trie_test.go new file mode 100644 index 0000000000000..6d703814ed4d2 --- /dev/null +++ b/op-chain-ops/script/forking/trie_test.go @@ -0,0 +1,209 @@ +package forking + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/holiman/uint256" + "github.com/stretchr/testify/require" +) + +func setupTrie(t *testing.T) (*ForkedAccountsTrie, *MockForkSource) { + mockSource := new(MockForkSource) + stateRoot := common.HexToHash("0x1234") + mockSource.On("StateRoot").Return(stateRoot) + + trie := &ForkedAccountsTrie{ + stateRoot: stateRoot, + src: mockSource, + diff: NewExportDiff(), + } + return trie, mockSource +} + +func TestForkedAccountsTrie_GetAccount(t *testing.T) { + trie, mockSource := setupTrie(t) + addr := common.HexToAddress("0x1234") + + // Setup mock responses + expectedNonce := uint64(1) + expectedBalance := uint256.NewInt(100) + expectedCode := []byte{1, 2, 3, 4} + expectedCodeHash := crypto.Keccak256Hash(expectedCode) + + mockSource.On("Nonce", addr).Return(expectedNonce, nil) + mockSource.On("Balance", addr).Return(expectedBalance, nil) + mockSource.On("Code", addr).Return(expectedCode, nil) + + // Test initial account retrieval + account, err := trie.GetAccount(addr) + require.NoError(t, err) + require.Equal(t, expectedNonce, account.Nonce) + require.Equal(t, expectedBalance, uint256.NewInt(0).SetBytes(account.Balance.Bytes())) + require.Equal(t, expectedCodeHash.Bytes(), account.CodeHash) + + // Update account and verify diff + newNonce := uint64(2) + newBalance := uint256.NewInt(200) + account.Nonce = newNonce + account.Balance = newBalance + + err = trie.UpdateAccount(addr, account, 0) + require.NoError(t, err) + + // Verify updated account + updatedAccount, err := trie.GetAccount(addr) + require.NoError(t, err) + require.Equal(t, newNonce, updatedAccount.Nonce) + require.Equal(t, newBalance, uint256.NewInt(0).SetBytes(updatedAccount.Balance.Bytes())) +} + +func TestForkedAccountsTrie_Storage(t *testing.T) { + trie, mockSource := setupTrie(t) + addr := common.HexToAddress("0x1234") + key := common.HexToHash("0x1") + value := common.HexToHash("0x2") + + // Setup mock for initial storage value + mockSource.On("StorageAt", addr, key).Return(value, nil) + + // Test initial storage retrieval + storageValue, err := trie.GetStorage(addr, key.Bytes()) + require.NoError(t, err) + require.Equal(t, value.Bytes(), storageValue) + + // Update storage + newValue := common.HexToHash("0x3") + err = trie.UpdateStorage(addr, key.Bytes(), newValue.Bytes()) + require.NoError(t, err) + + // Verify updated storage + updatedValue, err := trie.GetStorage(addr, key.Bytes()) + require.NoError(t, err) + require.Equal(t, newValue.Bytes(), updatedValue) +} + +func TestForkedAccountsTrie_ContractCode(t *testing.T) { + trie, mockSource := setupTrie(t) + addr := common.HexToAddress("0x1234") + code := []byte{1, 2, 3, 4} + codeHash := crypto.Keccak256Hash(code) + + // Setup mock for code retrieval + mockSource.On("Code", addr).Return(code, nil) + + // Test initial code retrieval + retrievedCode, err := trie.ContractCode(addr, codeHash) + require.NoError(t, err) + require.Equal(t, code, retrievedCode) + + // Update code + newCode := []byte{5, 6, 7, 8} + newCodeHash := crypto.Keccak256Hash(newCode) + + err = trie.UpdateContractCode(addr, newCodeHash, newCode) + require.NoError(t, err) + + // Verify updated code + updatedCode, err := trie.ContractCode(addr, newCodeHash) + require.NoError(t, err) + require.Equal(t, newCode, updatedCode) +} + +func TestForkedAccountsTrie_DeleteAccount(t *testing.T) { + trie, _ := setupTrie(t) + addr := common.HexToAddress("0x1234") + + // Setup initial account + account := &types.StateAccount{ + Nonce: 1, + Balance: uint256.NewInt(100), + CodeHash: crypto.Keccak256([]byte{1, 2, 3, 4}), + } + + err := trie.UpdateAccount(addr, account, 0) + require.NoError(t, err) + + // Delete account + err = trie.DeleteAccount(addr) + require.NoError(t, err) + + // Verify account is marked as deleted in diff + require.Nil(t, trie.diff.Account[addr]) +} + +func TestForkedAccountsTrie_Copy(t *testing.T) { + trie, _ := setupTrie(t) + addr := common.HexToAddress("0x1234") + + // Setup some initial state + account := &types.StateAccount{ + Nonce: 1, + Balance: uint256.NewInt(100), + CodeHash: crypto.Keccak256([]byte{1, 2, 3, 4}), + } + err := trie.UpdateAccount(addr, account, 0) + require.NoError(t, err) + + // Make a copy + cpy := trie.Copy() + + // Verify copy has same state + require.Equal(t, trie.stateRoot, cpy.stateRoot) + require.Equal(t, trie.diff.Account[addr].Nonce, cpy.diff.Account[addr].Nonce) + require.True(t, trie.diff.Account[addr].Balance.Eq(cpy.diff.Account[addr].Balance)) + + // Modify copy and verify original is unchanged + newAccount := &types.StateAccount{ + Nonce: 2, + Balance: uint256.NewInt(200), + CodeHash: crypto.Keccak256([]byte{5, 6, 7, 8}), + } + err = cpy.UpdateAccount(addr, newAccount, 0) + require.NoError(t, err) + + originalAccount, err := trie.GetAccount(addr) + require.NoError(t, err) + require.Equal(t, uint64(1), originalAccount.Nonce) + require.True(t, uint256.NewInt(100).Eq(uint256.NewInt(0).SetBytes(originalAccount.Balance.Bytes()))) +} + +func TestForkedAccountsTrie_HasDiff(t *testing.T) { + trie, _ := setupTrie(t) + + // Initially no diff + require.False(t, trie.HasDiff()) + + // Add account change + addr := common.HexToAddress("0x1234") + account := &types.StateAccount{ + Nonce: 1, + Balance: uint256.NewInt(100), + CodeHash: crypto.Keccak256([]byte{1, 2, 3, 4}), + } + err := trie.UpdateAccount(addr, account, 0) + require.NoError(t, err) + + // Verify diff exists + require.True(t, trie.HasDiff()) + + // Clear diff + trie.ClearDiff() + require.False(t, trie.HasDiff()) +} + +func TestForkedAccountsTrie_UnsupportedOperations(t *testing.T) { + trie, _ := setupTrie(t) + + require.Panics(t, func() { trie.GetKey([]byte{1, 2, 3}) }) + require.Panics(t, func() { trie.Commit(false) }) + require.Panics(t, func() { trie.Witness() }) + + _, err := trie.NodeIterator(nil) + require.Error(t, err) + + err = trie.Prove(nil, nil) + require.Error(t, err) +} diff --git a/op-chain-ops/script/prank.go b/op-chain-ops/script/prank.go index b6a68f4c44b17..cdea026063a20 100644 --- a/op-chain-ops/script/prank.go +++ b/op-chain-ops/script/prank.go @@ -8,6 +8,8 @@ import ( "fmt" "math/big" + "github.com/ethereum-optimism/optimism/op-chain-ops/script/addresses" + "github.com/holiman/uint256" "github.com/ethereum/go-ethereum/common" @@ -53,7 +55,7 @@ func (h *Host) handleCaller(caller vm.ContractRef) vm.ContractRef { // apply prank, if top call-frame had set up a prank if len(h.callStack) > 0 { parentCallFrame := h.callStack[len(h.callStack)-1] - if parentCallFrame.Prank != nil && caller.Address() != VMAddr { // pranks do not apply to the cheatcode precompile + if parentCallFrame.Prank != nil && caller.Address() != addresses.VMAddr { // pranks do not apply to the cheatcode precompile if parentCallFrame.Prank.Broadcast && parentCallFrame.LastOp == vm.CREATE2 && h.useCreate2Deployer { return &prankRef{ prank: DeterministicDeployerAddress, diff --git a/op-chain-ops/script/precompile.go b/op-chain-ops/script/precompile.go index 2dcea66018834..0ac692be7c1bf 100644 --- a/op-chain-ops/script/precompile.go +++ b/op-chain-ops/script/precompile.go @@ -9,6 +9,8 @@ import ( "reflect" "strings" + "github.com/holiman/uint256" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -352,6 +354,8 @@ type ABIInt256 big.Int var abiInt256Type = typeFor[ABIInt256]() +var abiUint256Type = typeFor[uint256.Int]() + // goTypeToSolidityType converts a Go type to the solidity ABI type definition. // The "internalType" is a quirk of the Geth ABI utils, for nested structures. // Unfortunately we have to convert to string, not directly to ABI type structure, @@ -364,6 +368,9 @@ func goTypeToSolidityType(typ reflect.Type) (typeDef, internalType string, err e reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return strings.ToLower(typ.Kind().String()), "", nil case reflect.Array: + if typ.AssignableTo(abiUint256Type) { // uint256.Int underlying Go type is [4]uint64 + return "uint256", "", nil + } if typ.Elem().Kind() == reflect.Uint8 { if typ.Len() == 20 && typ.Name() == "Address" { return "address", "", nil diff --git a/op-chain-ops/script/script.go b/op-chain-ops/script/script.go index b6dfa54062302..3ce493487f77f 100644 --- a/op-chain-ops/script/script.go +++ b/op-chain-ops/script/script.go @@ -4,9 +4,11 @@ import ( "bytes" "encoding/binary" "encoding/json" + "errors" "fmt" "math/big" + "github.com/ethereum-optimism/optimism/op-chain-ops/script/addresses" "github.com/holiman/uint256" "github.com/ethereum/go-ethereum/accounts/abi" @@ -19,13 +21,13 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb/hashdb" "github.com/ethereum-optimism/optimism/op-chain-ops/foundry" + "github.com/ethereum-optimism/optimism/op-chain-ops/script/forking" "github.com/ethereum-optimism/optimism/op-chain-ops/srcmap" ) @@ -72,9 +74,12 @@ type Host struct { af *foundry.ArtifactsFS chainCfg *params.ChainConfig env *vm.EVM - state *state.StateDB - stateDB state.Database - rawDB ethdb.Database + + state *forking.ForkableState + baseState *state.StateDB + + // only known contracts may utilize cheatcodes and logging + allowedCheatcodes map[common.Address]struct{} cheatcodes *Precompile[*CheatCodesPrecompile] console *Precompile[*ConsolePrecompile] @@ -117,6 +122,7 @@ type BroadcastHook func(broadcast Broadcast) type Hooks struct { OnBroadcast BroadcastHook + OnFork ForkHook } func WithBroadcastHook(hook BroadcastHook) HostOption { @@ -125,6 +131,12 @@ func WithBroadcastHook(hook BroadcastHook) HostOption { } } +func WithForkHook(hook ForkHook) HostOption { + return func(h *Host) { + h.hooks.OnFork = hook + } +} + // WithIsolatedBroadcasts makes each broadcast clean the context, // by flushing the dirty storage changes, and preparing the ephemeral state again. // This then produces more accurate gas estimation for broadcast calls. @@ -167,7 +179,11 @@ func NewHost( srcMaps: make(map[common.Address]*srcmap.SourceMap), hooks: &Hooks{ OnBroadcast: func(broadcast Broadcast) {}, + OnFork: func(opts *ForkConfig) (forking.ForkSource, error) { + return nil, errors.New("no forking configured") + }, }, + allowedCheatcodes: make(map[common.Address]struct{}), } for _, opt := range options { @@ -212,18 +228,19 @@ func NewHost( } // Create an in-memory database, to host our temporary script state changes - h.rawDB = rawdb.NewMemoryDatabase() - h.stateDB = state.NewDatabase(triedb.NewDatabase(h.rawDB, &triedb.Config{ + rawDB := rawdb.NewMemoryDatabase() + stateDB := state.NewDatabase(triedb.NewDatabase(rawDB, &triedb.Config{ Preimages: true, // To be able to iterate the state we need the Preimages IsVerkle: false, HashDB: hashdb.Defaults, PathDB: nil, }), nil) var err error - h.state, err = state.New(types.EmptyRootHash, h.stateDB) + h.baseState, err = state.New(types.EmptyRootHash, stateDB) if err != nil { panic(fmt.Errorf("failed to create memory state db: %w", err)) } + h.state = forking.NewForkableState(h.baseState) // Initialize a block-context for the EVM to access environment variables. // The block context (after embedding inside of the EVM environment) may be mutated later. @@ -252,7 +269,7 @@ func NewHost( GasPrice: big.NewInt(0), BlobHashes: executionContext.BlobHashes, BlobFeeCap: big.NewInt(0), - AccessEvents: state.NewAccessEvents(h.stateDB.PointCache()), + AccessEvents: state.NewAccessEvents(h.baseState.PointCache()), } // Hook up the Host to capture the EVM environment changes @@ -278,6 +295,18 @@ func NewHost( return h } +// AllowCheatcodes allows the given address to utilize the cheatcodes and logging precompiles +func (h *Host) AllowCheatcodes(addr common.Address) { + h.log.Debug("Allowing cheatcodes", "address", addr, "label", h.labels[addr]) + h.allowedCheatcodes[addr] = struct{}{} +} + +// AllowedCheatcodes returns whether the given address is allowed to use cheatcodes +func (h *Host) AllowedCheatcodes(addr common.Address) bool { + _, ok := h.allowedCheatcodes[addr] + return ok +} + // EnableCheats enables the Forge/HVM cheat-codes precompile and the Hardhat-style console2 precompile. func (h *Host) EnableCheats() error { vmPrecompile, err := NewPrecompile[*CheatCodesPrecompile](&CheatCodesPrecompile{h: h}) @@ -288,8 +317,8 @@ func (h *Host) EnableCheats() error { // Solidity does EXTCODESIZE checks on functions without return-data. // We need to insert some placeholder code to prevent it from aborting calls. // Emulates Forge script: https://github.com/foundry-rs/foundry/blob/224fe9cbf76084c176dabf7d3b2edab5df1ab818/crates/evm/evm/src/executors/mod.rs#L108 - h.state.SetCode(VMAddr, []byte{0x00}) - h.precompiles[VMAddr] = h.cheatcodes + h.state.SetCode(addresses.VMAddr, []byte{0x00}) + h.precompiles[addresses.VMAddr] = h.cheatcodes consolePrecompile, err := NewPrecompile[*ConsolePrecompile](&ConsolePrecompile{ logger: h.log, @@ -299,7 +328,7 @@ func (h *Host) EnableCheats() error { return fmt.Errorf("failed to init console precompile: %w", err) } h.console = consolePrecompile - h.precompiles[ConsoleAddr] = h.console + h.precompiles[addresses.ConsoleAddr] = h.console // The Console precompile does not need bytecode, // calls all go through a console lib, which avoids the EXTCODESIZE. return nil @@ -414,7 +443,7 @@ func (h *Host) ImportAccount(addr common.Address, account types.Account) { // getPrecompile overrides any accounts during runtime, to insert special precompiles, if activated. func (h *Host) getPrecompile(rules params.Rules, original vm.PrecompiledContract, addr common.Address) vm.PrecompiledContract { if p, ok := h.precompiles[addr]; ok { - return p + return &AccessControlledPrecompile{h: h, inner: p} } return original } @@ -462,7 +491,7 @@ func (h *Host) onEnter(depth int, typ byte, from common.Address, to common.Addre if !parentCallFrame.Prank.Broadcast { return } - if to == VMAddr || to == ConsoleAddr { // no broadcasts to the cheatcode or console address + if to == addresses.VMAddr || to == addresses.ConsoleAddr { // no broadcasts to the cheatcode or console address return } @@ -561,6 +590,13 @@ func (h *Host) unwindCallstack(depth int) { func (h *Host) onOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { h.unwindCallstack(depth) scopeCtx := scope.(*vm.ScopeContext) + if scopeCtx.Contract.IsDeployment { + // If we are not yet allowed access to cheatcodes, but if the caller is, + // and if this is a contract-creation, then we are automatically granted cheatcode access. + if !h.AllowedCheatcodes(scopeCtx.Address()) && h.AllowedCheatcodes(scopeCtx.Caller()) { + h.AllowCheatcodes(scopeCtx.Address()) + } + } // Check if we are entering a new depth, add it to the call-stack if so. // We do this here, instead of onEnter, to capture an initialized scope. if len(h.callStack) == 0 || h.callStack[len(h.callStack)-1].Depth < depth { @@ -609,11 +645,11 @@ func (h *Host) onLog(ev *types.Log) { // CurrentCall returns the top of the callstack. Or zeroed if there was no call frame yet. // If zeroed, the call-frame has a nil scope context. -func (h *Host) CurrentCall() CallFrame { +func (h *Host) CurrentCall() *CallFrame { if len(h.callStack) == 0 { - return CallFrame{} + return &CallFrame{} } - return *h.callStack[len(h.callStack)-1] + return h.callStack[len(h.callStack)-1] } // MsgSender returns the msg.sender of the current active EVM call-frame, @@ -652,27 +688,35 @@ func (h *Host) SetEnvVar(key string, value string) { // After flushing the EVM state also cannot revert to a previous snapshot state: // the state should not be dumped within contract-execution that needs to revert. func (h *Host) StateDump() (*foundry.ForgeAllocs, error) { + if id, ok := h.state.ActiveFork(); ok { + return nil, fmt.Errorf("cannot state-dump while fork %s is active", id) + } + baseState := h.baseState // We have to commit the existing state to the trie, // for all the state-changes to be captured by the trie iterator. - root, err := h.state.Commit(h.env.Context.BlockNumber.Uint64(), true) + root, err := baseState.Commit(h.env.Context.BlockNumber.Uint64(), true) if err != nil { return nil, fmt.Errorf("failed to commit state: %w", err) } // We need a state object around the state DB - st, err := state.New(root, h.stateDB) + st, err := state.New(root, baseState.Database()) if err != nil { return nil, fmt.Errorf("failed to create state object for state-dumping: %w", err) } // After Commit we cannot reuse the old State, so we update the host to use the new one - h.state = st - h.env.StateDB = st + h.baseState = st + h.state.SubstituteBaseState(st) + // We use the new state object for state-dumping & future state-access, wrapped around + // the just committed trie that has all changes in it. + // I.e. the trie is committed and ready to provide all data, + // and the state is new and iterable, prepared specifically for FromState(state). var allocs foundry.ForgeAllocs allocs.FromState(st) // Sanity check we have no lingering scripts. - for i := uint64(0); i <= allocs.Accounts[ScriptDeployer].Nonce; i++ { - scriptAddr := crypto.CreateAddress(ScriptDeployer, i) + for i := uint64(0); i <= allocs.Accounts[addresses.ScriptDeployer].Nonce; i++ { + scriptAddr := crypto.CreateAddress(addresses.ScriptDeployer, i) h.log.Info("removing script from state-dump", "addr", scriptAddr, "label", h.labels[scriptAddr]) delete(allocs.Accounts, scriptAddr) } @@ -694,12 +738,12 @@ func (h *Host) StateDump() (*foundry.ForgeAllocs, error) { } // Remove the script deployer from the output - delete(allocs.Accounts, ScriptDeployer) - delete(allocs.Accounts, ForgeDeployer) + delete(allocs.Accounts, addresses.ScriptDeployer) + delete(allocs.Accounts, addresses.ForgeDeployer) // The cheatcodes VM has a placeholder bytecode, // because solidity checks if the code exists prior to regular EVM-calls to it. - delete(allocs.Accounts, VMAddr) + delete(allocs.Accounts, addresses.VMAddr) // Precompile overrides come with temporary state account placeholders. Ignore those. for addr := range h.precompiles { @@ -776,7 +820,7 @@ func (h *Host) Label(addr common.Address, label string) { // NewScriptAddress creates a new address for the ScriptDeployer account, and bumps the nonce. func (h *Host) NewScriptAddress() common.Address { - deployer := ScriptDeployer + deployer := addresses.ScriptDeployer deployNonce := h.state.GetNonce(deployer) // compute address of script contract to be deployed addr := crypto.CreateAddress(deployer, deployNonce) @@ -805,3 +849,15 @@ func (h *Host) RememberOnLabel(label, srcFile, contract string) error { }) return nil } + +func (h *Host) CreateSelectFork(opts ...ForkOption) (*big.Int, error) { + src, err := h.onFork(opts...) + if err != nil { + return nil, fmt.Errorf("failed to setup fork source: %w", err) + } + id, err := h.state.CreateSelectFork(src) + if err != nil { + return nil, fmt.Errorf("failed to create-select fork: %w", err) + } + return id.U256().ToBig(), nil +} diff --git a/op-chain-ops/script/script_test.go b/op-chain-ops/script/script_test.go index 9d029c801060b..48949347b63d2 100644 --- a/op-chain-ops/script/script_test.go +++ b/op-chain-ops/script/script_test.go @@ -2,12 +2,18 @@ package script import ( "bytes" + "context" "encoding/json" "fmt" "math/big" "strings" "testing" + "github.com/ethereum-optimism/optimism/op-chain-ops/script/addresses" + + "github.com/ethereum-optimism/optimism/op-chain-ops/script/forking" + "github.com/stretchr/testify/mock" + "github.com/holiman/uint256" "github.com/stretchr/testify/require" @@ -23,16 +29,27 @@ import ( //go:generate ./testdata/generate.sh +// MockRPCClient implements RPCClient interface for testing +type MockRPCClient struct { + mock.Mock +} + +func (m *MockRPCClient) CallContext(ctx context.Context, result any, method string, args ...any) error { + return m.Called(ctx, result, method, args).Error(0) +} + func TestScript(t *testing.T) { logger, captLog := testlog.CaptureLogger(t, log.LevelInfo) af := foundry.OpenArtifactsDir("./testdata/test-artifacts") scriptContext := DefaultContext h := NewHost(logger, af, nil, scriptContext) + require.NoError(t, h.EnableCheats()) + addr, err := h.LoadContract("ScriptExample.s.sol", "ScriptExample") require.NoError(t, err) - - require.NoError(t, h.EnableCheats()) + h.AllowCheatcodes(addr) + t.Logf("allowing %s to access cheatcodes", addr) h.SetEnvVar("EXAMPLE_BOOL", "true") input := bytes4("run()") @@ -45,19 +62,19 @@ func TestScript(t *testing.T) { require.NoError(t, h.cheatcodes.Precompile.DumpState("noop")) } +func mustEncodeStringCalldata(t *testing.T, method, input string) []byte { + packer, err := abi.JSON(strings.NewReader(fmt.Sprintf(`[{"type":"function","name":"%s","inputs":[{"type":"string","name":"input"}]}]`, method))) + require.NoError(t, err) + + data, err := packer.Pack(method, input) + require.NoError(t, err) + return data +} + func TestScriptBroadcast(t *testing.T) { logger := testlog.Logger(t, log.LevelDebug) af := foundry.OpenArtifactsDir("./testdata/test-artifacts") - mustEncodeCalldata := func(method, input string) []byte { - packer, err := abi.JSON(strings.NewReader(fmt.Sprintf(`[{"type":"function","name":"%s","inputs":[{"type":"string","name":"input"}]}]`, method))) - require.NoError(t, err) - - data, err := packer.Pack(method, input) - require.NoError(t, err) - return data - } - fooBar, err := af.ReadArtifact("ScriptExample.s.sol", "FooBar") require.NoError(t, err) @@ -74,7 +91,7 @@ func TestScriptBroadcast(t *testing.T) { { From: scriptAddr, To: scriptAddr, - Input: mustEncodeCalldata("call1", "single_call1"), + Input: mustEncodeStringCalldata(t, "call1", "single_call1"), Value: (*hexutil.U256)(uint256.NewInt(0)), GasUsed: 23421, Type: BroadcastCall, @@ -83,7 +100,7 @@ func TestScriptBroadcast(t *testing.T) { { From: coffeeAddr, To: scriptAddr, - Input: mustEncodeCalldata("call1", "startstop_call1"), + Input: mustEncodeStringCalldata(t, "call1", "startstop_call1"), Value: (*hexutil.U256)(uint256.NewInt(0)), GasUsed: 1521, Type: BroadcastCall, @@ -92,7 +109,7 @@ func TestScriptBroadcast(t *testing.T) { { From: coffeeAddr, To: scriptAddr, - Input: mustEncodeCalldata("call2", "startstop_call2"), + Input: mustEncodeStringCalldata(t, "call2", "startstop_call2"), Value: (*hexutil.U256)(uint256.NewInt(0)), GasUsed: 1565, Type: BroadcastCall, @@ -101,7 +118,7 @@ func TestScriptBroadcast(t *testing.T) { { From: common.HexToAddress("0x1234"), To: scriptAddr, - Input: mustEncodeCalldata("nested1", "nested"), + Input: mustEncodeStringCalldata(t, "nested1", "nested"), Value: (*hexutil.U256)(uint256.NewInt(0)), GasUsed: 2763, Type: BroadcastCall, @@ -142,10 +159,11 @@ func TestScriptBroadcast(t *testing.T) { broadcasts = append(broadcasts, broadcast) } h := NewHost(logger, af, nil, DefaultContext, WithBroadcastHook(hook), WithCreate2Deployer()) + require.NoError(t, h.EnableCheats()) + addr, err := h.LoadContract("ScriptExample.s.sol", "ScriptExample") require.NoError(t, err) - - require.NoError(t, h.EnableCheats()) + h.AllowCheatcodes(addr) input := bytes4("runBroadcast()") returnData, _, err := h.Call(senderAddr, addr, input[:], DefaultFoundryGasLimit, uint256.NewInt(0)) @@ -168,3 +186,163 @@ func TestScriptBroadcast(t *testing.T) { // address that will perform the send to the Create2Deployer. require.EqualValues(t, 1, h.GetNonce(cafeAddr)) } + +func TestScriptStateDump(t *testing.T) { + logger := testlog.Logger(t, log.LevelDebug) + af := foundry.OpenArtifactsDir("./testdata/test-artifacts") + + h := NewHost(logger, af, nil, DefaultContext) + require.NoError(t, h.EnableCheats()) + + addr, err := h.LoadContract("ScriptExample.s.sol", "ScriptExample") + require.NoError(t, err) + h.AllowCheatcodes(addr) + + counterStorageSlot := common.Hash{} + + dump, err := h.StateDump() + require.NoError(t, err, "dump 1") + require.Contains(t, dump.Accounts, addr, "has contract") + require.NotContains(t, dump.Accounts[addr].Storage, counterStorageSlot, "not counted yet") + + dat := mustEncodeStringCalldata(t, "call1", "call A") + returnData, _, err := h.Call(addresses.DefaultSenderAddr, addr, dat, DefaultFoundryGasLimit, uint256.NewInt(0)) + require.NoError(t, err, "call A failed: %x", string(returnData)) + + dump, err = h.StateDump() + require.NoError(t, err, "dump 2") + require.Contains(t, dump.Accounts, addr, "has contract") + require.Equal(t, dump.Accounts[addr].Storage[counterStorageSlot], common.Hash{31: 1}, "counted to 1") + + dat = mustEncodeStringCalldata(t, "call1", "call B") + returnData, _, err = h.Call(addresses.DefaultSenderAddr, addr, dat, DefaultFoundryGasLimit, uint256.NewInt(0)) + require.NoError(t, err, "call B failed: %x", string(returnData)) + + dump, err = h.StateDump() + require.NoError(t, err, "dump 3") + require.Contains(t, dump.Accounts, addr, "has contract") + require.Equal(t, dump.Accounts[addr].Storage[counterStorageSlot], common.Hash{31: 2}, "counted to 2") +} + +type forkConfig struct { + blockNum uint64 + stateRoot common.Hash + blockHash common.Hash + nonce uint64 + storageValue *big.Int + code []byte + balance uint64 +} + +func TestForkingScript(t *testing.T) { + logger := testlog.Logger(t, log.LevelInfo) + af := foundry.OpenArtifactsDir("./testdata/test-artifacts") + + forkedContract, err := af.ReadArtifact("ScriptExample.s.sol", "ForkedContract") + require.NoError(t, err) + code := forkedContract.DeployedBytecode.Object + + fork1Config := forkConfig{ + blockNum: 12345, + stateRoot: common.HexToHash("0x1111"), + blockHash: common.HexToHash("0x2222"), + nonce: 12345, + storageValue: big.NewInt(1), + code: code, + balance: 1, + } + + fork2Config := forkConfig{ + blockNum: 23456, + stateRoot: common.HexToHash("0x3333"), + blockHash: common.HexToHash("0x4444"), + nonce: 23456, + storageValue: big.NewInt(2), + code: code, + balance: 2, + } + + // Map of URL/alias to RPC client + rpcClients := map[string]*MockRPCClient{ + "fork1": setupMockRPC(fork1Config), + "fork2": setupMockRPC(fork2Config), + } + forkHook := func(opts *ForkConfig) (forking.ForkSource, error) { + client, ok := rpcClients[opts.URLOrAlias] + if !ok { + return nil, fmt.Errorf("unknown fork URL/alias: %s", opts.URLOrAlias) + } + return forking.RPCSourceByNumber(opts.URLOrAlias, client, *opts.BlockNumber) + } + + scriptContext := DefaultContext + h := NewHost(logger, af, nil, scriptContext, WithForkHook(forkHook)) + require.NoError(t, h.EnableCheats()) + + addr, err := h.LoadContract("ScriptExample.s.sol", "ForkTester") + require.NoError(t, err) + h.AllowCheatcodes(addr) + // Make this script excluded so it doesn't call the fork RPC. + h.state.MakeExcluded(addr) + t.Logf("allowing %s to access cheatcodes", addr) + + input := bytes4("run()") + returnData, _, err := h.Call(scriptContext.Sender, addr, input[:], DefaultFoundryGasLimit, uint256.NewInt(0)) + require.NoError(t, err, "call failed: %x", string(returnData)) + + for _, client := range rpcClients { + client.AssertExpectations(t) + } +} + +// setupMockRPC creates a mock RPC client with the specified fork configuration +func setupMockRPC(config forkConfig) *MockRPCClient { + mockRPC := new(MockRPCClient) + testAddr := common.HexToAddress("0x1234") + + forkArgs := []any{testAddr, config.blockHash} + + // Mock block header + mockRPC.On("CallContext", mock.Anything, mock.AnythingOfType("**forking.Header"), + "eth_getBlockByNumber", []any{hexutil.Uint64(config.blockNum), false}). + Run(func(args mock.Arguments) { + result := args.Get(1).(**forking.Header) + *result = &forking.Header{ + StateRoot: config.stateRoot, + BlockHash: config.blockHash, + } + }).Return(nil).Once() + + mockRPC.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Uint64"), + "eth_getTransactionCount", forkArgs). + Run(func(args mock.Arguments) { + result := args.Get(1).(*hexutil.Uint64) + *result = hexutil.Uint64(config.nonce) + }).Return(nil) + + // Mock balance + mockRPC.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.U256"), + "eth_getBalance", forkArgs). + Run(func(args mock.Arguments) { + result := args.Get(1).(*hexutil.U256) + *result = hexutil.U256(*uint256.NewInt(config.balance)) + }).Return(nil) + + // Mock contract code + mockRPC.On("CallContext", mock.Anything, mock.AnythingOfType("*hexutil.Bytes"), + "eth_getCode", forkArgs). + Run(func(args mock.Arguments) { + result := args.Get(1).(*hexutil.Bytes) + *result = config.code + }).Return(nil) + + // Mock storage value + mockRPC.On("CallContext", mock.Anything, mock.AnythingOfType("*common.Hash"), + "eth_getStorageAt", []any{testAddr, common.Hash{}, config.blockHash}). + Run(func(args mock.Arguments) { + result := args.Get(1).(*common.Hash) + *result = common.BigToHash(config.storageValue) + }).Return(nil) + + return mockRPC +} diff --git a/op-chain-ops/script/testdata/scripts/ScriptExample.s.sol b/op-chain-ops/script/testdata/scripts/ScriptExample.s.sol index f2f20e5ca14e9..2f636afb2be3e 100644 --- a/op-chain-ops/script/testdata/scripts/ScriptExample.s.sol +++ b/op-chain-ops/script/testdata/scripts/ScriptExample.s.sol @@ -13,15 +13,21 @@ interface Vm { function startBroadcast(address msgSender) external; function startBroadcast() external; function stopBroadcast() external; + function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); + function etch(address target, bytes calldata newRuntimeBytecode) external; + function allowCheatcodes(address account) external; + function createSelectFork(string calldata forkName, uint256 blockNumber) external returns (uint256); } // console is a minimal version of the console2 lib. library console { address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); - function _castLogPayloadViewToPure( - function(bytes memory) internal view fnIn - ) internal pure returns (function(bytes memory) internal pure fnOut) { + function _castLogPayloadViewToPure(function(bytes memory) internal view fnIn) + internal + pure + returns (function(bytes memory) internal pure fnOut) + { assembly { fnOut := fnIn } @@ -42,30 +48,29 @@ library console { } function log(string memory p0) internal pure { - _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); // nosemgrep: sol-style-use-abi-encodecall } function log(string memory p0, bool p1) internal pure { - _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); // nosemgrep: sol-style-use-abi-encodecall } function log(string memory p0, uint256 p1) internal pure { - _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); // nosemgrep: sol-style-use-abi-encodecall } function log(string memory p0, address p1) internal pure { - _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); // nosemgrep: sol-style-use-abi-encodecall } function log(string memory p0, string memory p1, string memory p2) internal pure { - _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); // nosemgrep: sol-style-use-abi-encodecall } } /// @title ScriptExample /// @notice ScriptExample is an example script. The Go forge script code tests that it can run this. contract ScriptExample { - address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); Vm internal constant vm = Vm(VM_ADDRESS); @@ -95,6 +100,13 @@ contract ScriptExample { vm.stopPrank(); this.hello("from original again"); + // vm.etch should not give cheatcode access, unless allowed to afterwards + address tmpNonceGetter = address(uint160(uint256(keccak256("temp nonce test getter")))); + vm.etch(tmpNonceGetter, vm.getDeployedCode("ScriptExample.s.sol:NonceGetter")); + vm.allowCheatcodes(tmpNonceGetter); + uint256 v = NonceGetter(tmpNonceGetter).getNonce(address(this)); + console.log("nonce from nonce getter, no explicit access required with vm.etch:", v); + console.log("done!"); } @@ -123,12 +135,12 @@ contract ScriptExample { console.log("contract deployment"); vm.broadcast(address(uint160(0x123456))); FooBar x = new FooBar(1234); - require(x.foo() == 1234); + require(x.foo() == 1234, "FooBar: foo in create is not 1234"); console.log("create 2"); vm.broadcast(address(uint160(0xcafe))); FooBar y = new FooBar{salt: bytes32(uint256(42))}(1234); - require(y.foo() == 1234); + require(y.foo() == 1234, "FooBar: foo in create2 is not 1234"); console.log("done!"); // Deploy a script without a pranked sender and check the nonce. @@ -176,3 +188,44 @@ contract FooBar { foo = v; } } + +contract NonceGetter { + address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); + Vm internal constant vm = Vm(VM_ADDRESS); + + function getNonce(address _addr) public view returns (uint256) { + return vm.getNonce(_addr); + } +} + +contract ForkedContract { + uint256 internal v; + + constructor() { + v = 1; + } + + function getValue() public view returns (uint256) { + return v; + } +} + +contract ForkTester { + address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); + Vm internal constant vm = Vm(VM_ADDRESS); + + function run() external { + address testAddr = address(uint160(0x1234)); + ForkedContract fc = ForkedContract(testAddr); + + vm.createSelectFork("fork1", 12345); + require(vm.getNonce(testAddr) == 12345, "nonce should be 12345"); + require(fc.getValue() == 1, "value should be 1"); + require(testAddr.balance == uint256(1), "balance should be 1"); + + vm.createSelectFork("fork2", 23456); + require(vm.getNonce(testAddr) == 23456, "nonce should be 12345"); + require(fc.getValue() == 2, "value should be 2"); + require(testAddr.balance == uint256(2), "balance should be 2"); + } +} \ No newline at end of file diff --git a/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/FooBar.json b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/FooBar.json index ad4ac1569433c..249588154e111 100644 --- a/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/FooBar.json +++ b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/FooBar.json @@ -1 +1 @@ -{"abi":[{"type":"constructor","inputs":[{"name":"v","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"foo","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"}],"bytecode":{"object":"0x608060405234801561001057600080fd5b506040516100b23803806100b283398101604081905261002f91610037565b600055610050565b60006020828403121561004957600080fd5b5051919050565b60548061005e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c298557814602d575b600080fd5b603560005481565b60405190815260200160405180910390f3fea164736f6c634300080f000a","sourceMap":"5902:96:0:-:0;;;5949:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5982:3;:7;5902:96;;14:184:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;-1:-1:-1;176:16:1;;14:184;-1:-1:-1;14:184:1:o;:::-;5902:96:0;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063c298557814602d575b600080fd5b603560005481565b60405190815260200160405180910390f3fea164736f6c634300080f000a","sourceMap":"5902:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5924:18;;;;;;;;;160:25:1;;;148:2;133:18;5924::0;;;;;;","linkReferences":{}},"methodIdentifiers":{"foo()":"c2985578"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"v\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"foo\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"scripts/ScriptExample.s.sol\":\"FooBar\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"scripts/ScriptExample.s.sol\":{\"keccak256\":\"0x8d1dfa41908e7ccc3a498a2a2aa51c5275bedbb904ce32d08f8598e36f896d8d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5117bb7158363cae8b9dc0508d2852692fd36172f1c699ff680afbb5acebe1f3\",\"dweb:/ipfs/QmQdahJ8SPKfJ4yea5Ge9qaj5qh1TxVffhHvaWytBaL95h\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"uint256","name":"v","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"stateMutability":"view","type":"function","name":"foo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"scripts/ScriptExample.s.sol":"FooBar"},"evmVersion":"london","libraries":{}},"sources":{"scripts/ScriptExample.s.sol":{"keccak256":"0x8d1dfa41908e7ccc3a498a2a2aa51c5275bedbb904ce32d08f8598e36f896d8d","urls":["bzz-raw://5117bb7158363cae8b9dc0508d2852692fd36172f1c699ff680afbb5acebe1f3","dweb:/ipfs/QmQdahJ8SPKfJ4yea5Ge9qaj5qh1TxVffhHvaWytBaL95h"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[{"astId":708,"contract":"scripts/ScriptExample.s.sol:FooBar","label":"foo","offset":0,"slot":"0","type":"t_uint256"}],"types":{"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}},"userdoc":{"version":1,"kind":"user"},"devdoc":{"version":1,"kind":"dev"},"ast":{"absolutePath":"scripts/ScriptExample.s.sol","id":720,"exportedSymbols":{"FooBar":[719],"ScriptExample":[706],"Vm":[55],"console":[192]},"nodeType":"SourceUnit","src":"32:5967:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","0.8",".15"]},{"id":55,"nodeType":"ContractDefinition","src":"120:616:0","nodes":[{"id":10,"nodeType":"FunctionDefinition","src":"139:91:0","nodes":[],"functionSelector":"4777f3cf","implemented":false,"kind":"function","modifiers":[],"name":"envOr","nameLocation":"148:5:0","parameters":{"id":6,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"mutability":"mutable","name":"name","nameLocation":"170:4:0","nodeType":"VariableDeclaration","scope":10,"src":"154:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":2,"name":"string","nodeType":"ElementaryTypeName","src":"154:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":5,"mutability":"mutable","name":"defaultValue","nameLocation":"181:12:0","nodeType":"VariableDeclaration","scope":10,"src":"176:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":4,"name":"bool","nodeType":"ElementaryTypeName","src":"176:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"153:41:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[{"constant":false,"id":8,"mutability":"mutable","name":"value","nameLocation":"223:5:0","nodeType":"VariableDeclaration","scope":10,"src":"218:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":7,"name":"bool","nodeType":"ElementaryTypeName","src":"218:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"217:12:0"},"scope":55,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":17,"nodeType":"FunctionDefinition","src":"235:72:0","nodes":[],"functionSelector":"2d0335ab","implemented":false,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"244:8:0","parameters":{"id":13,"nodeType":"ParameterList","parameters":[{"constant":false,"id":12,"mutability":"mutable","name":"account","nameLocation":"261:7:0","nodeType":"VariableDeclaration","scope":17,"src":"253:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":11,"name":"address","nodeType":"ElementaryTypeName","src":"253:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"252:17:0"},"returnParameters":{"id":16,"nodeType":"ParameterList","parameters":[{"constant":false,"id":15,"mutability":"mutable","name":"nonce","nameLocation":"300:5:0","nodeType":"VariableDeclaration","scope":17,"src":"293:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"},"typeName":{"id":14,"name":"uint64","nodeType":"ElementaryTypeName","src":"293:6:0","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"visibility":"internal"}],"src":"292:14:0"},"scope":55,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":27,"nodeType":"FunctionDefinition","src":"312:111:0","nodes":[],"functionSelector":"213e4198","implemented":false,"kind":"function","modifiers":[],"name":"parseJsonKeys","nameLocation":"321:13:0","parameters":{"id":22,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19,"mutability":"mutable","name":"json","nameLocation":"351:4:0","nodeType":"VariableDeclaration","scope":27,"src":"335:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":18,"name":"string","nodeType":"ElementaryTypeName","src":"335:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":21,"mutability":"mutable","name":"key","nameLocation":"373:3:0","nodeType":"VariableDeclaration","scope":27,"src":"357:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":20,"name":"string","nodeType":"ElementaryTypeName","src":"357:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"334:43:0"},"returnParameters":{"id":26,"nodeType":"ParameterList","parameters":[{"constant":false,"id":25,"mutability":"mutable","name":"keys","nameLocation":"417:4:0","nodeType":"VariableDeclaration","scope":27,"src":"401:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":23,"name":"string","nodeType":"ElementaryTypeName","src":"401:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":24,"nodeType":"ArrayTypeName","src":"401:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"src":"400:22:0"},"scope":55,"stateMutability":"pure","virtual":false,"visibility":"external"},{"id":32,"nodeType":"FunctionDefinition","src":"428:48:0","nodes":[],"functionSelector":"06447d56","implemented":false,"kind":"function","modifiers":[],"name":"startPrank","nameLocation":"437:10:0","parameters":{"id":30,"nodeType":"ParameterList","parameters":[{"constant":false,"id":29,"mutability":"mutable","name":"msgSender","nameLocation":"456:9:0","nodeType":"VariableDeclaration","scope":32,"src":"448:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":28,"name":"address","nodeType":"ElementaryTypeName","src":"448:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"447:19:0"},"returnParameters":{"id":31,"nodeType":"ParameterList","parameters":[],"src":"475:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":35,"nodeType":"FunctionDefinition","src":"481:30:0","nodes":[],"functionSelector":"90c5013b","implemented":false,"kind":"function","modifiers":[],"name":"stopPrank","nameLocation":"490:9:0","parameters":{"id":33,"nodeType":"ParameterList","parameters":[],"src":"499:2:0"},"returnParameters":{"id":34,"nodeType":"ParameterList","parameters":[],"src":"510:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":38,"nodeType":"FunctionDefinition","src":"516:30:0","nodes":[],"functionSelector":"afc98040","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"525:9:0","parameters":{"id":36,"nodeType":"ParameterList","parameters":[],"src":"534:2:0"},"returnParameters":{"id":37,"nodeType":"ParameterList","parameters":[],"src":"545:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":43,"nodeType":"FunctionDefinition","src":"551:47:0","nodes":[],"functionSelector":"e6962cdb","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"560:9:0","parameters":{"id":41,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40,"mutability":"mutable","name":"msgSender","nameLocation":"578:9:0","nodeType":"VariableDeclaration","scope":43,"src":"570:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39,"name":"address","nodeType":"ElementaryTypeName","src":"570:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"569:19:0"},"returnParameters":{"id":42,"nodeType":"ParameterList","parameters":[],"src":"597:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":48,"nodeType":"FunctionDefinition","src":"603:52:0","nodes":[],"functionSelector":"7fec2a8d","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"612:14:0","parameters":{"id":46,"nodeType":"ParameterList","parameters":[{"constant":false,"id":45,"mutability":"mutable","name":"msgSender","nameLocation":"635:9:0","nodeType":"VariableDeclaration","scope":48,"src":"627:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":44,"name":"address","nodeType":"ElementaryTypeName","src":"627:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"626:19:0"},"returnParameters":{"id":47,"nodeType":"ParameterList","parameters":[],"src":"654:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":51,"nodeType":"FunctionDefinition","src":"660:35:0","nodes":[],"functionSelector":"7fb5297f","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"669:14:0","parameters":{"id":49,"nodeType":"ParameterList","parameters":[],"src":"683:2:0"},"returnParameters":{"id":50,"nodeType":"ParameterList","parameters":[],"src":"694:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":54,"nodeType":"FunctionDefinition","src":"700:34:0","nodes":[],"functionSelector":"76eadd36","implemented":false,"kind":"function","modifiers":[],"name":"stopBroadcast","nameLocation":"709:13:0","parameters":{"id":52,"nodeType":"ParameterList","parameters":[],"src":"722:2:0"},"returnParameters":{"id":53,"nodeType":"ParameterList","parameters":[],"src":"733:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"Vm","contractDependencies":[],"contractKind":"interface","fullyImplemented":false,"linearizedBaseContracts":[55],"name":"Vm","nameLocation":"130:2:0","scope":720,"usedErrors":[]},{"id":192,"nodeType":"ContractDefinition","src":"791:1622:0","nodes":[{"id":61,"nodeType":"VariableDeclaration","src":"813:86:0","nodes":[],"constant":true,"mutability":"constant","name":"CONSOLE_ADDRESS","nameLocation":"830:15:0","scope":192,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":56,"name":"address","nodeType":"ElementaryTypeName","src":"813:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"hexValue":"307830303030303030303030303030303030303036333646366537333646366336353265366336663637","id":59,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"856:42:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"value":"0x000000000000000000636F6e736F6c652e6c6f67"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":58,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"848:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":57,"name":"address","nodeType":"ElementaryTypeName","src":"848:7:0","typeDescriptions":{}}},"id":60,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"848:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":78,"nodeType":"FunctionDefinition","src":"906:221:0","nodes":[],"body":{"id":77,"nodeType":"Block","src":"1065:62:0","nodes":[],"statements":[{"AST":{"nodeType":"YulBlock","src":"1084:37:0","statements":[{"nodeType":"YulAssignment","src":"1098:13:0","value":{"name":"fnIn","nodeType":"YulIdentifier","src":"1107:4:0"},"variableNames":[{"name":"fnOut","nodeType":"YulIdentifier","src":"1098:5:0"}]}]},"evmVersion":"london","externalReferences":[{"declaration":67,"isOffset":false,"isSlot":false,"src":"1107:4:0","valueSize":1},{"declaration":74,"isOffset":false,"isSlot":false,"src":"1098:5:0","valueSize":1}],"id":76,"nodeType":"InlineAssembly","src":"1075:46:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_castLogPayloadViewToPure","nameLocation":"915:25:0","parameters":{"id":68,"nodeType":"ParameterList","parameters":[{"constant":false,"id":67,"mutability":"mutable","name":"fnIn","nameLocation":"987:4:0","nodeType":"VariableDeclaration","scope":78,"src":"950:41:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"typeName":{"id":66,"nodeType":"FunctionTypeName","parameterTypes":{"id":64,"nodeType":"ParameterList","parameters":[{"constant":false,"id":63,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":66,"src":"959:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":62,"name":"bytes","nodeType":"ElementaryTypeName","src":"959:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"958:14:0"},"returnParameterTypes":{"id":65,"nodeType":"ParameterList","parameters":[],"src":"987:0:0"},"src":"950:41:0","stateMutability":"view","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"visibility":"internal"},"visibility":"internal"}],"src":"940:57:0"},"returnParameters":{"id":75,"nodeType":"ParameterList","parameters":[{"constant":false,"id":74,"mutability":"mutable","name":"fnOut","nameLocation":"1058:5:0","nodeType":"VariableDeclaration","scope":78,"src":"1021:42:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"typeName":{"id":73,"nodeType":"FunctionTypeName","parameterTypes":{"id":71,"nodeType":"ParameterList","parameters":[{"constant":false,"id":70,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":73,"src":"1030:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":69,"name":"bytes","nodeType":"ElementaryTypeName","src":"1030:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1029:14:0"},"returnParameterTypes":{"id":72,"nodeType":"ParameterList","parameters":[],"src":"1058:0:0"},"src":"1021:42:0","stateMutability":"pure","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"visibility":"internal"},"visibility":"internal"}],"src":"1020:44:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":90,"nodeType":"FunctionDefinition","src":"1133:133:0","nodes":[],"body":{"id":89,"nodeType":"Block","src":"1194:72:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":86,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":80,"src":"1251:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"arguments":[{"id":84,"name":"_sendLogPayloadView","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":106,"src":"1230:19:0","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}],"id":83,"name":"_castLogPayloadViewToPure","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":78,"src":"1204:25:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_function_internal_view$_t_bytes_memory_ptr_$returns$__$_$returns$_t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$_$","typeString":"function (function (bytes memory) view) pure returns (function (bytes memory) pure)"}},"id":85,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1204:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":87,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1204:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":88,"nodeType":"ExpressionStatement","src":"1204:55:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayload","nameLocation":"1142:15:0","parameters":{"id":81,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"payload","nameLocation":"1171:7:0","nodeType":"VariableDeclaration","scope":90,"src":"1158:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":79,"name":"bytes","nodeType":"ElementaryTypeName","src":"1158:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1157:22:0"},"returnParameters":{"id":82,"nodeType":"ParameterList","parameters":[],"src":"1194:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":106,"nodeType":"FunctionDefinition","src":"1272:380:0","nodes":[],"body":{"id":105,"nodeType":"Block","src":"1336:316:0","nodes":[],"statements":[{"assignments":[96],"declarations":[{"constant":false,"id":96,"mutability":"mutable","name":"payloadLength","nameLocation":"1354:13:0","nodeType":"VariableDeclaration","scope":105,"src":"1346:21:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":95,"name":"uint256","nodeType":"ElementaryTypeName","src":"1346:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":99,"initialValue":{"expression":{"id":97,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":92,"src":"1370:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":98,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1370:14:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1346:38:0"},{"assignments":[101],"declarations":[{"constant":false,"id":101,"mutability":"mutable","name":"consoleAddress","nameLocation":"1402:14:0","nodeType":"VariableDeclaration","scope":105,"src":"1394:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":100,"name":"address","nodeType":"ElementaryTypeName","src":"1394:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":103,"initialValue":{"id":102,"name":"CONSOLE_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":61,"src":"1419:15:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"1394:40:0"},{"AST":{"nodeType":"YulBlock","src":"1496:150:0","statements":[{"nodeType":"YulVariableDeclaration","src":"1510:36:0","value":{"arguments":[{"name":"payload","nodeType":"YulIdentifier","src":"1534:7:0"},{"kind":"number","nodeType":"YulLiteral","src":"1543:2:0","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1530:3:0"},"nodeType":"YulFunctionCall","src":"1530:16:0"},"variables":[{"name":"payloadStart","nodeType":"YulTypedName","src":"1514:12:0","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1559:77:0","value":{"arguments":[{"arguments":[],"functionName":{"name":"gas","nodeType":"YulIdentifier","src":"1579:3:0"},"nodeType":"YulFunctionCall","src":"1579:5:0"},{"name":"consoleAddress","nodeType":"YulIdentifier","src":"1586:14:0"},{"name":"payloadStart","nodeType":"YulIdentifier","src":"1602:12:0"},{"name":"payloadLength","nodeType":"YulIdentifier","src":"1616:13:0"},{"kind":"number","nodeType":"YulLiteral","src":"1631:1:0","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1634:1:0","type":"","value":"0"}],"functionName":{"name":"staticcall","nodeType":"YulIdentifier","src":"1568:10:0"},"nodeType":"YulFunctionCall","src":"1568:68:0"},"variables":[{"name":"r","nodeType":"YulTypedName","src":"1563:1:0","type":""}]}]},"documentation":"@solidity memory-safe-assembly","evmVersion":"london","externalReferences":[{"declaration":101,"isOffset":false,"isSlot":false,"src":"1586:14:0","valueSize":1},{"declaration":92,"isOffset":false,"isSlot":false,"src":"1534:7:0","valueSize":1},{"declaration":96,"isOffset":false,"isSlot":false,"src":"1616:13:0","valueSize":1}],"id":104,"nodeType":"InlineAssembly","src":"1487:159:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayloadView","nameLocation":"1281:19:0","parameters":{"id":93,"nodeType":"ParameterList","parameters":[{"constant":false,"id":92,"mutability":"mutable","name":"payload","nameLocation":"1314:7:0","nodeType":"VariableDeclaration","scope":106,"src":"1301:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":91,"name":"bytes","nodeType":"ElementaryTypeName","src":"1301:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1300:22:0"},"returnParameters":{"id":94,"nodeType":"ParameterList","parameters":[],"src":"1336:0:0"},"scope":192,"stateMutability":"view","virtual":false,"visibility":"private"},{"id":120,"nodeType":"FunctionDefinition","src":"1658:121:0","nodes":[],"body":{"id":119,"nodeType":"Block","src":"1703:76:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e6729","id":114,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1753:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},"value":"log(string)"},{"id":115,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":108,"src":"1768:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":112,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"1729:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":113,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"1729:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":116,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1729:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":111,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"1713:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":117,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1713:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":118,"nodeType":"ExpressionStatement","src":"1713:59:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"1667:3:0","parameters":{"id":109,"nodeType":"ParameterList","parameters":[{"constant":false,"id":108,"mutability":"mutable","name":"p0","nameLocation":"1685:2:0","nodeType":"VariableDeclaration","scope":120,"src":"1671:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":107,"name":"string","nodeType":"ElementaryTypeName","src":"1671:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"1670:18:0"},"returnParameters":{"id":110,"nodeType":"ParameterList","parameters":[],"src":"1703:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":137,"nodeType":"FunctionDefinition","src":"1785:139:0","nodes":[],"body":{"id":136,"nodeType":"Block","src":"1839:85:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c626f6f6c29","id":130,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1889:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},"value":"log(string,bool)"},{"id":131,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":122,"src":"1909:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":132,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":124,"src":"1913:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":128,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"1865:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":129,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"1865:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":133,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1865:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":127,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"1849:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":134,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1849:68:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":135,"nodeType":"ExpressionStatement","src":"1849:68:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"1794:3:0","parameters":{"id":125,"nodeType":"ParameterList","parameters":[{"constant":false,"id":122,"mutability":"mutable","name":"p0","nameLocation":"1812:2:0","nodeType":"VariableDeclaration","scope":137,"src":"1798:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":121,"name":"string","nodeType":"ElementaryTypeName","src":"1798:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":124,"mutability":"mutable","name":"p1","nameLocation":"1821:2:0","nodeType":"VariableDeclaration","scope":137,"src":"1816:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":123,"name":"bool","nodeType":"ElementaryTypeName","src":"1816:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"1797:27:0"},"returnParameters":{"id":126,"nodeType":"ParameterList","parameters":[],"src":"1839:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":154,"nodeType":"FunctionDefinition","src":"1930:145:0","nodes":[],"body":{"id":153,"nodeType":"Block","src":"1987:88:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c75696e7432353629","id":147,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2037:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},"value":"log(string,uint256)"},{"id":148,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":139,"src":"2060:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":149,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":141,"src":"2064:2:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":145,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2013:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":146,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2013:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":150,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2013:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":144,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"1997:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":151,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1997:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":152,"nodeType":"ExpressionStatement","src":"1997:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"1939:3:0","parameters":{"id":142,"nodeType":"ParameterList","parameters":[{"constant":false,"id":139,"mutability":"mutable","name":"p0","nameLocation":"1957:2:0","nodeType":"VariableDeclaration","scope":154,"src":"1943:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":138,"name":"string","nodeType":"ElementaryTypeName","src":"1943:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":141,"mutability":"mutable","name":"p1","nameLocation":"1969:2:0","nodeType":"VariableDeclaration","scope":154,"src":"1961:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":140,"name":"uint256","nodeType":"ElementaryTypeName","src":"1961:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1942:30:0"},"returnParameters":{"id":143,"nodeType":"ParameterList","parameters":[],"src":"1987:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":171,"nodeType":"FunctionDefinition","src":"2081:145:0","nodes":[],"body":{"id":170,"nodeType":"Block","src":"2138:88:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c6164647265737329","id":164,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2188:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},"value":"log(string,address)"},{"id":165,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":156,"src":"2211:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":166,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":158,"src":"2215:2:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":162,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2164:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":163,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2164:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":167,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2164:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":161,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"2148:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":168,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2148:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":169,"nodeType":"ExpressionStatement","src":"2148:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2090:3:0","parameters":{"id":159,"nodeType":"ParameterList","parameters":[{"constant":false,"id":156,"mutability":"mutable","name":"p0","nameLocation":"2108:2:0","nodeType":"VariableDeclaration","scope":171,"src":"2094:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":155,"name":"string","nodeType":"ElementaryTypeName","src":"2094:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":158,"mutability":"mutable","name":"p1","nameLocation":"2120:2:0","nodeType":"VariableDeclaration","scope":171,"src":"2112:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":157,"name":"address","nodeType":"ElementaryTypeName","src":"2112:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2093:30:0"},"returnParameters":{"id":160,"nodeType":"ParameterList","parameters":[],"src":"2138:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":191,"nodeType":"FunctionDefinition","src":"2232:179:0","nodes":[],"body":{"id":190,"nodeType":"Block","src":"2313:98:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c737472696e672c737472696e6729","id":183,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2363:27:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},"value":"log(string,string,string)"},{"id":184,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":173,"src":"2392:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":185,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":175,"src":"2396:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":186,"name":"p2","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":177,"src":"2400:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":181,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2339:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":182,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2339:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":187,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2339:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":180,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"2323:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":188,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2323:81:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":189,"nodeType":"ExpressionStatement","src":"2323:81:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2241:3:0","parameters":{"id":178,"nodeType":"ParameterList","parameters":[{"constant":false,"id":173,"mutability":"mutable","name":"p0","nameLocation":"2259:2:0","nodeType":"VariableDeclaration","scope":191,"src":"2245:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":172,"name":"string","nodeType":"ElementaryTypeName","src":"2245:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":175,"mutability":"mutable","name":"p1","nameLocation":"2277:2:0","nodeType":"VariableDeclaration","scope":191,"src":"2263:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":174,"name":"string","nodeType":"ElementaryTypeName","src":"2263:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":177,"mutability":"mutable","name":"p2","nameLocation":"2295:2:0","nodeType":"VariableDeclaration","scope":191,"src":"2281:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":176,"name":"string","nodeType":"ElementaryTypeName","src":"2281:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2244:54:0"},"returnParameters":{"id":179,"nodeType":"ParameterList","parameters":[],"src":"2313:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"}],"abstract":false,"baseContracts":[],"canonicalName":"console","contractDependencies":[],"contractKind":"library","fullyImplemented":true,"linearizedBaseContracts":[192],"name":"console","nameLocation":"799:7:0","scope":720,"usedErrors":[]},{"id":706,"nodeType":"ContractDefinition","src":"2541:3359:0","nodes":[{"id":207,"nodeType":"VariableDeclaration","src":"2571:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"2597:10:0","scope":706,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":194,"name":"address","nodeType":"ElementaryTypeName","src":"2571:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":202,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2644:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":201,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"2634:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":203,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2634:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":200,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2626:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":199,"name":"uint256","nodeType":"ElementaryTypeName","src":"2626:7:0","typeDescriptions":{}}},"id":204,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2626:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":198,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2618:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":197,"name":"uint160","nodeType":"ElementaryTypeName","src":"2618:7:0","typeDescriptions":{}}},"id":205,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2618:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":196,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2610:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":195,"name":"address","nodeType":"ElementaryTypeName","src":"2610:7:0","typeDescriptions":{}}},"id":206,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2610:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":213,"nodeType":"VariableDeclaration","src":"2671:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"2692:2:0","scope":706,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"},"typeName":{"id":209,"nodeType":"UserDefinedTypeName","pathNode":{"id":208,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":55,"src":"2671:2:0"},"referencedDeclaration":55,"src":"2671:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"value":{"arguments":[{"id":211,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":207,"src":"2700:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":210,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":55,"src":"2697:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$55_$","typeString":"type(contract Vm)"}},"id":212,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2697:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"visibility":"internal"},{"id":215,"nodeType":"VariableDeclaration","src":"2775:22:0","nodes":[],"constant":false,"functionSelector":"61bc221a","mutability":"mutable","name":"counter","nameLocation":"2790:7:0","scope":706,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":214,"name":"uint256","nodeType":"ElementaryTypeName","src":"2775:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":378,"nodeType":"FunctionDefinition","src":"2887:949:0","nodes":[],"body":{"id":377,"nodeType":"Block","src":"2909:927:0","nodes":[],"statements":[{"assignments":[220],"declarations":[{"constant":false,"id":220,"mutability":"mutable","name":"x","nameLocation":"2924:1:0","nodeType":"VariableDeclaration","scope":377,"src":"2919:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":219,"name":"bool","nodeType":"ElementaryTypeName","src":"2919:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"id":226,"initialValue":{"arguments":[{"hexValue":"4558414d504c455f424f4f4c","id":223,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2937:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},"value":"EXAMPLE_BOOL"},{"hexValue":"66616c7365","id":224,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"2953:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":221,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"2928:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":222,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"envOr","nodeType":"MemberAccess","referencedDeclaration":10,"src":"2928:8:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$_t_bool_$returns$_t_bool_$","typeString":"function (string memory,bool) view external returns (bool)"}},"id":225,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2928:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"VariableDeclarationStatement","src":"2919:40:0"},{"expression":{"arguments":[{"hexValue":"626f6f6c2076616c75652066726f6d20656e76","id":230,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2981:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},"value":"bool value from env"},{"id":231,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3004:1:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":227,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"2969:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":229,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":137,"src":"2969:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_bool_$returns$__$","typeString":"function (string memory,bool) pure"}},"id":232,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2969:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":233,"nodeType":"ExpressionStatement","src":"2969:37:0"},{"expression":{"arguments":[{"hexValue":"636f6e74726163742061646472","id":237,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3029:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},"value":"contract addr"},{"arguments":[{"id":240,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3054:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":239,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3046:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":238,"name":"address","nodeType":"ElementaryTypeName","src":"3046:7:0","typeDescriptions":{}}},"id":241,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3046:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":234,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3017:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":236,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3017:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":242,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3017:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":243,"nodeType":"ExpressionStatement","src":"3017:43:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206e6f6e6365","id":247,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3082:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},"value":"contract nonce"},{"arguments":[{"arguments":[{"id":252,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3120:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":251,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3112:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":250,"name":"address","nodeType":"ElementaryTypeName","src":"3112:7:0","typeDescriptions":{}}},"id":253,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3112:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":248,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3100:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":249,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3100:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":254,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3100:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":244,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3070:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":246,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"3070:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":255,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3070:57:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":256,"nodeType":"ExpressionStatement","src":"3070:57:0"},{"expression":{"arguments":[{"hexValue":"73656e6465722061646472","id":260,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3149:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},"value":"sender addr"},{"arguments":[{"expression":{"id":263,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3172:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":264,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3172:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":262,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3164:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":261,"name":"address","nodeType":"ElementaryTypeName","src":"3164:7:0","typeDescriptions":{}}},"id":265,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3164:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":257,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3137:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":259,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3137:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":266,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3137:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":267,"nodeType":"ExpressionStatement","src":"3137:47:0"},{"expression":{"arguments":[{"hexValue":"73656e646572206e6f6e6365","id":271,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3206:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},"value":"sender nonce"},{"arguments":[{"arguments":[{"expression":{"id":276,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3242:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":277,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3242:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":275,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3234:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":274,"name":"address","nodeType":"ElementaryTypeName","src":"3234:7:0","typeDescriptions":{}}},"id":278,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3234:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":272,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3222:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":273,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3222:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":279,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3222:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":268,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3194:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":270,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"3194:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":280,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3194:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":281,"nodeType":"ExpressionStatement","src":"3194:61:0"},{"assignments":[283],"declarations":[{"constant":false,"id":283,"mutability":"mutable","name":"json","nameLocation":"3280:4:0","nodeType":"VariableDeclaration","scope":377,"src":"3266:18:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":282,"name":"string","nodeType":"ElementaryTypeName","src":"3266:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"id":285,"initialValue":{"hexValue":"7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d","id":284,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3287:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e95522e99766888d0261f55bd1eae5e3f3e26eaf009a16e2433eafaf0a4ecdf2","typeString":"literal_string \"{\"root_key\": [{\"a\": 1, \"b\": 2}]}\""},"value":"{\"root_key\": [{\"a\": 1, \"b\": 2}]}"},"nodeType":"VariableDeclarationStatement","src":"3266:55:0"},{"assignments":[290],"declarations":[{"constant":false,"id":290,"mutability":"mutable","name":"keys","nameLocation":"3347:4:0","nodeType":"VariableDeclaration","scope":377,"src":"3331:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":288,"name":"string","nodeType":"ElementaryTypeName","src":"3331:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":289,"nodeType":"ArrayTypeName","src":"3331:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"id":296,"initialValue":{"arguments":[{"id":293,"name":"json","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":283,"src":"3371:4:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"2e726f6f745f6b65795b305d","id":294,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3377:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""},"value":".root_key[0]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""}],"expression":{"id":291,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3354:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":292,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"parseJsonKeys","nodeType":"MemberAccess","referencedDeclaration":27,"src":"3354:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$_t_array$_t_string_memory_ptr_$dyn_memory_ptr_$","typeString":"function (string memory,string memory) pure external returns (string memory[] memory)"}},"id":295,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3354:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"nodeType":"VariableDeclarationStatement","src":"3331:61:0"},{"expression":{"arguments":[{"hexValue":"6b657973","id":300,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3414:6:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},"value":"keys"},{"baseExpression":{"id":301,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":290,"src":"3422:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":303,"indexExpression":{"hexValue":"30","id":302,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"3427:1:0","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"3422:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"baseExpression":{"id":304,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":290,"src":"3431:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":306,"indexExpression":{"hexValue":"31","id":305,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"3436:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"3431:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":297,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3402:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":299,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":191,"src":"3402:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory,string memory) pure"}},"id":307,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3402:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":308,"nodeType":"ExpressionStatement","src":"3402:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c","id":312,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3461:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""},"value":"from original"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""}],"expression":{"id":309,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3450:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":311,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3450:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":313,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3450:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":314,"nodeType":"ExpressionStatement","src":"3450:27:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"30783432","id":322,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"3517:4:0","typeDescriptions":{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"},"value":"0x42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"}],"id":321,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3509:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":320,"name":"uint160","nodeType":"ElementaryTypeName","src":"3509:7:0","typeDescriptions":{}}},"id":323,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3509:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":319,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3501:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":318,"name":"address","nodeType":"ElementaryTypeName","src":"3501:7:0","typeDescriptions":{}}},"id":324,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3501:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":315,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3487:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":317,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startPrank","nodeType":"MemberAccess","referencedDeclaration":32,"src":"3487:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":325,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3487:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":326,"nodeType":"ExpressionStatement","src":"3487:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2031","id":330,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3545:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""},"value":"from prank 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""}],"expression":{"id":327,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3534:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":329,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3534:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":331,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3534:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":332,"nodeType":"ExpressionStatement","src":"3534:26:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f7065206d73672e73656e646572","id":336,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3582:25:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},"value":"parent scope msg.sender"},{"arguments":[{"expression":{"id":339,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3617:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":340,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3617:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":338,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3609:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":337,"name":"address","nodeType":"ElementaryTypeName","src":"3609:7:0","typeDescriptions":{}}},"id":341,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3609:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":333,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3570:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":335,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3570:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":342,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3570:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":343,"nodeType":"ExpressionStatement","src":"3570:59:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f706520636f6e74726163742e61646472","id":347,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3651:28:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},"value":"parent scope contract.addr"},{"arguments":[{"id":350,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3689:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":349,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3681:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":348,"name":"address","nodeType":"ElementaryTypeName","src":"3681:7:0","typeDescriptions":{}}},"id":351,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3681:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":344,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3639:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":346,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3639:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":352,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3639:56:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":353,"nodeType":"ExpressionStatement","src":"3639:56:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2032","id":357,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3716:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""},"value":"from prank 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""}],"expression":{"id":354,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3705:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":356,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3705:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":358,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3705:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":359,"nodeType":"ExpressionStatement","src":"3705:26:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":360,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3741:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":362,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopPrank","nodeType":"MemberAccess","referencedDeclaration":35,"src":"3741:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":363,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3741:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":364,"nodeType":"ExpressionStatement","src":"3741:14:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c20616761696e","id":368,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3776:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""},"value":"from original again"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""}],"expression":{"id":365,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3765:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":367,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3765:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":369,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3765:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":370,"nodeType":"ExpressionStatement","src":"3765:33:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":374,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3821:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":371,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3809:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":373,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"3809:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":375,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3809:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":376,"nodeType":"ExpressionStatement","src":"3809:20:0"}]},"documentation":{"id":216,"nodeType":"StructuredDocumentation","src":"2804:78:0","text":"@notice example function, runs through basic cheat-codes and console logs."},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"2896:3:0","parameters":{"id":217,"nodeType":"ParameterList","parameters":[],"src":"2899:2:0"},"returnParameters":{"id":218,"nodeType":"ParameterList","parameters":[],"src":"2909:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":609,"nodeType":"FunctionDefinition","src":"3903:1258:0","nodes":[],"body":{"id":608,"nodeType":"Block","src":"3934:1227:0","nodes":[],"statements":[{"expression":{"arguments":[{"hexValue":"6e6f6e6365207374617274","id":385,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3956:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},"value":"nonce start"},{"arguments":[{"arguments":[{"arguments":[{"id":392,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3999:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":391,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3991:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":390,"name":"address","nodeType":"ElementaryTypeName","src":"3991:7:0","typeDescriptions":{}}},"id":393,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3991:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":388,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3979:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":389,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3979:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":394,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3979:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":387,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3971:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":386,"name":"uint256","nodeType":"ElementaryTypeName","src":"3971:7:0","typeDescriptions":{}}},"id":395,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3971:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":382,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3944:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":384,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"3944:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":396,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3944:63:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":397,"nodeType":"ExpressionStatement","src":"3944:63:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073696e676c65","id":401,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4030:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""},"value":"testing single"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""}],"expression":{"id":398,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4018:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":400,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4018:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":402,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4018:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":403,"nodeType":"ExpressionStatement","src":"4018:29:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":404,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4057:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":406,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"4057:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":407,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4057:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":408,"nodeType":"ExpressionStatement","src":"4057:14:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c31","id":412,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4092:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""},"value":"single_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""}],"expression":{"id":409,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4081:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":411,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":648,"src":"4081:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":413,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4081:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":414,"nodeType":"ExpressionStatement","src":"4081:26:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c32","id":418,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4128:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""},"value":"single_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""}],"expression":{"id":415,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4117:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":417,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":663,"src":"4117:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":419,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4117:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":420,"nodeType":"ExpressionStatement","src":"4117:26:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073746172742f73746f70","id":424,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4166:20:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""},"value":"testing start/stop"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""}],"expression":{"id":421,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4154:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":423,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4154:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":425,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4154:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":426,"nodeType":"ExpressionStatement","src":"4154:33:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078633066666565","id":434,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4231:8:0","typeDescriptions":{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"},"value":"0xc0ffee"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"}],"id":433,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4223:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":432,"name":"uint160","nodeType":"ElementaryTypeName","src":"4223:7:0","typeDescriptions":{}}},"id":435,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4223:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":431,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4215:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":430,"name":"address","nodeType":"ElementaryTypeName","src":"4215:7:0","typeDescriptions":{}}},"id":436,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4215:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":427,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4197:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":429,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"4197:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":437,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4197:45:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":438,"nodeType":"ExpressionStatement","src":"4197:45:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c31","id":442,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4263:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""},"value":"startstop_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""}],"expression":{"id":439,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4252:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":441,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":648,"src":"4252:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":443,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4252:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":444,"nodeType":"ExpressionStatement","src":"4252:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c32","id":448,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4302:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""},"value":"startstop_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""}],"expression":{"id":445,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4291:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":447,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":663,"src":"4291:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":449,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4291:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":450,"nodeType":"ExpressionStatement","src":"4291:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f70757265","id":454,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4344:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""},"value":"startstop_pure"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""}],"expression":{"id":451,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4330:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":453,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"callPure","nodeType":"MemberAccess","referencedDeclaration":705,"src":"4330:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure external"}},"id":455,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4330:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":456,"nodeType":"ExpressionStatement","src":"4330:31:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":457,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4371:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":459,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"4371:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":460,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4371:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":461,"nodeType":"ExpressionStatement","src":"4371:18:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c33","id":465,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4410:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""},"value":"startstop_call3"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""}],"expression":{"id":462,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4399:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":464,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":648,"src":"4399:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":466,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4399:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":467,"nodeType":"ExpressionStatement","src":"4399:29:0"},{"expression":{"arguments":[{"hexValue":"74657374696e67206e6573746564","id":471,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4451:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""},"value":"testing nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""}],"expression":{"id":468,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4439:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":470,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4439:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":472,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4439:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":473,"nodeType":"ExpressionStatement","src":"4439:29:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307831323334","id":481,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4512:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":480,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4504:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":479,"name":"uint160","nodeType":"ElementaryTypeName","src":"4504:7:0","typeDescriptions":{}}},"id":482,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4504:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":478,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4496:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":477,"name":"address","nodeType":"ElementaryTypeName","src":"4496:7:0","typeDescriptions":{}}},"id":483,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4496:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":474,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4478:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":476,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"4478:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":484,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4478:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":485,"nodeType":"ExpressionStatement","src":"4478:43:0"},{"expression":{"arguments":[{"hexValue":"6e6573746564","id":489,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4544:8:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""},"value":"nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""}],"expression":{"id":486,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4531:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":488,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested1","nodeType":"MemberAccess","referencedDeclaration":678,"src":"4531:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":490,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4531:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":491,"nodeType":"ExpressionStatement","src":"4531:22:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":492,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4563:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":494,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"4563:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":495,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4563:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":496,"nodeType":"ExpressionStatement","src":"4563:18:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206465706c6f796d656e74","id":500,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4604:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""},"value":"contract deployment"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""}],"expression":{"id":497,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4592:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":499,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4592:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":501,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4592:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":502,"nodeType":"ExpressionStatement","src":"4592:34:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078313233343536","id":510,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4665:8:0","typeDescriptions":{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"},"value":"0x123456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"}],"id":509,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4657:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":508,"name":"uint160","nodeType":"ElementaryTypeName","src":"4657:7:0","typeDescriptions":{}}},"id":511,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4657:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":507,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4649:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":506,"name":"address","nodeType":"ElementaryTypeName","src":"4649:7:0","typeDescriptions":{}}},"id":512,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4649:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":503,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4636:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":505,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"4636:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":513,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4636:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":514,"nodeType":"ExpressionStatement","src":"4636:40:0"},{"assignments":[517],"declarations":[{"constant":false,"id":517,"mutability":"mutable","name":"x","nameLocation":"4693:1:0","nodeType":"VariableDeclaration","scope":608,"src":"4686:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"},"typeName":{"id":516,"nodeType":"UserDefinedTypeName","pathNode":{"id":515,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4686:6:0"},"referencedDeclaration":719,"src":"4686:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"visibility":"internal"}],"id":523,"initialValue":{"arguments":[{"hexValue":"31323334","id":521,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4708:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":520,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"4697:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":519,"nodeType":"UserDefinedTypeName","pathNode":{"id":518,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4701:6:0"},"referencedDeclaration":719,"src":"4701:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}}},"id":522,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4697:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"4686:27:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":529,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":525,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"4731:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"id":526,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":708,"src":"4731:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":527,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4731:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":528,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4742:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"4731:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"}],"id":524,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"4723:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$returns$__$","typeString":"function (bool) pure"}},"id":530,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4723:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":531,"nodeType":"ExpressionStatement","src":"4723:24:0"},{"expression":{"arguments":[{"hexValue":"6372656174652032","id":535,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4770:10:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""},"value":"create 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""}],"expression":{"id":532,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4758:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":534,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4758:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":536,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4758:23:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":537,"nodeType":"ExpressionStatement","src":"4758:23:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307863616665","id":545,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4820:6:0","typeDescriptions":{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"},"value":"0xcafe"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"}],"id":544,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4812:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":543,"name":"uint160","nodeType":"ElementaryTypeName","src":"4812:7:0","typeDescriptions":{}}},"id":546,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4812:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":542,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4804:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":541,"name":"address","nodeType":"ElementaryTypeName","src":"4804:7:0","typeDescriptions":{}}},"id":547,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4804:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":538,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4791:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":540,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"4791:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":548,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4791:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":549,"nodeType":"ExpressionStatement","src":"4791:38:0"},{"assignments":[552],"declarations":[{"constant":false,"id":552,"mutability":"mutable","name":"y","nameLocation":"4846:1:0","nodeType":"VariableDeclaration","scope":608,"src":"4839:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"},"typeName":{"id":551,"nodeType":"UserDefinedTypeName","pathNode":{"id":550,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4839:6:0"},"referencedDeclaration":719,"src":"4839:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"visibility":"internal"}],"id":566,"initialValue":{"arguments":[{"hexValue":"31323334","id":564,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4889:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":555,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"4850:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":554,"nodeType":"UserDefinedTypeName","pathNode":{"id":553,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4854:6:0"},"referencedDeclaration":719,"src":"4854:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}}},"id":563,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"names":["salt"],"nodeType":"FunctionCallOptions","options":[{"arguments":[{"arguments":[{"hexValue":"3432","id":560,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4883:2:0","typeDescriptions":{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"},"value":"42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"}],"id":559,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4875:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":558,"name":"uint256","nodeType":"ElementaryTypeName","src":"4875:7:0","typeDescriptions":{}}},"id":561,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4875:11:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":557,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4867:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":556,"name":"bytes32","nodeType":"ElementaryTypeName","src":"4867:7:0","typeDescriptions":{}}},"id":562,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4867:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"src":"4850:38:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$salt","typeString":"function (uint256) returns (contract FooBar)"}},"id":565,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4850:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"4839:55:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":572,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":568,"name":"y","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":552,"src":"4912:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"id":569,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":708,"src":"4912:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":570,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4912:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":571,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4923:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"4912:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"}],"id":567,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"4904:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$returns$__$","typeString":"function (bool) pure"}},"id":573,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4904:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":574,"nodeType":"ExpressionStatement","src":"4904:24:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":578,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4950:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":575,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4938:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":577,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4938:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":579,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4938:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":580,"nodeType":"ExpressionStatement","src":"4938:20:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":581,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"5042:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":583,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"5042:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":584,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5042:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":585,"nodeType":"ExpressionStatement","src":"5042:14:0"},{"expression":{"arguments":[{"hexValue":"31323334","id":589,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5077:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":588,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5066:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":587,"nodeType":"UserDefinedTypeName","pathNode":{"id":586,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"5070:6:0"},"referencedDeclaration":719,"src":"5070:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}}},"id":590,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5066:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"id":591,"nodeType":"ExpressionStatement","src":"5066:16:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e636520656e64","id":595,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5105:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},"value":"nonce end"},{"arguments":[{"arguments":[{"arguments":[{"id":602,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5146:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":601,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5138:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":600,"name":"address","nodeType":"ElementaryTypeName","src":"5138:7:0","typeDescriptions":{}}},"id":603,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5138:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":598,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"5126:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":599,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"5126:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":604,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5126:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":597,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5118:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":596,"name":"uint256","nodeType":"ElementaryTypeName","src":"5118:7:0","typeDescriptions":{}}},"id":605,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5118:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":592,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5093:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":594,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"5093:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":606,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5093:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":607,"nodeType":"ExpressionStatement","src":"5093:61:0"}]},"documentation":{"id":379,"nodeType":"StructuredDocumentation","src":"3842:56:0","text":"@notice example function, to test vm.broadcast with."},"functionSelector":"bef03abc","implemented":true,"kind":"function","modifiers":[],"name":"runBroadcast","nameLocation":"3912:12:0","parameters":{"id":380,"nodeType":"ParameterList","parameters":[],"src":"3924:2:0"},"returnParameters":{"id":381,"nodeType":"ParameterList","parameters":[],"src":"3934:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":633,"nodeType":"FunctionDefinition","src":"5256:143:0","nodes":[],"body":{"id":632,"nodeType":"Block","src":"5305:94:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":618,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":612,"src":"5327:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":615,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5315:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":617,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5315:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":619,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5315:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":620,"nodeType":"ExpressionStatement","src":"5315:15:0"},{"expression":{"arguments":[{"hexValue":"68656c6c6f206d73672e73656e646572","id":624,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5352:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},"value":"hello msg.sender"},{"arguments":[{"expression":{"id":627,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"5380:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":628,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"5380:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":626,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5372:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":625,"name":"address","nodeType":"ElementaryTypeName","src":"5372:7:0","typeDescriptions":{}}},"id":629,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5372:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":621,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5340:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":623,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"5340:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":630,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5340:52:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":631,"nodeType":"ExpressionStatement","src":"5340:52:0"}]},"documentation":{"id":610,"nodeType":"StructuredDocumentation","src":"5167:84:0","text":"@notice example external function, to force a CALL, and test vm.startPrank with."},"functionSelector":"a777d0dc","implemented":true,"kind":"function","modifiers":[],"name":"hello","nameLocation":"5265:5:0","parameters":{"id":613,"nodeType":"ParameterList","parameters":[{"constant":false,"id":612,"mutability":"mutable","name":"_v","nameLocation":"5287:2:0","nodeType":"VariableDeclaration","scope":633,"src":"5271:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":611,"name":"string","nodeType":"ElementaryTypeName","src":"5271:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5270:20:0"},"returnParameters":{"id":614,"nodeType":"ParameterList","parameters":[],"src":"5305:0:0"},"scope":706,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":648,"nodeType":"FunctionDefinition","src":"5405:95:0","nodes":[],"body":{"id":647,"nodeType":"Block","src":"5449:51:0","nodes":[],"statements":[{"expression":{"id":639,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5459:9:0","subExpression":{"id":638,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5459:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":640,"nodeType":"ExpressionStatement","src":"5459:9:0"},{"expression":{"arguments":[{"id":644,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":635,"src":"5490:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":641,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5478:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":643,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5478:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":645,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5478:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":646,"nodeType":"ExpressionStatement","src":"5478:15:0"}]},"functionSelector":"7e79255d","implemented":true,"kind":"function","modifiers":[],"name":"call1","nameLocation":"5414:5:0","parameters":{"id":636,"nodeType":"ParameterList","parameters":[{"constant":false,"id":635,"mutability":"mutable","name":"_v","nameLocation":"5436:2:0","nodeType":"VariableDeclaration","scope":648,"src":"5420:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":634,"name":"string","nodeType":"ElementaryTypeName","src":"5420:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5419:20:0"},"returnParameters":{"id":637,"nodeType":"ParameterList","parameters":[],"src":"5449:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":663,"nodeType":"FunctionDefinition","src":"5506:95:0","nodes":[],"body":{"id":662,"nodeType":"Block","src":"5550:51:0","nodes":[],"statements":[{"expression":{"id":654,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5560:9:0","subExpression":{"id":653,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5560:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":655,"nodeType":"ExpressionStatement","src":"5560:9:0"},{"expression":{"arguments":[{"id":659,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":650,"src":"5591:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":656,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5579:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":658,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5579:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":660,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5579:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":661,"nodeType":"ExpressionStatement","src":"5579:15:0"}]},"functionSelector":"8d3ef7ca","implemented":true,"kind":"function","modifiers":[],"name":"call2","nameLocation":"5515:5:0","parameters":{"id":651,"nodeType":"ParameterList","parameters":[{"constant":false,"id":650,"mutability":"mutable","name":"_v","nameLocation":"5537:2:0","nodeType":"VariableDeclaration","scope":663,"src":"5521:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":649,"name":"string","nodeType":"ElementaryTypeName","src":"5521:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5520:20:0"},"returnParameters":{"id":652,"nodeType":"ParameterList","parameters":[],"src":"5550:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":678,"nodeType":"FunctionDefinition","src":"5607:98:0","nodes":[],"body":{"id":677,"nodeType":"Block","src":"5653:52:0","nodes":[],"statements":[{"expression":{"id":669,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5663:9:0","subExpression":{"id":668,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5663:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":670,"nodeType":"ExpressionStatement","src":"5663:9:0"},{"expression":{"arguments":[{"id":674,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":665,"src":"5695:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":671,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5682:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":673,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested2","nodeType":"MemberAccess","referencedDeclaration":693,"src":"5682:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":675,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5682:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":676,"nodeType":"ExpressionStatement","src":"5682:16:0"}]},"functionSelector":"a76ccdfa","implemented":true,"kind":"function","modifiers":[],"name":"nested1","nameLocation":"5616:7:0","parameters":{"id":666,"nodeType":"ParameterList","parameters":[{"constant":false,"id":665,"mutability":"mutable","name":"_v","nameLocation":"5640:2:0","nodeType":"VariableDeclaration","scope":678,"src":"5624:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":664,"name":"string","nodeType":"ElementaryTypeName","src":"5624:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5623:20:0"},"returnParameters":{"id":667,"nodeType":"ParameterList","parameters":[],"src":"5653:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":693,"nodeType":"FunctionDefinition","src":"5711:97:0","nodes":[],"body":{"id":692,"nodeType":"Block","src":"5757:51:0","nodes":[],"statements":[{"expression":{"id":684,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5767:9:0","subExpression":{"id":683,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5767:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":685,"nodeType":"ExpressionStatement","src":"5767:9:0"},{"expression":{"arguments":[{"id":689,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":680,"src":"5798:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":686,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5786:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":688,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5786:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":690,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5786:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":691,"nodeType":"ExpressionStatement","src":"5786:15:0"}]},"functionSelector":"dbf1282f","implemented":true,"kind":"function","modifiers":[],"name":"nested2","nameLocation":"5720:7:0","parameters":{"id":681,"nodeType":"ParameterList","parameters":[{"constant":false,"id":680,"mutability":"mutable","name":"_v","nameLocation":"5744:2:0","nodeType":"VariableDeclaration","scope":693,"src":"5728:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":679,"name":"string","nodeType":"ElementaryTypeName","src":"5728:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5727:20:0"},"returnParameters":{"id":682,"nodeType":"ParameterList","parameters":[],"src":"5757:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":705,"nodeType":"FunctionDefinition","src":"5814:84:0","nodes":[],"body":{"id":704,"nodeType":"Block","src":"5866:32:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":701,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":695,"src":"5888:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":698,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5876:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":700,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5876:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":702,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5876:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":703,"nodeType":"ExpressionStatement","src":"5876:15:0"}]},"functionSelector":"7f8b915c","implemented":true,"kind":"function","modifiers":[],"name":"callPure","nameLocation":"5823:8:0","parameters":{"id":696,"nodeType":"ParameterList","parameters":[{"constant":false,"id":695,"mutability":"mutable","name":"_v","nameLocation":"5848:2:0","nodeType":"VariableDeclaration","scope":705,"src":"5832:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":694,"name":"string","nodeType":"ElementaryTypeName","src":"5832:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5831:20:0"},"returnParameters":{"id":697,"nodeType":"ParameterList","parameters":[],"src":"5866:0:0"},"scope":706,"stateMutability":"pure","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ScriptExample","contractDependencies":[719],"contractKind":"contract","documentation":{"id":193,"nodeType":"StructuredDocumentation","src":"2415:126:0","text":"@title ScriptExample\n @notice ScriptExample is an example script. The Go forge script code tests that it can run this."},"fullyImplemented":true,"linearizedBaseContracts":[706],"name":"ScriptExample","nameLocation":"2550:13:0","scope":720,"usedErrors":[]},{"id":719,"nodeType":"ContractDefinition","src":"5902:96:0","nodes":[{"id":708,"nodeType":"VariableDeclaration","src":"5924:18:0","nodes":[],"constant":false,"functionSelector":"c2985578","mutability":"mutable","name":"foo","nameLocation":"5939:3:0","scope":719,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":707,"name":"uint256","nodeType":"ElementaryTypeName","src":"5924:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":718,"nodeType":"FunctionDefinition","src":"5949:47:0","nodes":[],"body":{"id":717,"nodeType":"Block","src":"5972:24:0","nodes":[],"statements":[{"expression":{"id":715,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":713,"name":"foo","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":708,"src":"5982:3:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":714,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":710,"src":"5988:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"5982:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":716,"nodeType":"ExpressionStatement","src":"5982:7:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":711,"nodeType":"ParameterList","parameters":[{"constant":false,"id":710,"mutability":"mutable","name":"v","nameLocation":"5969:1:0","nodeType":"VariableDeclaration","scope":718,"src":"5961:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":709,"name":"uint256","nodeType":"ElementaryTypeName","src":"5961:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"5960:11:0"},"returnParameters":{"id":712,"nodeType":"ParameterList","parameters":[],"src":"5972:0:0"},"scope":719,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"FooBar","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[719],"name":"FooBar","nameLocation":"5911:6:0","scope":720,"usedErrors":[]}],"license":"MIT"},"id":0} \ No newline at end of file +{"abi":[{"type":"constructor","inputs":[{"name":"v","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"foo","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"}],"bytecode":{"object":"0x608060405234801561001057600080fd5b506040516100b23803806100b283398101604081905261002f91610037565b600055610050565b60006020828403121561004957600080fd5b5051919050565b60548061005e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c298557814602d575b600080fd5b603560005481565b60405190815260200160405180910390f3fea164736f6c634300080f000a","sourceMap":"7037:96:0:-:0;;;7084:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7117:3;:7;7037:96;;14:184:1;84:6;137:2;125:9;116:7;112:23;108:32;105:52;;;153:1;150;143:12;105:52;-1:-1:-1;176:16:1;;14:184;-1:-1:-1;14:184:1:o;:::-;7037:96:0;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063c298557814602d575b600080fd5b603560005481565b60405190815260200160405180910390f3fea164736f6c634300080f000a","sourceMap":"7037:96:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7059:18;;;;;;;;;160:25:1;;;148:2;133:18;7059::0;;;;;;","linkReferences":{}},"methodIdentifiers":{"foo()":"c2985578"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"v\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"foo\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"scripts/ScriptExample.s.sol\":\"FooBar\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"scripts/ScriptExample.s.sol\":{\"keccak256\":\"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28\",\"dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"uint256","name":"v","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"stateMutability":"view","type":"function","name":"foo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"scripts/ScriptExample.s.sol":"FooBar"},"evmVersion":"london","libraries":{}},"sources":{"scripts/ScriptExample.s.sol":{"keccak256":"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da","urls":["bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28","dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[{"astId":788,"contract":"scripts/ScriptExample.s.sol:FooBar","label":"foo","offset":0,"slot":"0","type":"t_uint256"}],"types":{"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}},"userdoc":{"version":1,"kind":"user"},"devdoc":{"version":1,"kind":"dev"},"ast":{"absolutePath":"scripts/ScriptExample.s.sol","id":969,"exportedSymbols":{"FooBar":[799],"ForkTester":[968],"ForkedContract":[852],"NonceGetter":[833],"ScriptExample":[786],"Vm":[83],"console":[220]},"nodeType":"SourceUnit","src":"32:8375:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","0.8",".15"]},{"id":83,"nodeType":"ContractDefinition","src":"120:969:0","nodes":[{"id":10,"nodeType":"FunctionDefinition","src":"139:91:0","nodes":[],"functionSelector":"4777f3cf","implemented":false,"kind":"function","modifiers":[],"name":"envOr","nameLocation":"148:5:0","parameters":{"id":6,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"mutability":"mutable","name":"name","nameLocation":"170:4:0","nodeType":"VariableDeclaration","scope":10,"src":"154:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":2,"name":"string","nodeType":"ElementaryTypeName","src":"154:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":5,"mutability":"mutable","name":"defaultValue","nameLocation":"181:12:0","nodeType":"VariableDeclaration","scope":10,"src":"176:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":4,"name":"bool","nodeType":"ElementaryTypeName","src":"176:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"153:41:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[{"constant":false,"id":8,"mutability":"mutable","name":"value","nameLocation":"223:5:0","nodeType":"VariableDeclaration","scope":10,"src":"218:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":7,"name":"bool","nodeType":"ElementaryTypeName","src":"218:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"217:12:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":17,"nodeType":"FunctionDefinition","src":"235:72:0","nodes":[],"functionSelector":"2d0335ab","implemented":false,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"244:8:0","parameters":{"id":13,"nodeType":"ParameterList","parameters":[{"constant":false,"id":12,"mutability":"mutable","name":"account","nameLocation":"261:7:0","nodeType":"VariableDeclaration","scope":17,"src":"253:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":11,"name":"address","nodeType":"ElementaryTypeName","src":"253:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"252:17:0"},"returnParameters":{"id":16,"nodeType":"ParameterList","parameters":[{"constant":false,"id":15,"mutability":"mutable","name":"nonce","nameLocation":"300:5:0","nodeType":"VariableDeclaration","scope":17,"src":"293:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"},"typeName":{"id":14,"name":"uint64","nodeType":"ElementaryTypeName","src":"293:6:0","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"visibility":"internal"}],"src":"292:14:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":27,"nodeType":"FunctionDefinition","src":"312:111:0","nodes":[],"functionSelector":"213e4198","implemented":false,"kind":"function","modifiers":[],"name":"parseJsonKeys","nameLocation":"321:13:0","parameters":{"id":22,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19,"mutability":"mutable","name":"json","nameLocation":"351:4:0","nodeType":"VariableDeclaration","scope":27,"src":"335:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":18,"name":"string","nodeType":"ElementaryTypeName","src":"335:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":21,"mutability":"mutable","name":"key","nameLocation":"373:3:0","nodeType":"VariableDeclaration","scope":27,"src":"357:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":20,"name":"string","nodeType":"ElementaryTypeName","src":"357:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"334:43:0"},"returnParameters":{"id":26,"nodeType":"ParameterList","parameters":[{"constant":false,"id":25,"mutability":"mutable","name":"keys","nameLocation":"417:4:0","nodeType":"VariableDeclaration","scope":27,"src":"401:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":23,"name":"string","nodeType":"ElementaryTypeName","src":"401:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":24,"nodeType":"ArrayTypeName","src":"401:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"src":"400:22:0"},"scope":83,"stateMutability":"pure","virtual":false,"visibility":"external"},{"id":32,"nodeType":"FunctionDefinition","src":"428:48:0","nodes":[],"functionSelector":"06447d56","implemented":false,"kind":"function","modifiers":[],"name":"startPrank","nameLocation":"437:10:0","parameters":{"id":30,"nodeType":"ParameterList","parameters":[{"constant":false,"id":29,"mutability":"mutable","name":"msgSender","nameLocation":"456:9:0","nodeType":"VariableDeclaration","scope":32,"src":"448:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":28,"name":"address","nodeType":"ElementaryTypeName","src":"448:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"447:19:0"},"returnParameters":{"id":31,"nodeType":"ParameterList","parameters":[],"src":"475:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":35,"nodeType":"FunctionDefinition","src":"481:30:0","nodes":[],"functionSelector":"90c5013b","implemented":false,"kind":"function","modifiers":[],"name":"stopPrank","nameLocation":"490:9:0","parameters":{"id":33,"nodeType":"ParameterList","parameters":[],"src":"499:2:0"},"returnParameters":{"id":34,"nodeType":"ParameterList","parameters":[],"src":"510:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":38,"nodeType":"FunctionDefinition","src":"516:30:0","nodes":[],"functionSelector":"afc98040","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"525:9:0","parameters":{"id":36,"nodeType":"ParameterList","parameters":[],"src":"534:2:0"},"returnParameters":{"id":37,"nodeType":"ParameterList","parameters":[],"src":"545:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":43,"nodeType":"FunctionDefinition","src":"551:47:0","nodes":[],"functionSelector":"e6962cdb","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"560:9:0","parameters":{"id":41,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40,"mutability":"mutable","name":"msgSender","nameLocation":"578:9:0","nodeType":"VariableDeclaration","scope":43,"src":"570:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39,"name":"address","nodeType":"ElementaryTypeName","src":"570:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"569:19:0"},"returnParameters":{"id":42,"nodeType":"ParameterList","parameters":[],"src":"597:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":48,"nodeType":"FunctionDefinition","src":"603:52:0","nodes":[],"functionSelector":"7fec2a8d","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"612:14:0","parameters":{"id":46,"nodeType":"ParameterList","parameters":[{"constant":false,"id":45,"mutability":"mutable","name":"msgSender","nameLocation":"635:9:0","nodeType":"VariableDeclaration","scope":48,"src":"627:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":44,"name":"address","nodeType":"ElementaryTypeName","src":"627:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"626:19:0"},"returnParameters":{"id":47,"nodeType":"ParameterList","parameters":[],"src":"654:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":51,"nodeType":"FunctionDefinition","src":"660:35:0","nodes":[],"functionSelector":"7fb5297f","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"669:14:0","parameters":{"id":49,"nodeType":"ParameterList","parameters":[],"src":"683:2:0"},"returnParameters":{"id":50,"nodeType":"ParameterList","parameters":[],"src":"694:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":54,"nodeType":"FunctionDefinition","src":"700:34:0","nodes":[],"functionSelector":"76eadd36","implemented":false,"kind":"function","modifiers":[],"name":"stopBroadcast","nameLocation":"709:13:0","parameters":{"id":52,"nodeType":"ParameterList","parameters":[],"src":"722:2:0"},"returnParameters":{"id":53,"nodeType":"ParameterList","parameters":[],"src":"733:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":61,"nodeType":"FunctionDefinition","src":"739:108:0","nodes":[],"functionSelector":"3ebf73b4","implemented":false,"kind":"function","modifiers":[],"name":"getDeployedCode","nameLocation":"748:15:0","parameters":{"id":57,"nodeType":"ParameterList","parameters":[{"constant":false,"id":56,"mutability":"mutable","name":"artifactPath","nameLocation":"780:12:0","nodeType":"VariableDeclaration","scope":61,"src":"764:28:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":55,"name":"string","nodeType":"ElementaryTypeName","src":"764:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"763:30:0"},"returnParameters":{"id":60,"nodeType":"ParameterList","parameters":[{"constant":false,"id":59,"mutability":"mutable","name":"runtimeBytecode","nameLocation":"830:15:0","nodeType":"VariableDeclaration","scope":61,"src":"817:28:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":58,"name":"bytes","nodeType":"ElementaryTypeName","src":"817:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"816:30:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":68,"nodeType":"FunctionDefinition","src":"852:74:0","nodes":[],"functionSelector":"b4d6c782","implemented":false,"kind":"function","modifiers":[],"name":"etch","nameLocation":"861:4:0","parameters":{"id":66,"nodeType":"ParameterList","parameters":[{"constant":false,"id":63,"mutability":"mutable","name":"target","nameLocation":"874:6:0","nodeType":"VariableDeclaration","scope":68,"src":"866:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":62,"name":"address","nodeType":"ElementaryTypeName","src":"866:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":65,"mutability":"mutable","name":"newRuntimeBytecode","nameLocation":"897:18:0","nodeType":"VariableDeclaration","scope":68,"src":"882:33:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":64,"name":"bytes","nodeType":"ElementaryTypeName","src":"882:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"865:51:0"},"returnParameters":{"id":67,"nodeType":"ParameterList","parameters":[],"src":"925:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":73,"nodeType":"FunctionDefinition","src":"931:51:0","nodes":[],"functionSelector":"ea060291","implemented":false,"kind":"function","modifiers":[],"name":"allowCheatcodes","nameLocation":"940:15:0","parameters":{"id":71,"nodeType":"ParameterList","parameters":[{"constant":false,"id":70,"mutability":"mutable","name":"account","nameLocation":"964:7:0","nodeType":"VariableDeclaration","scope":73,"src":"956:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":69,"name":"address","nodeType":"ElementaryTypeName","src":"956:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"955:17:0"},"returnParameters":{"id":72,"nodeType":"ParameterList","parameters":[],"src":"981:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":82,"nodeType":"FunctionDefinition","src":"987:100:0","nodes":[],"functionSelector":"71ee464d","implemented":false,"kind":"function","modifiers":[],"name":"createSelectFork","nameLocation":"996:16:0","parameters":{"id":78,"nodeType":"ParameterList","parameters":[{"constant":false,"id":75,"mutability":"mutable","name":"forkName","nameLocation":"1029:8:0","nodeType":"VariableDeclaration","scope":82,"src":"1013:24:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":74,"name":"string","nodeType":"ElementaryTypeName","src":"1013:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":77,"mutability":"mutable","name":"blockNumber","nameLocation":"1047:11:0","nodeType":"VariableDeclaration","scope":82,"src":"1039:19:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":76,"name":"uint256","nodeType":"ElementaryTypeName","src":"1039:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1012:47:0"},"returnParameters":{"id":81,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":82,"src":"1078:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":79,"name":"uint256","nodeType":"ElementaryTypeName","src":"1078:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1077:9:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"Vm","contractDependencies":[],"contractKind":"interface","fullyImplemented":false,"linearizedBaseContracts":[83],"name":"Vm","nameLocation":"130:2:0","scope":969,"usedErrors":[]},{"id":220,"nodeType":"ContractDefinition","src":"1144:1851:0","nodes":[{"id":89,"nodeType":"VariableDeclaration","src":"1166:86:0","nodes":[],"constant":true,"mutability":"constant","name":"CONSOLE_ADDRESS","nameLocation":"1183:15:0","scope":220,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":84,"name":"address","nodeType":"ElementaryTypeName","src":"1166:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"hexValue":"307830303030303030303030303030303030303036333646366537333646366336353265366336663637","id":87,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1209:42:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"value":"0x000000000000000000636F6e736F6c652e6c6f67"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":86,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":85,"name":"address","nodeType":"ElementaryTypeName","src":"1201:7:0","typeDescriptions":{}}},"id":88,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1201:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":106,"nodeType":"FunctionDefinition","src":"1259:235:0","nodes":[],"body":{"id":105,"nodeType":"Block","src":"1432:62:0","nodes":[],"statements":[{"AST":{"nodeType":"YulBlock","src":"1451:37:0","statements":[{"nodeType":"YulAssignment","src":"1465:13:0","value":{"name":"fnIn","nodeType":"YulIdentifier","src":"1474:4:0"},"variableNames":[{"name":"fnOut","nodeType":"YulIdentifier","src":"1465:5:0"}]}]},"evmVersion":"london","externalReferences":[{"declaration":95,"isOffset":false,"isSlot":false,"src":"1474:4:0","valueSize":1},{"declaration":102,"isOffset":false,"isSlot":false,"src":"1465:5:0","valueSize":1}],"id":104,"nodeType":"InlineAssembly","src":"1442:46:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_castLogPayloadViewToPure","nameLocation":"1268:25:0","parameters":{"id":96,"nodeType":"ParameterList","parameters":[{"constant":false,"id":95,"mutability":"mutable","name":"fnIn","nameLocation":"1331:4:0","nodeType":"VariableDeclaration","scope":106,"src":"1294:41:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"typeName":{"id":94,"nodeType":"FunctionTypeName","parameterTypes":{"id":92,"nodeType":"ParameterList","parameters":[{"constant":false,"id":91,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":94,"src":"1303:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":90,"name":"bytes","nodeType":"ElementaryTypeName","src":"1303:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1302:14:0"},"returnParameterTypes":{"id":93,"nodeType":"ParameterList","parameters":[],"src":"1331:0:0"},"src":"1294:41:0","stateMutability":"view","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"visibility":"internal"},"visibility":"internal"}],"src":"1293:43:0"},"returnParameters":{"id":103,"nodeType":"ParameterList","parameters":[{"constant":false,"id":102,"mutability":"mutable","name":"fnOut","nameLocation":"1421:5:0","nodeType":"VariableDeclaration","scope":106,"src":"1384:42:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"typeName":{"id":101,"nodeType":"FunctionTypeName","parameterTypes":{"id":99,"nodeType":"ParameterList","parameters":[{"constant":false,"id":98,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":101,"src":"1393:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":97,"name":"bytes","nodeType":"ElementaryTypeName","src":"1393:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1392:14:0"},"returnParameterTypes":{"id":100,"nodeType":"ParameterList","parameters":[],"src":"1421:0:0"},"src":"1384:42:0","stateMutability":"pure","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"visibility":"internal"},"visibility":"internal"}],"src":"1383:44:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":118,"nodeType":"FunctionDefinition","src":"1500:133:0","nodes":[],"body":{"id":117,"nodeType":"Block","src":"1561:72:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":114,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":108,"src":"1618:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"arguments":[{"id":112,"name":"_sendLogPayloadView","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":134,"src":"1597:19:0","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}],"id":111,"name":"_castLogPayloadViewToPure","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":106,"src":"1571:25:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_function_internal_view$_t_bytes_memory_ptr_$returns$__$_$returns$_t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$_$","typeString":"function (function (bytes memory) view) pure returns (function (bytes memory) pure)"}},"id":113,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":115,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":116,"nodeType":"ExpressionStatement","src":"1571:55:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayload","nameLocation":"1509:15:0","parameters":{"id":109,"nodeType":"ParameterList","parameters":[{"constant":false,"id":108,"mutability":"mutable","name":"payload","nameLocation":"1538:7:0","nodeType":"VariableDeclaration","scope":118,"src":"1525:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":107,"name":"bytes","nodeType":"ElementaryTypeName","src":"1525:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1524:22:0"},"returnParameters":{"id":110,"nodeType":"ParameterList","parameters":[],"src":"1561:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":134,"nodeType":"FunctionDefinition","src":"1639:380:0","nodes":[],"body":{"id":133,"nodeType":"Block","src":"1703:316:0","nodes":[],"statements":[{"assignments":[124],"declarations":[{"constant":false,"id":124,"mutability":"mutable","name":"payloadLength","nameLocation":"1721:13:0","nodeType":"VariableDeclaration","scope":133,"src":"1713:21:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":123,"name":"uint256","nodeType":"ElementaryTypeName","src":"1713:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":127,"initialValue":{"expression":{"id":125,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":120,"src":"1737:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":126,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1737:14:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1713:38:0"},{"assignments":[129],"declarations":[{"constant":false,"id":129,"mutability":"mutable","name":"consoleAddress","nameLocation":"1769:14:0","nodeType":"VariableDeclaration","scope":133,"src":"1761:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":128,"name":"address","nodeType":"ElementaryTypeName","src":"1761:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":131,"initialValue":{"id":130,"name":"CONSOLE_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":89,"src":"1786:15:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"1761:40:0"},{"AST":{"nodeType":"YulBlock","src":"1863:150:0","statements":[{"nodeType":"YulVariableDeclaration","src":"1877:36:0","value":{"arguments":[{"name":"payload","nodeType":"YulIdentifier","src":"1901:7:0"},{"kind":"number","nodeType":"YulLiteral","src":"1910:2:0","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1897:3:0"},"nodeType":"YulFunctionCall","src":"1897:16:0"},"variables":[{"name":"payloadStart","nodeType":"YulTypedName","src":"1881:12:0","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1926:77:0","value":{"arguments":[{"arguments":[],"functionName":{"name":"gas","nodeType":"YulIdentifier","src":"1946:3:0"},"nodeType":"YulFunctionCall","src":"1946:5:0"},{"name":"consoleAddress","nodeType":"YulIdentifier","src":"1953:14:0"},{"name":"payloadStart","nodeType":"YulIdentifier","src":"1969:12:0"},{"name":"payloadLength","nodeType":"YulIdentifier","src":"1983:13:0"},{"kind":"number","nodeType":"YulLiteral","src":"1998:1:0","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"2001:1:0","type":"","value":"0"}],"functionName":{"name":"staticcall","nodeType":"YulIdentifier","src":"1935:10:0"},"nodeType":"YulFunctionCall","src":"1935:68:0"},"variables":[{"name":"r","nodeType":"YulTypedName","src":"1930:1:0","type":""}]}]},"documentation":"@solidity memory-safe-assembly","evmVersion":"london","externalReferences":[{"declaration":129,"isOffset":false,"isSlot":false,"src":"1953:14:0","valueSize":1},{"declaration":120,"isOffset":false,"isSlot":false,"src":"1901:7:0","valueSize":1},{"declaration":124,"isOffset":false,"isSlot":false,"src":"1983:13:0","valueSize":1}],"id":132,"nodeType":"InlineAssembly","src":"1854:159:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayloadView","nameLocation":"1648:19:0","parameters":{"id":121,"nodeType":"ParameterList","parameters":[{"constant":false,"id":120,"mutability":"mutable","name":"payload","nameLocation":"1681:7:0","nodeType":"VariableDeclaration","scope":134,"src":"1668:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":119,"name":"bytes","nodeType":"ElementaryTypeName","src":"1668:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1667:22:0"},"returnParameters":{"id":122,"nodeType":"ParameterList","parameters":[],"src":"1703:0:0"},"scope":220,"stateMutability":"view","virtual":false,"visibility":"private"},{"id":148,"nodeType":"FunctionDefinition","src":"2025:164:0","nodes":[],"body":{"id":147,"nodeType":"Block","src":"2070:119:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e6729","id":142,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2120:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},"value":"log(string)"},{"id":143,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":136,"src":"2135:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":140,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2096:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":141,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2096:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":144,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2096:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":139,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2080:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":145,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2080:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":146,"nodeType":"ExpressionStatement","src":"2080:59:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2034:3:0","parameters":{"id":137,"nodeType":"ParameterList","parameters":[{"constant":false,"id":136,"mutability":"mutable","name":"p0","nameLocation":"2052:2:0","nodeType":"VariableDeclaration","scope":148,"src":"2038:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":135,"name":"string","nodeType":"ElementaryTypeName","src":"2038:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2037:18:0"},"returnParameters":{"id":138,"nodeType":"ParameterList","parameters":[],"src":"2070:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":165,"nodeType":"FunctionDefinition","src":"2195:182:0","nodes":[],"body":{"id":164,"nodeType":"Block","src":"2249:128:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c626f6f6c29","id":158,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2299:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},"value":"log(string,bool)"},{"id":159,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":150,"src":"2319:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":160,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":152,"src":"2323:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":156,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2275:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":157,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2275:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":161,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2275:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":155,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2259:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":162,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2259:68:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":163,"nodeType":"ExpressionStatement","src":"2259:68:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2204:3:0","parameters":{"id":153,"nodeType":"ParameterList","parameters":[{"constant":false,"id":150,"mutability":"mutable","name":"p0","nameLocation":"2222:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2208:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":149,"name":"string","nodeType":"ElementaryTypeName","src":"2208:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":152,"mutability":"mutable","name":"p1","nameLocation":"2231:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2226:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":151,"name":"bool","nodeType":"ElementaryTypeName","src":"2226:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"2207:27:0"},"returnParameters":{"id":154,"nodeType":"ParameterList","parameters":[],"src":"2249:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":182,"nodeType":"FunctionDefinition","src":"2383:188:0","nodes":[],"body":{"id":181,"nodeType":"Block","src":"2440:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c75696e7432353629","id":175,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2490:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},"value":"log(string,uint256)"},{"id":176,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":167,"src":"2513:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":177,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":169,"src":"2517:2:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":173,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2466:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":174,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2466:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":178,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2466:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":172,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2450:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":179,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2450:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":180,"nodeType":"ExpressionStatement","src":"2450:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2392:3:0","parameters":{"id":170,"nodeType":"ParameterList","parameters":[{"constant":false,"id":167,"mutability":"mutable","name":"p0","nameLocation":"2410:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2396:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":166,"name":"string","nodeType":"ElementaryTypeName","src":"2396:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":169,"mutability":"mutable","name":"p1","nameLocation":"2422:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2414:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":168,"name":"uint256","nodeType":"ElementaryTypeName","src":"2414:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"2395:30:0"},"returnParameters":{"id":171,"nodeType":"ParameterList","parameters":[],"src":"2440:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":199,"nodeType":"FunctionDefinition","src":"2577:188:0","nodes":[],"body":{"id":198,"nodeType":"Block","src":"2634:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c6164647265737329","id":192,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2684:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},"value":"log(string,address)"},{"id":193,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":184,"src":"2707:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":194,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":186,"src":"2711:2:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":190,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2660:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":191,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2660:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":195,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2660:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":189,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2644:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":196,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2644:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":197,"nodeType":"ExpressionStatement","src":"2644:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2586:3:0","parameters":{"id":187,"nodeType":"ParameterList","parameters":[{"constant":false,"id":184,"mutability":"mutable","name":"p0","nameLocation":"2604:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2590:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":183,"name":"string","nodeType":"ElementaryTypeName","src":"2590:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":186,"mutability":"mutable","name":"p1","nameLocation":"2616:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2608:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":185,"name":"address","nodeType":"ElementaryTypeName","src":"2608:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2589:30:0"},"returnParameters":{"id":188,"nodeType":"ParameterList","parameters":[],"src":"2634:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":219,"nodeType":"FunctionDefinition","src":"2771:222:0","nodes":[],"body":{"id":218,"nodeType":"Block","src":"2852:141:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c737472696e672c737472696e6729","id":211,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2902:27:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},"value":"log(string,string,string)"},{"id":212,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":201,"src":"2931:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":213,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":203,"src":"2935:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":214,"name":"p2","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":205,"src":"2939:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":209,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2878:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":210,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2878:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":215,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2878:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":208,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2862:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":216,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2862:81:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":217,"nodeType":"ExpressionStatement","src":"2862:81:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2780:3:0","parameters":{"id":206,"nodeType":"ParameterList","parameters":[{"constant":false,"id":201,"mutability":"mutable","name":"p0","nameLocation":"2798:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2784:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":200,"name":"string","nodeType":"ElementaryTypeName","src":"2784:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":203,"mutability":"mutable","name":"p1","nameLocation":"2816:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2802:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":202,"name":"string","nodeType":"ElementaryTypeName","src":"2802:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":205,"mutability":"mutable","name":"p2","nameLocation":"2834:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2820:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":204,"name":"string","nodeType":"ElementaryTypeName","src":"2820:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2783:54:0"},"returnParameters":{"id":207,"nodeType":"ParameterList","parameters":[],"src":"2852:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"}],"abstract":false,"baseContracts":[],"canonicalName":"console","contractDependencies":[],"contractKind":"library","fullyImplemented":true,"linearizedBaseContracts":[220],"name":"console","nameLocation":"1152:7:0","scope":969,"usedErrors":[]},{"id":786,"nodeType":"ContractDefinition","src":"3123:3912:0","nodes":[{"id":235,"nodeType":"VariableDeclaration","src":"3152:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"3178:10:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":222,"name":"address","nodeType":"ElementaryTypeName","src":"3152:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":230,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3225:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":229,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"3215:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":231,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3215:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":228,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3207:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":227,"name":"uint256","nodeType":"ElementaryTypeName","src":"3207:7:0","typeDescriptions":{}}},"id":232,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3207:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":226,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3199:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":225,"name":"uint160","nodeType":"ElementaryTypeName","src":"3199:7:0","typeDescriptions":{}}},"id":233,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3199:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":224,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3191:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":223,"name":"address","nodeType":"ElementaryTypeName","src":"3191:7:0","typeDescriptions":{}}},"id":234,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3191:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":241,"nodeType":"VariableDeclaration","src":"3252:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"3273:2:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":237,"nodeType":"UserDefinedTypeName","pathNode":{"id":236,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"3252:2:0"},"referencedDeclaration":83,"src":"3252:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":239,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":235,"src":"3281:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":238,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"3278:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":240,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3278:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":243,"nodeType":"VariableDeclaration","src":"3356:22:0","nodes":[],"constant":false,"functionSelector":"61bc221a","mutability":"mutable","name":"counter","nameLocation":"3371:7:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":242,"name":"uint256","nodeType":"ElementaryTypeName","src":"3356:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":456,"nodeType":"FunctionDefinition","src":"3468:1428:0","nodes":[],"body":{"id":455,"nodeType":"Block","src":"3490:1406:0","nodes":[],"statements":[{"assignments":[248],"declarations":[{"constant":false,"id":248,"mutability":"mutable","name":"x","nameLocation":"3505:1:0","nodeType":"VariableDeclaration","scope":455,"src":"3500:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":247,"name":"bool","nodeType":"ElementaryTypeName","src":"3500:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"id":254,"initialValue":{"arguments":[{"hexValue":"4558414d504c455f424f4f4c","id":251,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3518:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},"value":"EXAMPLE_BOOL"},{"hexValue":"66616c7365","id":252,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"3534:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":249,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3509:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":250,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"envOr","nodeType":"MemberAccess","referencedDeclaration":10,"src":"3509:8:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$_t_bool_$returns$_t_bool_$","typeString":"function (string memory,bool) view external returns (bool)"}},"id":253,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3509:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"VariableDeclarationStatement","src":"3500:40:0"},{"expression":{"arguments":[{"hexValue":"626f6f6c2076616c75652066726f6d20656e76","id":258,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3562:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},"value":"bool value from env"},{"id":259,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":248,"src":"3585:1:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":255,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3550:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":257,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":165,"src":"3550:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_bool_$returns$__$","typeString":"function (string memory,bool) pure"}},"id":260,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3550:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":261,"nodeType":"ExpressionStatement","src":"3550:37:0"},{"expression":{"arguments":[{"hexValue":"636f6e74726163742061646472","id":265,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3610:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},"value":"contract addr"},{"arguments":[{"id":268,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3635:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":267,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3627:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":266,"name":"address","nodeType":"ElementaryTypeName","src":"3627:7:0","typeDescriptions":{}}},"id":269,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3627:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":262,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3598:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":264,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3598:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":270,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3598:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":271,"nodeType":"ExpressionStatement","src":"3598:43:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206e6f6e6365","id":275,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3663:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},"value":"contract nonce"},{"arguments":[{"arguments":[{"id":280,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3701:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":279,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3693:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":278,"name":"address","nodeType":"ElementaryTypeName","src":"3693:7:0","typeDescriptions":{}}},"id":281,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3693:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":276,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3681:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":277,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3681:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":282,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3681:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":272,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3651:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":274,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3651:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":283,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3651:57:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":284,"nodeType":"ExpressionStatement","src":"3651:57:0"},{"expression":{"arguments":[{"hexValue":"73656e6465722061646472","id":288,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3730:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},"value":"sender addr"},{"arguments":[{"expression":{"id":291,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3753:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":292,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3753:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":290,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3745:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":289,"name":"address","nodeType":"ElementaryTypeName","src":"3745:7:0","typeDescriptions":{}}},"id":293,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3745:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":285,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3718:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":287,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3718:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":294,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3718:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":295,"nodeType":"ExpressionStatement","src":"3718:47:0"},{"expression":{"arguments":[{"hexValue":"73656e646572206e6f6e6365","id":299,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3787:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},"value":"sender nonce"},{"arguments":[{"arguments":[{"expression":{"id":304,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3823:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":305,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3823:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":303,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3815:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":302,"name":"address","nodeType":"ElementaryTypeName","src":"3815:7:0","typeDescriptions":{}}},"id":306,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3815:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":300,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3803:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":301,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3803:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":307,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3803:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":296,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3775:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":298,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3775:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":308,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3775:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":309,"nodeType":"ExpressionStatement","src":"3775:61:0"},{"assignments":[311],"declarations":[{"constant":false,"id":311,"mutability":"mutable","name":"json","nameLocation":"3861:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3847:18:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":310,"name":"string","nodeType":"ElementaryTypeName","src":"3847:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"id":313,"initialValue":{"hexValue":"7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d","id":312,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3868:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e95522e99766888d0261f55bd1eae5e3f3e26eaf009a16e2433eafaf0a4ecdf2","typeString":"literal_string \"{\"root_key\": [{\"a\": 1, \"b\": 2}]}\""},"value":"{\"root_key\": [{\"a\": 1, \"b\": 2}]}"},"nodeType":"VariableDeclarationStatement","src":"3847:55:0"},{"assignments":[318],"declarations":[{"constant":false,"id":318,"mutability":"mutable","name":"keys","nameLocation":"3928:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3912:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":316,"name":"string","nodeType":"ElementaryTypeName","src":"3912:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":317,"nodeType":"ArrayTypeName","src":"3912:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"id":324,"initialValue":{"arguments":[{"id":321,"name":"json","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":311,"src":"3952:4:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"2e726f6f745f6b65795b305d","id":322,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3958:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""},"value":".root_key[0]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""}],"expression":{"id":319,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3935:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":320,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"parseJsonKeys","nodeType":"MemberAccess","referencedDeclaration":27,"src":"3935:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$_t_array$_t_string_memory_ptr_$dyn_memory_ptr_$","typeString":"function (string memory,string memory) pure external returns (string memory[] memory)"}},"id":323,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3935:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"nodeType":"VariableDeclarationStatement","src":"3912:61:0"},{"expression":{"arguments":[{"hexValue":"6b657973","id":328,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3995:6:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},"value":"keys"},{"baseExpression":{"id":329,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4003:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":331,"indexExpression":{"hexValue":"30","id":330,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4008:1:0","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4003:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"baseExpression":{"id":332,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4012:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":334,"indexExpression":{"hexValue":"31","id":333,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4017:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4012:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":325,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3983:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":327,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":219,"src":"3983:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory,string memory) pure"}},"id":335,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3983:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":336,"nodeType":"ExpressionStatement","src":"3983:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c","id":340,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4042:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""},"value":"from original"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""}],"expression":{"id":337,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4031:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":339,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4031:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":341,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4031:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":342,"nodeType":"ExpressionStatement","src":"4031:27:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"30783432","id":350,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4098:4:0","typeDescriptions":{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"},"value":"0x42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"}],"id":349,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4090:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":348,"name":"uint160","nodeType":"ElementaryTypeName","src":"4090:7:0","typeDescriptions":{}}},"id":351,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4090:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":347,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4082:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":346,"name":"address","nodeType":"ElementaryTypeName","src":"4082:7:0","typeDescriptions":{}}},"id":352,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4082:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":343,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4068:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":345,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startPrank","nodeType":"MemberAccess","referencedDeclaration":32,"src":"4068:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":353,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4068:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":354,"nodeType":"ExpressionStatement","src":"4068:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2031","id":358,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4126:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""},"value":"from prank 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""}],"expression":{"id":355,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4115:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":357,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4115:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":359,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4115:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":360,"nodeType":"ExpressionStatement","src":"4115:26:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f7065206d73672e73656e646572","id":364,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4163:25:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},"value":"parent scope msg.sender"},{"arguments":[{"expression":{"id":367,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"4198:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":368,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"4198:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":366,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4190:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":365,"name":"address","nodeType":"ElementaryTypeName","src":"4190:7:0","typeDescriptions":{}}},"id":369,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4190:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":361,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4151:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":363,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4151:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":370,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4151:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":371,"nodeType":"ExpressionStatement","src":"4151:59:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f706520636f6e74726163742e61646472","id":375,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4232:28:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},"value":"parent scope contract.addr"},{"arguments":[{"id":378,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4270:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":377,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4262:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":376,"name":"address","nodeType":"ElementaryTypeName","src":"4262:7:0","typeDescriptions":{}}},"id":379,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4262:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":372,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4220:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":374,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4220:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":380,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4220:56:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":381,"nodeType":"ExpressionStatement","src":"4220:56:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2032","id":385,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4297:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""},"value":"from prank 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""}],"expression":{"id":382,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4286:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":384,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4286:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":386,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4286:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":387,"nodeType":"ExpressionStatement","src":"4286:26:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":388,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4322:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":390,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopPrank","nodeType":"MemberAccess","referencedDeclaration":35,"src":"4322:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":391,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4322:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":392,"nodeType":"ExpressionStatement","src":"4322:14:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c20616761696e","id":396,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4357:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""},"value":"from original again"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""}],"expression":{"id":393,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4346:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":395,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4346:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":397,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4346:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":398,"nodeType":"ExpressionStatement","src":"4346:33:0"},{"assignments":[400],"declarations":[{"constant":false,"id":400,"mutability":"mutable","name":"tmpNonceGetter","nameLocation":"4480:14:0","nodeType":"VariableDeclaration","scope":455,"src":"4472:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":399,"name":"address","nodeType":"ElementaryTypeName","src":"4472:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":413,"initialValue":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"74656d70206e6f6e6365207465737420676574746572","id":408,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4531:24:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""},"value":"temp nonce test getter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""}],"id":407,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"4521:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":409,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4521:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":406,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4513:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":405,"name":"uint256","nodeType":"ElementaryTypeName","src":"4513:7:0","typeDescriptions":{}}},"id":410,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4513:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":404,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4505:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":403,"name":"uint160","nodeType":"ElementaryTypeName","src":"4505:7:0","typeDescriptions":{}}},"id":411,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4505:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":402,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4497:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":401,"name":"address","nodeType":"ElementaryTypeName","src":"4497:7:0","typeDescriptions":{}}},"id":412,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4497:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"4472:87:0"},{"expression":{"arguments":[{"id":417,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4577:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"arguments":[{"hexValue":"5363726970744578616d706c652e732e736f6c3a4e6f6e6365476574746572","id":420,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4612:33:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""},"value":"ScriptExample.s.sol:NonceGetter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""}],"expression":{"id":418,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4593:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":419,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getDeployedCode","nodeType":"MemberAccess","referencedDeclaration":61,"src":"4593:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) view external returns (bytes memory)"}},"id":421,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4593:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"expression":{"id":414,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4569:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":416,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"etch","nodeType":"MemberAccess","referencedDeclaration":68,"src":"4569:7:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$_t_bytes_memory_ptr_$returns$__$","typeString":"function (address,bytes memory) external"}},"id":422,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4569:78:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":423,"nodeType":"ExpressionStatement","src":"4569:78:0"},{"expression":{"arguments":[{"id":427,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4676:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":424,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4657:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":426,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"allowCheatcodes","nodeType":"MemberAccess","referencedDeclaration":73,"src":"4657:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":428,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4657:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":429,"nodeType":"ExpressionStatement","src":"4657:34:0"},{"assignments":[431],"declarations":[{"constant":false,"id":431,"mutability":"mutable","name":"v","nameLocation":"4709:1:0","nodeType":"VariableDeclaration","scope":455,"src":"4701:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":430,"name":"uint256","nodeType":"ElementaryTypeName","src":"4701:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":441,"initialValue":{"arguments":[{"arguments":[{"id":438,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4758:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":437,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4750:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":436,"name":"address","nodeType":"ElementaryTypeName","src":"4750:7:0","typeDescriptions":{}}},"id":439,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4750:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"arguments":[{"id":433,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4725:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":432,"name":"NonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":833,"src":"4713:11:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_NonceGetter_$833_$","typeString":"type(contract NonceGetter)"}},"id":434,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_NonceGetter_$833","typeString":"contract NonceGetter"}},"id":435,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":832,"src":"4713:36:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint256_$","typeString":"function (address) view external returns (uint256)"}},"id":440,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"4701:63:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e63652066726f6d206e6f6e6365206765747465722c206e6f206578706c6963697420616363657373207265717569726564207769746820766d2e657463683a","id":445,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4786:68:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},"value":"nonce from nonce getter, no explicit access required with vm.etch:"},{"id":446,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":431,"src":"4856:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":442,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4774:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":444,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"4774:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":447,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4774:84:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":448,"nodeType":"ExpressionStatement","src":"4774:84:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":452,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4881:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":449,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4869:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":451,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"4869:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":453,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4869:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":454,"nodeType":"ExpressionStatement","src":"4869:20:0"}]},"documentation":{"id":244,"nodeType":"StructuredDocumentation","src":"3385:78:0","text":"@notice example function, runs through basic cheat-codes and console logs."},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"3477:3:0","parameters":{"id":245,"nodeType":"ParameterList","parameters":[],"src":"3480:2:0"},"returnParameters":{"id":246,"nodeType":"ParameterList","parameters":[],"src":"3490:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":689,"nodeType":"FunctionDefinition","src":"4963:1333:0","nodes":[],"body":{"id":688,"nodeType":"Block","src":"4994:1302:0","nodes":[],"statements":[{"expression":{"arguments":[{"hexValue":"6e6f6e6365207374617274","id":463,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5016:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},"value":"nonce start"},{"arguments":[{"arguments":[{"arguments":[{"id":470,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5059:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":469,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5051:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":468,"name":"address","nodeType":"ElementaryTypeName","src":"5051:7:0","typeDescriptions":{}}},"id":471,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5051:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":466,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5039:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":467,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"5039:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":472,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5039:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":465,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5031:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":464,"name":"uint256","nodeType":"ElementaryTypeName","src":"5031:7:0","typeDescriptions":{}}},"id":473,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5031:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":460,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5004:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":462,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"5004:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":474,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5004:63:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":475,"nodeType":"ExpressionStatement","src":"5004:63:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073696e676c65","id":479,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5090:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""},"value":"testing single"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""}],"expression":{"id":476,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5078:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":478,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5078:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":480,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5078:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":481,"nodeType":"ExpressionStatement","src":"5078:29:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":482,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5117:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":484,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"5117:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":485,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5117:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":486,"nodeType":"ExpressionStatement","src":"5117:14:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c31","id":490,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5152:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""},"value":"single_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""}],"expression":{"id":487,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5141:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":489,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5141:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":491,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5141:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":492,"nodeType":"ExpressionStatement","src":"5141:26:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c32","id":496,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5188:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""},"value":"single_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""}],"expression":{"id":493,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5177:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":495,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5177:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":497,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5177:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":498,"nodeType":"ExpressionStatement","src":"5177:26:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073746172742f73746f70","id":502,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5226:20:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""},"value":"testing start/stop"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""}],"expression":{"id":499,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5214:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":501,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5214:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":503,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5214:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":504,"nodeType":"ExpressionStatement","src":"5214:33:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078633066666565","id":512,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5291:8:0","typeDescriptions":{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"},"value":"0xc0ffee"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"}],"id":511,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5283:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":510,"name":"uint160","nodeType":"ElementaryTypeName","src":"5283:7:0","typeDescriptions":{}}},"id":513,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5283:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":509,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5275:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":508,"name":"address","nodeType":"ElementaryTypeName","src":"5275:7:0","typeDescriptions":{}}},"id":514,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5275:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":505,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5257:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":507,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5257:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":515,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5257:45:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":516,"nodeType":"ExpressionStatement","src":"5257:45:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c31","id":520,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5323:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""},"value":"startstop_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""}],"expression":{"id":517,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5312:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":519,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5312:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":521,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5312:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":522,"nodeType":"ExpressionStatement","src":"5312:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c32","id":526,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5362:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""},"value":"startstop_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""}],"expression":{"id":523,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5351:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":525,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5351:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":527,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5351:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":528,"nodeType":"ExpressionStatement","src":"5351:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f70757265","id":532,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5404:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""},"value":"startstop_pure"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""}],"expression":{"id":529,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5390:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":531,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"callPure","nodeType":"MemberAccess","referencedDeclaration":785,"src":"5390:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure external"}},"id":533,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5390:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":534,"nodeType":"ExpressionStatement","src":"5390:31:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":535,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5431:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":537,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5431:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":538,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5431:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":539,"nodeType":"ExpressionStatement","src":"5431:18:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c33","id":543,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5470:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""},"value":"startstop_call3"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""}],"expression":{"id":540,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5459:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":542,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5459:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":544,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5459:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":545,"nodeType":"ExpressionStatement","src":"5459:29:0"},{"expression":{"arguments":[{"hexValue":"74657374696e67206e6573746564","id":549,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5511:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""},"value":"testing nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""}],"expression":{"id":546,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5499:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":548,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5499:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":550,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5499:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":551,"nodeType":"ExpressionStatement","src":"5499:29:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307831323334","id":559,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5572:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":558,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5564:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":557,"name":"uint160","nodeType":"ElementaryTypeName","src":"5564:7:0","typeDescriptions":{}}},"id":560,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5564:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":556,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5556:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":555,"name":"address","nodeType":"ElementaryTypeName","src":"5556:7:0","typeDescriptions":{}}},"id":561,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5556:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":552,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5538:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":554,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5538:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":562,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5538:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":563,"nodeType":"ExpressionStatement","src":"5538:43:0"},{"expression":{"arguments":[{"hexValue":"6e6573746564","id":567,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5604:8:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""},"value":"nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""}],"expression":{"id":564,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5591:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":566,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested1","nodeType":"MemberAccess","referencedDeclaration":758,"src":"5591:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":568,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5591:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":569,"nodeType":"ExpressionStatement","src":"5591:22:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":570,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5623:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":572,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5623:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":573,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5623:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":574,"nodeType":"ExpressionStatement","src":"5623:18:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206465706c6f796d656e74","id":578,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5664:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""},"value":"contract deployment"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""}],"expression":{"id":575,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5652:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":577,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5652:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":579,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5652:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":580,"nodeType":"ExpressionStatement","src":"5652:34:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078313233343536","id":588,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5725:8:0","typeDescriptions":{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"},"value":"0x123456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"}],"id":587,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5717:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":586,"name":"uint160","nodeType":"ElementaryTypeName","src":"5717:7:0","typeDescriptions":{}}},"id":589,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5717:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":585,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5709:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":584,"name":"address","nodeType":"ElementaryTypeName","src":"5709:7:0","typeDescriptions":{}}},"id":590,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5709:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":581,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5696:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":583,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5696:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":591,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5696:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":592,"nodeType":"ExpressionStatement","src":"5696:40:0"},{"assignments":[595],"declarations":[{"constant":false,"id":595,"mutability":"mutable","name":"x","nameLocation":"5753:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5746:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":594,"nodeType":"UserDefinedTypeName","pathNode":{"id":593,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5746:6:0"},"referencedDeclaration":799,"src":"5746:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":601,"initialValue":{"arguments":[{"hexValue":"31323334","id":599,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5768:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":598,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5757:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":597,"nodeType":"UserDefinedTypeName","pathNode":{"id":596,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5761:6:0"},"referencedDeclaration":799,"src":"5761:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":600,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5757:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5746:27:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":607,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":603,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":595,"src":"5791:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":604,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"5791:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":605,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5791:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":606,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5802:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"5791:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e20637265617465206973206e6f742031323334","id":608,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5808:35:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""},"value":"FooBar: foo in create is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""}],"id":602,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"5783:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":609,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5783:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":610,"nodeType":"ExpressionStatement","src":"5783:61:0"},{"expression":{"arguments":[{"hexValue":"6372656174652032","id":614,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5867:10:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""},"value":"create 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""}],"expression":{"id":611,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5855:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":613,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5855:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":615,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5855:23:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":616,"nodeType":"ExpressionStatement","src":"5855:23:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307863616665","id":624,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5917:6:0","typeDescriptions":{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"},"value":"0xcafe"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"}],"id":623,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5909:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":622,"name":"uint160","nodeType":"ElementaryTypeName","src":"5909:7:0","typeDescriptions":{}}},"id":625,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5909:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":621,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5901:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":620,"name":"address","nodeType":"ElementaryTypeName","src":"5901:7:0","typeDescriptions":{}}},"id":626,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5901:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":617,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5888:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":619,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5888:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":627,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5888:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":628,"nodeType":"ExpressionStatement","src":"5888:38:0"},{"assignments":[631],"declarations":[{"constant":false,"id":631,"mutability":"mutable","name":"y","nameLocation":"5943:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5936:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":630,"nodeType":"UserDefinedTypeName","pathNode":{"id":629,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5936:6:0"},"referencedDeclaration":799,"src":"5936:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":645,"initialValue":{"arguments":[{"hexValue":"31323334","id":643,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5986:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":634,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5947:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":633,"nodeType":"UserDefinedTypeName","pathNode":{"id":632,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5951:6:0"},"referencedDeclaration":799,"src":"5951:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":642,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"names":["salt"],"nodeType":"FunctionCallOptions","options":[{"arguments":[{"arguments":[{"hexValue":"3432","id":639,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5980:2:0","typeDescriptions":{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"},"value":"42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"}],"id":638,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5972:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":637,"name":"uint256","nodeType":"ElementaryTypeName","src":"5972:7:0","typeDescriptions":{}}},"id":640,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5972:11:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":636,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5964:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":635,"name":"bytes32","nodeType":"ElementaryTypeName","src":"5964:7:0","typeDescriptions":{}}},"id":641,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5964:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"src":"5947:38:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$salt","typeString":"function (uint256) returns (contract FooBar)"}},"id":644,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5947:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5936:55:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":651,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":647,"name":"y","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":631,"src":"6009:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":648,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"6009:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":649,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6009:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":650,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6020:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"6009:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e2063726561746532206973206e6f742031323334","id":652,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6026:36:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""},"value":"FooBar: foo in create2 is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""}],"id":646,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"6001:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":653,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6001:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":654,"nodeType":"ExpressionStatement","src":"6001:62:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":658,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6085:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":655,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6073:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":657,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6073:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":659,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6073:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":660,"nodeType":"ExpressionStatement","src":"6073:20:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":661,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6177:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":663,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"6177:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":664,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6177:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":665,"nodeType":"ExpressionStatement","src":"6177:14:0"},{"expression":{"arguments":[{"hexValue":"31323334","id":669,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6212:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":668,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"6201:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":667,"nodeType":"UserDefinedTypeName","pathNode":{"id":666,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"6205:6:0"},"referencedDeclaration":799,"src":"6205:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":670,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6201:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":671,"nodeType":"ExpressionStatement","src":"6201:16:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e636520656e64","id":675,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6240:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},"value":"nonce end"},{"arguments":[{"arguments":[{"arguments":[{"id":682,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6281:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":681,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6273:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":680,"name":"address","nodeType":"ElementaryTypeName","src":"6273:7:0","typeDescriptions":{}}},"id":683,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6273:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":678,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6261:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":679,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"6261:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":684,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6261:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":677,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6253:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":676,"name":"uint256","nodeType":"ElementaryTypeName","src":"6253:7:0","typeDescriptions":{}}},"id":685,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6253:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":672,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6228:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":674,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"6228:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":686,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6228:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":687,"nodeType":"ExpressionStatement","src":"6228:61:0"}]},"documentation":{"id":457,"nodeType":"StructuredDocumentation","src":"4902:56:0","text":"@notice example function, to test vm.broadcast with."},"functionSelector":"bef03abc","implemented":true,"kind":"function","modifiers":[],"name":"runBroadcast","nameLocation":"4972:12:0","parameters":{"id":458,"nodeType":"ParameterList","parameters":[],"src":"4984:2:0"},"returnParameters":{"id":459,"nodeType":"ParameterList","parameters":[],"src":"4994:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":713,"nodeType":"FunctionDefinition","src":"6391:143:0","nodes":[],"body":{"id":712,"nodeType":"Block","src":"6440:94:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":698,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":692,"src":"6462:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":695,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6450:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":697,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6450:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":699,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6450:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":700,"nodeType":"ExpressionStatement","src":"6450:15:0"},{"expression":{"arguments":[{"hexValue":"68656c6c6f206d73672e73656e646572","id":704,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6487:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},"value":"hello msg.sender"},{"arguments":[{"expression":{"id":707,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"6515:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":708,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"6515:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":706,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6507:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":705,"name":"address","nodeType":"ElementaryTypeName","src":"6507:7:0","typeDescriptions":{}}},"id":709,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6507:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":701,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6475:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":703,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"6475:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":710,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6475:52:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":711,"nodeType":"ExpressionStatement","src":"6475:52:0"}]},"documentation":{"id":690,"nodeType":"StructuredDocumentation","src":"6302:84:0","text":"@notice example external function, to force a CALL, and test vm.startPrank with."},"functionSelector":"a777d0dc","implemented":true,"kind":"function","modifiers":[],"name":"hello","nameLocation":"6400:5:0","parameters":{"id":693,"nodeType":"ParameterList","parameters":[{"constant":false,"id":692,"mutability":"mutable","name":"_v","nameLocation":"6422:2:0","nodeType":"VariableDeclaration","scope":713,"src":"6406:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":691,"name":"string","nodeType":"ElementaryTypeName","src":"6406:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6405:20:0"},"returnParameters":{"id":694,"nodeType":"ParameterList","parameters":[],"src":"6440:0:0"},"scope":786,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":728,"nodeType":"FunctionDefinition","src":"6540:95:0","nodes":[],"body":{"id":727,"nodeType":"Block","src":"6584:51:0","nodes":[],"statements":[{"expression":{"id":719,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6594:9:0","subExpression":{"id":718,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6594:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":720,"nodeType":"ExpressionStatement","src":"6594:9:0"},{"expression":{"arguments":[{"id":724,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":715,"src":"6625:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":721,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6613:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":723,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6613:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":725,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6613:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":726,"nodeType":"ExpressionStatement","src":"6613:15:0"}]},"functionSelector":"7e79255d","implemented":true,"kind":"function","modifiers":[],"name":"call1","nameLocation":"6549:5:0","parameters":{"id":716,"nodeType":"ParameterList","parameters":[{"constant":false,"id":715,"mutability":"mutable","name":"_v","nameLocation":"6571:2:0","nodeType":"VariableDeclaration","scope":728,"src":"6555:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":714,"name":"string","nodeType":"ElementaryTypeName","src":"6555:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6554:20:0"},"returnParameters":{"id":717,"nodeType":"ParameterList","parameters":[],"src":"6584:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":743,"nodeType":"FunctionDefinition","src":"6641:95:0","nodes":[],"body":{"id":742,"nodeType":"Block","src":"6685:51:0","nodes":[],"statements":[{"expression":{"id":734,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6695:9:0","subExpression":{"id":733,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6695:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":735,"nodeType":"ExpressionStatement","src":"6695:9:0"},{"expression":{"arguments":[{"id":739,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":730,"src":"6726:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":736,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6714:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":738,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6714:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":740,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6714:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":741,"nodeType":"ExpressionStatement","src":"6714:15:0"}]},"functionSelector":"8d3ef7ca","implemented":true,"kind":"function","modifiers":[],"name":"call2","nameLocation":"6650:5:0","parameters":{"id":731,"nodeType":"ParameterList","parameters":[{"constant":false,"id":730,"mutability":"mutable","name":"_v","nameLocation":"6672:2:0","nodeType":"VariableDeclaration","scope":743,"src":"6656:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":729,"name":"string","nodeType":"ElementaryTypeName","src":"6656:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6655:20:0"},"returnParameters":{"id":732,"nodeType":"ParameterList","parameters":[],"src":"6685:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":758,"nodeType":"FunctionDefinition","src":"6742:98:0","nodes":[],"body":{"id":757,"nodeType":"Block","src":"6788:52:0","nodes":[],"statements":[{"expression":{"id":749,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6798:9:0","subExpression":{"id":748,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6798:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":750,"nodeType":"ExpressionStatement","src":"6798:9:0"},{"expression":{"arguments":[{"id":754,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":745,"src":"6830:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":751,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6817:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":753,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested2","nodeType":"MemberAccess","referencedDeclaration":773,"src":"6817:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":755,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6817:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":756,"nodeType":"ExpressionStatement","src":"6817:16:0"}]},"functionSelector":"a76ccdfa","implemented":true,"kind":"function","modifiers":[],"name":"nested1","nameLocation":"6751:7:0","parameters":{"id":746,"nodeType":"ParameterList","parameters":[{"constant":false,"id":745,"mutability":"mutable","name":"_v","nameLocation":"6775:2:0","nodeType":"VariableDeclaration","scope":758,"src":"6759:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":744,"name":"string","nodeType":"ElementaryTypeName","src":"6759:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6758:20:0"},"returnParameters":{"id":747,"nodeType":"ParameterList","parameters":[],"src":"6788:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":773,"nodeType":"FunctionDefinition","src":"6846:97:0","nodes":[],"body":{"id":772,"nodeType":"Block","src":"6892:51:0","nodes":[],"statements":[{"expression":{"id":764,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6902:9:0","subExpression":{"id":763,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6902:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":765,"nodeType":"ExpressionStatement","src":"6902:9:0"},{"expression":{"arguments":[{"id":769,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":760,"src":"6933:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":766,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6921:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":768,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6921:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":770,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6921:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":771,"nodeType":"ExpressionStatement","src":"6921:15:0"}]},"functionSelector":"dbf1282f","implemented":true,"kind":"function","modifiers":[],"name":"nested2","nameLocation":"6855:7:0","parameters":{"id":761,"nodeType":"ParameterList","parameters":[{"constant":false,"id":760,"mutability":"mutable","name":"_v","nameLocation":"6879:2:0","nodeType":"VariableDeclaration","scope":773,"src":"6863:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":759,"name":"string","nodeType":"ElementaryTypeName","src":"6863:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6862:20:0"},"returnParameters":{"id":762,"nodeType":"ParameterList","parameters":[],"src":"6892:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":785,"nodeType":"FunctionDefinition","src":"6949:84:0","nodes":[],"body":{"id":784,"nodeType":"Block","src":"7001:32:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":781,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":775,"src":"7023:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":778,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"7011:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":780,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"7011:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":782,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7011:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":783,"nodeType":"ExpressionStatement","src":"7011:15:0"}]},"functionSelector":"7f8b915c","implemented":true,"kind":"function","modifiers":[],"name":"callPure","nameLocation":"6958:8:0","parameters":{"id":776,"nodeType":"ParameterList","parameters":[{"constant":false,"id":775,"mutability":"mutable","name":"_v","nameLocation":"6983:2:0","nodeType":"VariableDeclaration","scope":785,"src":"6967:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":774,"name":"string","nodeType":"ElementaryTypeName","src":"6967:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6966:20:0"},"returnParameters":{"id":777,"nodeType":"ParameterList","parameters":[],"src":"7001:0:0"},"scope":786,"stateMutability":"pure","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ScriptExample","contractDependencies":[799],"contractKind":"contract","documentation":{"id":221,"nodeType":"StructuredDocumentation","src":"2997:126:0","text":"@title ScriptExample\n @notice ScriptExample is an example script. The Go forge script code tests that it can run this."},"fullyImplemented":true,"linearizedBaseContracts":[786],"name":"ScriptExample","nameLocation":"3132:13:0","scope":969,"usedErrors":[]},{"id":799,"nodeType":"ContractDefinition","src":"7037:96:0","nodes":[{"id":788,"nodeType":"VariableDeclaration","src":"7059:18:0","nodes":[],"constant":false,"functionSelector":"c2985578","mutability":"mutable","name":"foo","nameLocation":"7074:3:0","scope":799,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":787,"name":"uint256","nodeType":"ElementaryTypeName","src":"7059:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":798,"nodeType":"FunctionDefinition","src":"7084:47:0","nodes":[],"body":{"id":797,"nodeType":"Block","src":"7107:24:0","nodes":[],"statements":[{"expression":{"id":795,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":793,"name":"foo","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":788,"src":"7117:3:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":794,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":790,"src":"7123:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"7117:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":796,"nodeType":"ExpressionStatement","src":"7117:7:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":791,"nodeType":"ParameterList","parameters":[{"constant":false,"id":790,"mutability":"mutable","name":"v","nameLocation":"7104:1:0","nodeType":"VariableDeclaration","scope":798,"src":"7096:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":789,"name":"uint256","nodeType":"ElementaryTypeName","src":"7096:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7095:11:0"},"returnParameters":{"id":792,"nodeType":"ParameterList","parameters":[],"src":"7107:0:0"},"scope":799,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"FooBar","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[799],"name":"FooBar","nameLocation":"7046:6:0","scope":969,"usedErrors":[]},{"id":833,"nodeType":"ContractDefinition","src":"7135:281:0","nodes":[{"id":813,"nodeType":"VariableDeclaration","src":"7162:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7188:10:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":800,"name":"address","nodeType":"ElementaryTypeName","src":"7162:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":808,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7235:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":807,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7225:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":809,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7225:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":806,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7217:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":805,"name":"uint256","nodeType":"ElementaryTypeName","src":"7217:7:0","typeDescriptions":{}}},"id":810,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7217:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":804,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7209:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":803,"name":"uint160","nodeType":"ElementaryTypeName","src":"7209:7:0","typeDescriptions":{}}},"id":811,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7209:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":802,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":801,"name":"address","nodeType":"ElementaryTypeName","src":"7201:7:0","typeDescriptions":{}}},"id":812,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7201:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":819,"nodeType":"VariableDeclaration","src":"7262:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7283:2:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":815,"nodeType":"UserDefinedTypeName","pathNode":{"id":814,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7262:2:0"},"referencedDeclaration":83,"src":"7262:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":817,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":813,"src":"7291:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":816,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7288:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":818,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7288:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":832,"nodeType":"FunctionDefinition","src":"7309:105:0","nodes":[],"body":{"id":831,"nodeType":"Block","src":"7372:42:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":828,"name":"_addr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":821,"src":"7401:5:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":826,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":819,"src":"7389:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":827,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7389:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":829,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7389:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"functionReturnParameters":825,"id":830,"nodeType":"Return","src":"7382:25:0"}]},"functionSelector":"2d0335ab","implemented":true,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"7318:8:0","parameters":{"id":822,"nodeType":"ParameterList","parameters":[{"constant":false,"id":821,"mutability":"mutable","name":"_addr","nameLocation":"7335:5:0","nodeType":"VariableDeclaration","scope":832,"src":"7327:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":820,"name":"address","nodeType":"ElementaryTypeName","src":"7327:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"7326:15:0"},"returnParameters":{"id":825,"nodeType":"ParameterList","parameters":[{"constant":false,"id":824,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":832,"src":"7363:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":823,"name":"uint256","nodeType":"ElementaryTypeName","src":"7363:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7362:9:0"},"scope":833,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"NonceGetter","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[833],"name":"NonceGetter","nameLocation":"7144:11:0","scope":969,"usedErrors":[]},{"id":852,"nodeType":"ContractDefinition","src":"7418:174:0","nodes":[{"id":835,"nodeType":"VariableDeclaration","src":"7448:18:0","nodes":[],"constant":false,"mutability":"mutable","name":"v","nameLocation":"7465:1:0","scope":852,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":834,"name":"uint256","nodeType":"ElementaryTypeName","src":"7448:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"id":843,"nodeType":"FunctionDefinition","src":"7473:36:0","nodes":[],"body":{"id":842,"nodeType":"Block","src":"7487:22:0","nodes":[],"statements":[{"expression":{"id":840,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":838,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7497:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"hexValue":"31","id":839,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7501:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"7497:5:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":841,"nodeType":"ExpressionStatement","src":"7497:5:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":836,"nodeType":"ParameterList","parameters":[],"src":"7484:2:0"},"returnParameters":{"id":837,"nodeType":"ParameterList","parameters":[],"src":"7487:0:0"},"scope":852,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":851,"nodeType":"FunctionDefinition","src":"7515:75:0","nodes":[],"body":{"id":850,"nodeType":"Block","src":"7565:25:0","nodes":[],"statements":[{"expression":{"id":848,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7582:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"functionReturnParameters":847,"id":849,"nodeType":"Return","src":"7575:8:0"}]},"functionSelector":"20965255","implemented":true,"kind":"function","modifiers":[],"name":"getValue","nameLocation":"7524:8:0","parameters":{"id":844,"nodeType":"ParameterList","parameters":[],"src":"7532:2:0"},"returnParameters":{"id":847,"nodeType":"ParameterList","parameters":[{"constant":false,"id":846,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":851,"src":"7556:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":845,"name":"uint256","nodeType":"ElementaryTypeName","src":"7556:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7555:9:0"},"scope":852,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkedContract","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[852],"name":"ForkedContract","nameLocation":"7427:14:0","scope":969,"usedErrors":[]},{"id":968,"nodeType":"ContractDefinition","src":"7594:813:0","nodes":[{"id":866,"nodeType":"VariableDeclaration","src":"7620:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7646:10:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":853,"name":"address","nodeType":"ElementaryTypeName","src":"7620:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":861,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7693:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":860,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7683:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":862,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7683:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":859,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7675:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":858,"name":"uint256","nodeType":"ElementaryTypeName","src":"7675:7:0","typeDescriptions":{}}},"id":863,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7675:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":857,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7667:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":856,"name":"uint160","nodeType":"ElementaryTypeName","src":"7667:7:0","typeDescriptions":{}}},"id":864,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7667:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":855,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7659:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":854,"name":"address","nodeType":"ElementaryTypeName","src":"7659:7:0","typeDescriptions":{}}},"id":865,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7659:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":872,"nodeType":"VariableDeclaration","src":"7720:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7741:2:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":868,"nodeType":"UserDefinedTypeName","pathNode":{"id":867,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7720:2:0"},"referencedDeclaration":83,"src":"7720:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":870,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":866,"src":"7749:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":869,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7746:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":871,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7746:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":967,"nodeType":"FunctionDefinition","src":"7767:638:0","nodes":[],"body":{"id":966,"nodeType":"Block","src":"7791:614:0","nodes":[],"statements":[{"assignments":[876],"declarations":[{"constant":false,"id":876,"mutability":"mutable","name":"testAddr","nameLocation":"7809:8:0","nodeType":"VariableDeclaration","scope":966,"src":"7801:16:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":875,"name":"address","nodeType":"ElementaryTypeName","src":"7801:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":884,"initialValue":{"arguments":[{"arguments":[{"hexValue":"307831323334","id":881,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7836:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":880,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7828:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":879,"name":"uint160","nodeType":"ElementaryTypeName","src":"7828:7:0","typeDescriptions":{}}},"id":882,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7828:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":878,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7820:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":877,"name":"address","nodeType":"ElementaryTypeName","src":"7820:7:0","typeDescriptions":{}}},"id":883,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7820:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"7801:43:0"},{"assignments":[887],"declarations":[{"constant":false,"id":887,"mutability":"mutable","name":"fc","nameLocation":"7869:2:0","nodeType":"VariableDeclaration","scope":966,"src":"7854:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"},"typeName":{"id":886,"nodeType":"UserDefinedTypeName","pathNode":{"id":885,"name":"ForkedContract","nodeType":"IdentifierPath","referencedDeclaration":852,"src":"7854:14:0"},"referencedDeclaration":852,"src":"7854:14:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"visibility":"internal"}],"id":891,"initialValue":{"arguments":[{"id":889,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7889:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":888,"name":"ForkedContract","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":852,"src":"7874:14:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_ForkedContract_$852_$","typeString":"type(contract ForkedContract)"}},"id":890,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7874:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"nodeType":"VariableDeclarationStatement","src":"7854:44:0"},{"expression":{"arguments":[{"hexValue":"666f726b31","id":895,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7929:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},"value":"fork1"},{"hexValue":"3132333435","id":896,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7938:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"}],"expression":{"id":892,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7909:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":894,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"7909:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":897,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7909:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":898,"nodeType":"ExpressionStatement","src":"7909:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":905,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":902,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7974:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":900,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7962:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":901,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7962:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":903,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7962:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3132333435","id":904,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7987:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"},"src":"7962:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":906,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7994:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":899,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"7954:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":907,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7954:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":908,"nodeType":"ExpressionStatement","src":"7954:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":914,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":910,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8036:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":911,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8036:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":912,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8036:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31","id":913,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8053:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"8036:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652031","id":915,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8056:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""},"value":"value should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""}],"id":909,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8028:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":916,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8028:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":917,"nodeType":"ExpressionStatement","src":"8028:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":925,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":919,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8094:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":920,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8094:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"31","id":923,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8122:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"}],"id":922,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8114:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":921,"name":"uint256","nodeType":"ElementaryTypeName","src":"8114:7:0","typeDescriptions":{}}},"id":924,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8114:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8094:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652031","id":926,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8126:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""},"value":"balance should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""}],"id":918,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8086:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":927,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8086:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":928,"nodeType":"ExpressionStatement","src":"8086:62:0"},{"expression":{"arguments":[{"hexValue":"666f726b32","id":932,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8179:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},"value":"fork2"},{"hexValue":"3233343536","id":933,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8188:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"}],"expression":{"id":929,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8159:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":931,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"8159:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":934,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8159:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":935,"nodeType":"ExpressionStatement","src":"8159:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":942,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":939,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8224:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":937,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8212:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":938,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"8212:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":940,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8212:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3233343536","id":941,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8237:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"},"src":"8212:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":943,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8244:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":936,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8204:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":944,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8204:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":945,"nodeType":"ExpressionStatement","src":"8204:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":951,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":947,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8286:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":948,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8286:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":949,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8286:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"32","id":950,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8303:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"},"src":"8286:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652032","id":952,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8306:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""},"value":"value should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""}],"id":946,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8278:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":953,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8278:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":954,"nodeType":"ExpressionStatement","src":"8278:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":962,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":956,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8344:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":957,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8344:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"32","id":960,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8372:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"}],"id":959,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8364:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":958,"name":"uint256","nodeType":"ElementaryTypeName","src":"8364:7:0","typeDescriptions":{}}},"id":961,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8364:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8344:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652032","id":963,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8376:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""},"value":"balance should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""}],"id":955,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8336:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":964,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8336:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":965,"nodeType":"ExpressionStatement","src":"8336:62:0"}]},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"7776:3:0","parameters":{"id":873,"nodeType":"ParameterList","parameters":[],"src":"7779:2:0"},"returnParameters":{"id":874,"nodeType":"ParameterList","parameters":[],"src":"7791:0:0"},"scope":968,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkTester","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[968],"name":"ForkTester","nameLocation":"7603:10:0","scope":969,"usedErrors":[]}],"license":"MIT"},"id":0} \ No newline at end of file diff --git a/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/ForkTester.json b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/ForkTester.json new file mode 100644 index 0000000000000..94470339ecceb --- /dev/null +++ b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/ForkTester.json @@ -0,0 +1 @@ +{"abi":[{"type":"function","name":"run","inputs":[],"outputs":[],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x608060405234801561001057600080fd5b5061070c806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c040622614610030575b600080fd5b61003861003a565b005b604080517f71ee464d0000000000000000000000000000000000000000000000000000000081526004810191909152600560448201527f666f726b3100000000000000000000000000000000000000000000000000000060648201526130396024820152611234908190737109709ecfa91a80626ff3989d68f67f5b1dd12d906371ee464d906084016020604051808303816000875af11580156100e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061010691906106b5565b506040517f2d0335ab00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401602060405180830381865afa158015610185573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101a991906106ce565b67ffffffffffffffff1661303914610222576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f6e6f6e63652073686f756c64206265203132333435000000000000000000000060448201526064015b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663209652556040518163ffffffff1660e01b8152600401602060405180830381865afa15801561026d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061029191906106b5565b6001146102fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f76616c75652073686f756c6420626520310000000000000000000000000000006044820152606401610219565b60018273ffffffffffffffffffffffffffffffffffffffff16311461037b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f62616c616e63652073686f756c642062652031000000000000000000000000006044820152606401610219565b604080517f71ee464d0000000000000000000000000000000000000000000000000000000081526004810191909152600560448201527f666f726b320000000000000000000000000000000000000000000000000000006064820152615ba06024820152737109709ecfa91a80626ff3989d68f67f5b1dd12d906371ee464d906084016020604051808303816000875af115801561041d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061044191906106b5565b506040517f2d0335ab00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401602060405180830381865afa1580156104c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e491906106ce565b67ffffffffffffffff16615ba014610558576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f6e6f6e63652073686f756c6420626520313233343500000000000000000000006044820152606401610219565b8073ffffffffffffffffffffffffffffffffffffffff1663209652556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c791906106b5565b600214610630576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f76616c75652073686f756c6420626520320000000000000000000000000000006044820152606401610219565b60028273ffffffffffffffffffffffffffffffffffffffff1631146106b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f62616c616e63652073686f756c642062652032000000000000000000000000006044820152606401610219565b5050565b6000602082840312156106c757600080fd5b5051919050565b6000602082840312156106e057600080fd5b815167ffffffffffffffff811681146106f857600080fd5b939250505056fea164736f6c634300080f000a","sourceMap":"7594:813:0:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c040622614610030575b600080fd5b61003861003a565b005b604080517f71ee464d0000000000000000000000000000000000000000000000000000000081526004810191909152600560448201527f666f726b3100000000000000000000000000000000000000000000000000000060648201526130396024820152611234908190737109709ecfa91a80626ff3989d68f67f5b1dd12d906371ee464d906084016020604051808303816000875af11580156100e2573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061010691906106b5565b506040517f2d0335ab00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401602060405180830381865afa158015610185573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101a991906106ce565b67ffffffffffffffff1661303914610222576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f6e6f6e63652073686f756c64206265203132333435000000000000000000000060448201526064015b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663209652556040518163ffffffff1660e01b8152600401602060405180830381865afa15801561026d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061029191906106b5565b6001146102fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f76616c75652073686f756c6420626520310000000000000000000000000000006044820152606401610219565b60018273ffffffffffffffffffffffffffffffffffffffff16311461037b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f62616c616e63652073686f756c642062652031000000000000000000000000006044820152606401610219565b604080517f71ee464d0000000000000000000000000000000000000000000000000000000081526004810191909152600560448201527f666f726b320000000000000000000000000000000000000000000000000000006064820152615ba06024820152737109709ecfa91a80626ff3989d68f67f5b1dd12d906371ee464d906084016020604051808303816000875af115801561041d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061044191906106b5565b506040517f2d0335ab00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401602060405180830381865afa1580156104c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e491906106ce565b67ffffffffffffffff16615ba014610558576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f6e6f6e63652073686f756c6420626520313233343500000000000000000000006044820152606401610219565b8073ffffffffffffffffffffffffffffffffffffffff1663209652556040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105c791906106b5565b600214610630576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f76616c75652073686f756c6420626520320000000000000000000000000000006044820152606401610219565b60028273ffffffffffffffffffffffffffffffffffffffff1631146106b1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f62616c616e63652073686f756c642062652032000000000000000000000000006044820152606401610219565b5050565b6000602082840312156106c757600080fd5b5051919050565b6000602082840312156106e057600080fd5b815167ffffffffffffffff811681146106f857600080fd5b939250505056fea164736f6c634300080f000a","sourceMap":"7594:813:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7767:638;;;:::i;:::-;;;7909:35;;;;;;;;;238:21:1;;;;295:1;275:18;;;268:29;333:7;313:18;;;306:35;7938:5:0;393:20:1;;;386:36;7836:6:0;;;;7909:19;;;;358::1;;7909:35:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;7962:21:0;;;;;798:42:1;786:55;;7962:21:0;;;768:74:1;7962:11:0;;;;741:18:1;;7962:21:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:30;;7987:5;7962:30;7954:64;;;;;;;1348:2:1;7954:64:0;;;1330:21:1;1387:2;1367:18;;;1360:30;1426:23;1406:18;;;1399:51;1467:18;;7954:64:0;;;;;;;;;8036:2;:11;;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8053:1;8036:18;8028:48;;;;;;;1698:2:1;8028:48:0;;;1680:21:1;1737:2;1717:18;;;1710:30;1776:19;1756:18;;;1749:47;1813:18;;8028:48:0;1496:341:1;8028:48:0;8122:1;8094:8;:16;;;:30;8086:62;;;;;;;2044:2:1;8086:62:0;;;2026:21:1;2083:2;2063:18;;;2056:30;2122:21;2102:18;;;2095:49;2161:18;;8086:62:0;1842:343:1;8086:62:0;8159:35;;;;;;;;;2414:21:1;;;;2471:1;2451:18;;;2444:29;2509:7;2489:18;;;2482:35;8188:5:0;2569:20:1;;;2562:36;8159:19:0;;;;2534::1;;8159:35:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;8212:21:0;;;;;798:42:1;786:55;;8212:21:0;;;768:74:1;8212:11:0;;;;741:18:1;;8212:21:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:30;;8237:5;8212:30;8204:64;;;;;;;1348:2:1;8204:64:0;;;1330:21:1;1387:2;1367:18;;;1360:30;1426:23;1406:18;;;1399:51;1467:18;;8204:64:0;1146:345:1;8204:64:0;8286:2;:11;;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8303:1;8286:18;8278:48;;;;;;;2811:2:1;8278:48:0;;;2793:21:1;2850:2;2830:18;;;2823:30;2889:19;2869:18;;;2862:47;2926:18;;8278:48:0;2609:341:1;8278:48:0;8372:1;8344:8;:16;;;:30;8336:62;;;;;;;3157:2:1;8336:62:0;;;3139:21:1;3196:2;3176:18;;;3169:30;3235:21;3215:18;;;3208:49;3274:18;;8336:62:0;2955:343:1;8336:62:0;7791:614;;7767:638::o;433:184:1:-;503:6;556:2;544:9;535:7;531:23;527:32;524:52;;;572:1;569;562:12;524:52;-1:-1:-1;595:16:1;;433:184;-1:-1:-1;433:184:1:o;853:288::-;922:6;975:2;963:9;954:7;950:23;946:32;943:52;;;991:1;988;981:12;943:52;1023:9;1017:16;1073:18;1066:5;1062:30;1055:5;1052:41;1042:69;;1107:1;1104;1097:12;1042:69;1130:5;853:288;-1:-1:-1;;;853:288:1:o","linkReferences":{}},"methodIdentifiers":{"run()":"c0406226"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"run\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"scripts/ScriptExample.s.sol\":\"ForkTester\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"scripts/ScriptExample.s.sol\":{\"keccak256\":\"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28\",\"dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"run"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"scripts/ScriptExample.s.sol":"ForkTester"},"evmVersion":"london","libraries":{}},"sources":{"scripts/ScriptExample.s.sol":{"keccak256":"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da","urls":["bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28","dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[],"types":{}},"userdoc":{"version":1,"kind":"user"},"devdoc":{"version":1,"kind":"dev"},"ast":{"absolutePath":"scripts/ScriptExample.s.sol","id":969,"exportedSymbols":{"FooBar":[799],"ForkTester":[968],"ForkedContract":[852],"NonceGetter":[833],"ScriptExample":[786],"Vm":[83],"console":[220]},"nodeType":"SourceUnit","src":"32:8375:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","0.8",".15"]},{"id":83,"nodeType":"ContractDefinition","src":"120:969:0","nodes":[{"id":10,"nodeType":"FunctionDefinition","src":"139:91:0","nodes":[],"functionSelector":"4777f3cf","implemented":false,"kind":"function","modifiers":[],"name":"envOr","nameLocation":"148:5:0","parameters":{"id":6,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"mutability":"mutable","name":"name","nameLocation":"170:4:0","nodeType":"VariableDeclaration","scope":10,"src":"154:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":2,"name":"string","nodeType":"ElementaryTypeName","src":"154:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":5,"mutability":"mutable","name":"defaultValue","nameLocation":"181:12:0","nodeType":"VariableDeclaration","scope":10,"src":"176:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":4,"name":"bool","nodeType":"ElementaryTypeName","src":"176:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"153:41:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[{"constant":false,"id":8,"mutability":"mutable","name":"value","nameLocation":"223:5:0","nodeType":"VariableDeclaration","scope":10,"src":"218:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":7,"name":"bool","nodeType":"ElementaryTypeName","src":"218:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"217:12:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":17,"nodeType":"FunctionDefinition","src":"235:72:0","nodes":[],"functionSelector":"2d0335ab","implemented":false,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"244:8:0","parameters":{"id":13,"nodeType":"ParameterList","parameters":[{"constant":false,"id":12,"mutability":"mutable","name":"account","nameLocation":"261:7:0","nodeType":"VariableDeclaration","scope":17,"src":"253:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":11,"name":"address","nodeType":"ElementaryTypeName","src":"253:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"252:17:0"},"returnParameters":{"id":16,"nodeType":"ParameterList","parameters":[{"constant":false,"id":15,"mutability":"mutable","name":"nonce","nameLocation":"300:5:0","nodeType":"VariableDeclaration","scope":17,"src":"293:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"},"typeName":{"id":14,"name":"uint64","nodeType":"ElementaryTypeName","src":"293:6:0","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"visibility":"internal"}],"src":"292:14:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":27,"nodeType":"FunctionDefinition","src":"312:111:0","nodes":[],"functionSelector":"213e4198","implemented":false,"kind":"function","modifiers":[],"name":"parseJsonKeys","nameLocation":"321:13:0","parameters":{"id":22,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19,"mutability":"mutable","name":"json","nameLocation":"351:4:0","nodeType":"VariableDeclaration","scope":27,"src":"335:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":18,"name":"string","nodeType":"ElementaryTypeName","src":"335:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":21,"mutability":"mutable","name":"key","nameLocation":"373:3:0","nodeType":"VariableDeclaration","scope":27,"src":"357:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":20,"name":"string","nodeType":"ElementaryTypeName","src":"357:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"334:43:0"},"returnParameters":{"id":26,"nodeType":"ParameterList","parameters":[{"constant":false,"id":25,"mutability":"mutable","name":"keys","nameLocation":"417:4:0","nodeType":"VariableDeclaration","scope":27,"src":"401:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":23,"name":"string","nodeType":"ElementaryTypeName","src":"401:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":24,"nodeType":"ArrayTypeName","src":"401:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"src":"400:22:0"},"scope":83,"stateMutability":"pure","virtual":false,"visibility":"external"},{"id":32,"nodeType":"FunctionDefinition","src":"428:48:0","nodes":[],"functionSelector":"06447d56","implemented":false,"kind":"function","modifiers":[],"name":"startPrank","nameLocation":"437:10:0","parameters":{"id":30,"nodeType":"ParameterList","parameters":[{"constant":false,"id":29,"mutability":"mutable","name":"msgSender","nameLocation":"456:9:0","nodeType":"VariableDeclaration","scope":32,"src":"448:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":28,"name":"address","nodeType":"ElementaryTypeName","src":"448:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"447:19:0"},"returnParameters":{"id":31,"nodeType":"ParameterList","parameters":[],"src":"475:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":35,"nodeType":"FunctionDefinition","src":"481:30:0","nodes":[],"functionSelector":"90c5013b","implemented":false,"kind":"function","modifiers":[],"name":"stopPrank","nameLocation":"490:9:0","parameters":{"id":33,"nodeType":"ParameterList","parameters":[],"src":"499:2:0"},"returnParameters":{"id":34,"nodeType":"ParameterList","parameters":[],"src":"510:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":38,"nodeType":"FunctionDefinition","src":"516:30:0","nodes":[],"functionSelector":"afc98040","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"525:9:0","parameters":{"id":36,"nodeType":"ParameterList","parameters":[],"src":"534:2:0"},"returnParameters":{"id":37,"nodeType":"ParameterList","parameters":[],"src":"545:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":43,"nodeType":"FunctionDefinition","src":"551:47:0","nodes":[],"functionSelector":"e6962cdb","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"560:9:0","parameters":{"id":41,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40,"mutability":"mutable","name":"msgSender","nameLocation":"578:9:0","nodeType":"VariableDeclaration","scope":43,"src":"570:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39,"name":"address","nodeType":"ElementaryTypeName","src":"570:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"569:19:0"},"returnParameters":{"id":42,"nodeType":"ParameterList","parameters":[],"src":"597:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":48,"nodeType":"FunctionDefinition","src":"603:52:0","nodes":[],"functionSelector":"7fec2a8d","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"612:14:0","parameters":{"id":46,"nodeType":"ParameterList","parameters":[{"constant":false,"id":45,"mutability":"mutable","name":"msgSender","nameLocation":"635:9:0","nodeType":"VariableDeclaration","scope":48,"src":"627:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":44,"name":"address","nodeType":"ElementaryTypeName","src":"627:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"626:19:0"},"returnParameters":{"id":47,"nodeType":"ParameterList","parameters":[],"src":"654:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":51,"nodeType":"FunctionDefinition","src":"660:35:0","nodes":[],"functionSelector":"7fb5297f","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"669:14:0","parameters":{"id":49,"nodeType":"ParameterList","parameters":[],"src":"683:2:0"},"returnParameters":{"id":50,"nodeType":"ParameterList","parameters":[],"src":"694:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":54,"nodeType":"FunctionDefinition","src":"700:34:0","nodes":[],"functionSelector":"76eadd36","implemented":false,"kind":"function","modifiers":[],"name":"stopBroadcast","nameLocation":"709:13:0","parameters":{"id":52,"nodeType":"ParameterList","parameters":[],"src":"722:2:0"},"returnParameters":{"id":53,"nodeType":"ParameterList","parameters":[],"src":"733:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":61,"nodeType":"FunctionDefinition","src":"739:108:0","nodes":[],"functionSelector":"3ebf73b4","implemented":false,"kind":"function","modifiers":[],"name":"getDeployedCode","nameLocation":"748:15:0","parameters":{"id":57,"nodeType":"ParameterList","parameters":[{"constant":false,"id":56,"mutability":"mutable","name":"artifactPath","nameLocation":"780:12:0","nodeType":"VariableDeclaration","scope":61,"src":"764:28:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":55,"name":"string","nodeType":"ElementaryTypeName","src":"764:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"763:30:0"},"returnParameters":{"id":60,"nodeType":"ParameterList","parameters":[{"constant":false,"id":59,"mutability":"mutable","name":"runtimeBytecode","nameLocation":"830:15:0","nodeType":"VariableDeclaration","scope":61,"src":"817:28:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":58,"name":"bytes","nodeType":"ElementaryTypeName","src":"817:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"816:30:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":68,"nodeType":"FunctionDefinition","src":"852:74:0","nodes":[],"functionSelector":"b4d6c782","implemented":false,"kind":"function","modifiers":[],"name":"etch","nameLocation":"861:4:0","parameters":{"id":66,"nodeType":"ParameterList","parameters":[{"constant":false,"id":63,"mutability":"mutable","name":"target","nameLocation":"874:6:0","nodeType":"VariableDeclaration","scope":68,"src":"866:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":62,"name":"address","nodeType":"ElementaryTypeName","src":"866:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":65,"mutability":"mutable","name":"newRuntimeBytecode","nameLocation":"897:18:0","nodeType":"VariableDeclaration","scope":68,"src":"882:33:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":64,"name":"bytes","nodeType":"ElementaryTypeName","src":"882:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"865:51:0"},"returnParameters":{"id":67,"nodeType":"ParameterList","parameters":[],"src":"925:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":73,"nodeType":"FunctionDefinition","src":"931:51:0","nodes":[],"functionSelector":"ea060291","implemented":false,"kind":"function","modifiers":[],"name":"allowCheatcodes","nameLocation":"940:15:0","parameters":{"id":71,"nodeType":"ParameterList","parameters":[{"constant":false,"id":70,"mutability":"mutable","name":"account","nameLocation":"964:7:0","nodeType":"VariableDeclaration","scope":73,"src":"956:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":69,"name":"address","nodeType":"ElementaryTypeName","src":"956:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"955:17:0"},"returnParameters":{"id":72,"nodeType":"ParameterList","parameters":[],"src":"981:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":82,"nodeType":"FunctionDefinition","src":"987:100:0","nodes":[],"functionSelector":"71ee464d","implemented":false,"kind":"function","modifiers":[],"name":"createSelectFork","nameLocation":"996:16:0","parameters":{"id":78,"nodeType":"ParameterList","parameters":[{"constant":false,"id":75,"mutability":"mutable","name":"forkName","nameLocation":"1029:8:0","nodeType":"VariableDeclaration","scope":82,"src":"1013:24:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":74,"name":"string","nodeType":"ElementaryTypeName","src":"1013:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":77,"mutability":"mutable","name":"blockNumber","nameLocation":"1047:11:0","nodeType":"VariableDeclaration","scope":82,"src":"1039:19:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":76,"name":"uint256","nodeType":"ElementaryTypeName","src":"1039:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1012:47:0"},"returnParameters":{"id":81,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":82,"src":"1078:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":79,"name":"uint256","nodeType":"ElementaryTypeName","src":"1078:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1077:9:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"Vm","contractDependencies":[],"contractKind":"interface","fullyImplemented":false,"linearizedBaseContracts":[83],"name":"Vm","nameLocation":"130:2:0","scope":969,"usedErrors":[]},{"id":220,"nodeType":"ContractDefinition","src":"1144:1851:0","nodes":[{"id":89,"nodeType":"VariableDeclaration","src":"1166:86:0","nodes":[],"constant":true,"mutability":"constant","name":"CONSOLE_ADDRESS","nameLocation":"1183:15:0","scope":220,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":84,"name":"address","nodeType":"ElementaryTypeName","src":"1166:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"hexValue":"307830303030303030303030303030303030303036333646366537333646366336353265366336663637","id":87,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1209:42:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"value":"0x000000000000000000636F6e736F6c652e6c6f67"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":86,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":85,"name":"address","nodeType":"ElementaryTypeName","src":"1201:7:0","typeDescriptions":{}}},"id":88,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1201:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":106,"nodeType":"FunctionDefinition","src":"1259:235:0","nodes":[],"body":{"id":105,"nodeType":"Block","src":"1432:62:0","nodes":[],"statements":[{"AST":{"nodeType":"YulBlock","src":"1451:37:0","statements":[{"nodeType":"YulAssignment","src":"1465:13:0","value":{"name":"fnIn","nodeType":"YulIdentifier","src":"1474:4:0"},"variableNames":[{"name":"fnOut","nodeType":"YulIdentifier","src":"1465:5:0"}]}]},"evmVersion":"london","externalReferences":[{"declaration":95,"isOffset":false,"isSlot":false,"src":"1474:4:0","valueSize":1},{"declaration":102,"isOffset":false,"isSlot":false,"src":"1465:5:0","valueSize":1}],"id":104,"nodeType":"InlineAssembly","src":"1442:46:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_castLogPayloadViewToPure","nameLocation":"1268:25:0","parameters":{"id":96,"nodeType":"ParameterList","parameters":[{"constant":false,"id":95,"mutability":"mutable","name":"fnIn","nameLocation":"1331:4:0","nodeType":"VariableDeclaration","scope":106,"src":"1294:41:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"typeName":{"id":94,"nodeType":"FunctionTypeName","parameterTypes":{"id":92,"nodeType":"ParameterList","parameters":[{"constant":false,"id":91,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":94,"src":"1303:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":90,"name":"bytes","nodeType":"ElementaryTypeName","src":"1303:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1302:14:0"},"returnParameterTypes":{"id":93,"nodeType":"ParameterList","parameters":[],"src":"1331:0:0"},"src":"1294:41:0","stateMutability":"view","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"visibility":"internal"},"visibility":"internal"}],"src":"1293:43:0"},"returnParameters":{"id":103,"nodeType":"ParameterList","parameters":[{"constant":false,"id":102,"mutability":"mutable","name":"fnOut","nameLocation":"1421:5:0","nodeType":"VariableDeclaration","scope":106,"src":"1384:42:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"typeName":{"id":101,"nodeType":"FunctionTypeName","parameterTypes":{"id":99,"nodeType":"ParameterList","parameters":[{"constant":false,"id":98,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":101,"src":"1393:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":97,"name":"bytes","nodeType":"ElementaryTypeName","src":"1393:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1392:14:0"},"returnParameterTypes":{"id":100,"nodeType":"ParameterList","parameters":[],"src":"1421:0:0"},"src":"1384:42:0","stateMutability":"pure","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"visibility":"internal"},"visibility":"internal"}],"src":"1383:44:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":118,"nodeType":"FunctionDefinition","src":"1500:133:0","nodes":[],"body":{"id":117,"nodeType":"Block","src":"1561:72:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":114,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":108,"src":"1618:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"arguments":[{"id":112,"name":"_sendLogPayloadView","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":134,"src":"1597:19:0","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}],"id":111,"name":"_castLogPayloadViewToPure","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":106,"src":"1571:25:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_function_internal_view$_t_bytes_memory_ptr_$returns$__$_$returns$_t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$_$","typeString":"function (function (bytes memory) view) pure returns (function (bytes memory) pure)"}},"id":113,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":115,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":116,"nodeType":"ExpressionStatement","src":"1571:55:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayload","nameLocation":"1509:15:0","parameters":{"id":109,"nodeType":"ParameterList","parameters":[{"constant":false,"id":108,"mutability":"mutable","name":"payload","nameLocation":"1538:7:0","nodeType":"VariableDeclaration","scope":118,"src":"1525:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":107,"name":"bytes","nodeType":"ElementaryTypeName","src":"1525:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1524:22:0"},"returnParameters":{"id":110,"nodeType":"ParameterList","parameters":[],"src":"1561:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":134,"nodeType":"FunctionDefinition","src":"1639:380:0","nodes":[],"body":{"id":133,"nodeType":"Block","src":"1703:316:0","nodes":[],"statements":[{"assignments":[124],"declarations":[{"constant":false,"id":124,"mutability":"mutable","name":"payloadLength","nameLocation":"1721:13:0","nodeType":"VariableDeclaration","scope":133,"src":"1713:21:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":123,"name":"uint256","nodeType":"ElementaryTypeName","src":"1713:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":127,"initialValue":{"expression":{"id":125,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":120,"src":"1737:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":126,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1737:14:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1713:38:0"},{"assignments":[129],"declarations":[{"constant":false,"id":129,"mutability":"mutable","name":"consoleAddress","nameLocation":"1769:14:0","nodeType":"VariableDeclaration","scope":133,"src":"1761:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":128,"name":"address","nodeType":"ElementaryTypeName","src":"1761:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":131,"initialValue":{"id":130,"name":"CONSOLE_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":89,"src":"1786:15:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"1761:40:0"},{"AST":{"nodeType":"YulBlock","src":"1863:150:0","statements":[{"nodeType":"YulVariableDeclaration","src":"1877:36:0","value":{"arguments":[{"name":"payload","nodeType":"YulIdentifier","src":"1901:7:0"},{"kind":"number","nodeType":"YulLiteral","src":"1910:2:0","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1897:3:0"},"nodeType":"YulFunctionCall","src":"1897:16:0"},"variables":[{"name":"payloadStart","nodeType":"YulTypedName","src":"1881:12:0","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1926:77:0","value":{"arguments":[{"arguments":[],"functionName":{"name":"gas","nodeType":"YulIdentifier","src":"1946:3:0"},"nodeType":"YulFunctionCall","src":"1946:5:0"},{"name":"consoleAddress","nodeType":"YulIdentifier","src":"1953:14:0"},{"name":"payloadStart","nodeType":"YulIdentifier","src":"1969:12:0"},{"name":"payloadLength","nodeType":"YulIdentifier","src":"1983:13:0"},{"kind":"number","nodeType":"YulLiteral","src":"1998:1:0","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"2001:1:0","type":"","value":"0"}],"functionName":{"name":"staticcall","nodeType":"YulIdentifier","src":"1935:10:0"},"nodeType":"YulFunctionCall","src":"1935:68:0"},"variables":[{"name":"r","nodeType":"YulTypedName","src":"1930:1:0","type":""}]}]},"documentation":"@solidity memory-safe-assembly","evmVersion":"london","externalReferences":[{"declaration":129,"isOffset":false,"isSlot":false,"src":"1953:14:0","valueSize":1},{"declaration":120,"isOffset":false,"isSlot":false,"src":"1901:7:0","valueSize":1},{"declaration":124,"isOffset":false,"isSlot":false,"src":"1983:13:0","valueSize":1}],"id":132,"nodeType":"InlineAssembly","src":"1854:159:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayloadView","nameLocation":"1648:19:0","parameters":{"id":121,"nodeType":"ParameterList","parameters":[{"constant":false,"id":120,"mutability":"mutable","name":"payload","nameLocation":"1681:7:0","nodeType":"VariableDeclaration","scope":134,"src":"1668:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":119,"name":"bytes","nodeType":"ElementaryTypeName","src":"1668:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1667:22:0"},"returnParameters":{"id":122,"nodeType":"ParameterList","parameters":[],"src":"1703:0:0"},"scope":220,"stateMutability":"view","virtual":false,"visibility":"private"},{"id":148,"nodeType":"FunctionDefinition","src":"2025:164:0","nodes":[],"body":{"id":147,"nodeType":"Block","src":"2070:119:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e6729","id":142,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2120:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},"value":"log(string)"},{"id":143,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":136,"src":"2135:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":140,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2096:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":141,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2096:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":144,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2096:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":139,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2080:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":145,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2080:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":146,"nodeType":"ExpressionStatement","src":"2080:59:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2034:3:0","parameters":{"id":137,"nodeType":"ParameterList","parameters":[{"constant":false,"id":136,"mutability":"mutable","name":"p0","nameLocation":"2052:2:0","nodeType":"VariableDeclaration","scope":148,"src":"2038:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":135,"name":"string","nodeType":"ElementaryTypeName","src":"2038:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2037:18:0"},"returnParameters":{"id":138,"nodeType":"ParameterList","parameters":[],"src":"2070:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":165,"nodeType":"FunctionDefinition","src":"2195:182:0","nodes":[],"body":{"id":164,"nodeType":"Block","src":"2249:128:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c626f6f6c29","id":158,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2299:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},"value":"log(string,bool)"},{"id":159,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":150,"src":"2319:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":160,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":152,"src":"2323:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":156,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2275:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":157,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2275:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":161,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2275:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":155,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2259:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":162,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2259:68:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":163,"nodeType":"ExpressionStatement","src":"2259:68:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2204:3:0","parameters":{"id":153,"nodeType":"ParameterList","parameters":[{"constant":false,"id":150,"mutability":"mutable","name":"p0","nameLocation":"2222:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2208:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":149,"name":"string","nodeType":"ElementaryTypeName","src":"2208:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":152,"mutability":"mutable","name":"p1","nameLocation":"2231:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2226:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":151,"name":"bool","nodeType":"ElementaryTypeName","src":"2226:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"2207:27:0"},"returnParameters":{"id":154,"nodeType":"ParameterList","parameters":[],"src":"2249:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":182,"nodeType":"FunctionDefinition","src":"2383:188:0","nodes":[],"body":{"id":181,"nodeType":"Block","src":"2440:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c75696e7432353629","id":175,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2490:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},"value":"log(string,uint256)"},{"id":176,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":167,"src":"2513:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":177,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":169,"src":"2517:2:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":173,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2466:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":174,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2466:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":178,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2466:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":172,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2450:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":179,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2450:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":180,"nodeType":"ExpressionStatement","src":"2450:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2392:3:0","parameters":{"id":170,"nodeType":"ParameterList","parameters":[{"constant":false,"id":167,"mutability":"mutable","name":"p0","nameLocation":"2410:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2396:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":166,"name":"string","nodeType":"ElementaryTypeName","src":"2396:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":169,"mutability":"mutable","name":"p1","nameLocation":"2422:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2414:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":168,"name":"uint256","nodeType":"ElementaryTypeName","src":"2414:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"2395:30:0"},"returnParameters":{"id":171,"nodeType":"ParameterList","parameters":[],"src":"2440:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":199,"nodeType":"FunctionDefinition","src":"2577:188:0","nodes":[],"body":{"id":198,"nodeType":"Block","src":"2634:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c6164647265737329","id":192,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2684:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},"value":"log(string,address)"},{"id":193,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":184,"src":"2707:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":194,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":186,"src":"2711:2:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":190,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2660:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":191,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2660:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":195,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2660:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":189,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2644:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":196,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2644:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":197,"nodeType":"ExpressionStatement","src":"2644:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2586:3:0","parameters":{"id":187,"nodeType":"ParameterList","parameters":[{"constant":false,"id":184,"mutability":"mutable","name":"p0","nameLocation":"2604:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2590:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":183,"name":"string","nodeType":"ElementaryTypeName","src":"2590:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":186,"mutability":"mutable","name":"p1","nameLocation":"2616:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2608:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":185,"name":"address","nodeType":"ElementaryTypeName","src":"2608:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2589:30:0"},"returnParameters":{"id":188,"nodeType":"ParameterList","parameters":[],"src":"2634:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":219,"nodeType":"FunctionDefinition","src":"2771:222:0","nodes":[],"body":{"id":218,"nodeType":"Block","src":"2852:141:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c737472696e672c737472696e6729","id":211,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2902:27:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},"value":"log(string,string,string)"},{"id":212,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":201,"src":"2931:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":213,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":203,"src":"2935:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":214,"name":"p2","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":205,"src":"2939:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":209,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2878:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":210,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2878:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":215,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2878:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":208,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2862:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":216,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2862:81:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":217,"nodeType":"ExpressionStatement","src":"2862:81:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2780:3:0","parameters":{"id":206,"nodeType":"ParameterList","parameters":[{"constant":false,"id":201,"mutability":"mutable","name":"p0","nameLocation":"2798:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2784:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":200,"name":"string","nodeType":"ElementaryTypeName","src":"2784:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":203,"mutability":"mutable","name":"p1","nameLocation":"2816:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2802:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":202,"name":"string","nodeType":"ElementaryTypeName","src":"2802:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":205,"mutability":"mutable","name":"p2","nameLocation":"2834:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2820:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":204,"name":"string","nodeType":"ElementaryTypeName","src":"2820:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2783:54:0"},"returnParameters":{"id":207,"nodeType":"ParameterList","parameters":[],"src":"2852:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"}],"abstract":false,"baseContracts":[],"canonicalName":"console","contractDependencies":[],"contractKind":"library","fullyImplemented":true,"linearizedBaseContracts":[220],"name":"console","nameLocation":"1152:7:0","scope":969,"usedErrors":[]},{"id":786,"nodeType":"ContractDefinition","src":"3123:3912:0","nodes":[{"id":235,"nodeType":"VariableDeclaration","src":"3152:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"3178:10:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":222,"name":"address","nodeType":"ElementaryTypeName","src":"3152:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":230,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3225:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":229,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"3215:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":231,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3215:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":228,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3207:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":227,"name":"uint256","nodeType":"ElementaryTypeName","src":"3207:7:0","typeDescriptions":{}}},"id":232,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3207:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":226,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3199:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":225,"name":"uint160","nodeType":"ElementaryTypeName","src":"3199:7:0","typeDescriptions":{}}},"id":233,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3199:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":224,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3191:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":223,"name":"address","nodeType":"ElementaryTypeName","src":"3191:7:0","typeDescriptions":{}}},"id":234,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3191:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":241,"nodeType":"VariableDeclaration","src":"3252:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"3273:2:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":237,"nodeType":"UserDefinedTypeName","pathNode":{"id":236,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"3252:2:0"},"referencedDeclaration":83,"src":"3252:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":239,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":235,"src":"3281:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":238,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"3278:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":240,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3278:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":243,"nodeType":"VariableDeclaration","src":"3356:22:0","nodes":[],"constant":false,"functionSelector":"61bc221a","mutability":"mutable","name":"counter","nameLocation":"3371:7:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":242,"name":"uint256","nodeType":"ElementaryTypeName","src":"3356:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":456,"nodeType":"FunctionDefinition","src":"3468:1428:0","nodes":[],"body":{"id":455,"nodeType":"Block","src":"3490:1406:0","nodes":[],"statements":[{"assignments":[248],"declarations":[{"constant":false,"id":248,"mutability":"mutable","name":"x","nameLocation":"3505:1:0","nodeType":"VariableDeclaration","scope":455,"src":"3500:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":247,"name":"bool","nodeType":"ElementaryTypeName","src":"3500:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"id":254,"initialValue":{"arguments":[{"hexValue":"4558414d504c455f424f4f4c","id":251,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3518:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},"value":"EXAMPLE_BOOL"},{"hexValue":"66616c7365","id":252,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"3534:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":249,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3509:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":250,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"envOr","nodeType":"MemberAccess","referencedDeclaration":10,"src":"3509:8:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$_t_bool_$returns$_t_bool_$","typeString":"function (string memory,bool) view external returns (bool)"}},"id":253,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3509:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"VariableDeclarationStatement","src":"3500:40:0"},{"expression":{"arguments":[{"hexValue":"626f6f6c2076616c75652066726f6d20656e76","id":258,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3562:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},"value":"bool value from env"},{"id":259,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":248,"src":"3585:1:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":255,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3550:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":257,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":165,"src":"3550:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_bool_$returns$__$","typeString":"function (string memory,bool) pure"}},"id":260,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3550:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":261,"nodeType":"ExpressionStatement","src":"3550:37:0"},{"expression":{"arguments":[{"hexValue":"636f6e74726163742061646472","id":265,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3610:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},"value":"contract addr"},{"arguments":[{"id":268,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3635:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":267,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3627:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":266,"name":"address","nodeType":"ElementaryTypeName","src":"3627:7:0","typeDescriptions":{}}},"id":269,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3627:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":262,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3598:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":264,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3598:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":270,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3598:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":271,"nodeType":"ExpressionStatement","src":"3598:43:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206e6f6e6365","id":275,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3663:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},"value":"contract nonce"},{"arguments":[{"arguments":[{"id":280,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3701:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":279,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3693:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":278,"name":"address","nodeType":"ElementaryTypeName","src":"3693:7:0","typeDescriptions":{}}},"id":281,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3693:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":276,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3681:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":277,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3681:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":282,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3681:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":272,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3651:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":274,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3651:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":283,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3651:57:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":284,"nodeType":"ExpressionStatement","src":"3651:57:0"},{"expression":{"arguments":[{"hexValue":"73656e6465722061646472","id":288,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3730:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},"value":"sender addr"},{"arguments":[{"expression":{"id":291,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3753:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":292,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3753:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":290,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3745:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":289,"name":"address","nodeType":"ElementaryTypeName","src":"3745:7:0","typeDescriptions":{}}},"id":293,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3745:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":285,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3718:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":287,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3718:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":294,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3718:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":295,"nodeType":"ExpressionStatement","src":"3718:47:0"},{"expression":{"arguments":[{"hexValue":"73656e646572206e6f6e6365","id":299,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3787:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},"value":"sender nonce"},{"arguments":[{"arguments":[{"expression":{"id":304,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3823:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":305,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3823:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":303,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3815:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":302,"name":"address","nodeType":"ElementaryTypeName","src":"3815:7:0","typeDescriptions":{}}},"id":306,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3815:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":300,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3803:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":301,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3803:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":307,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3803:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":296,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3775:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":298,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3775:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":308,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3775:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":309,"nodeType":"ExpressionStatement","src":"3775:61:0"},{"assignments":[311],"declarations":[{"constant":false,"id":311,"mutability":"mutable","name":"json","nameLocation":"3861:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3847:18:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":310,"name":"string","nodeType":"ElementaryTypeName","src":"3847:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"id":313,"initialValue":{"hexValue":"7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d","id":312,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3868:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e95522e99766888d0261f55bd1eae5e3f3e26eaf009a16e2433eafaf0a4ecdf2","typeString":"literal_string \"{\"root_key\": [{\"a\": 1, \"b\": 2}]}\""},"value":"{\"root_key\": [{\"a\": 1, \"b\": 2}]}"},"nodeType":"VariableDeclarationStatement","src":"3847:55:0"},{"assignments":[318],"declarations":[{"constant":false,"id":318,"mutability":"mutable","name":"keys","nameLocation":"3928:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3912:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":316,"name":"string","nodeType":"ElementaryTypeName","src":"3912:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":317,"nodeType":"ArrayTypeName","src":"3912:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"id":324,"initialValue":{"arguments":[{"id":321,"name":"json","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":311,"src":"3952:4:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"2e726f6f745f6b65795b305d","id":322,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3958:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""},"value":".root_key[0]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""}],"expression":{"id":319,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3935:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":320,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"parseJsonKeys","nodeType":"MemberAccess","referencedDeclaration":27,"src":"3935:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$_t_array$_t_string_memory_ptr_$dyn_memory_ptr_$","typeString":"function (string memory,string memory) pure external returns (string memory[] memory)"}},"id":323,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3935:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"nodeType":"VariableDeclarationStatement","src":"3912:61:0"},{"expression":{"arguments":[{"hexValue":"6b657973","id":328,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3995:6:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},"value":"keys"},{"baseExpression":{"id":329,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4003:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":331,"indexExpression":{"hexValue":"30","id":330,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4008:1:0","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4003:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"baseExpression":{"id":332,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4012:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":334,"indexExpression":{"hexValue":"31","id":333,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4017:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4012:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":325,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3983:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":327,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":219,"src":"3983:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory,string memory) pure"}},"id":335,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3983:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":336,"nodeType":"ExpressionStatement","src":"3983:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c","id":340,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4042:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""},"value":"from original"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""}],"expression":{"id":337,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4031:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":339,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4031:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":341,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4031:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":342,"nodeType":"ExpressionStatement","src":"4031:27:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"30783432","id":350,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4098:4:0","typeDescriptions":{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"},"value":"0x42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"}],"id":349,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4090:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":348,"name":"uint160","nodeType":"ElementaryTypeName","src":"4090:7:0","typeDescriptions":{}}},"id":351,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4090:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":347,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4082:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":346,"name":"address","nodeType":"ElementaryTypeName","src":"4082:7:0","typeDescriptions":{}}},"id":352,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4082:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":343,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4068:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":345,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startPrank","nodeType":"MemberAccess","referencedDeclaration":32,"src":"4068:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":353,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4068:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":354,"nodeType":"ExpressionStatement","src":"4068:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2031","id":358,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4126:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""},"value":"from prank 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""}],"expression":{"id":355,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4115:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":357,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4115:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":359,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4115:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":360,"nodeType":"ExpressionStatement","src":"4115:26:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f7065206d73672e73656e646572","id":364,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4163:25:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},"value":"parent scope msg.sender"},{"arguments":[{"expression":{"id":367,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"4198:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":368,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"4198:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":366,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4190:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":365,"name":"address","nodeType":"ElementaryTypeName","src":"4190:7:0","typeDescriptions":{}}},"id":369,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4190:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":361,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4151:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":363,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4151:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":370,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4151:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":371,"nodeType":"ExpressionStatement","src":"4151:59:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f706520636f6e74726163742e61646472","id":375,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4232:28:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},"value":"parent scope contract.addr"},{"arguments":[{"id":378,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4270:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":377,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4262:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":376,"name":"address","nodeType":"ElementaryTypeName","src":"4262:7:0","typeDescriptions":{}}},"id":379,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4262:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":372,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4220:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":374,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4220:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":380,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4220:56:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":381,"nodeType":"ExpressionStatement","src":"4220:56:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2032","id":385,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4297:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""},"value":"from prank 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""}],"expression":{"id":382,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4286:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":384,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4286:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":386,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4286:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":387,"nodeType":"ExpressionStatement","src":"4286:26:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":388,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4322:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":390,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopPrank","nodeType":"MemberAccess","referencedDeclaration":35,"src":"4322:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":391,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4322:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":392,"nodeType":"ExpressionStatement","src":"4322:14:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c20616761696e","id":396,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4357:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""},"value":"from original again"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""}],"expression":{"id":393,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4346:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":395,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4346:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":397,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4346:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":398,"nodeType":"ExpressionStatement","src":"4346:33:0"},{"assignments":[400],"declarations":[{"constant":false,"id":400,"mutability":"mutable","name":"tmpNonceGetter","nameLocation":"4480:14:0","nodeType":"VariableDeclaration","scope":455,"src":"4472:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":399,"name":"address","nodeType":"ElementaryTypeName","src":"4472:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":413,"initialValue":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"74656d70206e6f6e6365207465737420676574746572","id":408,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4531:24:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""},"value":"temp nonce test getter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""}],"id":407,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"4521:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":409,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4521:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":406,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4513:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":405,"name":"uint256","nodeType":"ElementaryTypeName","src":"4513:7:0","typeDescriptions":{}}},"id":410,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4513:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":404,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4505:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":403,"name":"uint160","nodeType":"ElementaryTypeName","src":"4505:7:0","typeDescriptions":{}}},"id":411,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4505:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":402,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4497:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":401,"name":"address","nodeType":"ElementaryTypeName","src":"4497:7:0","typeDescriptions":{}}},"id":412,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4497:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"4472:87:0"},{"expression":{"arguments":[{"id":417,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4577:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"arguments":[{"hexValue":"5363726970744578616d706c652e732e736f6c3a4e6f6e6365476574746572","id":420,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4612:33:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""},"value":"ScriptExample.s.sol:NonceGetter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""}],"expression":{"id":418,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4593:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":419,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getDeployedCode","nodeType":"MemberAccess","referencedDeclaration":61,"src":"4593:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) view external returns (bytes memory)"}},"id":421,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4593:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"expression":{"id":414,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4569:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":416,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"etch","nodeType":"MemberAccess","referencedDeclaration":68,"src":"4569:7:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$_t_bytes_memory_ptr_$returns$__$","typeString":"function (address,bytes memory) external"}},"id":422,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4569:78:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":423,"nodeType":"ExpressionStatement","src":"4569:78:0"},{"expression":{"arguments":[{"id":427,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4676:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":424,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4657:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":426,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"allowCheatcodes","nodeType":"MemberAccess","referencedDeclaration":73,"src":"4657:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":428,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4657:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":429,"nodeType":"ExpressionStatement","src":"4657:34:0"},{"assignments":[431],"declarations":[{"constant":false,"id":431,"mutability":"mutable","name":"v","nameLocation":"4709:1:0","nodeType":"VariableDeclaration","scope":455,"src":"4701:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":430,"name":"uint256","nodeType":"ElementaryTypeName","src":"4701:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":441,"initialValue":{"arguments":[{"arguments":[{"id":438,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4758:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":437,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4750:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":436,"name":"address","nodeType":"ElementaryTypeName","src":"4750:7:0","typeDescriptions":{}}},"id":439,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4750:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"arguments":[{"id":433,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4725:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":432,"name":"NonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":833,"src":"4713:11:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_NonceGetter_$833_$","typeString":"type(contract NonceGetter)"}},"id":434,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_NonceGetter_$833","typeString":"contract NonceGetter"}},"id":435,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":832,"src":"4713:36:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint256_$","typeString":"function (address) view external returns (uint256)"}},"id":440,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"4701:63:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e63652066726f6d206e6f6e6365206765747465722c206e6f206578706c6963697420616363657373207265717569726564207769746820766d2e657463683a","id":445,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4786:68:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},"value":"nonce from nonce getter, no explicit access required with vm.etch:"},{"id":446,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":431,"src":"4856:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":442,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4774:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":444,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"4774:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":447,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4774:84:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":448,"nodeType":"ExpressionStatement","src":"4774:84:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":452,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4881:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":449,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4869:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":451,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"4869:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":453,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4869:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":454,"nodeType":"ExpressionStatement","src":"4869:20:0"}]},"documentation":{"id":244,"nodeType":"StructuredDocumentation","src":"3385:78:0","text":"@notice example function, runs through basic cheat-codes and console logs."},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"3477:3:0","parameters":{"id":245,"nodeType":"ParameterList","parameters":[],"src":"3480:2:0"},"returnParameters":{"id":246,"nodeType":"ParameterList","parameters":[],"src":"3490:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":689,"nodeType":"FunctionDefinition","src":"4963:1333:0","nodes":[],"body":{"id":688,"nodeType":"Block","src":"4994:1302:0","nodes":[],"statements":[{"expression":{"arguments":[{"hexValue":"6e6f6e6365207374617274","id":463,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5016:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},"value":"nonce start"},{"arguments":[{"arguments":[{"arguments":[{"id":470,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5059:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":469,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5051:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":468,"name":"address","nodeType":"ElementaryTypeName","src":"5051:7:0","typeDescriptions":{}}},"id":471,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5051:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":466,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5039:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":467,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"5039:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":472,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5039:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":465,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5031:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":464,"name":"uint256","nodeType":"ElementaryTypeName","src":"5031:7:0","typeDescriptions":{}}},"id":473,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5031:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":460,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5004:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":462,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"5004:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":474,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5004:63:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":475,"nodeType":"ExpressionStatement","src":"5004:63:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073696e676c65","id":479,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5090:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""},"value":"testing single"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""}],"expression":{"id":476,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5078:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":478,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5078:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":480,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5078:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":481,"nodeType":"ExpressionStatement","src":"5078:29:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":482,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5117:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":484,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"5117:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":485,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5117:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":486,"nodeType":"ExpressionStatement","src":"5117:14:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c31","id":490,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5152:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""},"value":"single_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""}],"expression":{"id":487,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5141:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":489,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5141:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":491,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5141:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":492,"nodeType":"ExpressionStatement","src":"5141:26:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c32","id":496,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5188:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""},"value":"single_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""}],"expression":{"id":493,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5177:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":495,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5177:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":497,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5177:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":498,"nodeType":"ExpressionStatement","src":"5177:26:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073746172742f73746f70","id":502,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5226:20:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""},"value":"testing start/stop"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""}],"expression":{"id":499,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5214:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":501,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5214:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":503,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5214:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":504,"nodeType":"ExpressionStatement","src":"5214:33:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078633066666565","id":512,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5291:8:0","typeDescriptions":{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"},"value":"0xc0ffee"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"}],"id":511,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5283:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":510,"name":"uint160","nodeType":"ElementaryTypeName","src":"5283:7:0","typeDescriptions":{}}},"id":513,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5283:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":509,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5275:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":508,"name":"address","nodeType":"ElementaryTypeName","src":"5275:7:0","typeDescriptions":{}}},"id":514,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5275:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":505,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5257:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":507,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5257:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":515,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5257:45:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":516,"nodeType":"ExpressionStatement","src":"5257:45:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c31","id":520,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5323:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""},"value":"startstop_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""}],"expression":{"id":517,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5312:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":519,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5312:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":521,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5312:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":522,"nodeType":"ExpressionStatement","src":"5312:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c32","id":526,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5362:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""},"value":"startstop_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""}],"expression":{"id":523,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5351:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":525,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5351:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":527,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5351:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":528,"nodeType":"ExpressionStatement","src":"5351:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f70757265","id":532,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5404:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""},"value":"startstop_pure"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""}],"expression":{"id":529,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5390:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":531,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"callPure","nodeType":"MemberAccess","referencedDeclaration":785,"src":"5390:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure external"}},"id":533,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5390:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":534,"nodeType":"ExpressionStatement","src":"5390:31:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":535,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5431:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":537,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5431:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":538,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5431:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":539,"nodeType":"ExpressionStatement","src":"5431:18:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c33","id":543,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5470:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""},"value":"startstop_call3"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""}],"expression":{"id":540,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5459:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":542,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5459:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":544,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5459:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":545,"nodeType":"ExpressionStatement","src":"5459:29:0"},{"expression":{"arguments":[{"hexValue":"74657374696e67206e6573746564","id":549,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5511:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""},"value":"testing nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""}],"expression":{"id":546,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5499:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":548,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5499:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":550,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5499:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":551,"nodeType":"ExpressionStatement","src":"5499:29:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307831323334","id":559,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5572:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":558,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5564:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":557,"name":"uint160","nodeType":"ElementaryTypeName","src":"5564:7:0","typeDescriptions":{}}},"id":560,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5564:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":556,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5556:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":555,"name":"address","nodeType":"ElementaryTypeName","src":"5556:7:0","typeDescriptions":{}}},"id":561,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5556:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":552,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5538:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":554,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5538:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":562,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5538:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":563,"nodeType":"ExpressionStatement","src":"5538:43:0"},{"expression":{"arguments":[{"hexValue":"6e6573746564","id":567,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5604:8:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""},"value":"nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""}],"expression":{"id":564,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5591:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":566,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested1","nodeType":"MemberAccess","referencedDeclaration":758,"src":"5591:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":568,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5591:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":569,"nodeType":"ExpressionStatement","src":"5591:22:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":570,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5623:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":572,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5623:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":573,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5623:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":574,"nodeType":"ExpressionStatement","src":"5623:18:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206465706c6f796d656e74","id":578,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5664:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""},"value":"contract deployment"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""}],"expression":{"id":575,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5652:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":577,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5652:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":579,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5652:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":580,"nodeType":"ExpressionStatement","src":"5652:34:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078313233343536","id":588,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5725:8:0","typeDescriptions":{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"},"value":"0x123456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"}],"id":587,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5717:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":586,"name":"uint160","nodeType":"ElementaryTypeName","src":"5717:7:0","typeDescriptions":{}}},"id":589,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5717:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":585,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5709:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":584,"name":"address","nodeType":"ElementaryTypeName","src":"5709:7:0","typeDescriptions":{}}},"id":590,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5709:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":581,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5696:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":583,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5696:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":591,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5696:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":592,"nodeType":"ExpressionStatement","src":"5696:40:0"},{"assignments":[595],"declarations":[{"constant":false,"id":595,"mutability":"mutable","name":"x","nameLocation":"5753:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5746:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":594,"nodeType":"UserDefinedTypeName","pathNode":{"id":593,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5746:6:0"},"referencedDeclaration":799,"src":"5746:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":601,"initialValue":{"arguments":[{"hexValue":"31323334","id":599,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5768:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":598,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5757:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":597,"nodeType":"UserDefinedTypeName","pathNode":{"id":596,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5761:6:0"},"referencedDeclaration":799,"src":"5761:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":600,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5757:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5746:27:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":607,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":603,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":595,"src":"5791:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":604,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"5791:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":605,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5791:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":606,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5802:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"5791:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e20637265617465206973206e6f742031323334","id":608,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5808:35:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""},"value":"FooBar: foo in create is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""}],"id":602,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"5783:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":609,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5783:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":610,"nodeType":"ExpressionStatement","src":"5783:61:0"},{"expression":{"arguments":[{"hexValue":"6372656174652032","id":614,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5867:10:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""},"value":"create 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""}],"expression":{"id":611,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5855:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":613,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5855:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":615,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5855:23:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":616,"nodeType":"ExpressionStatement","src":"5855:23:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307863616665","id":624,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5917:6:0","typeDescriptions":{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"},"value":"0xcafe"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"}],"id":623,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5909:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":622,"name":"uint160","nodeType":"ElementaryTypeName","src":"5909:7:0","typeDescriptions":{}}},"id":625,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5909:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":621,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5901:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":620,"name":"address","nodeType":"ElementaryTypeName","src":"5901:7:0","typeDescriptions":{}}},"id":626,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5901:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":617,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5888:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":619,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5888:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":627,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5888:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":628,"nodeType":"ExpressionStatement","src":"5888:38:0"},{"assignments":[631],"declarations":[{"constant":false,"id":631,"mutability":"mutable","name":"y","nameLocation":"5943:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5936:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":630,"nodeType":"UserDefinedTypeName","pathNode":{"id":629,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5936:6:0"},"referencedDeclaration":799,"src":"5936:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":645,"initialValue":{"arguments":[{"hexValue":"31323334","id":643,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5986:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":634,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5947:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":633,"nodeType":"UserDefinedTypeName","pathNode":{"id":632,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5951:6:0"},"referencedDeclaration":799,"src":"5951:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":642,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"names":["salt"],"nodeType":"FunctionCallOptions","options":[{"arguments":[{"arguments":[{"hexValue":"3432","id":639,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5980:2:0","typeDescriptions":{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"},"value":"42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"}],"id":638,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5972:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":637,"name":"uint256","nodeType":"ElementaryTypeName","src":"5972:7:0","typeDescriptions":{}}},"id":640,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5972:11:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":636,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5964:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":635,"name":"bytes32","nodeType":"ElementaryTypeName","src":"5964:7:0","typeDescriptions":{}}},"id":641,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5964:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"src":"5947:38:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$salt","typeString":"function (uint256) returns (contract FooBar)"}},"id":644,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5947:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5936:55:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":651,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":647,"name":"y","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":631,"src":"6009:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":648,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"6009:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":649,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6009:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":650,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6020:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"6009:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e2063726561746532206973206e6f742031323334","id":652,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6026:36:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""},"value":"FooBar: foo in create2 is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""}],"id":646,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"6001:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":653,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6001:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":654,"nodeType":"ExpressionStatement","src":"6001:62:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":658,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6085:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":655,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6073:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":657,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6073:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":659,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6073:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":660,"nodeType":"ExpressionStatement","src":"6073:20:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":661,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6177:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":663,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"6177:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":664,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6177:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":665,"nodeType":"ExpressionStatement","src":"6177:14:0"},{"expression":{"arguments":[{"hexValue":"31323334","id":669,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6212:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":668,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"6201:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":667,"nodeType":"UserDefinedTypeName","pathNode":{"id":666,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"6205:6:0"},"referencedDeclaration":799,"src":"6205:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":670,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6201:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":671,"nodeType":"ExpressionStatement","src":"6201:16:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e636520656e64","id":675,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6240:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},"value":"nonce end"},{"arguments":[{"arguments":[{"arguments":[{"id":682,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6281:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":681,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6273:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":680,"name":"address","nodeType":"ElementaryTypeName","src":"6273:7:0","typeDescriptions":{}}},"id":683,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6273:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":678,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6261:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":679,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"6261:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":684,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6261:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":677,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6253:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":676,"name":"uint256","nodeType":"ElementaryTypeName","src":"6253:7:0","typeDescriptions":{}}},"id":685,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6253:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":672,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6228:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":674,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"6228:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":686,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6228:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":687,"nodeType":"ExpressionStatement","src":"6228:61:0"}]},"documentation":{"id":457,"nodeType":"StructuredDocumentation","src":"4902:56:0","text":"@notice example function, to test vm.broadcast with."},"functionSelector":"bef03abc","implemented":true,"kind":"function","modifiers":[],"name":"runBroadcast","nameLocation":"4972:12:0","parameters":{"id":458,"nodeType":"ParameterList","parameters":[],"src":"4984:2:0"},"returnParameters":{"id":459,"nodeType":"ParameterList","parameters":[],"src":"4994:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":713,"nodeType":"FunctionDefinition","src":"6391:143:0","nodes":[],"body":{"id":712,"nodeType":"Block","src":"6440:94:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":698,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":692,"src":"6462:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":695,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6450:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":697,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6450:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":699,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6450:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":700,"nodeType":"ExpressionStatement","src":"6450:15:0"},{"expression":{"arguments":[{"hexValue":"68656c6c6f206d73672e73656e646572","id":704,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6487:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},"value":"hello msg.sender"},{"arguments":[{"expression":{"id":707,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"6515:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":708,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"6515:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":706,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6507:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":705,"name":"address","nodeType":"ElementaryTypeName","src":"6507:7:0","typeDescriptions":{}}},"id":709,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6507:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":701,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6475:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":703,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"6475:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":710,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6475:52:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":711,"nodeType":"ExpressionStatement","src":"6475:52:0"}]},"documentation":{"id":690,"nodeType":"StructuredDocumentation","src":"6302:84:0","text":"@notice example external function, to force a CALL, and test vm.startPrank with."},"functionSelector":"a777d0dc","implemented":true,"kind":"function","modifiers":[],"name":"hello","nameLocation":"6400:5:0","parameters":{"id":693,"nodeType":"ParameterList","parameters":[{"constant":false,"id":692,"mutability":"mutable","name":"_v","nameLocation":"6422:2:0","nodeType":"VariableDeclaration","scope":713,"src":"6406:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":691,"name":"string","nodeType":"ElementaryTypeName","src":"6406:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6405:20:0"},"returnParameters":{"id":694,"nodeType":"ParameterList","parameters":[],"src":"6440:0:0"},"scope":786,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":728,"nodeType":"FunctionDefinition","src":"6540:95:0","nodes":[],"body":{"id":727,"nodeType":"Block","src":"6584:51:0","nodes":[],"statements":[{"expression":{"id":719,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6594:9:0","subExpression":{"id":718,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6594:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":720,"nodeType":"ExpressionStatement","src":"6594:9:0"},{"expression":{"arguments":[{"id":724,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":715,"src":"6625:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":721,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6613:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":723,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6613:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":725,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6613:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":726,"nodeType":"ExpressionStatement","src":"6613:15:0"}]},"functionSelector":"7e79255d","implemented":true,"kind":"function","modifiers":[],"name":"call1","nameLocation":"6549:5:0","parameters":{"id":716,"nodeType":"ParameterList","parameters":[{"constant":false,"id":715,"mutability":"mutable","name":"_v","nameLocation":"6571:2:0","nodeType":"VariableDeclaration","scope":728,"src":"6555:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":714,"name":"string","nodeType":"ElementaryTypeName","src":"6555:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6554:20:0"},"returnParameters":{"id":717,"nodeType":"ParameterList","parameters":[],"src":"6584:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":743,"nodeType":"FunctionDefinition","src":"6641:95:0","nodes":[],"body":{"id":742,"nodeType":"Block","src":"6685:51:0","nodes":[],"statements":[{"expression":{"id":734,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6695:9:0","subExpression":{"id":733,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6695:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":735,"nodeType":"ExpressionStatement","src":"6695:9:0"},{"expression":{"arguments":[{"id":739,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":730,"src":"6726:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":736,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6714:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":738,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6714:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":740,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6714:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":741,"nodeType":"ExpressionStatement","src":"6714:15:0"}]},"functionSelector":"8d3ef7ca","implemented":true,"kind":"function","modifiers":[],"name":"call2","nameLocation":"6650:5:0","parameters":{"id":731,"nodeType":"ParameterList","parameters":[{"constant":false,"id":730,"mutability":"mutable","name":"_v","nameLocation":"6672:2:0","nodeType":"VariableDeclaration","scope":743,"src":"6656:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":729,"name":"string","nodeType":"ElementaryTypeName","src":"6656:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6655:20:0"},"returnParameters":{"id":732,"nodeType":"ParameterList","parameters":[],"src":"6685:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":758,"nodeType":"FunctionDefinition","src":"6742:98:0","nodes":[],"body":{"id":757,"nodeType":"Block","src":"6788:52:0","nodes":[],"statements":[{"expression":{"id":749,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6798:9:0","subExpression":{"id":748,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6798:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":750,"nodeType":"ExpressionStatement","src":"6798:9:0"},{"expression":{"arguments":[{"id":754,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":745,"src":"6830:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":751,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6817:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":753,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested2","nodeType":"MemberAccess","referencedDeclaration":773,"src":"6817:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":755,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6817:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":756,"nodeType":"ExpressionStatement","src":"6817:16:0"}]},"functionSelector":"a76ccdfa","implemented":true,"kind":"function","modifiers":[],"name":"nested1","nameLocation":"6751:7:0","parameters":{"id":746,"nodeType":"ParameterList","parameters":[{"constant":false,"id":745,"mutability":"mutable","name":"_v","nameLocation":"6775:2:0","nodeType":"VariableDeclaration","scope":758,"src":"6759:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":744,"name":"string","nodeType":"ElementaryTypeName","src":"6759:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6758:20:0"},"returnParameters":{"id":747,"nodeType":"ParameterList","parameters":[],"src":"6788:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":773,"nodeType":"FunctionDefinition","src":"6846:97:0","nodes":[],"body":{"id":772,"nodeType":"Block","src":"6892:51:0","nodes":[],"statements":[{"expression":{"id":764,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6902:9:0","subExpression":{"id":763,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6902:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":765,"nodeType":"ExpressionStatement","src":"6902:9:0"},{"expression":{"arguments":[{"id":769,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":760,"src":"6933:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":766,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6921:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":768,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6921:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":770,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6921:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":771,"nodeType":"ExpressionStatement","src":"6921:15:0"}]},"functionSelector":"dbf1282f","implemented":true,"kind":"function","modifiers":[],"name":"nested2","nameLocation":"6855:7:0","parameters":{"id":761,"nodeType":"ParameterList","parameters":[{"constant":false,"id":760,"mutability":"mutable","name":"_v","nameLocation":"6879:2:0","nodeType":"VariableDeclaration","scope":773,"src":"6863:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":759,"name":"string","nodeType":"ElementaryTypeName","src":"6863:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6862:20:0"},"returnParameters":{"id":762,"nodeType":"ParameterList","parameters":[],"src":"6892:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":785,"nodeType":"FunctionDefinition","src":"6949:84:0","nodes":[],"body":{"id":784,"nodeType":"Block","src":"7001:32:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":781,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":775,"src":"7023:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":778,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"7011:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":780,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"7011:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":782,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7011:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":783,"nodeType":"ExpressionStatement","src":"7011:15:0"}]},"functionSelector":"7f8b915c","implemented":true,"kind":"function","modifiers":[],"name":"callPure","nameLocation":"6958:8:0","parameters":{"id":776,"nodeType":"ParameterList","parameters":[{"constant":false,"id":775,"mutability":"mutable","name":"_v","nameLocation":"6983:2:0","nodeType":"VariableDeclaration","scope":785,"src":"6967:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":774,"name":"string","nodeType":"ElementaryTypeName","src":"6967:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6966:20:0"},"returnParameters":{"id":777,"nodeType":"ParameterList","parameters":[],"src":"7001:0:0"},"scope":786,"stateMutability":"pure","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ScriptExample","contractDependencies":[799],"contractKind":"contract","documentation":{"id":221,"nodeType":"StructuredDocumentation","src":"2997:126:0","text":"@title ScriptExample\n @notice ScriptExample is an example script. The Go forge script code tests that it can run this."},"fullyImplemented":true,"linearizedBaseContracts":[786],"name":"ScriptExample","nameLocation":"3132:13:0","scope":969,"usedErrors":[]},{"id":799,"nodeType":"ContractDefinition","src":"7037:96:0","nodes":[{"id":788,"nodeType":"VariableDeclaration","src":"7059:18:0","nodes":[],"constant":false,"functionSelector":"c2985578","mutability":"mutable","name":"foo","nameLocation":"7074:3:0","scope":799,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":787,"name":"uint256","nodeType":"ElementaryTypeName","src":"7059:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":798,"nodeType":"FunctionDefinition","src":"7084:47:0","nodes":[],"body":{"id":797,"nodeType":"Block","src":"7107:24:0","nodes":[],"statements":[{"expression":{"id":795,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":793,"name":"foo","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":788,"src":"7117:3:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":794,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":790,"src":"7123:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"7117:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":796,"nodeType":"ExpressionStatement","src":"7117:7:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":791,"nodeType":"ParameterList","parameters":[{"constant":false,"id":790,"mutability":"mutable","name":"v","nameLocation":"7104:1:0","nodeType":"VariableDeclaration","scope":798,"src":"7096:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":789,"name":"uint256","nodeType":"ElementaryTypeName","src":"7096:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7095:11:0"},"returnParameters":{"id":792,"nodeType":"ParameterList","parameters":[],"src":"7107:0:0"},"scope":799,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"FooBar","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[799],"name":"FooBar","nameLocation":"7046:6:0","scope":969,"usedErrors":[]},{"id":833,"nodeType":"ContractDefinition","src":"7135:281:0","nodes":[{"id":813,"nodeType":"VariableDeclaration","src":"7162:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7188:10:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":800,"name":"address","nodeType":"ElementaryTypeName","src":"7162:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":808,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7235:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":807,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7225:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":809,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7225:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":806,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7217:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":805,"name":"uint256","nodeType":"ElementaryTypeName","src":"7217:7:0","typeDescriptions":{}}},"id":810,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7217:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":804,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7209:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":803,"name":"uint160","nodeType":"ElementaryTypeName","src":"7209:7:0","typeDescriptions":{}}},"id":811,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7209:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":802,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":801,"name":"address","nodeType":"ElementaryTypeName","src":"7201:7:0","typeDescriptions":{}}},"id":812,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7201:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":819,"nodeType":"VariableDeclaration","src":"7262:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7283:2:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":815,"nodeType":"UserDefinedTypeName","pathNode":{"id":814,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7262:2:0"},"referencedDeclaration":83,"src":"7262:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":817,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":813,"src":"7291:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":816,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7288:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":818,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7288:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":832,"nodeType":"FunctionDefinition","src":"7309:105:0","nodes":[],"body":{"id":831,"nodeType":"Block","src":"7372:42:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":828,"name":"_addr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":821,"src":"7401:5:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":826,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":819,"src":"7389:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":827,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7389:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":829,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7389:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"functionReturnParameters":825,"id":830,"nodeType":"Return","src":"7382:25:0"}]},"functionSelector":"2d0335ab","implemented":true,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"7318:8:0","parameters":{"id":822,"nodeType":"ParameterList","parameters":[{"constant":false,"id":821,"mutability":"mutable","name":"_addr","nameLocation":"7335:5:0","nodeType":"VariableDeclaration","scope":832,"src":"7327:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":820,"name":"address","nodeType":"ElementaryTypeName","src":"7327:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"7326:15:0"},"returnParameters":{"id":825,"nodeType":"ParameterList","parameters":[{"constant":false,"id":824,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":832,"src":"7363:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":823,"name":"uint256","nodeType":"ElementaryTypeName","src":"7363:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7362:9:0"},"scope":833,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"NonceGetter","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[833],"name":"NonceGetter","nameLocation":"7144:11:0","scope":969,"usedErrors":[]},{"id":852,"nodeType":"ContractDefinition","src":"7418:174:0","nodes":[{"id":835,"nodeType":"VariableDeclaration","src":"7448:18:0","nodes":[],"constant":false,"mutability":"mutable","name":"v","nameLocation":"7465:1:0","scope":852,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":834,"name":"uint256","nodeType":"ElementaryTypeName","src":"7448:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"id":843,"nodeType":"FunctionDefinition","src":"7473:36:0","nodes":[],"body":{"id":842,"nodeType":"Block","src":"7487:22:0","nodes":[],"statements":[{"expression":{"id":840,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":838,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7497:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"hexValue":"31","id":839,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7501:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"7497:5:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":841,"nodeType":"ExpressionStatement","src":"7497:5:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":836,"nodeType":"ParameterList","parameters":[],"src":"7484:2:0"},"returnParameters":{"id":837,"nodeType":"ParameterList","parameters":[],"src":"7487:0:0"},"scope":852,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":851,"nodeType":"FunctionDefinition","src":"7515:75:0","nodes":[],"body":{"id":850,"nodeType":"Block","src":"7565:25:0","nodes":[],"statements":[{"expression":{"id":848,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7582:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"functionReturnParameters":847,"id":849,"nodeType":"Return","src":"7575:8:0"}]},"functionSelector":"20965255","implemented":true,"kind":"function","modifiers":[],"name":"getValue","nameLocation":"7524:8:0","parameters":{"id":844,"nodeType":"ParameterList","parameters":[],"src":"7532:2:0"},"returnParameters":{"id":847,"nodeType":"ParameterList","parameters":[{"constant":false,"id":846,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":851,"src":"7556:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":845,"name":"uint256","nodeType":"ElementaryTypeName","src":"7556:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7555:9:0"},"scope":852,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkedContract","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[852],"name":"ForkedContract","nameLocation":"7427:14:0","scope":969,"usedErrors":[]},{"id":968,"nodeType":"ContractDefinition","src":"7594:813:0","nodes":[{"id":866,"nodeType":"VariableDeclaration","src":"7620:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7646:10:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":853,"name":"address","nodeType":"ElementaryTypeName","src":"7620:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":861,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7693:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":860,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7683:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":862,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7683:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":859,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7675:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":858,"name":"uint256","nodeType":"ElementaryTypeName","src":"7675:7:0","typeDescriptions":{}}},"id":863,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7675:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":857,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7667:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":856,"name":"uint160","nodeType":"ElementaryTypeName","src":"7667:7:0","typeDescriptions":{}}},"id":864,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7667:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":855,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7659:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":854,"name":"address","nodeType":"ElementaryTypeName","src":"7659:7:0","typeDescriptions":{}}},"id":865,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7659:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":872,"nodeType":"VariableDeclaration","src":"7720:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7741:2:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":868,"nodeType":"UserDefinedTypeName","pathNode":{"id":867,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7720:2:0"},"referencedDeclaration":83,"src":"7720:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":870,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":866,"src":"7749:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":869,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7746:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":871,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7746:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":967,"nodeType":"FunctionDefinition","src":"7767:638:0","nodes":[],"body":{"id":966,"nodeType":"Block","src":"7791:614:0","nodes":[],"statements":[{"assignments":[876],"declarations":[{"constant":false,"id":876,"mutability":"mutable","name":"testAddr","nameLocation":"7809:8:0","nodeType":"VariableDeclaration","scope":966,"src":"7801:16:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":875,"name":"address","nodeType":"ElementaryTypeName","src":"7801:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":884,"initialValue":{"arguments":[{"arguments":[{"hexValue":"307831323334","id":881,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7836:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":880,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7828:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":879,"name":"uint160","nodeType":"ElementaryTypeName","src":"7828:7:0","typeDescriptions":{}}},"id":882,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7828:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":878,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7820:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":877,"name":"address","nodeType":"ElementaryTypeName","src":"7820:7:0","typeDescriptions":{}}},"id":883,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7820:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"7801:43:0"},{"assignments":[887],"declarations":[{"constant":false,"id":887,"mutability":"mutable","name":"fc","nameLocation":"7869:2:0","nodeType":"VariableDeclaration","scope":966,"src":"7854:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"},"typeName":{"id":886,"nodeType":"UserDefinedTypeName","pathNode":{"id":885,"name":"ForkedContract","nodeType":"IdentifierPath","referencedDeclaration":852,"src":"7854:14:0"},"referencedDeclaration":852,"src":"7854:14:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"visibility":"internal"}],"id":891,"initialValue":{"arguments":[{"id":889,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7889:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":888,"name":"ForkedContract","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":852,"src":"7874:14:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_ForkedContract_$852_$","typeString":"type(contract ForkedContract)"}},"id":890,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7874:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"nodeType":"VariableDeclarationStatement","src":"7854:44:0"},{"expression":{"arguments":[{"hexValue":"666f726b31","id":895,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7929:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},"value":"fork1"},{"hexValue":"3132333435","id":896,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7938:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"}],"expression":{"id":892,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7909:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":894,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"7909:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":897,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7909:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":898,"nodeType":"ExpressionStatement","src":"7909:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":905,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":902,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7974:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":900,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7962:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":901,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7962:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":903,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7962:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3132333435","id":904,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7987:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"},"src":"7962:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":906,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7994:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":899,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"7954:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":907,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7954:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":908,"nodeType":"ExpressionStatement","src":"7954:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":914,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":910,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8036:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":911,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8036:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":912,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8036:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31","id":913,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8053:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"8036:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652031","id":915,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8056:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""},"value":"value should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""}],"id":909,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8028:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":916,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8028:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":917,"nodeType":"ExpressionStatement","src":"8028:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":925,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":919,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8094:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":920,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8094:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"31","id":923,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8122:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"}],"id":922,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8114:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":921,"name":"uint256","nodeType":"ElementaryTypeName","src":"8114:7:0","typeDescriptions":{}}},"id":924,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8114:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8094:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652031","id":926,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8126:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""},"value":"balance should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""}],"id":918,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8086:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":927,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8086:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":928,"nodeType":"ExpressionStatement","src":"8086:62:0"},{"expression":{"arguments":[{"hexValue":"666f726b32","id":932,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8179:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},"value":"fork2"},{"hexValue":"3233343536","id":933,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8188:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"}],"expression":{"id":929,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8159:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":931,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"8159:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":934,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8159:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":935,"nodeType":"ExpressionStatement","src":"8159:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":942,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":939,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8224:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":937,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8212:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":938,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"8212:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":940,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8212:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3233343536","id":941,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8237:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"},"src":"8212:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":943,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8244:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":936,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8204:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":944,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8204:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":945,"nodeType":"ExpressionStatement","src":"8204:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":951,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":947,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8286:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":948,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8286:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":949,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8286:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"32","id":950,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8303:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"},"src":"8286:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652032","id":952,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8306:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""},"value":"value should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""}],"id":946,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8278:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":953,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8278:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":954,"nodeType":"ExpressionStatement","src":"8278:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":962,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":956,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8344:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":957,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8344:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"32","id":960,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8372:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"}],"id":959,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8364:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":958,"name":"uint256","nodeType":"ElementaryTypeName","src":"8364:7:0","typeDescriptions":{}}},"id":961,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8364:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8344:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652032","id":963,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8376:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""},"value":"balance should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""}],"id":955,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8336:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":964,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8336:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":965,"nodeType":"ExpressionStatement","src":"8336:62:0"}]},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"7776:3:0","parameters":{"id":873,"nodeType":"ParameterList","parameters":[],"src":"7779:2:0"},"returnParameters":{"id":874,"nodeType":"ParameterList","parameters":[],"src":"7791:0:0"},"scope":968,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkTester","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[968],"name":"ForkTester","nameLocation":"7603:10:0","scope":969,"usedErrors":[]}],"license":"MIT"},"id":0} \ No newline at end of file diff --git a/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/ForkedContract.json b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/ForkedContract.json new file mode 100644 index 0000000000000..b2c69de3ffbc1 --- /dev/null +++ b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/ForkedContract.json @@ -0,0 +1 @@ +{"abi":[{"type":"constructor","inputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"getValue","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"}],"bytecode":{"object":"0x6080604052348015600f57600080fd5b506001600055604f8060226000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80632096525514602d575b600080fd5b60005460405190815260200160405180910390f3fea164736f6c634300080f000a","sourceMap":"7418:174:0:-:0;;;7473:36;;;;;;;;;-1:-1:-1;7501:1:0;7497;:5;7418:174;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x6080604052348015600f57600080fd5b506004361060285760003560e01c80632096525514602d575b600080fd5b60005460405190815260200160405180910390f3fea164736f6c634300080f000a","sourceMap":"7418:174:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7515:75;7556:7;7582:1;7515:75;;160:25:1;;;148:2;133:18;7515:75:0;;;;;;","linkReferences":{}},"methodIdentifiers":{"getValue()":"20965255"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"getValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"scripts/ScriptExample.s.sol\":\"ForkedContract\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"scripts/ScriptExample.s.sol\":{\"keccak256\":\"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28\",\"dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"stateMutability":"view","type":"function","name":"getValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"scripts/ScriptExample.s.sol":"ForkedContract"},"evmVersion":"london","libraries":{}},"sources":{"scripts/ScriptExample.s.sol":{"keccak256":"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da","urls":["bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28","dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[{"astId":835,"contract":"scripts/ScriptExample.s.sol:ForkedContract","label":"v","offset":0,"slot":"0","type":"t_uint256"}],"types":{"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}},"userdoc":{"version":1,"kind":"user"},"devdoc":{"version":1,"kind":"dev"},"ast":{"absolutePath":"scripts/ScriptExample.s.sol","id":969,"exportedSymbols":{"FooBar":[799],"ForkTester":[968],"ForkedContract":[852],"NonceGetter":[833],"ScriptExample":[786],"Vm":[83],"console":[220]},"nodeType":"SourceUnit","src":"32:8375:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","0.8",".15"]},{"id":83,"nodeType":"ContractDefinition","src":"120:969:0","nodes":[{"id":10,"nodeType":"FunctionDefinition","src":"139:91:0","nodes":[],"functionSelector":"4777f3cf","implemented":false,"kind":"function","modifiers":[],"name":"envOr","nameLocation":"148:5:0","parameters":{"id":6,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"mutability":"mutable","name":"name","nameLocation":"170:4:0","nodeType":"VariableDeclaration","scope":10,"src":"154:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":2,"name":"string","nodeType":"ElementaryTypeName","src":"154:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":5,"mutability":"mutable","name":"defaultValue","nameLocation":"181:12:0","nodeType":"VariableDeclaration","scope":10,"src":"176:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":4,"name":"bool","nodeType":"ElementaryTypeName","src":"176:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"153:41:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[{"constant":false,"id":8,"mutability":"mutable","name":"value","nameLocation":"223:5:0","nodeType":"VariableDeclaration","scope":10,"src":"218:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":7,"name":"bool","nodeType":"ElementaryTypeName","src":"218:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"217:12:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":17,"nodeType":"FunctionDefinition","src":"235:72:0","nodes":[],"functionSelector":"2d0335ab","implemented":false,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"244:8:0","parameters":{"id":13,"nodeType":"ParameterList","parameters":[{"constant":false,"id":12,"mutability":"mutable","name":"account","nameLocation":"261:7:0","nodeType":"VariableDeclaration","scope":17,"src":"253:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":11,"name":"address","nodeType":"ElementaryTypeName","src":"253:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"252:17:0"},"returnParameters":{"id":16,"nodeType":"ParameterList","parameters":[{"constant":false,"id":15,"mutability":"mutable","name":"nonce","nameLocation":"300:5:0","nodeType":"VariableDeclaration","scope":17,"src":"293:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"},"typeName":{"id":14,"name":"uint64","nodeType":"ElementaryTypeName","src":"293:6:0","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"visibility":"internal"}],"src":"292:14:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":27,"nodeType":"FunctionDefinition","src":"312:111:0","nodes":[],"functionSelector":"213e4198","implemented":false,"kind":"function","modifiers":[],"name":"parseJsonKeys","nameLocation":"321:13:0","parameters":{"id":22,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19,"mutability":"mutable","name":"json","nameLocation":"351:4:0","nodeType":"VariableDeclaration","scope":27,"src":"335:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":18,"name":"string","nodeType":"ElementaryTypeName","src":"335:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":21,"mutability":"mutable","name":"key","nameLocation":"373:3:0","nodeType":"VariableDeclaration","scope":27,"src":"357:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":20,"name":"string","nodeType":"ElementaryTypeName","src":"357:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"334:43:0"},"returnParameters":{"id":26,"nodeType":"ParameterList","parameters":[{"constant":false,"id":25,"mutability":"mutable","name":"keys","nameLocation":"417:4:0","nodeType":"VariableDeclaration","scope":27,"src":"401:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":23,"name":"string","nodeType":"ElementaryTypeName","src":"401:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":24,"nodeType":"ArrayTypeName","src":"401:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"src":"400:22:0"},"scope":83,"stateMutability":"pure","virtual":false,"visibility":"external"},{"id":32,"nodeType":"FunctionDefinition","src":"428:48:0","nodes":[],"functionSelector":"06447d56","implemented":false,"kind":"function","modifiers":[],"name":"startPrank","nameLocation":"437:10:0","parameters":{"id":30,"nodeType":"ParameterList","parameters":[{"constant":false,"id":29,"mutability":"mutable","name":"msgSender","nameLocation":"456:9:0","nodeType":"VariableDeclaration","scope":32,"src":"448:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":28,"name":"address","nodeType":"ElementaryTypeName","src":"448:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"447:19:0"},"returnParameters":{"id":31,"nodeType":"ParameterList","parameters":[],"src":"475:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":35,"nodeType":"FunctionDefinition","src":"481:30:0","nodes":[],"functionSelector":"90c5013b","implemented":false,"kind":"function","modifiers":[],"name":"stopPrank","nameLocation":"490:9:0","parameters":{"id":33,"nodeType":"ParameterList","parameters":[],"src":"499:2:0"},"returnParameters":{"id":34,"nodeType":"ParameterList","parameters":[],"src":"510:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":38,"nodeType":"FunctionDefinition","src":"516:30:0","nodes":[],"functionSelector":"afc98040","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"525:9:0","parameters":{"id":36,"nodeType":"ParameterList","parameters":[],"src":"534:2:0"},"returnParameters":{"id":37,"nodeType":"ParameterList","parameters":[],"src":"545:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":43,"nodeType":"FunctionDefinition","src":"551:47:0","nodes":[],"functionSelector":"e6962cdb","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"560:9:0","parameters":{"id":41,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40,"mutability":"mutable","name":"msgSender","nameLocation":"578:9:0","nodeType":"VariableDeclaration","scope":43,"src":"570:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39,"name":"address","nodeType":"ElementaryTypeName","src":"570:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"569:19:0"},"returnParameters":{"id":42,"nodeType":"ParameterList","parameters":[],"src":"597:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":48,"nodeType":"FunctionDefinition","src":"603:52:0","nodes":[],"functionSelector":"7fec2a8d","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"612:14:0","parameters":{"id":46,"nodeType":"ParameterList","parameters":[{"constant":false,"id":45,"mutability":"mutable","name":"msgSender","nameLocation":"635:9:0","nodeType":"VariableDeclaration","scope":48,"src":"627:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":44,"name":"address","nodeType":"ElementaryTypeName","src":"627:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"626:19:0"},"returnParameters":{"id":47,"nodeType":"ParameterList","parameters":[],"src":"654:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":51,"nodeType":"FunctionDefinition","src":"660:35:0","nodes":[],"functionSelector":"7fb5297f","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"669:14:0","parameters":{"id":49,"nodeType":"ParameterList","parameters":[],"src":"683:2:0"},"returnParameters":{"id":50,"nodeType":"ParameterList","parameters":[],"src":"694:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":54,"nodeType":"FunctionDefinition","src":"700:34:0","nodes":[],"functionSelector":"76eadd36","implemented":false,"kind":"function","modifiers":[],"name":"stopBroadcast","nameLocation":"709:13:0","parameters":{"id":52,"nodeType":"ParameterList","parameters":[],"src":"722:2:0"},"returnParameters":{"id":53,"nodeType":"ParameterList","parameters":[],"src":"733:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":61,"nodeType":"FunctionDefinition","src":"739:108:0","nodes":[],"functionSelector":"3ebf73b4","implemented":false,"kind":"function","modifiers":[],"name":"getDeployedCode","nameLocation":"748:15:0","parameters":{"id":57,"nodeType":"ParameterList","parameters":[{"constant":false,"id":56,"mutability":"mutable","name":"artifactPath","nameLocation":"780:12:0","nodeType":"VariableDeclaration","scope":61,"src":"764:28:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":55,"name":"string","nodeType":"ElementaryTypeName","src":"764:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"763:30:0"},"returnParameters":{"id":60,"nodeType":"ParameterList","parameters":[{"constant":false,"id":59,"mutability":"mutable","name":"runtimeBytecode","nameLocation":"830:15:0","nodeType":"VariableDeclaration","scope":61,"src":"817:28:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":58,"name":"bytes","nodeType":"ElementaryTypeName","src":"817:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"816:30:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":68,"nodeType":"FunctionDefinition","src":"852:74:0","nodes":[],"functionSelector":"b4d6c782","implemented":false,"kind":"function","modifiers":[],"name":"etch","nameLocation":"861:4:0","parameters":{"id":66,"nodeType":"ParameterList","parameters":[{"constant":false,"id":63,"mutability":"mutable","name":"target","nameLocation":"874:6:0","nodeType":"VariableDeclaration","scope":68,"src":"866:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":62,"name":"address","nodeType":"ElementaryTypeName","src":"866:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":65,"mutability":"mutable","name":"newRuntimeBytecode","nameLocation":"897:18:0","nodeType":"VariableDeclaration","scope":68,"src":"882:33:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":64,"name":"bytes","nodeType":"ElementaryTypeName","src":"882:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"865:51:0"},"returnParameters":{"id":67,"nodeType":"ParameterList","parameters":[],"src":"925:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":73,"nodeType":"FunctionDefinition","src":"931:51:0","nodes":[],"functionSelector":"ea060291","implemented":false,"kind":"function","modifiers":[],"name":"allowCheatcodes","nameLocation":"940:15:0","parameters":{"id":71,"nodeType":"ParameterList","parameters":[{"constant":false,"id":70,"mutability":"mutable","name":"account","nameLocation":"964:7:0","nodeType":"VariableDeclaration","scope":73,"src":"956:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":69,"name":"address","nodeType":"ElementaryTypeName","src":"956:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"955:17:0"},"returnParameters":{"id":72,"nodeType":"ParameterList","parameters":[],"src":"981:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":82,"nodeType":"FunctionDefinition","src":"987:100:0","nodes":[],"functionSelector":"71ee464d","implemented":false,"kind":"function","modifiers":[],"name":"createSelectFork","nameLocation":"996:16:0","parameters":{"id":78,"nodeType":"ParameterList","parameters":[{"constant":false,"id":75,"mutability":"mutable","name":"forkName","nameLocation":"1029:8:0","nodeType":"VariableDeclaration","scope":82,"src":"1013:24:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":74,"name":"string","nodeType":"ElementaryTypeName","src":"1013:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":77,"mutability":"mutable","name":"blockNumber","nameLocation":"1047:11:0","nodeType":"VariableDeclaration","scope":82,"src":"1039:19:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":76,"name":"uint256","nodeType":"ElementaryTypeName","src":"1039:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1012:47:0"},"returnParameters":{"id":81,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":82,"src":"1078:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":79,"name":"uint256","nodeType":"ElementaryTypeName","src":"1078:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1077:9:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"Vm","contractDependencies":[],"contractKind":"interface","fullyImplemented":false,"linearizedBaseContracts":[83],"name":"Vm","nameLocation":"130:2:0","scope":969,"usedErrors":[]},{"id":220,"nodeType":"ContractDefinition","src":"1144:1851:0","nodes":[{"id":89,"nodeType":"VariableDeclaration","src":"1166:86:0","nodes":[],"constant":true,"mutability":"constant","name":"CONSOLE_ADDRESS","nameLocation":"1183:15:0","scope":220,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":84,"name":"address","nodeType":"ElementaryTypeName","src":"1166:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"hexValue":"307830303030303030303030303030303030303036333646366537333646366336353265366336663637","id":87,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1209:42:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"value":"0x000000000000000000636F6e736F6c652e6c6f67"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":86,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":85,"name":"address","nodeType":"ElementaryTypeName","src":"1201:7:0","typeDescriptions":{}}},"id":88,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1201:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":106,"nodeType":"FunctionDefinition","src":"1259:235:0","nodes":[],"body":{"id":105,"nodeType":"Block","src":"1432:62:0","nodes":[],"statements":[{"AST":{"nodeType":"YulBlock","src":"1451:37:0","statements":[{"nodeType":"YulAssignment","src":"1465:13:0","value":{"name":"fnIn","nodeType":"YulIdentifier","src":"1474:4:0"},"variableNames":[{"name":"fnOut","nodeType":"YulIdentifier","src":"1465:5:0"}]}]},"evmVersion":"london","externalReferences":[{"declaration":95,"isOffset":false,"isSlot":false,"src":"1474:4:0","valueSize":1},{"declaration":102,"isOffset":false,"isSlot":false,"src":"1465:5:0","valueSize":1}],"id":104,"nodeType":"InlineAssembly","src":"1442:46:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_castLogPayloadViewToPure","nameLocation":"1268:25:0","parameters":{"id":96,"nodeType":"ParameterList","parameters":[{"constant":false,"id":95,"mutability":"mutable","name":"fnIn","nameLocation":"1331:4:0","nodeType":"VariableDeclaration","scope":106,"src":"1294:41:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"typeName":{"id":94,"nodeType":"FunctionTypeName","parameterTypes":{"id":92,"nodeType":"ParameterList","parameters":[{"constant":false,"id":91,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":94,"src":"1303:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":90,"name":"bytes","nodeType":"ElementaryTypeName","src":"1303:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1302:14:0"},"returnParameterTypes":{"id":93,"nodeType":"ParameterList","parameters":[],"src":"1331:0:0"},"src":"1294:41:0","stateMutability":"view","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"visibility":"internal"},"visibility":"internal"}],"src":"1293:43:0"},"returnParameters":{"id":103,"nodeType":"ParameterList","parameters":[{"constant":false,"id":102,"mutability":"mutable","name":"fnOut","nameLocation":"1421:5:0","nodeType":"VariableDeclaration","scope":106,"src":"1384:42:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"typeName":{"id":101,"nodeType":"FunctionTypeName","parameterTypes":{"id":99,"nodeType":"ParameterList","parameters":[{"constant":false,"id":98,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":101,"src":"1393:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":97,"name":"bytes","nodeType":"ElementaryTypeName","src":"1393:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1392:14:0"},"returnParameterTypes":{"id":100,"nodeType":"ParameterList","parameters":[],"src":"1421:0:0"},"src":"1384:42:0","stateMutability":"pure","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"visibility":"internal"},"visibility":"internal"}],"src":"1383:44:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":118,"nodeType":"FunctionDefinition","src":"1500:133:0","nodes":[],"body":{"id":117,"nodeType":"Block","src":"1561:72:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":114,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":108,"src":"1618:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"arguments":[{"id":112,"name":"_sendLogPayloadView","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":134,"src":"1597:19:0","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}],"id":111,"name":"_castLogPayloadViewToPure","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":106,"src":"1571:25:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_function_internal_view$_t_bytes_memory_ptr_$returns$__$_$returns$_t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$_$","typeString":"function (function (bytes memory) view) pure returns (function (bytes memory) pure)"}},"id":113,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":115,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":116,"nodeType":"ExpressionStatement","src":"1571:55:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayload","nameLocation":"1509:15:0","parameters":{"id":109,"nodeType":"ParameterList","parameters":[{"constant":false,"id":108,"mutability":"mutable","name":"payload","nameLocation":"1538:7:0","nodeType":"VariableDeclaration","scope":118,"src":"1525:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":107,"name":"bytes","nodeType":"ElementaryTypeName","src":"1525:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1524:22:0"},"returnParameters":{"id":110,"nodeType":"ParameterList","parameters":[],"src":"1561:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":134,"nodeType":"FunctionDefinition","src":"1639:380:0","nodes":[],"body":{"id":133,"nodeType":"Block","src":"1703:316:0","nodes":[],"statements":[{"assignments":[124],"declarations":[{"constant":false,"id":124,"mutability":"mutable","name":"payloadLength","nameLocation":"1721:13:0","nodeType":"VariableDeclaration","scope":133,"src":"1713:21:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":123,"name":"uint256","nodeType":"ElementaryTypeName","src":"1713:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":127,"initialValue":{"expression":{"id":125,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":120,"src":"1737:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":126,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1737:14:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1713:38:0"},{"assignments":[129],"declarations":[{"constant":false,"id":129,"mutability":"mutable","name":"consoleAddress","nameLocation":"1769:14:0","nodeType":"VariableDeclaration","scope":133,"src":"1761:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":128,"name":"address","nodeType":"ElementaryTypeName","src":"1761:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":131,"initialValue":{"id":130,"name":"CONSOLE_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":89,"src":"1786:15:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"1761:40:0"},{"AST":{"nodeType":"YulBlock","src":"1863:150:0","statements":[{"nodeType":"YulVariableDeclaration","src":"1877:36:0","value":{"arguments":[{"name":"payload","nodeType":"YulIdentifier","src":"1901:7:0"},{"kind":"number","nodeType":"YulLiteral","src":"1910:2:0","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1897:3:0"},"nodeType":"YulFunctionCall","src":"1897:16:0"},"variables":[{"name":"payloadStart","nodeType":"YulTypedName","src":"1881:12:0","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1926:77:0","value":{"arguments":[{"arguments":[],"functionName":{"name":"gas","nodeType":"YulIdentifier","src":"1946:3:0"},"nodeType":"YulFunctionCall","src":"1946:5:0"},{"name":"consoleAddress","nodeType":"YulIdentifier","src":"1953:14:0"},{"name":"payloadStart","nodeType":"YulIdentifier","src":"1969:12:0"},{"name":"payloadLength","nodeType":"YulIdentifier","src":"1983:13:0"},{"kind":"number","nodeType":"YulLiteral","src":"1998:1:0","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"2001:1:0","type":"","value":"0"}],"functionName":{"name":"staticcall","nodeType":"YulIdentifier","src":"1935:10:0"},"nodeType":"YulFunctionCall","src":"1935:68:0"},"variables":[{"name":"r","nodeType":"YulTypedName","src":"1930:1:0","type":""}]}]},"documentation":"@solidity memory-safe-assembly","evmVersion":"london","externalReferences":[{"declaration":129,"isOffset":false,"isSlot":false,"src":"1953:14:0","valueSize":1},{"declaration":120,"isOffset":false,"isSlot":false,"src":"1901:7:0","valueSize":1},{"declaration":124,"isOffset":false,"isSlot":false,"src":"1983:13:0","valueSize":1}],"id":132,"nodeType":"InlineAssembly","src":"1854:159:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayloadView","nameLocation":"1648:19:0","parameters":{"id":121,"nodeType":"ParameterList","parameters":[{"constant":false,"id":120,"mutability":"mutable","name":"payload","nameLocation":"1681:7:0","nodeType":"VariableDeclaration","scope":134,"src":"1668:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":119,"name":"bytes","nodeType":"ElementaryTypeName","src":"1668:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1667:22:0"},"returnParameters":{"id":122,"nodeType":"ParameterList","parameters":[],"src":"1703:0:0"},"scope":220,"stateMutability":"view","virtual":false,"visibility":"private"},{"id":148,"nodeType":"FunctionDefinition","src":"2025:164:0","nodes":[],"body":{"id":147,"nodeType":"Block","src":"2070:119:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e6729","id":142,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2120:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},"value":"log(string)"},{"id":143,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":136,"src":"2135:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":140,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2096:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":141,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2096:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":144,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2096:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":139,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2080:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":145,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2080:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":146,"nodeType":"ExpressionStatement","src":"2080:59:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2034:3:0","parameters":{"id":137,"nodeType":"ParameterList","parameters":[{"constant":false,"id":136,"mutability":"mutable","name":"p0","nameLocation":"2052:2:0","nodeType":"VariableDeclaration","scope":148,"src":"2038:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":135,"name":"string","nodeType":"ElementaryTypeName","src":"2038:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2037:18:0"},"returnParameters":{"id":138,"nodeType":"ParameterList","parameters":[],"src":"2070:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":165,"nodeType":"FunctionDefinition","src":"2195:182:0","nodes":[],"body":{"id":164,"nodeType":"Block","src":"2249:128:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c626f6f6c29","id":158,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2299:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},"value":"log(string,bool)"},{"id":159,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":150,"src":"2319:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":160,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":152,"src":"2323:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":156,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2275:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":157,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2275:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":161,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2275:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":155,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2259:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":162,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2259:68:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":163,"nodeType":"ExpressionStatement","src":"2259:68:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2204:3:0","parameters":{"id":153,"nodeType":"ParameterList","parameters":[{"constant":false,"id":150,"mutability":"mutable","name":"p0","nameLocation":"2222:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2208:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":149,"name":"string","nodeType":"ElementaryTypeName","src":"2208:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":152,"mutability":"mutable","name":"p1","nameLocation":"2231:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2226:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":151,"name":"bool","nodeType":"ElementaryTypeName","src":"2226:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"2207:27:0"},"returnParameters":{"id":154,"nodeType":"ParameterList","parameters":[],"src":"2249:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":182,"nodeType":"FunctionDefinition","src":"2383:188:0","nodes":[],"body":{"id":181,"nodeType":"Block","src":"2440:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c75696e7432353629","id":175,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2490:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},"value":"log(string,uint256)"},{"id":176,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":167,"src":"2513:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":177,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":169,"src":"2517:2:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":173,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2466:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":174,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2466:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":178,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2466:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":172,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2450:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":179,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2450:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":180,"nodeType":"ExpressionStatement","src":"2450:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2392:3:0","parameters":{"id":170,"nodeType":"ParameterList","parameters":[{"constant":false,"id":167,"mutability":"mutable","name":"p0","nameLocation":"2410:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2396:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":166,"name":"string","nodeType":"ElementaryTypeName","src":"2396:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":169,"mutability":"mutable","name":"p1","nameLocation":"2422:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2414:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":168,"name":"uint256","nodeType":"ElementaryTypeName","src":"2414:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"2395:30:0"},"returnParameters":{"id":171,"nodeType":"ParameterList","parameters":[],"src":"2440:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":199,"nodeType":"FunctionDefinition","src":"2577:188:0","nodes":[],"body":{"id":198,"nodeType":"Block","src":"2634:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c6164647265737329","id":192,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2684:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},"value":"log(string,address)"},{"id":193,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":184,"src":"2707:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":194,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":186,"src":"2711:2:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":190,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2660:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":191,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2660:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":195,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2660:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":189,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2644:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":196,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2644:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":197,"nodeType":"ExpressionStatement","src":"2644:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2586:3:0","parameters":{"id":187,"nodeType":"ParameterList","parameters":[{"constant":false,"id":184,"mutability":"mutable","name":"p0","nameLocation":"2604:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2590:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":183,"name":"string","nodeType":"ElementaryTypeName","src":"2590:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":186,"mutability":"mutable","name":"p1","nameLocation":"2616:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2608:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":185,"name":"address","nodeType":"ElementaryTypeName","src":"2608:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2589:30:0"},"returnParameters":{"id":188,"nodeType":"ParameterList","parameters":[],"src":"2634:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":219,"nodeType":"FunctionDefinition","src":"2771:222:0","nodes":[],"body":{"id":218,"nodeType":"Block","src":"2852:141:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c737472696e672c737472696e6729","id":211,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2902:27:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},"value":"log(string,string,string)"},{"id":212,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":201,"src":"2931:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":213,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":203,"src":"2935:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":214,"name":"p2","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":205,"src":"2939:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":209,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2878:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":210,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2878:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":215,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2878:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":208,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2862:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":216,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2862:81:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":217,"nodeType":"ExpressionStatement","src":"2862:81:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2780:3:0","parameters":{"id":206,"nodeType":"ParameterList","parameters":[{"constant":false,"id":201,"mutability":"mutable","name":"p0","nameLocation":"2798:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2784:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":200,"name":"string","nodeType":"ElementaryTypeName","src":"2784:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":203,"mutability":"mutable","name":"p1","nameLocation":"2816:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2802:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":202,"name":"string","nodeType":"ElementaryTypeName","src":"2802:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":205,"mutability":"mutable","name":"p2","nameLocation":"2834:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2820:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":204,"name":"string","nodeType":"ElementaryTypeName","src":"2820:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2783:54:0"},"returnParameters":{"id":207,"nodeType":"ParameterList","parameters":[],"src":"2852:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"}],"abstract":false,"baseContracts":[],"canonicalName":"console","contractDependencies":[],"contractKind":"library","fullyImplemented":true,"linearizedBaseContracts":[220],"name":"console","nameLocation":"1152:7:0","scope":969,"usedErrors":[]},{"id":786,"nodeType":"ContractDefinition","src":"3123:3912:0","nodes":[{"id":235,"nodeType":"VariableDeclaration","src":"3152:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"3178:10:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":222,"name":"address","nodeType":"ElementaryTypeName","src":"3152:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":230,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3225:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":229,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"3215:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":231,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3215:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":228,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3207:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":227,"name":"uint256","nodeType":"ElementaryTypeName","src":"3207:7:0","typeDescriptions":{}}},"id":232,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3207:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":226,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3199:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":225,"name":"uint160","nodeType":"ElementaryTypeName","src":"3199:7:0","typeDescriptions":{}}},"id":233,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3199:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":224,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3191:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":223,"name":"address","nodeType":"ElementaryTypeName","src":"3191:7:0","typeDescriptions":{}}},"id":234,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3191:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":241,"nodeType":"VariableDeclaration","src":"3252:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"3273:2:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":237,"nodeType":"UserDefinedTypeName","pathNode":{"id":236,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"3252:2:0"},"referencedDeclaration":83,"src":"3252:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":239,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":235,"src":"3281:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":238,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"3278:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":240,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3278:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":243,"nodeType":"VariableDeclaration","src":"3356:22:0","nodes":[],"constant":false,"functionSelector":"61bc221a","mutability":"mutable","name":"counter","nameLocation":"3371:7:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":242,"name":"uint256","nodeType":"ElementaryTypeName","src":"3356:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":456,"nodeType":"FunctionDefinition","src":"3468:1428:0","nodes":[],"body":{"id":455,"nodeType":"Block","src":"3490:1406:0","nodes":[],"statements":[{"assignments":[248],"declarations":[{"constant":false,"id":248,"mutability":"mutable","name":"x","nameLocation":"3505:1:0","nodeType":"VariableDeclaration","scope":455,"src":"3500:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":247,"name":"bool","nodeType":"ElementaryTypeName","src":"3500:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"id":254,"initialValue":{"arguments":[{"hexValue":"4558414d504c455f424f4f4c","id":251,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3518:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},"value":"EXAMPLE_BOOL"},{"hexValue":"66616c7365","id":252,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"3534:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":249,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3509:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":250,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"envOr","nodeType":"MemberAccess","referencedDeclaration":10,"src":"3509:8:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$_t_bool_$returns$_t_bool_$","typeString":"function (string memory,bool) view external returns (bool)"}},"id":253,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3509:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"VariableDeclarationStatement","src":"3500:40:0"},{"expression":{"arguments":[{"hexValue":"626f6f6c2076616c75652066726f6d20656e76","id":258,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3562:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},"value":"bool value from env"},{"id":259,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":248,"src":"3585:1:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":255,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3550:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":257,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":165,"src":"3550:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_bool_$returns$__$","typeString":"function (string memory,bool) pure"}},"id":260,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3550:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":261,"nodeType":"ExpressionStatement","src":"3550:37:0"},{"expression":{"arguments":[{"hexValue":"636f6e74726163742061646472","id":265,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3610:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},"value":"contract addr"},{"arguments":[{"id":268,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3635:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":267,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3627:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":266,"name":"address","nodeType":"ElementaryTypeName","src":"3627:7:0","typeDescriptions":{}}},"id":269,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3627:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":262,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3598:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":264,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3598:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":270,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3598:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":271,"nodeType":"ExpressionStatement","src":"3598:43:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206e6f6e6365","id":275,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3663:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},"value":"contract nonce"},{"arguments":[{"arguments":[{"id":280,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3701:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":279,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3693:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":278,"name":"address","nodeType":"ElementaryTypeName","src":"3693:7:0","typeDescriptions":{}}},"id":281,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3693:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":276,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3681:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":277,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3681:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":282,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3681:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":272,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3651:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":274,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3651:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":283,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3651:57:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":284,"nodeType":"ExpressionStatement","src":"3651:57:0"},{"expression":{"arguments":[{"hexValue":"73656e6465722061646472","id":288,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3730:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},"value":"sender addr"},{"arguments":[{"expression":{"id":291,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3753:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":292,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3753:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":290,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3745:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":289,"name":"address","nodeType":"ElementaryTypeName","src":"3745:7:0","typeDescriptions":{}}},"id":293,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3745:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":285,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3718:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":287,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3718:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":294,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3718:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":295,"nodeType":"ExpressionStatement","src":"3718:47:0"},{"expression":{"arguments":[{"hexValue":"73656e646572206e6f6e6365","id":299,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3787:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},"value":"sender nonce"},{"arguments":[{"arguments":[{"expression":{"id":304,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3823:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":305,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3823:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":303,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3815:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":302,"name":"address","nodeType":"ElementaryTypeName","src":"3815:7:0","typeDescriptions":{}}},"id":306,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3815:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":300,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3803:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":301,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3803:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":307,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3803:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":296,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3775:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":298,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3775:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":308,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3775:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":309,"nodeType":"ExpressionStatement","src":"3775:61:0"},{"assignments":[311],"declarations":[{"constant":false,"id":311,"mutability":"mutable","name":"json","nameLocation":"3861:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3847:18:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":310,"name":"string","nodeType":"ElementaryTypeName","src":"3847:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"id":313,"initialValue":{"hexValue":"7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d","id":312,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3868:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e95522e99766888d0261f55bd1eae5e3f3e26eaf009a16e2433eafaf0a4ecdf2","typeString":"literal_string \"{\"root_key\": [{\"a\": 1, \"b\": 2}]}\""},"value":"{\"root_key\": [{\"a\": 1, \"b\": 2}]}"},"nodeType":"VariableDeclarationStatement","src":"3847:55:0"},{"assignments":[318],"declarations":[{"constant":false,"id":318,"mutability":"mutable","name":"keys","nameLocation":"3928:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3912:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":316,"name":"string","nodeType":"ElementaryTypeName","src":"3912:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":317,"nodeType":"ArrayTypeName","src":"3912:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"id":324,"initialValue":{"arguments":[{"id":321,"name":"json","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":311,"src":"3952:4:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"2e726f6f745f6b65795b305d","id":322,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3958:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""},"value":".root_key[0]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""}],"expression":{"id":319,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3935:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":320,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"parseJsonKeys","nodeType":"MemberAccess","referencedDeclaration":27,"src":"3935:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$_t_array$_t_string_memory_ptr_$dyn_memory_ptr_$","typeString":"function (string memory,string memory) pure external returns (string memory[] memory)"}},"id":323,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3935:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"nodeType":"VariableDeclarationStatement","src":"3912:61:0"},{"expression":{"arguments":[{"hexValue":"6b657973","id":328,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3995:6:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},"value":"keys"},{"baseExpression":{"id":329,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4003:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":331,"indexExpression":{"hexValue":"30","id":330,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4008:1:0","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4003:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"baseExpression":{"id":332,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4012:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":334,"indexExpression":{"hexValue":"31","id":333,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4017:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4012:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":325,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3983:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":327,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":219,"src":"3983:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory,string memory) pure"}},"id":335,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3983:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":336,"nodeType":"ExpressionStatement","src":"3983:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c","id":340,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4042:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""},"value":"from original"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""}],"expression":{"id":337,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4031:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":339,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4031:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":341,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4031:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":342,"nodeType":"ExpressionStatement","src":"4031:27:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"30783432","id":350,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4098:4:0","typeDescriptions":{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"},"value":"0x42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"}],"id":349,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4090:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":348,"name":"uint160","nodeType":"ElementaryTypeName","src":"4090:7:0","typeDescriptions":{}}},"id":351,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4090:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":347,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4082:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":346,"name":"address","nodeType":"ElementaryTypeName","src":"4082:7:0","typeDescriptions":{}}},"id":352,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4082:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":343,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4068:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":345,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startPrank","nodeType":"MemberAccess","referencedDeclaration":32,"src":"4068:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":353,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4068:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":354,"nodeType":"ExpressionStatement","src":"4068:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2031","id":358,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4126:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""},"value":"from prank 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""}],"expression":{"id":355,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4115:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":357,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4115:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":359,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4115:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":360,"nodeType":"ExpressionStatement","src":"4115:26:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f7065206d73672e73656e646572","id":364,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4163:25:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},"value":"parent scope msg.sender"},{"arguments":[{"expression":{"id":367,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"4198:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":368,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"4198:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":366,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4190:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":365,"name":"address","nodeType":"ElementaryTypeName","src":"4190:7:0","typeDescriptions":{}}},"id":369,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4190:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":361,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4151:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":363,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4151:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":370,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4151:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":371,"nodeType":"ExpressionStatement","src":"4151:59:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f706520636f6e74726163742e61646472","id":375,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4232:28:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},"value":"parent scope contract.addr"},{"arguments":[{"id":378,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4270:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":377,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4262:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":376,"name":"address","nodeType":"ElementaryTypeName","src":"4262:7:0","typeDescriptions":{}}},"id":379,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4262:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":372,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4220:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":374,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4220:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":380,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4220:56:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":381,"nodeType":"ExpressionStatement","src":"4220:56:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2032","id":385,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4297:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""},"value":"from prank 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""}],"expression":{"id":382,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4286:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":384,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4286:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":386,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4286:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":387,"nodeType":"ExpressionStatement","src":"4286:26:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":388,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4322:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":390,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopPrank","nodeType":"MemberAccess","referencedDeclaration":35,"src":"4322:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":391,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4322:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":392,"nodeType":"ExpressionStatement","src":"4322:14:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c20616761696e","id":396,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4357:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""},"value":"from original again"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""}],"expression":{"id":393,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4346:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":395,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4346:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":397,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4346:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":398,"nodeType":"ExpressionStatement","src":"4346:33:0"},{"assignments":[400],"declarations":[{"constant":false,"id":400,"mutability":"mutable","name":"tmpNonceGetter","nameLocation":"4480:14:0","nodeType":"VariableDeclaration","scope":455,"src":"4472:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":399,"name":"address","nodeType":"ElementaryTypeName","src":"4472:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":413,"initialValue":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"74656d70206e6f6e6365207465737420676574746572","id":408,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4531:24:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""},"value":"temp nonce test getter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""}],"id":407,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"4521:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":409,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4521:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":406,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4513:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":405,"name":"uint256","nodeType":"ElementaryTypeName","src":"4513:7:0","typeDescriptions":{}}},"id":410,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4513:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":404,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4505:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":403,"name":"uint160","nodeType":"ElementaryTypeName","src":"4505:7:0","typeDescriptions":{}}},"id":411,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4505:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":402,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4497:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":401,"name":"address","nodeType":"ElementaryTypeName","src":"4497:7:0","typeDescriptions":{}}},"id":412,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4497:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"4472:87:0"},{"expression":{"arguments":[{"id":417,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4577:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"arguments":[{"hexValue":"5363726970744578616d706c652e732e736f6c3a4e6f6e6365476574746572","id":420,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4612:33:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""},"value":"ScriptExample.s.sol:NonceGetter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""}],"expression":{"id":418,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4593:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":419,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getDeployedCode","nodeType":"MemberAccess","referencedDeclaration":61,"src":"4593:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) view external returns (bytes memory)"}},"id":421,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4593:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"expression":{"id":414,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4569:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":416,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"etch","nodeType":"MemberAccess","referencedDeclaration":68,"src":"4569:7:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$_t_bytes_memory_ptr_$returns$__$","typeString":"function (address,bytes memory) external"}},"id":422,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4569:78:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":423,"nodeType":"ExpressionStatement","src":"4569:78:0"},{"expression":{"arguments":[{"id":427,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4676:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":424,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4657:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":426,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"allowCheatcodes","nodeType":"MemberAccess","referencedDeclaration":73,"src":"4657:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":428,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4657:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":429,"nodeType":"ExpressionStatement","src":"4657:34:0"},{"assignments":[431],"declarations":[{"constant":false,"id":431,"mutability":"mutable","name":"v","nameLocation":"4709:1:0","nodeType":"VariableDeclaration","scope":455,"src":"4701:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":430,"name":"uint256","nodeType":"ElementaryTypeName","src":"4701:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":441,"initialValue":{"arguments":[{"arguments":[{"id":438,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4758:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":437,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4750:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":436,"name":"address","nodeType":"ElementaryTypeName","src":"4750:7:0","typeDescriptions":{}}},"id":439,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4750:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"arguments":[{"id":433,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4725:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":432,"name":"NonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":833,"src":"4713:11:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_NonceGetter_$833_$","typeString":"type(contract NonceGetter)"}},"id":434,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_NonceGetter_$833","typeString":"contract NonceGetter"}},"id":435,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":832,"src":"4713:36:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint256_$","typeString":"function (address) view external returns (uint256)"}},"id":440,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"4701:63:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e63652066726f6d206e6f6e6365206765747465722c206e6f206578706c6963697420616363657373207265717569726564207769746820766d2e657463683a","id":445,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4786:68:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},"value":"nonce from nonce getter, no explicit access required with vm.etch:"},{"id":446,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":431,"src":"4856:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":442,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4774:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":444,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"4774:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":447,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4774:84:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":448,"nodeType":"ExpressionStatement","src":"4774:84:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":452,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4881:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":449,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4869:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":451,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"4869:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":453,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4869:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":454,"nodeType":"ExpressionStatement","src":"4869:20:0"}]},"documentation":{"id":244,"nodeType":"StructuredDocumentation","src":"3385:78:0","text":"@notice example function, runs through basic cheat-codes and console logs."},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"3477:3:0","parameters":{"id":245,"nodeType":"ParameterList","parameters":[],"src":"3480:2:0"},"returnParameters":{"id":246,"nodeType":"ParameterList","parameters":[],"src":"3490:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":689,"nodeType":"FunctionDefinition","src":"4963:1333:0","nodes":[],"body":{"id":688,"nodeType":"Block","src":"4994:1302:0","nodes":[],"statements":[{"expression":{"arguments":[{"hexValue":"6e6f6e6365207374617274","id":463,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5016:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},"value":"nonce start"},{"arguments":[{"arguments":[{"arguments":[{"id":470,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5059:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":469,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5051:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":468,"name":"address","nodeType":"ElementaryTypeName","src":"5051:7:0","typeDescriptions":{}}},"id":471,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5051:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":466,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5039:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":467,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"5039:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":472,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5039:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":465,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5031:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":464,"name":"uint256","nodeType":"ElementaryTypeName","src":"5031:7:0","typeDescriptions":{}}},"id":473,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5031:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":460,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5004:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":462,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"5004:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":474,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5004:63:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":475,"nodeType":"ExpressionStatement","src":"5004:63:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073696e676c65","id":479,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5090:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""},"value":"testing single"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""}],"expression":{"id":476,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5078:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":478,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5078:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":480,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5078:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":481,"nodeType":"ExpressionStatement","src":"5078:29:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":482,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5117:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":484,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"5117:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":485,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5117:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":486,"nodeType":"ExpressionStatement","src":"5117:14:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c31","id":490,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5152:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""},"value":"single_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""}],"expression":{"id":487,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5141:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":489,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5141:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":491,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5141:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":492,"nodeType":"ExpressionStatement","src":"5141:26:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c32","id":496,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5188:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""},"value":"single_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""}],"expression":{"id":493,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5177:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":495,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5177:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":497,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5177:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":498,"nodeType":"ExpressionStatement","src":"5177:26:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073746172742f73746f70","id":502,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5226:20:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""},"value":"testing start/stop"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""}],"expression":{"id":499,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5214:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":501,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5214:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":503,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5214:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":504,"nodeType":"ExpressionStatement","src":"5214:33:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078633066666565","id":512,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5291:8:0","typeDescriptions":{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"},"value":"0xc0ffee"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"}],"id":511,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5283:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":510,"name":"uint160","nodeType":"ElementaryTypeName","src":"5283:7:0","typeDescriptions":{}}},"id":513,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5283:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":509,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5275:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":508,"name":"address","nodeType":"ElementaryTypeName","src":"5275:7:0","typeDescriptions":{}}},"id":514,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5275:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":505,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5257:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":507,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5257:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":515,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5257:45:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":516,"nodeType":"ExpressionStatement","src":"5257:45:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c31","id":520,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5323:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""},"value":"startstop_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""}],"expression":{"id":517,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5312:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":519,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5312:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":521,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5312:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":522,"nodeType":"ExpressionStatement","src":"5312:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c32","id":526,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5362:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""},"value":"startstop_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""}],"expression":{"id":523,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5351:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":525,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5351:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":527,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5351:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":528,"nodeType":"ExpressionStatement","src":"5351:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f70757265","id":532,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5404:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""},"value":"startstop_pure"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""}],"expression":{"id":529,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5390:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":531,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"callPure","nodeType":"MemberAccess","referencedDeclaration":785,"src":"5390:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure external"}},"id":533,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5390:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":534,"nodeType":"ExpressionStatement","src":"5390:31:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":535,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5431:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":537,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5431:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":538,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5431:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":539,"nodeType":"ExpressionStatement","src":"5431:18:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c33","id":543,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5470:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""},"value":"startstop_call3"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""}],"expression":{"id":540,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5459:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":542,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5459:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":544,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5459:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":545,"nodeType":"ExpressionStatement","src":"5459:29:0"},{"expression":{"arguments":[{"hexValue":"74657374696e67206e6573746564","id":549,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5511:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""},"value":"testing nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""}],"expression":{"id":546,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5499:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":548,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5499:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":550,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5499:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":551,"nodeType":"ExpressionStatement","src":"5499:29:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307831323334","id":559,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5572:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":558,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5564:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":557,"name":"uint160","nodeType":"ElementaryTypeName","src":"5564:7:0","typeDescriptions":{}}},"id":560,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5564:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":556,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5556:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":555,"name":"address","nodeType":"ElementaryTypeName","src":"5556:7:0","typeDescriptions":{}}},"id":561,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5556:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":552,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5538:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":554,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5538:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":562,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5538:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":563,"nodeType":"ExpressionStatement","src":"5538:43:0"},{"expression":{"arguments":[{"hexValue":"6e6573746564","id":567,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5604:8:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""},"value":"nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""}],"expression":{"id":564,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5591:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":566,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested1","nodeType":"MemberAccess","referencedDeclaration":758,"src":"5591:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":568,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5591:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":569,"nodeType":"ExpressionStatement","src":"5591:22:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":570,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5623:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":572,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5623:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":573,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5623:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":574,"nodeType":"ExpressionStatement","src":"5623:18:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206465706c6f796d656e74","id":578,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5664:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""},"value":"contract deployment"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""}],"expression":{"id":575,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5652:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":577,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5652:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":579,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5652:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":580,"nodeType":"ExpressionStatement","src":"5652:34:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078313233343536","id":588,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5725:8:0","typeDescriptions":{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"},"value":"0x123456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"}],"id":587,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5717:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":586,"name":"uint160","nodeType":"ElementaryTypeName","src":"5717:7:0","typeDescriptions":{}}},"id":589,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5717:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":585,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5709:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":584,"name":"address","nodeType":"ElementaryTypeName","src":"5709:7:0","typeDescriptions":{}}},"id":590,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5709:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":581,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5696:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":583,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5696:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":591,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5696:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":592,"nodeType":"ExpressionStatement","src":"5696:40:0"},{"assignments":[595],"declarations":[{"constant":false,"id":595,"mutability":"mutable","name":"x","nameLocation":"5753:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5746:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":594,"nodeType":"UserDefinedTypeName","pathNode":{"id":593,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5746:6:0"},"referencedDeclaration":799,"src":"5746:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":601,"initialValue":{"arguments":[{"hexValue":"31323334","id":599,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5768:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":598,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5757:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":597,"nodeType":"UserDefinedTypeName","pathNode":{"id":596,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5761:6:0"},"referencedDeclaration":799,"src":"5761:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":600,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5757:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5746:27:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":607,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":603,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":595,"src":"5791:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":604,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"5791:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":605,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5791:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":606,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5802:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"5791:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e20637265617465206973206e6f742031323334","id":608,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5808:35:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""},"value":"FooBar: foo in create is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""}],"id":602,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"5783:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":609,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5783:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":610,"nodeType":"ExpressionStatement","src":"5783:61:0"},{"expression":{"arguments":[{"hexValue":"6372656174652032","id":614,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5867:10:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""},"value":"create 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""}],"expression":{"id":611,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5855:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":613,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5855:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":615,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5855:23:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":616,"nodeType":"ExpressionStatement","src":"5855:23:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307863616665","id":624,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5917:6:0","typeDescriptions":{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"},"value":"0xcafe"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"}],"id":623,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5909:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":622,"name":"uint160","nodeType":"ElementaryTypeName","src":"5909:7:0","typeDescriptions":{}}},"id":625,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5909:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":621,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5901:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":620,"name":"address","nodeType":"ElementaryTypeName","src":"5901:7:0","typeDescriptions":{}}},"id":626,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5901:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":617,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5888:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":619,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5888:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":627,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5888:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":628,"nodeType":"ExpressionStatement","src":"5888:38:0"},{"assignments":[631],"declarations":[{"constant":false,"id":631,"mutability":"mutable","name":"y","nameLocation":"5943:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5936:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":630,"nodeType":"UserDefinedTypeName","pathNode":{"id":629,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5936:6:0"},"referencedDeclaration":799,"src":"5936:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":645,"initialValue":{"arguments":[{"hexValue":"31323334","id":643,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5986:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":634,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5947:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":633,"nodeType":"UserDefinedTypeName","pathNode":{"id":632,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5951:6:0"},"referencedDeclaration":799,"src":"5951:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":642,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"names":["salt"],"nodeType":"FunctionCallOptions","options":[{"arguments":[{"arguments":[{"hexValue":"3432","id":639,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5980:2:0","typeDescriptions":{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"},"value":"42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"}],"id":638,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5972:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":637,"name":"uint256","nodeType":"ElementaryTypeName","src":"5972:7:0","typeDescriptions":{}}},"id":640,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5972:11:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":636,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5964:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":635,"name":"bytes32","nodeType":"ElementaryTypeName","src":"5964:7:0","typeDescriptions":{}}},"id":641,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5964:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"src":"5947:38:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$salt","typeString":"function (uint256) returns (contract FooBar)"}},"id":644,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5947:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5936:55:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":651,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":647,"name":"y","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":631,"src":"6009:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":648,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"6009:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":649,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6009:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":650,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6020:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"6009:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e2063726561746532206973206e6f742031323334","id":652,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6026:36:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""},"value":"FooBar: foo in create2 is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""}],"id":646,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"6001:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":653,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6001:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":654,"nodeType":"ExpressionStatement","src":"6001:62:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":658,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6085:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":655,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6073:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":657,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6073:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":659,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6073:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":660,"nodeType":"ExpressionStatement","src":"6073:20:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":661,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6177:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":663,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"6177:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":664,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6177:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":665,"nodeType":"ExpressionStatement","src":"6177:14:0"},{"expression":{"arguments":[{"hexValue":"31323334","id":669,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6212:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":668,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"6201:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":667,"nodeType":"UserDefinedTypeName","pathNode":{"id":666,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"6205:6:0"},"referencedDeclaration":799,"src":"6205:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":670,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6201:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":671,"nodeType":"ExpressionStatement","src":"6201:16:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e636520656e64","id":675,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6240:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},"value":"nonce end"},{"arguments":[{"arguments":[{"arguments":[{"id":682,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6281:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":681,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6273:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":680,"name":"address","nodeType":"ElementaryTypeName","src":"6273:7:0","typeDescriptions":{}}},"id":683,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6273:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":678,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6261:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":679,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"6261:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":684,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6261:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":677,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6253:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":676,"name":"uint256","nodeType":"ElementaryTypeName","src":"6253:7:0","typeDescriptions":{}}},"id":685,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6253:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":672,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6228:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":674,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"6228:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":686,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6228:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":687,"nodeType":"ExpressionStatement","src":"6228:61:0"}]},"documentation":{"id":457,"nodeType":"StructuredDocumentation","src":"4902:56:0","text":"@notice example function, to test vm.broadcast with."},"functionSelector":"bef03abc","implemented":true,"kind":"function","modifiers":[],"name":"runBroadcast","nameLocation":"4972:12:0","parameters":{"id":458,"nodeType":"ParameterList","parameters":[],"src":"4984:2:0"},"returnParameters":{"id":459,"nodeType":"ParameterList","parameters":[],"src":"4994:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":713,"nodeType":"FunctionDefinition","src":"6391:143:0","nodes":[],"body":{"id":712,"nodeType":"Block","src":"6440:94:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":698,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":692,"src":"6462:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":695,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6450:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":697,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6450:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":699,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6450:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":700,"nodeType":"ExpressionStatement","src":"6450:15:0"},{"expression":{"arguments":[{"hexValue":"68656c6c6f206d73672e73656e646572","id":704,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6487:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},"value":"hello msg.sender"},{"arguments":[{"expression":{"id":707,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"6515:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":708,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"6515:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":706,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6507:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":705,"name":"address","nodeType":"ElementaryTypeName","src":"6507:7:0","typeDescriptions":{}}},"id":709,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6507:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":701,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6475:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":703,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"6475:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":710,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6475:52:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":711,"nodeType":"ExpressionStatement","src":"6475:52:0"}]},"documentation":{"id":690,"nodeType":"StructuredDocumentation","src":"6302:84:0","text":"@notice example external function, to force a CALL, and test vm.startPrank with."},"functionSelector":"a777d0dc","implemented":true,"kind":"function","modifiers":[],"name":"hello","nameLocation":"6400:5:0","parameters":{"id":693,"nodeType":"ParameterList","parameters":[{"constant":false,"id":692,"mutability":"mutable","name":"_v","nameLocation":"6422:2:0","nodeType":"VariableDeclaration","scope":713,"src":"6406:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":691,"name":"string","nodeType":"ElementaryTypeName","src":"6406:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6405:20:0"},"returnParameters":{"id":694,"nodeType":"ParameterList","parameters":[],"src":"6440:0:0"},"scope":786,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":728,"nodeType":"FunctionDefinition","src":"6540:95:0","nodes":[],"body":{"id":727,"nodeType":"Block","src":"6584:51:0","nodes":[],"statements":[{"expression":{"id":719,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6594:9:0","subExpression":{"id":718,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6594:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":720,"nodeType":"ExpressionStatement","src":"6594:9:0"},{"expression":{"arguments":[{"id":724,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":715,"src":"6625:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":721,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6613:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":723,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6613:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":725,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6613:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":726,"nodeType":"ExpressionStatement","src":"6613:15:0"}]},"functionSelector":"7e79255d","implemented":true,"kind":"function","modifiers":[],"name":"call1","nameLocation":"6549:5:0","parameters":{"id":716,"nodeType":"ParameterList","parameters":[{"constant":false,"id":715,"mutability":"mutable","name":"_v","nameLocation":"6571:2:0","nodeType":"VariableDeclaration","scope":728,"src":"6555:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":714,"name":"string","nodeType":"ElementaryTypeName","src":"6555:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6554:20:0"},"returnParameters":{"id":717,"nodeType":"ParameterList","parameters":[],"src":"6584:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":743,"nodeType":"FunctionDefinition","src":"6641:95:0","nodes":[],"body":{"id":742,"nodeType":"Block","src":"6685:51:0","nodes":[],"statements":[{"expression":{"id":734,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6695:9:0","subExpression":{"id":733,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6695:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":735,"nodeType":"ExpressionStatement","src":"6695:9:0"},{"expression":{"arguments":[{"id":739,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":730,"src":"6726:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":736,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6714:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":738,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6714:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":740,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6714:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":741,"nodeType":"ExpressionStatement","src":"6714:15:0"}]},"functionSelector":"8d3ef7ca","implemented":true,"kind":"function","modifiers":[],"name":"call2","nameLocation":"6650:5:0","parameters":{"id":731,"nodeType":"ParameterList","parameters":[{"constant":false,"id":730,"mutability":"mutable","name":"_v","nameLocation":"6672:2:0","nodeType":"VariableDeclaration","scope":743,"src":"6656:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":729,"name":"string","nodeType":"ElementaryTypeName","src":"6656:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6655:20:0"},"returnParameters":{"id":732,"nodeType":"ParameterList","parameters":[],"src":"6685:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":758,"nodeType":"FunctionDefinition","src":"6742:98:0","nodes":[],"body":{"id":757,"nodeType":"Block","src":"6788:52:0","nodes":[],"statements":[{"expression":{"id":749,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6798:9:0","subExpression":{"id":748,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6798:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":750,"nodeType":"ExpressionStatement","src":"6798:9:0"},{"expression":{"arguments":[{"id":754,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":745,"src":"6830:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":751,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6817:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":753,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested2","nodeType":"MemberAccess","referencedDeclaration":773,"src":"6817:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":755,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6817:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":756,"nodeType":"ExpressionStatement","src":"6817:16:0"}]},"functionSelector":"a76ccdfa","implemented":true,"kind":"function","modifiers":[],"name":"nested1","nameLocation":"6751:7:0","parameters":{"id":746,"nodeType":"ParameterList","parameters":[{"constant":false,"id":745,"mutability":"mutable","name":"_v","nameLocation":"6775:2:0","nodeType":"VariableDeclaration","scope":758,"src":"6759:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":744,"name":"string","nodeType":"ElementaryTypeName","src":"6759:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6758:20:0"},"returnParameters":{"id":747,"nodeType":"ParameterList","parameters":[],"src":"6788:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":773,"nodeType":"FunctionDefinition","src":"6846:97:0","nodes":[],"body":{"id":772,"nodeType":"Block","src":"6892:51:0","nodes":[],"statements":[{"expression":{"id":764,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6902:9:0","subExpression":{"id":763,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6902:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":765,"nodeType":"ExpressionStatement","src":"6902:9:0"},{"expression":{"arguments":[{"id":769,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":760,"src":"6933:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":766,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6921:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":768,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6921:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":770,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6921:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":771,"nodeType":"ExpressionStatement","src":"6921:15:0"}]},"functionSelector":"dbf1282f","implemented":true,"kind":"function","modifiers":[],"name":"nested2","nameLocation":"6855:7:0","parameters":{"id":761,"nodeType":"ParameterList","parameters":[{"constant":false,"id":760,"mutability":"mutable","name":"_v","nameLocation":"6879:2:0","nodeType":"VariableDeclaration","scope":773,"src":"6863:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":759,"name":"string","nodeType":"ElementaryTypeName","src":"6863:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6862:20:0"},"returnParameters":{"id":762,"nodeType":"ParameterList","parameters":[],"src":"6892:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":785,"nodeType":"FunctionDefinition","src":"6949:84:0","nodes":[],"body":{"id":784,"nodeType":"Block","src":"7001:32:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":781,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":775,"src":"7023:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":778,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"7011:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":780,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"7011:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":782,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7011:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":783,"nodeType":"ExpressionStatement","src":"7011:15:0"}]},"functionSelector":"7f8b915c","implemented":true,"kind":"function","modifiers":[],"name":"callPure","nameLocation":"6958:8:0","parameters":{"id":776,"nodeType":"ParameterList","parameters":[{"constant":false,"id":775,"mutability":"mutable","name":"_v","nameLocation":"6983:2:0","nodeType":"VariableDeclaration","scope":785,"src":"6967:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":774,"name":"string","nodeType":"ElementaryTypeName","src":"6967:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6966:20:0"},"returnParameters":{"id":777,"nodeType":"ParameterList","parameters":[],"src":"7001:0:0"},"scope":786,"stateMutability":"pure","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ScriptExample","contractDependencies":[799],"contractKind":"contract","documentation":{"id":221,"nodeType":"StructuredDocumentation","src":"2997:126:0","text":"@title ScriptExample\n @notice ScriptExample is an example script. The Go forge script code tests that it can run this."},"fullyImplemented":true,"linearizedBaseContracts":[786],"name":"ScriptExample","nameLocation":"3132:13:0","scope":969,"usedErrors":[]},{"id":799,"nodeType":"ContractDefinition","src":"7037:96:0","nodes":[{"id":788,"nodeType":"VariableDeclaration","src":"7059:18:0","nodes":[],"constant":false,"functionSelector":"c2985578","mutability":"mutable","name":"foo","nameLocation":"7074:3:0","scope":799,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":787,"name":"uint256","nodeType":"ElementaryTypeName","src":"7059:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":798,"nodeType":"FunctionDefinition","src":"7084:47:0","nodes":[],"body":{"id":797,"nodeType":"Block","src":"7107:24:0","nodes":[],"statements":[{"expression":{"id":795,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":793,"name":"foo","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":788,"src":"7117:3:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":794,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":790,"src":"7123:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"7117:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":796,"nodeType":"ExpressionStatement","src":"7117:7:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":791,"nodeType":"ParameterList","parameters":[{"constant":false,"id":790,"mutability":"mutable","name":"v","nameLocation":"7104:1:0","nodeType":"VariableDeclaration","scope":798,"src":"7096:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":789,"name":"uint256","nodeType":"ElementaryTypeName","src":"7096:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7095:11:0"},"returnParameters":{"id":792,"nodeType":"ParameterList","parameters":[],"src":"7107:0:0"},"scope":799,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"FooBar","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[799],"name":"FooBar","nameLocation":"7046:6:0","scope":969,"usedErrors":[]},{"id":833,"nodeType":"ContractDefinition","src":"7135:281:0","nodes":[{"id":813,"nodeType":"VariableDeclaration","src":"7162:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7188:10:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":800,"name":"address","nodeType":"ElementaryTypeName","src":"7162:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":808,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7235:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":807,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7225:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":809,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7225:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":806,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7217:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":805,"name":"uint256","nodeType":"ElementaryTypeName","src":"7217:7:0","typeDescriptions":{}}},"id":810,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7217:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":804,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7209:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":803,"name":"uint160","nodeType":"ElementaryTypeName","src":"7209:7:0","typeDescriptions":{}}},"id":811,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7209:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":802,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":801,"name":"address","nodeType":"ElementaryTypeName","src":"7201:7:0","typeDescriptions":{}}},"id":812,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7201:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":819,"nodeType":"VariableDeclaration","src":"7262:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7283:2:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":815,"nodeType":"UserDefinedTypeName","pathNode":{"id":814,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7262:2:0"},"referencedDeclaration":83,"src":"7262:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":817,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":813,"src":"7291:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":816,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7288:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":818,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7288:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":832,"nodeType":"FunctionDefinition","src":"7309:105:0","nodes":[],"body":{"id":831,"nodeType":"Block","src":"7372:42:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":828,"name":"_addr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":821,"src":"7401:5:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":826,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":819,"src":"7389:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":827,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7389:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":829,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7389:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"functionReturnParameters":825,"id":830,"nodeType":"Return","src":"7382:25:0"}]},"functionSelector":"2d0335ab","implemented":true,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"7318:8:0","parameters":{"id":822,"nodeType":"ParameterList","parameters":[{"constant":false,"id":821,"mutability":"mutable","name":"_addr","nameLocation":"7335:5:0","nodeType":"VariableDeclaration","scope":832,"src":"7327:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":820,"name":"address","nodeType":"ElementaryTypeName","src":"7327:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"7326:15:0"},"returnParameters":{"id":825,"nodeType":"ParameterList","parameters":[{"constant":false,"id":824,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":832,"src":"7363:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":823,"name":"uint256","nodeType":"ElementaryTypeName","src":"7363:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7362:9:0"},"scope":833,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"NonceGetter","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[833],"name":"NonceGetter","nameLocation":"7144:11:0","scope":969,"usedErrors":[]},{"id":852,"nodeType":"ContractDefinition","src":"7418:174:0","nodes":[{"id":835,"nodeType":"VariableDeclaration","src":"7448:18:0","nodes":[],"constant":false,"mutability":"mutable","name":"v","nameLocation":"7465:1:0","scope":852,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":834,"name":"uint256","nodeType":"ElementaryTypeName","src":"7448:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"id":843,"nodeType":"FunctionDefinition","src":"7473:36:0","nodes":[],"body":{"id":842,"nodeType":"Block","src":"7487:22:0","nodes":[],"statements":[{"expression":{"id":840,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":838,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7497:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"hexValue":"31","id":839,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7501:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"7497:5:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":841,"nodeType":"ExpressionStatement","src":"7497:5:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":836,"nodeType":"ParameterList","parameters":[],"src":"7484:2:0"},"returnParameters":{"id":837,"nodeType":"ParameterList","parameters":[],"src":"7487:0:0"},"scope":852,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":851,"nodeType":"FunctionDefinition","src":"7515:75:0","nodes":[],"body":{"id":850,"nodeType":"Block","src":"7565:25:0","nodes":[],"statements":[{"expression":{"id":848,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7582:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"functionReturnParameters":847,"id":849,"nodeType":"Return","src":"7575:8:0"}]},"functionSelector":"20965255","implemented":true,"kind":"function","modifiers":[],"name":"getValue","nameLocation":"7524:8:0","parameters":{"id":844,"nodeType":"ParameterList","parameters":[],"src":"7532:2:0"},"returnParameters":{"id":847,"nodeType":"ParameterList","parameters":[{"constant":false,"id":846,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":851,"src":"7556:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":845,"name":"uint256","nodeType":"ElementaryTypeName","src":"7556:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7555:9:0"},"scope":852,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkedContract","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[852],"name":"ForkedContract","nameLocation":"7427:14:0","scope":969,"usedErrors":[]},{"id":968,"nodeType":"ContractDefinition","src":"7594:813:0","nodes":[{"id":866,"nodeType":"VariableDeclaration","src":"7620:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7646:10:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":853,"name":"address","nodeType":"ElementaryTypeName","src":"7620:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":861,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7693:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":860,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7683:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":862,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7683:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":859,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7675:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":858,"name":"uint256","nodeType":"ElementaryTypeName","src":"7675:7:0","typeDescriptions":{}}},"id":863,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7675:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":857,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7667:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":856,"name":"uint160","nodeType":"ElementaryTypeName","src":"7667:7:0","typeDescriptions":{}}},"id":864,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7667:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":855,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7659:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":854,"name":"address","nodeType":"ElementaryTypeName","src":"7659:7:0","typeDescriptions":{}}},"id":865,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7659:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":872,"nodeType":"VariableDeclaration","src":"7720:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7741:2:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":868,"nodeType":"UserDefinedTypeName","pathNode":{"id":867,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7720:2:0"},"referencedDeclaration":83,"src":"7720:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":870,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":866,"src":"7749:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":869,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7746:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":871,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7746:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":967,"nodeType":"FunctionDefinition","src":"7767:638:0","nodes":[],"body":{"id":966,"nodeType":"Block","src":"7791:614:0","nodes":[],"statements":[{"assignments":[876],"declarations":[{"constant":false,"id":876,"mutability":"mutable","name":"testAddr","nameLocation":"7809:8:0","nodeType":"VariableDeclaration","scope":966,"src":"7801:16:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":875,"name":"address","nodeType":"ElementaryTypeName","src":"7801:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":884,"initialValue":{"arguments":[{"arguments":[{"hexValue":"307831323334","id":881,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7836:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":880,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7828:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":879,"name":"uint160","nodeType":"ElementaryTypeName","src":"7828:7:0","typeDescriptions":{}}},"id":882,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7828:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":878,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7820:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":877,"name":"address","nodeType":"ElementaryTypeName","src":"7820:7:0","typeDescriptions":{}}},"id":883,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7820:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"7801:43:0"},{"assignments":[887],"declarations":[{"constant":false,"id":887,"mutability":"mutable","name":"fc","nameLocation":"7869:2:0","nodeType":"VariableDeclaration","scope":966,"src":"7854:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"},"typeName":{"id":886,"nodeType":"UserDefinedTypeName","pathNode":{"id":885,"name":"ForkedContract","nodeType":"IdentifierPath","referencedDeclaration":852,"src":"7854:14:0"},"referencedDeclaration":852,"src":"7854:14:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"visibility":"internal"}],"id":891,"initialValue":{"arguments":[{"id":889,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7889:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":888,"name":"ForkedContract","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":852,"src":"7874:14:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_ForkedContract_$852_$","typeString":"type(contract ForkedContract)"}},"id":890,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7874:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"nodeType":"VariableDeclarationStatement","src":"7854:44:0"},{"expression":{"arguments":[{"hexValue":"666f726b31","id":895,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7929:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},"value":"fork1"},{"hexValue":"3132333435","id":896,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7938:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"}],"expression":{"id":892,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7909:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":894,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"7909:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":897,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7909:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":898,"nodeType":"ExpressionStatement","src":"7909:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":905,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":902,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7974:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":900,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7962:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":901,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7962:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":903,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7962:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3132333435","id":904,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7987:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"},"src":"7962:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":906,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7994:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":899,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"7954:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":907,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7954:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":908,"nodeType":"ExpressionStatement","src":"7954:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":914,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":910,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8036:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":911,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8036:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":912,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8036:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31","id":913,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8053:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"8036:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652031","id":915,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8056:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""},"value":"value should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""}],"id":909,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8028:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":916,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8028:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":917,"nodeType":"ExpressionStatement","src":"8028:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":925,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":919,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8094:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":920,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8094:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"31","id":923,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8122:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"}],"id":922,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8114:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":921,"name":"uint256","nodeType":"ElementaryTypeName","src":"8114:7:0","typeDescriptions":{}}},"id":924,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8114:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8094:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652031","id":926,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8126:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""},"value":"balance should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""}],"id":918,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8086:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":927,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8086:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":928,"nodeType":"ExpressionStatement","src":"8086:62:0"},{"expression":{"arguments":[{"hexValue":"666f726b32","id":932,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8179:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},"value":"fork2"},{"hexValue":"3233343536","id":933,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8188:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"}],"expression":{"id":929,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8159:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":931,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"8159:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":934,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8159:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":935,"nodeType":"ExpressionStatement","src":"8159:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":942,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":939,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8224:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":937,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8212:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":938,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"8212:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":940,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8212:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3233343536","id":941,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8237:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"},"src":"8212:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":943,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8244:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":936,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8204:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":944,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8204:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":945,"nodeType":"ExpressionStatement","src":"8204:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":951,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":947,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8286:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":948,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8286:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":949,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8286:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"32","id":950,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8303:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"},"src":"8286:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652032","id":952,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8306:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""},"value":"value should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""}],"id":946,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8278:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":953,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8278:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":954,"nodeType":"ExpressionStatement","src":"8278:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":962,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":956,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8344:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":957,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8344:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"32","id":960,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8372:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"}],"id":959,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8364:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":958,"name":"uint256","nodeType":"ElementaryTypeName","src":"8364:7:0","typeDescriptions":{}}},"id":961,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8364:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8344:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652032","id":963,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8376:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""},"value":"balance should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""}],"id":955,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8336:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":964,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8336:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":965,"nodeType":"ExpressionStatement","src":"8336:62:0"}]},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"7776:3:0","parameters":{"id":873,"nodeType":"ParameterList","parameters":[],"src":"7779:2:0"},"returnParameters":{"id":874,"nodeType":"ParameterList","parameters":[],"src":"7791:0:0"},"scope":968,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkTester","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[968],"name":"ForkTester","nameLocation":"7603:10:0","scope":969,"usedErrors":[]}],"license":"MIT"},"id":0} \ No newline at end of file diff --git a/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/NonceGetter.json b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/NonceGetter.json new file mode 100644 index 0000000000000..5e6afe60d7101 --- /dev/null +++ b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/NonceGetter.json @@ -0,0 +1 @@ +{"abi":[{"type":"function","name":"getNonce","inputs":[{"name":"_addr","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"}],"bytecode":{"object":"0x608060405234801561001057600080fd5b5061017e806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80632d0335ab14610030575b600080fd5b61004361003e36600461010a565b610055565b60405190815260200160405180910390f35b6040517f2d0335ab00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152600090737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401602060405180830381865afa1580156100d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fa9190610147565b67ffffffffffffffff1692915050565b60006020828403121561011c57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461014057600080fd5b9392505050565b60006020828403121561015957600080fd5b815167ffffffffffffffff8116811461014057600080fdfea164736f6c634300080f000a","sourceMap":"7135:281:0:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b506004361061002b5760003560e01c80632d0335ab14610030575b600080fd5b61004361003e36600461010a565b610055565b60405190815260200160405180910390f35b6040517f2d0335ab00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152600090737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401602060405180830381865afa1580156100d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fa9190610147565b67ffffffffffffffff1692915050565b60006020828403121561011c57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461014057600080fd5b9392505050565b60006020828403121561015957600080fd5b815167ffffffffffffffff8116811461014057600080fdfea164736f6c634300080f000a","sourceMap":"7135:281:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7309:105;;;;;;:::i;:::-;;:::i;:::-;;;474:25:1;;;462:2;447:18;7309:105:0;;;;;;;;7389:18;;;;;686:42:1;674:55;;7389:18:0;;;656:74:1;7363:7:0;;7389:11;;;;629:18:1;;7389::0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7382:25;;;7309:105;-1:-1:-1;;7309:105:0:o;14:309:1:-;73:6;126:2;114:9;105:7;101:23;97:32;94:52;;;142:1;139;132:12;94:52;181:9;168:23;231:42;224:5;220:54;213:5;210:65;200:93;;289:1;286;279:12;200:93;312:5;14:309;-1:-1:-1;;;14:309:1:o;741:288::-;810:6;863:2;851:9;842:7;838:23;834:32;831:52;;;879:1;876;869:12;831:52;911:9;905:16;961:18;954:5;950:30;943:5;940:41;930:69;;995:1;992;985:12","linkReferences":{}},"methodIdentifiers":{"getNonce(address)":"2d0335ab"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"getNonce\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"scripts/ScriptExample.s.sol\":\"NonceGetter\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"scripts/ScriptExample.s.sol\":{\"keccak256\":\"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28\",\"dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"_addr","type":"address"}],"stateMutability":"view","type":"function","name":"getNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"scripts/ScriptExample.s.sol":"NonceGetter"},"evmVersion":"london","libraries":{}},"sources":{"scripts/ScriptExample.s.sol":{"keccak256":"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da","urls":["bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28","dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[],"types":{}},"userdoc":{"version":1,"kind":"user"},"devdoc":{"version":1,"kind":"dev"},"ast":{"absolutePath":"scripts/ScriptExample.s.sol","id":969,"exportedSymbols":{"FooBar":[799],"ForkTester":[968],"ForkedContract":[852],"NonceGetter":[833],"ScriptExample":[786],"Vm":[83],"console":[220]},"nodeType":"SourceUnit","src":"32:8375:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","0.8",".15"]},{"id":83,"nodeType":"ContractDefinition","src":"120:969:0","nodes":[{"id":10,"nodeType":"FunctionDefinition","src":"139:91:0","nodes":[],"functionSelector":"4777f3cf","implemented":false,"kind":"function","modifiers":[],"name":"envOr","nameLocation":"148:5:0","parameters":{"id":6,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"mutability":"mutable","name":"name","nameLocation":"170:4:0","nodeType":"VariableDeclaration","scope":10,"src":"154:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":2,"name":"string","nodeType":"ElementaryTypeName","src":"154:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":5,"mutability":"mutable","name":"defaultValue","nameLocation":"181:12:0","nodeType":"VariableDeclaration","scope":10,"src":"176:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":4,"name":"bool","nodeType":"ElementaryTypeName","src":"176:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"153:41:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[{"constant":false,"id":8,"mutability":"mutable","name":"value","nameLocation":"223:5:0","nodeType":"VariableDeclaration","scope":10,"src":"218:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":7,"name":"bool","nodeType":"ElementaryTypeName","src":"218:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"217:12:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":17,"nodeType":"FunctionDefinition","src":"235:72:0","nodes":[],"functionSelector":"2d0335ab","implemented":false,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"244:8:0","parameters":{"id":13,"nodeType":"ParameterList","parameters":[{"constant":false,"id":12,"mutability":"mutable","name":"account","nameLocation":"261:7:0","nodeType":"VariableDeclaration","scope":17,"src":"253:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":11,"name":"address","nodeType":"ElementaryTypeName","src":"253:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"252:17:0"},"returnParameters":{"id":16,"nodeType":"ParameterList","parameters":[{"constant":false,"id":15,"mutability":"mutable","name":"nonce","nameLocation":"300:5:0","nodeType":"VariableDeclaration","scope":17,"src":"293:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"},"typeName":{"id":14,"name":"uint64","nodeType":"ElementaryTypeName","src":"293:6:0","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"visibility":"internal"}],"src":"292:14:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":27,"nodeType":"FunctionDefinition","src":"312:111:0","nodes":[],"functionSelector":"213e4198","implemented":false,"kind":"function","modifiers":[],"name":"parseJsonKeys","nameLocation":"321:13:0","parameters":{"id":22,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19,"mutability":"mutable","name":"json","nameLocation":"351:4:0","nodeType":"VariableDeclaration","scope":27,"src":"335:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":18,"name":"string","nodeType":"ElementaryTypeName","src":"335:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":21,"mutability":"mutable","name":"key","nameLocation":"373:3:0","nodeType":"VariableDeclaration","scope":27,"src":"357:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":20,"name":"string","nodeType":"ElementaryTypeName","src":"357:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"334:43:0"},"returnParameters":{"id":26,"nodeType":"ParameterList","parameters":[{"constant":false,"id":25,"mutability":"mutable","name":"keys","nameLocation":"417:4:0","nodeType":"VariableDeclaration","scope":27,"src":"401:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":23,"name":"string","nodeType":"ElementaryTypeName","src":"401:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":24,"nodeType":"ArrayTypeName","src":"401:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"src":"400:22:0"},"scope":83,"stateMutability":"pure","virtual":false,"visibility":"external"},{"id":32,"nodeType":"FunctionDefinition","src":"428:48:0","nodes":[],"functionSelector":"06447d56","implemented":false,"kind":"function","modifiers":[],"name":"startPrank","nameLocation":"437:10:0","parameters":{"id":30,"nodeType":"ParameterList","parameters":[{"constant":false,"id":29,"mutability":"mutable","name":"msgSender","nameLocation":"456:9:0","nodeType":"VariableDeclaration","scope":32,"src":"448:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":28,"name":"address","nodeType":"ElementaryTypeName","src":"448:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"447:19:0"},"returnParameters":{"id":31,"nodeType":"ParameterList","parameters":[],"src":"475:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":35,"nodeType":"FunctionDefinition","src":"481:30:0","nodes":[],"functionSelector":"90c5013b","implemented":false,"kind":"function","modifiers":[],"name":"stopPrank","nameLocation":"490:9:0","parameters":{"id":33,"nodeType":"ParameterList","parameters":[],"src":"499:2:0"},"returnParameters":{"id":34,"nodeType":"ParameterList","parameters":[],"src":"510:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":38,"nodeType":"FunctionDefinition","src":"516:30:0","nodes":[],"functionSelector":"afc98040","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"525:9:0","parameters":{"id":36,"nodeType":"ParameterList","parameters":[],"src":"534:2:0"},"returnParameters":{"id":37,"nodeType":"ParameterList","parameters":[],"src":"545:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":43,"nodeType":"FunctionDefinition","src":"551:47:0","nodes":[],"functionSelector":"e6962cdb","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"560:9:0","parameters":{"id":41,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40,"mutability":"mutable","name":"msgSender","nameLocation":"578:9:0","nodeType":"VariableDeclaration","scope":43,"src":"570:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39,"name":"address","nodeType":"ElementaryTypeName","src":"570:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"569:19:0"},"returnParameters":{"id":42,"nodeType":"ParameterList","parameters":[],"src":"597:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":48,"nodeType":"FunctionDefinition","src":"603:52:0","nodes":[],"functionSelector":"7fec2a8d","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"612:14:0","parameters":{"id":46,"nodeType":"ParameterList","parameters":[{"constant":false,"id":45,"mutability":"mutable","name":"msgSender","nameLocation":"635:9:0","nodeType":"VariableDeclaration","scope":48,"src":"627:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":44,"name":"address","nodeType":"ElementaryTypeName","src":"627:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"626:19:0"},"returnParameters":{"id":47,"nodeType":"ParameterList","parameters":[],"src":"654:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":51,"nodeType":"FunctionDefinition","src":"660:35:0","nodes":[],"functionSelector":"7fb5297f","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"669:14:0","parameters":{"id":49,"nodeType":"ParameterList","parameters":[],"src":"683:2:0"},"returnParameters":{"id":50,"nodeType":"ParameterList","parameters":[],"src":"694:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":54,"nodeType":"FunctionDefinition","src":"700:34:0","nodes":[],"functionSelector":"76eadd36","implemented":false,"kind":"function","modifiers":[],"name":"stopBroadcast","nameLocation":"709:13:0","parameters":{"id":52,"nodeType":"ParameterList","parameters":[],"src":"722:2:0"},"returnParameters":{"id":53,"nodeType":"ParameterList","parameters":[],"src":"733:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":61,"nodeType":"FunctionDefinition","src":"739:108:0","nodes":[],"functionSelector":"3ebf73b4","implemented":false,"kind":"function","modifiers":[],"name":"getDeployedCode","nameLocation":"748:15:0","parameters":{"id":57,"nodeType":"ParameterList","parameters":[{"constant":false,"id":56,"mutability":"mutable","name":"artifactPath","nameLocation":"780:12:0","nodeType":"VariableDeclaration","scope":61,"src":"764:28:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":55,"name":"string","nodeType":"ElementaryTypeName","src":"764:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"763:30:0"},"returnParameters":{"id":60,"nodeType":"ParameterList","parameters":[{"constant":false,"id":59,"mutability":"mutable","name":"runtimeBytecode","nameLocation":"830:15:0","nodeType":"VariableDeclaration","scope":61,"src":"817:28:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":58,"name":"bytes","nodeType":"ElementaryTypeName","src":"817:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"816:30:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":68,"nodeType":"FunctionDefinition","src":"852:74:0","nodes":[],"functionSelector":"b4d6c782","implemented":false,"kind":"function","modifiers":[],"name":"etch","nameLocation":"861:4:0","parameters":{"id":66,"nodeType":"ParameterList","parameters":[{"constant":false,"id":63,"mutability":"mutable","name":"target","nameLocation":"874:6:0","nodeType":"VariableDeclaration","scope":68,"src":"866:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":62,"name":"address","nodeType":"ElementaryTypeName","src":"866:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":65,"mutability":"mutable","name":"newRuntimeBytecode","nameLocation":"897:18:0","nodeType":"VariableDeclaration","scope":68,"src":"882:33:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":64,"name":"bytes","nodeType":"ElementaryTypeName","src":"882:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"865:51:0"},"returnParameters":{"id":67,"nodeType":"ParameterList","parameters":[],"src":"925:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":73,"nodeType":"FunctionDefinition","src":"931:51:0","nodes":[],"functionSelector":"ea060291","implemented":false,"kind":"function","modifiers":[],"name":"allowCheatcodes","nameLocation":"940:15:0","parameters":{"id":71,"nodeType":"ParameterList","parameters":[{"constant":false,"id":70,"mutability":"mutable","name":"account","nameLocation":"964:7:0","nodeType":"VariableDeclaration","scope":73,"src":"956:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":69,"name":"address","nodeType":"ElementaryTypeName","src":"956:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"955:17:0"},"returnParameters":{"id":72,"nodeType":"ParameterList","parameters":[],"src":"981:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":82,"nodeType":"FunctionDefinition","src":"987:100:0","nodes":[],"functionSelector":"71ee464d","implemented":false,"kind":"function","modifiers":[],"name":"createSelectFork","nameLocation":"996:16:0","parameters":{"id":78,"nodeType":"ParameterList","parameters":[{"constant":false,"id":75,"mutability":"mutable","name":"forkName","nameLocation":"1029:8:0","nodeType":"VariableDeclaration","scope":82,"src":"1013:24:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":74,"name":"string","nodeType":"ElementaryTypeName","src":"1013:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":77,"mutability":"mutable","name":"blockNumber","nameLocation":"1047:11:0","nodeType":"VariableDeclaration","scope":82,"src":"1039:19:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":76,"name":"uint256","nodeType":"ElementaryTypeName","src":"1039:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1012:47:0"},"returnParameters":{"id":81,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":82,"src":"1078:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":79,"name":"uint256","nodeType":"ElementaryTypeName","src":"1078:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1077:9:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"Vm","contractDependencies":[],"contractKind":"interface","fullyImplemented":false,"linearizedBaseContracts":[83],"name":"Vm","nameLocation":"130:2:0","scope":969,"usedErrors":[]},{"id":220,"nodeType":"ContractDefinition","src":"1144:1851:0","nodes":[{"id":89,"nodeType":"VariableDeclaration","src":"1166:86:0","nodes":[],"constant":true,"mutability":"constant","name":"CONSOLE_ADDRESS","nameLocation":"1183:15:0","scope":220,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":84,"name":"address","nodeType":"ElementaryTypeName","src":"1166:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"hexValue":"307830303030303030303030303030303030303036333646366537333646366336353265366336663637","id":87,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1209:42:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"value":"0x000000000000000000636F6e736F6c652e6c6f67"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":86,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":85,"name":"address","nodeType":"ElementaryTypeName","src":"1201:7:0","typeDescriptions":{}}},"id":88,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1201:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":106,"nodeType":"FunctionDefinition","src":"1259:235:0","nodes":[],"body":{"id":105,"nodeType":"Block","src":"1432:62:0","nodes":[],"statements":[{"AST":{"nodeType":"YulBlock","src":"1451:37:0","statements":[{"nodeType":"YulAssignment","src":"1465:13:0","value":{"name":"fnIn","nodeType":"YulIdentifier","src":"1474:4:0"},"variableNames":[{"name":"fnOut","nodeType":"YulIdentifier","src":"1465:5:0"}]}]},"evmVersion":"london","externalReferences":[{"declaration":95,"isOffset":false,"isSlot":false,"src":"1474:4:0","valueSize":1},{"declaration":102,"isOffset":false,"isSlot":false,"src":"1465:5:0","valueSize":1}],"id":104,"nodeType":"InlineAssembly","src":"1442:46:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_castLogPayloadViewToPure","nameLocation":"1268:25:0","parameters":{"id":96,"nodeType":"ParameterList","parameters":[{"constant":false,"id":95,"mutability":"mutable","name":"fnIn","nameLocation":"1331:4:0","nodeType":"VariableDeclaration","scope":106,"src":"1294:41:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"typeName":{"id":94,"nodeType":"FunctionTypeName","parameterTypes":{"id":92,"nodeType":"ParameterList","parameters":[{"constant":false,"id":91,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":94,"src":"1303:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":90,"name":"bytes","nodeType":"ElementaryTypeName","src":"1303:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1302:14:0"},"returnParameterTypes":{"id":93,"nodeType":"ParameterList","parameters":[],"src":"1331:0:0"},"src":"1294:41:0","stateMutability":"view","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"visibility":"internal"},"visibility":"internal"}],"src":"1293:43:0"},"returnParameters":{"id":103,"nodeType":"ParameterList","parameters":[{"constant":false,"id":102,"mutability":"mutable","name":"fnOut","nameLocation":"1421:5:0","nodeType":"VariableDeclaration","scope":106,"src":"1384:42:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"typeName":{"id":101,"nodeType":"FunctionTypeName","parameterTypes":{"id":99,"nodeType":"ParameterList","parameters":[{"constant":false,"id":98,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":101,"src":"1393:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":97,"name":"bytes","nodeType":"ElementaryTypeName","src":"1393:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1392:14:0"},"returnParameterTypes":{"id":100,"nodeType":"ParameterList","parameters":[],"src":"1421:0:0"},"src":"1384:42:0","stateMutability":"pure","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"visibility":"internal"},"visibility":"internal"}],"src":"1383:44:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":118,"nodeType":"FunctionDefinition","src":"1500:133:0","nodes":[],"body":{"id":117,"nodeType":"Block","src":"1561:72:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":114,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":108,"src":"1618:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"arguments":[{"id":112,"name":"_sendLogPayloadView","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":134,"src":"1597:19:0","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}],"id":111,"name":"_castLogPayloadViewToPure","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":106,"src":"1571:25:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_function_internal_view$_t_bytes_memory_ptr_$returns$__$_$returns$_t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$_$","typeString":"function (function (bytes memory) view) pure returns (function (bytes memory) pure)"}},"id":113,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":115,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":116,"nodeType":"ExpressionStatement","src":"1571:55:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayload","nameLocation":"1509:15:0","parameters":{"id":109,"nodeType":"ParameterList","parameters":[{"constant":false,"id":108,"mutability":"mutable","name":"payload","nameLocation":"1538:7:0","nodeType":"VariableDeclaration","scope":118,"src":"1525:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":107,"name":"bytes","nodeType":"ElementaryTypeName","src":"1525:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1524:22:0"},"returnParameters":{"id":110,"nodeType":"ParameterList","parameters":[],"src":"1561:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":134,"nodeType":"FunctionDefinition","src":"1639:380:0","nodes":[],"body":{"id":133,"nodeType":"Block","src":"1703:316:0","nodes":[],"statements":[{"assignments":[124],"declarations":[{"constant":false,"id":124,"mutability":"mutable","name":"payloadLength","nameLocation":"1721:13:0","nodeType":"VariableDeclaration","scope":133,"src":"1713:21:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":123,"name":"uint256","nodeType":"ElementaryTypeName","src":"1713:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":127,"initialValue":{"expression":{"id":125,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":120,"src":"1737:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":126,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1737:14:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1713:38:0"},{"assignments":[129],"declarations":[{"constant":false,"id":129,"mutability":"mutable","name":"consoleAddress","nameLocation":"1769:14:0","nodeType":"VariableDeclaration","scope":133,"src":"1761:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":128,"name":"address","nodeType":"ElementaryTypeName","src":"1761:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":131,"initialValue":{"id":130,"name":"CONSOLE_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":89,"src":"1786:15:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"1761:40:0"},{"AST":{"nodeType":"YulBlock","src":"1863:150:0","statements":[{"nodeType":"YulVariableDeclaration","src":"1877:36:0","value":{"arguments":[{"name":"payload","nodeType":"YulIdentifier","src":"1901:7:0"},{"kind":"number","nodeType":"YulLiteral","src":"1910:2:0","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1897:3:0"},"nodeType":"YulFunctionCall","src":"1897:16:0"},"variables":[{"name":"payloadStart","nodeType":"YulTypedName","src":"1881:12:0","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1926:77:0","value":{"arguments":[{"arguments":[],"functionName":{"name":"gas","nodeType":"YulIdentifier","src":"1946:3:0"},"nodeType":"YulFunctionCall","src":"1946:5:0"},{"name":"consoleAddress","nodeType":"YulIdentifier","src":"1953:14:0"},{"name":"payloadStart","nodeType":"YulIdentifier","src":"1969:12:0"},{"name":"payloadLength","nodeType":"YulIdentifier","src":"1983:13:0"},{"kind":"number","nodeType":"YulLiteral","src":"1998:1:0","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"2001:1:0","type":"","value":"0"}],"functionName":{"name":"staticcall","nodeType":"YulIdentifier","src":"1935:10:0"},"nodeType":"YulFunctionCall","src":"1935:68:0"},"variables":[{"name":"r","nodeType":"YulTypedName","src":"1930:1:0","type":""}]}]},"documentation":"@solidity memory-safe-assembly","evmVersion":"london","externalReferences":[{"declaration":129,"isOffset":false,"isSlot":false,"src":"1953:14:0","valueSize":1},{"declaration":120,"isOffset":false,"isSlot":false,"src":"1901:7:0","valueSize":1},{"declaration":124,"isOffset":false,"isSlot":false,"src":"1983:13:0","valueSize":1}],"id":132,"nodeType":"InlineAssembly","src":"1854:159:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayloadView","nameLocation":"1648:19:0","parameters":{"id":121,"nodeType":"ParameterList","parameters":[{"constant":false,"id":120,"mutability":"mutable","name":"payload","nameLocation":"1681:7:0","nodeType":"VariableDeclaration","scope":134,"src":"1668:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":119,"name":"bytes","nodeType":"ElementaryTypeName","src":"1668:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1667:22:0"},"returnParameters":{"id":122,"nodeType":"ParameterList","parameters":[],"src":"1703:0:0"},"scope":220,"stateMutability":"view","virtual":false,"visibility":"private"},{"id":148,"nodeType":"FunctionDefinition","src":"2025:164:0","nodes":[],"body":{"id":147,"nodeType":"Block","src":"2070:119:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e6729","id":142,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2120:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},"value":"log(string)"},{"id":143,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":136,"src":"2135:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":140,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2096:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":141,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2096:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":144,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2096:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":139,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2080:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":145,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2080:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":146,"nodeType":"ExpressionStatement","src":"2080:59:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2034:3:0","parameters":{"id":137,"nodeType":"ParameterList","parameters":[{"constant":false,"id":136,"mutability":"mutable","name":"p0","nameLocation":"2052:2:0","nodeType":"VariableDeclaration","scope":148,"src":"2038:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":135,"name":"string","nodeType":"ElementaryTypeName","src":"2038:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2037:18:0"},"returnParameters":{"id":138,"nodeType":"ParameterList","parameters":[],"src":"2070:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":165,"nodeType":"FunctionDefinition","src":"2195:182:0","nodes":[],"body":{"id":164,"nodeType":"Block","src":"2249:128:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c626f6f6c29","id":158,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2299:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},"value":"log(string,bool)"},{"id":159,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":150,"src":"2319:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":160,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":152,"src":"2323:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":156,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2275:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":157,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2275:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":161,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2275:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":155,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2259:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":162,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2259:68:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":163,"nodeType":"ExpressionStatement","src":"2259:68:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2204:3:0","parameters":{"id":153,"nodeType":"ParameterList","parameters":[{"constant":false,"id":150,"mutability":"mutable","name":"p0","nameLocation":"2222:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2208:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":149,"name":"string","nodeType":"ElementaryTypeName","src":"2208:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":152,"mutability":"mutable","name":"p1","nameLocation":"2231:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2226:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":151,"name":"bool","nodeType":"ElementaryTypeName","src":"2226:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"2207:27:0"},"returnParameters":{"id":154,"nodeType":"ParameterList","parameters":[],"src":"2249:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":182,"nodeType":"FunctionDefinition","src":"2383:188:0","nodes":[],"body":{"id":181,"nodeType":"Block","src":"2440:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c75696e7432353629","id":175,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2490:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},"value":"log(string,uint256)"},{"id":176,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":167,"src":"2513:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":177,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":169,"src":"2517:2:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":173,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2466:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":174,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2466:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":178,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2466:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":172,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2450:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":179,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2450:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":180,"nodeType":"ExpressionStatement","src":"2450:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2392:3:0","parameters":{"id":170,"nodeType":"ParameterList","parameters":[{"constant":false,"id":167,"mutability":"mutable","name":"p0","nameLocation":"2410:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2396:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":166,"name":"string","nodeType":"ElementaryTypeName","src":"2396:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":169,"mutability":"mutable","name":"p1","nameLocation":"2422:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2414:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":168,"name":"uint256","nodeType":"ElementaryTypeName","src":"2414:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"2395:30:0"},"returnParameters":{"id":171,"nodeType":"ParameterList","parameters":[],"src":"2440:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":199,"nodeType":"FunctionDefinition","src":"2577:188:0","nodes":[],"body":{"id":198,"nodeType":"Block","src":"2634:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c6164647265737329","id":192,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2684:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},"value":"log(string,address)"},{"id":193,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":184,"src":"2707:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":194,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":186,"src":"2711:2:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":190,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2660:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":191,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2660:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":195,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2660:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":189,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2644:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":196,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2644:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":197,"nodeType":"ExpressionStatement","src":"2644:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2586:3:0","parameters":{"id":187,"nodeType":"ParameterList","parameters":[{"constant":false,"id":184,"mutability":"mutable","name":"p0","nameLocation":"2604:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2590:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":183,"name":"string","nodeType":"ElementaryTypeName","src":"2590:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":186,"mutability":"mutable","name":"p1","nameLocation":"2616:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2608:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":185,"name":"address","nodeType":"ElementaryTypeName","src":"2608:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2589:30:0"},"returnParameters":{"id":188,"nodeType":"ParameterList","parameters":[],"src":"2634:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":219,"nodeType":"FunctionDefinition","src":"2771:222:0","nodes":[],"body":{"id":218,"nodeType":"Block","src":"2852:141:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c737472696e672c737472696e6729","id":211,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2902:27:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},"value":"log(string,string,string)"},{"id":212,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":201,"src":"2931:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":213,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":203,"src":"2935:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":214,"name":"p2","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":205,"src":"2939:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":209,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2878:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":210,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2878:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":215,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2878:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":208,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2862:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":216,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2862:81:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":217,"nodeType":"ExpressionStatement","src":"2862:81:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2780:3:0","parameters":{"id":206,"nodeType":"ParameterList","parameters":[{"constant":false,"id":201,"mutability":"mutable","name":"p0","nameLocation":"2798:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2784:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":200,"name":"string","nodeType":"ElementaryTypeName","src":"2784:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":203,"mutability":"mutable","name":"p1","nameLocation":"2816:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2802:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":202,"name":"string","nodeType":"ElementaryTypeName","src":"2802:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":205,"mutability":"mutable","name":"p2","nameLocation":"2834:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2820:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":204,"name":"string","nodeType":"ElementaryTypeName","src":"2820:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2783:54:0"},"returnParameters":{"id":207,"nodeType":"ParameterList","parameters":[],"src":"2852:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"}],"abstract":false,"baseContracts":[],"canonicalName":"console","contractDependencies":[],"contractKind":"library","fullyImplemented":true,"linearizedBaseContracts":[220],"name":"console","nameLocation":"1152:7:0","scope":969,"usedErrors":[]},{"id":786,"nodeType":"ContractDefinition","src":"3123:3912:0","nodes":[{"id":235,"nodeType":"VariableDeclaration","src":"3152:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"3178:10:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":222,"name":"address","nodeType":"ElementaryTypeName","src":"3152:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":230,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3225:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":229,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"3215:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":231,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3215:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":228,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3207:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":227,"name":"uint256","nodeType":"ElementaryTypeName","src":"3207:7:0","typeDescriptions":{}}},"id":232,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3207:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":226,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3199:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":225,"name":"uint160","nodeType":"ElementaryTypeName","src":"3199:7:0","typeDescriptions":{}}},"id":233,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3199:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":224,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3191:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":223,"name":"address","nodeType":"ElementaryTypeName","src":"3191:7:0","typeDescriptions":{}}},"id":234,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3191:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":241,"nodeType":"VariableDeclaration","src":"3252:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"3273:2:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":237,"nodeType":"UserDefinedTypeName","pathNode":{"id":236,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"3252:2:0"},"referencedDeclaration":83,"src":"3252:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":239,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":235,"src":"3281:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":238,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"3278:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":240,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3278:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":243,"nodeType":"VariableDeclaration","src":"3356:22:0","nodes":[],"constant":false,"functionSelector":"61bc221a","mutability":"mutable","name":"counter","nameLocation":"3371:7:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":242,"name":"uint256","nodeType":"ElementaryTypeName","src":"3356:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":456,"nodeType":"FunctionDefinition","src":"3468:1428:0","nodes":[],"body":{"id":455,"nodeType":"Block","src":"3490:1406:0","nodes":[],"statements":[{"assignments":[248],"declarations":[{"constant":false,"id":248,"mutability":"mutable","name":"x","nameLocation":"3505:1:0","nodeType":"VariableDeclaration","scope":455,"src":"3500:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":247,"name":"bool","nodeType":"ElementaryTypeName","src":"3500:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"id":254,"initialValue":{"arguments":[{"hexValue":"4558414d504c455f424f4f4c","id":251,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3518:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},"value":"EXAMPLE_BOOL"},{"hexValue":"66616c7365","id":252,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"3534:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":249,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3509:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":250,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"envOr","nodeType":"MemberAccess","referencedDeclaration":10,"src":"3509:8:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$_t_bool_$returns$_t_bool_$","typeString":"function (string memory,bool) view external returns (bool)"}},"id":253,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3509:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"VariableDeclarationStatement","src":"3500:40:0"},{"expression":{"arguments":[{"hexValue":"626f6f6c2076616c75652066726f6d20656e76","id":258,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3562:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},"value":"bool value from env"},{"id":259,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":248,"src":"3585:1:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":255,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3550:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":257,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":165,"src":"3550:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_bool_$returns$__$","typeString":"function (string memory,bool) pure"}},"id":260,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3550:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":261,"nodeType":"ExpressionStatement","src":"3550:37:0"},{"expression":{"arguments":[{"hexValue":"636f6e74726163742061646472","id":265,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3610:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},"value":"contract addr"},{"arguments":[{"id":268,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3635:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":267,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3627:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":266,"name":"address","nodeType":"ElementaryTypeName","src":"3627:7:0","typeDescriptions":{}}},"id":269,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3627:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":262,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3598:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":264,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3598:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":270,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3598:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":271,"nodeType":"ExpressionStatement","src":"3598:43:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206e6f6e6365","id":275,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3663:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},"value":"contract nonce"},{"arguments":[{"arguments":[{"id":280,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3701:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":279,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3693:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":278,"name":"address","nodeType":"ElementaryTypeName","src":"3693:7:0","typeDescriptions":{}}},"id":281,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3693:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":276,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3681:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":277,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3681:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":282,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3681:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":272,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3651:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":274,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3651:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":283,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3651:57:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":284,"nodeType":"ExpressionStatement","src":"3651:57:0"},{"expression":{"arguments":[{"hexValue":"73656e6465722061646472","id":288,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3730:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},"value":"sender addr"},{"arguments":[{"expression":{"id":291,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3753:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":292,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3753:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":290,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3745:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":289,"name":"address","nodeType":"ElementaryTypeName","src":"3745:7:0","typeDescriptions":{}}},"id":293,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3745:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":285,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3718:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":287,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3718:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":294,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3718:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":295,"nodeType":"ExpressionStatement","src":"3718:47:0"},{"expression":{"arguments":[{"hexValue":"73656e646572206e6f6e6365","id":299,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3787:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},"value":"sender nonce"},{"arguments":[{"arguments":[{"expression":{"id":304,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3823:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":305,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3823:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":303,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3815:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":302,"name":"address","nodeType":"ElementaryTypeName","src":"3815:7:0","typeDescriptions":{}}},"id":306,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3815:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":300,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3803:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":301,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3803:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":307,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3803:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":296,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3775:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":298,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3775:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":308,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3775:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":309,"nodeType":"ExpressionStatement","src":"3775:61:0"},{"assignments":[311],"declarations":[{"constant":false,"id":311,"mutability":"mutable","name":"json","nameLocation":"3861:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3847:18:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":310,"name":"string","nodeType":"ElementaryTypeName","src":"3847:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"id":313,"initialValue":{"hexValue":"7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d","id":312,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3868:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e95522e99766888d0261f55bd1eae5e3f3e26eaf009a16e2433eafaf0a4ecdf2","typeString":"literal_string \"{\"root_key\": [{\"a\": 1, \"b\": 2}]}\""},"value":"{\"root_key\": [{\"a\": 1, \"b\": 2}]}"},"nodeType":"VariableDeclarationStatement","src":"3847:55:0"},{"assignments":[318],"declarations":[{"constant":false,"id":318,"mutability":"mutable","name":"keys","nameLocation":"3928:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3912:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":316,"name":"string","nodeType":"ElementaryTypeName","src":"3912:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":317,"nodeType":"ArrayTypeName","src":"3912:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"id":324,"initialValue":{"arguments":[{"id":321,"name":"json","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":311,"src":"3952:4:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"2e726f6f745f6b65795b305d","id":322,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3958:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""},"value":".root_key[0]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""}],"expression":{"id":319,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3935:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":320,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"parseJsonKeys","nodeType":"MemberAccess","referencedDeclaration":27,"src":"3935:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$_t_array$_t_string_memory_ptr_$dyn_memory_ptr_$","typeString":"function (string memory,string memory) pure external returns (string memory[] memory)"}},"id":323,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3935:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"nodeType":"VariableDeclarationStatement","src":"3912:61:0"},{"expression":{"arguments":[{"hexValue":"6b657973","id":328,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3995:6:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},"value":"keys"},{"baseExpression":{"id":329,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4003:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":331,"indexExpression":{"hexValue":"30","id":330,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4008:1:0","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4003:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"baseExpression":{"id":332,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4012:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":334,"indexExpression":{"hexValue":"31","id":333,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4017:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4012:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":325,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3983:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":327,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":219,"src":"3983:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory,string memory) pure"}},"id":335,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3983:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":336,"nodeType":"ExpressionStatement","src":"3983:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c","id":340,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4042:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""},"value":"from original"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""}],"expression":{"id":337,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4031:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":339,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4031:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":341,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4031:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":342,"nodeType":"ExpressionStatement","src":"4031:27:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"30783432","id":350,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4098:4:0","typeDescriptions":{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"},"value":"0x42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"}],"id":349,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4090:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":348,"name":"uint160","nodeType":"ElementaryTypeName","src":"4090:7:0","typeDescriptions":{}}},"id":351,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4090:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":347,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4082:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":346,"name":"address","nodeType":"ElementaryTypeName","src":"4082:7:0","typeDescriptions":{}}},"id":352,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4082:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":343,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4068:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":345,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startPrank","nodeType":"MemberAccess","referencedDeclaration":32,"src":"4068:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":353,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4068:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":354,"nodeType":"ExpressionStatement","src":"4068:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2031","id":358,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4126:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""},"value":"from prank 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""}],"expression":{"id":355,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4115:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":357,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4115:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":359,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4115:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":360,"nodeType":"ExpressionStatement","src":"4115:26:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f7065206d73672e73656e646572","id":364,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4163:25:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},"value":"parent scope msg.sender"},{"arguments":[{"expression":{"id":367,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"4198:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":368,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"4198:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":366,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4190:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":365,"name":"address","nodeType":"ElementaryTypeName","src":"4190:7:0","typeDescriptions":{}}},"id":369,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4190:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":361,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4151:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":363,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4151:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":370,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4151:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":371,"nodeType":"ExpressionStatement","src":"4151:59:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f706520636f6e74726163742e61646472","id":375,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4232:28:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},"value":"parent scope contract.addr"},{"arguments":[{"id":378,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4270:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":377,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4262:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":376,"name":"address","nodeType":"ElementaryTypeName","src":"4262:7:0","typeDescriptions":{}}},"id":379,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4262:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":372,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4220:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":374,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4220:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":380,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4220:56:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":381,"nodeType":"ExpressionStatement","src":"4220:56:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2032","id":385,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4297:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""},"value":"from prank 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""}],"expression":{"id":382,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4286:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":384,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4286:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":386,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4286:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":387,"nodeType":"ExpressionStatement","src":"4286:26:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":388,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4322:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":390,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopPrank","nodeType":"MemberAccess","referencedDeclaration":35,"src":"4322:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":391,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4322:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":392,"nodeType":"ExpressionStatement","src":"4322:14:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c20616761696e","id":396,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4357:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""},"value":"from original again"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""}],"expression":{"id":393,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4346:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":395,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4346:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":397,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4346:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":398,"nodeType":"ExpressionStatement","src":"4346:33:0"},{"assignments":[400],"declarations":[{"constant":false,"id":400,"mutability":"mutable","name":"tmpNonceGetter","nameLocation":"4480:14:0","nodeType":"VariableDeclaration","scope":455,"src":"4472:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":399,"name":"address","nodeType":"ElementaryTypeName","src":"4472:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":413,"initialValue":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"74656d70206e6f6e6365207465737420676574746572","id":408,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4531:24:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""},"value":"temp nonce test getter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""}],"id":407,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"4521:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":409,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4521:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":406,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4513:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":405,"name":"uint256","nodeType":"ElementaryTypeName","src":"4513:7:0","typeDescriptions":{}}},"id":410,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4513:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":404,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4505:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":403,"name":"uint160","nodeType":"ElementaryTypeName","src":"4505:7:0","typeDescriptions":{}}},"id":411,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4505:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":402,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4497:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":401,"name":"address","nodeType":"ElementaryTypeName","src":"4497:7:0","typeDescriptions":{}}},"id":412,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4497:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"4472:87:0"},{"expression":{"arguments":[{"id":417,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4577:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"arguments":[{"hexValue":"5363726970744578616d706c652e732e736f6c3a4e6f6e6365476574746572","id":420,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4612:33:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""},"value":"ScriptExample.s.sol:NonceGetter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""}],"expression":{"id":418,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4593:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":419,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getDeployedCode","nodeType":"MemberAccess","referencedDeclaration":61,"src":"4593:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) view external returns (bytes memory)"}},"id":421,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4593:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"expression":{"id":414,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4569:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":416,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"etch","nodeType":"MemberAccess","referencedDeclaration":68,"src":"4569:7:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$_t_bytes_memory_ptr_$returns$__$","typeString":"function (address,bytes memory) external"}},"id":422,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4569:78:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":423,"nodeType":"ExpressionStatement","src":"4569:78:0"},{"expression":{"arguments":[{"id":427,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4676:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":424,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4657:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":426,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"allowCheatcodes","nodeType":"MemberAccess","referencedDeclaration":73,"src":"4657:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":428,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4657:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":429,"nodeType":"ExpressionStatement","src":"4657:34:0"},{"assignments":[431],"declarations":[{"constant":false,"id":431,"mutability":"mutable","name":"v","nameLocation":"4709:1:0","nodeType":"VariableDeclaration","scope":455,"src":"4701:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":430,"name":"uint256","nodeType":"ElementaryTypeName","src":"4701:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":441,"initialValue":{"arguments":[{"arguments":[{"id":438,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4758:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":437,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4750:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":436,"name":"address","nodeType":"ElementaryTypeName","src":"4750:7:0","typeDescriptions":{}}},"id":439,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4750:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"arguments":[{"id":433,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4725:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":432,"name":"NonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":833,"src":"4713:11:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_NonceGetter_$833_$","typeString":"type(contract NonceGetter)"}},"id":434,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_NonceGetter_$833","typeString":"contract NonceGetter"}},"id":435,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":832,"src":"4713:36:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint256_$","typeString":"function (address) view external returns (uint256)"}},"id":440,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"4701:63:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e63652066726f6d206e6f6e6365206765747465722c206e6f206578706c6963697420616363657373207265717569726564207769746820766d2e657463683a","id":445,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4786:68:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},"value":"nonce from nonce getter, no explicit access required with vm.etch:"},{"id":446,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":431,"src":"4856:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":442,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4774:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":444,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"4774:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":447,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4774:84:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":448,"nodeType":"ExpressionStatement","src":"4774:84:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":452,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4881:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":449,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4869:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":451,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"4869:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":453,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4869:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":454,"nodeType":"ExpressionStatement","src":"4869:20:0"}]},"documentation":{"id":244,"nodeType":"StructuredDocumentation","src":"3385:78:0","text":"@notice example function, runs through basic cheat-codes and console logs."},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"3477:3:0","parameters":{"id":245,"nodeType":"ParameterList","parameters":[],"src":"3480:2:0"},"returnParameters":{"id":246,"nodeType":"ParameterList","parameters":[],"src":"3490:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":689,"nodeType":"FunctionDefinition","src":"4963:1333:0","nodes":[],"body":{"id":688,"nodeType":"Block","src":"4994:1302:0","nodes":[],"statements":[{"expression":{"arguments":[{"hexValue":"6e6f6e6365207374617274","id":463,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5016:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},"value":"nonce start"},{"arguments":[{"arguments":[{"arguments":[{"id":470,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5059:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":469,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5051:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":468,"name":"address","nodeType":"ElementaryTypeName","src":"5051:7:0","typeDescriptions":{}}},"id":471,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5051:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":466,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5039:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":467,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"5039:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":472,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5039:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":465,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5031:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":464,"name":"uint256","nodeType":"ElementaryTypeName","src":"5031:7:0","typeDescriptions":{}}},"id":473,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5031:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":460,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5004:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":462,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"5004:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":474,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5004:63:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":475,"nodeType":"ExpressionStatement","src":"5004:63:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073696e676c65","id":479,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5090:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""},"value":"testing single"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""}],"expression":{"id":476,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5078:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":478,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5078:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":480,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5078:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":481,"nodeType":"ExpressionStatement","src":"5078:29:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":482,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5117:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":484,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"5117:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":485,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5117:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":486,"nodeType":"ExpressionStatement","src":"5117:14:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c31","id":490,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5152:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""},"value":"single_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""}],"expression":{"id":487,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5141:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":489,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5141:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":491,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5141:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":492,"nodeType":"ExpressionStatement","src":"5141:26:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c32","id":496,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5188:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""},"value":"single_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""}],"expression":{"id":493,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5177:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":495,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5177:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":497,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5177:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":498,"nodeType":"ExpressionStatement","src":"5177:26:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073746172742f73746f70","id":502,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5226:20:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""},"value":"testing start/stop"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""}],"expression":{"id":499,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5214:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":501,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5214:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":503,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5214:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":504,"nodeType":"ExpressionStatement","src":"5214:33:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078633066666565","id":512,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5291:8:0","typeDescriptions":{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"},"value":"0xc0ffee"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"}],"id":511,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5283:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":510,"name":"uint160","nodeType":"ElementaryTypeName","src":"5283:7:0","typeDescriptions":{}}},"id":513,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5283:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":509,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5275:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":508,"name":"address","nodeType":"ElementaryTypeName","src":"5275:7:0","typeDescriptions":{}}},"id":514,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5275:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":505,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5257:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":507,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5257:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":515,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5257:45:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":516,"nodeType":"ExpressionStatement","src":"5257:45:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c31","id":520,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5323:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""},"value":"startstop_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""}],"expression":{"id":517,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5312:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":519,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5312:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":521,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5312:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":522,"nodeType":"ExpressionStatement","src":"5312:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c32","id":526,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5362:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""},"value":"startstop_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""}],"expression":{"id":523,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5351:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":525,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5351:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":527,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5351:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":528,"nodeType":"ExpressionStatement","src":"5351:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f70757265","id":532,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5404:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""},"value":"startstop_pure"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""}],"expression":{"id":529,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5390:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":531,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"callPure","nodeType":"MemberAccess","referencedDeclaration":785,"src":"5390:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure external"}},"id":533,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5390:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":534,"nodeType":"ExpressionStatement","src":"5390:31:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":535,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5431:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":537,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5431:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":538,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5431:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":539,"nodeType":"ExpressionStatement","src":"5431:18:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c33","id":543,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5470:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""},"value":"startstop_call3"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""}],"expression":{"id":540,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5459:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":542,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5459:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":544,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5459:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":545,"nodeType":"ExpressionStatement","src":"5459:29:0"},{"expression":{"arguments":[{"hexValue":"74657374696e67206e6573746564","id":549,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5511:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""},"value":"testing nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""}],"expression":{"id":546,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5499:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":548,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5499:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":550,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5499:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":551,"nodeType":"ExpressionStatement","src":"5499:29:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307831323334","id":559,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5572:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":558,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5564:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":557,"name":"uint160","nodeType":"ElementaryTypeName","src":"5564:7:0","typeDescriptions":{}}},"id":560,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5564:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":556,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5556:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":555,"name":"address","nodeType":"ElementaryTypeName","src":"5556:7:0","typeDescriptions":{}}},"id":561,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5556:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":552,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5538:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":554,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5538:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":562,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5538:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":563,"nodeType":"ExpressionStatement","src":"5538:43:0"},{"expression":{"arguments":[{"hexValue":"6e6573746564","id":567,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5604:8:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""},"value":"nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""}],"expression":{"id":564,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5591:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":566,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested1","nodeType":"MemberAccess","referencedDeclaration":758,"src":"5591:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":568,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5591:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":569,"nodeType":"ExpressionStatement","src":"5591:22:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":570,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5623:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":572,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5623:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":573,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5623:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":574,"nodeType":"ExpressionStatement","src":"5623:18:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206465706c6f796d656e74","id":578,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5664:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""},"value":"contract deployment"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""}],"expression":{"id":575,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5652:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":577,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5652:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":579,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5652:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":580,"nodeType":"ExpressionStatement","src":"5652:34:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078313233343536","id":588,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5725:8:0","typeDescriptions":{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"},"value":"0x123456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"}],"id":587,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5717:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":586,"name":"uint160","nodeType":"ElementaryTypeName","src":"5717:7:0","typeDescriptions":{}}},"id":589,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5717:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":585,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5709:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":584,"name":"address","nodeType":"ElementaryTypeName","src":"5709:7:0","typeDescriptions":{}}},"id":590,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5709:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":581,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5696:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":583,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5696:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":591,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5696:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":592,"nodeType":"ExpressionStatement","src":"5696:40:0"},{"assignments":[595],"declarations":[{"constant":false,"id":595,"mutability":"mutable","name":"x","nameLocation":"5753:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5746:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":594,"nodeType":"UserDefinedTypeName","pathNode":{"id":593,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5746:6:0"},"referencedDeclaration":799,"src":"5746:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":601,"initialValue":{"arguments":[{"hexValue":"31323334","id":599,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5768:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":598,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5757:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":597,"nodeType":"UserDefinedTypeName","pathNode":{"id":596,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5761:6:0"},"referencedDeclaration":799,"src":"5761:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":600,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5757:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5746:27:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":607,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":603,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":595,"src":"5791:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":604,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"5791:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":605,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5791:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":606,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5802:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"5791:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e20637265617465206973206e6f742031323334","id":608,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5808:35:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""},"value":"FooBar: foo in create is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""}],"id":602,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"5783:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":609,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5783:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":610,"nodeType":"ExpressionStatement","src":"5783:61:0"},{"expression":{"arguments":[{"hexValue":"6372656174652032","id":614,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5867:10:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""},"value":"create 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""}],"expression":{"id":611,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5855:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":613,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5855:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":615,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5855:23:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":616,"nodeType":"ExpressionStatement","src":"5855:23:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307863616665","id":624,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5917:6:0","typeDescriptions":{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"},"value":"0xcafe"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"}],"id":623,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5909:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":622,"name":"uint160","nodeType":"ElementaryTypeName","src":"5909:7:0","typeDescriptions":{}}},"id":625,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5909:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":621,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5901:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":620,"name":"address","nodeType":"ElementaryTypeName","src":"5901:7:0","typeDescriptions":{}}},"id":626,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5901:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":617,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5888:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":619,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5888:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":627,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5888:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":628,"nodeType":"ExpressionStatement","src":"5888:38:0"},{"assignments":[631],"declarations":[{"constant":false,"id":631,"mutability":"mutable","name":"y","nameLocation":"5943:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5936:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":630,"nodeType":"UserDefinedTypeName","pathNode":{"id":629,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5936:6:0"},"referencedDeclaration":799,"src":"5936:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":645,"initialValue":{"arguments":[{"hexValue":"31323334","id":643,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5986:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":634,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5947:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":633,"nodeType":"UserDefinedTypeName","pathNode":{"id":632,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5951:6:0"},"referencedDeclaration":799,"src":"5951:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":642,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"names":["salt"],"nodeType":"FunctionCallOptions","options":[{"arguments":[{"arguments":[{"hexValue":"3432","id":639,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5980:2:0","typeDescriptions":{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"},"value":"42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"}],"id":638,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5972:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":637,"name":"uint256","nodeType":"ElementaryTypeName","src":"5972:7:0","typeDescriptions":{}}},"id":640,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5972:11:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":636,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5964:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":635,"name":"bytes32","nodeType":"ElementaryTypeName","src":"5964:7:0","typeDescriptions":{}}},"id":641,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5964:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"src":"5947:38:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$salt","typeString":"function (uint256) returns (contract FooBar)"}},"id":644,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5947:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5936:55:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":651,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":647,"name":"y","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":631,"src":"6009:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":648,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"6009:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":649,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6009:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":650,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6020:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"6009:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e2063726561746532206973206e6f742031323334","id":652,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6026:36:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""},"value":"FooBar: foo in create2 is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""}],"id":646,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"6001:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":653,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6001:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":654,"nodeType":"ExpressionStatement","src":"6001:62:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":658,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6085:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":655,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6073:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":657,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6073:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":659,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6073:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":660,"nodeType":"ExpressionStatement","src":"6073:20:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":661,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6177:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":663,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"6177:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":664,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6177:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":665,"nodeType":"ExpressionStatement","src":"6177:14:0"},{"expression":{"arguments":[{"hexValue":"31323334","id":669,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6212:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":668,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"6201:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":667,"nodeType":"UserDefinedTypeName","pathNode":{"id":666,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"6205:6:0"},"referencedDeclaration":799,"src":"6205:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":670,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6201:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":671,"nodeType":"ExpressionStatement","src":"6201:16:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e636520656e64","id":675,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6240:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},"value":"nonce end"},{"arguments":[{"arguments":[{"arguments":[{"id":682,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6281:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":681,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6273:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":680,"name":"address","nodeType":"ElementaryTypeName","src":"6273:7:0","typeDescriptions":{}}},"id":683,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6273:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":678,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6261:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":679,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"6261:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":684,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6261:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":677,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6253:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":676,"name":"uint256","nodeType":"ElementaryTypeName","src":"6253:7:0","typeDescriptions":{}}},"id":685,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6253:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":672,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6228:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":674,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"6228:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":686,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6228:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":687,"nodeType":"ExpressionStatement","src":"6228:61:0"}]},"documentation":{"id":457,"nodeType":"StructuredDocumentation","src":"4902:56:0","text":"@notice example function, to test vm.broadcast with."},"functionSelector":"bef03abc","implemented":true,"kind":"function","modifiers":[],"name":"runBroadcast","nameLocation":"4972:12:0","parameters":{"id":458,"nodeType":"ParameterList","parameters":[],"src":"4984:2:0"},"returnParameters":{"id":459,"nodeType":"ParameterList","parameters":[],"src":"4994:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":713,"nodeType":"FunctionDefinition","src":"6391:143:0","nodes":[],"body":{"id":712,"nodeType":"Block","src":"6440:94:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":698,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":692,"src":"6462:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":695,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6450:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":697,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6450:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":699,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6450:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":700,"nodeType":"ExpressionStatement","src":"6450:15:0"},{"expression":{"arguments":[{"hexValue":"68656c6c6f206d73672e73656e646572","id":704,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6487:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},"value":"hello msg.sender"},{"arguments":[{"expression":{"id":707,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"6515:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":708,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"6515:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":706,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6507:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":705,"name":"address","nodeType":"ElementaryTypeName","src":"6507:7:0","typeDescriptions":{}}},"id":709,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6507:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":701,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6475:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":703,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"6475:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":710,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6475:52:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":711,"nodeType":"ExpressionStatement","src":"6475:52:0"}]},"documentation":{"id":690,"nodeType":"StructuredDocumentation","src":"6302:84:0","text":"@notice example external function, to force a CALL, and test vm.startPrank with."},"functionSelector":"a777d0dc","implemented":true,"kind":"function","modifiers":[],"name":"hello","nameLocation":"6400:5:0","parameters":{"id":693,"nodeType":"ParameterList","parameters":[{"constant":false,"id":692,"mutability":"mutable","name":"_v","nameLocation":"6422:2:0","nodeType":"VariableDeclaration","scope":713,"src":"6406:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":691,"name":"string","nodeType":"ElementaryTypeName","src":"6406:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6405:20:0"},"returnParameters":{"id":694,"nodeType":"ParameterList","parameters":[],"src":"6440:0:0"},"scope":786,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":728,"nodeType":"FunctionDefinition","src":"6540:95:0","nodes":[],"body":{"id":727,"nodeType":"Block","src":"6584:51:0","nodes":[],"statements":[{"expression":{"id":719,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6594:9:0","subExpression":{"id":718,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6594:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":720,"nodeType":"ExpressionStatement","src":"6594:9:0"},{"expression":{"arguments":[{"id":724,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":715,"src":"6625:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":721,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6613:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":723,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6613:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":725,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6613:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":726,"nodeType":"ExpressionStatement","src":"6613:15:0"}]},"functionSelector":"7e79255d","implemented":true,"kind":"function","modifiers":[],"name":"call1","nameLocation":"6549:5:0","parameters":{"id":716,"nodeType":"ParameterList","parameters":[{"constant":false,"id":715,"mutability":"mutable","name":"_v","nameLocation":"6571:2:0","nodeType":"VariableDeclaration","scope":728,"src":"6555:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":714,"name":"string","nodeType":"ElementaryTypeName","src":"6555:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6554:20:0"},"returnParameters":{"id":717,"nodeType":"ParameterList","parameters":[],"src":"6584:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":743,"nodeType":"FunctionDefinition","src":"6641:95:0","nodes":[],"body":{"id":742,"nodeType":"Block","src":"6685:51:0","nodes":[],"statements":[{"expression":{"id":734,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6695:9:0","subExpression":{"id":733,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6695:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":735,"nodeType":"ExpressionStatement","src":"6695:9:0"},{"expression":{"arguments":[{"id":739,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":730,"src":"6726:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":736,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6714:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":738,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6714:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":740,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6714:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":741,"nodeType":"ExpressionStatement","src":"6714:15:0"}]},"functionSelector":"8d3ef7ca","implemented":true,"kind":"function","modifiers":[],"name":"call2","nameLocation":"6650:5:0","parameters":{"id":731,"nodeType":"ParameterList","parameters":[{"constant":false,"id":730,"mutability":"mutable","name":"_v","nameLocation":"6672:2:0","nodeType":"VariableDeclaration","scope":743,"src":"6656:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":729,"name":"string","nodeType":"ElementaryTypeName","src":"6656:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6655:20:0"},"returnParameters":{"id":732,"nodeType":"ParameterList","parameters":[],"src":"6685:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":758,"nodeType":"FunctionDefinition","src":"6742:98:0","nodes":[],"body":{"id":757,"nodeType":"Block","src":"6788:52:0","nodes":[],"statements":[{"expression":{"id":749,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6798:9:0","subExpression":{"id":748,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6798:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":750,"nodeType":"ExpressionStatement","src":"6798:9:0"},{"expression":{"arguments":[{"id":754,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":745,"src":"6830:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":751,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6817:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":753,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested2","nodeType":"MemberAccess","referencedDeclaration":773,"src":"6817:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":755,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6817:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":756,"nodeType":"ExpressionStatement","src":"6817:16:0"}]},"functionSelector":"a76ccdfa","implemented":true,"kind":"function","modifiers":[],"name":"nested1","nameLocation":"6751:7:0","parameters":{"id":746,"nodeType":"ParameterList","parameters":[{"constant":false,"id":745,"mutability":"mutable","name":"_v","nameLocation":"6775:2:0","nodeType":"VariableDeclaration","scope":758,"src":"6759:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":744,"name":"string","nodeType":"ElementaryTypeName","src":"6759:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6758:20:0"},"returnParameters":{"id":747,"nodeType":"ParameterList","parameters":[],"src":"6788:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":773,"nodeType":"FunctionDefinition","src":"6846:97:0","nodes":[],"body":{"id":772,"nodeType":"Block","src":"6892:51:0","nodes":[],"statements":[{"expression":{"id":764,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6902:9:0","subExpression":{"id":763,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6902:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":765,"nodeType":"ExpressionStatement","src":"6902:9:0"},{"expression":{"arguments":[{"id":769,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":760,"src":"6933:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":766,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6921:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":768,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6921:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":770,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6921:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":771,"nodeType":"ExpressionStatement","src":"6921:15:0"}]},"functionSelector":"dbf1282f","implemented":true,"kind":"function","modifiers":[],"name":"nested2","nameLocation":"6855:7:0","parameters":{"id":761,"nodeType":"ParameterList","parameters":[{"constant":false,"id":760,"mutability":"mutable","name":"_v","nameLocation":"6879:2:0","nodeType":"VariableDeclaration","scope":773,"src":"6863:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":759,"name":"string","nodeType":"ElementaryTypeName","src":"6863:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6862:20:0"},"returnParameters":{"id":762,"nodeType":"ParameterList","parameters":[],"src":"6892:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":785,"nodeType":"FunctionDefinition","src":"6949:84:0","nodes":[],"body":{"id":784,"nodeType":"Block","src":"7001:32:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":781,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":775,"src":"7023:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":778,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"7011:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":780,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"7011:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":782,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7011:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":783,"nodeType":"ExpressionStatement","src":"7011:15:0"}]},"functionSelector":"7f8b915c","implemented":true,"kind":"function","modifiers":[],"name":"callPure","nameLocation":"6958:8:0","parameters":{"id":776,"nodeType":"ParameterList","parameters":[{"constant":false,"id":775,"mutability":"mutable","name":"_v","nameLocation":"6983:2:0","nodeType":"VariableDeclaration","scope":785,"src":"6967:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":774,"name":"string","nodeType":"ElementaryTypeName","src":"6967:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6966:20:0"},"returnParameters":{"id":777,"nodeType":"ParameterList","parameters":[],"src":"7001:0:0"},"scope":786,"stateMutability":"pure","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ScriptExample","contractDependencies":[799],"contractKind":"contract","documentation":{"id":221,"nodeType":"StructuredDocumentation","src":"2997:126:0","text":"@title ScriptExample\n @notice ScriptExample is an example script. The Go forge script code tests that it can run this."},"fullyImplemented":true,"linearizedBaseContracts":[786],"name":"ScriptExample","nameLocation":"3132:13:0","scope":969,"usedErrors":[]},{"id":799,"nodeType":"ContractDefinition","src":"7037:96:0","nodes":[{"id":788,"nodeType":"VariableDeclaration","src":"7059:18:0","nodes":[],"constant":false,"functionSelector":"c2985578","mutability":"mutable","name":"foo","nameLocation":"7074:3:0","scope":799,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":787,"name":"uint256","nodeType":"ElementaryTypeName","src":"7059:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":798,"nodeType":"FunctionDefinition","src":"7084:47:0","nodes":[],"body":{"id":797,"nodeType":"Block","src":"7107:24:0","nodes":[],"statements":[{"expression":{"id":795,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":793,"name":"foo","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":788,"src":"7117:3:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":794,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":790,"src":"7123:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"7117:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":796,"nodeType":"ExpressionStatement","src":"7117:7:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":791,"nodeType":"ParameterList","parameters":[{"constant":false,"id":790,"mutability":"mutable","name":"v","nameLocation":"7104:1:0","nodeType":"VariableDeclaration","scope":798,"src":"7096:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":789,"name":"uint256","nodeType":"ElementaryTypeName","src":"7096:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7095:11:0"},"returnParameters":{"id":792,"nodeType":"ParameterList","parameters":[],"src":"7107:0:0"},"scope":799,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"FooBar","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[799],"name":"FooBar","nameLocation":"7046:6:0","scope":969,"usedErrors":[]},{"id":833,"nodeType":"ContractDefinition","src":"7135:281:0","nodes":[{"id":813,"nodeType":"VariableDeclaration","src":"7162:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7188:10:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":800,"name":"address","nodeType":"ElementaryTypeName","src":"7162:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":808,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7235:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":807,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7225:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":809,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7225:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":806,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7217:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":805,"name":"uint256","nodeType":"ElementaryTypeName","src":"7217:7:0","typeDescriptions":{}}},"id":810,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7217:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":804,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7209:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":803,"name":"uint160","nodeType":"ElementaryTypeName","src":"7209:7:0","typeDescriptions":{}}},"id":811,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7209:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":802,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":801,"name":"address","nodeType":"ElementaryTypeName","src":"7201:7:0","typeDescriptions":{}}},"id":812,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7201:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":819,"nodeType":"VariableDeclaration","src":"7262:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7283:2:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":815,"nodeType":"UserDefinedTypeName","pathNode":{"id":814,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7262:2:0"},"referencedDeclaration":83,"src":"7262:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":817,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":813,"src":"7291:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":816,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7288:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":818,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7288:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":832,"nodeType":"FunctionDefinition","src":"7309:105:0","nodes":[],"body":{"id":831,"nodeType":"Block","src":"7372:42:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":828,"name":"_addr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":821,"src":"7401:5:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":826,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":819,"src":"7389:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":827,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7389:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":829,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7389:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"functionReturnParameters":825,"id":830,"nodeType":"Return","src":"7382:25:0"}]},"functionSelector":"2d0335ab","implemented":true,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"7318:8:0","parameters":{"id":822,"nodeType":"ParameterList","parameters":[{"constant":false,"id":821,"mutability":"mutable","name":"_addr","nameLocation":"7335:5:0","nodeType":"VariableDeclaration","scope":832,"src":"7327:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":820,"name":"address","nodeType":"ElementaryTypeName","src":"7327:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"7326:15:0"},"returnParameters":{"id":825,"nodeType":"ParameterList","parameters":[{"constant":false,"id":824,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":832,"src":"7363:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":823,"name":"uint256","nodeType":"ElementaryTypeName","src":"7363:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7362:9:0"},"scope":833,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"NonceGetter","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[833],"name":"NonceGetter","nameLocation":"7144:11:0","scope":969,"usedErrors":[]},{"id":852,"nodeType":"ContractDefinition","src":"7418:174:0","nodes":[{"id":835,"nodeType":"VariableDeclaration","src":"7448:18:0","nodes":[],"constant":false,"mutability":"mutable","name":"v","nameLocation":"7465:1:0","scope":852,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":834,"name":"uint256","nodeType":"ElementaryTypeName","src":"7448:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"id":843,"nodeType":"FunctionDefinition","src":"7473:36:0","nodes":[],"body":{"id":842,"nodeType":"Block","src":"7487:22:0","nodes":[],"statements":[{"expression":{"id":840,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":838,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7497:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"hexValue":"31","id":839,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7501:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"7497:5:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":841,"nodeType":"ExpressionStatement","src":"7497:5:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":836,"nodeType":"ParameterList","parameters":[],"src":"7484:2:0"},"returnParameters":{"id":837,"nodeType":"ParameterList","parameters":[],"src":"7487:0:0"},"scope":852,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":851,"nodeType":"FunctionDefinition","src":"7515:75:0","nodes":[],"body":{"id":850,"nodeType":"Block","src":"7565:25:0","nodes":[],"statements":[{"expression":{"id":848,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7582:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"functionReturnParameters":847,"id":849,"nodeType":"Return","src":"7575:8:0"}]},"functionSelector":"20965255","implemented":true,"kind":"function","modifiers":[],"name":"getValue","nameLocation":"7524:8:0","parameters":{"id":844,"nodeType":"ParameterList","parameters":[],"src":"7532:2:0"},"returnParameters":{"id":847,"nodeType":"ParameterList","parameters":[{"constant":false,"id":846,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":851,"src":"7556:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":845,"name":"uint256","nodeType":"ElementaryTypeName","src":"7556:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7555:9:0"},"scope":852,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkedContract","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[852],"name":"ForkedContract","nameLocation":"7427:14:0","scope":969,"usedErrors":[]},{"id":968,"nodeType":"ContractDefinition","src":"7594:813:0","nodes":[{"id":866,"nodeType":"VariableDeclaration","src":"7620:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7646:10:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":853,"name":"address","nodeType":"ElementaryTypeName","src":"7620:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":861,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7693:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":860,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7683:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":862,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7683:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":859,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7675:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":858,"name":"uint256","nodeType":"ElementaryTypeName","src":"7675:7:0","typeDescriptions":{}}},"id":863,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7675:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":857,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7667:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":856,"name":"uint160","nodeType":"ElementaryTypeName","src":"7667:7:0","typeDescriptions":{}}},"id":864,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7667:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":855,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7659:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":854,"name":"address","nodeType":"ElementaryTypeName","src":"7659:7:0","typeDescriptions":{}}},"id":865,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7659:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":872,"nodeType":"VariableDeclaration","src":"7720:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7741:2:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":868,"nodeType":"UserDefinedTypeName","pathNode":{"id":867,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7720:2:0"},"referencedDeclaration":83,"src":"7720:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":870,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":866,"src":"7749:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":869,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7746:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":871,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7746:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":967,"nodeType":"FunctionDefinition","src":"7767:638:0","nodes":[],"body":{"id":966,"nodeType":"Block","src":"7791:614:0","nodes":[],"statements":[{"assignments":[876],"declarations":[{"constant":false,"id":876,"mutability":"mutable","name":"testAddr","nameLocation":"7809:8:0","nodeType":"VariableDeclaration","scope":966,"src":"7801:16:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":875,"name":"address","nodeType":"ElementaryTypeName","src":"7801:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":884,"initialValue":{"arguments":[{"arguments":[{"hexValue":"307831323334","id":881,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7836:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":880,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7828:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":879,"name":"uint160","nodeType":"ElementaryTypeName","src":"7828:7:0","typeDescriptions":{}}},"id":882,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7828:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":878,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7820:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":877,"name":"address","nodeType":"ElementaryTypeName","src":"7820:7:0","typeDescriptions":{}}},"id":883,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7820:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"7801:43:0"},{"assignments":[887],"declarations":[{"constant":false,"id":887,"mutability":"mutable","name":"fc","nameLocation":"7869:2:0","nodeType":"VariableDeclaration","scope":966,"src":"7854:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"},"typeName":{"id":886,"nodeType":"UserDefinedTypeName","pathNode":{"id":885,"name":"ForkedContract","nodeType":"IdentifierPath","referencedDeclaration":852,"src":"7854:14:0"},"referencedDeclaration":852,"src":"7854:14:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"visibility":"internal"}],"id":891,"initialValue":{"arguments":[{"id":889,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7889:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":888,"name":"ForkedContract","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":852,"src":"7874:14:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_ForkedContract_$852_$","typeString":"type(contract ForkedContract)"}},"id":890,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7874:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"nodeType":"VariableDeclarationStatement","src":"7854:44:0"},{"expression":{"arguments":[{"hexValue":"666f726b31","id":895,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7929:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},"value":"fork1"},{"hexValue":"3132333435","id":896,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7938:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"}],"expression":{"id":892,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7909:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":894,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"7909:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":897,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7909:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":898,"nodeType":"ExpressionStatement","src":"7909:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":905,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":902,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7974:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":900,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7962:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":901,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7962:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":903,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7962:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3132333435","id":904,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7987:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"},"src":"7962:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":906,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7994:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":899,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"7954:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":907,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7954:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":908,"nodeType":"ExpressionStatement","src":"7954:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":914,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":910,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8036:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":911,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8036:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":912,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8036:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31","id":913,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8053:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"8036:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652031","id":915,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8056:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""},"value":"value should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""}],"id":909,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8028:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":916,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8028:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":917,"nodeType":"ExpressionStatement","src":"8028:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":925,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":919,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8094:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":920,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8094:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"31","id":923,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8122:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"}],"id":922,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8114:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":921,"name":"uint256","nodeType":"ElementaryTypeName","src":"8114:7:0","typeDescriptions":{}}},"id":924,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8114:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8094:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652031","id":926,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8126:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""},"value":"balance should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""}],"id":918,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8086:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":927,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8086:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":928,"nodeType":"ExpressionStatement","src":"8086:62:0"},{"expression":{"arguments":[{"hexValue":"666f726b32","id":932,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8179:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},"value":"fork2"},{"hexValue":"3233343536","id":933,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8188:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"}],"expression":{"id":929,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8159:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":931,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"8159:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":934,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8159:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":935,"nodeType":"ExpressionStatement","src":"8159:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":942,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":939,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8224:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":937,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8212:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":938,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"8212:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":940,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8212:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3233343536","id":941,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8237:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"},"src":"8212:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":943,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8244:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":936,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8204:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":944,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8204:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":945,"nodeType":"ExpressionStatement","src":"8204:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":951,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":947,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8286:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":948,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8286:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":949,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8286:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"32","id":950,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8303:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"},"src":"8286:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652032","id":952,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8306:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""},"value":"value should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""}],"id":946,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8278:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":953,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8278:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":954,"nodeType":"ExpressionStatement","src":"8278:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":962,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":956,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8344:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":957,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8344:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"32","id":960,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8372:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"}],"id":959,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8364:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":958,"name":"uint256","nodeType":"ElementaryTypeName","src":"8364:7:0","typeDescriptions":{}}},"id":961,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8364:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8344:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652032","id":963,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8376:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""},"value":"balance should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""}],"id":955,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8336:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":964,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8336:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":965,"nodeType":"ExpressionStatement","src":"8336:62:0"}]},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"7776:3:0","parameters":{"id":873,"nodeType":"ParameterList","parameters":[],"src":"7779:2:0"},"returnParameters":{"id":874,"nodeType":"ParameterList","parameters":[],"src":"7791:0:0"},"scope":968,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkTester","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[968],"name":"ForkTester","nameLocation":"7603:10:0","scope":969,"usedErrors":[]}],"license":"MIT"},"id":0} \ No newline at end of file diff --git a/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/ScriptExample.json b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/ScriptExample.json index 09a0bf47f02db..0fd610c4725cf 100644 --- a/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/ScriptExample.json +++ b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/ScriptExample.json @@ -1 +1 @@ -{"abi":[{"type":"function","name":"call1","inputs":[{"name":"_v","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"call2","inputs":[{"name":"_v","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"callPure","inputs":[{"name":"_v","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"pure"},{"type":"function","name":"counter","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"hello","inputs":[{"name":"_v","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"view"},{"type":"function","name":"nested1","inputs":[{"name":"_v","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"nested2","inputs":[{"name":"_v","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"run","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"runBroadcast","inputs":[],"outputs":[],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x608060405234801561001057600080fd5b5061202a806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c8063a76ccdfa11610076578063bef03abc1161005b578063bef03abc14610111578063c040622614610119578063dbf1282f146100c357600080fd5b8063a76ccdfa146100eb578063a777d0dc146100fe57600080fd5b806361bc221a146100a85780637e79255d146100c35780637f8b915c146100d85780638d3ef7ca146100c3575b600080fd5b6100b160005481565b60405190815260200160405180910390f35b6100d66100d1366004611a60565b610121565b005b6100d66100e6366004611a60565b610178565b6100d66100f9366004611a60565b6101b7565b6100d661010c366004611a60565b61023f565b6100d66102bd565b6100d6610f54565b60008054908061013083611ad2565b919050555061017482828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061175b92505050565b5050565b61017482828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061175b92505050565b6000805490806101c683611ad2565b90915550506040517fdbf1282f000000000000000000000000000000000000000000000000000000008152309063dbf1282f906102099085908590600401611b31565b600060405180830381600087803b15801561022357600080fd5b505af1158015610237573d6000803e3d6000fd5b505050505050565b61027e82828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061175b92505050565b6101746040518060400160405280601081526020017f68656c6c6f206d73672e73656e64657200000000000000000000000000000000815250336117ed565b604080518082018252600b81527f6e6f6e6365207374617274000000000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523060048201526103909190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab906024015b602060405180830381865afa15801561035d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103819190611b7e565b67ffffffffffffffff1661187e565b6103ce6040518060400160405280600e81526020017f74657374696e672073696e676c6500000000000000000000000000000000000081525061175b565b7f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff1663afc980406040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561043957600080fd5b505af115801561044d573d6000803e3d6000fd5b50506040517f7e79255d00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f73696e676c655f63616c6c3100000000000000000000000000000000000000006044820152309250637e79255d9150606401600060405180830381600087803b1580156104d057600080fd5b505af11580156104e4573d6000803e3d6000fd5b50506040517f8d3ef7ca00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f73696e676c655f63616c6c3200000000000000000000000000000000000000006044820152309250638d3ef7ca9150606401600060405180830381600087803b15801561056757600080fd5b505af115801561057b573d6000803e3d6000fd5b505050506105bd6040518060400160405280601281526020017f74657374696e672073746172742f73746f70000000000000000000000000000081525061175b565b6040517f7fec2a8d00000000000000000000000000000000000000000000000000000000815262c0ffee6004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90637fec2a8d90602401600060405180830381600087803b15801561062557600080fd5b505af1158015610639573d6000803e3d6000fd5b50506040517f7e79255d00000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f737461727473746f705f63616c6c3100000000000000000000000000000000006044820152309250637e79255d9150606401600060405180830381600087803b1580156106bc57600080fd5b505af11580156106d0573d6000803e3d6000fd5b50506040517f8d3ef7ca00000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f737461727473746f705f63616c6c3200000000000000000000000000000000006044820152309250638d3ef7ca9150606401600060405180830381600087803b15801561075357600080fd5b505af1158015610767573d6000803e3d6000fd5b50506040517f7f8b915c00000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f737461727473746f705f707572650000000000000000000000000000000000006044820152309250637f8b915c915060640160006040518083038186803b1580156107e857600080fd5b505afa1580156107fc573d6000803e3d6000fd5b505050507f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff166376eadd366040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561086b57600080fd5b505af115801561087f573d6000803e3d6000fd5b50506040517f7e79255d00000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f737461727473746f705f63616c6c3300000000000000000000000000000000006044820152309250637e79255d9150606401600060405180830381600087803b15801561090257600080fd5b505af1158015610916573d6000803e3d6000fd5b505050506109586040518060400160405280600e81526020017f74657374696e67206e657374656400000000000000000000000000000000000081525061175b565b6040517f7fec2a8d0000000000000000000000000000000000000000000000000000000081526112346004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90637fec2a8d90602401600060405180830381600087803b1580156109bf57600080fd5b505af11580156109d3573d6000803e3d6000fd5b50506040517fa76ccdfa00000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f6e65737465640000000000000000000000000000000000000000000000000000604482015230925063a76ccdfa9150606401600060405180830381600087803b158015610a5657600080fd5b505af1158015610a6a573d6000803e3d6000fd5b505050507f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff166376eadd366040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610ad957600080fd5b505af1158015610aed573d6000803e3d6000fd5b50505050610b2f6040518060400160405280601381526020017f636f6e7472616374206465706c6f796d656e740000000000000000000000000081525061175b565b6040517fe6962cdb000000000000000000000000000000000000000000000000000000008152621234566004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d9063e6962cdb90602401600060405180830381600087803b158015610b9757600080fd5b505af1158015610bab573d6000803e3d6000fd5b5050505060006104d2604051610bc090611a54565b908152602001604051809103906000f080158015610be2573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c29855786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c549190611baf565b6104d214610c6157600080fd5b610c9f6040518060400160405280600881526020017f637265617465203200000000000000000000000000000000000000000000000081525061175b565b6040517fe6962cdb00000000000000000000000000000000000000000000000000000000815261cafe6004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d9063e6962cdb90602401600060405180830381600087803b158015610d0657600080fd5b505af1158015610d1a573d6000803e3d6000fd5b505050506000602a60001b6104d2604051610d3490611a54565b9081526020018190604051809103906000f5905080158015610d5a573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c29855786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcc9190611baf565b6104d214610dd957600080fd5b610e176040518060400160405280600581526020017f646f6e652100000000000000000000000000000000000000000000000000000081525061175b565b7f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff1663afc980406040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610e8257600080fd5b505af1158015610e96573d6000803e3d6000fd5b505050506104d2604051610ea990611a54565b908152602001604051809103906000f080158015610ecb573d6000803e3d6000fd5b5050604080518082018252600981527f6e6f6e636520656e640000000000000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523060048201526101749190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401610340565b604080517f4777f3cf0000000000000000000000000000000000000000000000000000000081526004810191909152600c60448201527f4558414d504c455f424f4f4c0000000000000000000000000000000000000000606482015260006024820181905290737109709ecfa91a80626ff3989d68f67f5b1dd12d90634777f3cf90608401602060405180830381865afa158015610ff6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101a9190611bc8565b905061105b6040518060400160405280601381526020017f626f6f6c2076616c75652066726f6d20656e76000000000000000000000000008152508261190f565b61109a6040518060400160405280600d81526020017f636f6e7472616374206164647200000000000000000000000000000000000000815250306117ed565b604080518082018252600e81527f636f6e7472616374206e6f6e6365000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523060048201526111219190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401610340565b6111606040518060400160405280600b81526020017f73656e6465722061646472000000000000000000000000000000000000000000815250336117ed565b604080518082018252600c81527f73656e646572206e6f6e63650000000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523360048201526111e79190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401610340565b60408051808201825260208082527f7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d9082015290517f213e4198000000000000000000000000000000000000000000000000000000008152600090737109709ecfa91a80626ff3989d68f67f5b1dd12d9063213e41989061126c908590600401611c64565b600060405180830381865afa158015611289573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526112cf9190810190611d34565b90506113456040518060400160405280600481526020017f6b657973000000000000000000000000000000000000000000000000000000008152508260008151811061131d5761131d611e68565b60200260200101518360018151811061133857611338611e68565b60200260200101516119a0565b6040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f66726f6d206f726967696e616c000000000000000000000000000000000000006044820152309063a777d0dc9060640160006040518083038186803b1580156113c257600080fd5b505afa1580156113d6573d6000803e3d6000fd5b50506040517f06447d5600000000000000000000000000000000000000000000000000000000815260426004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d92506306447d569150602401600060405180830381600087803b15801561144057600080fd5b505af1158015611454573d6000803e3d6000fd5b50506040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f66726f6d207072616e6b20310000000000000000000000000000000000000000604482015230925063a777d0dc915060640160006040518083038186803b1580156114d557600080fd5b505afa1580156114e9573d6000803e3d6000fd5b5050505061152c6040518060400160405280601781526020017f706172656e742073636f7065206d73672e73656e646572000000000000000000815250336117ed565b61156b6040518060400160405280601a81526020017f706172656e742073636f706520636f6e74726163742e61646472000000000000815250306117ed565b6040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f66726f6d207072616e6b203200000000000000000000000000000000000000006044820152309063a777d0dc9060640160006040518083038186803b1580156115e857600080fd5b505afa1580156115fc573d6000803e3d6000fd5b505050507f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff166390c5013b6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561166b57600080fd5b505af115801561167f573d6000803e3d6000fd5b50506040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f66726f6d206f726967696e616c20616761696e00000000000000000000000000604482015230925063a777d0dc915060640160006040518083038186803b15801561170057600080fd5b505afa158015611714573d6000803e3d6000fd5b505050506117566040518060400160405280600581526020017f646f6e652100000000000000000000000000000000000000000000000000000081525061175b565b505050565b6117ea8160405160240161176f9190611e97565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f41304fac00000000000000000000000000000000000000000000000000000000179052611a2f565b50565b6101748282604051602401611803929190611eaa565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f319af33300000000000000000000000000000000000000000000000000000000179052611a2f565b6101748282604051602401611894929190611ee2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb60e72cc00000000000000000000000000000000000000000000000000000000179052611a2f565b6101748282604051602401611925929190611f04565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fc3b5563500000000000000000000000000000000000000000000000000000000179052611a2f565b6117568383836040516024016119b893929190611f28565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f2ced7cef000000000000000000000000000000000000000000000000000000001790525b6117ea8180516a636f6e736f6c652e6c6f67602083016000808483855afa5050505050565b60b280611f6c83390190565b60008060208385031215611a7357600080fd5b823567ffffffffffffffff80821115611a8b57600080fd5b818501915085601f830112611a9f57600080fd5b813581811115611aae57600080fd5b866020828501011115611ac057600080fd5b60209290920196919550909350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611b2a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b600060208284031215611b9057600080fd5b815167ffffffffffffffff81168114611ba857600080fd5b9392505050565b600060208284031215611bc157600080fd5b5051919050565b600060208284031215611bda57600080fd5b81518015158114611ba857600080fd5b60005b83811015611c05578181015183820152602001611bed565b83811115611c14576000848401525b50505050565b60008151808452611c32816020860160208601611bea565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b604081526000611c776040830184611c1a565b8281036020840152600c81527f2e726f6f745f6b65795b305d000000000000000000000000000000000000000060208201526040810191505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611d2c57611d2c611cb6565b604052919050565b60006020808385031215611d4757600080fd5b825167ffffffffffffffff80821115611d5f57600080fd5b8185019150601f8681840112611d7457600080fd5b825182811115611d8657611d86611cb6565b8060051b611d95868201611ce5565b918252848101860191868101908a841115611daf57600080fd5b87870192505b83831015611e5a57825186811115611dcd5760008081fd5b8701603f81018c13611ddf5760008081fd5b88810151604088821115611df557611df5611cb6565b611e248b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08a85011601611ce5565b8281528e82848601011115611e395760008081fd5b611e48838d8301848701611bea565b85525050509187019190870190611db5565b9a9950505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602081526000611ba86020830184611c1a565b604081526000611ebd6040830185611c1a565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b604081526000611ef56040830185611c1a565b90508260208301529392505050565b604081526000611f176040830185611c1a565b905082151560208301529392505050565b606081526000611f3b6060830186611c1a565b8281036020840152611f4d8186611c1a565b90508281036040840152611f618185611c1a565b969550505050505056fe608060405234801561001057600080fd5b506040516100b23803806100b283398101604081905261002f91610037565b600055610050565b60006020828403121561004957600080fd5b5051919050565b60548061005e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c298557814602d575b600080fd5b603560005481565b60405190815260200160405180910390f3fea164736f6c634300080f000aa164736f6c634300080f000a","sourceMap":"2541:3359:0:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b50600436106100a35760003560e01c8063a76ccdfa11610076578063bef03abc1161005b578063bef03abc14610111578063c040622614610119578063dbf1282f146100c357600080fd5b8063a76ccdfa146100eb578063a777d0dc146100fe57600080fd5b806361bc221a146100a85780637e79255d146100c35780637f8b915c146100d85780638d3ef7ca146100c3575b600080fd5b6100b160005481565b60405190815260200160405180910390f35b6100d66100d1366004611a60565b610121565b005b6100d66100e6366004611a60565b610178565b6100d66100f9366004611a60565b6101b7565b6100d661010c366004611a60565b61023f565b6100d66102bd565b6100d6610f54565b60008054908061013083611ad2565b919050555061017482828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061175b92505050565b5050565b61017482828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061175b92505050565b6000805490806101c683611ad2565b90915550506040517fdbf1282f000000000000000000000000000000000000000000000000000000008152309063dbf1282f906102099085908590600401611b31565b600060405180830381600087803b15801561022357600080fd5b505af1158015610237573d6000803e3d6000fd5b505050505050565b61027e82828080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061175b92505050565b6101746040518060400160405280601081526020017f68656c6c6f206d73672e73656e64657200000000000000000000000000000000815250336117ed565b604080518082018252600b81527f6e6f6e6365207374617274000000000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523060048201526103909190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab906024015b602060405180830381865afa15801561035d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103819190611b7e565b67ffffffffffffffff1661187e565b6103ce6040518060400160405280600e81526020017f74657374696e672073696e676c6500000000000000000000000000000000000081525061175b565b7f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff1663afc980406040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561043957600080fd5b505af115801561044d573d6000803e3d6000fd5b50506040517f7e79255d00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f73696e676c655f63616c6c3100000000000000000000000000000000000000006044820152309250637e79255d9150606401600060405180830381600087803b1580156104d057600080fd5b505af11580156104e4573d6000803e3d6000fd5b50506040517f8d3ef7ca00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f73696e676c655f63616c6c3200000000000000000000000000000000000000006044820152309250638d3ef7ca9150606401600060405180830381600087803b15801561056757600080fd5b505af115801561057b573d6000803e3d6000fd5b505050506105bd6040518060400160405280601281526020017f74657374696e672073746172742f73746f70000000000000000000000000000081525061175b565b6040517f7fec2a8d00000000000000000000000000000000000000000000000000000000815262c0ffee6004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90637fec2a8d90602401600060405180830381600087803b15801561062557600080fd5b505af1158015610639573d6000803e3d6000fd5b50506040517f7e79255d00000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f737461727473746f705f63616c6c3100000000000000000000000000000000006044820152309250637e79255d9150606401600060405180830381600087803b1580156106bc57600080fd5b505af11580156106d0573d6000803e3d6000fd5b50506040517f8d3ef7ca00000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f737461727473746f705f63616c6c3200000000000000000000000000000000006044820152309250638d3ef7ca9150606401600060405180830381600087803b15801561075357600080fd5b505af1158015610767573d6000803e3d6000fd5b50506040517f7f8b915c00000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f737461727473746f705f707572650000000000000000000000000000000000006044820152309250637f8b915c915060640160006040518083038186803b1580156107e857600080fd5b505afa1580156107fc573d6000803e3d6000fd5b505050507f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff166376eadd366040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561086b57600080fd5b505af115801561087f573d6000803e3d6000fd5b50506040517f7e79255d00000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f737461727473746f705f63616c6c3300000000000000000000000000000000006044820152309250637e79255d9150606401600060405180830381600087803b15801561090257600080fd5b505af1158015610916573d6000803e3d6000fd5b505050506109586040518060400160405280600e81526020017f74657374696e67206e657374656400000000000000000000000000000000000081525061175b565b6040517f7fec2a8d0000000000000000000000000000000000000000000000000000000081526112346004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90637fec2a8d90602401600060405180830381600087803b1580156109bf57600080fd5b505af11580156109d3573d6000803e3d6000fd5b50506040517fa76ccdfa00000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f6e65737465640000000000000000000000000000000000000000000000000000604482015230925063a76ccdfa9150606401600060405180830381600087803b158015610a5657600080fd5b505af1158015610a6a573d6000803e3d6000fd5b505050507f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff166376eadd366040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610ad957600080fd5b505af1158015610aed573d6000803e3d6000fd5b50505050610b2f6040518060400160405280601381526020017f636f6e7472616374206465706c6f796d656e740000000000000000000000000081525061175b565b6040517fe6962cdb000000000000000000000000000000000000000000000000000000008152621234566004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d9063e6962cdb90602401600060405180830381600087803b158015610b9757600080fd5b505af1158015610bab573d6000803e3d6000fd5b5050505060006104d2604051610bc090611a54565b908152602001604051809103906000f080158015610be2573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c29855786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c549190611baf565b6104d214610c6157600080fd5b610c9f6040518060400160405280600881526020017f637265617465203200000000000000000000000000000000000000000000000081525061175b565b6040517fe6962cdb00000000000000000000000000000000000000000000000000000000815261cafe6004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d9063e6962cdb90602401600060405180830381600087803b158015610d0657600080fd5b505af1158015610d1a573d6000803e3d6000fd5b505050506000602a60001b6104d2604051610d3490611a54565b9081526020018190604051809103906000f5905080158015610d5a573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c29855786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610da8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dcc9190611baf565b6104d214610dd957600080fd5b610e176040518060400160405280600581526020017f646f6e652100000000000000000000000000000000000000000000000000000081525061175b565b7f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff1663afc980406040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610e8257600080fd5b505af1158015610e96573d6000803e3d6000fd5b505050506104d2604051610ea990611a54565b908152602001604051809103906000f080158015610ecb573d6000803e3d6000fd5b5050604080518082018252600981527f6e6f6e636520656e640000000000000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523060048201526101749190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401610340565b604080517f4777f3cf0000000000000000000000000000000000000000000000000000000081526004810191909152600c60448201527f4558414d504c455f424f4f4c0000000000000000000000000000000000000000606482015260006024820181905290737109709ecfa91a80626ff3989d68f67f5b1dd12d90634777f3cf90608401602060405180830381865afa158015610ff6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061101a9190611bc8565b905061105b6040518060400160405280601381526020017f626f6f6c2076616c75652066726f6d20656e76000000000000000000000000008152508261190f565b61109a6040518060400160405280600d81526020017f636f6e7472616374206164647200000000000000000000000000000000000000815250306117ed565b604080518082018252600e81527f636f6e7472616374206e6f6e6365000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523060048201526111219190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401610340565b6111606040518060400160405280600b81526020017f73656e6465722061646472000000000000000000000000000000000000000000815250336117ed565b604080518082018252600c81527f73656e646572206e6f6e63650000000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523360048201526111e79190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401610340565b60408051808201825260208082527f7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d9082015290517f213e4198000000000000000000000000000000000000000000000000000000008152600090737109709ecfa91a80626ff3989d68f67f5b1dd12d9063213e41989061126c908590600401611c64565b600060405180830381865afa158015611289573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526112cf9190810190611d34565b90506113456040518060400160405280600481526020017f6b657973000000000000000000000000000000000000000000000000000000008152508260008151811061131d5761131d611e68565b60200260200101518360018151811061133857611338611e68565b60200260200101516119a0565b6040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f66726f6d206f726967696e616c000000000000000000000000000000000000006044820152309063a777d0dc9060640160006040518083038186803b1580156113c257600080fd5b505afa1580156113d6573d6000803e3d6000fd5b50506040517f06447d5600000000000000000000000000000000000000000000000000000000815260426004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d92506306447d569150602401600060405180830381600087803b15801561144057600080fd5b505af1158015611454573d6000803e3d6000fd5b50506040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f66726f6d207072616e6b20310000000000000000000000000000000000000000604482015230925063a777d0dc915060640160006040518083038186803b1580156114d557600080fd5b505afa1580156114e9573d6000803e3d6000fd5b5050505061152c6040518060400160405280601781526020017f706172656e742073636f7065206d73672e73656e646572000000000000000000815250336117ed565b61156b6040518060400160405280601a81526020017f706172656e742073636f706520636f6e74726163742e61646472000000000000815250306117ed565b6040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f66726f6d207072616e6b203200000000000000000000000000000000000000006044820152309063a777d0dc9060640160006040518083038186803b1580156115e857600080fd5b505afa1580156115fc573d6000803e3d6000fd5b505050507f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff166390c5013b6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561166b57600080fd5b505af115801561167f573d6000803e3d6000fd5b50506040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f66726f6d206f726967696e616c20616761696e00000000000000000000000000604482015230925063a777d0dc915060640160006040518083038186803b15801561170057600080fd5b505afa158015611714573d6000803e3d6000fd5b505050506117566040518060400160405280600581526020017f646f6e652100000000000000000000000000000000000000000000000000000081525061175b565b505050565b6117ea8160405160240161176f9190611e97565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f41304fac00000000000000000000000000000000000000000000000000000000179052611a2f565b50565b6101748282604051602401611803929190611eaa565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f319af33300000000000000000000000000000000000000000000000000000000179052611a2f565b6101748282604051602401611894929190611ee2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb60e72cc00000000000000000000000000000000000000000000000000000000179052611a2f565b6101748282604051602401611925929190611f04565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fc3b5563500000000000000000000000000000000000000000000000000000000179052611a2f565b6117568383836040516024016119b893929190611f28565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f2ced7cef000000000000000000000000000000000000000000000000000000001790525b6117ea8180516a636f6e736f6c652e6c6f67602083016000808483855afa5050505050565b60b280611f6c83390190565b60008060208385031215611a7357600080fd5b823567ffffffffffffffff80821115611a8b57600080fd5b818501915085601f830112611a9f57600080fd5b813581811115611aae57600080fd5b866020828501011115611ac057600080fd5b60209290920196919550909350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611b2a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b600060208284031215611b9057600080fd5b815167ffffffffffffffff81168114611ba857600080fd5b9392505050565b600060208284031215611bc157600080fd5b5051919050565b600060208284031215611bda57600080fd5b81518015158114611ba857600080fd5b60005b83811015611c05578181015183820152602001611bed565b83811115611c14576000848401525b50505050565b60008151808452611c32816020860160208601611bea565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b604081526000611c776040830184611c1a565b8281036020840152600c81527f2e726f6f745f6b65795b305d000000000000000000000000000000000000000060208201526040810191505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611d2c57611d2c611cb6565b604052919050565b60006020808385031215611d4757600080fd5b825167ffffffffffffffff80821115611d5f57600080fd5b8185019150601f8681840112611d7457600080fd5b825182811115611d8657611d86611cb6565b8060051b611d95868201611ce5565b918252848101860191868101908a841115611daf57600080fd5b87870192505b83831015611e5a57825186811115611dcd5760008081fd5b8701603f81018c13611ddf5760008081fd5b88810151604088821115611df557611df5611cb6565b611e248b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08a85011601611ce5565b8281528e82848601011115611e395760008081fd5b611e48838d8301848701611bea565b85525050509187019190870190611db5565b9a9950505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602081526000611ba86020830184611c1a565b604081526000611ebd6040830185611c1a565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b604081526000611ef56040830185611c1a565b90508260208301529392505050565b604081526000611f176040830185611c1a565b905082151560208301529392505050565b606081526000611f3b6060830186611c1a565b8281036020840152611f4d8186611c1a565b90508281036040840152611f618185611c1a565b969550505050505056fe608060405234801561001057600080fd5b506040516100b23803806100b283398101604081905261002f91610037565b600055610050565b60006020828403121561004957600080fd5b5051919050565b60548061005e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c298557814602d575b600080fd5b603560005481565b60405190815260200160405180910390f3fea164736f6c634300080f000aa164736f6c634300080f000a","sourceMap":"2541:3359:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2775:22;;;;;;;;;160:25:1;;;148:2;133:18;2775:22:0;;;;;;;5405:95;;;;;;:::i;:::-;;:::i;:::-;;5814:84;;;;;;:::i;:::-;;:::i;5607:98::-;;;;;;:::i;:::-;;:::i;5256:143::-;;;;;;:::i;:::-;;:::i;3903:1258::-;;;:::i;2887:949::-;;;:::i;5405:95::-;5459:7;:9;;;:7;:9;;;:::i;:::-;;;;;;5478:15;5490:2;;5478:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;5478:11:0;;-1:-1:-1;;;5478:15:0:i;:::-;5405:95;;:::o;5814:84::-;5876:15;5888:2;;5876:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;5876:11:0;;-1:-1:-1;;;5876:15:0:i;5607:98::-;5663:7;:9;;;:7;:9;;;:::i;:::-;;;;-1:-1:-1;;5682:16:0;;;;;:4;;:12;;:16;;5695:2;;;;5682:16;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5607:98;;:::o;5256:143::-;5315:15;5327:2;;5315:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;5315:11:0;;-1:-1:-1;;;5315:15:0:i;:::-;5340:52;;;;;;;;;;;;;;;;;;5380:10;5340:11;:52::i;3903:1258::-;3944:63;;;;;;;;;;;;;;;;3979:26;;;;;3999:4;3979:26;;;1747:74:1;3944:63:0;;;3979:11;;;;1720:18:1;;3979:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3971:35;;3944:11;:63::i;:::-;4018:29;;;;;;;;;;;;;;;;;;:11;:29::i;:::-;2634:28;2626:37;;4057:12;;;:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4081:26:0;;;;;2327:2:1;4081:26:0;;;2309:21:1;2366:2;2346:18;;;2339:30;2405:14;2385:18;;;2378:42;4081:4:0;;-1:-1:-1;4081:10:0;;-1:-1:-1;2437:18:1;;4081:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4117:26:0;;;;;2668:2:1;4117:26:0;;;2650:21:1;2707:2;2687:18;;;2680:30;2746:14;2726:18;;;2719:42;4117:4:0;;-1:-1:-1;4117:10:0;;-1:-1:-1;2778:18:1;;4117:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4154:33;;;;;;;;;;;;;;;;;;:11;:33::i;:::-;4197:45;;;;;4231:8;4197:45;;;1747:74:1;4197:17:0;;;;1720:18:1;;4197:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4252:29:0;;;;;3009:2:1;4252:29:0;;;2991:21:1;3048:2;3028:18;;;3021:30;3087:17;3067:18;;;3060:45;4252:4:0;;-1:-1:-1;4252:10:0;;-1:-1:-1;3122:18:1;;4252:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4291:29:0;;;;;3353:2:1;4291:29:0;;;3335:21:1;3392:2;3372:18;;;3365:30;3431:17;3411:18;;;3404:45;4291:4:0;;-1:-1:-1;4291:10:0;;-1:-1:-1;3466:18:1;;4291:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4330:31:0;;;;;3697:2:1;4330:31:0;;;3679:21:1;3736:2;3716:18;;;3709:30;3775:16;3755:18;;;3748:44;4330:4:0;;-1:-1:-1;4330:13:0;;-1:-1:-1;3809:18:1;;4330:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2634:28;2626:37;;4371:16;;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4399:29:0;;;;;4040:2:1;4399:29:0;;;4022:21:1;4079:2;4059:18;;;4052:30;4118:17;4098:18;;;4091:45;4399:4:0;;-1:-1:-1;4399:10:0;;-1:-1:-1;4153:18:1;;4399:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4439;;;;;;;;;;;;;;;;;;:11;:29::i;:::-;4478:43;;;;;4512:6;4478:43;;;1747:74:1;4478:17:0;;;;1720:18:1;;4478:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4531:22:0;;;;;4384:2:1;4531:22:0;;;4366:21:1;4423:1;4403:18;;;4396:29;4461:8;4441:18;;;4434:36;4531:4:0;;-1:-1:-1;4531:12:0;;-1:-1:-1;4487:18:1;;4531:22:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2634:28;2626:37;;4563:16;;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4592:34;;;;;;;;;;;;;;;;;;:11;:34::i;:::-;4636:40;;;;;4665:8;4636:40;;;1747:74:1;4636:12:0;;;;1720:18:1;;4636:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4686:8;4708:4;4697:16;;;;;:::i;:::-;160:25:1;;;148:2;133:18;4697:16:0;;;;;;;;;;;;;;;;;;;;;;;4686:27;;4731:1;:5;;;:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4742:4;4731:15;4723:24;;;;;;4758:23;;;;;;;;;;;;;;;;;;:11;:23::i;:::-;4791:38;;;;;4820:6;4791:38;;;1747:74:1;4791:12:0;;;;1720:18:1;;4791:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4839:8;4883:2;4867:20;;4889:4;4850:44;;;;;:::i;:::-;160:25:1;;;148:2;133:18;4850:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;4839:55;;4912:1;:5;;;:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4923:4;4912:15;4904:24;;;;;;4938:20;;;;;;;;;;;;;;;;;;:11;:20::i;:::-;2634:28;2626:37;;5042:12;;;:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5077:4;5066:16;;;;;:::i;:::-;160:25:1;;;148:2;133:18;5066:16:0;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5093:61:0;;;;;;;;;;;;;;;;5126:26;;;;;5146:4;5126:26;;;1747:74:1;5093:61:0;;;5126:11;;;;1720:18:1;;5126:26:0;1601:226:1;2887:949:0;2928:31;;;;;;;;;5104:21:1;;;;5161:2;5141:18;;;5134:30;5200:14;5180:18;;;5173:42;2919:6:0;5267:20:1;;;5260:52;;;2919:6:0;2928:8;;;;5232:19:1;;2928:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2919:40;;2969:37;;;;;;;;;;;;;;;;;;3004:1;2969:11;:37::i;:::-;3017:43;;;;;;;;;;;;;;;;;;3054:4;3017:11;:43::i;:::-;3070:57;;;;;;;;;;;;;;;;3100:26;;;;;3120:4;3100:26;;;1747:74:1;3070:57:0;;;3100:11;;;;1720:18:1;;3100:26:0;1601:226:1;3070:57:0;3137:47;;;;;;;;;;;;;;;;;;3172:10;3137:11;:47::i;:::-;3194:61;;;;;;;;;;;;;;;;3222:32;;;;;3242:10;3222:32;;;1747:74:1;3194:61:0;;;3222:11;;;;1720:18:1;;3222:32:0;1601:226:1;3194:61:0;3266:55;;;;;;;;;;;;;;;;;3354:38;;;;;3266:18;;3354:16;;;;:38;;3266:55;;3354:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3331:61;;3402:37;;;;;;;;;;;;;;;;;;3422:4;3427:1;3422:7;;;;;;;;:::i;:::-;;;;;;;3431:4;3436:1;3431:7;;;;;;;;:::i;:::-;;;;;;;3402:11;:37::i;:::-;3450:27;;;;;9413:2:1;3450:27:0;;;9395:21:1;9452:2;9432:18;;;9425:30;9491:15;9471:18;;;9464:43;3450:4:0;;:10;;9524:18:1;;3450:27:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;3487:37:0;;;;;3517:4;3487:37;;;1747:74:1;3487:13:0;;-1:-1:-1;3487:13:0;;-1:-1:-1;1720:18:1;;3487:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;3534:26:0;;;;;9755:2:1;3534:26:0;;;9737:21:1;9794:2;9774:18;;;9767:30;9833:14;9813:18;;;9806:42;3534:4:0;;-1:-1:-1;3534:10:0;;-1:-1:-1;9865:18:1;;3534:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3570:59;;;;;;;;;;;;;;;;;;3617:10;3570:11;:59::i;:::-;3639:56;;;;;;;;;;;;;;;;;;3689:4;3639:11;:56::i;:::-;3705:26;;;;;10096:2:1;3705:26:0;;;10078:21:1;10135:2;10115:18;;;10108:30;10174:14;10154:18;;;10147:42;3705:4:0;;:10;;10206:18:1;;3705:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2634:28;2626:37;;3741:12;;;:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;3765:33:0;;;;;10437:2:1;3765:33:0;;;10419:21:1;10476:2;10456:18;;;10449:30;10515:21;10495:18;;;10488:49;3765:4:0;;-1:-1:-1;3765:10:0;;-1:-1:-1;10554:18:1;;3765:33:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3809:20;;;;;;;;;;;;;;;;;;:11;:20::i;:::-;2909:927;;;2887:949::o;1658:121::-;1713:59;1768:2;1729:42;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;1713:15;:59::i;:::-;1658:121;:::o;2081:145::-;2148:71;2211:2;2215;2164:54;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;2148:15;:71::i;1930:145::-;1997:71;2060:2;2064;2013:54;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;1997:15;:71::i;1785:139::-;1849:68;1909:2;1913;1865:51;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;1849:15;:68::i;2232:179::-;2323:81;2392:2;2396;2400;2339:64;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;1133:133;1204:55;1251:7;1370:14;;856:42;1543:2;1530:16;;1346:21;;1370:14;1530:16;856:42;1579:5;1568:68;1559:77;;1496:150;;1272:380;:::o;-1:-1:-1:-;;;;;;;;:::o;196:592:1:-;267:6;275;328:2;316:9;307:7;303:23;299:32;296:52;;;344:1;341;334:12;296:52;384:9;371:23;413:18;454:2;446:6;443:14;440:34;;;470:1;467;460:12;440:34;508:6;497:9;493:22;483:32;;553:7;546:4;542:2;538:13;534:27;524:55;;575:1;572;565:12;524:55;615:2;602:16;641:2;633:6;630:14;627:34;;;657:1;654;647:12;627:34;702:7;697:2;688:6;684:2;680:15;676:24;673:37;670:57;;;723:1;720;713:12;670:57;754:2;746:11;;;;;776:6;;-1:-1:-1;196:592:1;;-1:-1:-1;;;;196:592:1:o;793:349::-;832:3;863:66;856:5;853:77;850:257;;963:77;960:1;953:88;1064:4;1061:1;1054:15;1092:4;1089:1;1082:15;850:257;-1:-1:-1;1134:1:1;1123:13;;793:349::o;1147:449::-;1306:2;1295:9;1288:21;1345:6;1340:2;1329:9;1325:18;1318:34;1402:6;1394;1389:2;1378:9;1374:18;1361:48;1458:1;1429:22;;;1453:2;1425:31;;;1418:42;;;;1512:2;1500:15;;;1517:66;1496:88;1481:104;1477:113;;1147:449;-1:-1:-1;1147:449:1:o;1832:288::-;1901:6;1954:2;1942:9;1933:7;1929:23;1925:32;1922:52;;;1970:1;1967;1960:12;1922:52;2002:9;1996:16;2052:18;2045:5;2041:30;2034:5;2031:41;2021:69;;2086:1;2083;2076:12;2021:69;2109:5;1832:288;-1:-1:-1;;;1832:288:1:o;4709:184::-;4779:6;4832:2;4820:9;4811:7;4807:23;4803:32;4800:52;;;4848:1;4845;4838:12;4800:52;-1:-1:-1;4871:16:1;;4709:184;-1:-1:-1;4709:184:1:o;5323:277::-;5390:6;5443:2;5431:9;5422:7;5418:23;5414:32;5411:52;;;5459:1;5456;5449:12;5411:52;5491:9;5485:16;5544:5;5537:13;5530:21;5523:5;5520:32;5510:60;;5566:1;5563;5556:12;5605:258;5677:1;5687:113;5701:6;5698:1;5695:13;5687:113;;;5777:11;;;5771:18;5758:11;;;5751:39;5723:2;5716:10;5687:113;;;5818:6;5815:1;5812:13;5809:48;;;5853:1;5844:6;5839:3;5835:16;5828:27;5809:48;;5605:258;;;:::o;5868:317::-;5910:3;5948:5;5942:12;5975:6;5970:3;5963:19;5991:63;6047:6;6040:4;6035:3;6031:14;6024:4;6017:5;6013:16;5991:63;:::i;:::-;6099:2;6087:15;6104:66;6083:88;6074:98;;;;6174:4;6070:109;;5868:317;-1:-1:-1;;5868:317:1:o;6190:493::-;6440:2;6429:9;6422:21;6403:4;6466:45;6507:2;6496:9;6492:18;6484:6;6466:45;:::i;:::-;6559:9;6551:6;6547:22;6542:2;6531:9;6527:18;6520:50;6594:2;6586:6;6579:18;6630:14;6625:2;6617:6;6613:15;6606:39;6674:2;6666:6;6662:15;6654:23;;;6190:493;;;;:::o;6688:184::-;6740:77;6737:1;6730:88;6837:4;6834:1;6827:15;6861:4;6858:1;6851:15;6877:334;6948:2;6942:9;7004:2;6994:13;;7009:66;6990:86;6978:99;;7107:18;7092:34;;7128:22;;;7089:62;7086:88;;;7154:18;;:::i;:::-;7190:2;7183:22;6877:334;;-1:-1:-1;6877:334:1:o;7216:1801::-;7321:6;7352:2;7395;7383:9;7374:7;7370:23;7366:32;7363:52;;;7411:1;7408;7401:12;7363:52;7444:9;7438:16;7473:18;7514:2;7506:6;7503:14;7500:34;;;7530:1;7527;7520:12;7500:34;7568:6;7557:9;7553:22;7543:32;;7594:4;7634:7;7629:2;7625;7621:11;7617:25;7607:53;;7656:1;7653;7646:12;7607:53;7685:2;7679:9;7707:2;7703;7700:10;7697:36;;;7713:18;;:::i;:::-;7759:2;7756:1;7752:10;7782:28;7806:2;7802;7798:11;7782:28;:::i;:::-;7844:15;;;7914:11;;;7910:20;;;7875:12;;;;7942:19;;;7939:39;;;7974:1;7971;7964:12;7939:39;8006:2;8002;7998:11;7987:22;;8018:969;8034:6;8029:3;8026:15;8018:969;;;8113:3;8107:10;8149:2;8136:11;8133:19;8130:109;;;8193:1;8222:2;8218;8211:14;8130:109;8262:20;;8317:2;8309:11;;8305:25;-1:-1:-1;8295:123:1;;8372:1;8401:2;8397;8390:14;8295:123;8456:2;8452;8448:11;8442:18;8484:2;8510;8505:3;8502:11;8499:37;;;8516:18;;:::i;:::-;8562:111;8669:2;8600:66;8595:2;8590:3;8586:12;8582:85;8578:94;8562:111;:::i;:::-;8700:3;8693:5;8686:18;8747:7;8741:3;8735;8731:2;8727:12;8723:22;8720:35;8717:128;;;8797:1;8827:3;8822;8815:16;8717:128;8858:56;8910:3;8905:2;8898:5;8894:14;8888:3;8884:2;8880:12;8858:56;:::i;:::-;8927:18;;-1:-1:-1;;;8051:12:1;;;;8965;;;;8018:969;;;9006:5;7216:1801;-1:-1:-1;;;;;;;;;;7216:1801:1:o;9022:184::-;9074:77;9071:1;9064:88;9171:4;9168:1;9161:15;9195:4;9192:1;9185:15;10583:220;10732:2;10721:9;10714:21;10695:4;10752:45;10793:2;10782:9;10778:18;10770:6;10752:45;:::i;10808:340::-;10985:2;10974:9;10967:21;10948:4;11005:45;11046:2;11035:9;11031:18;11023:6;11005:45;:::i;:::-;10997:53;;11098:42;11090:6;11086:55;11081:2;11070:9;11066:18;11059:83;10808:340;;;;;:::o;11153:291::-;11330:2;11319:9;11312:21;11293:4;11350:45;11391:2;11380:9;11376:18;11368:6;11350:45;:::i;:::-;11342:53;;11431:6;11426:2;11415:9;11411:18;11404:34;11153:291;;;;;:::o;11449:301::-;11620:2;11609:9;11602:21;11583:4;11640:45;11681:2;11670:9;11666:18;11658:6;11640:45;:::i;:::-;11632:53;;11735:6;11728:14;11721:22;11716:2;11705:9;11701:18;11694:50;11449:301;;;;;:::o;11755:546::-;12000:2;11989:9;11982:21;11963:4;12026:45;12067:2;12056:9;12052:18;12044:6;12026:45;:::i;:::-;12119:9;12111:6;12107:22;12102:2;12091:9;12087:18;12080:50;12153:33;12179:6;12171;12153:33;:::i;:::-;12139:47;;12234:9;12226:6;12222:22;12217:2;12206:9;12202:18;12195:50;12262:33;12288:6;12280;12262:33;:::i;:::-;12254:41;11755:546;-1:-1:-1;;;;;;11755:546:1:o","linkReferences":{}},"methodIdentifiers":{"call1(string)":"7e79255d","call2(string)":"8d3ef7ca","callPure(string)":"7f8b915c","counter()":"61bc221a","hello(string)":"a777d0dc","nested1(string)":"a76ccdfa","nested2(string)":"dbf1282f","run()":"c0406226","runBroadcast()":"bef03abc"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_v\",\"type\":\"string\"}],\"name\":\"call1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_v\",\"type\":\"string\"}],\"name\":\"call2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_v\",\"type\":\"string\"}],\"name\":\"callPure\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_v\",\"type\":\"string\"}],\"name\":\"hello\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_v\",\"type\":\"string\"}],\"name\":\"nested1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_v\",\"type\":\"string\"}],\"name\":\"nested2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"run\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"runBroadcast\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"ScriptExample\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"hello(string)\":{\"notice\":\"example external function, to force a CALL, and test vm.startPrank with.\"},\"run()\":{\"notice\":\"example function, runs through basic cheat-codes and console logs.\"},\"runBroadcast()\":{\"notice\":\"example function, to test vm.broadcast with.\"}},\"notice\":\"ScriptExample is an example script. The Go forge script code tests that it can run this.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"scripts/ScriptExample.s.sol\":\"ScriptExample\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"scripts/ScriptExample.s.sol\":{\"keccak256\":\"0x8d1dfa41908e7ccc3a498a2a2aa51c5275bedbb904ce32d08f8598e36f896d8d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5117bb7158363cae8b9dc0508d2852692fd36172f1c699ff680afbb5acebe1f3\",\"dweb:/ipfs/QmQdahJ8SPKfJ4yea5Ge9qaj5qh1TxVffhHvaWytBaL95h\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"string","name":"_v","type":"string"}],"stateMutability":"nonpayable","type":"function","name":"call1"},{"inputs":[{"internalType":"string","name":"_v","type":"string"}],"stateMutability":"nonpayable","type":"function","name":"call2"},{"inputs":[{"internalType":"string","name":"_v","type":"string"}],"stateMutability":"pure","type":"function","name":"callPure"},{"inputs":[],"stateMutability":"view","type":"function","name":"counter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"string","name":"_v","type":"string"}],"stateMutability":"view","type":"function","name":"hello"},{"inputs":[{"internalType":"string","name":"_v","type":"string"}],"stateMutability":"nonpayable","type":"function","name":"nested1"},{"inputs":[{"internalType":"string","name":"_v","type":"string"}],"stateMutability":"nonpayable","type":"function","name":"nested2"},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"run"},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"runBroadcast"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{"hello(string)":{"notice":"example external function, to force a CALL, and test vm.startPrank with."},"run()":{"notice":"example function, runs through basic cheat-codes and console logs."},"runBroadcast()":{"notice":"example function, to test vm.broadcast with."}},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"scripts/ScriptExample.s.sol":"ScriptExample"},"evmVersion":"london","libraries":{}},"sources":{"scripts/ScriptExample.s.sol":{"keccak256":"0x8d1dfa41908e7ccc3a498a2a2aa51c5275bedbb904ce32d08f8598e36f896d8d","urls":["bzz-raw://5117bb7158363cae8b9dc0508d2852692fd36172f1c699ff680afbb5acebe1f3","dweb:/ipfs/QmQdahJ8SPKfJ4yea5Ge9qaj5qh1TxVffhHvaWytBaL95h"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[{"astId":215,"contract":"scripts/ScriptExample.s.sol:ScriptExample","label":"counter","offset":0,"slot":"0","type":"t_uint256"}],"types":{"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}},"userdoc":{"version":1,"kind":"user","methods":{"hello(string)":{"notice":"example external function, to force a CALL, and test vm.startPrank with."},"run()":{"notice":"example function, runs through basic cheat-codes and console logs."},"runBroadcast()":{"notice":"example function, to test vm.broadcast with."}},"notice":"ScriptExample is an example script. The Go forge script code tests that it can run this."},"devdoc":{"version":1,"kind":"dev","title":"ScriptExample"},"ast":{"absolutePath":"scripts/ScriptExample.s.sol","id":720,"exportedSymbols":{"FooBar":[719],"ScriptExample":[706],"Vm":[55],"console":[192]},"nodeType":"SourceUnit","src":"32:5967:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","0.8",".15"]},{"id":55,"nodeType":"ContractDefinition","src":"120:616:0","nodes":[{"id":10,"nodeType":"FunctionDefinition","src":"139:91:0","nodes":[],"functionSelector":"4777f3cf","implemented":false,"kind":"function","modifiers":[],"name":"envOr","nameLocation":"148:5:0","parameters":{"id":6,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"mutability":"mutable","name":"name","nameLocation":"170:4:0","nodeType":"VariableDeclaration","scope":10,"src":"154:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":2,"name":"string","nodeType":"ElementaryTypeName","src":"154:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":5,"mutability":"mutable","name":"defaultValue","nameLocation":"181:12:0","nodeType":"VariableDeclaration","scope":10,"src":"176:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":4,"name":"bool","nodeType":"ElementaryTypeName","src":"176:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"153:41:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[{"constant":false,"id":8,"mutability":"mutable","name":"value","nameLocation":"223:5:0","nodeType":"VariableDeclaration","scope":10,"src":"218:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":7,"name":"bool","nodeType":"ElementaryTypeName","src":"218:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"217:12:0"},"scope":55,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":17,"nodeType":"FunctionDefinition","src":"235:72:0","nodes":[],"functionSelector":"2d0335ab","implemented":false,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"244:8:0","parameters":{"id":13,"nodeType":"ParameterList","parameters":[{"constant":false,"id":12,"mutability":"mutable","name":"account","nameLocation":"261:7:0","nodeType":"VariableDeclaration","scope":17,"src":"253:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":11,"name":"address","nodeType":"ElementaryTypeName","src":"253:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"252:17:0"},"returnParameters":{"id":16,"nodeType":"ParameterList","parameters":[{"constant":false,"id":15,"mutability":"mutable","name":"nonce","nameLocation":"300:5:0","nodeType":"VariableDeclaration","scope":17,"src":"293:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"},"typeName":{"id":14,"name":"uint64","nodeType":"ElementaryTypeName","src":"293:6:0","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"visibility":"internal"}],"src":"292:14:0"},"scope":55,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":27,"nodeType":"FunctionDefinition","src":"312:111:0","nodes":[],"functionSelector":"213e4198","implemented":false,"kind":"function","modifiers":[],"name":"parseJsonKeys","nameLocation":"321:13:0","parameters":{"id":22,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19,"mutability":"mutable","name":"json","nameLocation":"351:4:0","nodeType":"VariableDeclaration","scope":27,"src":"335:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":18,"name":"string","nodeType":"ElementaryTypeName","src":"335:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":21,"mutability":"mutable","name":"key","nameLocation":"373:3:0","nodeType":"VariableDeclaration","scope":27,"src":"357:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":20,"name":"string","nodeType":"ElementaryTypeName","src":"357:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"334:43:0"},"returnParameters":{"id":26,"nodeType":"ParameterList","parameters":[{"constant":false,"id":25,"mutability":"mutable","name":"keys","nameLocation":"417:4:0","nodeType":"VariableDeclaration","scope":27,"src":"401:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":23,"name":"string","nodeType":"ElementaryTypeName","src":"401:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":24,"nodeType":"ArrayTypeName","src":"401:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"src":"400:22:0"},"scope":55,"stateMutability":"pure","virtual":false,"visibility":"external"},{"id":32,"nodeType":"FunctionDefinition","src":"428:48:0","nodes":[],"functionSelector":"06447d56","implemented":false,"kind":"function","modifiers":[],"name":"startPrank","nameLocation":"437:10:0","parameters":{"id":30,"nodeType":"ParameterList","parameters":[{"constant":false,"id":29,"mutability":"mutable","name":"msgSender","nameLocation":"456:9:0","nodeType":"VariableDeclaration","scope":32,"src":"448:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":28,"name":"address","nodeType":"ElementaryTypeName","src":"448:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"447:19:0"},"returnParameters":{"id":31,"nodeType":"ParameterList","parameters":[],"src":"475:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":35,"nodeType":"FunctionDefinition","src":"481:30:0","nodes":[],"functionSelector":"90c5013b","implemented":false,"kind":"function","modifiers":[],"name":"stopPrank","nameLocation":"490:9:0","parameters":{"id":33,"nodeType":"ParameterList","parameters":[],"src":"499:2:0"},"returnParameters":{"id":34,"nodeType":"ParameterList","parameters":[],"src":"510:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":38,"nodeType":"FunctionDefinition","src":"516:30:0","nodes":[],"functionSelector":"afc98040","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"525:9:0","parameters":{"id":36,"nodeType":"ParameterList","parameters":[],"src":"534:2:0"},"returnParameters":{"id":37,"nodeType":"ParameterList","parameters":[],"src":"545:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":43,"nodeType":"FunctionDefinition","src":"551:47:0","nodes":[],"functionSelector":"e6962cdb","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"560:9:0","parameters":{"id":41,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40,"mutability":"mutable","name":"msgSender","nameLocation":"578:9:0","nodeType":"VariableDeclaration","scope":43,"src":"570:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39,"name":"address","nodeType":"ElementaryTypeName","src":"570:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"569:19:0"},"returnParameters":{"id":42,"nodeType":"ParameterList","parameters":[],"src":"597:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":48,"nodeType":"FunctionDefinition","src":"603:52:0","nodes":[],"functionSelector":"7fec2a8d","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"612:14:0","parameters":{"id":46,"nodeType":"ParameterList","parameters":[{"constant":false,"id":45,"mutability":"mutable","name":"msgSender","nameLocation":"635:9:0","nodeType":"VariableDeclaration","scope":48,"src":"627:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":44,"name":"address","nodeType":"ElementaryTypeName","src":"627:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"626:19:0"},"returnParameters":{"id":47,"nodeType":"ParameterList","parameters":[],"src":"654:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":51,"nodeType":"FunctionDefinition","src":"660:35:0","nodes":[],"functionSelector":"7fb5297f","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"669:14:0","parameters":{"id":49,"nodeType":"ParameterList","parameters":[],"src":"683:2:0"},"returnParameters":{"id":50,"nodeType":"ParameterList","parameters":[],"src":"694:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":54,"nodeType":"FunctionDefinition","src":"700:34:0","nodes":[],"functionSelector":"76eadd36","implemented":false,"kind":"function","modifiers":[],"name":"stopBroadcast","nameLocation":"709:13:0","parameters":{"id":52,"nodeType":"ParameterList","parameters":[],"src":"722:2:0"},"returnParameters":{"id":53,"nodeType":"ParameterList","parameters":[],"src":"733:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"Vm","contractDependencies":[],"contractKind":"interface","fullyImplemented":false,"linearizedBaseContracts":[55],"name":"Vm","nameLocation":"130:2:0","scope":720,"usedErrors":[]},{"id":192,"nodeType":"ContractDefinition","src":"791:1622:0","nodes":[{"id":61,"nodeType":"VariableDeclaration","src":"813:86:0","nodes":[],"constant":true,"mutability":"constant","name":"CONSOLE_ADDRESS","nameLocation":"830:15:0","scope":192,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":56,"name":"address","nodeType":"ElementaryTypeName","src":"813:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"hexValue":"307830303030303030303030303030303030303036333646366537333646366336353265366336663637","id":59,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"856:42:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"value":"0x000000000000000000636F6e736F6c652e6c6f67"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":58,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"848:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":57,"name":"address","nodeType":"ElementaryTypeName","src":"848:7:0","typeDescriptions":{}}},"id":60,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"848:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":78,"nodeType":"FunctionDefinition","src":"906:221:0","nodes":[],"body":{"id":77,"nodeType":"Block","src":"1065:62:0","nodes":[],"statements":[{"AST":{"nodeType":"YulBlock","src":"1084:37:0","statements":[{"nodeType":"YulAssignment","src":"1098:13:0","value":{"name":"fnIn","nodeType":"YulIdentifier","src":"1107:4:0"},"variableNames":[{"name":"fnOut","nodeType":"YulIdentifier","src":"1098:5:0"}]}]},"evmVersion":"london","externalReferences":[{"declaration":67,"isOffset":false,"isSlot":false,"src":"1107:4:0","valueSize":1},{"declaration":74,"isOffset":false,"isSlot":false,"src":"1098:5:0","valueSize":1}],"id":76,"nodeType":"InlineAssembly","src":"1075:46:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_castLogPayloadViewToPure","nameLocation":"915:25:0","parameters":{"id":68,"nodeType":"ParameterList","parameters":[{"constant":false,"id":67,"mutability":"mutable","name":"fnIn","nameLocation":"987:4:0","nodeType":"VariableDeclaration","scope":78,"src":"950:41:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"typeName":{"id":66,"nodeType":"FunctionTypeName","parameterTypes":{"id":64,"nodeType":"ParameterList","parameters":[{"constant":false,"id":63,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":66,"src":"959:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":62,"name":"bytes","nodeType":"ElementaryTypeName","src":"959:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"958:14:0"},"returnParameterTypes":{"id":65,"nodeType":"ParameterList","parameters":[],"src":"987:0:0"},"src":"950:41:0","stateMutability":"view","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"visibility":"internal"},"visibility":"internal"}],"src":"940:57:0"},"returnParameters":{"id":75,"nodeType":"ParameterList","parameters":[{"constant":false,"id":74,"mutability":"mutable","name":"fnOut","nameLocation":"1058:5:0","nodeType":"VariableDeclaration","scope":78,"src":"1021:42:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"typeName":{"id":73,"nodeType":"FunctionTypeName","parameterTypes":{"id":71,"nodeType":"ParameterList","parameters":[{"constant":false,"id":70,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":73,"src":"1030:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":69,"name":"bytes","nodeType":"ElementaryTypeName","src":"1030:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1029:14:0"},"returnParameterTypes":{"id":72,"nodeType":"ParameterList","parameters":[],"src":"1058:0:0"},"src":"1021:42:0","stateMutability":"pure","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"visibility":"internal"},"visibility":"internal"}],"src":"1020:44:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":90,"nodeType":"FunctionDefinition","src":"1133:133:0","nodes":[],"body":{"id":89,"nodeType":"Block","src":"1194:72:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":86,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":80,"src":"1251:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"arguments":[{"id":84,"name":"_sendLogPayloadView","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":106,"src":"1230:19:0","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}],"id":83,"name":"_castLogPayloadViewToPure","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":78,"src":"1204:25:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_function_internal_view$_t_bytes_memory_ptr_$returns$__$_$returns$_t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$_$","typeString":"function (function (bytes memory) view) pure returns (function (bytes memory) pure)"}},"id":85,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1204:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":87,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1204:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":88,"nodeType":"ExpressionStatement","src":"1204:55:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayload","nameLocation":"1142:15:0","parameters":{"id":81,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"payload","nameLocation":"1171:7:0","nodeType":"VariableDeclaration","scope":90,"src":"1158:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":79,"name":"bytes","nodeType":"ElementaryTypeName","src":"1158:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1157:22:0"},"returnParameters":{"id":82,"nodeType":"ParameterList","parameters":[],"src":"1194:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":106,"nodeType":"FunctionDefinition","src":"1272:380:0","nodes":[],"body":{"id":105,"nodeType":"Block","src":"1336:316:0","nodes":[],"statements":[{"assignments":[96],"declarations":[{"constant":false,"id":96,"mutability":"mutable","name":"payloadLength","nameLocation":"1354:13:0","nodeType":"VariableDeclaration","scope":105,"src":"1346:21:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":95,"name":"uint256","nodeType":"ElementaryTypeName","src":"1346:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":99,"initialValue":{"expression":{"id":97,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":92,"src":"1370:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":98,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1370:14:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1346:38:0"},{"assignments":[101],"declarations":[{"constant":false,"id":101,"mutability":"mutable","name":"consoleAddress","nameLocation":"1402:14:0","nodeType":"VariableDeclaration","scope":105,"src":"1394:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":100,"name":"address","nodeType":"ElementaryTypeName","src":"1394:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":103,"initialValue":{"id":102,"name":"CONSOLE_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":61,"src":"1419:15:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"1394:40:0"},{"AST":{"nodeType":"YulBlock","src":"1496:150:0","statements":[{"nodeType":"YulVariableDeclaration","src":"1510:36:0","value":{"arguments":[{"name":"payload","nodeType":"YulIdentifier","src":"1534:7:0"},{"kind":"number","nodeType":"YulLiteral","src":"1543:2:0","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1530:3:0"},"nodeType":"YulFunctionCall","src":"1530:16:0"},"variables":[{"name":"payloadStart","nodeType":"YulTypedName","src":"1514:12:0","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1559:77:0","value":{"arguments":[{"arguments":[],"functionName":{"name":"gas","nodeType":"YulIdentifier","src":"1579:3:0"},"nodeType":"YulFunctionCall","src":"1579:5:0"},{"name":"consoleAddress","nodeType":"YulIdentifier","src":"1586:14:0"},{"name":"payloadStart","nodeType":"YulIdentifier","src":"1602:12:0"},{"name":"payloadLength","nodeType":"YulIdentifier","src":"1616:13:0"},{"kind":"number","nodeType":"YulLiteral","src":"1631:1:0","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1634:1:0","type":"","value":"0"}],"functionName":{"name":"staticcall","nodeType":"YulIdentifier","src":"1568:10:0"},"nodeType":"YulFunctionCall","src":"1568:68:0"},"variables":[{"name":"r","nodeType":"YulTypedName","src":"1563:1:0","type":""}]}]},"documentation":"@solidity memory-safe-assembly","evmVersion":"london","externalReferences":[{"declaration":101,"isOffset":false,"isSlot":false,"src":"1586:14:0","valueSize":1},{"declaration":92,"isOffset":false,"isSlot":false,"src":"1534:7:0","valueSize":1},{"declaration":96,"isOffset":false,"isSlot":false,"src":"1616:13:0","valueSize":1}],"id":104,"nodeType":"InlineAssembly","src":"1487:159:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayloadView","nameLocation":"1281:19:0","parameters":{"id":93,"nodeType":"ParameterList","parameters":[{"constant":false,"id":92,"mutability":"mutable","name":"payload","nameLocation":"1314:7:0","nodeType":"VariableDeclaration","scope":106,"src":"1301:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":91,"name":"bytes","nodeType":"ElementaryTypeName","src":"1301:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1300:22:0"},"returnParameters":{"id":94,"nodeType":"ParameterList","parameters":[],"src":"1336:0:0"},"scope":192,"stateMutability":"view","virtual":false,"visibility":"private"},{"id":120,"nodeType":"FunctionDefinition","src":"1658:121:0","nodes":[],"body":{"id":119,"nodeType":"Block","src":"1703:76:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e6729","id":114,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1753:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},"value":"log(string)"},{"id":115,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":108,"src":"1768:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":112,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"1729:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":113,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"1729:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":116,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1729:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":111,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"1713:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":117,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1713:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":118,"nodeType":"ExpressionStatement","src":"1713:59:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"1667:3:0","parameters":{"id":109,"nodeType":"ParameterList","parameters":[{"constant":false,"id":108,"mutability":"mutable","name":"p0","nameLocation":"1685:2:0","nodeType":"VariableDeclaration","scope":120,"src":"1671:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":107,"name":"string","nodeType":"ElementaryTypeName","src":"1671:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"1670:18:0"},"returnParameters":{"id":110,"nodeType":"ParameterList","parameters":[],"src":"1703:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":137,"nodeType":"FunctionDefinition","src":"1785:139:0","nodes":[],"body":{"id":136,"nodeType":"Block","src":"1839:85:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c626f6f6c29","id":130,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1889:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},"value":"log(string,bool)"},{"id":131,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":122,"src":"1909:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":132,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":124,"src":"1913:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":128,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"1865:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":129,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"1865:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":133,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1865:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":127,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"1849:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":134,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1849:68:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":135,"nodeType":"ExpressionStatement","src":"1849:68:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"1794:3:0","parameters":{"id":125,"nodeType":"ParameterList","parameters":[{"constant":false,"id":122,"mutability":"mutable","name":"p0","nameLocation":"1812:2:0","nodeType":"VariableDeclaration","scope":137,"src":"1798:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":121,"name":"string","nodeType":"ElementaryTypeName","src":"1798:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":124,"mutability":"mutable","name":"p1","nameLocation":"1821:2:0","nodeType":"VariableDeclaration","scope":137,"src":"1816:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":123,"name":"bool","nodeType":"ElementaryTypeName","src":"1816:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"1797:27:0"},"returnParameters":{"id":126,"nodeType":"ParameterList","parameters":[],"src":"1839:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":154,"nodeType":"FunctionDefinition","src":"1930:145:0","nodes":[],"body":{"id":153,"nodeType":"Block","src":"1987:88:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c75696e7432353629","id":147,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2037:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},"value":"log(string,uint256)"},{"id":148,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":139,"src":"2060:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":149,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":141,"src":"2064:2:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":145,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2013:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":146,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2013:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":150,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2013:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":144,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"1997:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":151,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1997:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":152,"nodeType":"ExpressionStatement","src":"1997:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"1939:3:0","parameters":{"id":142,"nodeType":"ParameterList","parameters":[{"constant":false,"id":139,"mutability":"mutable","name":"p0","nameLocation":"1957:2:0","nodeType":"VariableDeclaration","scope":154,"src":"1943:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":138,"name":"string","nodeType":"ElementaryTypeName","src":"1943:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":141,"mutability":"mutable","name":"p1","nameLocation":"1969:2:0","nodeType":"VariableDeclaration","scope":154,"src":"1961:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":140,"name":"uint256","nodeType":"ElementaryTypeName","src":"1961:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1942:30:0"},"returnParameters":{"id":143,"nodeType":"ParameterList","parameters":[],"src":"1987:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":171,"nodeType":"FunctionDefinition","src":"2081:145:0","nodes":[],"body":{"id":170,"nodeType":"Block","src":"2138:88:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c6164647265737329","id":164,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2188:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},"value":"log(string,address)"},{"id":165,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":156,"src":"2211:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":166,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":158,"src":"2215:2:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":162,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2164:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":163,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2164:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":167,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2164:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":161,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"2148:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":168,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2148:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":169,"nodeType":"ExpressionStatement","src":"2148:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2090:3:0","parameters":{"id":159,"nodeType":"ParameterList","parameters":[{"constant":false,"id":156,"mutability":"mutable","name":"p0","nameLocation":"2108:2:0","nodeType":"VariableDeclaration","scope":171,"src":"2094:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":155,"name":"string","nodeType":"ElementaryTypeName","src":"2094:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":158,"mutability":"mutable","name":"p1","nameLocation":"2120:2:0","nodeType":"VariableDeclaration","scope":171,"src":"2112:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":157,"name":"address","nodeType":"ElementaryTypeName","src":"2112:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2093:30:0"},"returnParameters":{"id":160,"nodeType":"ParameterList","parameters":[],"src":"2138:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":191,"nodeType":"FunctionDefinition","src":"2232:179:0","nodes":[],"body":{"id":190,"nodeType":"Block","src":"2313:98:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c737472696e672c737472696e6729","id":183,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2363:27:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},"value":"log(string,string,string)"},{"id":184,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":173,"src":"2392:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":185,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":175,"src":"2396:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":186,"name":"p2","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":177,"src":"2400:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":181,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2339:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":182,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2339:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":187,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2339:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":180,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"2323:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":188,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2323:81:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":189,"nodeType":"ExpressionStatement","src":"2323:81:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2241:3:0","parameters":{"id":178,"nodeType":"ParameterList","parameters":[{"constant":false,"id":173,"mutability":"mutable","name":"p0","nameLocation":"2259:2:0","nodeType":"VariableDeclaration","scope":191,"src":"2245:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":172,"name":"string","nodeType":"ElementaryTypeName","src":"2245:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":175,"mutability":"mutable","name":"p1","nameLocation":"2277:2:0","nodeType":"VariableDeclaration","scope":191,"src":"2263:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":174,"name":"string","nodeType":"ElementaryTypeName","src":"2263:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":177,"mutability":"mutable","name":"p2","nameLocation":"2295:2:0","nodeType":"VariableDeclaration","scope":191,"src":"2281:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":176,"name":"string","nodeType":"ElementaryTypeName","src":"2281:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2244:54:0"},"returnParameters":{"id":179,"nodeType":"ParameterList","parameters":[],"src":"2313:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"}],"abstract":false,"baseContracts":[],"canonicalName":"console","contractDependencies":[],"contractKind":"library","fullyImplemented":true,"linearizedBaseContracts":[192],"name":"console","nameLocation":"799:7:0","scope":720,"usedErrors":[]},{"id":706,"nodeType":"ContractDefinition","src":"2541:3359:0","nodes":[{"id":207,"nodeType":"VariableDeclaration","src":"2571:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"2597:10:0","scope":706,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":194,"name":"address","nodeType":"ElementaryTypeName","src":"2571:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":202,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2644:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":201,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"2634:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":203,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2634:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":200,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2626:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":199,"name":"uint256","nodeType":"ElementaryTypeName","src":"2626:7:0","typeDescriptions":{}}},"id":204,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2626:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":198,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2618:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":197,"name":"uint160","nodeType":"ElementaryTypeName","src":"2618:7:0","typeDescriptions":{}}},"id":205,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2618:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":196,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2610:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":195,"name":"address","nodeType":"ElementaryTypeName","src":"2610:7:0","typeDescriptions":{}}},"id":206,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2610:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":213,"nodeType":"VariableDeclaration","src":"2671:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"2692:2:0","scope":706,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"},"typeName":{"id":209,"nodeType":"UserDefinedTypeName","pathNode":{"id":208,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":55,"src":"2671:2:0"},"referencedDeclaration":55,"src":"2671:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"value":{"arguments":[{"id":211,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":207,"src":"2700:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":210,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":55,"src":"2697:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$55_$","typeString":"type(contract Vm)"}},"id":212,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2697:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"visibility":"internal"},{"id":215,"nodeType":"VariableDeclaration","src":"2775:22:0","nodes":[],"constant":false,"functionSelector":"61bc221a","mutability":"mutable","name":"counter","nameLocation":"2790:7:0","scope":706,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":214,"name":"uint256","nodeType":"ElementaryTypeName","src":"2775:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":378,"nodeType":"FunctionDefinition","src":"2887:949:0","nodes":[],"body":{"id":377,"nodeType":"Block","src":"2909:927:0","nodes":[],"statements":[{"assignments":[220],"declarations":[{"constant":false,"id":220,"mutability":"mutable","name":"x","nameLocation":"2924:1:0","nodeType":"VariableDeclaration","scope":377,"src":"2919:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":219,"name":"bool","nodeType":"ElementaryTypeName","src":"2919:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"id":226,"initialValue":{"arguments":[{"hexValue":"4558414d504c455f424f4f4c","id":223,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2937:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},"value":"EXAMPLE_BOOL"},{"hexValue":"66616c7365","id":224,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"2953:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":221,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"2928:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":222,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"envOr","nodeType":"MemberAccess","referencedDeclaration":10,"src":"2928:8:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$_t_bool_$returns$_t_bool_$","typeString":"function (string memory,bool) view external returns (bool)"}},"id":225,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2928:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"VariableDeclarationStatement","src":"2919:40:0"},{"expression":{"arguments":[{"hexValue":"626f6f6c2076616c75652066726f6d20656e76","id":230,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2981:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},"value":"bool value from env"},{"id":231,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3004:1:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":227,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"2969:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":229,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":137,"src":"2969:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_bool_$returns$__$","typeString":"function (string memory,bool) pure"}},"id":232,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2969:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":233,"nodeType":"ExpressionStatement","src":"2969:37:0"},{"expression":{"arguments":[{"hexValue":"636f6e74726163742061646472","id":237,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3029:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},"value":"contract addr"},{"arguments":[{"id":240,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3054:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":239,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3046:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":238,"name":"address","nodeType":"ElementaryTypeName","src":"3046:7:0","typeDescriptions":{}}},"id":241,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3046:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":234,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3017:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":236,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3017:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":242,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3017:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":243,"nodeType":"ExpressionStatement","src":"3017:43:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206e6f6e6365","id":247,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3082:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},"value":"contract nonce"},{"arguments":[{"arguments":[{"id":252,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3120:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":251,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3112:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":250,"name":"address","nodeType":"ElementaryTypeName","src":"3112:7:0","typeDescriptions":{}}},"id":253,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3112:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":248,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3100:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":249,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3100:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":254,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3100:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":244,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3070:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":246,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"3070:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":255,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3070:57:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":256,"nodeType":"ExpressionStatement","src":"3070:57:0"},{"expression":{"arguments":[{"hexValue":"73656e6465722061646472","id":260,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3149:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},"value":"sender addr"},{"arguments":[{"expression":{"id":263,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3172:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":264,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3172:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":262,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3164:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":261,"name":"address","nodeType":"ElementaryTypeName","src":"3164:7:0","typeDescriptions":{}}},"id":265,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3164:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":257,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3137:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":259,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3137:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":266,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3137:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":267,"nodeType":"ExpressionStatement","src":"3137:47:0"},{"expression":{"arguments":[{"hexValue":"73656e646572206e6f6e6365","id":271,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3206:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},"value":"sender nonce"},{"arguments":[{"arguments":[{"expression":{"id":276,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3242:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":277,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3242:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":275,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3234:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":274,"name":"address","nodeType":"ElementaryTypeName","src":"3234:7:0","typeDescriptions":{}}},"id":278,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3234:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":272,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3222:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":273,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3222:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":279,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3222:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":268,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3194:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":270,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"3194:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":280,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3194:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":281,"nodeType":"ExpressionStatement","src":"3194:61:0"},{"assignments":[283],"declarations":[{"constant":false,"id":283,"mutability":"mutable","name":"json","nameLocation":"3280:4:0","nodeType":"VariableDeclaration","scope":377,"src":"3266:18:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":282,"name":"string","nodeType":"ElementaryTypeName","src":"3266:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"id":285,"initialValue":{"hexValue":"7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d","id":284,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3287:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e95522e99766888d0261f55bd1eae5e3f3e26eaf009a16e2433eafaf0a4ecdf2","typeString":"literal_string \"{\"root_key\": [{\"a\": 1, \"b\": 2}]}\""},"value":"{\"root_key\": [{\"a\": 1, \"b\": 2}]}"},"nodeType":"VariableDeclarationStatement","src":"3266:55:0"},{"assignments":[290],"declarations":[{"constant":false,"id":290,"mutability":"mutable","name":"keys","nameLocation":"3347:4:0","nodeType":"VariableDeclaration","scope":377,"src":"3331:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":288,"name":"string","nodeType":"ElementaryTypeName","src":"3331:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":289,"nodeType":"ArrayTypeName","src":"3331:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"id":296,"initialValue":{"arguments":[{"id":293,"name":"json","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":283,"src":"3371:4:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"2e726f6f745f6b65795b305d","id":294,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3377:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""},"value":".root_key[0]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""}],"expression":{"id":291,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3354:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":292,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"parseJsonKeys","nodeType":"MemberAccess","referencedDeclaration":27,"src":"3354:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$_t_array$_t_string_memory_ptr_$dyn_memory_ptr_$","typeString":"function (string memory,string memory) pure external returns (string memory[] memory)"}},"id":295,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3354:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"nodeType":"VariableDeclarationStatement","src":"3331:61:0"},{"expression":{"arguments":[{"hexValue":"6b657973","id":300,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3414:6:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},"value":"keys"},{"baseExpression":{"id":301,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":290,"src":"3422:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":303,"indexExpression":{"hexValue":"30","id":302,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"3427:1:0","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"3422:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"baseExpression":{"id":304,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":290,"src":"3431:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":306,"indexExpression":{"hexValue":"31","id":305,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"3436:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"3431:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":297,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3402:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":299,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":191,"src":"3402:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory,string memory) pure"}},"id":307,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3402:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":308,"nodeType":"ExpressionStatement","src":"3402:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c","id":312,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3461:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""},"value":"from original"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""}],"expression":{"id":309,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3450:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":311,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3450:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":313,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3450:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":314,"nodeType":"ExpressionStatement","src":"3450:27:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"30783432","id":322,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"3517:4:0","typeDescriptions":{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"},"value":"0x42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"}],"id":321,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3509:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":320,"name":"uint160","nodeType":"ElementaryTypeName","src":"3509:7:0","typeDescriptions":{}}},"id":323,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3509:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":319,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3501:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":318,"name":"address","nodeType":"ElementaryTypeName","src":"3501:7:0","typeDescriptions":{}}},"id":324,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3501:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":315,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3487:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":317,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startPrank","nodeType":"MemberAccess","referencedDeclaration":32,"src":"3487:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":325,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3487:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":326,"nodeType":"ExpressionStatement","src":"3487:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2031","id":330,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3545:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""},"value":"from prank 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""}],"expression":{"id":327,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3534:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":329,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3534:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":331,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3534:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":332,"nodeType":"ExpressionStatement","src":"3534:26:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f7065206d73672e73656e646572","id":336,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3582:25:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},"value":"parent scope msg.sender"},{"arguments":[{"expression":{"id":339,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3617:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":340,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3617:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":338,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3609:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":337,"name":"address","nodeType":"ElementaryTypeName","src":"3609:7:0","typeDescriptions":{}}},"id":341,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3609:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":333,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3570:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":335,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3570:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":342,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3570:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":343,"nodeType":"ExpressionStatement","src":"3570:59:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f706520636f6e74726163742e61646472","id":347,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3651:28:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},"value":"parent scope contract.addr"},{"arguments":[{"id":350,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3689:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":349,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3681:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":348,"name":"address","nodeType":"ElementaryTypeName","src":"3681:7:0","typeDescriptions":{}}},"id":351,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3681:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":344,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3639:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":346,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3639:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":352,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3639:56:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":353,"nodeType":"ExpressionStatement","src":"3639:56:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2032","id":357,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3716:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""},"value":"from prank 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""}],"expression":{"id":354,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3705:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":356,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3705:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":358,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3705:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":359,"nodeType":"ExpressionStatement","src":"3705:26:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":360,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3741:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":362,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopPrank","nodeType":"MemberAccess","referencedDeclaration":35,"src":"3741:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":363,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3741:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":364,"nodeType":"ExpressionStatement","src":"3741:14:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c20616761696e","id":368,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3776:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""},"value":"from original again"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""}],"expression":{"id":365,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3765:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":367,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3765:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":369,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3765:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":370,"nodeType":"ExpressionStatement","src":"3765:33:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":374,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3821:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":371,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3809:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":373,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"3809:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":375,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3809:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":376,"nodeType":"ExpressionStatement","src":"3809:20:0"}]},"documentation":{"id":216,"nodeType":"StructuredDocumentation","src":"2804:78:0","text":"@notice example function, runs through basic cheat-codes and console logs."},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"2896:3:0","parameters":{"id":217,"nodeType":"ParameterList","parameters":[],"src":"2899:2:0"},"returnParameters":{"id":218,"nodeType":"ParameterList","parameters":[],"src":"2909:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":609,"nodeType":"FunctionDefinition","src":"3903:1258:0","nodes":[],"body":{"id":608,"nodeType":"Block","src":"3934:1227:0","nodes":[],"statements":[{"expression":{"arguments":[{"hexValue":"6e6f6e6365207374617274","id":385,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3956:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},"value":"nonce start"},{"arguments":[{"arguments":[{"arguments":[{"id":392,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3999:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":391,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3991:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":390,"name":"address","nodeType":"ElementaryTypeName","src":"3991:7:0","typeDescriptions":{}}},"id":393,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3991:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":388,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3979:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":389,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3979:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":394,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3979:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":387,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3971:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":386,"name":"uint256","nodeType":"ElementaryTypeName","src":"3971:7:0","typeDescriptions":{}}},"id":395,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3971:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":382,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3944:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":384,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"3944:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":396,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3944:63:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":397,"nodeType":"ExpressionStatement","src":"3944:63:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073696e676c65","id":401,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4030:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""},"value":"testing single"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""}],"expression":{"id":398,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4018:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":400,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4018:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":402,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4018:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":403,"nodeType":"ExpressionStatement","src":"4018:29:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":404,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4057:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":406,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"4057:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":407,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4057:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":408,"nodeType":"ExpressionStatement","src":"4057:14:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c31","id":412,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4092:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""},"value":"single_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""}],"expression":{"id":409,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4081:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":411,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":648,"src":"4081:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":413,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4081:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":414,"nodeType":"ExpressionStatement","src":"4081:26:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c32","id":418,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4128:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""},"value":"single_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""}],"expression":{"id":415,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4117:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":417,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":663,"src":"4117:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":419,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4117:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":420,"nodeType":"ExpressionStatement","src":"4117:26:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073746172742f73746f70","id":424,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4166:20:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""},"value":"testing start/stop"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""}],"expression":{"id":421,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4154:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":423,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4154:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":425,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4154:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":426,"nodeType":"ExpressionStatement","src":"4154:33:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078633066666565","id":434,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4231:8:0","typeDescriptions":{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"},"value":"0xc0ffee"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"}],"id":433,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4223:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":432,"name":"uint160","nodeType":"ElementaryTypeName","src":"4223:7:0","typeDescriptions":{}}},"id":435,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4223:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":431,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4215:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":430,"name":"address","nodeType":"ElementaryTypeName","src":"4215:7:0","typeDescriptions":{}}},"id":436,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4215:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":427,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4197:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":429,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"4197:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":437,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4197:45:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":438,"nodeType":"ExpressionStatement","src":"4197:45:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c31","id":442,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4263:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""},"value":"startstop_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""}],"expression":{"id":439,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4252:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":441,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":648,"src":"4252:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":443,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4252:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":444,"nodeType":"ExpressionStatement","src":"4252:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c32","id":448,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4302:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""},"value":"startstop_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""}],"expression":{"id":445,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4291:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":447,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":663,"src":"4291:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":449,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4291:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":450,"nodeType":"ExpressionStatement","src":"4291:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f70757265","id":454,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4344:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""},"value":"startstop_pure"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""}],"expression":{"id":451,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4330:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":453,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"callPure","nodeType":"MemberAccess","referencedDeclaration":705,"src":"4330:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure external"}},"id":455,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4330:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":456,"nodeType":"ExpressionStatement","src":"4330:31:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":457,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4371:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":459,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"4371:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":460,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4371:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":461,"nodeType":"ExpressionStatement","src":"4371:18:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c33","id":465,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4410:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""},"value":"startstop_call3"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""}],"expression":{"id":462,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4399:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":464,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":648,"src":"4399:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":466,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4399:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":467,"nodeType":"ExpressionStatement","src":"4399:29:0"},{"expression":{"arguments":[{"hexValue":"74657374696e67206e6573746564","id":471,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4451:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""},"value":"testing nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""}],"expression":{"id":468,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4439:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":470,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4439:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":472,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4439:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":473,"nodeType":"ExpressionStatement","src":"4439:29:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307831323334","id":481,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4512:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":480,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4504:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":479,"name":"uint160","nodeType":"ElementaryTypeName","src":"4504:7:0","typeDescriptions":{}}},"id":482,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4504:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":478,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4496:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":477,"name":"address","nodeType":"ElementaryTypeName","src":"4496:7:0","typeDescriptions":{}}},"id":483,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4496:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":474,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4478:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":476,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"4478:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":484,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4478:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":485,"nodeType":"ExpressionStatement","src":"4478:43:0"},{"expression":{"arguments":[{"hexValue":"6e6573746564","id":489,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4544:8:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""},"value":"nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""}],"expression":{"id":486,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4531:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":488,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested1","nodeType":"MemberAccess","referencedDeclaration":678,"src":"4531:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":490,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4531:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":491,"nodeType":"ExpressionStatement","src":"4531:22:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":492,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4563:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":494,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"4563:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":495,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4563:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":496,"nodeType":"ExpressionStatement","src":"4563:18:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206465706c6f796d656e74","id":500,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4604:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""},"value":"contract deployment"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""}],"expression":{"id":497,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4592:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":499,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4592:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":501,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4592:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":502,"nodeType":"ExpressionStatement","src":"4592:34:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078313233343536","id":510,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4665:8:0","typeDescriptions":{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"},"value":"0x123456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"}],"id":509,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4657:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":508,"name":"uint160","nodeType":"ElementaryTypeName","src":"4657:7:0","typeDescriptions":{}}},"id":511,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4657:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":507,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4649:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":506,"name":"address","nodeType":"ElementaryTypeName","src":"4649:7:0","typeDescriptions":{}}},"id":512,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4649:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":503,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4636:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":505,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"4636:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":513,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4636:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":514,"nodeType":"ExpressionStatement","src":"4636:40:0"},{"assignments":[517],"declarations":[{"constant":false,"id":517,"mutability":"mutable","name":"x","nameLocation":"4693:1:0","nodeType":"VariableDeclaration","scope":608,"src":"4686:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"},"typeName":{"id":516,"nodeType":"UserDefinedTypeName","pathNode":{"id":515,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4686:6:0"},"referencedDeclaration":719,"src":"4686:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"visibility":"internal"}],"id":523,"initialValue":{"arguments":[{"hexValue":"31323334","id":521,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4708:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":520,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"4697:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":519,"nodeType":"UserDefinedTypeName","pathNode":{"id":518,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4701:6:0"},"referencedDeclaration":719,"src":"4701:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}}},"id":522,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4697:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"4686:27:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":529,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":525,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"4731:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"id":526,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":708,"src":"4731:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":527,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4731:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":528,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4742:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"4731:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"}],"id":524,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"4723:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$returns$__$","typeString":"function (bool) pure"}},"id":530,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4723:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":531,"nodeType":"ExpressionStatement","src":"4723:24:0"},{"expression":{"arguments":[{"hexValue":"6372656174652032","id":535,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4770:10:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""},"value":"create 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""}],"expression":{"id":532,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4758:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":534,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4758:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":536,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4758:23:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":537,"nodeType":"ExpressionStatement","src":"4758:23:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307863616665","id":545,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4820:6:0","typeDescriptions":{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"},"value":"0xcafe"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"}],"id":544,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4812:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":543,"name":"uint160","nodeType":"ElementaryTypeName","src":"4812:7:0","typeDescriptions":{}}},"id":546,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4812:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":542,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4804:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":541,"name":"address","nodeType":"ElementaryTypeName","src":"4804:7:0","typeDescriptions":{}}},"id":547,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4804:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":538,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4791:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":540,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"4791:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":548,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4791:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":549,"nodeType":"ExpressionStatement","src":"4791:38:0"},{"assignments":[552],"declarations":[{"constant":false,"id":552,"mutability":"mutable","name":"y","nameLocation":"4846:1:0","nodeType":"VariableDeclaration","scope":608,"src":"4839:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"},"typeName":{"id":551,"nodeType":"UserDefinedTypeName","pathNode":{"id":550,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4839:6:0"},"referencedDeclaration":719,"src":"4839:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"visibility":"internal"}],"id":566,"initialValue":{"arguments":[{"hexValue":"31323334","id":564,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4889:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":555,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"4850:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":554,"nodeType":"UserDefinedTypeName","pathNode":{"id":553,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4854:6:0"},"referencedDeclaration":719,"src":"4854:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}}},"id":563,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"names":["salt"],"nodeType":"FunctionCallOptions","options":[{"arguments":[{"arguments":[{"hexValue":"3432","id":560,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4883:2:0","typeDescriptions":{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"},"value":"42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"}],"id":559,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4875:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":558,"name":"uint256","nodeType":"ElementaryTypeName","src":"4875:7:0","typeDescriptions":{}}},"id":561,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4875:11:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":557,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4867:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":556,"name":"bytes32","nodeType":"ElementaryTypeName","src":"4867:7:0","typeDescriptions":{}}},"id":562,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4867:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"src":"4850:38:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$salt","typeString":"function (uint256) returns (contract FooBar)"}},"id":565,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4850:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"4839:55:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":572,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":568,"name":"y","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":552,"src":"4912:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"id":569,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":708,"src":"4912:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":570,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4912:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":571,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4923:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"4912:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"}],"id":567,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"4904:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$returns$__$","typeString":"function (bool) pure"}},"id":573,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4904:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":574,"nodeType":"ExpressionStatement","src":"4904:24:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":578,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4950:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":575,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4938:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":577,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4938:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":579,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4938:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":580,"nodeType":"ExpressionStatement","src":"4938:20:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":581,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"5042:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":583,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"5042:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":584,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5042:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":585,"nodeType":"ExpressionStatement","src":"5042:14:0"},{"expression":{"arguments":[{"hexValue":"31323334","id":589,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5077:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":588,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5066:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":587,"nodeType":"UserDefinedTypeName","pathNode":{"id":586,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"5070:6:0"},"referencedDeclaration":719,"src":"5070:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}}},"id":590,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5066:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"id":591,"nodeType":"ExpressionStatement","src":"5066:16:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e636520656e64","id":595,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5105:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},"value":"nonce end"},{"arguments":[{"arguments":[{"arguments":[{"id":602,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5146:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":601,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5138:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":600,"name":"address","nodeType":"ElementaryTypeName","src":"5138:7:0","typeDescriptions":{}}},"id":603,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5138:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":598,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"5126:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":599,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"5126:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":604,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5126:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":597,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5118:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":596,"name":"uint256","nodeType":"ElementaryTypeName","src":"5118:7:0","typeDescriptions":{}}},"id":605,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5118:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":592,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5093:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":594,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"5093:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":606,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5093:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":607,"nodeType":"ExpressionStatement","src":"5093:61:0"}]},"documentation":{"id":379,"nodeType":"StructuredDocumentation","src":"3842:56:0","text":"@notice example function, to test vm.broadcast with."},"functionSelector":"bef03abc","implemented":true,"kind":"function","modifiers":[],"name":"runBroadcast","nameLocation":"3912:12:0","parameters":{"id":380,"nodeType":"ParameterList","parameters":[],"src":"3924:2:0"},"returnParameters":{"id":381,"nodeType":"ParameterList","parameters":[],"src":"3934:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":633,"nodeType":"FunctionDefinition","src":"5256:143:0","nodes":[],"body":{"id":632,"nodeType":"Block","src":"5305:94:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":618,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":612,"src":"5327:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":615,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5315:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":617,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5315:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":619,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5315:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":620,"nodeType":"ExpressionStatement","src":"5315:15:0"},{"expression":{"arguments":[{"hexValue":"68656c6c6f206d73672e73656e646572","id":624,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5352:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},"value":"hello msg.sender"},{"arguments":[{"expression":{"id":627,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"5380:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":628,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"5380:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":626,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5372:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":625,"name":"address","nodeType":"ElementaryTypeName","src":"5372:7:0","typeDescriptions":{}}},"id":629,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5372:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":621,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5340:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":623,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"5340:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":630,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5340:52:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":631,"nodeType":"ExpressionStatement","src":"5340:52:0"}]},"documentation":{"id":610,"nodeType":"StructuredDocumentation","src":"5167:84:0","text":"@notice example external function, to force a CALL, and test vm.startPrank with."},"functionSelector":"a777d0dc","implemented":true,"kind":"function","modifiers":[],"name":"hello","nameLocation":"5265:5:0","parameters":{"id":613,"nodeType":"ParameterList","parameters":[{"constant":false,"id":612,"mutability":"mutable","name":"_v","nameLocation":"5287:2:0","nodeType":"VariableDeclaration","scope":633,"src":"5271:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":611,"name":"string","nodeType":"ElementaryTypeName","src":"5271:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5270:20:0"},"returnParameters":{"id":614,"nodeType":"ParameterList","parameters":[],"src":"5305:0:0"},"scope":706,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":648,"nodeType":"FunctionDefinition","src":"5405:95:0","nodes":[],"body":{"id":647,"nodeType":"Block","src":"5449:51:0","nodes":[],"statements":[{"expression":{"id":639,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5459:9:0","subExpression":{"id":638,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5459:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":640,"nodeType":"ExpressionStatement","src":"5459:9:0"},{"expression":{"arguments":[{"id":644,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":635,"src":"5490:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":641,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5478:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":643,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5478:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":645,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5478:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":646,"nodeType":"ExpressionStatement","src":"5478:15:0"}]},"functionSelector":"7e79255d","implemented":true,"kind":"function","modifiers":[],"name":"call1","nameLocation":"5414:5:0","parameters":{"id":636,"nodeType":"ParameterList","parameters":[{"constant":false,"id":635,"mutability":"mutable","name":"_v","nameLocation":"5436:2:0","nodeType":"VariableDeclaration","scope":648,"src":"5420:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":634,"name":"string","nodeType":"ElementaryTypeName","src":"5420:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5419:20:0"},"returnParameters":{"id":637,"nodeType":"ParameterList","parameters":[],"src":"5449:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":663,"nodeType":"FunctionDefinition","src":"5506:95:0","nodes":[],"body":{"id":662,"nodeType":"Block","src":"5550:51:0","nodes":[],"statements":[{"expression":{"id":654,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5560:9:0","subExpression":{"id":653,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5560:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":655,"nodeType":"ExpressionStatement","src":"5560:9:0"},{"expression":{"arguments":[{"id":659,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":650,"src":"5591:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":656,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5579:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":658,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5579:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":660,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5579:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":661,"nodeType":"ExpressionStatement","src":"5579:15:0"}]},"functionSelector":"8d3ef7ca","implemented":true,"kind":"function","modifiers":[],"name":"call2","nameLocation":"5515:5:0","parameters":{"id":651,"nodeType":"ParameterList","parameters":[{"constant":false,"id":650,"mutability":"mutable","name":"_v","nameLocation":"5537:2:0","nodeType":"VariableDeclaration","scope":663,"src":"5521:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":649,"name":"string","nodeType":"ElementaryTypeName","src":"5521:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5520:20:0"},"returnParameters":{"id":652,"nodeType":"ParameterList","parameters":[],"src":"5550:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":678,"nodeType":"FunctionDefinition","src":"5607:98:0","nodes":[],"body":{"id":677,"nodeType":"Block","src":"5653:52:0","nodes":[],"statements":[{"expression":{"id":669,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5663:9:0","subExpression":{"id":668,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5663:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":670,"nodeType":"ExpressionStatement","src":"5663:9:0"},{"expression":{"arguments":[{"id":674,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":665,"src":"5695:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":671,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5682:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":673,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested2","nodeType":"MemberAccess","referencedDeclaration":693,"src":"5682:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":675,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5682:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":676,"nodeType":"ExpressionStatement","src":"5682:16:0"}]},"functionSelector":"a76ccdfa","implemented":true,"kind":"function","modifiers":[],"name":"nested1","nameLocation":"5616:7:0","parameters":{"id":666,"nodeType":"ParameterList","parameters":[{"constant":false,"id":665,"mutability":"mutable","name":"_v","nameLocation":"5640:2:0","nodeType":"VariableDeclaration","scope":678,"src":"5624:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":664,"name":"string","nodeType":"ElementaryTypeName","src":"5624:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5623:20:0"},"returnParameters":{"id":667,"nodeType":"ParameterList","parameters":[],"src":"5653:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":693,"nodeType":"FunctionDefinition","src":"5711:97:0","nodes":[],"body":{"id":692,"nodeType":"Block","src":"5757:51:0","nodes":[],"statements":[{"expression":{"id":684,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5767:9:0","subExpression":{"id":683,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5767:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":685,"nodeType":"ExpressionStatement","src":"5767:9:0"},{"expression":{"arguments":[{"id":689,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":680,"src":"5798:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":686,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5786:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":688,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5786:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":690,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5786:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":691,"nodeType":"ExpressionStatement","src":"5786:15:0"}]},"functionSelector":"dbf1282f","implemented":true,"kind":"function","modifiers":[],"name":"nested2","nameLocation":"5720:7:0","parameters":{"id":681,"nodeType":"ParameterList","parameters":[{"constant":false,"id":680,"mutability":"mutable","name":"_v","nameLocation":"5744:2:0","nodeType":"VariableDeclaration","scope":693,"src":"5728:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":679,"name":"string","nodeType":"ElementaryTypeName","src":"5728:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5727:20:0"},"returnParameters":{"id":682,"nodeType":"ParameterList","parameters":[],"src":"5757:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":705,"nodeType":"FunctionDefinition","src":"5814:84:0","nodes":[],"body":{"id":704,"nodeType":"Block","src":"5866:32:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":701,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":695,"src":"5888:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":698,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5876:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":700,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5876:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":702,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5876:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":703,"nodeType":"ExpressionStatement","src":"5876:15:0"}]},"functionSelector":"7f8b915c","implemented":true,"kind":"function","modifiers":[],"name":"callPure","nameLocation":"5823:8:0","parameters":{"id":696,"nodeType":"ParameterList","parameters":[{"constant":false,"id":695,"mutability":"mutable","name":"_v","nameLocation":"5848:2:0","nodeType":"VariableDeclaration","scope":705,"src":"5832:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":694,"name":"string","nodeType":"ElementaryTypeName","src":"5832:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5831:20:0"},"returnParameters":{"id":697,"nodeType":"ParameterList","parameters":[],"src":"5866:0:0"},"scope":706,"stateMutability":"pure","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ScriptExample","contractDependencies":[719],"contractKind":"contract","documentation":{"id":193,"nodeType":"StructuredDocumentation","src":"2415:126:0","text":"@title ScriptExample\n @notice ScriptExample is an example script. The Go forge script code tests that it can run this."},"fullyImplemented":true,"linearizedBaseContracts":[706],"name":"ScriptExample","nameLocation":"2550:13:0","scope":720,"usedErrors":[]},{"id":719,"nodeType":"ContractDefinition","src":"5902:96:0","nodes":[{"id":708,"nodeType":"VariableDeclaration","src":"5924:18:0","nodes":[],"constant":false,"functionSelector":"c2985578","mutability":"mutable","name":"foo","nameLocation":"5939:3:0","scope":719,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":707,"name":"uint256","nodeType":"ElementaryTypeName","src":"5924:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":718,"nodeType":"FunctionDefinition","src":"5949:47:0","nodes":[],"body":{"id":717,"nodeType":"Block","src":"5972:24:0","nodes":[],"statements":[{"expression":{"id":715,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":713,"name":"foo","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":708,"src":"5982:3:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":714,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":710,"src":"5988:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"5982:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":716,"nodeType":"ExpressionStatement","src":"5982:7:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":711,"nodeType":"ParameterList","parameters":[{"constant":false,"id":710,"mutability":"mutable","name":"v","nameLocation":"5969:1:0","nodeType":"VariableDeclaration","scope":718,"src":"5961:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":709,"name":"uint256","nodeType":"ElementaryTypeName","src":"5961:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"5960:11:0"},"returnParameters":{"id":712,"nodeType":"ParameterList","parameters":[],"src":"5972:0:0"},"scope":719,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"FooBar","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[719],"name":"FooBar","nameLocation":"5911:6:0","scope":720,"usedErrors":[]}],"license":"MIT"},"id":0} \ No newline at end of file +{"abi":[{"type":"function","name":"call1","inputs":[{"name":"_v","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"call2","inputs":[{"name":"_v","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"callPure","inputs":[{"name":"_v","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"pure"},{"type":"function","name":"counter","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"hello","inputs":[{"name":"_v","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"view"},{"type":"function","name":"nested1","inputs":[{"name":"_v","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"nested2","inputs":[{"name":"_v","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"run","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"runBroadcast","inputs":[],"outputs":[],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x608060405234801561001057600080fd5b506124b2806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c8063a76ccdfa11610076578063bef03abc1161005b578063bef03abc14610111578063c040622614610119578063dbf1282f146100c357600080fd5b8063a76ccdfa146100eb578063a777d0dc146100fe57600080fd5b806361bc221a146100a85780637e79255d146100c35780637f8b915c146100d85780638d3ef7ca146100c3575b600080fd5b6100b160005481565b60405190815260200160405180910390f35b6100d66100d1366004611e15565b610121565b005b6100d66100e6366004611e15565b610178565b6100d66100f9366004611e15565b6101b7565b6100d661010c366004611e15565b61023f565b6100d66102bd565b6100d661105f565b60008054908061013083611e87565b919050555061017482828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b0792505050565b5050565b61017482828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b0792505050565b6000805490806101c683611e87565b90915550506040517fdbf1282f000000000000000000000000000000000000000000000000000000008152309063dbf1282f906102099085908590600401611ee6565b600060405180830381600087803b15801561022357600080fd5b505af1158015610237573d6000803e3d6000fd5b505050505050565b61027e82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b0792505050565b6101746040518060400160405280601081526020017f68656c6c6f206d73672e73656e6465720000000000000000000000000000000081525033611b99565b604080518082018252600b81527f6e6f6e6365207374617274000000000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523060048201526103909190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab906024015b602060405180830381865afa15801561035d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103819190611f33565b67ffffffffffffffff16611c2a565b6103ce6040518060400160405280600e81526020017f74657374696e672073696e676c65000000000000000000000000000000000000815250611b07565b7f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff1663afc980406040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561043957600080fd5b505af115801561044d573d6000803e3d6000fd5b50506040517f7e79255d00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f73696e676c655f63616c6c3100000000000000000000000000000000000000006044820152309250637e79255d9150606401600060405180830381600087803b1580156104d057600080fd5b505af11580156104e4573d6000803e3d6000fd5b50506040517f8d3ef7ca00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f73696e676c655f63616c6c3200000000000000000000000000000000000000006044820152309250638d3ef7ca9150606401600060405180830381600087803b15801561056757600080fd5b505af115801561057b573d6000803e3d6000fd5b505050506105bd6040518060400160405280601281526020017f74657374696e672073746172742f73746f700000000000000000000000000000815250611b07565b6040517f7fec2a8d00000000000000000000000000000000000000000000000000000000815262c0ffee6004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90637fec2a8d90602401600060405180830381600087803b15801561062557600080fd5b505af1158015610639573d6000803e3d6000fd5b50506040517f7e79255d00000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f737461727473746f705f63616c6c3100000000000000000000000000000000006044820152309250637e79255d9150606401600060405180830381600087803b1580156106bc57600080fd5b505af11580156106d0573d6000803e3d6000fd5b50506040517f8d3ef7ca00000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f737461727473746f705f63616c6c3200000000000000000000000000000000006044820152309250638d3ef7ca9150606401600060405180830381600087803b15801561075357600080fd5b505af1158015610767573d6000803e3d6000fd5b50506040517f7f8b915c00000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f737461727473746f705f707572650000000000000000000000000000000000006044820152309250637f8b915c915060640160006040518083038186803b1580156107e857600080fd5b505afa1580156107fc573d6000803e3d6000fd5b505050507f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff166376eadd366040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561086b57600080fd5b505af115801561087f573d6000803e3d6000fd5b50506040517f7e79255d00000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f737461727473746f705f63616c6c3300000000000000000000000000000000006044820152309250637e79255d9150606401600060405180830381600087803b15801561090257600080fd5b505af1158015610916573d6000803e3d6000fd5b505050506109586040518060400160405280600e81526020017f74657374696e67206e6573746564000000000000000000000000000000000000815250611b07565b6040517f7fec2a8d0000000000000000000000000000000000000000000000000000000081526112346004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90637fec2a8d90602401600060405180830381600087803b1580156109bf57600080fd5b505af11580156109d3573d6000803e3d6000fd5b50506040517fa76ccdfa00000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f6e65737465640000000000000000000000000000000000000000000000000000604482015230925063a76ccdfa9150606401600060405180830381600087803b158015610a5657600080fd5b505af1158015610a6a573d6000803e3d6000fd5b505050507f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff166376eadd366040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610ad957600080fd5b505af1158015610aed573d6000803e3d6000fd5b50505050610b2f6040518060400160405280601381526020017f636f6e7472616374206465706c6f796d656e7400000000000000000000000000815250611b07565b6040517fe6962cdb000000000000000000000000000000000000000000000000000000008152621234566004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d9063e6962cdb90602401600060405180830381600087803b158015610b9757600080fd5b505af1158015610bab573d6000803e3d6000fd5b5050505060006104d2604051610bc090611e09565b908152602001604051809103906000f080158015610be2573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c29855786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c549190611f64565b6104d214610ce9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f466f6f4261723a20666f6f20696e20637265617465206973206e6f742031323360448201527f340000000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610d276040518060400160405280600881526020017f6372656174652032000000000000000000000000000000000000000000000000815250611b07565b6040517fe6962cdb00000000000000000000000000000000000000000000000000000000815261cafe6004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d9063e6962cdb90602401600060405180830381600087803b158015610d8e57600080fd5b505af1158015610da2573d6000803e3d6000fd5b505050506000602a60001b6104d2604051610dbc90611e09565b9081526020018190604051809103906000f5905080158015610de2573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c29855786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e549190611f64565b6104d214610ee4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f466f6f4261723a20666f6f20696e2063726561746532206973206e6f7420313260448201527f33340000000000000000000000000000000000000000000000000000000000006064820152608401610ce0565b610f226040518060400160405280600581526020017f646f6e6521000000000000000000000000000000000000000000000000000000815250611b07565b7f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff1663afc980406040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610f8d57600080fd5b505af1158015610fa1573d6000803e3d6000fd5b505050506104d2604051610fb490611e09565b908152602001604051809103906000f080158015610fd6573d6000803e3d6000fd5b5050604080518082018252600981527f6e6f6e636520656e640000000000000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523060048201526101749190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401610340565b604080517f4777f3cf0000000000000000000000000000000000000000000000000000000081526004810191909152600c60448201527f4558414d504c455f424f4f4c0000000000000000000000000000000000000000606482015260006024820181905290737109709ecfa91a80626ff3989d68f67f5b1dd12d90634777f3cf90608401602060405180830381865afa158015611101573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111259190611f7d565b90506111666040518060400160405280601381526020017f626f6f6c2076616c75652066726f6d20656e760000000000000000000000000081525082611cbb565b6111a56040518060400160405280600d81526020017f636f6e747261637420616464720000000000000000000000000000000000000081525030611b99565b604080518082018252600e81527f636f6e7472616374206e6f6e6365000000000000000000000000000000000000602082015290517f2d0335ab00000000000000000000000000000000000000000000000000000000815230600482015261122c9190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401610340565b61126b6040518060400160405280600b81526020017f73656e646572206164647200000000000000000000000000000000000000000081525033611b99565b604080518082018252600c81527f73656e646572206e6f6e63650000000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523360048201526112f29190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401610340565b60408051808201825260208082527f7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d9082015290517f213e4198000000000000000000000000000000000000000000000000000000008152600090737109709ecfa91a80626ff3989d68f67f5b1dd12d9063213e419890611377908590600401612019565b600060405180830381865afa158015611394573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526113da9190810190612156565b90506114506040518060400160405280600481526020017f6b65797300000000000000000000000000000000000000000000000000000000815250826000815181106114285761142861222e565b6020026020010151836001815181106114435761144361222e565b6020026020010151611d4c565b6040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f66726f6d206f726967696e616c000000000000000000000000000000000000006044820152309063a777d0dc9060640160006040518083038186803b1580156114cd57600080fd5b505afa1580156114e1573d6000803e3d6000fd5b50506040517f06447d5600000000000000000000000000000000000000000000000000000000815260426004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d92506306447d569150602401600060405180830381600087803b15801561154b57600080fd5b505af115801561155f573d6000803e3d6000fd5b50506040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f66726f6d207072616e6b20310000000000000000000000000000000000000000604482015230925063a777d0dc915060640160006040518083038186803b1580156115e057600080fd5b505afa1580156115f4573d6000803e3d6000fd5b505050506116376040518060400160405280601781526020017f706172656e742073636f7065206d73672e73656e64657200000000000000000081525033611b99565b6116766040518060400160405280601a81526020017f706172656e742073636f706520636f6e74726163742e6164647200000000000081525030611b99565b6040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f66726f6d207072616e6b203200000000000000000000000000000000000000006044820152309063a777d0dc9060640160006040518083038186803b1580156116f357600080fd5b505afa158015611707573d6000803e3d6000fd5b505050507f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff166390c5013b6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561177657600080fd5b505af115801561178a573d6000803e3d6000fd5b50506040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f66726f6d206f726967696e616c20616761696e00000000000000000000000000604482015230925063a777d0dc915060640160006040518083038186803b15801561180b57600080fd5b505afa15801561181f573d6000803e3d6000fd5b50506040517f3ebf73b400000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5363726970744578616d706c652e732e736f6c3a4e6f6e63654765747465720060448201527f12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a2529250737109709ecfa91a80626ff3989d68f67f5b1dd12d915063b4d6c7829083908390633ebf73b490606401600060405180830381865afa1580156118e5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261192b919081019061225d565b6040518363ffffffff1660e01b81526004016119489291906122ae565b600060405180830381600087803b15801561196257600080fd5b505af1158015611976573d6000803e3d6000fd5b50506040517fea06029100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d925063ea0602919150602401600060405180830381600087803b1580156119f557600080fd5b505af1158015611a09573d6000803e3d6000fd5b50506040517f2d0335ab0000000000000000000000000000000000000000000000000000000081523060048201526000925073ffffffffffffffffffffffffffffffffffffffff84169150632d0335ab90602401602060405180830381865afa158015611a7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9e9190611f64565b9050611ac26040518060800160405280604281526020016124646042913982611c2a565b611b006040518060400160405280600581526020017f646f6e6521000000000000000000000000000000000000000000000000000000815250611b07565b5050505050565b611b9681604051602401611b1b91906122dd565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f41304fac00000000000000000000000000000000000000000000000000000000179052611de4565b50565b6101748282604051602401611baf9291906122f0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f319af33300000000000000000000000000000000000000000000000000000000179052611de4565b6101748282604051602401611c40929190612328565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb60e72cc00000000000000000000000000000000000000000000000000000000179052611de4565b6101748282604051602401611cd192919061234a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fc3b5563500000000000000000000000000000000000000000000000000000000179052611de4565b611ddf838383604051602401611d649392919061236e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f2ced7cef00000000000000000000000000000000000000000000000000000000179052611de4565b505050565b611b968180516a636f6e736f6c652e6c6f67602083016000808483855afa5050505050565b60b2806123b283390190565b60008060208385031215611e2857600080fd5b823567ffffffffffffffff80821115611e4057600080fd5b818501915085601f830112611e5457600080fd5b813581811115611e6357600080fd5b866020828501011115611e7557600080fd5b60209290920196919550909350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611edf577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b600060208284031215611f4557600080fd5b815167ffffffffffffffff81168114611f5d57600080fd5b9392505050565b600060208284031215611f7657600080fd5b5051919050565b600060208284031215611f8f57600080fd5b81518015158114611f5d57600080fd5b60005b83811015611fba578181015183820152602001611fa2565b83811115611fc9576000848401525b50505050565b60008151808452611fe7816020860160208601611f9f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60408152600061202c6040830184611fcf565b8281036020840152600c81527f2e726f6f745f6b65795b305d000000000000000000000000000000000000000060208201526040810191505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156120e1576120e161206b565b604052919050565b600067ffffffffffffffff8311156121035761210361206b565b61213460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8601160161209a565b905082815283838301111561214857600080fd5b611f5d836020830184611f9f565b6000602080838503121561216957600080fd5b825167ffffffffffffffff8082111561218157600080fd5b818501915085601f83011261219557600080fd5b8151818111156121a7576121a761206b565b8060051b6121b685820161209a565b91825283810185019185810190898411156121d057600080fd5b86860192505b83831015612221578251858111156121ee5760008081fd5b8601603f81018b136122005760008081fd5b6122118b89830151604084016120e9565b83525091860191908601906121d6565b9998505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561226f57600080fd5b815167ffffffffffffffff81111561228657600080fd5b8201601f8101841361229757600080fd5b6122a6848251602084016120e9565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006122a66040830184611fcf565b602081526000611f5d6020830184611fcf565b6040815260006123036040830185611fcf565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b60408152600061233b6040830185611fcf565b90508260208301529392505050565b60408152600061235d6040830185611fcf565b905082151560208301529392505050565b6060815260006123816060830186611fcf565b82810360208401526123938186611fcf565b905082810360408401526123a78185611fcf565b969550505050505056fe608060405234801561001057600080fd5b506040516100b23803806100b283398101604081905261002f91610037565b600055610050565b60006020828403121561004957600080fd5b5051919050565b60548061005e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c298557814602d575b600080fd5b603560005481565b60405190815260200160405180910390f3fea164736f6c634300080f000a6e6f6e63652066726f6d206e6f6e6365206765747465722c206e6f206578706c6963697420616363657373207265717569726564207769746820766d2e657463683aa164736f6c634300080f000a","sourceMap":"3123:3912:0:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b50600436106100a35760003560e01c8063a76ccdfa11610076578063bef03abc1161005b578063bef03abc14610111578063c040622614610119578063dbf1282f146100c357600080fd5b8063a76ccdfa146100eb578063a777d0dc146100fe57600080fd5b806361bc221a146100a85780637e79255d146100c35780637f8b915c146100d85780638d3ef7ca146100c3575b600080fd5b6100b160005481565b60405190815260200160405180910390f35b6100d66100d1366004611e15565b610121565b005b6100d66100e6366004611e15565b610178565b6100d66100f9366004611e15565b6101b7565b6100d661010c366004611e15565b61023f565b6100d66102bd565b6100d661105f565b60008054908061013083611e87565b919050555061017482828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b0792505050565b5050565b61017482828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b0792505050565b6000805490806101c683611e87565b90915550506040517fdbf1282f000000000000000000000000000000000000000000000000000000008152309063dbf1282f906102099085908590600401611ee6565b600060405180830381600087803b15801561022357600080fd5b505af1158015610237573d6000803e3d6000fd5b505050505050565b61027e82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b0792505050565b6101746040518060400160405280601081526020017f68656c6c6f206d73672e73656e6465720000000000000000000000000000000081525033611b99565b604080518082018252600b81527f6e6f6e6365207374617274000000000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523060048201526103909190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab906024015b602060405180830381865afa15801561035d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103819190611f33565b67ffffffffffffffff16611c2a565b6103ce6040518060400160405280600e81526020017f74657374696e672073696e676c65000000000000000000000000000000000000815250611b07565b7f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff1663afc980406040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561043957600080fd5b505af115801561044d573d6000803e3d6000fd5b50506040517f7e79255d00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f73696e676c655f63616c6c3100000000000000000000000000000000000000006044820152309250637e79255d9150606401600060405180830381600087803b1580156104d057600080fd5b505af11580156104e4573d6000803e3d6000fd5b50506040517f8d3ef7ca00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f73696e676c655f63616c6c3200000000000000000000000000000000000000006044820152309250638d3ef7ca9150606401600060405180830381600087803b15801561056757600080fd5b505af115801561057b573d6000803e3d6000fd5b505050506105bd6040518060400160405280601281526020017f74657374696e672073746172742f73746f700000000000000000000000000000815250611b07565b6040517f7fec2a8d00000000000000000000000000000000000000000000000000000000815262c0ffee6004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90637fec2a8d90602401600060405180830381600087803b15801561062557600080fd5b505af1158015610639573d6000803e3d6000fd5b50506040517f7e79255d00000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f737461727473746f705f63616c6c3100000000000000000000000000000000006044820152309250637e79255d9150606401600060405180830381600087803b1580156106bc57600080fd5b505af11580156106d0573d6000803e3d6000fd5b50506040517f8d3ef7ca00000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f737461727473746f705f63616c6c3200000000000000000000000000000000006044820152309250638d3ef7ca9150606401600060405180830381600087803b15801561075357600080fd5b505af1158015610767573d6000803e3d6000fd5b50506040517f7f8b915c00000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f737461727473746f705f707572650000000000000000000000000000000000006044820152309250637f8b915c915060640160006040518083038186803b1580156107e857600080fd5b505afa1580156107fc573d6000803e3d6000fd5b505050507f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff166376eadd366040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561086b57600080fd5b505af115801561087f573d6000803e3d6000fd5b50506040517f7e79255d00000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f737461727473746f705f63616c6c3300000000000000000000000000000000006044820152309250637e79255d9150606401600060405180830381600087803b15801561090257600080fd5b505af1158015610916573d6000803e3d6000fd5b505050506109586040518060400160405280600e81526020017f74657374696e67206e6573746564000000000000000000000000000000000000815250611b07565b6040517f7fec2a8d0000000000000000000000000000000000000000000000000000000081526112346004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d90637fec2a8d90602401600060405180830381600087803b1580156109bf57600080fd5b505af11580156109d3573d6000803e3d6000fd5b50506040517fa76ccdfa00000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f6e65737465640000000000000000000000000000000000000000000000000000604482015230925063a76ccdfa9150606401600060405180830381600087803b158015610a5657600080fd5b505af1158015610a6a573d6000803e3d6000fd5b505050507f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff166376eadd366040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610ad957600080fd5b505af1158015610aed573d6000803e3d6000fd5b50505050610b2f6040518060400160405280601381526020017f636f6e7472616374206465706c6f796d656e7400000000000000000000000000815250611b07565b6040517fe6962cdb000000000000000000000000000000000000000000000000000000008152621234566004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d9063e6962cdb90602401600060405180830381600087803b158015610b9757600080fd5b505af1158015610bab573d6000803e3d6000fd5b5050505060006104d2604051610bc090611e09565b908152602001604051809103906000f080158015610be2573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c29855786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c549190611f64565b6104d214610ce9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f466f6f4261723a20666f6f20696e20637265617465206973206e6f742031323360448201527f340000000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b610d276040518060400160405280600881526020017f6372656174652032000000000000000000000000000000000000000000000000815250611b07565b6040517fe6962cdb00000000000000000000000000000000000000000000000000000000815261cafe6004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d9063e6962cdb90602401600060405180830381600087803b158015610d8e57600080fd5b505af1158015610da2573d6000803e3d6000fd5b505050506000602a60001b6104d2604051610dbc90611e09565b9081526020018190604051809103906000f5905080158015610de2573d6000803e3d6000fd5b5090508073ffffffffffffffffffffffffffffffffffffffff1663c29855786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e549190611f64565b6104d214610ee4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f466f6f4261723a20666f6f20696e2063726561746532206973206e6f7420313260448201527f33340000000000000000000000000000000000000000000000000000000000006064820152608401610ce0565b610f226040518060400160405280600581526020017f646f6e6521000000000000000000000000000000000000000000000000000000815250611b07565b7f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff1663afc980406040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610f8d57600080fd5b505af1158015610fa1573d6000803e3d6000fd5b505050506104d2604051610fb490611e09565b908152602001604051809103906000f080158015610fd6573d6000803e3d6000fd5b5050604080518082018252600981527f6e6f6e636520656e640000000000000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523060048201526101749190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401610340565b604080517f4777f3cf0000000000000000000000000000000000000000000000000000000081526004810191909152600c60448201527f4558414d504c455f424f4f4c0000000000000000000000000000000000000000606482015260006024820181905290737109709ecfa91a80626ff3989d68f67f5b1dd12d90634777f3cf90608401602060405180830381865afa158015611101573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111259190611f7d565b90506111666040518060400160405280601381526020017f626f6f6c2076616c75652066726f6d20656e760000000000000000000000000081525082611cbb565b6111a56040518060400160405280600d81526020017f636f6e747261637420616464720000000000000000000000000000000000000081525030611b99565b604080518082018252600e81527f636f6e7472616374206e6f6e6365000000000000000000000000000000000000602082015290517f2d0335ab00000000000000000000000000000000000000000000000000000000815230600482015261122c9190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401610340565b61126b6040518060400160405280600b81526020017f73656e646572206164647200000000000000000000000000000000000000000081525033611b99565b604080518082018252600c81527f73656e646572206e6f6e63650000000000000000000000000000000000000000602082015290517f2d0335ab0000000000000000000000000000000000000000000000000000000081523360048201526112f29190737109709ecfa91a80626ff3989d68f67f5b1dd12d90632d0335ab90602401610340565b60408051808201825260208082527f7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d9082015290517f213e4198000000000000000000000000000000000000000000000000000000008152600090737109709ecfa91a80626ff3989d68f67f5b1dd12d9063213e419890611377908590600401612019565b600060405180830381865afa158015611394573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526113da9190810190612156565b90506114506040518060400160405280600481526020017f6b65797300000000000000000000000000000000000000000000000000000000815250826000815181106114285761142861222e565b6020026020010151836001815181106114435761144361222e565b6020026020010151611d4c565b6040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f66726f6d206f726967696e616c000000000000000000000000000000000000006044820152309063a777d0dc9060640160006040518083038186803b1580156114cd57600080fd5b505afa1580156114e1573d6000803e3d6000fd5b50506040517f06447d5600000000000000000000000000000000000000000000000000000000815260426004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d92506306447d569150602401600060405180830381600087803b15801561154b57600080fd5b505af115801561155f573d6000803e3d6000fd5b50506040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f66726f6d207072616e6b20310000000000000000000000000000000000000000604482015230925063a777d0dc915060640160006040518083038186803b1580156115e057600080fd5b505afa1580156115f4573d6000803e3d6000fd5b505050506116376040518060400160405280601781526020017f706172656e742073636f7065206d73672e73656e64657200000000000000000081525033611b99565b6116766040518060400160405280601a81526020017f706172656e742073636f706520636f6e74726163742e6164647200000000000081525030611b99565b6040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f66726f6d207072616e6b203200000000000000000000000000000000000000006044820152309063a777d0dc9060640160006040518083038186803b1580156116f357600080fd5b505afa158015611707573d6000803e3d6000fd5b505050507f885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d60001c73ffffffffffffffffffffffffffffffffffffffff166390c5013b6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561177657600080fd5b505af115801561178a573d6000803e3d6000fd5b50506040517fa777d0dc00000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f66726f6d206f726967696e616c20616761696e00000000000000000000000000604482015230925063a777d0dc915060640160006040518083038186803b15801561180b57600080fd5b505afa15801561181f573d6000803e3d6000fd5b50506040517f3ebf73b400000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5363726970744578616d706c652e732e736f6c3a4e6f6e63654765747465720060448201527f12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a2529250737109709ecfa91a80626ff3989d68f67f5b1dd12d915063b4d6c7829083908390633ebf73b490606401600060405180830381865afa1580156118e5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261192b919081019061225d565b6040518363ffffffff1660e01b81526004016119489291906122ae565b600060405180830381600087803b15801561196257600080fd5b505af1158015611976573d6000803e3d6000fd5b50506040517fea06029100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152737109709ecfa91a80626ff3989d68f67f5b1dd12d925063ea0602919150602401600060405180830381600087803b1580156119f557600080fd5b505af1158015611a09573d6000803e3d6000fd5b50506040517f2d0335ab0000000000000000000000000000000000000000000000000000000081523060048201526000925073ffffffffffffffffffffffffffffffffffffffff84169150632d0335ab90602401602060405180830381865afa158015611a7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a9e9190611f64565b9050611ac26040518060800160405280604281526020016124646042913982611c2a565b611b006040518060400160405280600581526020017f646f6e6521000000000000000000000000000000000000000000000000000000815250611b07565b5050505050565b611b9681604051602401611b1b91906122dd565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f41304fac00000000000000000000000000000000000000000000000000000000179052611de4565b50565b6101748282604051602401611baf9291906122f0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f319af33300000000000000000000000000000000000000000000000000000000179052611de4565b6101748282604051602401611c40929190612328565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fb60e72cc00000000000000000000000000000000000000000000000000000000179052611de4565b6101748282604051602401611cd192919061234a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fc3b5563500000000000000000000000000000000000000000000000000000000179052611de4565b611ddf838383604051602401611d649392919061236e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f2ced7cef00000000000000000000000000000000000000000000000000000000179052611de4565b505050565b611b968180516a636f6e736f6c652e6c6f67602083016000808483855afa5050505050565b60b2806123b283390190565b60008060208385031215611e2857600080fd5b823567ffffffffffffffff80821115611e4057600080fd5b818501915085601f830112611e5457600080fd5b813581811115611e6357600080fd5b866020828501011115611e7557600080fd5b60209290920196919550909350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611edf577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b600060208284031215611f4557600080fd5b815167ffffffffffffffff81168114611f5d57600080fd5b9392505050565b600060208284031215611f7657600080fd5b5051919050565b600060208284031215611f8f57600080fd5b81518015158114611f5d57600080fd5b60005b83811015611fba578181015183820152602001611fa2565b83811115611fc9576000848401525b50505050565b60008151808452611fe7816020860160208601611f9f565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60408152600061202c6040830184611fcf565b8281036020840152600c81527f2e726f6f745f6b65795b305d000000000000000000000000000000000000000060208201526040810191505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156120e1576120e161206b565b604052919050565b600067ffffffffffffffff8311156121035761210361206b565b61213460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8601160161209a565b905082815283838301111561214857600080fd5b611f5d836020830184611f9f565b6000602080838503121561216957600080fd5b825167ffffffffffffffff8082111561218157600080fd5b818501915085601f83011261219557600080fd5b8151818111156121a7576121a761206b565b8060051b6121b685820161209a565b91825283810185019185810190898411156121d057600080fd5b86860192505b83831015612221578251858111156121ee5760008081fd5b8601603f81018b136122005760008081fd5b6122118b89830151604084016120e9565b83525091860191908601906121d6565b9998505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561226f57600080fd5b815167ffffffffffffffff81111561228657600080fd5b8201601f8101841361229757600080fd5b6122a6848251602084016120e9565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006122a66040830184611fcf565b602081526000611f5d6020830184611fcf565b6040815260006123036040830185611fcf565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b60408152600061233b6040830185611fcf565b90508260208301529392505050565b60408152600061235d6040830185611fcf565b905082151560208301529392505050565b6060815260006123816060830186611fcf565b82810360208401526123938186611fcf565b905082810360408401526123a78185611fcf565b969550505050505056fe608060405234801561001057600080fd5b506040516100b23803806100b283398101604081905261002f91610037565b600055610050565b60006020828403121561004957600080fd5b5051919050565b60548061005e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c298557814602d575b600080fd5b603560005481565b60405190815260200160405180910390f3fea164736f6c634300080f000a6e6f6e63652066726f6d206e6f6e6365206765747465722c206e6f206578706c6963697420616363657373207265717569726564207769746820766d2e657463683aa164736f6c634300080f000a","sourceMap":"3123:3912:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3356:22;;;;;;;;;160:25:1;;;148:2;133:18;3356:22:0;;;;;;;6540:95;;;;;;:::i;:::-;;:::i;:::-;;6949:84;;;;;;:::i;:::-;;:::i;6742:98::-;;;;;;:::i;:::-;;:::i;6391:143::-;;;;;;:::i;:::-;;:::i;4963:1333::-;;;:::i;3468:1428::-;;;:::i;6540:95::-;6594:7;:9;;;:7;:9;;;:::i;:::-;;;;;;6613:15;6625:2;;6613:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6613:11:0;;-1:-1:-1;;;6613:15:0:i;:::-;6540:95;;:::o;6949:84::-;7011:15;7023:2;;7011:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;7011:11:0;;-1:-1:-1;;;7011:15:0:i;6742:98::-;6798:7;:9;;;:7;:9;;;:::i;:::-;;;;-1:-1:-1;;6817:16:0;;;;;:4;;:12;;:16;;6830:2;;;;6817:16;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6742:98;;:::o;6391:143::-;6450:15;6462:2;;6450:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6450:11:0;;-1:-1:-1;;;6450:15:0:i;:::-;6475:52;;;;;;;;;;;;;;;;;;6515:10;6475:11;:52::i;4963:1333::-;5004:63;;;;;;;;;;;;;;;;5039:26;;;;;5059:4;5039:26;;;1747:74:1;5004:63:0;;;5039:11;;;;1720:18:1;;5039:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5031:35;;5004:11;:63::i;:::-;5078:29;;;;;;;;;;;;;;;;;;:11;:29::i;:::-;3215:28;3207:37;;5117:12;;;:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5141:26:0;;;;;2327:2:1;5141:26:0;;;2309:21:1;2366:2;2346:18;;;2339:30;2405:14;2385:18;;;2378:42;5141:4:0;;-1:-1:-1;5141:10:0;;-1:-1:-1;2437:18:1;;5141:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5177:26:0;;;;;2668:2:1;5177:26:0;;;2650:21:1;2707:2;2687:18;;;2680:30;2746:14;2726:18;;;2719:42;5177:4:0;;-1:-1:-1;5177:10:0;;-1:-1:-1;2778:18:1;;5177:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5214:33;;;;;;;;;;;;;;;;;;:11;:33::i;:::-;5257:45;;;;;5291:8;5257:45;;;1747:74:1;5257:17:0;;;;1720:18:1;;5257:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5312:29:0;;;;;3009:2:1;5312:29:0;;;2991:21:1;3048:2;3028:18;;;3021:30;3087:17;3067:18;;;3060:45;5312:4:0;;-1:-1:-1;5312:10:0;;-1:-1:-1;3122:18:1;;5312:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5351:29:0;;;;;3353:2:1;5351:29:0;;;3335:21:1;3392:2;3372:18;;;3365:30;3431:17;3411:18;;;3404:45;5351:4:0;;-1:-1:-1;5351:10:0;;-1:-1:-1;3466:18:1;;5351:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5390:31:0;;;;;3697:2:1;5390:31:0;;;3679:21:1;3736:2;3716:18;;;3709:30;3775:16;3755:18;;;3748:44;5390:4:0;;-1:-1:-1;5390:13:0;;-1:-1:-1;3809:18:1;;5390:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3215:28;3207:37;;5431:16;;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5459:29:0;;;;;4040:2:1;5459:29:0;;;4022:21:1;4079:2;4059:18;;;4052:30;4118:17;4098:18;;;4091:45;5459:4:0;;-1:-1:-1;5459:10:0;;-1:-1:-1;4153:18:1;;5459:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5499;;;;;;;;;;;;;;;;;;:11;:29::i;:::-;5538:43;;;;;5572:6;5538:43;;;1747:74:1;5538:17:0;;;;1720:18:1;;5538:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5591:22:0;;;;;4384:2:1;5591:22:0;;;4366:21:1;4423:1;4403:18;;;4396:29;4461:8;4441:18;;;4434:36;5591:4:0;;-1:-1:-1;5591:12:0;;-1:-1:-1;4487:18:1;;5591:22:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3215:28;3207:37;;5623:16;;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5652:34;;;;;;;;;;;;;;;;;;:11;:34::i;:::-;5696:40;;;;;5725:8;5696:40;;;1747:74:1;5696:12:0;;;;1720:18:1;;5696:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5746:8;5768:4;5757:16;;;;;:::i;:::-;160:25:1;;;148:2;133:18;5757:16:0;;;;;;;;;;;;;;;;;;;;;;;5746:27;;5791:1;:5;;;:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5802:4;5791:15;5783:61;;;;;;;5100:2:1;5783:61:0;;;5082:21:1;5139:2;5119:18;;;5112:30;5178:34;5158:18;;;5151:62;5249:3;5229:18;;;5222:31;5270:19;;5783:61:0;;;;;;;;;5855:23;;;;;;;;;;;;;;;;;;:11;:23::i;:::-;5888:38;;;;;5917:6;5888:38;;;1747:74:1;5888:12:0;;;;1720:18:1;;5888:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5936:8;5980:2;5964:20;;5986:4;5947:44;;;;;:::i;:::-;160:25:1;;;148:2;133:18;5947:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;5936:55;;6009:1;:5;;;:7;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6020:4;6009:15;6001:62;;;;;;;5502:2:1;6001:62:0;;;5484:21:1;5541:2;5521:18;;;5514:30;5580:34;5560:18;;;5553:62;5651:4;5631:18;;;5624:32;5673:19;;6001:62:0;5300:398:1;6001:62:0;6073:20;;;;;;;;;;;;;;;;;;:11;:20::i;:::-;3215:28;3207:37;;6177:12;;;:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6212:4;6201:16;;;;;:::i;:::-;160:25:1;;;148:2;133:18;6201:16:0;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;6228:61:0;;;;;;;;;;;;;;;;6261:26;;;;;6281:4;6261:26;;;1747:74:1;6228:61:0;;;6261:11;;;;1720:18:1;;6261:26:0;1601:226:1;3468:1428:0;3509:31;;;;;;;;;5909:21:1;;;;5966:2;5946:18;;;5939:30;6005:14;5985:18;;;5978:42;3500:6:0;6072:20:1;;;6065:52;;;3500:6:0;3509:8;;;;6037:19:1;;3509:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3500:40;;3550:37;;;;;;;;;;;;;;;;;;3585:1;3550:11;:37::i;:::-;3598:43;;;;;;;;;;;;;;;;;;3635:4;3598:11;:43::i;:::-;3651:57;;;;;;;;;;;;;;;;3681:26;;;;;3701:4;3681:26;;;1747:74:1;3651:57:0;;;3681:11;;;;1720:18:1;;3681:26:0;1601:226:1;3651:57:0;3718:47;;;;;;;;;;;;;;;;;;3753:10;3718:11;:47::i;:::-;3775:61;;;;;;;;;;;;;;;;3803:32;;;;;3823:10;3803:32;;;1747:74:1;3775:61:0;;;3803:11;;;;1720:18:1;;3803:32:0;1601:226:1;3775:61:0;3847:55;;;;;;;;;;;;;;;;;3935:38;;;;;3847:18;;3935:16;;;;:38;;3847:55;;3935:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3912:61;;3983:37;;;;;;;;;;;;;;;;;;4003:4;4008:1;4003:7;;;;;;;;:::i;:::-;;;;;;;4012:4;4017:1;4012:7;;;;;;;;:::i;:::-;;;;;;;3983:11;:37::i;:::-;4031:27;;;;;10225:2:1;4031:27:0;;;10207:21:1;10264:2;10244:18;;;10237:30;10303:15;10283:18;;;10276:43;4031:4:0;;:10;;10336:18:1;;4031:27:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4068:37:0;;;;;4098:4;4068:37;;;1747:74:1;4068:13:0;;-1:-1:-1;4068:13:0;;-1:-1:-1;1720:18:1;;4068:37:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4115:26:0;;;;;10567:2:1;4115:26:0;;;10549:21:1;10606:2;10586:18;;;10579:30;10645:14;10625:18;;;10618:42;4115:4:0;;-1:-1:-1;4115:10:0;;-1:-1:-1;10677:18:1;;4115:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4151:59;;;;;;;;;;;;;;;;;;4198:10;4151:11;:59::i;:::-;4220:56;;;;;;;;;;;;;;;;;;4270:4;4220:11;:56::i;:::-;4286:26;;;;;10908:2:1;4286:26:0;;;10890:21:1;10947:2;10927:18;;;10920:30;10986:14;10966:18;;;10959:42;4286:4:0;;:10;;11018:18:1;;4286:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3215:28;3207:37;;4322:12;;;:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4346:33:0;;;;;11249:2:1;4346:33:0;;;11231:21:1;11288:2;11268:18;;;11261:30;11327:21;11307:18;;;11300:49;4346:4:0;;-1:-1:-1;4346:10:0;;-1:-1:-1;11366:18:1;;4346:33:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4593:53:0;;;;;11597:2:1;4593:53:0;;;11579:21:1;11636:2;11616:18;;;11609:30;11675:33;11655:18;;;11648:61;4521:35:0;;-1:-1:-1;4569:7:0;;-1:-1:-1;4569:7:0;;4521:35;;4569:7;;4593:18;;11726::1;;4593:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4569:78;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4657:34:0;;;;;1777:42:1;1765:55;;4657:34:0;;;1747:74:1;4657:18:0;;-1:-1:-1;4657:18:0;;-1:-1:-1;1720:18:1;;4657:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4713:51:0;;;;;4758:4;4713:51;;;1747:74:1;4701:9:0;;-1:-1:-1;4713:36:0;;;;-1:-1:-1;4713:36:0;;1720:18:1;;4713:51:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4701:63;;4774:84;;;;;;;;;;;;;;;;;;4856:1;4774:11;:84::i;:::-;4869:20;;;;;;;;;;;;;;;;;;:11;:20::i;:::-;3490:1406;;;;;3468:1428::o;2025:164::-;2080:59;2135:2;2096:42;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;2080:15;:59::i;:::-;2025:164;:::o;2577:188::-;2644:71;2707:2;2711;2660:54;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;2644:15;:71::i;2383:188::-;2450:71;2513:2;2517;2466:54;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;2450:15;:71::i;2195:182::-;2259:68;2319:2;2323;2275:51;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;2259:15;:68::i;2771:222::-;2862:81;2931:2;2935;2939;2878:64;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;2862:15;:81::i;:::-;2771:222;;;:::o;1500:133::-;1571:55;1618:7;1737:14;;1209:42;1910:2;1897:16;;1713:21;;1737:14;1897:16;1209:42;1946:5;1935:68;1926:77;;1863:150;;1639:380;:::o;-1:-1:-1:-;;;;;;;;:::o;196:592:1:-;267:6;275;328:2;316:9;307:7;303:23;299:32;296:52;;;344:1;341;334:12;296:52;384:9;371:23;413:18;454:2;446:6;443:14;440:34;;;470:1;467;460:12;440:34;508:6;497:9;493:22;483:32;;553:7;546:4;542:2;538:13;534:27;524:55;;575:1;572;565:12;524:55;615:2;602:16;641:2;633:6;630:14;627:34;;;657:1;654;647:12;627:34;702:7;697:2;688:6;684:2;680:15;676:24;673:37;670:57;;;723:1;720;713:12;670:57;754:2;746:11;;;;;776:6;;-1:-1:-1;196:592:1;;-1:-1:-1;;;;196:592:1:o;793:349::-;832:3;863:66;856:5;853:77;850:257;;963:77;960:1;953:88;1064:4;1061:1;1054:15;1092:4;1089:1;1082:15;850:257;-1:-1:-1;1134:1:1;1123:13;;793:349::o;1147:449::-;1306:2;1295:9;1288:21;1345:6;1340:2;1329:9;1325:18;1318:34;1402:6;1394;1389:2;1378:9;1374:18;1361:48;1458:1;1429:22;;;1453:2;1425:31;;;1418:42;;;;1512:2;1500:15;;;1517:66;1496:88;1481:104;1477:113;;1147:449;-1:-1:-1;1147:449:1:o;1832:288::-;1901:6;1954:2;1942:9;1933:7;1929:23;1925:32;1922:52;;;1970:1;1967;1960:12;1922:52;2002:9;1996:16;2052:18;2045:5;2041:30;2034:5;2031:41;2021:69;;2086:1;2083;2076:12;2021:69;2109:5;1832:288;-1:-1:-1;;;1832:288:1:o;4709:184::-;4779:6;4832:2;4820:9;4811:7;4807:23;4803:32;4800:52;;;4848:1;4845;4838:12;4800:52;-1:-1:-1;4871:16:1;;4709:184;-1:-1:-1;4709:184:1:o;6128:277::-;6195:6;6248:2;6236:9;6227:7;6223:23;6219:32;6216:52;;;6264:1;6261;6254:12;6216:52;6296:9;6290:16;6349:5;6342:13;6335:21;6328:5;6325:32;6315:60;;6371:1;6368;6361:12;6410:258;6482:1;6492:113;6506:6;6503:1;6500:13;6492:113;;;6582:11;;;6576:18;6563:11;;;6556:39;6528:2;6521:10;6492:113;;;6623:6;6620:1;6617:13;6614:48;;;6658:1;6649:6;6644:3;6640:16;6633:27;6614:48;;6410:258;;;:::o;6673:317::-;6715:3;6753:5;6747:12;6780:6;6775:3;6768:19;6796:63;6852:6;6845:4;6840:3;6836:14;6829:4;6822:5;6818:16;6796:63;:::i;:::-;6904:2;6892:15;6909:66;6888:88;6879:98;;;;6979:4;6875:109;;6673:317;-1:-1:-1;;6673:317:1:o;6995:493::-;7245:2;7234:9;7227:21;7208:4;7271:45;7312:2;7301:9;7297:18;7289:6;7271:45;:::i;:::-;7364:9;7356:6;7352:22;7347:2;7336:9;7332:18;7325:50;7399:2;7391:6;7384:18;7435:14;7430:2;7422:6;7418:15;7411:39;7479:2;7471:6;7467:15;7459:23;;;6995:493;;;;:::o;7493:184::-;7545:77;7542:1;7535:88;7642:4;7639:1;7632:15;7666:4;7663:1;7656:15;7682:334;7753:2;7747:9;7809:2;7799:13;;7814:66;7795:86;7783:99;;7912:18;7897:34;;7933:22;;;7894:62;7891:88;;;7959:18;;:::i;:::-;7995:2;7988:22;7682:334;;-1:-1:-1;7682:334:1:o;8021:437::-;8097:5;8131:18;8123:6;8120:30;8117:56;;;8153:18;;:::i;:::-;8191:116;8301:4;8232:66;8227:2;8219:6;8215:15;8211:88;8207:99;8191:116;:::i;:::-;8182:125;;8330:6;8323:5;8316:21;8370:3;8361:6;8356:3;8352:16;8349:25;8346:45;;;8387:1;8384;8377:12;8346:45;8400:52;8445:6;8438:4;8431:5;8427:16;8422:3;8400:52;:::i;8463:1366::-;8568:6;8599:2;8642;8630:9;8621:7;8617:23;8613:32;8610:52;;;8658:1;8655;8648:12;8610:52;8691:9;8685:16;8720:18;8761:2;8753:6;8750:14;8747:34;;;8777:1;8774;8767:12;8747:34;8815:6;8804:9;8800:22;8790:32;;8860:7;8853:4;8849:2;8845:13;8841:27;8831:55;;8882:1;8879;8872:12;8831:55;8911:2;8905:9;8933:2;8929;8926:10;8923:36;;;8939:18;;:::i;:::-;8985:2;8982:1;8978:10;9008:28;9032:2;9028;9024:11;9008:28;:::i;:::-;9070:15;;;9140:11;;;9136:20;;;9101:12;;;;9168:19;;;9165:39;;;9200:1;9197;9190:12;9165:39;9232:2;9228;9224:11;9213:22;;9244:555;9260:6;9255:3;9252:15;9244:555;;;9339:3;9333:10;9375:2;9362:11;9359:19;9356:109;;;9419:1;9448:2;9444;9437:14;9356:109;9488:20;;9543:2;9535:11;;9531:25;-1:-1:-1;9521:123:1;;9598:1;9627:2;9623;9616:14;9521:123;9669:87;9748:7;9742:2;9738;9734:11;9728:18;9723:2;9719;9715:11;9669:87;:::i;:::-;9657:100;;-1:-1:-1;9277:12:1;;;;9777;;;;9244:555;;;9818:5;8463:1366;-1:-1:-1;;;;;;;;;8463:1366:1:o;9834:184::-;9886:77;9883:1;9876:88;9983:4;9980:1;9973:15;10007:4;10004:1;9997:15;11755:458;11834:6;11887:2;11875:9;11866:7;11862:23;11858:32;11855:52;;;11903:1;11900;11893:12;11855:52;11936:9;11930:16;11969:18;11961:6;11958:30;11955:50;;;12001:1;11998;11991:12;11955:50;12024:22;;12077:4;12069:13;;12065:27;-1:-1:-1;12055:55:1;;12106:1;12103;12096:12;12055:55;12129:78;12199:7;12194:2;12188:9;12183:2;12179;12175:11;12129:78;:::i;:::-;12119:88;11755:458;-1:-1:-1;;;;11755:458:1:o;12218:338::-;12405:42;12397:6;12393:55;12382:9;12375:74;12485:2;12480;12469:9;12465:18;12458:30;12356:4;12505:45;12546:2;12535:9;12531:18;12523:6;12505:45;:::i;12561:220::-;12710:2;12699:9;12692:21;12673:4;12730:45;12771:2;12760:9;12756:18;12748:6;12730:45;:::i;12786:340::-;12963:2;12952:9;12945:21;12926:4;12983:45;13024:2;13013:9;13009:18;13001:6;12983:45;:::i;:::-;12975:53;;13076:42;13068:6;13064:55;13059:2;13048:9;13044:18;13037:83;12786:340;;;;;:::o;13131:291::-;13308:2;13297:9;13290:21;13271:4;13328:45;13369:2;13358:9;13354:18;13346:6;13328:45;:::i;:::-;13320:53;;13409:6;13404:2;13393:9;13389:18;13382:34;13131:291;;;;;:::o;13427:301::-;13598:2;13587:9;13580:21;13561:4;13618:45;13659:2;13648:9;13644:18;13636:6;13618:45;:::i;:::-;13610:53;;13713:6;13706:14;13699:22;13694:2;13683:9;13679:18;13672:50;13427:301;;;;;:::o;13733:546::-;13978:2;13967:9;13960:21;13941:4;14004:45;14045:2;14034:9;14030:18;14022:6;14004:45;:::i;:::-;14097:9;14089:6;14085:22;14080:2;14069:9;14065:18;14058:50;14131:33;14157:6;14149;14131:33;:::i;:::-;14117:47;;14212:9;14204:6;14200:22;14195:2;14184:9;14180:18;14173:50;14240:33;14266:6;14258;14240:33;:::i;:::-;14232:41;13733:546;-1:-1:-1;;;;;;13733:546:1:o","linkReferences":{}},"methodIdentifiers":{"call1(string)":"7e79255d","call2(string)":"8d3ef7ca","callPure(string)":"7f8b915c","counter()":"61bc221a","hello(string)":"a777d0dc","nested1(string)":"a76ccdfa","nested2(string)":"dbf1282f","run()":"c0406226","runBroadcast()":"bef03abc"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_v\",\"type\":\"string\"}],\"name\":\"call1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_v\",\"type\":\"string\"}],\"name\":\"call2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_v\",\"type\":\"string\"}],\"name\":\"callPure\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_v\",\"type\":\"string\"}],\"name\":\"hello\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_v\",\"type\":\"string\"}],\"name\":\"nested1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_v\",\"type\":\"string\"}],\"name\":\"nested2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"run\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"runBroadcast\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"ScriptExample\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"hello(string)\":{\"notice\":\"example external function, to force a CALL, and test vm.startPrank with.\"},\"run()\":{\"notice\":\"example function, runs through basic cheat-codes and console logs.\"},\"runBroadcast()\":{\"notice\":\"example function, to test vm.broadcast with.\"}},\"notice\":\"ScriptExample is an example script. The Go forge script code tests that it can run this.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"scripts/ScriptExample.s.sol\":\"ScriptExample\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"scripts/ScriptExample.s.sol\":{\"keccak256\":\"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28\",\"dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"string","name":"_v","type":"string"}],"stateMutability":"nonpayable","type":"function","name":"call1"},{"inputs":[{"internalType":"string","name":"_v","type":"string"}],"stateMutability":"nonpayable","type":"function","name":"call2"},{"inputs":[{"internalType":"string","name":"_v","type":"string"}],"stateMutability":"pure","type":"function","name":"callPure"},{"inputs":[],"stateMutability":"view","type":"function","name":"counter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"string","name":"_v","type":"string"}],"stateMutability":"view","type":"function","name":"hello"},{"inputs":[{"internalType":"string","name":"_v","type":"string"}],"stateMutability":"nonpayable","type":"function","name":"nested1"},{"inputs":[{"internalType":"string","name":"_v","type":"string"}],"stateMutability":"nonpayable","type":"function","name":"nested2"},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"run"},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"runBroadcast"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{"hello(string)":{"notice":"example external function, to force a CALL, and test vm.startPrank with."},"run()":{"notice":"example function, runs through basic cheat-codes and console logs."},"runBroadcast()":{"notice":"example function, to test vm.broadcast with."}},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"scripts/ScriptExample.s.sol":"ScriptExample"},"evmVersion":"london","libraries":{}},"sources":{"scripts/ScriptExample.s.sol":{"keccak256":"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da","urls":["bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28","dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[{"astId":243,"contract":"scripts/ScriptExample.s.sol:ScriptExample","label":"counter","offset":0,"slot":"0","type":"t_uint256"}],"types":{"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}},"userdoc":{"version":1,"kind":"user","methods":{"hello(string)":{"notice":"example external function, to force a CALL, and test vm.startPrank with."},"run()":{"notice":"example function, runs through basic cheat-codes and console logs."},"runBroadcast()":{"notice":"example function, to test vm.broadcast with."}},"notice":"ScriptExample is an example script. The Go forge script code tests that it can run this."},"devdoc":{"version":1,"kind":"dev","title":"ScriptExample"},"ast":{"absolutePath":"scripts/ScriptExample.s.sol","id":969,"exportedSymbols":{"FooBar":[799],"ForkTester":[968],"ForkedContract":[852],"NonceGetter":[833],"ScriptExample":[786],"Vm":[83],"console":[220]},"nodeType":"SourceUnit","src":"32:8375:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","0.8",".15"]},{"id":83,"nodeType":"ContractDefinition","src":"120:969:0","nodes":[{"id":10,"nodeType":"FunctionDefinition","src":"139:91:0","nodes":[],"functionSelector":"4777f3cf","implemented":false,"kind":"function","modifiers":[],"name":"envOr","nameLocation":"148:5:0","parameters":{"id":6,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"mutability":"mutable","name":"name","nameLocation":"170:4:0","nodeType":"VariableDeclaration","scope":10,"src":"154:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":2,"name":"string","nodeType":"ElementaryTypeName","src":"154:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":5,"mutability":"mutable","name":"defaultValue","nameLocation":"181:12:0","nodeType":"VariableDeclaration","scope":10,"src":"176:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":4,"name":"bool","nodeType":"ElementaryTypeName","src":"176:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"153:41:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[{"constant":false,"id":8,"mutability":"mutable","name":"value","nameLocation":"223:5:0","nodeType":"VariableDeclaration","scope":10,"src":"218:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":7,"name":"bool","nodeType":"ElementaryTypeName","src":"218:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"217:12:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":17,"nodeType":"FunctionDefinition","src":"235:72:0","nodes":[],"functionSelector":"2d0335ab","implemented":false,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"244:8:0","parameters":{"id":13,"nodeType":"ParameterList","parameters":[{"constant":false,"id":12,"mutability":"mutable","name":"account","nameLocation":"261:7:0","nodeType":"VariableDeclaration","scope":17,"src":"253:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":11,"name":"address","nodeType":"ElementaryTypeName","src":"253:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"252:17:0"},"returnParameters":{"id":16,"nodeType":"ParameterList","parameters":[{"constant":false,"id":15,"mutability":"mutable","name":"nonce","nameLocation":"300:5:0","nodeType":"VariableDeclaration","scope":17,"src":"293:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"},"typeName":{"id":14,"name":"uint64","nodeType":"ElementaryTypeName","src":"293:6:0","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"visibility":"internal"}],"src":"292:14:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":27,"nodeType":"FunctionDefinition","src":"312:111:0","nodes":[],"functionSelector":"213e4198","implemented":false,"kind":"function","modifiers":[],"name":"parseJsonKeys","nameLocation":"321:13:0","parameters":{"id":22,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19,"mutability":"mutable","name":"json","nameLocation":"351:4:0","nodeType":"VariableDeclaration","scope":27,"src":"335:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":18,"name":"string","nodeType":"ElementaryTypeName","src":"335:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":21,"mutability":"mutable","name":"key","nameLocation":"373:3:0","nodeType":"VariableDeclaration","scope":27,"src":"357:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":20,"name":"string","nodeType":"ElementaryTypeName","src":"357:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"334:43:0"},"returnParameters":{"id":26,"nodeType":"ParameterList","parameters":[{"constant":false,"id":25,"mutability":"mutable","name":"keys","nameLocation":"417:4:0","nodeType":"VariableDeclaration","scope":27,"src":"401:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":23,"name":"string","nodeType":"ElementaryTypeName","src":"401:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":24,"nodeType":"ArrayTypeName","src":"401:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"src":"400:22:0"},"scope":83,"stateMutability":"pure","virtual":false,"visibility":"external"},{"id":32,"nodeType":"FunctionDefinition","src":"428:48:0","nodes":[],"functionSelector":"06447d56","implemented":false,"kind":"function","modifiers":[],"name":"startPrank","nameLocation":"437:10:0","parameters":{"id":30,"nodeType":"ParameterList","parameters":[{"constant":false,"id":29,"mutability":"mutable","name":"msgSender","nameLocation":"456:9:0","nodeType":"VariableDeclaration","scope":32,"src":"448:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":28,"name":"address","nodeType":"ElementaryTypeName","src":"448:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"447:19:0"},"returnParameters":{"id":31,"nodeType":"ParameterList","parameters":[],"src":"475:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":35,"nodeType":"FunctionDefinition","src":"481:30:0","nodes":[],"functionSelector":"90c5013b","implemented":false,"kind":"function","modifiers":[],"name":"stopPrank","nameLocation":"490:9:0","parameters":{"id":33,"nodeType":"ParameterList","parameters":[],"src":"499:2:0"},"returnParameters":{"id":34,"nodeType":"ParameterList","parameters":[],"src":"510:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":38,"nodeType":"FunctionDefinition","src":"516:30:0","nodes":[],"functionSelector":"afc98040","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"525:9:0","parameters":{"id":36,"nodeType":"ParameterList","parameters":[],"src":"534:2:0"},"returnParameters":{"id":37,"nodeType":"ParameterList","parameters":[],"src":"545:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":43,"nodeType":"FunctionDefinition","src":"551:47:0","nodes":[],"functionSelector":"e6962cdb","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"560:9:0","parameters":{"id":41,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40,"mutability":"mutable","name":"msgSender","nameLocation":"578:9:0","nodeType":"VariableDeclaration","scope":43,"src":"570:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39,"name":"address","nodeType":"ElementaryTypeName","src":"570:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"569:19:0"},"returnParameters":{"id":42,"nodeType":"ParameterList","parameters":[],"src":"597:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":48,"nodeType":"FunctionDefinition","src":"603:52:0","nodes":[],"functionSelector":"7fec2a8d","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"612:14:0","parameters":{"id":46,"nodeType":"ParameterList","parameters":[{"constant":false,"id":45,"mutability":"mutable","name":"msgSender","nameLocation":"635:9:0","nodeType":"VariableDeclaration","scope":48,"src":"627:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":44,"name":"address","nodeType":"ElementaryTypeName","src":"627:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"626:19:0"},"returnParameters":{"id":47,"nodeType":"ParameterList","parameters":[],"src":"654:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":51,"nodeType":"FunctionDefinition","src":"660:35:0","nodes":[],"functionSelector":"7fb5297f","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"669:14:0","parameters":{"id":49,"nodeType":"ParameterList","parameters":[],"src":"683:2:0"},"returnParameters":{"id":50,"nodeType":"ParameterList","parameters":[],"src":"694:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":54,"nodeType":"FunctionDefinition","src":"700:34:0","nodes":[],"functionSelector":"76eadd36","implemented":false,"kind":"function","modifiers":[],"name":"stopBroadcast","nameLocation":"709:13:0","parameters":{"id":52,"nodeType":"ParameterList","parameters":[],"src":"722:2:0"},"returnParameters":{"id":53,"nodeType":"ParameterList","parameters":[],"src":"733:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":61,"nodeType":"FunctionDefinition","src":"739:108:0","nodes":[],"functionSelector":"3ebf73b4","implemented":false,"kind":"function","modifiers":[],"name":"getDeployedCode","nameLocation":"748:15:0","parameters":{"id":57,"nodeType":"ParameterList","parameters":[{"constant":false,"id":56,"mutability":"mutable","name":"artifactPath","nameLocation":"780:12:0","nodeType":"VariableDeclaration","scope":61,"src":"764:28:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":55,"name":"string","nodeType":"ElementaryTypeName","src":"764:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"763:30:0"},"returnParameters":{"id":60,"nodeType":"ParameterList","parameters":[{"constant":false,"id":59,"mutability":"mutable","name":"runtimeBytecode","nameLocation":"830:15:0","nodeType":"VariableDeclaration","scope":61,"src":"817:28:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":58,"name":"bytes","nodeType":"ElementaryTypeName","src":"817:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"816:30:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":68,"nodeType":"FunctionDefinition","src":"852:74:0","nodes":[],"functionSelector":"b4d6c782","implemented":false,"kind":"function","modifiers":[],"name":"etch","nameLocation":"861:4:0","parameters":{"id":66,"nodeType":"ParameterList","parameters":[{"constant":false,"id":63,"mutability":"mutable","name":"target","nameLocation":"874:6:0","nodeType":"VariableDeclaration","scope":68,"src":"866:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":62,"name":"address","nodeType":"ElementaryTypeName","src":"866:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":65,"mutability":"mutable","name":"newRuntimeBytecode","nameLocation":"897:18:0","nodeType":"VariableDeclaration","scope":68,"src":"882:33:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":64,"name":"bytes","nodeType":"ElementaryTypeName","src":"882:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"865:51:0"},"returnParameters":{"id":67,"nodeType":"ParameterList","parameters":[],"src":"925:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":73,"nodeType":"FunctionDefinition","src":"931:51:0","nodes":[],"functionSelector":"ea060291","implemented":false,"kind":"function","modifiers":[],"name":"allowCheatcodes","nameLocation":"940:15:0","parameters":{"id":71,"nodeType":"ParameterList","parameters":[{"constant":false,"id":70,"mutability":"mutable","name":"account","nameLocation":"964:7:0","nodeType":"VariableDeclaration","scope":73,"src":"956:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":69,"name":"address","nodeType":"ElementaryTypeName","src":"956:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"955:17:0"},"returnParameters":{"id":72,"nodeType":"ParameterList","parameters":[],"src":"981:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":82,"nodeType":"FunctionDefinition","src":"987:100:0","nodes":[],"functionSelector":"71ee464d","implemented":false,"kind":"function","modifiers":[],"name":"createSelectFork","nameLocation":"996:16:0","parameters":{"id":78,"nodeType":"ParameterList","parameters":[{"constant":false,"id":75,"mutability":"mutable","name":"forkName","nameLocation":"1029:8:0","nodeType":"VariableDeclaration","scope":82,"src":"1013:24:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":74,"name":"string","nodeType":"ElementaryTypeName","src":"1013:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":77,"mutability":"mutable","name":"blockNumber","nameLocation":"1047:11:0","nodeType":"VariableDeclaration","scope":82,"src":"1039:19:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":76,"name":"uint256","nodeType":"ElementaryTypeName","src":"1039:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1012:47:0"},"returnParameters":{"id":81,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":82,"src":"1078:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":79,"name":"uint256","nodeType":"ElementaryTypeName","src":"1078:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1077:9:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"Vm","contractDependencies":[],"contractKind":"interface","fullyImplemented":false,"linearizedBaseContracts":[83],"name":"Vm","nameLocation":"130:2:0","scope":969,"usedErrors":[]},{"id":220,"nodeType":"ContractDefinition","src":"1144:1851:0","nodes":[{"id":89,"nodeType":"VariableDeclaration","src":"1166:86:0","nodes":[],"constant":true,"mutability":"constant","name":"CONSOLE_ADDRESS","nameLocation":"1183:15:0","scope":220,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":84,"name":"address","nodeType":"ElementaryTypeName","src":"1166:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"hexValue":"307830303030303030303030303030303030303036333646366537333646366336353265366336663637","id":87,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1209:42:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"value":"0x000000000000000000636F6e736F6c652e6c6f67"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":86,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":85,"name":"address","nodeType":"ElementaryTypeName","src":"1201:7:0","typeDescriptions":{}}},"id":88,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1201:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":106,"nodeType":"FunctionDefinition","src":"1259:235:0","nodes":[],"body":{"id":105,"nodeType":"Block","src":"1432:62:0","nodes":[],"statements":[{"AST":{"nodeType":"YulBlock","src":"1451:37:0","statements":[{"nodeType":"YulAssignment","src":"1465:13:0","value":{"name":"fnIn","nodeType":"YulIdentifier","src":"1474:4:0"},"variableNames":[{"name":"fnOut","nodeType":"YulIdentifier","src":"1465:5:0"}]}]},"evmVersion":"london","externalReferences":[{"declaration":95,"isOffset":false,"isSlot":false,"src":"1474:4:0","valueSize":1},{"declaration":102,"isOffset":false,"isSlot":false,"src":"1465:5:0","valueSize":1}],"id":104,"nodeType":"InlineAssembly","src":"1442:46:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_castLogPayloadViewToPure","nameLocation":"1268:25:0","parameters":{"id":96,"nodeType":"ParameterList","parameters":[{"constant":false,"id":95,"mutability":"mutable","name":"fnIn","nameLocation":"1331:4:0","nodeType":"VariableDeclaration","scope":106,"src":"1294:41:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"typeName":{"id":94,"nodeType":"FunctionTypeName","parameterTypes":{"id":92,"nodeType":"ParameterList","parameters":[{"constant":false,"id":91,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":94,"src":"1303:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":90,"name":"bytes","nodeType":"ElementaryTypeName","src":"1303:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1302:14:0"},"returnParameterTypes":{"id":93,"nodeType":"ParameterList","parameters":[],"src":"1331:0:0"},"src":"1294:41:0","stateMutability":"view","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"visibility":"internal"},"visibility":"internal"}],"src":"1293:43:0"},"returnParameters":{"id":103,"nodeType":"ParameterList","parameters":[{"constant":false,"id":102,"mutability":"mutable","name":"fnOut","nameLocation":"1421:5:0","nodeType":"VariableDeclaration","scope":106,"src":"1384:42:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"typeName":{"id":101,"nodeType":"FunctionTypeName","parameterTypes":{"id":99,"nodeType":"ParameterList","parameters":[{"constant":false,"id":98,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":101,"src":"1393:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":97,"name":"bytes","nodeType":"ElementaryTypeName","src":"1393:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1392:14:0"},"returnParameterTypes":{"id":100,"nodeType":"ParameterList","parameters":[],"src":"1421:0:0"},"src":"1384:42:0","stateMutability":"pure","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"visibility":"internal"},"visibility":"internal"}],"src":"1383:44:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":118,"nodeType":"FunctionDefinition","src":"1500:133:0","nodes":[],"body":{"id":117,"nodeType":"Block","src":"1561:72:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":114,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":108,"src":"1618:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"arguments":[{"id":112,"name":"_sendLogPayloadView","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":134,"src":"1597:19:0","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}],"id":111,"name":"_castLogPayloadViewToPure","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":106,"src":"1571:25:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_function_internal_view$_t_bytes_memory_ptr_$returns$__$_$returns$_t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$_$","typeString":"function (function (bytes memory) view) pure returns (function (bytes memory) pure)"}},"id":113,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":115,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":116,"nodeType":"ExpressionStatement","src":"1571:55:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayload","nameLocation":"1509:15:0","parameters":{"id":109,"nodeType":"ParameterList","parameters":[{"constant":false,"id":108,"mutability":"mutable","name":"payload","nameLocation":"1538:7:0","nodeType":"VariableDeclaration","scope":118,"src":"1525:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":107,"name":"bytes","nodeType":"ElementaryTypeName","src":"1525:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1524:22:0"},"returnParameters":{"id":110,"nodeType":"ParameterList","parameters":[],"src":"1561:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":134,"nodeType":"FunctionDefinition","src":"1639:380:0","nodes":[],"body":{"id":133,"nodeType":"Block","src":"1703:316:0","nodes":[],"statements":[{"assignments":[124],"declarations":[{"constant":false,"id":124,"mutability":"mutable","name":"payloadLength","nameLocation":"1721:13:0","nodeType":"VariableDeclaration","scope":133,"src":"1713:21:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":123,"name":"uint256","nodeType":"ElementaryTypeName","src":"1713:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":127,"initialValue":{"expression":{"id":125,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":120,"src":"1737:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":126,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1737:14:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1713:38:0"},{"assignments":[129],"declarations":[{"constant":false,"id":129,"mutability":"mutable","name":"consoleAddress","nameLocation":"1769:14:0","nodeType":"VariableDeclaration","scope":133,"src":"1761:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":128,"name":"address","nodeType":"ElementaryTypeName","src":"1761:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":131,"initialValue":{"id":130,"name":"CONSOLE_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":89,"src":"1786:15:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"1761:40:0"},{"AST":{"nodeType":"YulBlock","src":"1863:150:0","statements":[{"nodeType":"YulVariableDeclaration","src":"1877:36:0","value":{"arguments":[{"name":"payload","nodeType":"YulIdentifier","src":"1901:7:0"},{"kind":"number","nodeType":"YulLiteral","src":"1910:2:0","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1897:3:0"},"nodeType":"YulFunctionCall","src":"1897:16:0"},"variables":[{"name":"payloadStart","nodeType":"YulTypedName","src":"1881:12:0","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1926:77:0","value":{"arguments":[{"arguments":[],"functionName":{"name":"gas","nodeType":"YulIdentifier","src":"1946:3:0"},"nodeType":"YulFunctionCall","src":"1946:5:0"},{"name":"consoleAddress","nodeType":"YulIdentifier","src":"1953:14:0"},{"name":"payloadStart","nodeType":"YulIdentifier","src":"1969:12:0"},{"name":"payloadLength","nodeType":"YulIdentifier","src":"1983:13:0"},{"kind":"number","nodeType":"YulLiteral","src":"1998:1:0","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"2001:1:0","type":"","value":"0"}],"functionName":{"name":"staticcall","nodeType":"YulIdentifier","src":"1935:10:0"},"nodeType":"YulFunctionCall","src":"1935:68:0"},"variables":[{"name":"r","nodeType":"YulTypedName","src":"1930:1:0","type":""}]}]},"documentation":"@solidity memory-safe-assembly","evmVersion":"london","externalReferences":[{"declaration":129,"isOffset":false,"isSlot":false,"src":"1953:14:0","valueSize":1},{"declaration":120,"isOffset":false,"isSlot":false,"src":"1901:7:0","valueSize":1},{"declaration":124,"isOffset":false,"isSlot":false,"src":"1983:13:0","valueSize":1}],"id":132,"nodeType":"InlineAssembly","src":"1854:159:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayloadView","nameLocation":"1648:19:0","parameters":{"id":121,"nodeType":"ParameterList","parameters":[{"constant":false,"id":120,"mutability":"mutable","name":"payload","nameLocation":"1681:7:0","nodeType":"VariableDeclaration","scope":134,"src":"1668:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":119,"name":"bytes","nodeType":"ElementaryTypeName","src":"1668:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1667:22:0"},"returnParameters":{"id":122,"nodeType":"ParameterList","parameters":[],"src":"1703:0:0"},"scope":220,"stateMutability":"view","virtual":false,"visibility":"private"},{"id":148,"nodeType":"FunctionDefinition","src":"2025:164:0","nodes":[],"body":{"id":147,"nodeType":"Block","src":"2070:119:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e6729","id":142,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2120:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},"value":"log(string)"},{"id":143,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":136,"src":"2135:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":140,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2096:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":141,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2096:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":144,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2096:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":139,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2080:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":145,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2080:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":146,"nodeType":"ExpressionStatement","src":"2080:59:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2034:3:0","parameters":{"id":137,"nodeType":"ParameterList","parameters":[{"constant":false,"id":136,"mutability":"mutable","name":"p0","nameLocation":"2052:2:0","nodeType":"VariableDeclaration","scope":148,"src":"2038:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":135,"name":"string","nodeType":"ElementaryTypeName","src":"2038:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2037:18:0"},"returnParameters":{"id":138,"nodeType":"ParameterList","parameters":[],"src":"2070:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":165,"nodeType":"FunctionDefinition","src":"2195:182:0","nodes":[],"body":{"id":164,"nodeType":"Block","src":"2249:128:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c626f6f6c29","id":158,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2299:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},"value":"log(string,bool)"},{"id":159,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":150,"src":"2319:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":160,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":152,"src":"2323:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":156,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2275:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":157,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2275:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":161,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2275:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":155,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2259:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":162,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2259:68:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":163,"nodeType":"ExpressionStatement","src":"2259:68:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2204:3:0","parameters":{"id":153,"nodeType":"ParameterList","parameters":[{"constant":false,"id":150,"mutability":"mutable","name":"p0","nameLocation":"2222:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2208:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":149,"name":"string","nodeType":"ElementaryTypeName","src":"2208:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":152,"mutability":"mutable","name":"p1","nameLocation":"2231:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2226:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":151,"name":"bool","nodeType":"ElementaryTypeName","src":"2226:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"2207:27:0"},"returnParameters":{"id":154,"nodeType":"ParameterList","parameters":[],"src":"2249:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":182,"nodeType":"FunctionDefinition","src":"2383:188:0","nodes":[],"body":{"id":181,"nodeType":"Block","src":"2440:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c75696e7432353629","id":175,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2490:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},"value":"log(string,uint256)"},{"id":176,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":167,"src":"2513:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":177,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":169,"src":"2517:2:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":173,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2466:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":174,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2466:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":178,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2466:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":172,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2450:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":179,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2450:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":180,"nodeType":"ExpressionStatement","src":"2450:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2392:3:0","parameters":{"id":170,"nodeType":"ParameterList","parameters":[{"constant":false,"id":167,"mutability":"mutable","name":"p0","nameLocation":"2410:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2396:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":166,"name":"string","nodeType":"ElementaryTypeName","src":"2396:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":169,"mutability":"mutable","name":"p1","nameLocation":"2422:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2414:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":168,"name":"uint256","nodeType":"ElementaryTypeName","src":"2414:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"2395:30:0"},"returnParameters":{"id":171,"nodeType":"ParameterList","parameters":[],"src":"2440:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":199,"nodeType":"FunctionDefinition","src":"2577:188:0","nodes":[],"body":{"id":198,"nodeType":"Block","src":"2634:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c6164647265737329","id":192,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2684:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},"value":"log(string,address)"},{"id":193,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":184,"src":"2707:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":194,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":186,"src":"2711:2:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":190,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2660:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":191,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2660:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":195,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2660:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":189,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2644:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":196,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2644:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":197,"nodeType":"ExpressionStatement","src":"2644:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2586:3:0","parameters":{"id":187,"nodeType":"ParameterList","parameters":[{"constant":false,"id":184,"mutability":"mutable","name":"p0","nameLocation":"2604:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2590:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":183,"name":"string","nodeType":"ElementaryTypeName","src":"2590:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":186,"mutability":"mutable","name":"p1","nameLocation":"2616:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2608:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":185,"name":"address","nodeType":"ElementaryTypeName","src":"2608:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2589:30:0"},"returnParameters":{"id":188,"nodeType":"ParameterList","parameters":[],"src":"2634:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":219,"nodeType":"FunctionDefinition","src":"2771:222:0","nodes":[],"body":{"id":218,"nodeType":"Block","src":"2852:141:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c737472696e672c737472696e6729","id":211,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2902:27:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},"value":"log(string,string,string)"},{"id":212,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":201,"src":"2931:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":213,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":203,"src":"2935:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":214,"name":"p2","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":205,"src":"2939:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":209,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2878:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":210,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2878:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":215,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2878:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":208,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2862:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":216,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2862:81:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":217,"nodeType":"ExpressionStatement","src":"2862:81:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2780:3:0","parameters":{"id":206,"nodeType":"ParameterList","parameters":[{"constant":false,"id":201,"mutability":"mutable","name":"p0","nameLocation":"2798:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2784:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":200,"name":"string","nodeType":"ElementaryTypeName","src":"2784:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":203,"mutability":"mutable","name":"p1","nameLocation":"2816:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2802:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":202,"name":"string","nodeType":"ElementaryTypeName","src":"2802:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":205,"mutability":"mutable","name":"p2","nameLocation":"2834:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2820:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":204,"name":"string","nodeType":"ElementaryTypeName","src":"2820:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2783:54:0"},"returnParameters":{"id":207,"nodeType":"ParameterList","parameters":[],"src":"2852:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"}],"abstract":false,"baseContracts":[],"canonicalName":"console","contractDependencies":[],"contractKind":"library","fullyImplemented":true,"linearizedBaseContracts":[220],"name":"console","nameLocation":"1152:7:0","scope":969,"usedErrors":[]},{"id":786,"nodeType":"ContractDefinition","src":"3123:3912:0","nodes":[{"id":235,"nodeType":"VariableDeclaration","src":"3152:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"3178:10:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":222,"name":"address","nodeType":"ElementaryTypeName","src":"3152:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":230,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3225:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":229,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"3215:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":231,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3215:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":228,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3207:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":227,"name":"uint256","nodeType":"ElementaryTypeName","src":"3207:7:0","typeDescriptions":{}}},"id":232,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3207:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":226,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3199:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":225,"name":"uint160","nodeType":"ElementaryTypeName","src":"3199:7:0","typeDescriptions":{}}},"id":233,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3199:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":224,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3191:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":223,"name":"address","nodeType":"ElementaryTypeName","src":"3191:7:0","typeDescriptions":{}}},"id":234,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3191:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":241,"nodeType":"VariableDeclaration","src":"3252:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"3273:2:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":237,"nodeType":"UserDefinedTypeName","pathNode":{"id":236,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"3252:2:0"},"referencedDeclaration":83,"src":"3252:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":239,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":235,"src":"3281:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":238,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"3278:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":240,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3278:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":243,"nodeType":"VariableDeclaration","src":"3356:22:0","nodes":[],"constant":false,"functionSelector":"61bc221a","mutability":"mutable","name":"counter","nameLocation":"3371:7:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":242,"name":"uint256","nodeType":"ElementaryTypeName","src":"3356:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":456,"nodeType":"FunctionDefinition","src":"3468:1428:0","nodes":[],"body":{"id":455,"nodeType":"Block","src":"3490:1406:0","nodes":[],"statements":[{"assignments":[248],"declarations":[{"constant":false,"id":248,"mutability":"mutable","name":"x","nameLocation":"3505:1:0","nodeType":"VariableDeclaration","scope":455,"src":"3500:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":247,"name":"bool","nodeType":"ElementaryTypeName","src":"3500:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"id":254,"initialValue":{"arguments":[{"hexValue":"4558414d504c455f424f4f4c","id":251,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3518:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},"value":"EXAMPLE_BOOL"},{"hexValue":"66616c7365","id":252,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"3534:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":249,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3509:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":250,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"envOr","nodeType":"MemberAccess","referencedDeclaration":10,"src":"3509:8:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$_t_bool_$returns$_t_bool_$","typeString":"function (string memory,bool) view external returns (bool)"}},"id":253,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3509:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"VariableDeclarationStatement","src":"3500:40:0"},{"expression":{"arguments":[{"hexValue":"626f6f6c2076616c75652066726f6d20656e76","id":258,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3562:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},"value":"bool value from env"},{"id":259,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":248,"src":"3585:1:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":255,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3550:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":257,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":165,"src":"3550:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_bool_$returns$__$","typeString":"function (string memory,bool) pure"}},"id":260,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3550:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":261,"nodeType":"ExpressionStatement","src":"3550:37:0"},{"expression":{"arguments":[{"hexValue":"636f6e74726163742061646472","id":265,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3610:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},"value":"contract addr"},{"arguments":[{"id":268,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3635:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":267,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3627:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":266,"name":"address","nodeType":"ElementaryTypeName","src":"3627:7:0","typeDescriptions":{}}},"id":269,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3627:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":262,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3598:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":264,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3598:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":270,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3598:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":271,"nodeType":"ExpressionStatement","src":"3598:43:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206e6f6e6365","id":275,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3663:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},"value":"contract nonce"},{"arguments":[{"arguments":[{"id":280,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3701:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":279,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3693:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":278,"name":"address","nodeType":"ElementaryTypeName","src":"3693:7:0","typeDescriptions":{}}},"id":281,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3693:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":276,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3681:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":277,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3681:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":282,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3681:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":272,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3651:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":274,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3651:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":283,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3651:57:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":284,"nodeType":"ExpressionStatement","src":"3651:57:0"},{"expression":{"arguments":[{"hexValue":"73656e6465722061646472","id":288,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3730:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},"value":"sender addr"},{"arguments":[{"expression":{"id":291,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3753:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":292,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3753:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":290,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3745:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":289,"name":"address","nodeType":"ElementaryTypeName","src":"3745:7:0","typeDescriptions":{}}},"id":293,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3745:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":285,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3718:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":287,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3718:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":294,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3718:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":295,"nodeType":"ExpressionStatement","src":"3718:47:0"},{"expression":{"arguments":[{"hexValue":"73656e646572206e6f6e6365","id":299,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3787:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},"value":"sender nonce"},{"arguments":[{"arguments":[{"expression":{"id":304,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3823:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":305,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3823:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":303,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3815:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":302,"name":"address","nodeType":"ElementaryTypeName","src":"3815:7:0","typeDescriptions":{}}},"id":306,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3815:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":300,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3803:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":301,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3803:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":307,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3803:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":296,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3775:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":298,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3775:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":308,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3775:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":309,"nodeType":"ExpressionStatement","src":"3775:61:0"},{"assignments":[311],"declarations":[{"constant":false,"id":311,"mutability":"mutable","name":"json","nameLocation":"3861:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3847:18:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":310,"name":"string","nodeType":"ElementaryTypeName","src":"3847:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"id":313,"initialValue":{"hexValue":"7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d","id":312,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3868:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e95522e99766888d0261f55bd1eae5e3f3e26eaf009a16e2433eafaf0a4ecdf2","typeString":"literal_string \"{\"root_key\": [{\"a\": 1, \"b\": 2}]}\""},"value":"{\"root_key\": [{\"a\": 1, \"b\": 2}]}"},"nodeType":"VariableDeclarationStatement","src":"3847:55:0"},{"assignments":[318],"declarations":[{"constant":false,"id":318,"mutability":"mutable","name":"keys","nameLocation":"3928:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3912:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":316,"name":"string","nodeType":"ElementaryTypeName","src":"3912:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":317,"nodeType":"ArrayTypeName","src":"3912:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"id":324,"initialValue":{"arguments":[{"id":321,"name":"json","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":311,"src":"3952:4:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"2e726f6f745f6b65795b305d","id":322,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3958:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""},"value":".root_key[0]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""}],"expression":{"id":319,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3935:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":320,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"parseJsonKeys","nodeType":"MemberAccess","referencedDeclaration":27,"src":"3935:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$_t_array$_t_string_memory_ptr_$dyn_memory_ptr_$","typeString":"function (string memory,string memory) pure external returns (string memory[] memory)"}},"id":323,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3935:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"nodeType":"VariableDeclarationStatement","src":"3912:61:0"},{"expression":{"arguments":[{"hexValue":"6b657973","id":328,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3995:6:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},"value":"keys"},{"baseExpression":{"id":329,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4003:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":331,"indexExpression":{"hexValue":"30","id":330,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4008:1:0","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4003:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"baseExpression":{"id":332,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4012:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":334,"indexExpression":{"hexValue":"31","id":333,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4017:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4012:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":325,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3983:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":327,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":219,"src":"3983:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory,string memory) pure"}},"id":335,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3983:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":336,"nodeType":"ExpressionStatement","src":"3983:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c","id":340,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4042:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""},"value":"from original"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""}],"expression":{"id":337,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4031:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":339,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4031:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":341,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4031:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":342,"nodeType":"ExpressionStatement","src":"4031:27:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"30783432","id":350,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4098:4:0","typeDescriptions":{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"},"value":"0x42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"}],"id":349,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4090:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":348,"name":"uint160","nodeType":"ElementaryTypeName","src":"4090:7:0","typeDescriptions":{}}},"id":351,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4090:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":347,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4082:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":346,"name":"address","nodeType":"ElementaryTypeName","src":"4082:7:0","typeDescriptions":{}}},"id":352,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4082:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":343,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4068:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":345,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startPrank","nodeType":"MemberAccess","referencedDeclaration":32,"src":"4068:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":353,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4068:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":354,"nodeType":"ExpressionStatement","src":"4068:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2031","id":358,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4126:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""},"value":"from prank 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""}],"expression":{"id":355,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4115:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":357,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4115:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":359,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4115:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":360,"nodeType":"ExpressionStatement","src":"4115:26:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f7065206d73672e73656e646572","id":364,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4163:25:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},"value":"parent scope msg.sender"},{"arguments":[{"expression":{"id":367,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"4198:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":368,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"4198:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":366,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4190:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":365,"name":"address","nodeType":"ElementaryTypeName","src":"4190:7:0","typeDescriptions":{}}},"id":369,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4190:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":361,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4151:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":363,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4151:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":370,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4151:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":371,"nodeType":"ExpressionStatement","src":"4151:59:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f706520636f6e74726163742e61646472","id":375,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4232:28:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},"value":"parent scope contract.addr"},{"arguments":[{"id":378,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4270:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":377,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4262:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":376,"name":"address","nodeType":"ElementaryTypeName","src":"4262:7:0","typeDescriptions":{}}},"id":379,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4262:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":372,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4220:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":374,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4220:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":380,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4220:56:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":381,"nodeType":"ExpressionStatement","src":"4220:56:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2032","id":385,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4297:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""},"value":"from prank 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""}],"expression":{"id":382,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4286:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":384,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4286:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":386,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4286:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":387,"nodeType":"ExpressionStatement","src":"4286:26:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":388,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4322:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":390,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopPrank","nodeType":"MemberAccess","referencedDeclaration":35,"src":"4322:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":391,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4322:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":392,"nodeType":"ExpressionStatement","src":"4322:14:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c20616761696e","id":396,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4357:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""},"value":"from original again"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""}],"expression":{"id":393,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4346:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":395,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4346:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":397,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4346:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":398,"nodeType":"ExpressionStatement","src":"4346:33:0"},{"assignments":[400],"declarations":[{"constant":false,"id":400,"mutability":"mutable","name":"tmpNonceGetter","nameLocation":"4480:14:0","nodeType":"VariableDeclaration","scope":455,"src":"4472:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":399,"name":"address","nodeType":"ElementaryTypeName","src":"4472:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":413,"initialValue":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"74656d70206e6f6e6365207465737420676574746572","id":408,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4531:24:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""},"value":"temp nonce test getter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""}],"id":407,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"4521:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":409,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4521:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":406,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4513:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":405,"name":"uint256","nodeType":"ElementaryTypeName","src":"4513:7:0","typeDescriptions":{}}},"id":410,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4513:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":404,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4505:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":403,"name":"uint160","nodeType":"ElementaryTypeName","src":"4505:7:0","typeDescriptions":{}}},"id":411,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4505:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":402,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4497:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":401,"name":"address","nodeType":"ElementaryTypeName","src":"4497:7:0","typeDescriptions":{}}},"id":412,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4497:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"4472:87:0"},{"expression":{"arguments":[{"id":417,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4577:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"arguments":[{"hexValue":"5363726970744578616d706c652e732e736f6c3a4e6f6e6365476574746572","id":420,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4612:33:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""},"value":"ScriptExample.s.sol:NonceGetter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""}],"expression":{"id":418,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4593:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":419,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getDeployedCode","nodeType":"MemberAccess","referencedDeclaration":61,"src":"4593:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) view external returns (bytes memory)"}},"id":421,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4593:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"expression":{"id":414,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4569:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":416,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"etch","nodeType":"MemberAccess","referencedDeclaration":68,"src":"4569:7:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$_t_bytes_memory_ptr_$returns$__$","typeString":"function (address,bytes memory) external"}},"id":422,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4569:78:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":423,"nodeType":"ExpressionStatement","src":"4569:78:0"},{"expression":{"arguments":[{"id":427,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4676:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":424,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4657:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":426,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"allowCheatcodes","nodeType":"MemberAccess","referencedDeclaration":73,"src":"4657:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":428,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4657:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":429,"nodeType":"ExpressionStatement","src":"4657:34:0"},{"assignments":[431],"declarations":[{"constant":false,"id":431,"mutability":"mutable","name":"v","nameLocation":"4709:1:0","nodeType":"VariableDeclaration","scope":455,"src":"4701:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":430,"name":"uint256","nodeType":"ElementaryTypeName","src":"4701:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":441,"initialValue":{"arguments":[{"arguments":[{"id":438,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4758:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":437,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4750:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":436,"name":"address","nodeType":"ElementaryTypeName","src":"4750:7:0","typeDescriptions":{}}},"id":439,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4750:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"arguments":[{"id":433,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4725:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":432,"name":"NonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":833,"src":"4713:11:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_NonceGetter_$833_$","typeString":"type(contract NonceGetter)"}},"id":434,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_NonceGetter_$833","typeString":"contract NonceGetter"}},"id":435,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":832,"src":"4713:36:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint256_$","typeString":"function (address) view external returns (uint256)"}},"id":440,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"4701:63:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e63652066726f6d206e6f6e6365206765747465722c206e6f206578706c6963697420616363657373207265717569726564207769746820766d2e657463683a","id":445,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4786:68:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},"value":"nonce from nonce getter, no explicit access required with vm.etch:"},{"id":446,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":431,"src":"4856:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":442,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4774:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":444,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"4774:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":447,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4774:84:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":448,"nodeType":"ExpressionStatement","src":"4774:84:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":452,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4881:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":449,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4869:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":451,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"4869:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":453,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4869:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":454,"nodeType":"ExpressionStatement","src":"4869:20:0"}]},"documentation":{"id":244,"nodeType":"StructuredDocumentation","src":"3385:78:0","text":"@notice example function, runs through basic cheat-codes and console logs."},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"3477:3:0","parameters":{"id":245,"nodeType":"ParameterList","parameters":[],"src":"3480:2:0"},"returnParameters":{"id":246,"nodeType":"ParameterList","parameters":[],"src":"3490:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":689,"nodeType":"FunctionDefinition","src":"4963:1333:0","nodes":[],"body":{"id":688,"nodeType":"Block","src":"4994:1302:0","nodes":[],"statements":[{"expression":{"arguments":[{"hexValue":"6e6f6e6365207374617274","id":463,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5016:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},"value":"nonce start"},{"arguments":[{"arguments":[{"arguments":[{"id":470,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5059:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":469,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5051:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":468,"name":"address","nodeType":"ElementaryTypeName","src":"5051:7:0","typeDescriptions":{}}},"id":471,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5051:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":466,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5039:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":467,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"5039:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":472,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5039:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":465,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5031:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":464,"name":"uint256","nodeType":"ElementaryTypeName","src":"5031:7:0","typeDescriptions":{}}},"id":473,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5031:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":460,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5004:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":462,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"5004:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":474,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5004:63:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":475,"nodeType":"ExpressionStatement","src":"5004:63:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073696e676c65","id":479,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5090:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""},"value":"testing single"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""}],"expression":{"id":476,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5078:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":478,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5078:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":480,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5078:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":481,"nodeType":"ExpressionStatement","src":"5078:29:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":482,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5117:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":484,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"5117:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":485,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5117:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":486,"nodeType":"ExpressionStatement","src":"5117:14:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c31","id":490,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5152:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""},"value":"single_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""}],"expression":{"id":487,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5141:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":489,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5141:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":491,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5141:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":492,"nodeType":"ExpressionStatement","src":"5141:26:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c32","id":496,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5188:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""},"value":"single_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""}],"expression":{"id":493,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5177:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":495,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5177:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":497,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5177:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":498,"nodeType":"ExpressionStatement","src":"5177:26:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073746172742f73746f70","id":502,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5226:20:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""},"value":"testing start/stop"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""}],"expression":{"id":499,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5214:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":501,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5214:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":503,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5214:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":504,"nodeType":"ExpressionStatement","src":"5214:33:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078633066666565","id":512,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5291:8:0","typeDescriptions":{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"},"value":"0xc0ffee"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"}],"id":511,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5283:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":510,"name":"uint160","nodeType":"ElementaryTypeName","src":"5283:7:0","typeDescriptions":{}}},"id":513,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5283:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":509,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5275:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":508,"name":"address","nodeType":"ElementaryTypeName","src":"5275:7:0","typeDescriptions":{}}},"id":514,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5275:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":505,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5257:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":507,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5257:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":515,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5257:45:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":516,"nodeType":"ExpressionStatement","src":"5257:45:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c31","id":520,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5323:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""},"value":"startstop_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""}],"expression":{"id":517,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5312:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":519,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5312:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":521,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5312:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":522,"nodeType":"ExpressionStatement","src":"5312:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c32","id":526,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5362:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""},"value":"startstop_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""}],"expression":{"id":523,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5351:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":525,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5351:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":527,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5351:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":528,"nodeType":"ExpressionStatement","src":"5351:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f70757265","id":532,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5404:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""},"value":"startstop_pure"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""}],"expression":{"id":529,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5390:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":531,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"callPure","nodeType":"MemberAccess","referencedDeclaration":785,"src":"5390:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure external"}},"id":533,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5390:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":534,"nodeType":"ExpressionStatement","src":"5390:31:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":535,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5431:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":537,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5431:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":538,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5431:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":539,"nodeType":"ExpressionStatement","src":"5431:18:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c33","id":543,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5470:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""},"value":"startstop_call3"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""}],"expression":{"id":540,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5459:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":542,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5459:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":544,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5459:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":545,"nodeType":"ExpressionStatement","src":"5459:29:0"},{"expression":{"arguments":[{"hexValue":"74657374696e67206e6573746564","id":549,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5511:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""},"value":"testing nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""}],"expression":{"id":546,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5499:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":548,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5499:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":550,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5499:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":551,"nodeType":"ExpressionStatement","src":"5499:29:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307831323334","id":559,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5572:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":558,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5564:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":557,"name":"uint160","nodeType":"ElementaryTypeName","src":"5564:7:0","typeDescriptions":{}}},"id":560,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5564:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":556,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5556:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":555,"name":"address","nodeType":"ElementaryTypeName","src":"5556:7:0","typeDescriptions":{}}},"id":561,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5556:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":552,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5538:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":554,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5538:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":562,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5538:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":563,"nodeType":"ExpressionStatement","src":"5538:43:0"},{"expression":{"arguments":[{"hexValue":"6e6573746564","id":567,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5604:8:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""},"value":"nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""}],"expression":{"id":564,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5591:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":566,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested1","nodeType":"MemberAccess","referencedDeclaration":758,"src":"5591:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":568,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5591:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":569,"nodeType":"ExpressionStatement","src":"5591:22:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":570,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5623:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":572,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5623:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":573,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5623:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":574,"nodeType":"ExpressionStatement","src":"5623:18:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206465706c6f796d656e74","id":578,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5664:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""},"value":"contract deployment"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""}],"expression":{"id":575,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5652:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":577,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5652:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":579,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5652:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":580,"nodeType":"ExpressionStatement","src":"5652:34:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078313233343536","id":588,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5725:8:0","typeDescriptions":{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"},"value":"0x123456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"}],"id":587,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5717:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":586,"name":"uint160","nodeType":"ElementaryTypeName","src":"5717:7:0","typeDescriptions":{}}},"id":589,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5717:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":585,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5709:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":584,"name":"address","nodeType":"ElementaryTypeName","src":"5709:7:0","typeDescriptions":{}}},"id":590,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5709:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":581,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5696:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":583,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5696:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":591,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5696:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":592,"nodeType":"ExpressionStatement","src":"5696:40:0"},{"assignments":[595],"declarations":[{"constant":false,"id":595,"mutability":"mutable","name":"x","nameLocation":"5753:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5746:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":594,"nodeType":"UserDefinedTypeName","pathNode":{"id":593,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5746:6:0"},"referencedDeclaration":799,"src":"5746:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":601,"initialValue":{"arguments":[{"hexValue":"31323334","id":599,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5768:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":598,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5757:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":597,"nodeType":"UserDefinedTypeName","pathNode":{"id":596,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5761:6:0"},"referencedDeclaration":799,"src":"5761:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":600,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5757:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5746:27:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":607,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":603,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":595,"src":"5791:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":604,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"5791:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":605,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5791:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":606,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5802:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"5791:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e20637265617465206973206e6f742031323334","id":608,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5808:35:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""},"value":"FooBar: foo in create is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""}],"id":602,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"5783:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":609,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5783:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":610,"nodeType":"ExpressionStatement","src":"5783:61:0"},{"expression":{"arguments":[{"hexValue":"6372656174652032","id":614,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5867:10:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""},"value":"create 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""}],"expression":{"id":611,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5855:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":613,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5855:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":615,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5855:23:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":616,"nodeType":"ExpressionStatement","src":"5855:23:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307863616665","id":624,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5917:6:0","typeDescriptions":{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"},"value":"0xcafe"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"}],"id":623,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5909:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":622,"name":"uint160","nodeType":"ElementaryTypeName","src":"5909:7:0","typeDescriptions":{}}},"id":625,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5909:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":621,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5901:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":620,"name":"address","nodeType":"ElementaryTypeName","src":"5901:7:0","typeDescriptions":{}}},"id":626,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5901:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":617,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5888:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":619,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5888:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":627,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5888:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":628,"nodeType":"ExpressionStatement","src":"5888:38:0"},{"assignments":[631],"declarations":[{"constant":false,"id":631,"mutability":"mutable","name":"y","nameLocation":"5943:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5936:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":630,"nodeType":"UserDefinedTypeName","pathNode":{"id":629,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5936:6:0"},"referencedDeclaration":799,"src":"5936:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":645,"initialValue":{"arguments":[{"hexValue":"31323334","id":643,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5986:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":634,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5947:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":633,"nodeType":"UserDefinedTypeName","pathNode":{"id":632,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5951:6:0"},"referencedDeclaration":799,"src":"5951:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":642,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"names":["salt"],"nodeType":"FunctionCallOptions","options":[{"arguments":[{"arguments":[{"hexValue":"3432","id":639,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5980:2:0","typeDescriptions":{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"},"value":"42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"}],"id":638,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5972:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":637,"name":"uint256","nodeType":"ElementaryTypeName","src":"5972:7:0","typeDescriptions":{}}},"id":640,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5972:11:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":636,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5964:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":635,"name":"bytes32","nodeType":"ElementaryTypeName","src":"5964:7:0","typeDescriptions":{}}},"id":641,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5964:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"src":"5947:38:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$salt","typeString":"function (uint256) returns (contract FooBar)"}},"id":644,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5947:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5936:55:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":651,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":647,"name":"y","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":631,"src":"6009:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":648,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"6009:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":649,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6009:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":650,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6020:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"6009:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e2063726561746532206973206e6f742031323334","id":652,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6026:36:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""},"value":"FooBar: foo in create2 is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""}],"id":646,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"6001:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":653,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6001:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":654,"nodeType":"ExpressionStatement","src":"6001:62:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":658,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6085:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":655,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6073:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":657,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6073:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":659,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6073:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":660,"nodeType":"ExpressionStatement","src":"6073:20:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":661,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6177:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":663,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"6177:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":664,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6177:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":665,"nodeType":"ExpressionStatement","src":"6177:14:0"},{"expression":{"arguments":[{"hexValue":"31323334","id":669,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6212:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":668,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"6201:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":667,"nodeType":"UserDefinedTypeName","pathNode":{"id":666,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"6205:6:0"},"referencedDeclaration":799,"src":"6205:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":670,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6201:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":671,"nodeType":"ExpressionStatement","src":"6201:16:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e636520656e64","id":675,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6240:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},"value":"nonce end"},{"arguments":[{"arguments":[{"arguments":[{"id":682,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6281:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":681,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6273:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":680,"name":"address","nodeType":"ElementaryTypeName","src":"6273:7:0","typeDescriptions":{}}},"id":683,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6273:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":678,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6261:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":679,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"6261:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":684,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6261:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":677,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6253:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":676,"name":"uint256","nodeType":"ElementaryTypeName","src":"6253:7:0","typeDescriptions":{}}},"id":685,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6253:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":672,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6228:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":674,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"6228:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":686,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6228:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":687,"nodeType":"ExpressionStatement","src":"6228:61:0"}]},"documentation":{"id":457,"nodeType":"StructuredDocumentation","src":"4902:56:0","text":"@notice example function, to test vm.broadcast with."},"functionSelector":"bef03abc","implemented":true,"kind":"function","modifiers":[],"name":"runBroadcast","nameLocation":"4972:12:0","parameters":{"id":458,"nodeType":"ParameterList","parameters":[],"src":"4984:2:0"},"returnParameters":{"id":459,"nodeType":"ParameterList","parameters":[],"src":"4994:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":713,"nodeType":"FunctionDefinition","src":"6391:143:0","nodes":[],"body":{"id":712,"nodeType":"Block","src":"6440:94:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":698,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":692,"src":"6462:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":695,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6450:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":697,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6450:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":699,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6450:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":700,"nodeType":"ExpressionStatement","src":"6450:15:0"},{"expression":{"arguments":[{"hexValue":"68656c6c6f206d73672e73656e646572","id":704,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6487:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},"value":"hello msg.sender"},{"arguments":[{"expression":{"id":707,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"6515:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":708,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"6515:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":706,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6507:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":705,"name":"address","nodeType":"ElementaryTypeName","src":"6507:7:0","typeDescriptions":{}}},"id":709,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6507:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":701,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6475:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":703,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"6475:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":710,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6475:52:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":711,"nodeType":"ExpressionStatement","src":"6475:52:0"}]},"documentation":{"id":690,"nodeType":"StructuredDocumentation","src":"6302:84:0","text":"@notice example external function, to force a CALL, and test vm.startPrank with."},"functionSelector":"a777d0dc","implemented":true,"kind":"function","modifiers":[],"name":"hello","nameLocation":"6400:5:0","parameters":{"id":693,"nodeType":"ParameterList","parameters":[{"constant":false,"id":692,"mutability":"mutable","name":"_v","nameLocation":"6422:2:0","nodeType":"VariableDeclaration","scope":713,"src":"6406:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":691,"name":"string","nodeType":"ElementaryTypeName","src":"6406:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6405:20:0"},"returnParameters":{"id":694,"nodeType":"ParameterList","parameters":[],"src":"6440:0:0"},"scope":786,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":728,"nodeType":"FunctionDefinition","src":"6540:95:0","nodes":[],"body":{"id":727,"nodeType":"Block","src":"6584:51:0","nodes":[],"statements":[{"expression":{"id":719,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6594:9:0","subExpression":{"id":718,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6594:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":720,"nodeType":"ExpressionStatement","src":"6594:9:0"},{"expression":{"arguments":[{"id":724,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":715,"src":"6625:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":721,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6613:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":723,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6613:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":725,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6613:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":726,"nodeType":"ExpressionStatement","src":"6613:15:0"}]},"functionSelector":"7e79255d","implemented":true,"kind":"function","modifiers":[],"name":"call1","nameLocation":"6549:5:0","parameters":{"id":716,"nodeType":"ParameterList","parameters":[{"constant":false,"id":715,"mutability":"mutable","name":"_v","nameLocation":"6571:2:0","nodeType":"VariableDeclaration","scope":728,"src":"6555:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":714,"name":"string","nodeType":"ElementaryTypeName","src":"6555:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6554:20:0"},"returnParameters":{"id":717,"nodeType":"ParameterList","parameters":[],"src":"6584:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":743,"nodeType":"FunctionDefinition","src":"6641:95:0","nodes":[],"body":{"id":742,"nodeType":"Block","src":"6685:51:0","nodes":[],"statements":[{"expression":{"id":734,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6695:9:0","subExpression":{"id":733,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6695:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":735,"nodeType":"ExpressionStatement","src":"6695:9:0"},{"expression":{"arguments":[{"id":739,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":730,"src":"6726:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":736,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6714:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":738,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6714:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":740,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6714:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":741,"nodeType":"ExpressionStatement","src":"6714:15:0"}]},"functionSelector":"8d3ef7ca","implemented":true,"kind":"function","modifiers":[],"name":"call2","nameLocation":"6650:5:0","parameters":{"id":731,"nodeType":"ParameterList","parameters":[{"constant":false,"id":730,"mutability":"mutable","name":"_v","nameLocation":"6672:2:0","nodeType":"VariableDeclaration","scope":743,"src":"6656:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":729,"name":"string","nodeType":"ElementaryTypeName","src":"6656:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6655:20:0"},"returnParameters":{"id":732,"nodeType":"ParameterList","parameters":[],"src":"6685:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":758,"nodeType":"FunctionDefinition","src":"6742:98:0","nodes":[],"body":{"id":757,"nodeType":"Block","src":"6788:52:0","nodes":[],"statements":[{"expression":{"id":749,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6798:9:0","subExpression":{"id":748,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6798:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":750,"nodeType":"ExpressionStatement","src":"6798:9:0"},{"expression":{"arguments":[{"id":754,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":745,"src":"6830:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":751,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6817:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":753,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested2","nodeType":"MemberAccess","referencedDeclaration":773,"src":"6817:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":755,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6817:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":756,"nodeType":"ExpressionStatement","src":"6817:16:0"}]},"functionSelector":"a76ccdfa","implemented":true,"kind":"function","modifiers":[],"name":"nested1","nameLocation":"6751:7:0","parameters":{"id":746,"nodeType":"ParameterList","parameters":[{"constant":false,"id":745,"mutability":"mutable","name":"_v","nameLocation":"6775:2:0","nodeType":"VariableDeclaration","scope":758,"src":"6759:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":744,"name":"string","nodeType":"ElementaryTypeName","src":"6759:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6758:20:0"},"returnParameters":{"id":747,"nodeType":"ParameterList","parameters":[],"src":"6788:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":773,"nodeType":"FunctionDefinition","src":"6846:97:0","nodes":[],"body":{"id":772,"nodeType":"Block","src":"6892:51:0","nodes":[],"statements":[{"expression":{"id":764,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6902:9:0","subExpression":{"id":763,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6902:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":765,"nodeType":"ExpressionStatement","src":"6902:9:0"},{"expression":{"arguments":[{"id":769,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":760,"src":"6933:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":766,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6921:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":768,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6921:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":770,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6921:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":771,"nodeType":"ExpressionStatement","src":"6921:15:0"}]},"functionSelector":"dbf1282f","implemented":true,"kind":"function","modifiers":[],"name":"nested2","nameLocation":"6855:7:0","parameters":{"id":761,"nodeType":"ParameterList","parameters":[{"constant":false,"id":760,"mutability":"mutable","name":"_v","nameLocation":"6879:2:0","nodeType":"VariableDeclaration","scope":773,"src":"6863:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":759,"name":"string","nodeType":"ElementaryTypeName","src":"6863:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6862:20:0"},"returnParameters":{"id":762,"nodeType":"ParameterList","parameters":[],"src":"6892:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":785,"nodeType":"FunctionDefinition","src":"6949:84:0","nodes":[],"body":{"id":784,"nodeType":"Block","src":"7001:32:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":781,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":775,"src":"7023:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":778,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"7011:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":780,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"7011:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":782,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7011:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":783,"nodeType":"ExpressionStatement","src":"7011:15:0"}]},"functionSelector":"7f8b915c","implemented":true,"kind":"function","modifiers":[],"name":"callPure","nameLocation":"6958:8:0","parameters":{"id":776,"nodeType":"ParameterList","parameters":[{"constant":false,"id":775,"mutability":"mutable","name":"_v","nameLocation":"6983:2:0","nodeType":"VariableDeclaration","scope":785,"src":"6967:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":774,"name":"string","nodeType":"ElementaryTypeName","src":"6967:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6966:20:0"},"returnParameters":{"id":777,"nodeType":"ParameterList","parameters":[],"src":"7001:0:0"},"scope":786,"stateMutability":"pure","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ScriptExample","contractDependencies":[799],"contractKind":"contract","documentation":{"id":221,"nodeType":"StructuredDocumentation","src":"2997:126:0","text":"@title ScriptExample\n @notice ScriptExample is an example script. The Go forge script code tests that it can run this."},"fullyImplemented":true,"linearizedBaseContracts":[786],"name":"ScriptExample","nameLocation":"3132:13:0","scope":969,"usedErrors":[]},{"id":799,"nodeType":"ContractDefinition","src":"7037:96:0","nodes":[{"id":788,"nodeType":"VariableDeclaration","src":"7059:18:0","nodes":[],"constant":false,"functionSelector":"c2985578","mutability":"mutable","name":"foo","nameLocation":"7074:3:0","scope":799,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":787,"name":"uint256","nodeType":"ElementaryTypeName","src":"7059:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":798,"nodeType":"FunctionDefinition","src":"7084:47:0","nodes":[],"body":{"id":797,"nodeType":"Block","src":"7107:24:0","nodes":[],"statements":[{"expression":{"id":795,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":793,"name":"foo","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":788,"src":"7117:3:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":794,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":790,"src":"7123:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"7117:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":796,"nodeType":"ExpressionStatement","src":"7117:7:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":791,"nodeType":"ParameterList","parameters":[{"constant":false,"id":790,"mutability":"mutable","name":"v","nameLocation":"7104:1:0","nodeType":"VariableDeclaration","scope":798,"src":"7096:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":789,"name":"uint256","nodeType":"ElementaryTypeName","src":"7096:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7095:11:0"},"returnParameters":{"id":792,"nodeType":"ParameterList","parameters":[],"src":"7107:0:0"},"scope":799,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"FooBar","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[799],"name":"FooBar","nameLocation":"7046:6:0","scope":969,"usedErrors":[]},{"id":833,"nodeType":"ContractDefinition","src":"7135:281:0","nodes":[{"id":813,"nodeType":"VariableDeclaration","src":"7162:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7188:10:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":800,"name":"address","nodeType":"ElementaryTypeName","src":"7162:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":808,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7235:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":807,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7225:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":809,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7225:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":806,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7217:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":805,"name":"uint256","nodeType":"ElementaryTypeName","src":"7217:7:0","typeDescriptions":{}}},"id":810,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7217:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":804,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7209:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":803,"name":"uint160","nodeType":"ElementaryTypeName","src":"7209:7:0","typeDescriptions":{}}},"id":811,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7209:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":802,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":801,"name":"address","nodeType":"ElementaryTypeName","src":"7201:7:0","typeDescriptions":{}}},"id":812,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7201:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":819,"nodeType":"VariableDeclaration","src":"7262:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7283:2:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":815,"nodeType":"UserDefinedTypeName","pathNode":{"id":814,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7262:2:0"},"referencedDeclaration":83,"src":"7262:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":817,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":813,"src":"7291:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":816,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7288:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":818,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7288:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":832,"nodeType":"FunctionDefinition","src":"7309:105:0","nodes":[],"body":{"id":831,"nodeType":"Block","src":"7372:42:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":828,"name":"_addr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":821,"src":"7401:5:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":826,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":819,"src":"7389:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":827,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7389:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":829,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7389:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"functionReturnParameters":825,"id":830,"nodeType":"Return","src":"7382:25:0"}]},"functionSelector":"2d0335ab","implemented":true,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"7318:8:0","parameters":{"id":822,"nodeType":"ParameterList","parameters":[{"constant":false,"id":821,"mutability":"mutable","name":"_addr","nameLocation":"7335:5:0","nodeType":"VariableDeclaration","scope":832,"src":"7327:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":820,"name":"address","nodeType":"ElementaryTypeName","src":"7327:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"7326:15:0"},"returnParameters":{"id":825,"nodeType":"ParameterList","parameters":[{"constant":false,"id":824,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":832,"src":"7363:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":823,"name":"uint256","nodeType":"ElementaryTypeName","src":"7363:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7362:9:0"},"scope":833,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"NonceGetter","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[833],"name":"NonceGetter","nameLocation":"7144:11:0","scope":969,"usedErrors":[]},{"id":852,"nodeType":"ContractDefinition","src":"7418:174:0","nodes":[{"id":835,"nodeType":"VariableDeclaration","src":"7448:18:0","nodes":[],"constant":false,"mutability":"mutable","name":"v","nameLocation":"7465:1:0","scope":852,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":834,"name":"uint256","nodeType":"ElementaryTypeName","src":"7448:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"id":843,"nodeType":"FunctionDefinition","src":"7473:36:0","nodes":[],"body":{"id":842,"nodeType":"Block","src":"7487:22:0","nodes":[],"statements":[{"expression":{"id":840,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":838,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7497:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"hexValue":"31","id":839,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7501:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"7497:5:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":841,"nodeType":"ExpressionStatement","src":"7497:5:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":836,"nodeType":"ParameterList","parameters":[],"src":"7484:2:0"},"returnParameters":{"id":837,"nodeType":"ParameterList","parameters":[],"src":"7487:0:0"},"scope":852,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":851,"nodeType":"FunctionDefinition","src":"7515:75:0","nodes":[],"body":{"id":850,"nodeType":"Block","src":"7565:25:0","nodes":[],"statements":[{"expression":{"id":848,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7582:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"functionReturnParameters":847,"id":849,"nodeType":"Return","src":"7575:8:0"}]},"functionSelector":"20965255","implemented":true,"kind":"function","modifiers":[],"name":"getValue","nameLocation":"7524:8:0","parameters":{"id":844,"nodeType":"ParameterList","parameters":[],"src":"7532:2:0"},"returnParameters":{"id":847,"nodeType":"ParameterList","parameters":[{"constant":false,"id":846,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":851,"src":"7556:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":845,"name":"uint256","nodeType":"ElementaryTypeName","src":"7556:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7555:9:0"},"scope":852,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkedContract","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[852],"name":"ForkedContract","nameLocation":"7427:14:0","scope":969,"usedErrors":[]},{"id":968,"nodeType":"ContractDefinition","src":"7594:813:0","nodes":[{"id":866,"nodeType":"VariableDeclaration","src":"7620:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7646:10:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":853,"name":"address","nodeType":"ElementaryTypeName","src":"7620:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":861,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7693:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":860,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7683:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":862,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7683:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":859,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7675:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":858,"name":"uint256","nodeType":"ElementaryTypeName","src":"7675:7:0","typeDescriptions":{}}},"id":863,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7675:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":857,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7667:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":856,"name":"uint160","nodeType":"ElementaryTypeName","src":"7667:7:0","typeDescriptions":{}}},"id":864,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7667:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":855,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7659:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":854,"name":"address","nodeType":"ElementaryTypeName","src":"7659:7:0","typeDescriptions":{}}},"id":865,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7659:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":872,"nodeType":"VariableDeclaration","src":"7720:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7741:2:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":868,"nodeType":"UserDefinedTypeName","pathNode":{"id":867,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7720:2:0"},"referencedDeclaration":83,"src":"7720:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":870,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":866,"src":"7749:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":869,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7746:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":871,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7746:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":967,"nodeType":"FunctionDefinition","src":"7767:638:0","nodes":[],"body":{"id":966,"nodeType":"Block","src":"7791:614:0","nodes":[],"statements":[{"assignments":[876],"declarations":[{"constant":false,"id":876,"mutability":"mutable","name":"testAddr","nameLocation":"7809:8:0","nodeType":"VariableDeclaration","scope":966,"src":"7801:16:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":875,"name":"address","nodeType":"ElementaryTypeName","src":"7801:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":884,"initialValue":{"arguments":[{"arguments":[{"hexValue":"307831323334","id":881,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7836:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":880,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7828:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":879,"name":"uint160","nodeType":"ElementaryTypeName","src":"7828:7:0","typeDescriptions":{}}},"id":882,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7828:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":878,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7820:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":877,"name":"address","nodeType":"ElementaryTypeName","src":"7820:7:0","typeDescriptions":{}}},"id":883,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7820:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"7801:43:0"},{"assignments":[887],"declarations":[{"constant":false,"id":887,"mutability":"mutable","name":"fc","nameLocation":"7869:2:0","nodeType":"VariableDeclaration","scope":966,"src":"7854:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"},"typeName":{"id":886,"nodeType":"UserDefinedTypeName","pathNode":{"id":885,"name":"ForkedContract","nodeType":"IdentifierPath","referencedDeclaration":852,"src":"7854:14:0"},"referencedDeclaration":852,"src":"7854:14:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"visibility":"internal"}],"id":891,"initialValue":{"arguments":[{"id":889,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7889:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":888,"name":"ForkedContract","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":852,"src":"7874:14:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_ForkedContract_$852_$","typeString":"type(contract ForkedContract)"}},"id":890,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7874:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"nodeType":"VariableDeclarationStatement","src":"7854:44:0"},{"expression":{"arguments":[{"hexValue":"666f726b31","id":895,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7929:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},"value":"fork1"},{"hexValue":"3132333435","id":896,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7938:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"}],"expression":{"id":892,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7909:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":894,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"7909:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":897,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7909:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":898,"nodeType":"ExpressionStatement","src":"7909:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":905,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":902,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7974:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":900,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7962:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":901,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7962:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":903,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7962:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3132333435","id":904,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7987:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"},"src":"7962:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":906,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7994:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":899,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"7954:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":907,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7954:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":908,"nodeType":"ExpressionStatement","src":"7954:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":914,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":910,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8036:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":911,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8036:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":912,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8036:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31","id":913,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8053:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"8036:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652031","id":915,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8056:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""},"value":"value should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""}],"id":909,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8028:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":916,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8028:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":917,"nodeType":"ExpressionStatement","src":"8028:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":925,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":919,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8094:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":920,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8094:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"31","id":923,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8122:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"}],"id":922,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8114:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":921,"name":"uint256","nodeType":"ElementaryTypeName","src":"8114:7:0","typeDescriptions":{}}},"id":924,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8114:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8094:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652031","id":926,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8126:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""},"value":"balance should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""}],"id":918,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8086:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":927,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8086:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":928,"nodeType":"ExpressionStatement","src":"8086:62:0"},{"expression":{"arguments":[{"hexValue":"666f726b32","id":932,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8179:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},"value":"fork2"},{"hexValue":"3233343536","id":933,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8188:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"}],"expression":{"id":929,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8159:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":931,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"8159:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":934,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8159:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":935,"nodeType":"ExpressionStatement","src":"8159:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":942,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":939,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8224:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":937,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8212:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":938,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"8212:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":940,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8212:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3233343536","id":941,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8237:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"},"src":"8212:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":943,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8244:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":936,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8204:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":944,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8204:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":945,"nodeType":"ExpressionStatement","src":"8204:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":951,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":947,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8286:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":948,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8286:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":949,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8286:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"32","id":950,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8303:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"},"src":"8286:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652032","id":952,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8306:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""},"value":"value should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""}],"id":946,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8278:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":953,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8278:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":954,"nodeType":"ExpressionStatement","src":"8278:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":962,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":956,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8344:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":957,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8344:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"32","id":960,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8372:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"}],"id":959,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8364:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":958,"name":"uint256","nodeType":"ElementaryTypeName","src":"8364:7:0","typeDescriptions":{}}},"id":961,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8364:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8344:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652032","id":963,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8376:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""},"value":"balance should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""}],"id":955,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8336:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":964,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8336:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":965,"nodeType":"ExpressionStatement","src":"8336:62:0"}]},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"7776:3:0","parameters":{"id":873,"nodeType":"ParameterList","parameters":[],"src":"7779:2:0"},"returnParameters":{"id":874,"nodeType":"ParameterList","parameters":[],"src":"7791:0:0"},"scope":968,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkTester","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[968],"name":"ForkTester","nameLocation":"7603:10:0","scope":969,"usedErrors":[]}],"license":"MIT"},"id":0} \ No newline at end of file diff --git a/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/Vm.json b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/Vm.json index 34175684c5aaa..3861727127444 100644 --- a/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/Vm.json +++ b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/Vm.json @@ -1 +1 @@ -{"abi":[{"type":"function","name":"broadcast","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"broadcast","inputs":[{"name":"msgSender","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"envOr","inputs":[{"name":"name","type":"string","internalType":"string"},{"name":"defaultValue","type":"bool","internalType":"bool"}],"outputs":[{"name":"value","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"getNonce","inputs":[{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"nonce","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"parseJsonKeys","inputs":[{"name":"json","type":"string","internalType":"string"},{"name":"key","type":"string","internalType":"string"}],"outputs":[{"name":"keys","type":"string[]","internalType":"string[]"}],"stateMutability":"pure"},{"type":"function","name":"startBroadcast","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"startBroadcast","inputs":[{"name":"msgSender","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"startPrank","inputs":[{"name":"msgSender","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"stopBroadcast","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"stopPrank","inputs":[],"outputs":[],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"broadcast()":"afc98040","broadcast(address)":"e6962cdb","envOr(string,bool)":"4777f3cf","getNonce(address)":"2d0335ab","parseJsonKeys(string,string)":"213e4198","startBroadcast()":"7fb5297f","startBroadcast(address)":"7fec2a8d","startPrank(address)":"06447d56","stopBroadcast()":"76eadd36","stopPrank()":"90c5013b"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"broadcast\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"msgSender\",\"type\":\"address\"}],\"name\":\"broadcast\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"defaultValue\",\"type\":\"bool\"}],\"name\":\"envOr\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"json\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"}],\"name\":\"parseJsonKeys\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"keys\",\"type\":\"string[]\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"startBroadcast\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"msgSender\",\"type\":\"address\"}],\"name\":\"startBroadcast\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"msgSender\",\"type\":\"address\"}],\"name\":\"startPrank\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stopBroadcast\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stopPrank\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"scripts/ScriptExample.s.sol\":\"Vm\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"scripts/ScriptExample.s.sol\":{\"keccak256\":\"0x8d1dfa41908e7ccc3a498a2a2aa51c5275bedbb904ce32d08f8598e36f896d8d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5117bb7158363cae8b9dc0508d2852692fd36172f1c699ff680afbb5acebe1f3\",\"dweb:/ipfs/QmQdahJ8SPKfJ4yea5Ge9qaj5qh1TxVffhHvaWytBaL95h\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"broadcast"},{"inputs":[{"internalType":"address","name":"msgSender","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"broadcast"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"bool","name":"defaultValue","type":"bool"}],"stateMutability":"view","type":"function","name":"envOr","outputs":[{"internalType":"bool","name":"value","type":"bool"}]},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"stateMutability":"view","type":"function","name":"getNonce","outputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}]},{"inputs":[{"internalType":"string","name":"json","type":"string"},{"internalType":"string","name":"key","type":"string"}],"stateMutability":"pure","type":"function","name":"parseJsonKeys","outputs":[{"internalType":"string[]","name":"keys","type":"string[]"}]},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"startBroadcast"},{"inputs":[{"internalType":"address","name":"msgSender","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"startBroadcast"},{"inputs":[{"internalType":"address","name":"msgSender","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"startPrank"},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"stopBroadcast"},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"stopPrank"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"scripts/ScriptExample.s.sol":"Vm"},"evmVersion":"london","libraries":{}},"sources":{"scripts/ScriptExample.s.sol":{"keccak256":"0x8d1dfa41908e7ccc3a498a2a2aa51c5275bedbb904ce32d08f8598e36f896d8d","urls":["bzz-raw://5117bb7158363cae8b9dc0508d2852692fd36172f1c699ff680afbb5acebe1f3","dweb:/ipfs/QmQdahJ8SPKfJ4yea5Ge9qaj5qh1TxVffhHvaWytBaL95h"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[],"types":{}},"userdoc":{"version":1,"kind":"user"},"devdoc":{"version":1,"kind":"dev"},"ast":{"absolutePath":"scripts/ScriptExample.s.sol","id":720,"exportedSymbols":{"FooBar":[719],"ScriptExample":[706],"Vm":[55],"console":[192]},"nodeType":"SourceUnit","src":"32:5967:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","0.8",".15"]},{"id":55,"nodeType":"ContractDefinition","src":"120:616:0","nodes":[{"id":10,"nodeType":"FunctionDefinition","src":"139:91:0","nodes":[],"functionSelector":"4777f3cf","implemented":false,"kind":"function","modifiers":[],"name":"envOr","nameLocation":"148:5:0","parameters":{"id":6,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"mutability":"mutable","name":"name","nameLocation":"170:4:0","nodeType":"VariableDeclaration","scope":10,"src":"154:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":2,"name":"string","nodeType":"ElementaryTypeName","src":"154:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":5,"mutability":"mutable","name":"defaultValue","nameLocation":"181:12:0","nodeType":"VariableDeclaration","scope":10,"src":"176:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":4,"name":"bool","nodeType":"ElementaryTypeName","src":"176:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"153:41:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[{"constant":false,"id":8,"mutability":"mutable","name":"value","nameLocation":"223:5:0","nodeType":"VariableDeclaration","scope":10,"src":"218:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":7,"name":"bool","nodeType":"ElementaryTypeName","src":"218:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"217:12:0"},"scope":55,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":17,"nodeType":"FunctionDefinition","src":"235:72:0","nodes":[],"functionSelector":"2d0335ab","implemented":false,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"244:8:0","parameters":{"id":13,"nodeType":"ParameterList","parameters":[{"constant":false,"id":12,"mutability":"mutable","name":"account","nameLocation":"261:7:0","nodeType":"VariableDeclaration","scope":17,"src":"253:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":11,"name":"address","nodeType":"ElementaryTypeName","src":"253:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"252:17:0"},"returnParameters":{"id":16,"nodeType":"ParameterList","parameters":[{"constant":false,"id":15,"mutability":"mutable","name":"nonce","nameLocation":"300:5:0","nodeType":"VariableDeclaration","scope":17,"src":"293:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"},"typeName":{"id":14,"name":"uint64","nodeType":"ElementaryTypeName","src":"293:6:0","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"visibility":"internal"}],"src":"292:14:0"},"scope":55,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":27,"nodeType":"FunctionDefinition","src":"312:111:0","nodes":[],"functionSelector":"213e4198","implemented":false,"kind":"function","modifiers":[],"name":"parseJsonKeys","nameLocation":"321:13:0","parameters":{"id":22,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19,"mutability":"mutable","name":"json","nameLocation":"351:4:0","nodeType":"VariableDeclaration","scope":27,"src":"335:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":18,"name":"string","nodeType":"ElementaryTypeName","src":"335:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":21,"mutability":"mutable","name":"key","nameLocation":"373:3:0","nodeType":"VariableDeclaration","scope":27,"src":"357:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":20,"name":"string","nodeType":"ElementaryTypeName","src":"357:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"334:43:0"},"returnParameters":{"id":26,"nodeType":"ParameterList","parameters":[{"constant":false,"id":25,"mutability":"mutable","name":"keys","nameLocation":"417:4:0","nodeType":"VariableDeclaration","scope":27,"src":"401:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":23,"name":"string","nodeType":"ElementaryTypeName","src":"401:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":24,"nodeType":"ArrayTypeName","src":"401:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"src":"400:22:0"},"scope":55,"stateMutability":"pure","virtual":false,"visibility":"external"},{"id":32,"nodeType":"FunctionDefinition","src":"428:48:0","nodes":[],"functionSelector":"06447d56","implemented":false,"kind":"function","modifiers":[],"name":"startPrank","nameLocation":"437:10:0","parameters":{"id":30,"nodeType":"ParameterList","parameters":[{"constant":false,"id":29,"mutability":"mutable","name":"msgSender","nameLocation":"456:9:0","nodeType":"VariableDeclaration","scope":32,"src":"448:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":28,"name":"address","nodeType":"ElementaryTypeName","src":"448:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"447:19:0"},"returnParameters":{"id":31,"nodeType":"ParameterList","parameters":[],"src":"475:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":35,"nodeType":"FunctionDefinition","src":"481:30:0","nodes":[],"functionSelector":"90c5013b","implemented":false,"kind":"function","modifiers":[],"name":"stopPrank","nameLocation":"490:9:0","parameters":{"id":33,"nodeType":"ParameterList","parameters":[],"src":"499:2:0"},"returnParameters":{"id":34,"nodeType":"ParameterList","parameters":[],"src":"510:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":38,"nodeType":"FunctionDefinition","src":"516:30:0","nodes":[],"functionSelector":"afc98040","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"525:9:0","parameters":{"id":36,"nodeType":"ParameterList","parameters":[],"src":"534:2:0"},"returnParameters":{"id":37,"nodeType":"ParameterList","parameters":[],"src":"545:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":43,"nodeType":"FunctionDefinition","src":"551:47:0","nodes":[],"functionSelector":"e6962cdb","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"560:9:0","parameters":{"id":41,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40,"mutability":"mutable","name":"msgSender","nameLocation":"578:9:0","nodeType":"VariableDeclaration","scope":43,"src":"570:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39,"name":"address","nodeType":"ElementaryTypeName","src":"570:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"569:19:0"},"returnParameters":{"id":42,"nodeType":"ParameterList","parameters":[],"src":"597:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":48,"nodeType":"FunctionDefinition","src":"603:52:0","nodes":[],"functionSelector":"7fec2a8d","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"612:14:0","parameters":{"id":46,"nodeType":"ParameterList","parameters":[{"constant":false,"id":45,"mutability":"mutable","name":"msgSender","nameLocation":"635:9:0","nodeType":"VariableDeclaration","scope":48,"src":"627:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":44,"name":"address","nodeType":"ElementaryTypeName","src":"627:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"626:19:0"},"returnParameters":{"id":47,"nodeType":"ParameterList","parameters":[],"src":"654:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":51,"nodeType":"FunctionDefinition","src":"660:35:0","nodes":[],"functionSelector":"7fb5297f","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"669:14:0","parameters":{"id":49,"nodeType":"ParameterList","parameters":[],"src":"683:2:0"},"returnParameters":{"id":50,"nodeType":"ParameterList","parameters":[],"src":"694:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":54,"nodeType":"FunctionDefinition","src":"700:34:0","nodes":[],"functionSelector":"76eadd36","implemented":false,"kind":"function","modifiers":[],"name":"stopBroadcast","nameLocation":"709:13:0","parameters":{"id":52,"nodeType":"ParameterList","parameters":[],"src":"722:2:0"},"returnParameters":{"id":53,"nodeType":"ParameterList","parameters":[],"src":"733:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"Vm","contractDependencies":[],"contractKind":"interface","fullyImplemented":false,"linearizedBaseContracts":[55],"name":"Vm","nameLocation":"130:2:0","scope":720,"usedErrors":[]},{"id":192,"nodeType":"ContractDefinition","src":"791:1622:0","nodes":[{"id":61,"nodeType":"VariableDeclaration","src":"813:86:0","nodes":[],"constant":true,"mutability":"constant","name":"CONSOLE_ADDRESS","nameLocation":"830:15:0","scope":192,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":56,"name":"address","nodeType":"ElementaryTypeName","src":"813:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"hexValue":"307830303030303030303030303030303030303036333646366537333646366336353265366336663637","id":59,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"856:42:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"value":"0x000000000000000000636F6e736F6c652e6c6f67"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":58,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"848:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":57,"name":"address","nodeType":"ElementaryTypeName","src":"848:7:0","typeDescriptions":{}}},"id":60,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"848:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":78,"nodeType":"FunctionDefinition","src":"906:221:0","nodes":[],"body":{"id":77,"nodeType":"Block","src":"1065:62:0","nodes":[],"statements":[{"AST":{"nodeType":"YulBlock","src":"1084:37:0","statements":[{"nodeType":"YulAssignment","src":"1098:13:0","value":{"name":"fnIn","nodeType":"YulIdentifier","src":"1107:4:0"},"variableNames":[{"name":"fnOut","nodeType":"YulIdentifier","src":"1098:5:0"}]}]},"evmVersion":"london","externalReferences":[{"declaration":67,"isOffset":false,"isSlot":false,"src":"1107:4:0","valueSize":1},{"declaration":74,"isOffset":false,"isSlot":false,"src":"1098:5:0","valueSize":1}],"id":76,"nodeType":"InlineAssembly","src":"1075:46:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_castLogPayloadViewToPure","nameLocation":"915:25:0","parameters":{"id":68,"nodeType":"ParameterList","parameters":[{"constant":false,"id":67,"mutability":"mutable","name":"fnIn","nameLocation":"987:4:0","nodeType":"VariableDeclaration","scope":78,"src":"950:41:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"typeName":{"id":66,"nodeType":"FunctionTypeName","parameterTypes":{"id":64,"nodeType":"ParameterList","parameters":[{"constant":false,"id":63,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":66,"src":"959:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":62,"name":"bytes","nodeType":"ElementaryTypeName","src":"959:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"958:14:0"},"returnParameterTypes":{"id":65,"nodeType":"ParameterList","parameters":[],"src":"987:0:0"},"src":"950:41:0","stateMutability":"view","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"visibility":"internal"},"visibility":"internal"}],"src":"940:57:0"},"returnParameters":{"id":75,"nodeType":"ParameterList","parameters":[{"constant":false,"id":74,"mutability":"mutable","name":"fnOut","nameLocation":"1058:5:0","nodeType":"VariableDeclaration","scope":78,"src":"1021:42:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"typeName":{"id":73,"nodeType":"FunctionTypeName","parameterTypes":{"id":71,"nodeType":"ParameterList","parameters":[{"constant":false,"id":70,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":73,"src":"1030:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":69,"name":"bytes","nodeType":"ElementaryTypeName","src":"1030:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1029:14:0"},"returnParameterTypes":{"id":72,"nodeType":"ParameterList","parameters":[],"src":"1058:0:0"},"src":"1021:42:0","stateMutability":"pure","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"visibility":"internal"},"visibility":"internal"}],"src":"1020:44:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":90,"nodeType":"FunctionDefinition","src":"1133:133:0","nodes":[],"body":{"id":89,"nodeType":"Block","src":"1194:72:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":86,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":80,"src":"1251:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"arguments":[{"id":84,"name":"_sendLogPayloadView","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":106,"src":"1230:19:0","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}],"id":83,"name":"_castLogPayloadViewToPure","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":78,"src":"1204:25:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_function_internal_view$_t_bytes_memory_ptr_$returns$__$_$returns$_t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$_$","typeString":"function (function (bytes memory) view) pure returns (function (bytes memory) pure)"}},"id":85,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1204:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":87,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1204:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":88,"nodeType":"ExpressionStatement","src":"1204:55:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayload","nameLocation":"1142:15:0","parameters":{"id":81,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"payload","nameLocation":"1171:7:0","nodeType":"VariableDeclaration","scope":90,"src":"1158:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":79,"name":"bytes","nodeType":"ElementaryTypeName","src":"1158:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1157:22:0"},"returnParameters":{"id":82,"nodeType":"ParameterList","parameters":[],"src":"1194:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":106,"nodeType":"FunctionDefinition","src":"1272:380:0","nodes":[],"body":{"id":105,"nodeType":"Block","src":"1336:316:0","nodes":[],"statements":[{"assignments":[96],"declarations":[{"constant":false,"id":96,"mutability":"mutable","name":"payloadLength","nameLocation":"1354:13:0","nodeType":"VariableDeclaration","scope":105,"src":"1346:21:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":95,"name":"uint256","nodeType":"ElementaryTypeName","src":"1346:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":99,"initialValue":{"expression":{"id":97,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":92,"src":"1370:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":98,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1370:14:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1346:38:0"},{"assignments":[101],"declarations":[{"constant":false,"id":101,"mutability":"mutable","name":"consoleAddress","nameLocation":"1402:14:0","nodeType":"VariableDeclaration","scope":105,"src":"1394:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":100,"name":"address","nodeType":"ElementaryTypeName","src":"1394:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":103,"initialValue":{"id":102,"name":"CONSOLE_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":61,"src":"1419:15:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"1394:40:0"},{"AST":{"nodeType":"YulBlock","src":"1496:150:0","statements":[{"nodeType":"YulVariableDeclaration","src":"1510:36:0","value":{"arguments":[{"name":"payload","nodeType":"YulIdentifier","src":"1534:7:0"},{"kind":"number","nodeType":"YulLiteral","src":"1543:2:0","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1530:3:0"},"nodeType":"YulFunctionCall","src":"1530:16:0"},"variables":[{"name":"payloadStart","nodeType":"YulTypedName","src":"1514:12:0","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1559:77:0","value":{"arguments":[{"arguments":[],"functionName":{"name":"gas","nodeType":"YulIdentifier","src":"1579:3:0"},"nodeType":"YulFunctionCall","src":"1579:5:0"},{"name":"consoleAddress","nodeType":"YulIdentifier","src":"1586:14:0"},{"name":"payloadStart","nodeType":"YulIdentifier","src":"1602:12:0"},{"name":"payloadLength","nodeType":"YulIdentifier","src":"1616:13:0"},{"kind":"number","nodeType":"YulLiteral","src":"1631:1:0","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1634:1:0","type":"","value":"0"}],"functionName":{"name":"staticcall","nodeType":"YulIdentifier","src":"1568:10:0"},"nodeType":"YulFunctionCall","src":"1568:68:0"},"variables":[{"name":"r","nodeType":"YulTypedName","src":"1563:1:0","type":""}]}]},"documentation":"@solidity memory-safe-assembly","evmVersion":"london","externalReferences":[{"declaration":101,"isOffset":false,"isSlot":false,"src":"1586:14:0","valueSize":1},{"declaration":92,"isOffset":false,"isSlot":false,"src":"1534:7:0","valueSize":1},{"declaration":96,"isOffset":false,"isSlot":false,"src":"1616:13:0","valueSize":1}],"id":104,"nodeType":"InlineAssembly","src":"1487:159:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayloadView","nameLocation":"1281:19:0","parameters":{"id":93,"nodeType":"ParameterList","parameters":[{"constant":false,"id":92,"mutability":"mutable","name":"payload","nameLocation":"1314:7:0","nodeType":"VariableDeclaration","scope":106,"src":"1301:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":91,"name":"bytes","nodeType":"ElementaryTypeName","src":"1301:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1300:22:0"},"returnParameters":{"id":94,"nodeType":"ParameterList","parameters":[],"src":"1336:0:0"},"scope":192,"stateMutability":"view","virtual":false,"visibility":"private"},{"id":120,"nodeType":"FunctionDefinition","src":"1658:121:0","nodes":[],"body":{"id":119,"nodeType":"Block","src":"1703:76:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e6729","id":114,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1753:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},"value":"log(string)"},{"id":115,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":108,"src":"1768:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":112,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"1729:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":113,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"1729:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":116,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1729:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":111,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"1713:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":117,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1713:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":118,"nodeType":"ExpressionStatement","src":"1713:59:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"1667:3:0","parameters":{"id":109,"nodeType":"ParameterList","parameters":[{"constant":false,"id":108,"mutability":"mutable","name":"p0","nameLocation":"1685:2:0","nodeType":"VariableDeclaration","scope":120,"src":"1671:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":107,"name":"string","nodeType":"ElementaryTypeName","src":"1671:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"1670:18:0"},"returnParameters":{"id":110,"nodeType":"ParameterList","parameters":[],"src":"1703:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":137,"nodeType":"FunctionDefinition","src":"1785:139:0","nodes":[],"body":{"id":136,"nodeType":"Block","src":"1839:85:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c626f6f6c29","id":130,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1889:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},"value":"log(string,bool)"},{"id":131,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":122,"src":"1909:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":132,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":124,"src":"1913:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":128,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"1865:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":129,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"1865:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":133,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1865:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":127,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"1849:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":134,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1849:68:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":135,"nodeType":"ExpressionStatement","src":"1849:68:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"1794:3:0","parameters":{"id":125,"nodeType":"ParameterList","parameters":[{"constant":false,"id":122,"mutability":"mutable","name":"p0","nameLocation":"1812:2:0","nodeType":"VariableDeclaration","scope":137,"src":"1798:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":121,"name":"string","nodeType":"ElementaryTypeName","src":"1798:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":124,"mutability":"mutable","name":"p1","nameLocation":"1821:2:0","nodeType":"VariableDeclaration","scope":137,"src":"1816:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":123,"name":"bool","nodeType":"ElementaryTypeName","src":"1816:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"1797:27:0"},"returnParameters":{"id":126,"nodeType":"ParameterList","parameters":[],"src":"1839:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":154,"nodeType":"FunctionDefinition","src":"1930:145:0","nodes":[],"body":{"id":153,"nodeType":"Block","src":"1987:88:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c75696e7432353629","id":147,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2037:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},"value":"log(string,uint256)"},{"id":148,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":139,"src":"2060:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":149,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":141,"src":"2064:2:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":145,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2013:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":146,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2013:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":150,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2013:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":144,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"1997:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":151,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1997:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":152,"nodeType":"ExpressionStatement","src":"1997:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"1939:3:0","parameters":{"id":142,"nodeType":"ParameterList","parameters":[{"constant":false,"id":139,"mutability":"mutable","name":"p0","nameLocation":"1957:2:0","nodeType":"VariableDeclaration","scope":154,"src":"1943:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":138,"name":"string","nodeType":"ElementaryTypeName","src":"1943:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":141,"mutability":"mutable","name":"p1","nameLocation":"1969:2:0","nodeType":"VariableDeclaration","scope":154,"src":"1961:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":140,"name":"uint256","nodeType":"ElementaryTypeName","src":"1961:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1942:30:0"},"returnParameters":{"id":143,"nodeType":"ParameterList","parameters":[],"src":"1987:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":171,"nodeType":"FunctionDefinition","src":"2081:145:0","nodes":[],"body":{"id":170,"nodeType":"Block","src":"2138:88:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c6164647265737329","id":164,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2188:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},"value":"log(string,address)"},{"id":165,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":156,"src":"2211:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":166,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":158,"src":"2215:2:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":162,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2164:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":163,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2164:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":167,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2164:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":161,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"2148:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":168,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2148:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":169,"nodeType":"ExpressionStatement","src":"2148:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2090:3:0","parameters":{"id":159,"nodeType":"ParameterList","parameters":[{"constant":false,"id":156,"mutability":"mutable","name":"p0","nameLocation":"2108:2:0","nodeType":"VariableDeclaration","scope":171,"src":"2094:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":155,"name":"string","nodeType":"ElementaryTypeName","src":"2094:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":158,"mutability":"mutable","name":"p1","nameLocation":"2120:2:0","nodeType":"VariableDeclaration","scope":171,"src":"2112:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":157,"name":"address","nodeType":"ElementaryTypeName","src":"2112:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2093:30:0"},"returnParameters":{"id":160,"nodeType":"ParameterList","parameters":[],"src":"2138:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":191,"nodeType":"FunctionDefinition","src":"2232:179:0","nodes":[],"body":{"id":190,"nodeType":"Block","src":"2313:98:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c737472696e672c737472696e6729","id":183,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2363:27:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},"value":"log(string,string,string)"},{"id":184,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":173,"src":"2392:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":185,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":175,"src":"2396:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":186,"name":"p2","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":177,"src":"2400:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":181,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2339:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":182,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2339:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":187,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2339:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":180,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"2323:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":188,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2323:81:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":189,"nodeType":"ExpressionStatement","src":"2323:81:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2241:3:0","parameters":{"id":178,"nodeType":"ParameterList","parameters":[{"constant":false,"id":173,"mutability":"mutable","name":"p0","nameLocation":"2259:2:0","nodeType":"VariableDeclaration","scope":191,"src":"2245:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":172,"name":"string","nodeType":"ElementaryTypeName","src":"2245:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":175,"mutability":"mutable","name":"p1","nameLocation":"2277:2:0","nodeType":"VariableDeclaration","scope":191,"src":"2263:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":174,"name":"string","nodeType":"ElementaryTypeName","src":"2263:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":177,"mutability":"mutable","name":"p2","nameLocation":"2295:2:0","nodeType":"VariableDeclaration","scope":191,"src":"2281:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":176,"name":"string","nodeType":"ElementaryTypeName","src":"2281:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2244:54:0"},"returnParameters":{"id":179,"nodeType":"ParameterList","parameters":[],"src":"2313:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"}],"abstract":false,"baseContracts":[],"canonicalName":"console","contractDependencies":[],"contractKind":"library","fullyImplemented":true,"linearizedBaseContracts":[192],"name":"console","nameLocation":"799:7:0","scope":720,"usedErrors":[]},{"id":706,"nodeType":"ContractDefinition","src":"2541:3359:0","nodes":[{"id":207,"nodeType":"VariableDeclaration","src":"2571:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"2597:10:0","scope":706,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":194,"name":"address","nodeType":"ElementaryTypeName","src":"2571:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":202,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2644:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":201,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"2634:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":203,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2634:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":200,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2626:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":199,"name":"uint256","nodeType":"ElementaryTypeName","src":"2626:7:0","typeDescriptions":{}}},"id":204,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2626:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":198,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2618:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":197,"name":"uint160","nodeType":"ElementaryTypeName","src":"2618:7:0","typeDescriptions":{}}},"id":205,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2618:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":196,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2610:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":195,"name":"address","nodeType":"ElementaryTypeName","src":"2610:7:0","typeDescriptions":{}}},"id":206,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2610:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":213,"nodeType":"VariableDeclaration","src":"2671:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"2692:2:0","scope":706,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"},"typeName":{"id":209,"nodeType":"UserDefinedTypeName","pathNode":{"id":208,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":55,"src":"2671:2:0"},"referencedDeclaration":55,"src":"2671:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"value":{"arguments":[{"id":211,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":207,"src":"2700:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":210,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":55,"src":"2697:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$55_$","typeString":"type(contract Vm)"}},"id":212,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2697:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"visibility":"internal"},{"id":215,"nodeType":"VariableDeclaration","src":"2775:22:0","nodes":[],"constant":false,"functionSelector":"61bc221a","mutability":"mutable","name":"counter","nameLocation":"2790:7:0","scope":706,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":214,"name":"uint256","nodeType":"ElementaryTypeName","src":"2775:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":378,"nodeType":"FunctionDefinition","src":"2887:949:0","nodes":[],"body":{"id":377,"nodeType":"Block","src":"2909:927:0","nodes":[],"statements":[{"assignments":[220],"declarations":[{"constant":false,"id":220,"mutability":"mutable","name":"x","nameLocation":"2924:1:0","nodeType":"VariableDeclaration","scope":377,"src":"2919:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":219,"name":"bool","nodeType":"ElementaryTypeName","src":"2919:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"id":226,"initialValue":{"arguments":[{"hexValue":"4558414d504c455f424f4f4c","id":223,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2937:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},"value":"EXAMPLE_BOOL"},{"hexValue":"66616c7365","id":224,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"2953:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":221,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"2928:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":222,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"envOr","nodeType":"MemberAccess","referencedDeclaration":10,"src":"2928:8:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$_t_bool_$returns$_t_bool_$","typeString":"function (string memory,bool) view external returns (bool)"}},"id":225,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2928:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"VariableDeclarationStatement","src":"2919:40:0"},{"expression":{"arguments":[{"hexValue":"626f6f6c2076616c75652066726f6d20656e76","id":230,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2981:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},"value":"bool value from env"},{"id":231,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3004:1:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":227,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"2969:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":229,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":137,"src":"2969:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_bool_$returns$__$","typeString":"function (string memory,bool) pure"}},"id":232,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2969:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":233,"nodeType":"ExpressionStatement","src":"2969:37:0"},{"expression":{"arguments":[{"hexValue":"636f6e74726163742061646472","id":237,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3029:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},"value":"contract addr"},{"arguments":[{"id":240,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3054:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":239,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3046:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":238,"name":"address","nodeType":"ElementaryTypeName","src":"3046:7:0","typeDescriptions":{}}},"id":241,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3046:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":234,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3017:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":236,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3017:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":242,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3017:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":243,"nodeType":"ExpressionStatement","src":"3017:43:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206e6f6e6365","id":247,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3082:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},"value":"contract nonce"},{"arguments":[{"arguments":[{"id":252,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3120:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":251,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3112:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":250,"name":"address","nodeType":"ElementaryTypeName","src":"3112:7:0","typeDescriptions":{}}},"id":253,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3112:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":248,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3100:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":249,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3100:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":254,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3100:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":244,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3070:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":246,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"3070:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":255,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3070:57:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":256,"nodeType":"ExpressionStatement","src":"3070:57:0"},{"expression":{"arguments":[{"hexValue":"73656e6465722061646472","id":260,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3149:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},"value":"sender addr"},{"arguments":[{"expression":{"id":263,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3172:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":264,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3172:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":262,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3164:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":261,"name":"address","nodeType":"ElementaryTypeName","src":"3164:7:0","typeDescriptions":{}}},"id":265,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3164:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":257,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3137:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":259,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3137:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":266,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3137:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":267,"nodeType":"ExpressionStatement","src":"3137:47:0"},{"expression":{"arguments":[{"hexValue":"73656e646572206e6f6e6365","id":271,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3206:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},"value":"sender nonce"},{"arguments":[{"arguments":[{"expression":{"id":276,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3242:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":277,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3242:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":275,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3234:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":274,"name":"address","nodeType":"ElementaryTypeName","src":"3234:7:0","typeDescriptions":{}}},"id":278,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3234:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":272,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3222:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":273,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3222:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":279,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3222:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":268,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3194:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":270,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"3194:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":280,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3194:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":281,"nodeType":"ExpressionStatement","src":"3194:61:0"},{"assignments":[283],"declarations":[{"constant":false,"id":283,"mutability":"mutable","name":"json","nameLocation":"3280:4:0","nodeType":"VariableDeclaration","scope":377,"src":"3266:18:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":282,"name":"string","nodeType":"ElementaryTypeName","src":"3266:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"id":285,"initialValue":{"hexValue":"7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d","id":284,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3287:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e95522e99766888d0261f55bd1eae5e3f3e26eaf009a16e2433eafaf0a4ecdf2","typeString":"literal_string \"{\"root_key\": [{\"a\": 1, \"b\": 2}]}\""},"value":"{\"root_key\": [{\"a\": 1, \"b\": 2}]}"},"nodeType":"VariableDeclarationStatement","src":"3266:55:0"},{"assignments":[290],"declarations":[{"constant":false,"id":290,"mutability":"mutable","name":"keys","nameLocation":"3347:4:0","nodeType":"VariableDeclaration","scope":377,"src":"3331:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":288,"name":"string","nodeType":"ElementaryTypeName","src":"3331:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":289,"nodeType":"ArrayTypeName","src":"3331:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"id":296,"initialValue":{"arguments":[{"id":293,"name":"json","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":283,"src":"3371:4:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"2e726f6f745f6b65795b305d","id":294,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3377:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""},"value":".root_key[0]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""}],"expression":{"id":291,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3354:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":292,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"parseJsonKeys","nodeType":"MemberAccess","referencedDeclaration":27,"src":"3354:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$_t_array$_t_string_memory_ptr_$dyn_memory_ptr_$","typeString":"function (string memory,string memory) pure external returns (string memory[] memory)"}},"id":295,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3354:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"nodeType":"VariableDeclarationStatement","src":"3331:61:0"},{"expression":{"arguments":[{"hexValue":"6b657973","id":300,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3414:6:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},"value":"keys"},{"baseExpression":{"id":301,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":290,"src":"3422:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":303,"indexExpression":{"hexValue":"30","id":302,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"3427:1:0","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"3422:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"baseExpression":{"id":304,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":290,"src":"3431:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":306,"indexExpression":{"hexValue":"31","id":305,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"3436:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"3431:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":297,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3402:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":299,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":191,"src":"3402:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory,string memory) pure"}},"id":307,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3402:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":308,"nodeType":"ExpressionStatement","src":"3402:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c","id":312,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3461:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""},"value":"from original"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""}],"expression":{"id":309,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3450:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":311,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3450:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":313,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3450:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":314,"nodeType":"ExpressionStatement","src":"3450:27:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"30783432","id":322,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"3517:4:0","typeDescriptions":{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"},"value":"0x42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"}],"id":321,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3509:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":320,"name":"uint160","nodeType":"ElementaryTypeName","src":"3509:7:0","typeDescriptions":{}}},"id":323,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3509:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":319,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3501:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":318,"name":"address","nodeType":"ElementaryTypeName","src":"3501:7:0","typeDescriptions":{}}},"id":324,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3501:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":315,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3487:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":317,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startPrank","nodeType":"MemberAccess","referencedDeclaration":32,"src":"3487:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":325,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3487:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":326,"nodeType":"ExpressionStatement","src":"3487:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2031","id":330,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3545:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""},"value":"from prank 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""}],"expression":{"id":327,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3534:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":329,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3534:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":331,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3534:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":332,"nodeType":"ExpressionStatement","src":"3534:26:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f7065206d73672e73656e646572","id":336,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3582:25:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},"value":"parent scope msg.sender"},{"arguments":[{"expression":{"id":339,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3617:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":340,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3617:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":338,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3609:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":337,"name":"address","nodeType":"ElementaryTypeName","src":"3609:7:0","typeDescriptions":{}}},"id":341,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3609:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":333,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3570:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":335,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3570:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":342,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3570:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":343,"nodeType":"ExpressionStatement","src":"3570:59:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f706520636f6e74726163742e61646472","id":347,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3651:28:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},"value":"parent scope contract.addr"},{"arguments":[{"id":350,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3689:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":349,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3681:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":348,"name":"address","nodeType":"ElementaryTypeName","src":"3681:7:0","typeDescriptions":{}}},"id":351,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3681:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":344,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3639:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":346,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3639:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":352,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3639:56:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":353,"nodeType":"ExpressionStatement","src":"3639:56:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2032","id":357,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3716:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""},"value":"from prank 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""}],"expression":{"id":354,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3705:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":356,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3705:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":358,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3705:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":359,"nodeType":"ExpressionStatement","src":"3705:26:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":360,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3741:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":362,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopPrank","nodeType":"MemberAccess","referencedDeclaration":35,"src":"3741:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":363,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3741:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":364,"nodeType":"ExpressionStatement","src":"3741:14:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c20616761696e","id":368,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3776:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""},"value":"from original again"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""}],"expression":{"id":365,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3765:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":367,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3765:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":369,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3765:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":370,"nodeType":"ExpressionStatement","src":"3765:33:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":374,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3821:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":371,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3809:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":373,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"3809:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":375,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3809:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":376,"nodeType":"ExpressionStatement","src":"3809:20:0"}]},"documentation":{"id":216,"nodeType":"StructuredDocumentation","src":"2804:78:0","text":"@notice example function, runs through basic cheat-codes and console logs."},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"2896:3:0","parameters":{"id":217,"nodeType":"ParameterList","parameters":[],"src":"2899:2:0"},"returnParameters":{"id":218,"nodeType":"ParameterList","parameters":[],"src":"2909:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":609,"nodeType":"FunctionDefinition","src":"3903:1258:0","nodes":[],"body":{"id":608,"nodeType":"Block","src":"3934:1227:0","nodes":[],"statements":[{"expression":{"arguments":[{"hexValue":"6e6f6e6365207374617274","id":385,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3956:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},"value":"nonce start"},{"arguments":[{"arguments":[{"arguments":[{"id":392,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3999:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":391,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3991:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":390,"name":"address","nodeType":"ElementaryTypeName","src":"3991:7:0","typeDescriptions":{}}},"id":393,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3991:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":388,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3979:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":389,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3979:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":394,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3979:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":387,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3971:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":386,"name":"uint256","nodeType":"ElementaryTypeName","src":"3971:7:0","typeDescriptions":{}}},"id":395,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3971:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":382,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3944:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":384,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"3944:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":396,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3944:63:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":397,"nodeType":"ExpressionStatement","src":"3944:63:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073696e676c65","id":401,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4030:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""},"value":"testing single"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""}],"expression":{"id":398,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4018:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":400,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4018:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":402,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4018:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":403,"nodeType":"ExpressionStatement","src":"4018:29:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":404,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4057:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":406,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"4057:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":407,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4057:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":408,"nodeType":"ExpressionStatement","src":"4057:14:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c31","id":412,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4092:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""},"value":"single_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""}],"expression":{"id":409,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4081:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":411,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":648,"src":"4081:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":413,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4081:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":414,"nodeType":"ExpressionStatement","src":"4081:26:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c32","id":418,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4128:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""},"value":"single_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""}],"expression":{"id":415,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4117:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":417,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":663,"src":"4117:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":419,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4117:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":420,"nodeType":"ExpressionStatement","src":"4117:26:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073746172742f73746f70","id":424,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4166:20:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""},"value":"testing start/stop"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""}],"expression":{"id":421,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4154:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":423,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4154:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":425,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4154:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":426,"nodeType":"ExpressionStatement","src":"4154:33:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078633066666565","id":434,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4231:8:0","typeDescriptions":{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"},"value":"0xc0ffee"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"}],"id":433,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4223:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":432,"name":"uint160","nodeType":"ElementaryTypeName","src":"4223:7:0","typeDescriptions":{}}},"id":435,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4223:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":431,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4215:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":430,"name":"address","nodeType":"ElementaryTypeName","src":"4215:7:0","typeDescriptions":{}}},"id":436,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4215:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":427,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4197:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":429,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"4197:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":437,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4197:45:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":438,"nodeType":"ExpressionStatement","src":"4197:45:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c31","id":442,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4263:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""},"value":"startstop_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""}],"expression":{"id":439,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4252:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":441,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":648,"src":"4252:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":443,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4252:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":444,"nodeType":"ExpressionStatement","src":"4252:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c32","id":448,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4302:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""},"value":"startstop_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""}],"expression":{"id":445,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4291:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":447,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":663,"src":"4291:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":449,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4291:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":450,"nodeType":"ExpressionStatement","src":"4291:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f70757265","id":454,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4344:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""},"value":"startstop_pure"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""}],"expression":{"id":451,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4330:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":453,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"callPure","nodeType":"MemberAccess","referencedDeclaration":705,"src":"4330:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure external"}},"id":455,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4330:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":456,"nodeType":"ExpressionStatement","src":"4330:31:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":457,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4371:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":459,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"4371:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":460,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4371:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":461,"nodeType":"ExpressionStatement","src":"4371:18:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c33","id":465,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4410:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""},"value":"startstop_call3"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""}],"expression":{"id":462,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4399:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":464,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":648,"src":"4399:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":466,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4399:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":467,"nodeType":"ExpressionStatement","src":"4399:29:0"},{"expression":{"arguments":[{"hexValue":"74657374696e67206e6573746564","id":471,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4451:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""},"value":"testing nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""}],"expression":{"id":468,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4439:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":470,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4439:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":472,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4439:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":473,"nodeType":"ExpressionStatement","src":"4439:29:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307831323334","id":481,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4512:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":480,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4504:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":479,"name":"uint160","nodeType":"ElementaryTypeName","src":"4504:7:0","typeDescriptions":{}}},"id":482,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4504:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":478,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4496:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":477,"name":"address","nodeType":"ElementaryTypeName","src":"4496:7:0","typeDescriptions":{}}},"id":483,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4496:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":474,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4478:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":476,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"4478:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":484,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4478:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":485,"nodeType":"ExpressionStatement","src":"4478:43:0"},{"expression":{"arguments":[{"hexValue":"6e6573746564","id":489,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4544:8:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""},"value":"nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""}],"expression":{"id":486,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4531:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":488,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested1","nodeType":"MemberAccess","referencedDeclaration":678,"src":"4531:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":490,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4531:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":491,"nodeType":"ExpressionStatement","src":"4531:22:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":492,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4563:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":494,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"4563:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":495,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4563:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":496,"nodeType":"ExpressionStatement","src":"4563:18:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206465706c6f796d656e74","id":500,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4604:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""},"value":"contract deployment"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""}],"expression":{"id":497,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4592:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":499,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4592:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":501,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4592:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":502,"nodeType":"ExpressionStatement","src":"4592:34:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078313233343536","id":510,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4665:8:0","typeDescriptions":{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"},"value":"0x123456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"}],"id":509,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4657:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":508,"name":"uint160","nodeType":"ElementaryTypeName","src":"4657:7:0","typeDescriptions":{}}},"id":511,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4657:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":507,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4649:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":506,"name":"address","nodeType":"ElementaryTypeName","src":"4649:7:0","typeDescriptions":{}}},"id":512,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4649:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":503,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4636:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":505,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"4636:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":513,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4636:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":514,"nodeType":"ExpressionStatement","src":"4636:40:0"},{"assignments":[517],"declarations":[{"constant":false,"id":517,"mutability":"mutable","name":"x","nameLocation":"4693:1:0","nodeType":"VariableDeclaration","scope":608,"src":"4686:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"},"typeName":{"id":516,"nodeType":"UserDefinedTypeName","pathNode":{"id":515,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4686:6:0"},"referencedDeclaration":719,"src":"4686:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"visibility":"internal"}],"id":523,"initialValue":{"arguments":[{"hexValue":"31323334","id":521,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4708:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":520,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"4697:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":519,"nodeType":"UserDefinedTypeName","pathNode":{"id":518,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4701:6:0"},"referencedDeclaration":719,"src":"4701:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}}},"id":522,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4697:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"4686:27:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":529,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":525,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"4731:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"id":526,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":708,"src":"4731:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":527,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4731:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":528,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4742:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"4731:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"}],"id":524,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"4723:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$returns$__$","typeString":"function (bool) pure"}},"id":530,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4723:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":531,"nodeType":"ExpressionStatement","src":"4723:24:0"},{"expression":{"arguments":[{"hexValue":"6372656174652032","id":535,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4770:10:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""},"value":"create 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""}],"expression":{"id":532,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4758:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":534,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4758:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":536,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4758:23:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":537,"nodeType":"ExpressionStatement","src":"4758:23:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307863616665","id":545,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4820:6:0","typeDescriptions":{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"},"value":"0xcafe"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"}],"id":544,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4812:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":543,"name":"uint160","nodeType":"ElementaryTypeName","src":"4812:7:0","typeDescriptions":{}}},"id":546,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4812:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":542,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4804:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":541,"name":"address","nodeType":"ElementaryTypeName","src":"4804:7:0","typeDescriptions":{}}},"id":547,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4804:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":538,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4791:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":540,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"4791:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":548,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4791:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":549,"nodeType":"ExpressionStatement","src":"4791:38:0"},{"assignments":[552],"declarations":[{"constant":false,"id":552,"mutability":"mutable","name":"y","nameLocation":"4846:1:0","nodeType":"VariableDeclaration","scope":608,"src":"4839:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"},"typeName":{"id":551,"nodeType":"UserDefinedTypeName","pathNode":{"id":550,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4839:6:0"},"referencedDeclaration":719,"src":"4839:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"visibility":"internal"}],"id":566,"initialValue":{"arguments":[{"hexValue":"31323334","id":564,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4889:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":555,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"4850:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":554,"nodeType":"UserDefinedTypeName","pathNode":{"id":553,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4854:6:0"},"referencedDeclaration":719,"src":"4854:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}}},"id":563,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"names":["salt"],"nodeType":"FunctionCallOptions","options":[{"arguments":[{"arguments":[{"hexValue":"3432","id":560,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4883:2:0","typeDescriptions":{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"},"value":"42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"}],"id":559,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4875:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":558,"name":"uint256","nodeType":"ElementaryTypeName","src":"4875:7:0","typeDescriptions":{}}},"id":561,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4875:11:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":557,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4867:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":556,"name":"bytes32","nodeType":"ElementaryTypeName","src":"4867:7:0","typeDescriptions":{}}},"id":562,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4867:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"src":"4850:38:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$salt","typeString":"function (uint256) returns (contract FooBar)"}},"id":565,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4850:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"4839:55:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":572,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":568,"name":"y","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":552,"src":"4912:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"id":569,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":708,"src":"4912:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":570,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4912:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":571,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4923:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"4912:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"}],"id":567,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"4904:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$returns$__$","typeString":"function (bool) pure"}},"id":573,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4904:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":574,"nodeType":"ExpressionStatement","src":"4904:24:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":578,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4950:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":575,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4938:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":577,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4938:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":579,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4938:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":580,"nodeType":"ExpressionStatement","src":"4938:20:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":581,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"5042:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":583,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"5042:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":584,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5042:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":585,"nodeType":"ExpressionStatement","src":"5042:14:0"},{"expression":{"arguments":[{"hexValue":"31323334","id":589,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5077:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":588,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5066:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":587,"nodeType":"UserDefinedTypeName","pathNode":{"id":586,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"5070:6:0"},"referencedDeclaration":719,"src":"5070:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}}},"id":590,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5066:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"id":591,"nodeType":"ExpressionStatement","src":"5066:16:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e636520656e64","id":595,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5105:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},"value":"nonce end"},{"arguments":[{"arguments":[{"arguments":[{"id":602,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5146:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":601,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5138:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":600,"name":"address","nodeType":"ElementaryTypeName","src":"5138:7:0","typeDescriptions":{}}},"id":603,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5138:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":598,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"5126:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":599,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"5126:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":604,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5126:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":597,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5118:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":596,"name":"uint256","nodeType":"ElementaryTypeName","src":"5118:7:0","typeDescriptions":{}}},"id":605,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5118:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":592,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5093:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":594,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"5093:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":606,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5093:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":607,"nodeType":"ExpressionStatement","src":"5093:61:0"}]},"documentation":{"id":379,"nodeType":"StructuredDocumentation","src":"3842:56:0","text":"@notice example function, to test vm.broadcast with."},"functionSelector":"bef03abc","implemented":true,"kind":"function","modifiers":[],"name":"runBroadcast","nameLocation":"3912:12:0","parameters":{"id":380,"nodeType":"ParameterList","parameters":[],"src":"3924:2:0"},"returnParameters":{"id":381,"nodeType":"ParameterList","parameters":[],"src":"3934:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":633,"nodeType":"FunctionDefinition","src":"5256:143:0","nodes":[],"body":{"id":632,"nodeType":"Block","src":"5305:94:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":618,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":612,"src":"5327:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":615,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5315:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":617,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5315:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":619,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5315:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":620,"nodeType":"ExpressionStatement","src":"5315:15:0"},{"expression":{"arguments":[{"hexValue":"68656c6c6f206d73672e73656e646572","id":624,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5352:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},"value":"hello msg.sender"},{"arguments":[{"expression":{"id":627,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"5380:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":628,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"5380:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":626,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5372:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":625,"name":"address","nodeType":"ElementaryTypeName","src":"5372:7:0","typeDescriptions":{}}},"id":629,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5372:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":621,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5340:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":623,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"5340:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":630,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5340:52:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":631,"nodeType":"ExpressionStatement","src":"5340:52:0"}]},"documentation":{"id":610,"nodeType":"StructuredDocumentation","src":"5167:84:0","text":"@notice example external function, to force a CALL, and test vm.startPrank with."},"functionSelector":"a777d0dc","implemented":true,"kind":"function","modifiers":[],"name":"hello","nameLocation":"5265:5:0","parameters":{"id":613,"nodeType":"ParameterList","parameters":[{"constant":false,"id":612,"mutability":"mutable","name":"_v","nameLocation":"5287:2:0","nodeType":"VariableDeclaration","scope":633,"src":"5271:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":611,"name":"string","nodeType":"ElementaryTypeName","src":"5271:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5270:20:0"},"returnParameters":{"id":614,"nodeType":"ParameterList","parameters":[],"src":"5305:0:0"},"scope":706,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":648,"nodeType":"FunctionDefinition","src":"5405:95:0","nodes":[],"body":{"id":647,"nodeType":"Block","src":"5449:51:0","nodes":[],"statements":[{"expression":{"id":639,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5459:9:0","subExpression":{"id":638,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5459:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":640,"nodeType":"ExpressionStatement","src":"5459:9:0"},{"expression":{"arguments":[{"id":644,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":635,"src":"5490:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":641,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5478:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":643,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5478:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":645,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5478:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":646,"nodeType":"ExpressionStatement","src":"5478:15:0"}]},"functionSelector":"7e79255d","implemented":true,"kind":"function","modifiers":[],"name":"call1","nameLocation":"5414:5:0","parameters":{"id":636,"nodeType":"ParameterList","parameters":[{"constant":false,"id":635,"mutability":"mutable","name":"_v","nameLocation":"5436:2:0","nodeType":"VariableDeclaration","scope":648,"src":"5420:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":634,"name":"string","nodeType":"ElementaryTypeName","src":"5420:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5419:20:0"},"returnParameters":{"id":637,"nodeType":"ParameterList","parameters":[],"src":"5449:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":663,"nodeType":"FunctionDefinition","src":"5506:95:0","nodes":[],"body":{"id":662,"nodeType":"Block","src":"5550:51:0","nodes":[],"statements":[{"expression":{"id":654,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5560:9:0","subExpression":{"id":653,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5560:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":655,"nodeType":"ExpressionStatement","src":"5560:9:0"},{"expression":{"arguments":[{"id":659,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":650,"src":"5591:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":656,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5579:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":658,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5579:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":660,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5579:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":661,"nodeType":"ExpressionStatement","src":"5579:15:0"}]},"functionSelector":"8d3ef7ca","implemented":true,"kind":"function","modifiers":[],"name":"call2","nameLocation":"5515:5:0","parameters":{"id":651,"nodeType":"ParameterList","parameters":[{"constant":false,"id":650,"mutability":"mutable","name":"_v","nameLocation":"5537:2:0","nodeType":"VariableDeclaration","scope":663,"src":"5521:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":649,"name":"string","nodeType":"ElementaryTypeName","src":"5521:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5520:20:0"},"returnParameters":{"id":652,"nodeType":"ParameterList","parameters":[],"src":"5550:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":678,"nodeType":"FunctionDefinition","src":"5607:98:0","nodes":[],"body":{"id":677,"nodeType":"Block","src":"5653:52:0","nodes":[],"statements":[{"expression":{"id":669,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5663:9:0","subExpression":{"id":668,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5663:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":670,"nodeType":"ExpressionStatement","src":"5663:9:0"},{"expression":{"arguments":[{"id":674,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":665,"src":"5695:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":671,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5682:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":673,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested2","nodeType":"MemberAccess","referencedDeclaration":693,"src":"5682:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":675,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5682:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":676,"nodeType":"ExpressionStatement","src":"5682:16:0"}]},"functionSelector":"a76ccdfa","implemented":true,"kind":"function","modifiers":[],"name":"nested1","nameLocation":"5616:7:0","parameters":{"id":666,"nodeType":"ParameterList","parameters":[{"constant":false,"id":665,"mutability":"mutable","name":"_v","nameLocation":"5640:2:0","nodeType":"VariableDeclaration","scope":678,"src":"5624:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":664,"name":"string","nodeType":"ElementaryTypeName","src":"5624:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5623:20:0"},"returnParameters":{"id":667,"nodeType":"ParameterList","parameters":[],"src":"5653:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":693,"nodeType":"FunctionDefinition","src":"5711:97:0","nodes":[],"body":{"id":692,"nodeType":"Block","src":"5757:51:0","nodes":[],"statements":[{"expression":{"id":684,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5767:9:0","subExpression":{"id":683,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5767:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":685,"nodeType":"ExpressionStatement","src":"5767:9:0"},{"expression":{"arguments":[{"id":689,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":680,"src":"5798:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":686,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5786:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":688,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5786:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":690,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5786:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":691,"nodeType":"ExpressionStatement","src":"5786:15:0"}]},"functionSelector":"dbf1282f","implemented":true,"kind":"function","modifiers":[],"name":"nested2","nameLocation":"5720:7:0","parameters":{"id":681,"nodeType":"ParameterList","parameters":[{"constant":false,"id":680,"mutability":"mutable","name":"_v","nameLocation":"5744:2:0","nodeType":"VariableDeclaration","scope":693,"src":"5728:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":679,"name":"string","nodeType":"ElementaryTypeName","src":"5728:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5727:20:0"},"returnParameters":{"id":682,"nodeType":"ParameterList","parameters":[],"src":"5757:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":705,"nodeType":"FunctionDefinition","src":"5814:84:0","nodes":[],"body":{"id":704,"nodeType":"Block","src":"5866:32:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":701,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":695,"src":"5888:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":698,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5876:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":700,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5876:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":702,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5876:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":703,"nodeType":"ExpressionStatement","src":"5876:15:0"}]},"functionSelector":"7f8b915c","implemented":true,"kind":"function","modifiers":[],"name":"callPure","nameLocation":"5823:8:0","parameters":{"id":696,"nodeType":"ParameterList","parameters":[{"constant":false,"id":695,"mutability":"mutable","name":"_v","nameLocation":"5848:2:0","nodeType":"VariableDeclaration","scope":705,"src":"5832:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":694,"name":"string","nodeType":"ElementaryTypeName","src":"5832:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5831:20:0"},"returnParameters":{"id":697,"nodeType":"ParameterList","parameters":[],"src":"5866:0:0"},"scope":706,"stateMutability":"pure","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ScriptExample","contractDependencies":[719],"contractKind":"contract","documentation":{"id":193,"nodeType":"StructuredDocumentation","src":"2415:126:0","text":"@title ScriptExample\n @notice ScriptExample is an example script. The Go forge script code tests that it can run this."},"fullyImplemented":true,"linearizedBaseContracts":[706],"name":"ScriptExample","nameLocation":"2550:13:0","scope":720,"usedErrors":[]},{"id":719,"nodeType":"ContractDefinition","src":"5902:96:0","nodes":[{"id":708,"nodeType":"VariableDeclaration","src":"5924:18:0","nodes":[],"constant":false,"functionSelector":"c2985578","mutability":"mutable","name":"foo","nameLocation":"5939:3:0","scope":719,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":707,"name":"uint256","nodeType":"ElementaryTypeName","src":"5924:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":718,"nodeType":"FunctionDefinition","src":"5949:47:0","nodes":[],"body":{"id":717,"nodeType":"Block","src":"5972:24:0","nodes":[],"statements":[{"expression":{"id":715,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":713,"name":"foo","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":708,"src":"5982:3:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":714,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":710,"src":"5988:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"5982:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":716,"nodeType":"ExpressionStatement","src":"5982:7:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":711,"nodeType":"ParameterList","parameters":[{"constant":false,"id":710,"mutability":"mutable","name":"v","nameLocation":"5969:1:0","nodeType":"VariableDeclaration","scope":718,"src":"5961:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":709,"name":"uint256","nodeType":"ElementaryTypeName","src":"5961:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"5960:11:0"},"returnParameters":{"id":712,"nodeType":"ParameterList","parameters":[],"src":"5972:0:0"},"scope":719,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"FooBar","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[719],"name":"FooBar","nameLocation":"5911:6:0","scope":720,"usedErrors":[]}],"license":"MIT"},"id":0} \ No newline at end of file +{"abi":[{"type":"function","name":"allowCheatcodes","inputs":[{"name":"account","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"broadcast","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"broadcast","inputs":[{"name":"msgSender","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"createSelectFork","inputs":[{"name":"forkName","type":"string","internalType":"string"},{"name":"blockNumber","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"nonpayable"},{"type":"function","name":"envOr","inputs":[{"name":"name","type":"string","internalType":"string"},{"name":"defaultValue","type":"bool","internalType":"bool"}],"outputs":[{"name":"value","type":"bool","internalType":"bool"}],"stateMutability":"view"},{"type":"function","name":"etch","inputs":[{"name":"target","type":"address","internalType":"address"},{"name":"newRuntimeBytecode","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"getDeployedCode","inputs":[{"name":"artifactPath","type":"string","internalType":"string"}],"outputs":[{"name":"runtimeBytecode","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"getNonce","inputs":[{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"nonce","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"function","name":"parseJsonKeys","inputs":[{"name":"json","type":"string","internalType":"string"},{"name":"key","type":"string","internalType":"string"}],"outputs":[{"name":"keys","type":"string[]","internalType":"string[]"}],"stateMutability":"pure"},{"type":"function","name":"startBroadcast","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"startBroadcast","inputs":[{"name":"msgSender","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"startPrank","inputs":[{"name":"msgSender","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"stopBroadcast","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"stopPrank","inputs":[],"outputs":[],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"allowCheatcodes(address)":"ea060291","broadcast()":"afc98040","broadcast(address)":"e6962cdb","createSelectFork(string,uint256)":"71ee464d","envOr(string,bool)":"4777f3cf","etch(address,bytes)":"b4d6c782","getDeployedCode(string)":"3ebf73b4","getNonce(address)":"2d0335ab","parseJsonKeys(string,string)":"213e4198","startBroadcast()":"7fb5297f","startBroadcast(address)":"7fec2a8d","startPrank(address)":"06447d56","stopBroadcast()":"76eadd36","stopPrank()":"90c5013b"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"allowCheatcodes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"broadcast\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"msgSender\",\"type\":\"address\"}],\"name\":\"broadcast\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"forkName\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"createSelectFork\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bool\",\"name\":\"defaultValue\",\"type\":\"bool\"}],\"name\":\"envOr\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"value\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"newRuntimeBytecode\",\"type\":\"bytes\"}],\"name\":\"etch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"artifactPath\",\"type\":\"string\"}],\"name\":\"getDeployedCode\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"runtimeBytecode\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"getNonce\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"json\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"key\",\"type\":\"string\"}],\"name\":\"parseJsonKeys\",\"outputs\":[{\"internalType\":\"string[]\",\"name\":\"keys\",\"type\":\"string[]\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"startBroadcast\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"msgSender\",\"type\":\"address\"}],\"name\":\"startBroadcast\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"msgSender\",\"type\":\"address\"}],\"name\":\"startPrank\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stopBroadcast\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"stopPrank\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"scripts/ScriptExample.s.sol\":\"Vm\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"scripts/ScriptExample.s.sol\":{\"keccak256\":\"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28\",\"dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"account","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"allowCheatcodes"},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"broadcast"},{"inputs":[{"internalType":"address","name":"msgSender","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"broadcast"},{"inputs":[{"internalType":"string","name":"forkName","type":"string"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"createSelectFork","outputs":[{"internalType":"uint256","name":"","type":"uint256"}]},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"bool","name":"defaultValue","type":"bool"}],"stateMutability":"view","type":"function","name":"envOr","outputs":[{"internalType":"bool","name":"value","type":"bool"}]},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"newRuntimeBytecode","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"etch"},{"inputs":[{"internalType":"string","name":"artifactPath","type":"string"}],"stateMutability":"view","type":"function","name":"getDeployedCode","outputs":[{"internalType":"bytes","name":"runtimeBytecode","type":"bytes"}]},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"stateMutability":"view","type":"function","name":"getNonce","outputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}]},{"inputs":[{"internalType":"string","name":"json","type":"string"},{"internalType":"string","name":"key","type":"string"}],"stateMutability":"pure","type":"function","name":"parseJsonKeys","outputs":[{"internalType":"string[]","name":"keys","type":"string[]"}]},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"startBroadcast"},{"inputs":[{"internalType":"address","name":"msgSender","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"startBroadcast"},{"inputs":[{"internalType":"address","name":"msgSender","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"startPrank"},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"stopBroadcast"},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"stopPrank"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"scripts/ScriptExample.s.sol":"Vm"},"evmVersion":"london","libraries":{}},"sources":{"scripts/ScriptExample.s.sol":{"keccak256":"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da","urls":["bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28","dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[],"types":{}},"userdoc":{"version":1,"kind":"user"},"devdoc":{"version":1,"kind":"dev"},"ast":{"absolutePath":"scripts/ScriptExample.s.sol","id":969,"exportedSymbols":{"FooBar":[799],"ForkTester":[968],"ForkedContract":[852],"NonceGetter":[833],"ScriptExample":[786],"Vm":[83],"console":[220]},"nodeType":"SourceUnit","src":"32:8375:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","0.8",".15"]},{"id":83,"nodeType":"ContractDefinition","src":"120:969:0","nodes":[{"id":10,"nodeType":"FunctionDefinition","src":"139:91:0","nodes":[],"functionSelector":"4777f3cf","implemented":false,"kind":"function","modifiers":[],"name":"envOr","nameLocation":"148:5:0","parameters":{"id":6,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"mutability":"mutable","name":"name","nameLocation":"170:4:0","nodeType":"VariableDeclaration","scope":10,"src":"154:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":2,"name":"string","nodeType":"ElementaryTypeName","src":"154:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":5,"mutability":"mutable","name":"defaultValue","nameLocation":"181:12:0","nodeType":"VariableDeclaration","scope":10,"src":"176:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":4,"name":"bool","nodeType":"ElementaryTypeName","src":"176:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"153:41:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[{"constant":false,"id":8,"mutability":"mutable","name":"value","nameLocation":"223:5:0","nodeType":"VariableDeclaration","scope":10,"src":"218:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":7,"name":"bool","nodeType":"ElementaryTypeName","src":"218:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"217:12:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":17,"nodeType":"FunctionDefinition","src":"235:72:0","nodes":[],"functionSelector":"2d0335ab","implemented":false,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"244:8:0","parameters":{"id":13,"nodeType":"ParameterList","parameters":[{"constant":false,"id":12,"mutability":"mutable","name":"account","nameLocation":"261:7:0","nodeType":"VariableDeclaration","scope":17,"src":"253:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":11,"name":"address","nodeType":"ElementaryTypeName","src":"253:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"252:17:0"},"returnParameters":{"id":16,"nodeType":"ParameterList","parameters":[{"constant":false,"id":15,"mutability":"mutable","name":"nonce","nameLocation":"300:5:0","nodeType":"VariableDeclaration","scope":17,"src":"293:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"},"typeName":{"id":14,"name":"uint64","nodeType":"ElementaryTypeName","src":"293:6:0","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"visibility":"internal"}],"src":"292:14:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":27,"nodeType":"FunctionDefinition","src":"312:111:0","nodes":[],"functionSelector":"213e4198","implemented":false,"kind":"function","modifiers":[],"name":"parseJsonKeys","nameLocation":"321:13:0","parameters":{"id":22,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19,"mutability":"mutable","name":"json","nameLocation":"351:4:0","nodeType":"VariableDeclaration","scope":27,"src":"335:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":18,"name":"string","nodeType":"ElementaryTypeName","src":"335:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":21,"mutability":"mutable","name":"key","nameLocation":"373:3:0","nodeType":"VariableDeclaration","scope":27,"src":"357:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":20,"name":"string","nodeType":"ElementaryTypeName","src":"357:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"334:43:0"},"returnParameters":{"id":26,"nodeType":"ParameterList","parameters":[{"constant":false,"id":25,"mutability":"mutable","name":"keys","nameLocation":"417:4:0","nodeType":"VariableDeclaration","scope":27,"src":"401:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":23,"name":"string","nodeType":"ElementaryTypeName","src":"401:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":24,"nodeType":"ArrayTypeName","src":"401:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"src":"400:22:0"},"scope":83,"stateMutability":"pure","virtual":false,"visibility":"external"},{"id":32,"nodeType":"FunctionDefinition","src":"428:48:0","nodes":[],"functionSelector":"06447d56","implemented":false,"kind":"function","modifiers":[],"name":"startPrank","nameLocation":"437:10:0","parameters":{"id":30,"nodeType":"ParameterList","parameters":[{"constant":false,"id":29,"mutability":"mutable","name":"msgSender","nameLocation":"456:9:0","nodeType":"VariableDeclaration","scope":32,"src":"448:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":28,"name":"address","nodeType":"ElementaryTypeName","src":"448:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"447:19:0"},"returnParameters":{"id":31,"nodeType":"ParameterList","parameters":[],"src":"475:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":35,"nodeType":"FunctionDefinition","src":"481:30:0","nodes":[],"functionSelector":"90c5013b","implemented":false,"kind":"function","modifiers":[],"name":"stopPrank","nameLocation":"490:9:0","parameters":{"id":33,"nodeType":"ParameterList","parameters":[],"src":"499:2:0"},"returnParameters":{"id":34,"nodeType":"ParameterList","parameters":[],"src":"510:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":38,"nodeType":"FunctionDefinition","src":"516:30:0","nodes":[],"functionSelector":"afc98040","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"525:9:0","parameters":{"id":36,"nodeType":"ParameterList","parameters":[],"src":"534:2:0"},"returnParameters":{"id":37,"nodeType":"ParameterList","parameters":[],"src":"545:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":43,"nodeType":"FunctionDefinition","src":"551:47:0","nodes":[],"functionSelector":"e6962cdb","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"560:9:0","parameters":{"id":41,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40,"mutability":"mutable","name":"msgSender","nameLocation":"578:9:0","nodeType":"VariableDeclaration","scope":43,"src":"570:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39,"name":"address","nodeType":"ElementaryTypeName","src":"570:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"569:19:0"},"returnParameters":{"id":42,"nodeType":"ParameterList","parameters":[],"src":"597:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":48,"nodeType":"FunctionDefinition","src":"603:52:0","nodes":[],"functionSelector":"7fec2a8d","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"612:14:0","parameters":{"id":46,"nodeType":"ParameterList","parameters":[{"constant":false,"id":45,"mutability":"mutable","name":"msgSender","nameLocation":"635:9:0","nodeType":"VariableDeclaration","scope":48,"src":"627:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":44,"name":"address","nodeType":"ElementaryTypeName","src":"627:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"626:19:0"},"returnParameters":{"id":47,"nodeType":"ParameterList","parameters":[],"src":"654:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":51,"nodeType":"FunctionDefinition","src":"660:35:0","nodes":[],"functionSelector":"7fb5297f","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"669:14:0","parameters":{"id":49,"nodeType":"ParameterList","parameters":[],"src":"683:2:0"},"returnParameters":{"id":50,"nodeType":"ParameterList","parameters":[],"src":"694:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":54,"nodeType":"FunctionDefinition","src":"700:34:0","nodes":[],"functionSelector":"76eadd36","implemented":false,"kind":"function","modifiers":[],"name":"stopBroadcast","nameLocation":"709:13:0","parameters":{"id":52,"nodeType":"ParameterList","parameters":[],"src":"722:2:0"},"returnParameters":{"id":53,"nodeType":"ParameterList","parameters":[],"src":"733:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":61,"nodeType":"FunctionDefinition","src":"739:108:0","nodes":[],"functionSelector":"3ebf73b4","implemented":false,"kind":"function","modifiers":[],"name":"getDeployedCode","nameLocation":"748:15:0","parameters":{"id":57,"nodeType":"ParameterList","parameters":[{"constant":false,"id":56,"mutability":"mutable","name":"artifactPath","nameLocation":"780:12:0","nodeType":"VariableDeclaration","scope":61,"src":"764:28:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":55,"name":"string","nodeType":"ElementaryTypeName","src":"764:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"763:30:0"},"returnParameters":{"id":60,"nodeType":"ParameterList","parameters":[{"constant":false,"id":59,"mutability":"mutable","name":"runtimeBytecode","nameLocation":"830:15:0","nodeType":"VariableDeclaration","scope":61,"src":"817:28:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":58,"name":"bytes","nodeType":"ElementaryTypeName","src":"817:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"816:30:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":68,"nodeType":"FunctionDefinition","src":"852:74:0","nodes":[],"functionSelector":"b4d6c782","implemented":false,"kind":"function","modifiers":[],"name":"etch","nameLocation":"861:4:0","parameters":{"id":66,"nodeType":"ParameterList","parameters":[{"constant":false,"id":63,"mutability":"mutable","name":"target","nameLocation":"874:6:0","nodeType":"VariableDeclaration","scope":68,"src":"866:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":62,"name":"address","nodeType":"ElementaryTypeName","src":"866:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":65,"mutability":"mutable","name":"newRuntimeBytecode","nameLocation":"897:18:0","nodeType":"VariableDeclaration","scope":68,"src":"882:33:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":64,"name":"bytes","nodeType":"ElementaryTypeName","src":"882:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"865:51:0"},"returnParameters":{"id":67,"nodeType":"ParameterList","parameters":[],"src":"925:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":73,"nodeType":"FunctionDefinition","src":"931:51:0","nodes":[],"functionSelector":"ea060291","implemented":false,"kind":"function","modifiers":[],"name":"allowCheatcodes","nameLocation":"940:15:0","parameters":{"id":71,"nodeType":"ParameterList","parameters":[{"constant":false,"id":70,"mutability":"mutable","name":"account","nameLocation":"964:7:0","nodeType":"VariableDeclaration","scope":73,"src":"956:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":69,"name":"address","nodeType":"ElementaryTypeName","src":"956:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"955:17:0"},"returnParameters":{"id":72,"nodeType":"ParameterList","parameters":[],"src":"981:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":82,"nodeType":"FunctionDefinition","src":"987:100:0","nodes":[],"functionSelector":"71ee464d","implemented":false,"kind":"function","modifiers":[],"name":"createSelectFork","nameLocation":"996:16:0","parameters":{"id":78,"nodeType":"ParameterList","parameters":[{"constant":false,"id":75,"mutability":"mutable","name":"forkName","nameLocation":"1029:8:0","nodeType":"VariableDeclaration","scope":82,"src":"1013:24:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":74,"name":"string","nodeType":"ElementaryTypeName","src":"1013:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":77,"mutability":"mutable","name":"blockNumber","nameLocation":"1047:11:0","nodeType":"VariableDeclaration","scope":82,"src":"1039:19:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":76,"name":"uint256","nodeType":"ElementaryTypeName","src":"1039:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1012:47:0"},"returnParameters":{"id":81,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":82,"src":"1078:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":79,"name":"uint256","nodeType":"ElementaryTypeName","src":"1078:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1077:9:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"Vm","contractDependencies":[],"contractKind":"interface","fullyImplemented":false,"linearizedBaseContracts":[83],"name":"Vm","nameLocation":"130:2:0","scope":969,"usedErrors":[]},{"id":220,"nodeType":"ContractDefinition","src":"1144:1851:0","nodes":[{"id":89,"nodeType":"VariableDeclaration","src":"1166:86:0","nodes":[],"constant":true,"mutability":"constant","name":"CONSOLE_ADDRESS","nameLocation":"1183:15:0","scope":220,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":84,"name":"address","nodeType":"ElementaryTypeName","src":"1166:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"hexValue":"307830303030303030303030303030303030303036333646366537333646366336353265366336663637","id":87,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1209:42:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"value":"0x000000000000000000636F6e736F6c652e6c6f67"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":86,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":85,"name":"address","nodeType":"ElementaryTypeName","src":"1201:7:0","typeDescriptions":{}}},"id":88,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1201:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":106,"nodeType":"FunctionDefinition","src":"1259:235:0","nodes":[],"body":{"id":105,"nodeType":"Block","src":"1432:62:0","nodes":[],"statements":[{"AST":{"nodeType":"YulBlock","src":"1451:37:0","statements":[{"nodeType":"YulAssignment","src":"1465:13:0","value":{"name":"fnIn","nodeType":"YulIdentifier","src":"1474:4:0"},"variableNames":[{"name":"fnOut","nodeType":"YulIdentifier","src":"1465:5:0"}]}]},"evmVersion":"london","externalReferences":[{"declaration":95,"isOffset":false,"isSlot":false,"src":"1474:4:0","valueSize":1},{"declaration":102,"isOffset":false,"isSlot":false,"src":"1465:5:0","valueSize":1}],"id":104,"nodeType":"InlineAssembly","src":"1442:46:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_castLogPayloadViewToPure","nameLocation":"1268:25:0","parameters":{"id":96,"nodeType":"ParameterList","parameters":[{"constant":false,"id":95,"mutability":"mutable","name":"fnIn","nameLocation":"1331:4:0","nodeType":"VariableDeclaration","scope":106,"src":"1294:41:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"typeName":{"id":94,"nodeType":"FunctionTypeName","parameterTypes":{"id":92,"nodeType":"ParameterList","parameters":[{"constant":false,"id":91,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":94,"src":"1303:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":90,"name":"bytes","nodeType":"ElementaryTypeName","src":"1303:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1302:14:0"},"returnParameterTypes":{"id":93,"nodeType":"ParameterList","parameters":[],"src":"1331:0:0"},"src":"1294:41:0","stateMutability":"view","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"visibility":"internal"},"visibility":"internal"}],"src":"1293:43:0"},"returnParameters":{"id":103,"nodeType":"ParameterList","parameters":[{"constant":false,"id":102,"mutability":"mutable","name":"fnOut","nameLocation":"1421:5:0","nodeType":"VariableDeclaration","scope":106,"src":"1384:42:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"typeName":{"id":101,"nodeType":"FunctionTypeName","parameterTypes":{"id":99,"nodeType":"ParameterList","parameters":[{"constant":false,"id":98,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":101,"src":"1393:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":97,"name":"bytes","nodeType":"ElementaryTypeName","src":"1393:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1392:14:0"},"returnParameterTypes":{"id":100,"nodeType":"ParameterList","parameters":[],"src":"1421:0:0"},"src":"1384:42:0","stateMutability":"pure","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"visibility":"internal"},"visibility":"internal"}],"src":"1383:44:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":118,"nodeType":"FunctionDefinition","src":"1500:133:0","nodes":[],"body":{"id":117,"nodeType":"Block","src":"1561:72:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":114,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":108,"src":"1618:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"arguments":[{"id":112,"name":"_sendLogPayloadView","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":134,"src":"1597:19:0","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}],"id":111,"name":"_castLogPayloadViewToPure","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":106,"src":"1571:25:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_function_internal_view$_t_bytes_memory_ptr_$returns$__$_$returns$_t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$_$","typeString":"function (function (bytes memory) view) pure returns (function (bytes memory) pure)"}},"id":113,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":115,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":116,"nodeType":"ExpressionStatement","src":"1571:55:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayload","nameLocation":"1509:15:0","parameters":{"id":109,"nodeType":"ParameterList","parameters":[{"constant":false,"id":108,"mutability":"mutable","name":"payload","nameLocation":"1538:7:0","nodeType":"VariableDeclaration","scope":118,"src":"1525:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":107,"name":"bytes","nodeType":"ElementaryTypeName","src":"1525:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1524:22:0"},"returnParameters":{"id":110,"nodeType":"ParameterList","parameters":[],"src":"1561:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":134,"nodeType":"FunctionDefinition","src":"1639:380:0","nodes":[],"body":{"id":133,"nodeType":"Block","src":"1703:316:0","nodes":[],"statements":[{"assignments":[124],"declarations":[{"constant":false,"id":124,"mutability":"mutable","name":"payloadLength","nameLocation":"1721:13:0","nodeType":"VariableDeclaration","scope":133,"src":"1713:21:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":123,"name":"uint256","nodeType":"ElementaryTypeName","src":"1713:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":127,"initialValue":{"expression":{"id":125,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":120,"src":"1737:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":126,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1737:14:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1713:38:0"},{"assignments":[129],"declarations":[{"constant":false,"id":129,"mutability":"mutable","name":"consoleAddress","nameLocation":"1769:14:0","nodeType":"VariableDeclaration","scope":133,"src":"1761:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":128,"name":"address","nodeType":"ElementaryTypeName","src":"1761:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":131,"initialValue":{"id":130,"name":"CONSOLE_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":89,"src":"1786:15:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"1761:40:0"},{"AST":{"nodeType":"YulBlock","src":"1863:150:0","statements":[{"nodeType":"YulVariableDeclaration","src":"1877:36:0","value":{"arguments":[{"name":"payload","nodeType":"YulIdentifier","src":"1901:7:0"},{"kind":"number","nodeType":"YulLiteral","src":"1910:2:0","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1897:3:0"},"nodeType":"YulFunctionCall","src":"1897:16:0"},"variables":[{"name":"payloadStart","nodeType":"YulTypedName","src":"1881:12:0","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1926:77:0","value":{"arguments":[{"arguments":[],"functionName":{"name":"gas","nodeType":"YulIdentifier","src":"1946:3:0"},"nodeType":"YulFunctionCall","src":"1946:5:0"},{"name":"consoleAddress","nodeType":"YulIdentifier","src":"1953:14:0"},{"name":"payloadStart","nodeType":"YulIdentifier","src":"1969:12:0"},{"name":"payloadLength","nodeType":"YulIdentifier","src":"1983:13:0"},{"kind":"number","nodeType":"YulLiteral","src":"1998:1:0","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"2001:1:0","type":"","value":"0"}],"functionName":{"name":"staticcall","nodeType":"YulIdentifier","src":"1935:10:0"},"nodeType":"YulFunctionCall","src":"1935:68:0"},"variables":[{"name":"r","nodeType":"YulTypedName","src":"1930:1:0","type":""}]}]},"documentation":"@solidity memory-safe-assembly","evmVersion":"london","externalReferences":[{"declaration":129,"isOffset":false,"isSlot":false,"src":"1953:14:0","valueSize":1},{"declaration":120,"isOffset":false,"isSlot":false,"src":"1901:7:0","valueSize":1},{"declaration":124,"isOffset":false,"isSlot":false,"src":"1983:13:0","valueSize":1}],"id":132,"nodeType":"InlineAssembly","src":"1854:159:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayloadView","nameLocation":"1648:19:0","parameters":{"id":121,"nodeType":"ParameterList","parameters":[{"constant":false,"id":120,"mutability":"mutable","name":"payload","nameLocation":"1681:7:0","nodeType":"VariableDeclaration","scope":134,"src":"1668:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":119,"name":"bytes","nodeType":"ElementaryTypeName","src":"1668:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1667:22:0"},"returnParameters":{"id":122,"nodeType":"ParameterList","parameters":[],"src":"1703:0:0"},"scope":220,"stateMutability":"view","virtual":false,"visibility":"private"},{"id":148,"nodeType":"FunctionDefinition","src":"2025:164:0","nodes":[],"body":{"id":147,"nodeType":"Block","src":"2070:119:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e6729","id":142,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2120:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},"value":"log(string)"},{"id":143,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":136,"src":"2135:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":140,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2096:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":141,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2096:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":144,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2096:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":139,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2080:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":145,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2080:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":146,"nodeType":"ExpressionStatement","src":"2080:59:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2034:3:0","parameters":{"id":137,"nodeType":"ParameterList","parameters":[{"constant":false,"id":136,"mutability":"mutable","name":"p0","nameLocation":"2052:2:0","nodeType":"VariableDeclaration","scope":148,"src":"2038:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":135,"name":"string","nodeType":"ElementaryTypeName","src":"2038:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2037:18:0"},"returnParameters":{"id":138,"nodeType":"ParameterList","parameters":[],"src":"2070:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":165,"nodeType":"FunctionDefinition","src":"2195:182:0","nodes":[],"body":{"id":164,"nodeType":"Block","src":"2249:128:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c626f6f6c29","id":158,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2299:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},"value":"log(string,bool)"},{"id":159,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":150,"src":"2319:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":160,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":152,"src":"2323:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":156,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2275:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":157,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2275:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":161,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2275:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":155,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2259:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":162,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2259:68:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":163,"nodeType":"ExpressionStatement","src":"2259:68:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2204:3:0","parameters":{"id":153,"nodeType":"ParameterList","parameters":[{"constant":false,"id":150,"mutability":"mutable","name":"p0","nameLocation":"2222:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2208:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":149,"name":"string","nodeType":"ElementaryTypeName","src":"2208:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":152,"mutability":"mutable","name":"p1","nameLocation":"2231:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2226:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":151,"name":"bool","nodeType":"ElementaryTypeName","src":"2226:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"2207:27:0"},"returnParameters":{"id":154,"nodeType":"ParameterList","parameters":[],"src":"2249:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":182,"nodeType":"FunctionDefinition","src":"2383:188:0","nodes":[],"body":{"id":181,"nodeType":"Block","src":"2440:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c75696e7432353629","id":175,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2490:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},"value":"log(string,uint256)"},{"id":176,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":167,"src":"2513:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":177,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":169,"src":"2517:2:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":173,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2466:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":174,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2466:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":178,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2466:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":172,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2450:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":179,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2450:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":180,"nodeType":"ExpressionStatement","src":"2450:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2392:3:0","parameters":{"id":170,"nodeType":"ParameterList","parameters":[{"constant":false,"id":167,"mutability":"mutable","name":"p0","nameLocation":"2410:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2396:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":166,"name":"string","nodeType":"ElementaryTypeName","src":"2396:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":169,"mutability":"mutable","name":"p1","nameLocation":"2422:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2414:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":168,"name":"uint256","nodeType":"ElementaryTypeName","src":"2414:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"2395:30:0"},"returnParameters":{"id":171,"nodeType":"ParameterList","parameters":[],"src":"2440:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":199,"nodeType":"FunctionDefinition","src":"2577:188:0","nodes":[],"body":{"id":198,"nodeType":"Block","src":"2634:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c6164647265737329","id":192,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2684:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},"value":"log(string,address)"},{"id":193,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":184,"src":"2707:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":194,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":186,"src":"2711:2:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":190,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2660:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":191,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2660:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":195,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2660:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":189,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2644:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":196,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2644:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":197,"nodeType":"ExpressionStatement","src":"2644:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2586:3:0","parameters":{"id":187,"nodeType":"ParameterList","parameters":[{"constant":false,"id":184,"mutability":"mutable","name":"p0","nameLocation":"2604:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2590:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":183,"name":"string","nodeType":"ElementaryTypeName","src":"2590:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":186,"mutability":"mutable","name":"p1","nameLocation":"2616:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2608:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":185,"name":"address","nodeType":"ElementaryTypeName","src":"2608:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2589:30:0"},"returnParameters":{"id":188,"nodeType":"ParameterList","parameters":[],"src":"2634:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":219,"nodeType":"FunctionDefinition","src":"2771:222:0","nodes":[],"body":{"id":218,"nodeType":"Block","src":"2852:141:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c737472696e672c737472696e6729","id":211,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2902:27:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},"value":"log(string,string,string)"},{"id":212,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":201,"src":"2931:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":213,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":203,"src":"2935:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":214,"name":"p2","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":205,"src":"2939:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":209,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2878:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":210,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2878:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":215,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2878:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":208,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2862:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":216,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2862:81:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":217,"nodeType":"ExpressionStatement","src":"2862:81:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2780:3:0","parameters":{"id":206,"nodeType":"ParameterList","parameters":[{"constant":false,"id":201,"mutability":"mutable","name":"p0","nameLocation":"2798:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2784:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":200,"name":"string","nodeType":"ElementaryTypeName","src":"2784:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":203,"mutability":"mutable","name":"p1","nameLocation":"2816:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2802:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":202,"name":"string","nodeType":"ElementaryTypeName","src":"2802:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":205,"mutability":"mutable","name":"p2","nameLocation":"2834:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2820:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":204,"name":"string","nodeType":"ElementaryTypeName","src":"2820:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2783:54:0"},"returnParameters":{"id":207,"nodeType":"ParameterList","parameters":[],"src":"2852:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"}],"abstract":false,"baseContracts":[],"canonicalName":"console","contractDependencies":[],"contractKind":"library","fullyImplemented":true,"linearizedBaseContracts":[220],"name":"console","nameLocation":"1152:7:0","scope":969,"usedErrors":[]},{"id":786,"nodeType":"ContractDefinition","src":"3123:3912:0","nodes":[{"id":235,"nodeType":"VariableDeclaration","src":"3152:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"3178:10:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":222,"name":"address","nodeType":"ElementaryTypeName","src":"3152:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":230,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3225:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":229,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"3215:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":231,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3215:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":228,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3207:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":227,"name":"uint256","nodeType":"ElementaryTypeName","src":"3207:7:0","typeDescriptions":{}}},"id":232,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3207:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":226,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3199:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":225,"name":"uint160","nodeType":"ElementaryTypeName","src":"3199:7:0","typeDescriptions":{}}},"id":233,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3199:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":224,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3191:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":223,"name":"address","nodeType":"ElementaryTypeName","src":"3191:7:0","typeDescriptions":{}}},"id":234,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3191:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":241,"nodeType":"VariableDeclaration","src":"3252:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"3273:2:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":237,"nodeType":"UserDefinedTypeName","pathNode":{"id":236,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"3252:2:0"},"referencedDeclaration":83,"src":"3252:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":239,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":235,"src":"3281:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":238,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"3278:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":240,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3278:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":243,"nodeType":"VariableDeclaration","src":"3356:22:0","nodes":[],"constant":false,"functionSelector":"61bc221a","mutability":"mutable","name":"counter","nameLocation":"3371:7:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":242,"name":"uint256","nodeType":"ElementaryTypeName","src":"3356:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":456,"nodeType":"FunctionDefinition","src":"3468:1428:0","nodes":[],"body":{"id":455,"nodeType":"Block","src":"3490:1406:0","nodes":[],"statements":[{"assignments":[248],"declarations":[{"constant":false,"id":248,"mutability":"mutable","name":"x","nameLocation":"3505:1:0","nodeType":"VariableDeclaration","scope":455,"src":"3500:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":247,"name":"bool","nodeType":"ElementaryTypeName","src":"3500:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"id":254,"initialValue":{"arguments":[{"hexValue":"4558414d504c455f424f4f4c","id":251,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3518:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},"value":"EXAMPLE_BOOL"},{"hexValue":"66616c7365","id":252,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"3534:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":249,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3509:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":250,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"envOr","nodeType":"MemberAccess","referencedDeclaration":10,"src":"3509:8:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$_t_bool_$returns$_t_bool_$","typeString":"function (string memory,bool) view external returns (bool)"}},"id":253,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3509:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"VariableDeclarationStatement","src":"3500:40:0"},{"expression":{"arguments":[{"hexValue":"626f6f6c2076616c75652066726f6d20656e76","id":258,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3562:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},"value":"bool value from env"},{"id":259,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":248,"src":"3585:1:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":255,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3550:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":257,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":165,"src":"3550:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_bool_$returns$__$","typeString":"function (string memory,bool) pure"}},"id":260,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3550:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":261,"nodeType":"ExpressionStatement","src":"3550:37:0"},{"expression":{"arguments":[{"hexValue":"636f6e74726163742061646472","id":265,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3610:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},"value":"contract addr"},{"arguments":[{"id":268,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3635:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":267,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3627:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":266,"name":"address","nodeType":"ElementaryTypeName","src":"3627:7:0","typeDescriptions":{}}},"id":269,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3627:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":262,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3598:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":264,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3598:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":270,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3598:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":271,"nodeType":"ExpressionStatement","src":"3598:43:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206e6f6e6365","id":275,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3663:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},"value":"contract nonce"},{"arguments":[{"arguments":[{"id":280,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3701:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":279,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3693:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":278,"name":"address","nodeType":"ElementaryTypeName","src":"3693:7:0","typeDescriptions":{}}},"id":281,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3693:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":276,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3681:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":277,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3681:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":282,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3681:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":272,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3651:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":274,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3651:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":283,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3651:57:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":284,"nodeType":"ExpressionStatement","src":"3651:57:0"},{"expression":{"arguments":[{"hexValue":"73656e6465722061646472","id":288,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3730:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},"value":"sender addr"},{"arguments":[{"expression":{"id":291,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3753:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":292,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3753:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":290,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3745:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":289,"name":"address","nodeType":"ElementaryTypeName","src":"3745:7:0","typeDescriptions":{}}},"id":293,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3745:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":285,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3718:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":287,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3718:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":294,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3718:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":295,"nodeType":"ExpressionStatement","src":"3718:47:0"},{"expression":{"arguments":[{"hexValue":"73656e646572206e6f6e6365","id":299,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3787:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},"value":"sender nonce"},{"arguments":[{"arguments":[{"expression":{"id":304,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3823:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":305,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3823:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":303,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3815:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":302,"name":"address","nodeType":"ElementaryTypeName","src":"3815:7:0","typeDescriptions":{}}},"id":306,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3815:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":300,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3803:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":301,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3803:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":307,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3803:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":296,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3775:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":298,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3775:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":308,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3775:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":309,"nodeType":"ExpressionStatement","src":"3775:61:0"},{"assignments":[311],"declarations":[{"constant":false,"id":311,"mutability":"mutable","name":"json","nameLocation":"3861:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3847:18:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":310,"name":"string","nodeType":"ElementaryTypeName","src":"3847:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"id":313,"initialValue":{"hexValue":"7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d","id":312,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3868:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e95522e99766888d0261f55bd1eae5e3f3e26eaf009a16e2433eafaf0a4ecdf2","typeString":"literal_string \"{\"root_key\": [{\"a\": 1, \"b\": 2}]}\""},"value":"{\"root_key\": [{\"a\": 1, \"b\": 2}]}"},"nodeType":"VariableDeclarationStatement","src":"3847:55:0"},{"assignments":[318],"declarations":[{"constant":false,"id":318,"mutability":"mutable","name":"keys","nameLocation":"3928:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3912:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":316,"name":"string","nodeType":"ElementaryTypeName","src":"3912:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":317,"nodeType":"ArrayTypeName","src":"3912:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"id":324,"initialValue":{"arguments":[{"id":321,"name":"json","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":311,"src":"3952:4:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"2e726f6f745f6b65795b305d","id":322,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3958:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""},"value":".root_key[0]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""}],"expression":{"id":319,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3935:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":320,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"parseJsonKeys","nodeType":"MemberAccess","referencedDeclaration":27,"src":"3935:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$_t_array$_t_string_memory_ptr_$dyn_memory_ptr_$","typeString":"function (string memory,string memory) pure external returns (string memory[] memory)"}},"id":323,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3935:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"nodeType":"VariableDeclarationStatement","src":"3912:61:0"},{"expression":{"arguments":[{"hexValue":"6b657973","id":328,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3995:6:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},"value":"keys"},{"baseExpression":{"id":329,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4003:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":331,"indexExpression":{"hexValue":"30","id":330,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4008:1:0","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4003:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"baseExpression":{"id":332,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4012:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":334,"indexExpression":{"hexValue":"31","id":333,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4017:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4012:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":325,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3983:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":327,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":219,"src":"3983:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory,string memory) pure"}},"id":335,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3983:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":336,"nodeType":"ExpressionStatement","src":"3983:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c","id":340,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4042:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""},"value":"from original"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""}],"expression":{"id":337,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4031:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":339,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4031:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":341,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4031:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":342,"nodeType":"ExpressionStatement","src":"4031:27:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"30783432","id":350,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4098:4:0","typeDescriptions":{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"},"value":"0x42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"}],"id":349,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4090:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":348,"name":"uint160","nodeType":"ElementaryTypeName","src":"4090:7:0","typeDescriptions":{}}},"id":351,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4090:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":347,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4082:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":346,"name":"address","nodeType":"ElementaryTypeName","src":"4082:7:0","typeDescriptions":{}}},"id":352,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4082:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":343,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4068:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":345,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startPrank","nodeType":"MemberAccess","referencedDeclaration":32,"src":"4068:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":353,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4068:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":354,"nodeType":"ExpressionStatement","src":"4068:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2031","id":358,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4126:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""},"value":"from prank 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""}],"expression":{"id":355,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4115:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":357,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4115:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":359,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4115:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":360,"nodeType":"ExpressionStatement","src":"4115:26:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f7065206d73672e73656e646572","id":364,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4163:25:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},"value":"parent scope msg.sender"},{"arguments":[{"expression":{"id":367,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"4198:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":368,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"4198:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":366,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4190:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":365,"name":"address","nodeType":"ElementaryTypeName","src":"4190:7:0","typeDescriptions":{}}},"id":369,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4190:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":361,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4151:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":363,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4151:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":370,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4151:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":371,"nodeType":"ExpressionStatement","src":"4151:59:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f706520636f6e74726163742e61646472","id":375,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4232:28:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},"value":"parent scope contract.addr"},{"arguments":[{"id":378,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4270:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":377,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4262:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":376,"name":"address","nodeType":"ElementaryTypeName","src":"4262:7:0","typeDescriptions":{}}},"id":379,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4262:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":372,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4220:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":374,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4220:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":380,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4220:56:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":381,"nodeType":"ExpressionStatement","src":"4220:56:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2032","id":385,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4297:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""},"value":"from prank 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""}],"expression":{"id":382,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4286:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":384,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4286:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":386,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4286:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":387,"nodeType":"ExpressionStatement","src":"4286:26:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":388,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4322:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":390,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopPrank","nodeType":"MemberAccess","referencedDeclaration":35,"src":"4322:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":391,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4322:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":392,"nodeType":"ExpressionStatement","src":"4322:14:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c20616761696e","id":396,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4357:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""},"value":"from original again"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""}],"expression":{"id":393,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4346:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":395,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4346:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":397,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4346:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":398,"nodeType":"ExpressionStatement","src":"4346:33:0"},{"assignments":[400],"declarations":[{"constant":false,"id":400,"mutability":"mutable","name":"tmpNonceGetter","nameLocation":"4480:14:0","nodeType":"VariableDeclaration","scope":455,"src":"4472:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":399,"name":"address","nodeType":"ElementaryTypeName","src":"4472:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":413,"initialValue":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"74656d70206e6f6e6365207465737420676574746572","id":408,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4531:24:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""},"value":"temp nonce test getter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""}],"id":407,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"4521:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":409,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4521:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":406,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4513:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":405,"name":"uint256","nodeType":"ElementaryTypeName","src":"4513:7:0","typeDescriptions":{}}},"id":410,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4513:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":404,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4505:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":403,"name":"uint160","nodeType":"ElementaryTypeName","src":"4505:7:0","typeDescriptions":{}}},"id":411,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4505:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":402,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4497:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":401,"name":"address","nodeType":"ElementaryTypeName","src":"4497:7:0","typeDescriptions":{}}},"id":412,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4497:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"4472:87:0"},{"expression":{"arguments":[{"id":417,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4577:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"arguments":[{"hexValue":"5363726970744578616d706c652e732e736f6c3a4e6f6e6365476574746572","id":420,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4612:33:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""},"value":"ScriptExample.s.sol:NonceGetter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""}],"expression":{"id":418,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4593:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":419,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getDeployedCode","nodeType":"MemberAccess","referencedDeclaration":61,"src":"4593:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) view external returns (bytes memory)"}},"id":421,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4593:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"expression":{"id":414,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4569:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":416,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"etch","nodeType":"MemberAccess","referencedDeclaration":68,"src":"4569:7:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$_t_bytes_memory_ptr_$returns$__$","typeString":"function (address,bytes memory) external"}},"id":422,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4569:78:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":423,"nodeType":"ExpressionStatement","src":"4569:78:0"},{"expression":{"arguments":[{"id":427,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4676:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":424,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4657:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":426,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"allowCheatcodes","nodeType":"MemberAccess","referencedDeclaration":73,"src":"4657:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":428,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4657:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":429,"nodeType":"ExpressionStatement","src":"4657:34:0"},{"assignments":[431],"declarations":[{"constant":false,"id":431,"mutability":"mutable","name":"v","nameLocation":"4709:1:0","nodeType":"VariableDeclaration","scope":455,"src":"4701:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":430,"name":"uint256","nodeType":"ElementaryTypeName","src":"4701:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":441,"initialValue":{"arguments":[{"arguments":[{"id":438,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4758:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":437,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4750:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":436,"name":"address","nodeType":"ElementaryTypeName","src":"4750:7:0","typeDescriptions":{}}},"id":439,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4750:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"arguments":[{"id":433,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4725:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":432,"name":"NonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":833,"src":"4713:11:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_NonceGetter_$833_$","typeString":"type(contract NonceGetter)"}},"id":434,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_NonceGetter_$833","typeString":"contract NonceGetter"}},"id":435,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":832,"src":"4713:36:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint256_$","typeString":"function (address) view external returns (uint256)"}},"id":440,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"4701:63:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e63652066726f6d206e6f6e6365206765747465722c206e6f206578706c6963697420616363657373207265717569726564207769746820766d2e657463683a","id":445,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4786:68:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},"value":"nonce from nonce getter, no explicit access required with vm.etch:"},{"id":446,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":431,"src":"4856:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":442,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4774:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":444,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"4774:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":447,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4774:84:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":448,"nodeType":"ExpressionStatement","src":"4774:84:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":452,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4881:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":449,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4869:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":451,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"4869:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":453,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4869:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":454,"nodeType":"ExpressionStatement","src":"4869:20:0"}]},"documentation":{"id":244,"nodeType":"StructuredDocumentation","src":"3385:78:0","text":"@notice example function, runs through basic cheat-codes and console logs."},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"3477:3:0","parameters":{"id":245,"nodeType":"ParameterList","parameters":[],"src":"3480:2:0"},"returnParameters":{"id":246,"nodeType":"ParameterList","parameters":[],"src":"3490:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":689,"nodeType":"FunctionDefinition","src":"4963:1333:0","nodes":[],"body":{"id":688,"nodeType":"Block","src":"4994:1302:0","nodes":[],"statements":[{"expression":{"arguments":[{"hexValue":"6e6f6e6365207374617274","id":463,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5016:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},"value":"nonce start"},{"arguments":[{"arguments":[{"arguments":[{"id":470,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5059:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":469,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5051:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":468,"name":"address","nodeType":"ElementaryTypeName","src":"5051:7:0","typeDescriptions":{}}},"id":471,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5051:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":466,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5039:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":467,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"5039:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":472,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5039:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":465,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5031:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":464,"name":"uint256","nodeType":"ElementaryTypeName","src":"5031:7:0","typeDescriptions":{}}},"id":473,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5031:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":460,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5004:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":462,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"5004:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":474,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5004:63:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":475,"nodeType":"ExpressionStatement","src":"5004:63:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073696e676c65","id":479,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5090:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""},"value":"testing single"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""}],"expression":{"id":476,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5078:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":478,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5078:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":480,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5078:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":481,"nodeType":"ExpressionStatement","src":"5078:29:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":482,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5117:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":484,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"5117:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":485,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5117:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":486,"nodeType":"ExpressionStatement","src":"5117:14:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c31","id":490,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5152:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""},"value":"single_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""}],"expression":{"id":487,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5141:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":489,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5141:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":491,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5141:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":492,"nodeType":"ExpressionStatement","src":"5141:26:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c32","id":496,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5188:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""},"value":"single_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""}],"expression":{"id":493,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5177:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":495,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5177:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":497,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5177:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":498,"nodeType":"ExpressionStatement","src":"5177:26:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073746172742f73746f70","id":502,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5226:20:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""},"value":"testing start/stop"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""}],"expression":{"id":499,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5214:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":501,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5214:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":503,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5214:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":504,"nodeType":"ExpressionStatement","src":"5214:33:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078633066666565","id":512,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5291:8:0","typeDescriptions":{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"},"value":"0xc0ffee"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"}],"id":511,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5283:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":510,"name":"uint160","nodeType":"ElementaryTypeName","src":"5283:7:0","typeDescriptions":{}}},"id":513,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5283:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":509,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5275:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":508,"name":"address","nodeType":"ElementaryTypeName","src":"5275:7:0","typeDescriptions":{}}},"id":514,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5275:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":505,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5257:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":507,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5257:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":515,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5257:45:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":516,"nodeType":"ExpressionStatement","src":"5257:45:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c31","id":520,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5323:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""},"value":"startstop_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""}],"expression":{"id":517,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5312:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":519,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5312:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":521,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5312:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":522,"nodeType":"ExpressionStatement","src":"5312:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c32","id":526,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5362:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""},"value":"startstop_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""}],"expression":{"id":523,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5351:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":525,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5351:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":527,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5351:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":528,"nodeType":"ExpressionStatement","src":"5351:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f70757265","id":532,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5404:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""},"value":"startstop_pure"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""}],"expression":{"id":529,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5390:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":531,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"callPure","nodeType":"MemberAccess","referencedDeclaration":785,"src":"5390:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure external"}},"id":533,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5390:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":534,"nodeType":"ExpressionStatement","src":"5390:31:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":535,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5431:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":537,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5431:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":538,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5431:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":539,"nodeType":"ExpressionStatement","src":"5431:18:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c33","id":543,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5470:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""},"value":"startstop_call3"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""}],"expression":{"id":540,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5459:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":542,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5459:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":544,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5459:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":545,"nodeType":"ExpressionStatement","src":"5459:29:0"},{"expression":{"arguments":[{"hexValue":"74657374696e67206e6573746564","id":549,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5511:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""},"value":"testing nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""}],"expression":{"id":546,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5499:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":548,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5499:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":550,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5499:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":551,"nodeType":"ExpressionStatement","src":"5499:29:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307831323334","id":559,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5572:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":558,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5564:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":557,"name":"uint160","nodeType":"ElementaryTypeName","src":"5564:7:0","typeDescriptions":{}}},"id":560,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5564:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":556,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5556:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":555,"name":"address","nodeType":"ElementaryTypeName","src":"5556:7:0","typeDescriptions":{}}},"id":561,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5556:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":552,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5538:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":554,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5538:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":562,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5538:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":563,"nodeType":"ExpressionStatement","src":"5538:43:0"},{"expression":{"arguments":[{"hexValue":"6e6573746564","id":567,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5604:8:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""},"value":"nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""}],"expression":{"id":564,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5591:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":566,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested1","nodeType":"MemberAccess","referencedDeclaration":758,"src":"5591:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":568,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5591:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":569,"nodeType":"ExpressionStatement","src":"5591:22:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":570,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5623:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":572,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5623:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":573,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5623:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":574,"nodeType":"ExpressionStatement","src":"5623:18:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206465706c6f796d656e74","id":578,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5664:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""},"value":"contract deployment"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""}],"expression":{"id":575,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5652:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":577,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5652:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":579,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5652:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":580,"nodeType":"ExpressionStatement","src":"5652:34:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078313233343536","id":588,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5725:8:0","typeDescriptions":{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"},"value":"0x123456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"}],"id":587,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5717:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":586,"name":"uint160","nodeType":"ElementaryTypeName","src":"5717:7:0","typeDescriptions":{}}},"id":589,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5717:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":585,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5709:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":584,"name":"address","nodeType":"ElementaryTypeName","src":"5709:7:0","typeDescriptions":{}}},"id":590,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5709:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":581,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5696:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":583,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5696:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":591,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5696:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":592,"nodeType":"ExpressionStatement","src":"5696:40:0"},{"assignments":[595],"declarations":[{"constant":false,"id":595,"mutability":"mutable","name":"x","nameLocation":"5753:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5746:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":594,"nodeType":"UserDefinedTypeName","pathNode":{"id":593,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5746:6:0"},"referencedDeclaration":799,"src":"5746:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":601,"initialValue":{"arguments":[{"hexValue":"31323334","id":599,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5768:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":598,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5757:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":597,"nodeType":"UserDefinedTypeName","pathNode":{"id":596,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5761:6:0"},"referencedDeclaration":799,"src":"5761:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":600,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5757:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5746:27:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":607,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":603,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":595,"src":"5791:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":604,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"5791:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":605,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5791:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":606,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5802:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"5791:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e20637265617465206973206e6f742031323334","id":608,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5808:35:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""},"value":"FooBar: foo in create is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""}],"id":602,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"5783:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":609,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5783:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":610,"nodeType":"ExpressionStatement","src":"5783:61:0"},{"expression":{"arguments":[{"hexValue":"6372656174652032","id":614,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5867:10:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""},"value":"create 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""}],"expression":{"id":611,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5855:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":613,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5855:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":615,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5855:23:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":616,"nodeType":"ExpressionStatement","src":"5855:23:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307863616665","id":624,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5917:6:0","typeDescriptions":{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"},"value":"0xcafe"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"}],"id":623,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5909:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":622,"name":"uint160","nodeType":"ElementaryTypeName","src":"5909:7:0","typeDescriptions":{}}},"id":625,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5909:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":621,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5901:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":620,"name":"address","nodeType":"ElementaryTypeName","src":"5901:7:0","typeDescriptions":{}}},"id":626,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5901:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":617,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5888:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":619,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5888:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":627,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5888:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":628,"nodeType":"ExpressionStatement","src":"5888:38:0"},{"assignments":[631],"declarations":[{"constant":false,"id":631,"mutability":"mutable","name":"y","nameLocation":"5943:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5936:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":630,"nodeType":"UserDefinedTypeName","pathNode":{"id":629,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5936:6:0"},"referencedDeclaration":799,"src":"5936:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":645,"initialValue":{"arguments":[{"hexValue":"31323334","id":643,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5986:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":634,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5947:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":633,"nodeType":"UserDefinedTypeName","pathNode":{"id":632,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5951:6:0"},"referencedDeclaration":799,"src":"5951:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":642,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"names":["salt"],"nodeType":"FunctionCallOptions","options":[{"arguments":[{"arguments":[{"hexValue":"3432","id":639,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5980:2:0","typeDescriptions":{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"},"value":"42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"}],"id":638,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5972:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":637,"name":"uint256","nodeType":"ElementaryTypeName","src":"5972:7:0","typeDescriptions":{}}},"id":640,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5972:11:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":636,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5964:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":635,"name":"bytes32","nodeType":"ElementaryTypeName","src":"5964:7:0","typeDescriptions":{}}},"id":641,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5964:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"src":"5947:38:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$salt","typeString":"function (uint256) returns (contract FooBar)"}},"id":644,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5947:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5936:55:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":651,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":647,"name":"y","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":631,"src":"6009:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":648,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"6009:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":649,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6009:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":650,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6020:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"6009:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e2063726561746532206973206e6f742031323334","id":652,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6026:36:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""},"value":"FooBar: foo in create2 is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""}],"id":646,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"6001:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":653,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6001:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":654,"nodeType":"ExpressionStatement","src":"6001:62:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":658,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6085:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":655,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6073:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":657,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6073:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":659,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6073:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":660,"nodeType":"ExpressionStatement","src":"6073:20:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":661,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6177:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":663,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"6177:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":664,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6177:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":665,"nodeType":"ExpressionStatement","src":"6177:14:0"},{"expression":{"arguments":[{"hexValue":"31323334","id":669,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6212:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":668,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"6201:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":667,"nodeType":"UserDefinedTypeName","pathNode":{"id":666,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"6205:6:0"},"referencedDeclaration":799,"src":"6205:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":670,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6201:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":671,"nodeType":"ExpressionStatement","src":"6201:16:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e636520656e64","id":675,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6240:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},"value":"nonce end"},{"arguments":[{"arguments":[{"arguments":[{"id":682,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6281:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":681,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6273:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":680,"name":"address","nodeType":"ElementaryTypeName","src":"6273:7:0","typeDescriptions":{}}},"id":683,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6273:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":678,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6261:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":679,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"6261:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":684,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6261:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":677,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6253:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":676,"name":"uint256","nodeType":"ElementaryTypeName","src":"6253:7:0","typeDescriptions":{}}},"id":685,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6253:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":672,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6228:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":674,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"6228:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":686,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6228:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":687,"nodeType":"ExpressionStatement","src":"6228:61:0"}]},"documentation":{"id":457,"nodeType":"StructuredDocumentation","src":"4902:56:0","text":"@notice example function, to test vm.broadcast with."},"functionSelector":"bef03abc","implemented":true,"kind":"function","modifiers":[],"name":"runBroadcast","nameLocation":"4972:12:0","parameters":{"id":458,"nodeType":"ParameterList","parameters":[],"src":"4984:2:0"},"returnParameters":{"id":459,"nodeType":"ParameterList","parameters":[],"src":"4994:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":713,"nodeType":"FunctionDefinition","src":"6391:143:0","nodes":[],"body":{"id":712,"nodeType":"Block","src":"6440:94:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":698,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":692,"src":"6462:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":695,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6450:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":697,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6450:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":699,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6450:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":700,"nodeType":"ExpressionStatement","src":"6450:15:0"},{"expression":{"arguments":[{"hexValue":"68656c6c6f206d73672e73656e646572","id":704,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6487:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},"value":"hello msg.sender"},{"arguments":[{"expression":{"id":707,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"6515:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":708,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"6515:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":706,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6507:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":705,"name":"address","nodeType":"ElementaryTypeName","src":"6507:7:0","typeDescriptions":{}}},"id":709,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6507:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":701,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6475:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":703,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"6475:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":710,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6475:52:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":711,"nodeType":"ExpressionStatement","src":"6475:52:0"}]},"documentation":{"id":690,"nodeType":"StructuredDocumentation","src":"6302:84:0","text":"@notice example external function, to force a CALL, and test vm.startPrank with."},"functionSelector":"a777d0dc","implemented":true,"kind":"function","modifiers":[],"name":"hello","nameLocation":"6400:5:0","parameters":{"id":693,"nodeType":"ParameterList","parameters":[{"constant":false,"id":692,"mutability":"mutable","name":"_v","nameLocation":"6422:2:0","nodeType":"VariableDeclaration","scope":713,"src":"6406:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":691,"name":"string","nodeType":"ElementaryTypeName","src":"6406:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6405:20:0"},"returnParameters":{"id":694,"nodeType":"ParameterList","parameters":[],"src":"6440:0:0"},"scope":786,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":728,"nodeType":"FunctionDefinition","src":"6540:95:0","nodes":[],"body":{"id":727,"nodeType":"Block","src":"6584:51:0","nodes":[],"statements":[{"expression":{"id":719,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6594:9:0","subExpression":{"id":718,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6594:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":720,"nodeType":"ExpressionStatement","src":"6594:9:0"},{"expression":{"arguments":[{"id":724,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":715,"src":"6625:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":721,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6613:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":723,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6613:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":725,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6613:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":726,"nodeType":"ExpressionStatement","src":"6613:15:0"}]},"functionSelector":"7e79255d","implemented":true,"kind":"function","modifiers":[],"name":"call1","nameLocation":"6549:5:0","parameters":{"id":716,"nodeType":"ParameterList","parameters":[{"constant":false,"id":715,"mutability":"mutable","name":"_v","nameLocation":"6571:2:0","nodeType":"VariableDeclaration","scope":728,"src":"6555:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":714,"name":"string","nodeType":"ElementaryTypeName","src":"6555:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6554:20:0"},"returnParameters":{"id":717,"nodeType":"ParameterList","parameters":[],"src":"6584:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":743,"nodeType":"FunctionDefinition","src":"6641:95:0","nodes":[],"body":{"id":742,"nodeType":"Block","src":"6685:51:0","nodes":[],"statements":[{"expression":{"id":734,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6695:9:0","subExpression":{"id":733,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6695:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":735,"nodeType":"ExpressionStatement","src":"6695:9:0"},{"expression":{"arguments":[{"id":739,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":730,"src":"6726:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":736,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6714:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":738,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6714:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":740,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6714:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":741,"nodeType":"ExpressionStatement","src":"6714:15:0"}]},"functionSelector":"8d3ef7ca","implemented":true,"kind":"function","modifiers":[],"name":"call2","nameLocation":"6650:5:0","parameters":{"id":731,"nodeType":"ParameterList","parameters":[{"constant":false,"id":730,"mutability":"mutable","name":"_v","nameLocation":"6672:2:0","nodeType":"VariableDeclaration","scope":743,"src":"6656:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":729,"name":"string","nodeType":"ElementaryTypeName","src":"6656:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6655:20:0"},"returnParameters":{"id":732,"nodeType":"ParameterList","parameters":[],"src":"6685:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":758,"nodeType":"FunctionDefinition","src":"6742:98:0","nodes":[],"body":{"id":757,"nodeType":"Block","src":"6788:52:0","nodes":[],"statements":[{"expression":{"id":749,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6798:9:0","subExpression":{"id":748,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6798:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":750,"nodeType":"ExpressionStatement","src":"6798:9:0"},{"expression":{"arguments":[{"id":754,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":745,"src":"6830:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":751,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6817:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":753,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested2","nodeType":"MemberAccess","referencedDeclaration":773,"src":"6817:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":755,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6817:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":756,"nodeType":"ExpressionStatement","src":"6817:16:0"}]},"functionSelector":"a76ccdfa","implemented":true,"kind":"function","modifiers":[],"name":"nested1","nameLocation":"6751:7:0","parameters":{"id":746,"nodeType":"ParameterList","parameters":[{"constant":false,"id":745,"mutability":"mutable","name":"_v","nameLocation":"6775:2:0","nodeType":"VariableDeclaration","scope":758,"src":"6759:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":744,"name":"string","nodeType":"ElementaryTypeName","src":"6759:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6758:20:0"},"returnParameters":{"id":747,"nodeType":"ParameterList","parameters":[],"src":"6788:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":773,"nodeType":"FunctionDefinition","src":"6846:97:0","nodes":[],"body":{"id":772,"nodeType":"Block","src":"6892:51:0","nodes":[],"statements":[{"expression":{"id":764,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6902:9:0","subExpression":{"id":763,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6902:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":765,"nodeType":"ExpressionStatement","src":"6902:9:0"},{"expression":{"arguments":[{"id":769,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":760,"src":"6933:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":766,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6921:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":768,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6921:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":770,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6921:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":771,"nodeType":"ExpressionStatement","src":"6921:15:0"}]},"functionSelector":"dbf1282f","implemented":true,"kind":"function","modifiers":[],"name":"nested2","nameLocation":"6855:7:0","parameters":{"id":761,"nodeType":"ParameterList","parameters":[{"constant":false,"id":760,"mutability":"mutable","name":"_v","nameLocation":"6879:2:0","nodeType":"VariableDeclaration","scope":773,"src":"6863:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":759,"name":"string","nodeType":"ElementaryTypeName","src":"6863:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6862:20:0"},"returnParameters":{"id":762,"nodeType":"ParameterList","parameters":[],"src":"6892:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":785,"nodeType":"FunctionDefinition","src":"6949:84:0","nodes":[],"body":{"id":784,"nodeType":"Block","src":"7001:32:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":781,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":775,"src":"7023:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":778,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"7011:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":780,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"7011:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":782,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7011:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":783,"nodeType":"ExpressionStatement","src":"7011:15:0"}]},"functionSelector":"7f8b915c","implemented":true,"kind":"function","modifiers":[],"name":"callPure","nameLocation":"6958:8:0","parameters":{"id":776,"nodeType":"ParameterList","parameters":[{"constant":false,"id":775,"mutability":"mutable","name":"_v","nameLocation":"6983:2:0","nodeType":"VariableDeclaration","scope":785,"src":"6967:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":774,"name":"string","nodeType":"ElementaryTypeName","src":"6967:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6966:20:0"},"returnParameters":{"id":777,"nodeType":"ParameterList","parameters":[],"src":"7001:0:0"},"scope":786,"stateMutability":"pure","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ScriptExample","contractDependencies":[799],"contractKind":"contract","documentation":{"id":221,"nodeType":"StructuredDocumentation","src":"2997:126:0","text":"@title ScriptExample\n @notice ScriptExample is an example script. The Go forge script code tests that it can run this."},"fullyImplemented":true,"linearizedBaseContracts":[786],"name":"ScriptExample","nameLocation":"3132:13:0","scope":969,"usedErrors":[]},{"id":799,"nodeType":"ContractDefinition","src":"7037:96:0","nodes":[{"id":788,"nodeType":"VariableDeclaration","src":"7059:18:0","nodes":[],"constant":false,"functionSelector":"c2985578","mutability":"mutable","name":"foo","nameLocation":"7074:3:0","scope":799,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":787,"name":"uint256","nodeType":"ElementaryTypeName","src":"7059:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":798,"nodeType":"FunctionDefinition","src":"7084:47:0","nodes":[],"body":{"id":797,"nodeType":"Block","src":"7107:24:0","nodes":[],"statements":[{"expression":{"id":795,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":793,"name":"foo","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":788,"src":"7117:3:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":794,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":790,"src":"7123:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"7117:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":796,"nodeType":"ExpressionStatement","src":"7117:7:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":791,"nodeType":"ParameterList","parameters":[{"constant":false,"id":790,"mutability":"mutable","name":"v","nameLocation":"7104:1:0","nodeType":"VariableDeclaration","scope":798,"src":"7096:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":789,"name":"uint256","nodeType":"ElementaryTypeName","src":"7096:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7095:11:0"},"returnParameters":{"id":792,"nodeType":"ParameterList","parameters":[],"src":"7107:0:0"},"scope":799,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"FooBar","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[799],"name":"FooBar","nameLocation":"7046:6:0","scope":969,"usedErrors":[]},{"id":833,"nodeType":"ContractDefinition","src":"7135:281:0","nodes":[{"id":813,"nodeType":"VariableDeclaration","src":"7162:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7188:10:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":800,"name":"address","nodeType":"ElementaryTypeName","src":"7162:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":808,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7235:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":807,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7225:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":809,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7225:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":806,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7217:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":805,"name":"uint256","nodeType":"ElementaryTypeName","src":"7217:7:0","typeDescriptions":{}}},"id":810,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7217:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":804,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7209:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":803,"name":"uint160","nodeType":"ElementaryTypeName","src":"7209:7:0","typeDescriptions":{}}},"id":811,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7209:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":802,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":801,"name":"address","nodeType":"ElementaryTypeName","src":"7201:7:0","typeDescriptions":{}}},"id":812,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7201:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":819,"nodeType":"VariableDeclaration","src":"7262:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7283:2:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":815,"nodeType":"UserDefinedTypeName","pathNode":{"id":814,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7262:2:0"},"referencedDeclaration":83,"src":"7262:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":817,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":813,"src":"7291:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":816,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7288:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":818,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7288:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":832,"nodeType":"FunctionDefinition","src":"7309:105:0","nodes":[],"body":{"id":831,"nodeType":"Block","src":"7372:42:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":828,"name":"_addr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":821,"src":"7401:5:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":826,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":819,"src":"7389:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":827,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7389:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":829,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7389:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"functionReturnParameters":825,"id":830,"nodeType":"Return","src":"7382:25:0"}]},"functionSelector":"2d0335ab","implemented":true,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"7318:8:0","parameters":{"id":822,"nodeType":"ParameterList","parameters":[{"constant":false,"id":821,"mutability":"mutable","name":"_addr","nameLocation":"7335:5:0","nodeType":"VariableDeclaration","scope":832,"src":"7327:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":820,"name":"address","nodeType":"ElementaryTypeName","src":"7327:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"7326:15:0"},"returnParameters":{"id":825,"nodeType":"ParameterList","parameters":[{"constant":false,"id":824,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":832,"src":"7363:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":823,"name":"uint256","nodeType":"ElementaryTypeName","src":"7363:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7362:9:0"},"scope":833,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"NonceGetter","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[833],"name":"NonceGetter","nameLocation":"7144:11:0","scope":969,"usedErrors":[]},{"id":852,"nodeType":"ContractDefinition","src":"7418:174:0","nodes":[{"id":835,"nodeType":"VariableDeclaration","src":"7448:18:0","nodes":[],"constant":false,"mutability":"mutable","name":"v","nameLocation":"7465:1:0","scope":852,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":834,"name":"uint256","nodeType":"ElementaryTypeName","src":"7448:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"id":843,"nodeType":"FunctionDefinition","src":"7473:36:0","nodes":[],"body":{"id":842,"nodeType":"Block","src":"7487:22:0","nodes":[],"statements":[{"expression":{"id":840,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":838,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7497:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"hexValue":"31","id":839,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7501:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"7497:5:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":841,"nodeType":"ExpressionStatement","src":"7497:5:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":836,"nodeType":"ParameterList","parameters":[],"src":"7484:2:0"},"returnParameters":{"id":837,"nodeType":"ParameterList","parameters":[],"src":"7487:0:0"},"scope":852,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":851,"nodeType":"FunctionDefinition","src":"7515:75:0","nodes":[],"body":{"id":850,"nodeType":"Block","src":"7565:25:0","nodes":[],"statements":[{"expression":{"id":848,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7582:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"functionReturnParameters":847,"id":849,"nodeType":"Return","src":"7575:8:0"}]},"functionSelector":"20965255","implemented":true,"kind":"function","modifiers":[],"name":"getValue","nameLocation":"7524:8:0","parameters":{"id":844,"nodeType":"ParameterList","parameters":[],"src":"7532:2:0"},"returnParameters":{"id":847,"nodeType":"ParameterList","parameters":[{"constant":false,"id":846,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":851,"src":"7556:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":845,"name":"uint256","nodeType":"ElementaryTypeName","src":"7556:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7555:9:0"},"scope":852,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkedContract","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[852],"name":"ForkedContract","nameLocation":"7427:14:0","scope":969,"usedErrors":[]},{"id":968,"nodeType":"ContractDefinition","src":"7594:813:0","nodes":[{"id":866,"nodeType":"VariableDeclaration","src":"7620:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7646:10:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":853,"name":"address","nodeType":"ElementaryTypeName","src":"7620:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":861,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7693:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":860,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7683:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":862,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7683:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":859,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7675:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":858,"name":"uint256","nodeType":"ElementaryTypeName","src":"7675:7:0","typeDescriptions":{}}},"id":863,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7675:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":857,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7667:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":856,"name":"uint160","nodeType":"ElementaryTypeName","src":"7667:7:0","typeDescriptions":{}}},"id":864,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7667:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":855,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7659:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":854,"name":"address","nodeType":"ElementaryTypeName","src":"7659:7:0","typeDescriptions":{}}},"id":865,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7659:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":872,"nodeType":"VariableDeclaration","src":"7720:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7741:2:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":868,"nodeType":"UserDefinedTypeName","pathNode":{"id":867,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7720:2:0"},"referencedDeclaration":83,"src":"7720:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":870,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":866,"src":"7749:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":869,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7746:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":871,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7746:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":967,"nodeType":"FunctionDefinition","src":"7767:638:0","nodes":[],"body":{"id":966,"nodeType":"Block","src":"7791:614:0","nodes":[],"statements":[{"assignments":[876],"declarations":[{"constant":false,"id":876,"mutability":"mutable","name":"testAddr","nameLocation":"7809:8:0","nodeType":"VariableDeclaration","scope":966,"src":"7801:16:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":875,"name":"address","nodeType":"ElementaryTypeName","src":"7801:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":884,"initialValue":{"arguments":[{"arguments":[{"hexValue":"307831323334","id":881,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7836:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":880,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7828:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":879,"name":"uint160","nodeType":"ElementaryTypeName","src":"7828:7:0","typeDescriptions":{}}},"id":882,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7828:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":878,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7820:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":877,"name":"address","nodeType":"ElementaryTypeName","src":"7820:7:0","typeDescriptions":{}}},"id":883,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7820:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"7801:43:0"},{"assignments":[887],"declarations":[{"constant":false,"id":887,"mutability":"mutable","name":"fc","nameLocation":"7869:2:0","nodeType":"VariableDeclaration","scope":966,"src":"7854:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"},"typeName":{"id":886,"nodeType":"UserDefinedTypeName","pathNode":{"id":885,"name":"ForkedContract","nodeType":"IdentifierPath","referencedDeclaration":852,"src":"7854:14:0"},"referencedDeclaration":852,"src":"7854:14:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"visibility":"internal"}],"id":891,"initialValue":{"arguments":[{"id":889,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7889:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":888,"name":"ForkedContract","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":852,"src":"7874:14:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_ForkedContract_$852_$","typeString":"type(contract ForkedContract)"}},"id":890,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7874:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"nodeType":"VariableDeclarationStatement","src":"7854:44:0"},{"expression":{"arguments":[{"hexValue":"666f726b31","id":895,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7929:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},"value":"fork1"},{"hexValue":"3132333435","id":896,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7938:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"}],"expression":{"id":892,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7909:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":894,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"7909:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":897,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7909:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":898,"nodeType":"ExpressionStatement","src":"7909:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":905,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":902,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7974:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":900,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7962:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":901,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7962:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":903,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7962:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3132333435","id":904,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7987:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"},"src":"7962:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":906,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7994:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":899,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"7954:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":907,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7954:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":908,"nodeType":"ExpressionStatement","src":"7954:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":914,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":910,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8036:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":911,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8036:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":912,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8036:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31","id":913,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8053:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"8036:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652031","id":915,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8056:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""},"value":"value should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""}],"id":909,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8028:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":916,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8028:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":917,"nodeType":"ExpressionStatement","src":"8028:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":925,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":919,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8094:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":920,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8094:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"31","id":923,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8122:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"}],"id":922,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8114:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":921,"name":"uint256","nodeType":"ElementaryTypeName","src":"8114:7:0","typeDescriptions":{}}},"id":924,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8114:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8094:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652031","id":926,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8126:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""},"value":"balance should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""}],"id":918,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8086:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":927,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8086:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":928,"nodeType":"ExpressionStatement","src":"8086:62:0"},{"expression":{"arguments":[{"hexValue":"666f726b32","id":932,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8179:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},"value":"fork2"},{"hexValue":"3233343536","id":933,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8188:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"}],"expression":{"id":929,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8159:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":931,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"8159:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":934,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8159:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":935,"nodeType":"ExpressionStatement","src":"8159:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":942,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":939,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8224:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":937,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8212:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":938,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"8212:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":940,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8212:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3233343536","id":941,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8237:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"},"src":"8212:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":943,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8244:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":936,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8204:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":944,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8204:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":945,"nodeType":"ExpressionStatement","src":"8204:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":951,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":947,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8286:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":948,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8286:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":949,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8286:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"32","id":950,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8303:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"},"src":"8286:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652032","id":952,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8306:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""},"value":"value should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""}],"id":946,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8278:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":953,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8278:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":954,"nodeType":"ExpressionStatement","src":"8278:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":962,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":956,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8344:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":957,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8344:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"32","id":960,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8372:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"}],"id":959,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8364:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":958,"name":"uint256","nodeType":"ElementaryTypeName","src":"8364:7:0","typeDescriptions":{}}},"id":961,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8364:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8344:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652032","id":963,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8376:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""},"value":"balance should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""}],"id":955,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8336:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":964,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8336:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":965,"nodeType":"ExpressionStatement","src":"8336:62:0"}]},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"7776:3:0","parameters":{"id":873,"nodeType":"ParameterList","parameters":[],"src":"7779:2:0"},"returnParameters":{"id":874,"nodeType":"ParameterList","parameters":[],"src":"7791:0:0"},"scope":968,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkTester","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[968],"name":"ForkTester","nameLocation":"7603:10:0","scope":969,"usedErrors":[]}],"license":"MIT"},"id":0} \ No newline at end of file diff --git a/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/console.json b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/console.json index 390e798a47011..6ef800dd39d51 100644 --- a/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/console.json +++ b/op-chain-ops/script/testdata/test-artifacts/ScriptExample.s.sol/console.json @@ -1 +1 @@ -{"abi":[],"bytecode":{"object":"0x602d6037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c634300080f000a","sourceMap":"791:1622:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;791:1622:0;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c634300080f000a","sourceMap":"791:1622:0:-:0;;;;;;;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"scripts/ScriptExample.s.sol\":\"console\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"scripts/ScriptExample.s.sol\":{\"keccak256\":\"0x8d1dfa41908e7ccc3a498a2a2aa51c5275bedbb904ce32d08f8598e36f896d8d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://5117bb7158363cae8b9dc0508d2852692fd36172f1c699ff680afbb5acebe1f3\",\"dweb:/ipfs/QmQdahJ8SPKfJ4yea5Ge9qaj5qh1TxVffhHvaWytBaL95h\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"scripts/ScriptExample.s.sol":"console"},"evmVersion":"london","libraries":{}},"sources":{"scripts/ScriptExample.s.sol":{"keccak256":"0x8d1dfa41908e7ccc3a498a2a2aa51c5275bedbb904ce32d08f8598e36f896d8d","urls":["bzz-raw://5117bb7158363cae8b9dc0508d2852692fd36172f1c699ff680afbb5acebe1f3","dweb:/ipfs/QmQdahJ8SPKfJ4yea5Ge9qaj5qh1TxVffhHvaWytBaL95h"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[],"types":{}},"userdoc":{"version":1,"kind":"user"},"devdoc":{"version":1,"kind":"dev"},"ast":{"absolutePath":"scripts/ScriptExample.s.sol","id":720,"exportedSymbols":{"FooBar":[719],"ScriptExample":[706],"Vm":[55],"console":[192]},"nodeType":"SourceUnit","src":"32:5967:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","0.8",".15"]},{"id":55,"nodeType":"ContractDefinition","src":"120:616:0","nodes":[{"id":10,"nodeType":"FunctionDefinition","src":"139:91:0","nodes":[],"functionSelector":"4777f3cf","implemented":false,"kind":"function","modifiers":[],"name":"envOr","nameLocation":"148:5:0","parameters":{"id":6,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"mutability":"mutable","name":"name","nameLocation":"170:4:0","nodeType":"VariableDeclaration","scope":10,"src":"154:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":2,"name":"string","nodeType":"ElementaryTypeName","src":"154:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":5,"mutability":"mutable","name":"defaultValue","nameLocation":"181:12:0","nodeType":"VariableDeclaration","scope":10,"src":"176:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":4,"name":"bool","nodeType":"ElementaryTypeName","src":"176:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"153:41:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[{"constant":false,"id":8,"mutability":"mutable","name":"value","nameLocation":"223:5:0","nodeType":"VariableDeclaration","scope":10,"src":"218:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":7,"name":"bool","nodeType":"ElementaryTypeName","src":"218:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"217:12:0"},"scope":55,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":17,"nodeType":"FunctionDefinition","src":"235:72:0","nodes":[],"functionSelector":"2d0335ab","implemented":false,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"244:8:0","parameters":{"id":13,"nodeType":"ParameterList","parameters":[{"constant":false,"id":12,"mutability":"mutable","name":"account","nameLocation":"261:7:0","nodeType":"VariableDeclaration","scope":17,"src":"253:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":11,"name":"address","nodeType":"ElementaryTypeName","src":"253:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"252:17:0"},"returnParameters":{"id":16,"nodeType":"ParameterList","parameters":[{"constant":false,"id":15,"mutability":"mutable","name":"nonce","nameLocation":"300:5:0","nodeType":"VariableDeclaration","scope":17,"src":"293:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"},"typeName":{"id":14,"name":"uint64","nodeType":"ElementaryTypeName","src":"293:6:0","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"visibility":"internal"}],"src":"292:14:0"},"scope":55,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":27,"nodeType":"FunctionDefinition","src":"312:111:0","nodes":[],"functionSelector":"213e4198","implemented":false,"kind":"function","modifiers":[],"name":"parseJsonKeys","nameLocation":"321:13:0","parameters":{"id":22,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19,"mutability":"mutable","name":"json","nameLocation":"351:4:0","nodeType":"VariableDeclaration","scope":27,"src":"335:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":18,"name":"string","nodeType":"ElementaryTypeName","src":"335:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":21,"mutability":"mutable","name":"key","nameLocation":"373:3:0","nodeType":"VariableDeclaration","scope":27,"src":"357:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":20,"name":"string","nodeType":"ElementaryTypeName","src":"357:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"334:43:0"},"returnParameters":{"id":26,"nodeType":"ParameterList","parameters":[{"constant":false,"id":25,"mutability":"mutable","name":"keys","nameLocation":"417:4:0","nodeType":"VariableDeclaration","scope":27,"src":"401:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":23,"name":"string","nodeType":"ElementaryTypeName","src":"401:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":24,"nodeType":"ArrayTypeName","src":"401:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"src":"400:22:0"},"scope":55,"stateMutability":"pure","virtual":false,"visibility":"external"},{"id":32,"nodeType":"FunctionDefinition","src":"428:48:0","nodes":[],"functionSelector":"06447d56","implemented":false,"kind":"function","modifiers":[],"name":"startPrank","nameLocation":"437:10:0","parameters":{"id":30,"nodeType":"ParameterList","parameters":[{"constant":false,"id":29,"mutability":"mutable","name":"msgSender","nameLocation":"456:9:0","nodeType":"VariableDeclaration","scope":32,"src":"448:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":28,"name":"address","nodeType":"ElementaryTypeName","src":"448:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"447:19:0"},"returnParameters":{"id":31,"nodeType":"ParameterList","parameters":[],"src":"475:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":35,"nodeType":"FunctionDefinition","src":"481:30:0","nodes":[],"functionSelector":"90c5013b","implemented":false,"kind":"function","modifiers":[],"name":"stopPrank","nameLocation":"490:9:0","parameters":{"id":33,"nodeType":"ParameterList","parameters":[],"src":"499:2:0"},"returnParameters":{"id":34,"nodeType":"ParameterList","parameters":[],"src":"510:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":38,"nodeType":"FunctionDefinition","src":"516:30:0","nodes":[],"functionSelector":"afc98040","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"525:9:0","parameters":{"id":36,"nodeType":"ParameterList","parameters":[],"src":"534:2:0"},"returnParameters":{"id":37,"nodeType":"ParameterList","parameters":[],"src":"545:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":43,"nodeType":"FunctionDefinition","src":"551:47:0","nodes":[],"functionSelector":"e6962cdb","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"560:9:0","parameters":{"id":41,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40,"mutability":"mutable","name":"msgSender","nameLocation":"578:9:0","nodeType":"VariableDeclaration","scope":43,"src":"570:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39,"name":"address","nodeType":"ElementaryTypeName","src":"570:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"569:19:0"},"returnParameters":{"id":42,"nodeType":"ParameterList","parameters":[],"src":"597:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":48,"nodeType":"FunctionDefinition","src":"603:52:0","nodes":[],"functionSelector":"7fec2a8d","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"612:14:0","parameters":{"id":46,"nodeType":"ParameterList","parameters":[{"constant":false,"id":45,"mutability":"mutable","name":"msgSender","nameLocation":"635:9:0","nodeType":"VariableDeclaration","scope":48,"src":"627:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":44,"name":"address","nodeType":"ElementaryTypeName","src":"627:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"626:19:0"},"returnParameters":{"id":47,"nodeType":"ParameterList","parameters":[],"src":"654:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":51,"nodeType":"FunctionDefinition","src":"660:35:0","nodes":[],"functionSelector":"7fb5297f","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"669:14:0","parameters":{"id":49,"nodeType":"ParameterList","parameters":[],"src":"683:2:0"},"returnParameters":{"id":50,"nodeType":"ParameterList","parameters":[],"src":"694:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":54,"nodeType":"FunctionDefinition","src":"700:34:0","nodes":[],"functionSelector":"76eadd36","implemented":false,"kind":"function","modifiers":[],"name":"stopBroadcast","nameLocation":"709:13:0","parameters":{"id":52,"nodeType":"ParameterList","parameters":[],"src":"722:2:0"},"returnParameters":{"id":53,"nodeType":"ParameterList","parameters":[],"src":"733:0:0"},"scope":55,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"Vm","contractDependencies":[],"contractKind":"interface","fullyImplemented":false,"linearizedBaseContracts":[55],"name":"Vm","nameLocation":"130:2:0","scope":720,"usedErrors":[]},{"id":192,"nodeType":"ContractDefinition","src":"791:1622:0","nodes":[{"id":61,"nodeType":"VariableDeclaration","src":"813:86:0","nodes":[],"constant":true,"mutability":"constant","name":"CONSOLE_ADDRESS","nameLocation":"830:15:0","scope":192,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":56,"name":"address","nodeType":"ElementaryTypeName","src":"813:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"hexValue":"307830303030303030303030303030303030303036333646366537333646366336353265366336663637","id":59,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"856:42:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"value":"0x000000000000000000636F6e736F6c652e6c6f67"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":58,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"848:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":57,"name":"address","nodeType":"ElementaryTypeName","src":"848:7:0","typeDescriptions":{}}},"id":60,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"848:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":78,"nodeType":"FunctionDefinition","src":"906:221:0","nodes":[],"body":{"id":77,"nodeType":"Block","src":"1065:62:0","nodes":[],"statements":[{"AST":{"nodeType":"YulBlock","src":"1084:37:0","statements":[{"nodeType":"YulAssignment","src":"1098:13:0","value":{"name":"fnIn","nodeType":"YulIdentifier","src":"1107:4:0"},"variableNames":[{"name":"fnOut","nodeType":"YulIdentifier","src":"1098:5:0"}]}]},"evmVersion":"london","externalReferences":[{"declaration":67,"isOffset":false,"isSlot":false,"src":"1107:4:0","valueSize":1},{"declaration":74,"isOffset":false,"isSlot":false,"src":"1098:5:0","valueSize":1}],"id":76,"nodeType":"InlineAssembly","src":"1075:46:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_castLogPayloadViewToPure","nameLocation":"915:25:0","parameters":{"id":68,"nodeType":"ParameterList","parameters":[{"constant":false,"id":67,"mutability":"mutable","name":"fnIn","nameLocation":"987:4:0","nodeType":"VariableDeclaration","scope":78,"src":"950:41:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"typeName":{"id":66,"nodeType":"FunctionTypeName","parameterTypes":{"id":64,"nodeType":"ParameterList","parameters":[{"constant":false,"id":63,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":66,"src":"959:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":62,"name":"bytes","nodeType":"ElementaryTypeName","src":"959:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"958:14:0"},"returnParameterTypes":{"id":65,"nodeType":"ParameterList","parameters":[],"src":"987:0:0"},"src":"950:41:0","stateMutability":"view","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"visibility":"internal"},"visibility":"internal"}],"src":"940:57:0"},"returnParameters":{"id":75,"nodeType":"ParameterList","parameters":[{"constant":false,"id":74,"mutability":"mutable","name":"fnOut","nameLocation":"1058:5:0","nodeType":"VariableDeclaration","scope":78,"src":"1021:42:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"typeName":{"id":73,"nodeType":"FunctionTypeName","parameterTypes":{"id":71,"nodeType":"ParameterList","parameters":[{"constant":false,"id":70,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":73,"src":"1030:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":69,"name":"bytes","nodeType":"ElementaryTypeName","src":"1030:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1029:14:0"},"returnParameterTypes":{"id":72,"nodeType":"ParameterList","parameters":[],"src":"1058:0:0"},"src":"1021:42:0","stateMutability":"pure","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"visibility":"internal"},"visibility":"internal"}],"src":"1020:44:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":90,"nodeType":"FunctionDefinition","src":"1133:133:0","nodes":[],"body":{"id":89,"nodeType":"Block","src":"1194:72:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":86,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":80,"src":"1251:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"arguments":[{"id":84,"name":"_sendLogPayloadView","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":106,"src":"1230:19:0","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}],"id":83,"name":"_castLogPayloadViewToPure","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":78,"src":"1204:25:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_function_internal_view$_t_bytes_memory_ptr_$returns$__$_$returns$_t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$_$","typeString":"function (function (bytes memory) view) pure returns (function (bytes memory) pure)"}},"id":85,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1204:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":87,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1204:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":88,"nodeType":"ExpressionStatement","src":"1204:55:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayload","nameLocation":"1142:15:0","parameters":{"id":81,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"payload","nameLocation":"1171:7:0","nodeType":"VariableDeclaration","scope":90,"src":"1158:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":79,"name":"bytes","nodeType":"ElementaryTypeName","src":"1158:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1157:22:0"},"returnParameters":{"id":82,"nodeType":"ParameterList","parameters":[],"src":"1194:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":106,"nodeType":"FunctionDefinition","src":"1272:380:0","nodes":[],"body":{"id":105,"nodeType":"Block","src":"1336:316:0","nodes":[],"statements":[{"assignments":[96],"declarations":[{"constant":false,"id":96,"mutability":"mutable","name":"payloadLength","nameLocation":"1354:13:0","nodeType":"VariableDeclaration","scope":105,"src":"1346:21:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":95,"name":"uint256","nodeType":"ElementaryTypeName","src":"1346:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":99,"initialValue":{"expression":{"id":97,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":92,"src":"1370:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":98,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1370:14:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1346:38:0"},{"assignments":[101],"declarations":[{"constant":false,"id":101,"mutability":"mutable","name":"consoleAddress","nameLocation":"1402:14:0","nodeType":"VariableDeclaration","scope":105,"src":"1394:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":100,"name":"address","nodeType":"ElementaryTypeName","src":"1394:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":103,"initialValue":{"id":102,"name":"CONSOLE_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":61,"src":"1419:15:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"1394:40:0"},{"AST":{"nodeType":"YulBlock","src":"1496:150:0","statements":[{"nodeType":"YulVariableDeclaration","src":"1510:36:0","value":{"arguments":[{"name":"payload","nodeType":"YulIdentifier","src":"1534:7:0"},{"kind":"number","nodeType":"YulLiteral","src":"1543:2:0","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1530:3:0"},"nodeType":"YulFunctionCall","src":"1530:16:0"},"variables":[{"name":"payloadStart","nodeType":"YulTypedName","src":"1514:12:0","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1559:77:0","value":{"arguments":[{"arguments":[],"functionName":{"name":"gas","nodeType":"YulIdentifier","src":"1579:3:0"},"nodeType":"YulFunctionCall","src":"1579:5:0"},{"name":"consoleAddress","nodeType":"YulIdentifier","src":"1586:14:0"},{"name":"payloadStart","nodeType":"YulIdentifier","src":"1602:12:0"},{"name":"payloadLength","nodeType":"YulIdentifier","src":"1616:13:0"},{"kind":"number","nodeType":"YulLiteral","src":"1631:1:0","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1634:1:0","type":"","value":"0"}],"functionName":{"name":"staticcall","nodeType":"YulIdentifier","src":"1568:10:0"},"nodeType":"YulFunctionCall","src":"1568:68:0"},"variables":[{"name":"r","nodeType":"YulTypedName","src":"1563:1:0","type":""}]}]},"documentation":"@solidity memory-safe-assembly","evmVersion":"london","externalReferences":[{"declaration":101,"isOffset":false,"isSlot":false,"src":"1586:14:0","valueSize":1},{"declaration":92,"isOffset":false,"isSlot":false,"src":"1534:7:0","valueSize":1},{"declaration":96,"isOffset":false,"isSlot":false,"src":"1616:13:0","valueSize":1}],"id":104,"nodeType":"InlineAssembly","src":"1487:159:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayloadView","nameLocation":"1281:19:0","parameters":{"id":93,"nodeType":"ParameterList","parameters":[{"constant":false,"id":92,"mutability":"mutable","name":"payload","nameLocation":"1314:7:0","nodeType":"VariableDeclaration","scope":106,"src":"1301:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":91,"name":"bytes","nodeType":"ElementaryTypeName","src":"1301:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1300:22:0"},"returnParameters":{"id":94,"nodeType":"ParameterList","parameters":[],"src":"1336:0:0"},"scope":192,"stateMutability":"view","virtual":false,"visibility":"private"},{"id":120,"nodeType":"FunctionDefinition","src":"1658:121:0","nodes":[],"body":{"id":119,"nodeType":"Block","src":"1703:76:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e6729","id":114,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1753:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},"value":"log(string)"},{"id":115,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":108,"src":"1768:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":112,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"1729:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":113,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"1729:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":116,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1729:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":111,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"1713:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":117,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1713:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":118,"nodeType":"ExpressionStatement","src":"1713:59:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"1667:3:0","parameters":{"id":109,"nodeType":"ParameterList","parameters":[{"constant":false,"id":108,"mutability":"mutable","name":"p0","nameLocation":"1685:2:0","nodeType":"VariableDeclaration","scope":120,"src":"1671:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":107,"name":"string","nodeType":"ElementaryTypeName","src":"1671:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"1670:18:0"},"returnParameters":{"id":110,"nodeType":"ParameterList","parameters":[],"src":"1703:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":137,"nodeType":"FunctionDefinition","src":"1785:139:0","nodes":[],"body":{"id":136,"nodeType":"Block","src":"1839:85:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c626f6f6c29","id":130,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1889:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},"value":"log(string,bool)"},{"id":131,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":122,"src":"1909:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":132,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":124,"src":"1913:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":128,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"1865:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":129,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"1865:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":133,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1865:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":127,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"1849:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":134,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1849:68:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":135,"nodeType":"ExpressionStatement","src":"1849:68:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"1794:3:0","parameters":{"id":125,"nodeType":"ParameterList","parameters":[{"constant":false,"id":122,"mutability":"mutable","name":"p0","nameLocation":"1812:2:0","nodeType":"VariableDeclaration","scope":137,"src":"1798:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":121,"name":"string","nodeType":"ElementaryTypeName","src":"1798:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":124,"mutability":"mutable","name":"p1","nameLocation":"1821:2:0","nodeType":"VariableDeclaration","scope":137,"src":"1816:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":123,"name":"bool","nodeType":"ElementaryTypeName","src":"1816:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"1797:27:0"},"returnParameters":{"id":126,"nodeType":"ParameterList","parameters":[],"src":"1839:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":154,"nodeType":"FunctionDefinition","src":"1930:145:0","nodes":[],"body":{"id":153,"nodeType":"Block","src":"1987:88:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c75696e7432353629","id":147,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2037:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},"value":"log(string,uint256)"},{"id":148,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":139,"src":"2060:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":149,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":141,"src":"2064:2:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":145,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2013:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":146,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2013:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":150,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2013:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":144,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"1997:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":151,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1997:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":152,"nodeType":"ExpressionStatement","src":"1997:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"1939:3:0","parameters":{"id":142,"nodeType":"ParameterList","parameters":[{"constant":false,"id":139,"mutability":"mutable","name":"p0","nameLocation":"1957:2:0","nodeType":"VariableDeclaration","scope":154,"src":"1943:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":138,"name":"string","nodeType":"ElementaryTypeName","src":"1943:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":141,"mutability":"mutable","name":"p1","nameLocation":"1969:2:0","nodeType":"VariableDeclaration","scope":154,"src":"1961:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":140,"name":"uint256","nodeType":"ElementaryTypeName","src":"1961:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1942:30:0"},"returnParameters":{"id":143,"nodeType":"ParameterList","parameters":[],"src":"1987:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":171,"nodeType":"FunctionDefinition","src":"2081:145:0","nodes":[],"body":{"id":170,"nodeType":"Block","src":"2138:88:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c6164647265737329","id":164,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2188:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},"value":"log(string,address)"},{"id":165,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":156,"src":"2211:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":166,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":158,"src":"2215:2:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":162,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2164:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":163,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2164:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":167,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2164:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":161,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"2148:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":168,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2148:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":169,"nodeType":"ExpressionStatement","src":"2148:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2090:3:0","parameters":{"id":159,"nodeType":"ParameterList","parameters":[{"constant":false,"id":156,"mutability":"mutable","name":"p0","nameLocation":"2108:2:0","nodeType":"VariableDeclaration","scope":171,"src":"2094:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":155,"name":"string","nodeType":"ElementaryTypeName","src":"2094:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":158,"mutability":"mutable","name":"p1","nameLocation":"2120:2:0","nodeType":"VariableDeclaration","scope":171,"src":"2112:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":157,"name":"address","nodeType":"ElementaryTypeName","src":"2112:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2093:30:0"},"returnParameters":{"id":160,"nodeType":"ParameterList","parameters":[],"src":"2138:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":191,"nodeType":"FunctionDefinition","src":"2232:179:0","nodes":[],"body":{"id":190,"nodeType":"Block","src":"2313:98:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c737472696e672c737472696e6729","id":183,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2363:27:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},"value":"log(string,string,string)"},{"id":184,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":173,"src":"2392:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":185,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":175,"src":"2396:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":186,"name":"p2","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":177,"src":"2400:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":181,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2339:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":182,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2339:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":187,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2339:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":180,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":90,"src":"2323:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":188,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2323:81:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":189,"nodeType":"ExpressionStatement","src":"2323:81:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2241:3:0","parameters":{"id":178,"nodeType":"ParameterList","parameters":[{"constant":false,"id":173,"mutability":"mutable","name":"p0","nameLocation":"2259:2:0","nodeType":"VariableDeclaration","scope":191,"src":"2245:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":172,"name":"string","nodeType":"ElementaryTypeName","src":"2245:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":175,"mutability":"mutable","name":"p1","nameLocation":"2277:2:0","nodeType":"VariableDeclaration","scope":191,"src":"2263:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":174,"name":"string","nodeType":"ElementaryTypeName","src":"2263:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":177,"mutability":"mutable","name":"p2","nameLocation":"2295:2:0","nodeType":"VariableDeclaration","scope":191,"src":"2281:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":176,"name":"string","nodeType":"ElementaryTypeName","src":"2281:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2244:54:0"},"returnParameters":{"id":179,"nodeType":"ParameterList","parameters":[],"src":"2313:0:0"},"scope":192,"stateMutability":"pure","virtual":false,"visibility":"internal"}],"abstract":false,"baseContracts":[],"canonicalName":"console","contractDependencies":[],"contractKind":"library","fullyImplemented":true,"linearizedBaseContracts":[192],"name":"console","nameLocation":"799:7:0","scope":720,"usedErrors":[]},{"id":706,"nodeType":"ContractDefinition","src":"2541:3359:0","nodes":[{"id":207,"nodeType":"VariableDeclaration","src":"2571:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"2597:10:0","scope":706,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":194,"name":"address","nodeType":"ElementaryTypeName","src":"2571:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":202,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2644:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":201,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"2634:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":203,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2634:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":200,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2626:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":199,"name":"uint256","nodeType":"ElementaryTypeName","src":"2626:7:0","typeDescriptions":{}}},"id":204,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2626:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":198,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2618:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":197,"name":"uint160","nodeType":"ElementaryTypeName","src":"2618:7:0","typeDescriptions":{}}},"id":205,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2618:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":196,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"2610:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":195,"name":"address","nodeType":"ElementaryTypeName","src":"2610:7:0","typeDescriptions":{}}},"id":206,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2610:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":213,"nodeType":"VariableDeclaration","src":"2671:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"2692:2:0","scope":706,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"},"typeName":{"id":209,"nodeType":"UserDefinedTypeName","pathNode":{"id":208,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":55,"src":"2671:2:0"},"referencedDeclaration":55,"src":"2671:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"value":{"arguments":[{"id":211,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":207,"src":"2700:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":210,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":55,"src":"2697:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$55_$","typeString":"type(contract Vm)"}},"id":212,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2697:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"visibility":"internal"},{"id":215,"nodeType":"VariableDeclaration","src":"2775:22:0","nodes":[],"constant":false,"functionSelector":"61bc221a","mutability":"mutable","name":"counter","nameLocation":"2790:7:0","scope":706,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":214,"name":"uint256","nodeType":"ElementaryTypeName","src":"2775:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":378,"nodeType":"FunctionDefinition","src":"2887:949:0","nodes":[],"body":{"id":377,"nodeType":"Block","src":"2909:927:0","nodes":[],"statements":[{"assignments":[220],"declarations":[{"constant":false,"id":220,"mutability":"mutable","name":"x","nameLocation":"2924:1:0","nodeType":"VariableDeclaration","scope":377,"src":"2919:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":219,"name":"bool","nodeType":"ElementaryTypeName","src":"2919:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"id":226,"initialValue":{"arguments":[{"hexValue":"4558414d504c455f424f4f4c","id":223,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2937:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},"value":"EXAMPLE_BOOL"},{"hexValue":"66616c7365","id":224,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"2953:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":221,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"2928:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":222,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"envOr","nodeType":"MemberAccess","referencedDeclaration":10,"src":"2928:8:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$_t_bool_$returns$_t_bool_$","typeString":"function (string memory,bool) view external returns (bool)"}},"id":225,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2928:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"VariableDeclarationStatement","src":"2919:40:0"},{"expression":{"arguments":[{"hexValue":"626f6f6c2076616c75652066726f6d20656e76","id":230,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2981:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},"value":"bool value from env"},{"id":231,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3004:1:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":227,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"2969:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":229,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":137,"src":"2969:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_bool_$returns$__$","typeString":"function (string memory,bool) pure"}},"id":232,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2969:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":233,"nodeType":"ExpressionStatement","src":"2969:37:0"},{"expression":{"arguments":[{"hexValue":"636f6e74726163742061646472","id":237,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3029:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},"value":"contract addr"},{"arguments":[{"id":240,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3054:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":239,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3046:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":238,"name":"address","nodeType":"ElementaryTypeName","src":"3046:7:0","typeDescriptions":{}}},"id":241,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3046:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":234,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3017:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":236,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3017:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":242,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3017:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":243,"nodeType":"ExpressionStatement","src":"3017:43:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206e6f6e6365","id":247,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3082:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},"value":"contract nonce"},{"arguments":[{"arguments":[{"id":252,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3120:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":251,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3112:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":250,"name":"address","nodeType":"ElementaryTypeName","src":"3112:7:0","typeDescriptions":{}}},"id":253,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3112:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":248,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3100:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":249,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3100:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":254,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3100:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":244,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3070:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":246,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"3070:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":255,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3070:57:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":256,"nodeType":"ExpressionStatement","src":"3070:57:0"},{"expression":{"arguments":[{"hexValue":"73656e6465722061646472","id":260,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3149:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},"value":"sender addr"},{"arguments":[{"expression":{"id":263,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3172:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":264,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3172:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":262,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3164:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":261,"name":"address","nodeType":"ElementaryTypeName","src":"3164:7:0","typeDescriptions":{}}},"id":265,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3164:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":257,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3137:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":259,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3137:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":266,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3137:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":267,"nodeType":"ExpressionStatement","src":"3137:47:0"},{"expression":{"arguments":[{"hexValue":"73656e646572206e6f6e6365","id":271,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3206:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},"value":"sender nonce"},{"arguments":[{"arguments":[{"expression":{"id":276,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3242:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":277,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3242:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":275,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3234:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":274,"name":"address","nodeType":"ElementaryTypeName","src":"3234:7:0","typeDescriptions":{}}},"id":278,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3234:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":272,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3222:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":273,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3222:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":279,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3222:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":268,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3194:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":270,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"3194:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":280,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3194:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":281,"nodeType":"ExpressionStatement","src":"3194:61:0"},{"assignments":[283],"declarations":[{"constant":false,"id":283,"mutability":"mutable","name":"json","nameLocation":"3280:4:0","nodeType":"VariableDeclaration","scope":377,"src":"3266:18:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":282,"name":"string","nodeType":"ElementaryTypeName","src":"3266:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"id":285,"initialValue":{"hexValue":"7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d","id":284,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3287:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e95522e99766888d0261f55bd1eae5e3f3e26eaf009a16e2433eafaf0a4ecdf2","typeString":"literal_string \"{\"root_key\": [{\"a\": 1, \"b\": 2}]}\""},"value":"{\"root_key\": [{\"a\": 1, \"b\": 2}]}"},"nodeType":"VariableDeclarationStatement","src":"3266:55:0"},{"assignments":[290],"declarations":[{"constant":false,"id":290,"mutability":"mutable","name":"keys","nameLocation":"3347:4:0","nodeType":"VariableDeclaration","scope":377,"src":"3331:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":288,"name":"string","nodeType":"ElementaryTypeName","src":"3331:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":289,"nodeType":"ArrayTypeName","src":"3331:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"id":296,"initialValue":{"arguments":[{"id":293,"name":"json","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":283,"src":"3371:4:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"2e726f6f745f6b65795b305d","id":294,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3377:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""},"value":".root_key[0]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""}],"expression":{"id":291,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3354:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":292,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"parseJsonKeys","nodeType":"MemberAccess","referencedDeclaration":27,"src":"3354:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$_t_array$_t_string_memory_ptr_$dyn_memory_ptr_$","typeString":"function (string memory,string memory) pure external returns (string memory[] memory)"}},"id":295,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3354:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"nodeType":"VariableDeclarationStatement","src":"3331:61:0"},{"expression":{"arguments":[{"hexValue":"6b657973","id":300,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3414:6:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},"value":"keys"},{"baseExpression":{"id":301,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":290,"src":"3422:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":303,"indexExpression":{"hexValue":"30","id":302,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"3427:1:0","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"3422:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"baseExpression":{"id":304,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":290,"src":"3431:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":306,"indexExpression":{"hexValue":"31","id":305,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"3436:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"3431:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":297,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3402:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":299,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":191,"src":"3402:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory,string memory) pure"}},"id":307,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3402:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":308,"nodeType":"ExpressionStatement","src":"3402:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c","id":312,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3461:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""},"value":"from original"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""}],"expression":{"id":309,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3450:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":311,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3450:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":313,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3450:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":314,"nodeType":"ExpressionStatement","src":"3450:27:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"30783432","id":322,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"3517:4:0","typeDescriptions":{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"},"value":"0x42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"}],"id":321,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3509:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":320,"name":"uint160","nodeType":"ElementaryTypeName","src":"3509:7:0","typeDescriptions":{}}},"id":323,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3509:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":319,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3501:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":318,"name":"address","nodeType":"ElementaryTypeName","src":"3501:7:0","typeDescriptions":{}}},"id":324,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3501:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":315,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3487:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":317,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startPrank","nodeType":"MemberAccess","referencedDeclaration":32,"src":"3487:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":325,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3487:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":326,"nodeType":"ExpressionStatement","src":"3487:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2031","id":330,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3545:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""},"value":"from prank 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""}],"expression":{"id":327,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3534:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":329,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3534:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":331,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3534:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":332,"nodeType":"ExpressionStatement","src":"3534:26:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f7065206d73672e73656e646572","id":336,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3582:25:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},"value":"parent scope msg.sender"},{"arguments":[{"expression":{"id":339,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3617:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":340,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3617:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":338,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3609:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":337,"name":"address","nodeType":"ElementaryTypeName","src":"3609:7:0","typeDescriptions":{}}},"id":341,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3609:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":333,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3570:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":335,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3570:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":342,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3570:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":343,"nodeType":"ExpressionStatement","src":"3570:59:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f706520636f6e74726163742e61646472","id":347,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3651:28:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},"value":"parent scope contract.addr"},{"arguments":[{"id":350,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3689:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":349,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3681:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":348,"name":"address","nodeType":"ElementaryTypeName","src":"3681:7:0","typeDescriptions":{}}},"id":351,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3681:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":344,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3639:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":346,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"3639:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":352,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3639:56:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":353,"nodeType":"ExpressionStatement","src":"3639:56:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2032","id":357,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3716:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""},"value":"from prank 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""}],"expression":{"id":354,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3705:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":356,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3705:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":358,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3705:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":359,"nodeType":"ExpressionStatement","src":"3705:26:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":360,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3741:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":362,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopPrank","nodeType":"MemberAccess","referencedDeclaration":35,"src":"3741:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":363,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3741:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":364,"nodeType":"ExpressionStatement","src":"3741:14:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c20616761696e","id":368,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3776:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""},"value":"from original again"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""}],"expression":{"id":365,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3765:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":367,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":633,"src":"3765:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":369,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3765:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":370,"nodeType":"ExpressionStatement","src":"3765:33:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":374,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3821:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":371,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3809:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":373,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"3809:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":375,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3809:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":376,"nodeType":"ExpressionStatement","src":"3809:20:0"}]},"documentation":{"id":216,"nodeType":"StructuredDocumentation","src":"2804:78:0","text":"@notice example function, runs through basic cheat-codes and console logs."},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"2896:3:0","parameters":{"id":217,"nodeType":"ParameterList","parameters":[],"src":"2899:2:0"},"returnParameters":{"id":218,"nodeType":"ParameterList","parameters":[],"src":"2909:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":609,"nodeType":"FunctionDefinition","src":"3903:1258:0","nodes":[],"body":{"id":608,"nodeType":"Block","src":"3934:1227:0","nodes":[],"statements":[{"expression":{"arguments":[{"hexValue":"6e6f6e6365207374617274","id":385,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3956:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},"value":"nonce start"},{"arguments":[{"arguments":[{"arguments":[{"id":392,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3999:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":391,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3991:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":390,"name":"address","nodeType":"ElementaryTypeName","src":"3991:7:0","typeDescriptions":{}}},"id":393,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3991:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":388,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"3979:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":389,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3979:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":394,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3979:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":387,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3971:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":386,"name":"uint256","nodeType":"ElementaryTypeName","src":"3971:7:0","typeDescriptions":{}}},"id":395,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3971:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":382,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"3944:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":384,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"3944:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":396,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3944:63:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":397,"nodeType":"ExpressionStatement","src":"3944:63:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073696e676c65","id":401,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4030:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""},"value":"testing single"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""}],"expression":{"id":398,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4018:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":400,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4018:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":402,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4018:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":403,"nodeType":"ExpressionStatement","src":"4018:29:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":404,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4057:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":406,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"4057:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":407,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4057:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":408,"nodeType":"ExpressionStatement","src":"4057:14:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c31","id":412,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4092:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""},"value":"single_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""}],"expression":{"id":409,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4081:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":411,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":648,"src":"4081:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":413,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4081:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":414,"nodeType":"ExpressionStatement","src":"4081:26:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c32","id":418,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4128:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""},"value":"single_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""}],"expression":{"id":415,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4117:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":417,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":663,"src":"4117:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":419,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4117:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":420,"nodeType":"ExpressionStatement","src":"4117:26:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073746172742f73746f70","id":424,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4166:20:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""},"value":"testing start/stop"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""}],"expression":{"id":421,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4154:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":423,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4154:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":425,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4154:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":426,"nodeType":"ExpressionStatement","src":"4154:33:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078633066666565","id":434,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4231:8:0","typeDescriptions":{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"},"value":"0xc0ffee"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"}],"id":433,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4223:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":432,"name":"uint160","nodeType":"ElementaryTypeName","src":"4223:7:0","typeDescriptions":{}}},"id":435,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4223:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":431,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4215:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":430,"name":"address","nodeType":"ElementaryTypeName","src":"4215:7:0","typeDescriptions":{}}},"id":436,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4215:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":427,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4197:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":429,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"4197:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":437,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4197:45:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":438,"nodeType":"ExpressionStatement","src":"4197:45:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c31","id":442,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4263:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""},"value":"startstop_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""}],"expression":{"id":439,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4252:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":441,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":648,"src":"4252:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":443,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4252:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":444,"nodeType":"ExpressionStatement","src":"4252:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c32","id":448,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4302:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""},"value":"startstop_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""}],"expression":{"id":445,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4291:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":447,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":663,"src":"4291:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":449,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4291:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":450,"nodeType":"ExpressionStatement","src":"4291:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f70757265","id":454,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4344:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""},"value":"startstop_pure"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""}],"expression":{"id":451,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4330:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":453,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"callPure","nodeType":"MemberAccess","referencedDeclaration":705,"src":"4330:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure external"}},"id":455,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4330:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":456,"nodeType":"ExpressionStatement","src":"4330:31:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":457,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4371:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":459,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"4371:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":460,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4371:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":461,"nodeType":"ExpressionStatement","src":"4371:18:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c33","id":465,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4410:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""},"value":"startstop_call3"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""}],"expression":{"id":462,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4399:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":464,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":648,"src":"4399:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":466,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4399:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":467,"nodeType":"ExpressionStatement","src":"4399:29:0"},{"expression":{"arguments":[{"hexValue":"74657374696e67206e6573746564","id":471,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4451:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""},"value":"testing nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""}],"expression":{"id":468,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4439:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":470,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4439:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":472,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4439:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":473,"nodeType":"ExpressionStatement","src":"4439:29:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307831323334","id":481,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4512:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":480,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4504:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":479,"name":"uint160","nodeType":"ElementaryTypeName","src":"4504:7:0","typeDescriptions":{}}},"id":482,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4504:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":478,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4496:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":477,"name":"address","nodeType":"ElementaryTypeName","src":"4496:7:0","typeDescriptions":{}}},"id":483,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4496:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":474,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4478:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":476,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"4478:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":484,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4478:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":485,"nodeType":"ExpressionStatement","src":"4478:43:0"},{"expression":{"arguments":[{"hexValue":"6e6573746564","id":489,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4544:8:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""},"value":"nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""}],"expression":{"id":486,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4531:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":488,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested1","nodeType":"MemberAccess","referencedDeclaration":678,"src":"4531:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":490,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4531:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":491,"nodeType":"ExpressionStatement","src":"4531:22:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":492,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4563:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":494,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"4563:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":495,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4563:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":496,"nodeType":"ExpressionStatement","src":"4563:18:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206465706c6f796d656e74","id":500,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4604:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""},"value":"contract deployment"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""}],"expression":{"id":497,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4592:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":499,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4592:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":501,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4592:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":502,"nodeType":"ExpressionStatement","src":"4592:34:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078313233343536","id":510,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4665:8:0","typeDescriptions":{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"},"value":"0x123456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"}],"id":509,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4657:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":508,"name":"uint160","nodeType":"ElementaryTypeName","src":"4657:7:0","typeDescriptions":{}}},"id":511,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4657:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":507,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4649:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":506,"name":"address","nodeType":"ElementaryTypeName","src":"4649:7:0","typeDescriptions":{}}},"id":512,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4649:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":503,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4636:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":505,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"4636:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":513,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4636:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":514,"nodeType":"ExpressionStatement","src":"4636:40:0"},{"assignments":[517],"declarations":[{"constant":false,"id":517,"mutability":"mutable","name":"x","nameLocation":"4693:1:0","nodeType":"VariableDeclaration","scope":608,"src":"4686:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"},"typeName":{"id":516,"nodeType":"UserDefinedTypeName","pathNode":{"id":515,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4686:6:0"},"referencedDeclaration":719,"src":"4686:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"visibility":"internal"}],"id":523,"initialValue":{"arguments":[{"hexValue":"31323334","id":521,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4708:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":520,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"4697:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":519,"nodeType":"UserDefinedTypeName","pathNode":{"id":518,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4701:6:0"},"referencedDeclaration":719,"src":"4701:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}}},"id":522,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4697:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"4686:27:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":529,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":525,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":517,"src":"4731:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"id":526,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":708,"src":"4731:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":527,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4731:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":528,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4742:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"4731:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"}],"id":524,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"4723:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$returns$__$","typeString":"function (bool) pure"}},"id":530,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4723:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":531,"nodeType":"ExpressionStatement","src":"4723:24:0"},{"expression":{"arguments":[{"hexValue":"6372656174652032","id":535,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4770:10:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""},"value":"create 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""}],"expression":{"id":532,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4758:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":534,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4758:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":536,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4758:23:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":537,"nodeType":"ExpressionStatement","src":"4758:23:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307863616665","id":545,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4820:6:0","typeDescriptions":{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"},"value":"0xcafe"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"}],"id":544,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4812:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":543,"name":"uint160","nodeType":"ElementaryTypeName","src":"4812:7:0","typeDescriptions":{}}},"id":546,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4812:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":542,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4804:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":541,"name":"address","nodeType":"ElementaryTypeName","src":"4804:7:0","typeDescriptions":{}}},"id":547,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4804:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":538,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"4791:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":540,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"4791:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":548,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4791:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":549,"nodeType":"ExpressionStatement","src":"4791:38:0"},{"assignments":[552],"declarations":[{"constant":false,"id":552,"mutability":"mutable","name":"y","nameLocation":"4846:1:0","nodeType":"VariableDeclaration","scope":608,"src":"4839:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"},"typeName":{"id":551,"nodeType":"UserDefinedTypeName","pathNode":{"id":550,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4839:6:0"},"referencedDeclaration":719,"src":"4839:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"visibility":"internal"}],"id":566,"initialValue":{"arguments":[{"hexValue":"31323334","id":564,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4889:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":555,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"4850:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":554,"nodeType":"UserDefinedTypeName","pathNode":{"id":553,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"4854:6:0"},"referencedDeclaration":719,"src":"4854:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}}},"id":563,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"names":["salt"],"nodeType":"FunctionCallOptions","options":[{"arguments":[{"arguments":[{"hexValue":"3432","id":560,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4883:2:0","typeDescriptions":{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"},"value":"42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"}],"id":559,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4875:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":558,"name":"uint256","nodeType":"ElementaryTypeName","src":"4875:7:0","typeDescriptions":{}}},"id":561,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4875:11:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":557,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4867:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":556,"name":"bytes32","nodeType":"ElementaryTypeName","src":"4867:7:0","typeDescriptions":{}}},"id":562,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4867:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"src":"4850:38:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$salt","typeString":"function (uint256) returns (contract FooBar)"}},"id":565,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4850:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"4839:55:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":572,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":568,"name":"y","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":552,"src":"4912:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"id":569,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":708,"src":"4912:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":570,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4912:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":571,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4923:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"4912:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"}],"id":567,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"4904:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$returns$__$","typeString":"function (bool) pure"}},"id":573,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4904:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":574,"nodeType":"ExpressionStatement","src":"4904:24:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":578,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4950:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":575,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"4938:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":577,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"4938:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":579,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4938:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":580,"nodeType":"ExpressionStatement","src":"4938:20:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":581,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"5042:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":583,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"5042:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":584,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5042:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":585,"nodeType":"ExpressionStatement","src":"5042:14:0"},{"expression":{"arguments":[{"hexValue":"31323334","id":589,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5077:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":588,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5066:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$719_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":587,"nodeType":"UserDefinedTypeName","pathNode":{"id":586,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":719,"src":"5070:6:0"},"referencedDeclaration":719,"src":"5070:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}}},"id":590,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5066:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$719","typeString":"contract FooBar"}},"id":591,"nodeType":"ExpressionStatement","src":"5066:16:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e636520656e64","id":595,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5105:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},"value":"nonce end"},{"arguments":[{"arguments":[{"arguments":[{"id":602,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5146:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}],"id":601,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5138:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":600,"name":"address","nodeType":"ElementaryTypeName","src":"5138:7:0","typeDescriptions":{}}},"id":603,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5138:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":598,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":213,"src":"5126:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$55","typeString":"contract Vm"}},"id":599,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"5126:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":604,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5126:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":597,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5118:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":596,"name":"uint256","nodeType":"ElementaryTypeName","src":"5118:7:0","typeDescriptions":{}}},"id":605,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5118:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":592,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5093:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":594,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":154,"src":"5093:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":606,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5093:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":607,"nodeType":"ExpressionStatement","src":"5093:61:0"}]},"documentation":{"id":379,"nodeType":"StructuredDocumentation","src":"3842:56:0","text":"@notice example function, to test vm.broadcast with."},"functionSelector":"bef03abc","implemented":true,"kind":"function","modifiers":[],"name":"runBroadcast","nameLocation":"3912:12:0","parameters":{"id":380,"nodeType":"ParameterList","parameters":[],"src":"3924:2:0"},"returnParameters":{"id":381,"nodeType":"ParameterList","parameters":[],"src":"3934:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":633,"nodeType":"FunctionDefinition","src":"5256:143:0","nodes":[],"body":{"id":632,"nodeType":"Block","src":"5305:94:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":618,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":612,"src":"5327:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":615,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5315:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":617,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5315:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":619,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5315:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":620,"nodeType":"ExpressionStatement","src":"5315:15:0"},{"expression":{"arguments":[{"hexValue":"68656c6c6f206d73672e73656e646572","id":624,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5352:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},"value":"hello msg.sender"},{"arguments":[{"expression":{"id":627,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"5380:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":628,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"5380:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":626,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5372:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":625,"name":"address","nodeType":"ElementaryTypeName","src":"5372:7:0","typeDescriptions":{}}},"id":629,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5372:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":621,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5340:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":623,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":171,"src":"5340:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":630,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5340:52:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":631,"nodeType":"ExpressionStatement","src":"5340:52:0"}]},"documentation":{"id":610,"nodeType":"StructuredDocumentation","src":"5167:84:0","text":"@notice example external function, to force a CALL, and test vm.startPrank with."},"functionSelector":"a777d0dc","implemented":true,"kind":"function","modifiers":[],"name":"hello","nameLocation":"5265:5:0","parameters":{"id":613,"nodeType":"ParameterList","parameters":[{"constant":false,"id":612,"mutability":"mutable","name":"_v","nameLocation":"5287:2:0","nodeType":"VariableDeclaration","scope":633,"src":"5271:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":611,"name":"string","nodeType":"ElementaryTypeName","src":"5271:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5270:20:0"},"returnParameters":{"id":614,"nodeType":"ParameterList","parameters":[],"src":"5305:0:0"},"scope":706,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":648,"nodeType":"FunctionDefinition","src":"5405:95:0","nodes":[],"body":{"id":647,"nodeType":"Block","src":"5449:51:0","nodes":[],"statements":[{"expression":{"id":639,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5459:9:0","subExpression":{"id":638,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5459:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":640,"nodeType":"ExpressionStatement","src":"5459:9:0"},{"expression":{"arguments":[{"id":644,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":635,"src":"5490:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":641,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5478:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":643,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5478:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":645,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5478:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":646,"nodeType":"ExpressionStatement","src":"5478:15:0"}]},"functionSelector":"7e79255d","implemented":true,"kind":"function","modifiers":[],"name":"call1","nameLocation":"5414:5:0","parameters":{"id":636,"nodeType":"ParameterList","parameters":[{"constant":false,"id":635,"mutability":"mutable","name":"_v","nameLocation":"5436:2:0","nodeType":"VariableDeclaration","scope":648,"src":"5420:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":634,"name":"string","nodeType":"ElementaryTypeName","src":"5420:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5419:20:0"},"returnParameters":{"id":637,"nodeType":"ParameterList","parameters":[],"src":"5449:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":663,"nodeType":"FunctionDefinition","src":"5506:95:0","nodes":[],"body":{"id":662,"nodeType":"Block","src":"5550:51:0","nodes":[],"statements":[{"expression":{"id":654,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5560:9:0","subExpression":{"id":653,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5560:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":655,"nodeType":"ExpressionStatement","src":"5560:9:0"},{"expression":{"arguments":[{"id":659,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":650,"src":"5591:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":656,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5579:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":658,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5579:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":660,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5579:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":661,"nodeType":"ExpressionStatement","src":"5579:15:0"}]},"functionSelector":"8d3ef7ca","implemented":true,"kind":"function","modifiers":[],"name":"call2","nameLocation":"5515:5:0","parameters":{"id":651,"nodeType":"ParameterList","parameters":[{"constant":false,"id":650,"mutability":"mutable","name":"_v","nameLocation":"5537:2:0","nodeType":"VariableDeclaration","scope":663,"src":"5521:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":649,"name":"string","nodeType":"ElementaryTypeName","src":"5521:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5520:20:0"},"returnParameters":{"id":652,"nodeType":"ParameterList","parameters":[],"src":"5550:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":678,"nodeType":"FunctionDefinition","src":"5607:98:0","nodes":[],"body":{"id":677,"nodeType":"Block","src":"5653:52:0","nodes":[],"statements":[{"expression":{"id":669,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5663:9:0","subExpression":{"id":668,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5663:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":670,"nodeType":"ExpressionStatement","src":"5663:9:0"},{"expression":{"arguments":[{"id":674,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":665,"src":"5695:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":671,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5682:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$706","typeString":"contract ScriptExample"}},"id":673,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested2","nodeType":"MemberAccess","referencedDeclaration":693,"src":"5682:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":675,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5682:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":676,"nodeType":"ExpressionStatement","src":"5682:16:0"}]},"functionSelector":"a76ccdfa","implemented":true,"kind":"function","modifiers":[],"name":"nested1","nameLocation":"5616:7:0","parameters":{"id":666,"nodeType":"ParameterList","parameters":[{"constant":false,"id":665,"mutability":"mutable","name":"_v","nameLocation":"5640:2:0","nodeType":"VariableDeclaration","scope":678,"src":"5624:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":664,"name":"string","nodeType":"ElementaryTypeName","src":"5624:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5623:20:0"},"returnParameters":{"id":667,"nodeType":"ParameterList","parameters":[],"src":"5653:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":693,"nodeType":"FunctionDefinition","src":"5711:97:0","nodes":[],"body":{"id":692,"nodeType":"Block","src":"5757:51:0","nodes":[],"statements":[{"expression":{"id":684,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"5767:9:0","subExpression":{"id":683,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":215,"src":"5767:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":685,"nodeType":"ExpressionStatement","src":"5767:9:0"},{"expression":{"arguments":[{"id":689,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":680,"src":"5798:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":686,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5786:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":688,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5786:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":690,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5786:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":691,"nodeType":"ExpressionStatement","src":"5786:15:0"}]},"functionSelector":"dbf1282f","implemented":true,"kind":"function","modifiers":[],"name":"nested2","nameLocation":"5720:7:0","parameters":{"id":681,"nodeType":"ParameterList","parameters":[{"constant":false,"id":680,"mutability":"mutable","name":"_v","nameLocation":"5744:2:0","nodeType":"VariableDeclaration","scope":693,"src":"5728:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":679,"name":"string","nodeType":"ElementaryTypeName","src":"5728:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5727:20:0"},"returnParameters":{"id":682,"nodeType":"ParameterList","parameters":[],"src":"5757:0:0"},"scope":706,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":705,"nodeType":"FunctionDefinition","src":"5814:84:0","nodes":[],"body":{"id":704,"nodeType":"Block","src":"5866:32:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":701,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":695,"src":"5888:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":698,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":192,"src":"5876:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$192_$","typeString":"type(library console)"}},"id":700,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":120,"src":"5876:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":702,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5876:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":703,"nodeType":"ExpressionStatement","src":"5876:15:0"}]},"functionSelector":"7f8b915c","implemented":true,"kind":"function","modifiers":[],"name":"callPure","nameLocation":"5823:8:0","parameters":{"id":696,"nodeType":"ParameterList","parameters":[{"constant":false,"id":695,"mutability":"mutable","name":"_v","nameLocation":"5848:2:0","nodeType":"VariableDeclaration","scope":705,"src":"5832:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":694,"name":"string","nodeType":"ElementaryTypeName","src":"5832:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"5831:20:0"},"returnParameters":{"id":697,"nodeType":"ParameterList","parameters":[],"src":"5866:0:0"},"scope":706,"stateMutability":"pure","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ScriptExample","contractDependencies":[719],"contractKind":"contract","documentation":{"id":193,"nodeType":"StructuredDocumentation","src":"2415:126:0","text":"@title ScriptExample\n @notice ScriptExample is an example script. The Go forge script code tests that it can run this."},"fullyImplemented":true,"linearizedBaseContracts":[706],"name":"ScriptExample","nameLocation":"2550:13:0","scope":720,"usedErrors":[]},{"id":719,"nodeType":"ContractDefinition","src":"5902:96:0","nodes":[{"id":708,"nodeType":"VariableDeclaration","src":"5924:18:0","nodes":[],"constant":false,"functionSelector":"c2985578","mutability":"mutable","name":"foo","nameLocation":"5939:3:0","scope":719,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":707,"name":"uint256","nodeType":"ElementaryTypeName","src":"5924:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":718,"nodeType":"FunctionDefinition","src":"5949:47:0","nodes":[],"body":{"id":717,"nodeType":"Block","src":"5972:24:0","nodes":[],"statements":[{"expression":{"id":715,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":713,"name":"foo","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":708,"src":"5982:3:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":714,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":710,"src":"5988:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"5982:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":716,"nodeType":"ExpressionStatement","src":"5982:7:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":711,"nodeType":"ParameterList","parameters":[{"constant":false,"id":710,"mutability":"mutable","name":"v","nameLocation":"5969:1:0","nodeType":"VariableDeclaration","scope":718,"src":"5961:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":709,"name":"uint256","nodeType":"ElementaryTypeName","src":"5961:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"5960:11:0"},"returnParameters":{"id":712,"nodeType":"ParameterList","parameters":[],"src":"5972:0:0"},"scope":719,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"FooBar","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[719],"name":"FooBar","nameLocation":"5911:6:0","scope":720,"usedErrors":[]}],"license":"MIT"},"id":0} \ No newline at end of file +{"abi":[],"bytecode":{"object":"0x602d6037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c634300080f000a","sourceMap":"1144:1851:0:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;1144:1851:0;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c634300080f000a","sourceMap":"1144:1851:0:-:0;;;;;;;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"scripts/ScriptExample.s.sol\":\"console\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"scripts/ScriptExample.s.sol\":{\"keccak256\":\"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28\",\"dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.15+commit.e14f2714"},"language":"Solidity","output":{"abi":[],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"scripts/ScriptExample.s.sol":"console"},"evmVersion":"london","libraries":{}},"sources":{"scripts/ScriptExample.s.sol":{"keccak256":"0x1fd8237b3b3dff6f5f0dcff6572ad225d40275cdf471b8f6bac1df896c0e56da","urls":["bzz-raw://0e60c01e0c609f4401cb66c7d10819321ca7aec52cfb8b688f57f5ae54ee9f28","dweb:/ipfs/QmXyqERiuKiVaUWmP4XVZXdJvhoPsFvbySF2WWJtKjgSy8"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[],"types":{}},"userdoc":{"version":1,"kind":"user"},"devdoc":{"version":1,"kind":"dev"},"ast":{"absolutePath":"scripts/ScriptExample.s.sol","id":969,"exportedSymbols":{"FooBar":[799],"ForkTester":[968],"ForkedContract":[852],"NonceGetter":[833],"ScriptExample":[786],"Vm":[83],"console":[220]},"nodeType":"SourceUnit","src":"32:8375:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","0.8",".15"]},{"id":83,"nodeType":"ContractDefinition","src":"120:969:0","nodes":[{"id":10,"nodeType":"FunctionDefinition","src":"139:91:0","nodes":[],"functionSelector":"4777f3cf","implemented":false,"kind":"function","modifiers":[],"name":"envOr","nameLocation":"148:5:0","parameters":{"id":6,"nodeType":"ParameterList","parameters":[{"constant":false,"id":3,"mutability":"mutable","name":"name","nameLocation":"170:4:0","nodeType":"VariableDeclaration","scope":10,"src":"154:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":2,"name":"string","nodeType":"ElementaryTypeName","src":"154:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":5,"mutability":"mutable","name":"defaultValue","nameLocation":"181:12:0","nodeType":"VariableDeclaration","scope":10,"src":"176:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":4,"name":"bool","nodeType":"ElementaryTypeName","src":"176:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"153:41:0"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[{"constant":false,"id":8,"mutability":"mutable","name":"value","nameLocation":"223:5:0","nodeType":"VariableDeclaration","scope":10,"src":"218:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":7,"name":"bool","nodeType":"ElementaryTypeName","src":"218:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"217:12:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":17,"nodeType":"FunctionDefinition","src":"235:72:0","nodes":[],"functionSelector":"2d0335ab","implemented":false,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"244:8:0","parameters":{"id":13,"nodeType":"ParameterList","parameters":[{"constant":false,"id":12,"mutability":"mutable","name":"account","nameLocation":"261:7:0","nodeType":"VariableDeclaration","scope":17,"src":"253:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":11,"name":"address","nodeType":"ElementaryTypeName","src":"253:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"252:17:0"},"returnParameters":{"id":16,"nodeType":"ParameterList","parameters":[{"constant":false,"id":15,"mutability":"mutable","name":"nonce","nameLocation":"300:5:0","nodeType":"VariableDeclaration","scope":17,"src":"293:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"},"typeName":{"id":14,"name":"uint64","nodeType":"ElementaryTypeName","src":"293:6:0","typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"visibility":"internal"}],"src":"292:14:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":27,"nodeType":"FunctionDefinition","src":"312:111:0","nodes":[],"functionSelector":"213e4198","implemented":false,"kind":"function","modifiers":[],"name":"parseJsonKeys","nameLocation":"321:13:0","parameters":{"id":22,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19,"mutability":"mutable","name":"json","nameLocation":"351:4:0","nodeType":"VariableDeclaration","scope":27,"src":"335:20:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":18,"name":"string","nodeType":"ElementaryTypeName","src":"335:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":21,"mutability":"mutable","name":"key","nameLocation":"373:3:0","nodeType":"VariableDeclaration","scope":27,"src":"357:19:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":20,"name":"string","nodeType":"ElementaryTypeName","src":"357:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"334:43:0"},"returnParameters":{"id":26,"nodeType":"ParameterList","parameters":[{"constant":false,"id":25,"mutability":"mutable","name":"keys","nameLocation":"417:4:0","nodeType":"VariableDeclaration","scope":27,"src":"401:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":23,"name":"string","nodeType":"ElementaryTypeName","src":"401:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":24,"nodeType":"ArrayTypeName","src":"401:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"src":"400:22:0"},"scope":83,"stateMutability":"pure","virtual":false,"visibility":"external"},{"id":32,"nodeType":"FunctionDefinition","src":"428:48:0","nodes":[],"functionSelector":"06447d56","implemented":false,"kind":"function","modifiers":[],"name":"startPrank","nameLocation":"437:10:0","parameters":{"id":30,"nodeType":"ParameterList","parameters":[{"constant":false,"id":29,"mutability":"mutable","name":"msgSender","nameLocation":"456:9:0","nodeType":"VariableDeclaration","scope":32,"src":"448:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":28,"name":"address","nodeType":"ElementaryTypeName","src":"448:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"447:19:0"},"returnParameters":{"id":31,"nodeType":"ParameterList","parameters":[],"src":"475:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":35,"nodeType":"FunctionDefinition","src":"481:30:0","nodes":[],"functionSelector":"90c5013b","implemented":false,"kind":"function","modifiers":[],"name":"stopPrank","nameLocation":"490:9:0","parameters":{"id":33,"nodeType":"ParameterList","parameters":[],"src":"499:2:0"},"returnParameters":{"id":34,"nodeType":"ParameterList","parameters":[],"src":"510:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":38,"nodeType":"FunctionDefinition","src":"516:30:0","nodes":[],"functionSelector":"afc98040","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"525:9:0","parameters":{"id":36,"nodeType":"ParameterList","parameters":[],"src":"534:2:0"},"returnParameters":{"id":37,"nodeType":"ParameterList","parameters":[],"src":"545:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":43,"nodeType":"FunctionDefinition","src":"551:47:0","nodes":[],"functionSelector":"e6962cdb","implemented":false,"kind":"function","modifiers":[],"name":"broadcast","nameLocation":"560:9:0","parameters":{"id":41,"nodeType":"ParameterList","parameters":[{"constant":false,"id":40,"mutability":"mutable","name":"msgSender","nameLocation":"578:9:0","nodeType":"VariableDeclaration","scope":43,"src":"570:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":39,"name":"address","nodeType":"ElementaryTypeName","src":"570:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"569:19:0"},"returnParameters":{"id":42,"nodeType":"ParameterList","parameters":[],"src":"597:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":48,"nodeType":"FunctionDefinition","src":"603:52:0","nodes":[],"functionSelector":"7fec2a8d","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"612:14:0","parameters":{"id":46,"nodeType":"ParameterList","parameters":[{"constant":false,"id":45,"mutability":"mutable","name":"msgSender","nameLocation":"635:9:0","nodeType":"VariableDeclaration","scope":48,"src":"627:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":44,"name":"address","nodeType":"ElementaryTypeName","src":"627:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"626:19:0"},"returnParameters":{"id":47,"nodeType":"ParameterList","parameters":[],"src":"654:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":51,"nodeType":"FunctionDefinition","src":"660:35:0","nodes":[],"functionSelector":"7fb5297f","implemented":false,"kind":"function","modifiers":[],"name":"startBroadcast","nameLocation":"669:14:0","parameters":{"id":49,"nodeType":"ParameterList","parameters":[],"src":"683:2:0"},"returnParameters":{"id":50,"nodeType":"ParameterList","parameters":[],"src":"694:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":54,"nodeType":"FunctionDefinition","src":"700:34:0","nodes":[],"functionSelector":"76eadd36","implemented":false,"kind":"function","modifiers":[],"name":"stopBroadcast","nameLocation":"709:13:0","parameters":{"id":52,"nodeType":"ParameterList","parameters":[],"src":"722:2:0"},"returnParameters":{"id":53,"nodeType":"ParameterList","parameters":[],"src":"733:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":61,"nodeType":"FunctionDefinition","src":"739:108:0","nodes":[],"functionSelector":"3ebf73b4","implemented":false,"kind":"function","modifiers":[],"name":"getDeployedCode","nameLocation":"748:15:0","parameters":{"id":57,"nodeType":"ParameterList","parameters":[{"constant":false,"id":56,"mutability":"mutable","name":"artifactPath","nameLocation":"780:12:0","nodeType":"VariableDeclaration","scope":61,"src":"764:28:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":55,"name":"string","nodeType":"ElementaryTypeName","src":"764:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"763:30:0"},"returnParameters":{"id":60,"nodeType":"ParameterList","parameters":[{"constant":false,"id":59,"mutability":"mutable","name":"runtimeBytecode","nameLocation":"830:15:0","nodeType":"VariableDeclaration","scope":61,"src":"817:28:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":58,"name":"bytes","nodeType":"ElementaryTypeName","src":"817:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"816:30:0"},"scope":83,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":68,"nodeType":"FunctionDefinition","src":"852:74:0","nodes":[],"functionSelector":"b4d6c782","implemented":false,"kind":"function","modifiers":[],"name":"etch","nameLocation":"861:4:0","parameters":{"id":66,"nodeType":"ParameterList","parameters":[{"constant":false,"id":63,"mutability":"mutable","name":"target","nameLocation":"874:6:0","nodeType":"VariableDeclaration","scope":68,"src":"866:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":62,"name":"address","nodeType":"ElementaryTypeName","src":"866:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":65,"mutability":"mutable","name":"newRuntimeBytecode","nameLocation":"897:18:0","nodeType":"VariableDeclaration","scope":68,"src":"882:33:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":64,"name":"bytes","nodeType":"ElementaryTypeName","src":"882:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"865:51:0"},"returnParameters":{"id":67,"nodeType":"ParameterList","parameters":[],"src":"925:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":73,"nodeType":"FunctionDefinition","src":"931:51:0","nodes":[],"functionSelector":"ea060291","implemented":false,"kind":"function","modifiers":[],"name":"allowCheatcodes","nameLocation":"940:15:0","parameters":{"id":71,"nodeType":"ParameterList","parameters":[{"constant":false,"id":70,"mutability":"mutable","name":"account","nameLocation":"964:7:0","nodeType":"VariableDeclaration","scope":73,"src":"956:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":69,"name":"address","nodeType":"ElementaryTypeName","src":"956:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"955:17:0"},"returnParameters":{"id":72,"nodeType":"ParameterList","parameters":[],"src":"981:0:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":82,"nodeType":"FunctionDefinition","src":"987:100:0","nodes":[],"functionSelector":"71ee464d","implemented":false,"kind":"function","modifiers":[],"name":"createSelectFork","nameLocation":"996:16:0","parameters":{"id":78,"nodeType":"ParameterList","parameters":[{"constant":false,"id":75,"mutability":"mutable","name":"forkName","nameLocation":"1029:8:0","nodeType":"VariableDeclaration","scope":82,"src":"1013:24:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":74,"name":"string","nodeType":"ElementaryTypeName","src":"1013:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":77,"mutability":"mutable","name":"blockNumber","nameLocation":"1047:11:0","nodeType":"VariableDeclaration","scope":82,"src":"1039:19:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":76,"name":"uint256","nodeType":"ElementaryTypeName","src":"1039:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1012:47:0"},"returnParameters":{"id":81,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":82,"src":"1078:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":79,"name":"uint256","nodeType":"ElementaryTypeName","src":"1078:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1077:9:0"},"scope":83,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"Vm","contractDependencies":[],"contractKind":"interface","fullyImplemented":false,"linearizedBaseContracts":[83],"name":"Vm","nameLocation":"130:2:0","scope":969,"usedErrors":[]},{"id":220,"nodeType":"ContractDefinition","src":"1144:1851:0","nodes":[{"id":89,"nodeType":"VariableDeclaration","src":"1166:86:0","nodes":[],"constant":true,"mutability":"constant","name":"CONSOLE_ADDRESS","nameLocation":"1183:15:0","scope":220,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":84,"name":"address","nodeType":"ElementaryTypeName","src":"1166:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"hexValue":"307830303030303030303030303030303030303036333646366537333646366336353265366336663637","id":87,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1209:42:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"value":"0x000000000000000000636F6e736F6c652e6c6f67"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":86,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":85,"name":"address","nodeType":"ElementaryTypeName","src":"1201:7:0","typeDescriptions":{}}},"id":88,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1201:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":106,"nodeType":"FunctionDefinition","src":"1259:235:0","nodes":[],"body":{"id":105,"nodeType":"Block","src":"1432:62:0","nodes":[],"statements":[{"AST":{"nodeType":"YulBlock","src":"1451:37:0","statements":[{"nodeType":"YulAssignment","src":"1465:13:0","value":{"name":"fnIn","nodeType":"YulIdentifier","src":"1474:4:0"},"variableNames":[{"name":"fnOut","nodeType":"YulIdentifier","src":"1465:5:0"}]}]},"evmVersion":"london","externalReferences":[{"declaration":95,"isOffset":false,"isSlot":false,"src":"1474:4:0","valueSize":1},{"declaration":102,"isOffset":false,"isSlot":false,"src":"1465:5:0","valueSize":1}],"id":104,"nodeType":"InlineAssembly","src":"1442:46:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_castLogPayloadViewToPure","nameLocation":"1268:25:0","parameters":{"id":96,"nodeType":"ParameterList","parameters":[{"constant":false,"id":95,"mutability":"mutable","name":"fnIn","nameLocation":"1331:4:0","nodeType":"VariableDeclaration","scope":106,"src":"1294:41:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"typeName":{"id":94,"nodeType":"FunctionTypeName","parameterTypes":{"id":92,"nodeType":"ParameterList","parameters":[{"constant":false,"id":91,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":94,"src":"1303:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":90,"name":"bytes","nodeType":"ElementaryTypeName","src":"1303:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1302:14:0"},"returnParameterTypes":{"id":93,"nodeType":"ParameterList","parameters":[],"src":"1331:0:0"},"src":"1294:41:0","stateMutability":"view","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) view"},"visibility":"internal"},"visibility":"internal"}],"src":"1293:43:0"},"returnParameters":{"id":103,"nodeType":"ParameterList","parameters":[{"constant":false,"id":102,"mutability":"mutable","name":"fnOut","nameLocation":"1421:5:0","nodeType":"VariableDeclaration","scope":106,"src":"1384:42:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"typeName":{"id":101,"nodeType":"FunctionTypeName","parameterTypes":{"id":99,"nodeType":"ParameterList","parameters":[{"constant":false,"id":98,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":101,"src":"1393:12:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":97,"name":"bytes","nodeType":"ElementaryTypeName","src":"1393:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1392:14:0"},"returnParameterTypes":{"id":100,"nodeType":"ParameterList","parameters":[],"src":"1421:0:0"},"src":"1384:42:0","stateMutability":"pure","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes) pure"},"visibility":"internal"},"visibility":"internal"}],"src":"1383:44:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":118,"nodeType":"FunctionDefinition","src":"1500:133:0","nodes":[],"body":{"id":117,"nodeType":"Block","src":"1561:72:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":114,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":108,"src":"1618:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"arguments":[{"id":112,"name":"_sendLogPayloadView","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":134,"src":"1597:19:0","typeDescriptions":{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_function_internal_view$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) view"}],"id":111,"name":"_castLogPayloadViewToPure","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":106,"src":"1571:25:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_function_internal_view$_t_bytes_memory_ptr_$returns$__$_$returns$_t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$_$","typeString":"function (function (bytes memory) view) pure returns (function (bytes memory) pure)"}},"id":113,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":115,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"1571:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":116,"nodeType":"ExpressionStatement","src":"1571:55:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayload","nameLocation":"1509:15:0","parameters":{"id":109,"nodeType":"ParameterList","parameters":[{"constant":false,"id":108,"mutability":"mutable","name":"payload","nameLocation":"1538:7:0","nodeType":"VariableDeclaration","scope":118,"src":"1525:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":107,"name":"bytes","nodeType":"ElementaryTypeName","src":"1525:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1524:22:0"},"returnParameters":{"id":110,"nodeType":"ParameterList","parameters":[],"src":"1561:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":134,"nodeType":"FunctionDefinition","src":"1639:380:0","nodes":[],"body":{"id":133,"nodeType":"Block","src":"1703:316:0","nodes":[],"statements":[{"assignments":[124],"declarations":[{"constant":false,"id":124,"mutability":"mutable","name":"payloadLength","nameLocation":"1721:13:0","nodeType":"VariableDeclaration","scope":133,"src":"1713:21:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":123,"name":"uint256","nodeType":"ElementaryTypeName","src":"1713:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":127,"initialValue":{"expression":{"id":125,"name":"payload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":120,"src":"1737:7:0","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"id":126,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"length","nodeType":"MemberAccess","src":"1737:14:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"1713:38:0"},{"assignments":[129],"declarations":[{"constant":false,"id":129,"mutability":"mutable","name":"consoleAddress","nameLocation":"1769:14:0","nodeType":"VariableDeclaration","scope":133,"src":"1761:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":128,"name":"address","nodeType":"ElementaryTypeName","src":"1761:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":131,"initialValue":{"id":130,"name":"CONSOLE_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":89,"src":"1786:15:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"1761:40:0"},{"AST":{"nodeType":"YulBlock","src":"1863:150:0","statements":[{"nodeType":"YulVariableDeclaration","src":"1877:36:0","value":{"arguments":[{"name":"payload","nodeType":"YulIdentifier","src":"1901:7:0"},{"kind":"number","nodeType":"YulLiteral","src":"1910:2:0","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1897:3:0"},"nodeType":"YulFunctionCall","src":"1897:16:0"},"variables":[{"name":"payloadStart","nodeType":"YulTypedName","src":"1881:12:0","type":""}]},{"nodeType":"YulVariableDeclaration","src":"1926:77:0","value":{"arguments":[{"arguments":[],"functionName":{"name":"gas","nodeType":"YulIdentifier","src":"1946:3:0"},"nodeType":"YulFunctionCall","src":"1946:5:0"},{"name":"consoleAddress","nodeType":"YulIdentifier","src":"1953:14:0"},{"name":"payloadStart","nodeType":"YulIdentifier","src":"1969:12:0"},{"name":"payloadLength","nodeType":"YulIdentifier","src":"1983:13:0"},{"kind":"number","nodeType":"YulLiteral","src":"1998:1:0","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"2001:1:0","type":"","value":"0"}],"functionName":{"name":"staticcall","nodeType":"YulIdentifier","src":"1935:10:0"},"nodeType":"YulFunctionCall","src":"1935:68:0"},"variables":[{"name":"r","nodeType":"YulTypedName","src":"1930:1:0","type":""}]}]},"documentation":"@solidity memory-safe-assembly","evmVersion":"london","externalReferences":[{"declaration":129,"isOffset":false,"isSlot":false,"src":"1953:14:0","valueSize":1},{"declaration":120,"isOffset":false,"isSlot":false,"src":"1901:7:0","valueSize":1},{"declaration":124,"isOffset":false,"isSlot":false,"src":"1983:13:0","valueSize":1}],"id":132,"nodeType":"InlineAssembly","src":"1854:159:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"_sendLogPayloadView","nameLocation":"1648:19:0","parameters":{"id":121,"nodeType":"ParameterList","parameters":[{"constant":false,"id":120,"mutability":"mutable","name":"payload","nameLocation":"1681:7:0","nodeType":"VariableDeclaration","scope":134,"src":"1668:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":119,"name":"bytes","nodeType":"ElementaryTypeName","src":"1668:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"1667:22:0"},"returnParameters":{"id":122,"nodeType":"ParameterList","parameters":[],"src":"1703:0:0"},"scope":220,"stateMutability":"view","virtual":false,"visibility":"private"},{"id":148,"nodeType":"FunctionDefinition","src":"2025:164:0","nodes":[],"body":{"id":147,"nodeType":"Block","src":"2070:119:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e6729","id":142,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2120:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},"value":"log(string)"},{"id":143,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":136,"src":"2135:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_41304facd9323d75b11bcdd609cb38effffdb05710f7caf0e9b16c6d9d709f50","typeString":"literal_string \"log(string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":140,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2096:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":141,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2096:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":144,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2096:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":139,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2080:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":145,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2080:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":146,"nodeType":"ExpressionStatement","src":"2080:59:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2034:3:0","parameters":{"id":137,"nodeType":"ParameterList","parameters":[{"constant":false,"id":136,"mutability":"mutable","name":"p0","nameLocation":"2052:2:0","nodeType":"VariableDeclaration","scope":148,"src":"2038:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":135,"name":"string","nodeType":"ElementaryTypeName","src":"2038:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2037:18:0"},"returnParameters":{"id":138,"nodeType":"ParameterList","parameters":[],"src":"2070:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":165,"nodeType":"FunctionDefinition","src":"2195:182:0","nodes":[],"body":{"id":164,"nodeType":"Block","src":"2249:128:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c626f6f6c29","id":158,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2299:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},"value":"log(string,bool)"},{"id":159,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":150,"src":"2319:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":160,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":152,"src":"2323:2:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_c3b556354c088fbb43886eb83c2a04bc7089663f964d22be308197a236f5b870","typeString":"literal_string \"log(string,bool)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":156,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2275:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":157,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2275:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":161,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2275:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":155,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2259:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":162,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2259:68:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":163,"nodeType":"ExpressionStatement","src":"2259:68:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2204:3:0","parameters":{"id":153,"nodeType":"ParameterList","parameters":[{"constant":false,"id":150,"mutability":"mutable","name":"p0","nameLocation":"2222:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2208:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":149,"name":"string","nodeType":"ElementaryTypeName","src":"2208:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":152,"mutability":"mutable","name":"p1","nameLocation":"2231:2:0","nodeType":"VariableDeclaration","scope":165,"src":"2226:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":151,"name":"bool","nodeType":"ElementaryTypeName","src":"2226:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"2207:27:0"},"returnParameters":{"id":154,"nodeType":"ParameterList","parameters":[],"src":"2249:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":182,"nodeType":"FunctionDefinition","src":"2383:188:0","nodes":[],"body":{"id":181,"nodeType":"Block","src":"2440:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c75696e7432353629","id":175,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2490:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},"value":"log(string,uint256)"},{"id":176,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":167,"src":"2513:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":177,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":169,"src":"2517:2:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b60e72ccf6d57ab53eb84d7e94a9545806ed7f93c4d5673f11a64f03471e584e","typeString":"literal_string \"log(string,uint256)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":173,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2466:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":174,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2466:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":178,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2466:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":172,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2450:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":179,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2450:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":180,"nodeType":"ExpressionStatement","src":"2450:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2392:3:0","parameters":{"id":170,"nodeType":"ParameterList","parameters":[{"constant":false,"id":167,"mutability":"mutable","name":"p0","nameLocation":"2410:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2396:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":166,"name":"string","nodeType":"ElementaryTypeName","src":"2396:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":169,"mutability":"mutable","name":"p1","nameLocation":"2422:2:0","nodeType":"VariableDeclaration","scope":182,"src":"2414:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":168,"name":"uint256","nodeType":"ElementaryTypeName","src":"2414:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"2395:30:0"},"returnParameters":{"id":171,"nodeType":"ParameterList","parameters":[],"src":"2440:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":199,"nodeType":"FunctionDefinition","src":"2577:188:0","nodes":[],"body":{"id":198,"nodeType":"Block","src":"2634:131:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c6164647265737329","id":192,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2684:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},"value":"log(string,address)"},{"id":193,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":184,"src":"2707:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":194,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":186,"src":"2711:2:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_319af333460570a1937bf195dd33445c0d0951c59127da6f1f038b9fdce3fd72","typeString":"literal_string \"log(string,address)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":190,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2660:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":191,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2660:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":195,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2660:54:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":189,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2644:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":196,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2644:71:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":197,"nodeType":"ExpressionStatement","src":"2644:71:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2586:3:0","parameters":{"id":187,"nodeType":"ParameterList","parameters":[{"constant":false,"id":184,"mutability":"mutable","name":"p0","nameLocation":"2604:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2590:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":183,"name":"string","nodeType":"ElementaryTypeName","src":"2590:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":186,"mutability":"mutable","name":"p1","nameLocation":"2616:2:0","nodeType":"VariableDeclaration","scope":199,"src":"2608:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":185,"name":"address","nodeType":"ElementaryTypeName","src":"2608:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"2589:30:0"},"returnParameters":{"id":188,"nodeType":"ParameterList","parameters":[],"src":"2634:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":219,"nodeType":"FunctionDefinition","src":"2771:222:0","nodes":[],"body":{"id":218,"nodeType":"Block","src":"2852:141:0","nodes":[],"statements":[{"expression":{"arguments":[{"arguments":[{"hexValue":"6c6f6728737472696e672c737472696e672c737472696e6729","id":211,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"2902:27:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},"value":"log(string,string,string)"},{"id":212,"name":"p0","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":201,"src":"2931:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":213,"name":"p1","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":203,"src":"2935:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"id":214,"name":"p2","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":205,"src":"2939:2:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2ced7cef693312206c21f0e92e3b54e2e16bf33db5eec350c78866822c665e1f","typeString":"literal_string \"log(string,string,string)\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":209,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"2878:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":210,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberName":"encodeWithSignature","nodeType":"MemberAccess","src":"2878:23:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) pure returns (bytes memory)"}},"id":215,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2878:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":208,"name":"_sendLogPayload","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"2862:15:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory) pure"}},"id":216,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"2862:81:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":217,"nodeType":"ExpressionStatement","src":"2862:81:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"log","nameLocation":"2780:3:0","parameters":{"id":206,"nodeType":"ParameterList","parameters":[{"constant":false,"id":201,"mutability":"mutable","name":"p0","nameLocation":"2798:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2784:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":200,"name":"string","nodeType":"ElementaryTypeName","src":"2784:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":203,"mutability":"mutable","name":"p1","nameLocation":"2816:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2802:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":202,"name":"string","nodeType":"ElementaryTypeName","src":"2802:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"},{"constant":false,"id":205,"mutability":"mutable","name":"p2","nameLocation":"2834:2:0","nodeType":"VariableDeclaration","scope":219,"src":"2820:16:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":204,"name":"string","nodeType":"ElementaryTypeName","src":"2820:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"2783:54:0"},"returnParameters":{"id":207,"nodeType":"ParameterList","parameters":[],"src":"2852:0:0"},"scope":220,"stateMutability":"pure","virtual":false,"visibility":"internal"}],"abstract":false,"baseContracts":[],"canonicalName":"console","contractDependencies":[],"contractKind":"library","fullyImplemented":true,"linearizedBaseContracts":[220],"name":"console","nameLocation":"1152:7:0","scope":969,"usedErrors":[]},{"id":786,"nodeType":"ContractDefinition","src":"3123:3912:0","nodes":[{"id":235,"nodeType":"VariableDeclaration","src":"3152:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"3178:10:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":222,"name":"address","nodeType":"ElementaryTypeName","src":"3152:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":230,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3225:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":229,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"3215:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":231,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3215:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":228,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3207:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":227,"name":"uint256","nodeType":"ElementaryTypeName","src":"3207:7:0","typeDescriptions":{}}},"id":232,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3207:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":226,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3199:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":225,"name":"uint160","nodeType":"ElementaryTypeName","src":"3199:7:0","typeDescriptions":{}}},"id":233,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3199:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":224,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3191:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":223,"name":"address","nodeType":"ElementaryTypeName","src":"3191:7:0","typeDescriptions":{}}},"id":234,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3191:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":241,"nodeType":"VariableDeclaration","src":"3252:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"3273:2:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":237,"nodeType":"UserDefinedTypeName","pathNode":{"id":236,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"3252:2:0"},"referencedDeclaration":83,"src":"3252:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":239,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":235,"src":"3281:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":238,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"3278:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":240,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3278:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":243,"nodeType":"VariableDeclaration","src":"3356:22:0","nodes":[],"constant":false,"functionSelector":"61bc221a","mutability":"mutable","name":"counter","nameLocation":"3371:7:0","scope":786,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":242,"name":"uint256","nodeType":"ElementaryTypeName","src":"3356:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":456,"nodeType":"FunctionDefinition","src":"3468:1428:0","nodes":[],"body":{"id":455,"nodeType":"Block","src":"3490:1406:0","nodes":[],"statements":[{"assignments":[248],"declarations":[{"constant":false,"id":248,"mutability":"mutable","name":"x","nameLocation":"3505:1:0","nodeType":"VariableDeclaration","scope":455,"src":"3500:6:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":247,"name":"bool","nodeType":"ElementaryTypeName","src":"3500:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"id":254,"initialValue":{"arguments":[{"hexValue":"4558414d504c455f424f4f4c","id":251,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3518:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},"value":"EXAMPLE_BOOL"},{"hexValue":"66616c7365","id":252,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"3534:5:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a634dae177a0e138ae7aaa2afae347412e148992e88c7aabd33ee71be146cb7f","typeString":"literal_string \"EXAMPLE_BOOL\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":249,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3509:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":250,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"envOr","nodeType":"MemberAccess","referencedDeclaration":10,"src":"3509:8:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$_t_bool_$returns$_t_bool_$","typeString":"function (string memory,bool) view external returns (bool)"}},"id":253,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3509:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"VariableDeclarationStatement","src":"3500:40:0"},{"expression":{"arguments":[{"hexValue":"626f6f6c2076616c75652066726f6d20656e76","id":258,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3562:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},"value":"bool value from env"},{"id":259,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":248,"src":"3585:1:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5a607d0b5a1295325aa8901721d78ba402601bba6f62cebdd5235dd0204a590b","typeString":"literal_string \"bool value from env\""},{"typeIdentifier":"t_bool","typeString":"bool"}],"expression":{"id":255,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3550:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":257,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":165,"src":"3550:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_bool_$returns$__$","typeString":"function (string memory,bool) pure"}},"id":260,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3550:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":261,"nodeType":"ExpressionStatement","src":"3550:37:0"},{"expression":{"arguments":[{"hexValue":"636f6e74726163742061646472","id":265,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3610:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},"value":"contract addr"},{"arguments":[{"id":268,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3635:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":267,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3627:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":266,"name":"address","nodeType":"ElementaryTypeName","src":"3627:7:0","typeDescriptions":{}}},"id":269,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3627:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa50728770d00fe8f6a0592f3565bbfaf063ee4077f1f5bbc003d091d33cd0c4","typeString":"literal_string \"contract addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":262,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3598:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":264,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3598:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":270,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3598:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":271,"nodeType":"ExpressionStatement","src":"3598:43:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206e6f6e6365","id":275,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3663:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},"value":"contract nonce"},{"arguments":[{"arguments":[{"id":280,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"3701:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":279,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3693:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":278,"name":"address","nodeType":"ElementaryTypeName","src":"3693:7:0","typeDescriptions":{}}},"id":281,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3693:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":276,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3681:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":277,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3681:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":282,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3681:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_3a23091615a5de8c0a35ffd8857a37e2c4e0b72f3ef8a34d6caf65efcd562e2f","typeString":"literal_string \"contract nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":272,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3651:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":274,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3651:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":283,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3651:57:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":284,"nodeType":"ExpressionStatement","src":"3651:57:0"},{"expression":{"arguments":[{"hexValue":"73656e6465722061646472","id":288,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3730:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},"value":"sender addr"},{"arguments":[{"expression":{"id":291,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3753:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":292,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3753:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":290,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3745:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":289,"name":"address","nodeType":"ElementaryTypeName","src":"3745:7:0","typeDescriptions":{}}},"id":293,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3745:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8125ca2decf812b25b65606ff16dad37cb198ff0433485a7926e50feafacfc35","typeString":"literal_string \"sender addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":285,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3718:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":287,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"3718:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":294,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3718:47:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":295,"nodeType":"ExpressionStatement","src":"3718:47:0"},{"expression":{"arguments":[{"hexValue":"73656e646572206e6f6e6365","id":299,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3787:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},"value":"sender nonce"},{"arguments":[{"arguments":[{"expression":{"id":304,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"3823:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":305,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"3823:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":303,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"3815:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":302,"name":"address","nodeType":"ElementaryTypeName","src":"3815:7:0","typeDescriptions":{}}},"id":306,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3815:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":300,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3803:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":301,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"3803:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":307,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3803:32:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_db7deb43f2f9e0404016de53b7e64c4976b54149581f7534daae2551e8cf4e40","typeString":"literal_string \"sender nonce\""},{"typeIdentifier":"t_uint64","typeString":"uint64"}],"expression":{"id":296,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3775:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":298,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"3775:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":308,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3775:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":309,"nodeType":"ExpressionStatement","src":"3775:61:0"},{"assignments":[311],"declarations":[{"constant":false,"id":311,"mutability":"mutable","name":"json","nameLocation":"3861:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3847:18:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string"},"typeName":{"id":310,"name":"string","nodeType":"ElementaryTypeName","src":"3847:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"id":313,"initialValue":{"hexValue":"7b22726f6f745f6b6579223a205b7b2261223a20312c202262223a20327d5d7d","id":312,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3868:34:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_e95522e99766888d0261f55bd1eae5e3f3e26eaf009a16e2433eafaf0a4ecdf2","typeString":"literal_string \"{\"root_key\": [{\"a\": 1, \"b\": 2}]}\""},"value":"{\"root_key\": [{\"a\": 1, \"b\": 2}]}"},"nodeType":"VariableDeclarationStatement","src":"3847:55:0"},{"assignments":[318],"declarations":[{"constant":false,"id":318,"mutability":"mutable","name":"keys","nameLocation":"3928:4:0","nodeType":"VariableDeclaration","scope":455,"src":"3912:20:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string[]"},"typeName":{"baseType":{"id":316,"name":"string","nodeType":"ElementaryTypeName","src":"3912:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"id":317,"nodeType":"ArrayTypeName","src":"3912:8:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_storage_$dyn_storage_ptr","typeString":"string[]"}},"visibility":"internal"}],"id":324,"initialValue":{"arguments":[{"id":321,"name":"json","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":311,"src":"3952:4:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"hexValue":"2e726f6f745f6b65795b305d","id":322,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3958:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""},"value":".root_key[0]"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_stringliteral_d82f67100edb80050915e1ec4b565c9a8319a22efb1075e1298b7bb60101d266","typeString":"literal_string \".root_key[0]\""}],"expression":{"id":319,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"3935:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":320,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"parseJsonKeys","nodeType":"MemberAccess","referencedDeclaration":27,"src":"3935:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$_t_array$_t_string_memory_ptr_$dyn_memory_ptr_$","typeString":"function (string memory,string memory) pure external returns (string memory[] memory)"}},"id":323,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3935:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"nodeType":"VariableDeclarationStatement","src":"3912:61:0"},{"expression":{"arguments":[{"hexValue":"6b657973","id":328,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"3995:6:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},"value":"keys"},{"baseExpression":{"id":329,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4003:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":331,"indexExpression":{"hexValue":"30","id":330,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4008:1:0","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4003:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}},{"baseExpression":{"id":332,"name":"keys","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":318,"src":"4012:4:0","typeDescriptions":{"typeIdentifier":"t_array$_t_string_memory_ptr_$dyn_memory_ptr","typeString":"string memory[] memory"}},"id":334,"indexExpression":{"hexValue":"31","id":333,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4017:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"isConstant":false,"isLValue":true,"isPure":false,"lValueRequested":false,"nodeType":"IndexAccess","src":"4012:7:0","typeDescriptions":{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f29790a80c4ce5f42f59892f424f9c92856c6b656c3378e2cf305b260c6f4195","typeString":"literal_string \"keys\""},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"},{"typeIdentifier":"t_string_memory_ptr","typeString":"string memory"}],"expression":{"id":325,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"3983:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":327,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":219,"src":"3983:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_string_memory_ptr_$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory,string memory,string memory) pure"}},"id":335,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"3983:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":336,"nodeType":"ExpressionStatement","src":"3983:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c","id":340,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4042:15:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""},"value":"from original"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_77928970c8757d110f3c23e003246f49e0de890480ba9717ba659b2f56f316b2","typeString":"literal_string \"from original\""}],"expression":{"id":337,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4031:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":339,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4031:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":341,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4031:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":342,"nodeType":"ExpressionStatement","src":"4031:27:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"30783432","id":350,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"4098:4:0","typeDescriptions":{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"},"value":"0x42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_66_by_1","typeString":"int_const 66"}],"id":349,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4090:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":348,"name":"uint160","nodeType":"ElementaryTypeName","src":"4090:7:0","typeDescriptions":{}}},"id":351,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4090:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":347,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4082:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":346,"name":"address","nodeType":"ElementaryTypeName","src":"4082:7:0","typeDescriptions":{}}},"id":352,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4082:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":343,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4068:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":345,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startPrank","nodeType":"MemberAccess","referencedDeclaration":32,"src":"4068:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":353,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4068:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":354,"nodeType":"ExpressionStatement","src":"4068:37:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2031","id":358,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4126:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""},"value":"from prank 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_42b34abfe37a8b0add910cda7b4a379e6538fa7a1dcafce47a02bd38f6c88e2a","typeString":"literal_string \"from prank 1\""}],"expression":{"id":355,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4115:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":357,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4115:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":359,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4115:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":360,"nodeType":"ExpressionStatement","src":"4115:26:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f7065206d73672e73656e646572","id":364,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4163:25:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},"value":"parent scope msg.sender"},{"arguments":[{"expression":{"id":367,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"4198:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":368,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"4198:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":366,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4190:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":365,"name":"address","nodeType":"ElementaryTypeName","src":"4190:7:0","typeDescriptions":{}}},"id":369,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4190:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_83ec9246154d8845de47aafc5c2865c9985d2efe84472c27283879f2fbf5cc94","typeString":"literal_string \"parent scope msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":361,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4151:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":363,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4151:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":370,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4151:59:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":371,"nodeType":"ExpressionStatement","src":"4151:59:0"},{"expression":{"arguments":[{"hexValue":"706172656e742073636f706520636f6e74726163742e61646472","id":375,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4232:28:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},"value":"parent scope contract.addr"},{"arguments":[{"id":378,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4270:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":377,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4262:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":376,"name":"address","nodeType":"ElementaryTypeName","src":"4262:7:0","typeDescriptions":{}}},"id":379,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4262:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_97df66250e0b2b48f0ec8d0e01eb1b8ca012d95f1572895622aa1ea433e5570f","typeString":"literal_string \"parent scope contract.addr\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":372,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4220:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":374,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"4220:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":380,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4220:56:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":381,"nodeType":"ExpressionStatement","src":"4220:56:0"},{"expression":{"arguments":[{"hexValue":"66726f6d207072616e6b2032","id":385,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4297:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""},"value":"from prank 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_a38a34f8cad750a79aa097a92971f8f405b51ee9d53d25c5b14fc129ba3684bb","typeString":"literal_string \"from prank 2\""}],"expression":{"id":382,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4286:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":384,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4286:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":386,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4286:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":387,"nodeType":"ExpressionStatement","src":"4286:26:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":388,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4322:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":390,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopPrank","nodeType":"MemberAccess","referencedDeclaration":35,"src":"4322:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":391,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4322:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":392,"nodeType":"ExpressionStatement","src":"4322:14:0"},{"expression":{"arguments":[{"hexValue":"66726f6d206f726967696e616c20616761696e","id":396,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4357:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""},"value":"from original again"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_0c805c6579e20a9c4c8e11aeab23330910a9f2da629191dc119d1730e8ed6860","typeString":"literal_string \"from original again\""}],"expression":{"id":393,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4346:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":395,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"hello","nodeType":"MemberAccess","referencedDeclaration":713,"src":"4346:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) view external"}},"id":397,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4346:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":398,"nodeType":"ExpressionStatement","src":"4346:33:0"},{"assignments":[400],"declarations":[{"constant":false,"id":400,"mutability":"mutable","name":"tmpNonceGetter","nameLocation":"4480:14:0","nodeType":"VariableDeclaration","scope":455,"src":"4472:22:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":399,"name":"address","nodeType":"ElementaryTypeName","src":"4472:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":413,"initialValue":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"74656d70206e6f6e6365207465737420676574746572","id":408,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4531:24:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""},"value":"temp nonce test getter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_12520bf22cf2eb7252f13fda2b7eb7ddaed1b3456e20c8008c714c7ba4d9a252","typeString":"literal_string \"temp nonce test getter\""}],"id":407,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"4521:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":409,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4521:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":406,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4513:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":405,"name":"uint256","nodeType":"ElementaryTypeName","src":"4513:7:0","typeDescriptions":{}}},"id":410,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4513:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":404,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4505:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":403,"name":"uint160","nodeType":"ElementaryTypeName","src":"4505:7:0","typeDescriptions":{}}},"id":411,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4505:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":402,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4497:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":401,"name":"address","nodeType":"ElementaryTypeName","src":"4497:7:0","typeDescriptions":{}}},"id":412,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4497:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"4472:87:0"},{"expression":{"arguments":[{"id":417,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4577:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"arguments":[{"hexValue":"5363726970744578616d706c652e732e736f6c3a4e6f6e6365476574746572","id":420,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4612:33:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""},"value":"ScriptExample.s.sol:NonceGetter"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_6ff7ab2e79e6b7d182bbfccfe7f8e2118d655ff1b4bf1a4f4ed2eab0f3f8c825","typeString":"literal_string \"ScriptExample.s.sol:NonceGetter\""}],"expression":{"id":418,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4593:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":419,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getDeployedCode","nodeType":"MemberAccess","referencedDeclaration":61,"src":"4593:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$","typeString":"function (string memory) view external returns (bytes memory)"}},"id":421,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4593:53:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"expression":{"id":414,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4569:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":416,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"etch","nodeType":"MemberAccess","referencedDeclaration":68,"src":"4569:7:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$_t_bytes_memory_ptr_$returns$__$","typeString":"function (address,bytes memory) external"}},"id":422,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4569:78:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":423,"nodeType":"ExpressionStatement","src":"4569:78:0"},{"expression":{"arguments":[{"id":427,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4676:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":424,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"4657:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":426,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"allowCheatcodes","nodeType":"MemberAccess","referencedDeclaration":73,"src":"4657:18:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":428,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4657:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":429,"nodeType":"ExpressionStatement","src":"4657:34:0"},{"assignments":[431],"declarations":[{"constant":false,"id":431,"mutability":"mutable","name":"v","nameLocation":"4709:1:0","nodeType":"VariableDeclaration","scope":455,"src":"4701:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":430,"name":"uint256","nodeType":"ElementaryTypeName","src":"4701:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":441,"initialValue":{"arguments":[{"arguments":[{"id":438,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"4758:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":437,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"4750:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":436,"name":"address","nodeType":"ElementaryTypeName","src":"4750:7:0","typeDescriptions":{}}},"id":439,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4750:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"arguments":[{"id":433,"name":"tmpNonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":400,"src":"4725:14:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":432,"name":"NonceGetter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":833,"src":"4713:11:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_NonceGetter_$833_$","typeString":"type(contract NonceGetter)"}},"id":434,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:27:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_NonceGetter_$833","typeString":"contract NonceGetter"}},"id":435,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":832,"src":"4713:36:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint256_$","typeString":"function (address) view external returns (uint256)"}},"id":440,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4713:51:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"VariableDeclarationStatement","src":"4701:63:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e63652066726f6d206e6f6e6365206765747465722c206e6f206578706c6963697420616363657373207265717569726564207769746820766d2e657463683a","id":445,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4786:68:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},"value":"nonce from nonce getter, no explicit access required with vm.etch:"},{"id":446,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":431,"src":"4856:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_afafcfffb72f22a98864f79a750e1a4a41d7dd81365e873e06ff57a1a9f42b11","typeString":"literal_string \"nonce from nonce getter, no explicit access required with vm.etch:\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":442,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4774:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":444,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"4774:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":447,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4774:84:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":448,"nodeType":"ExpressionStatement","src":"4774:84:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":452,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"4881:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":449,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"4869:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":451,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"4869:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":453,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"4869:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":454,"nodeType":"ExpressionStatement","src":"4869:20:0"}]},"documentation":{"id":244,"nodeType":"StructuredDocumentation","src":"3385:78:0","text":"@notice example function, runs through basic cheat-codes and console logs."},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"3477:3:0","parameters":{"id":245,"nodeType":"ParameterList","parameters":[],"src":"3480:2:0"},"returnParameters":{"id":246,"nodeType":"ParameterList","parameters":[],"src":"3490:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":689,"nodeType":"FunctionDefinition","src":"4963:1333:0","nodes":[],"body":{"id":688,"nodeType":"Block","src":"4994:1302:0","nodes":[],"statements":[{"expression":{"arguments":[{"hexValue":"6e6f6e6365207374617274","id":463,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5016:13:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},"value":"nonce start"},{"arguments":[{"arguments":[{"arguments":[{"id":470,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5059:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":469,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5051:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":468,"name":"address","nodeType":"ElementaryTypeName","src":"5051:7:0","typeDescriptions":{}}},"id":471,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5051:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":466,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5039:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":467,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"5039:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":472,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5039:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":465,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5031:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":464,"name":"uint256","nodeType":"ElementaryTypeName","src":"5031:7:0","typeDescriptions":{}}},"id":473,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5031:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_71efc69b9a13b6bc1e9a14d766ff01c79022262c6daa6532fb5dfb14f8511a20","typeString":"literal_string \"nonce start\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":460,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5004:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":462,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"5004:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":474,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5004:63:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":475,"nodeType":"ExpressionStatement","src":"5004:63:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073696e676c65","id":479,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5090:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""},"value":"testing single"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b75103528423218e7569082dad569ed0d2ce7c0ac770c0812b220e2d369fe474","typeString":"literal_string \"testing single\""}],"expression":{"id":476,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5078:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":478,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5078:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":480,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5078:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":481,"nodeType":"ExpressionStatement","src":"5078:29:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":482,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5117:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":484,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"5117:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":485,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5117:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":486,"nodeType":"ExpressionStatement","src":"5117:14:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c31","id":490,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5152:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""},"value":"single_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_5e1cad6d7a968cfacf2731373e1248ffb11f4886bced66a02a6de1a67ac8f777","typeString":"literal_string \"single_call1\""}],"expression":{"id":487,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5141:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":489,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5141:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":491,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5141:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":492,"nodeType":"ExpressionStatement","src":"5141:26:0"},{"expression":{"arguments":[{"hexValue":"73696e676c655f63616c6c32","id":496,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5188:14:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""},"value":"single_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b37ddaf5d00ad9e6371de3fb71b91eef731fae1e86b768666380f7d44e1ada25","typeString":"literal_string \"single_call2\""}],"expression":{"id":493,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5177:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":495,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5177:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":497,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5177:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":498,"nodeType":"ExpressionStatement","src":"5177:26:0"},{"expression":{"arguments":[{"hexValue":"74657374696e672073746172742f73746f70","id":502,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5226:20:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""},"value":"testing start/stop"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_778e886e3a1c3c5096aca76228832105f3f9269f362effd0e8ce3737787cb784","typeString":"literal_string \"testing start/stop\""}],"expression":{"id":499,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5214:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":501,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5214:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":503,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5214:33:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":504,"nodeType":"ExpressionStatement","src":"5214:33:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078633066666565","id":512,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5291:8:0","typeDescriptions":{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"},"value":"0xc0ffee"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_12648430_by_1","typeString":"int_const 12648430"}],"id":511,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5283:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":510,"name":"uint160","nodeType":"ElementaryTypeName","src":"5283:7:0","typeDescriptions":{}}},"id":513,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5283:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":509,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5275:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":508,"name":"address","nodeType":"ElementaryTypeName","src":"5275:7:0","typeDescriptions":{}}},"id":514,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5275:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":505,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5257:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":507,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5257:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":515,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5257:45:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":516,"nodeType":"ExpressionStatement","src":"5257:45:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c31","id":520,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5323:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""},"value":"startstop_call1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_2fc2682edf10ed478ee3b9a190f6b1c88bb492b300935ce44545a1613cf8f041","typeString":"literal_string \"startstop_call1\""}],"expression":{"id":517,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5312:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":519,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5312:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":521,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5312:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":522,"nodeType":"ExpressionStatement","src":"5312:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c32","id":526,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5362:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""},"value":"startstop_call2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_1a6fd77f04b28bf45d6d0e2dd4c65c0bbfeba174f849e43bb67ebca1c019cda4","typeString":"literal_string \"startstop_call2\""}],"expression":{"id":523,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5351:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":525,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call2","nodeType":"MemberAccess","referencedDeclaration":743,"src":"5351:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":527,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5351:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":528,"nodeType":"ExpressionStatement","src":"5351:29:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f70757265","id":532,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5404:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""},"value":"startstop_pure"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6e9eb1efd186b1d92b54da45026aa97a178e6eaffdf9dbf9f666fc751fb0ff9","typeString":"literal_string \"startstop_pure\""}],"expression":{"id":529,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5390:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":531,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"callPure","nodeType":"MemberAccess","referencedDeclaration":785,"src":"5390:13:0","typeDescriptions":{"typeIdentifier":"t_function_external_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure external"}},"id":533,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5390:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":534,"nodeType":"ExpressionStatement","src":"5390:31:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":535,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5431:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":537,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5431:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":538,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5431:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":539,"nodeType":"ExpressionStatement","src":"5431:18:0"},{"expression":{"arguments":[{"hexValue":"737461727473746f705f63616c6c33","id":543,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5470:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""},"value":"startstop_call3"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_8eb502bfdc4adda22bd960aa2ae13ce4c0ed8cc3b3791ed65e321a38cdd36f72","typeString":"literal_string \"startstop_call3\""}],"expression":{"id":540,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5459:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":542,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"call1","nodeType":"MemberAccess","referencedDeclaration":728,"src":"5459:10:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":544,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5459:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":545,"nodeType":"ExpressionStatement","src":"5459:29:0"},{"expression":{"arguments":[{"hexValue":"74657374696e67206e6573746564","id":549,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5511:16:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""},"value":"testing nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_f92f19f7a5b5b9ce341188bf4e15925f184cdb5ac135c4846ced718f259dbde5","typeString":"literal_string \"testing nested\""}],"expression":{"id":546,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5499:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":548,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5499:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":550,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5499:29:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":551,"nodeType":"ExpressionStatement","src":"5499:29:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307831323334","id":559,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5572:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":558,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5564:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":557,"name":"uint160","nodeType":"ElementaryTypeName","src":"5564:7:0","typeDescriptions":{}}},"id":560,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5564:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":556,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5556:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":555,"name":"address","nodeType":"ElementaryTypeName","src":"5556:7:0","typeDescriptions":{}}},"id":561,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5556:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":552,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5538:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":554,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"startBroadcast","nodeType":"MemberAccess","referencedDeclaration":48,"src":"5538:17:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":562,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5538:43:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":563,"nodeType":"ExpressionStatement","src":"5538:43:0"},{"expression":{"arguments":[{"hexValue":"6e6573746564","id":567,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5604:8:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""},"value":"nested"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4d5b14044d78fbf0c9dd8b9c49e35f09ee5a6f5b1b3b8117b5d0e15c8dd2cb09","typeString":"literal_string \"nested\""}],"expression":{"id":564,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"5591:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":566,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested1","nodeType":"MemberAccess","referencedDeclaration":758,"src":"5591:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":568,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5591:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":569,"nodeType":"ExpressionStatement","src":"5591:22:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":570,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5623:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":572,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"stopBroadcast","nodeType":"MemberAccess","referencedDeclaration":54,"src":"5623:16:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":573,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5623:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":574,"nodeType":"ExpressionStatement","src":"5623:18:0"},{"expression":{"arguments":[{"hexValue":"636f6e7472616374206465706c6f796d656e74","id":578,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5664:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""},"value":"contract deployment"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_aaf9be86adf9b6872d87eed3526f7c55f3c5d61f4e4dd6d55ef2fcbb8ad0bd57","typeString":"literal_string \"contract deployment\""}],"expression":{"id":575,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5652:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":577,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5652:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":579,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5652:34:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":580,"nodeType":"ExpressionStatement","src":"5652:34:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"3078313233343536","id":588,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5725:8:0","typeDescriptions":{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"},"value":"0x123456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1193046_by_1","typeString":"int_const 1193046"}],"id":587,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5717:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":586,"name":"uint160","nodeType":"ElementaryTypeName","src":"5717:7:0","typeDescriptions":{}}},"id":589,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5717:17:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":585,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5709:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":584,"name":"address","nodeType":"ElementaryTypeName","src":"5709:7:0","typeDescriptions":{}}},"id":590,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5709:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":581,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5696:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":583,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5696:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":591,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5696:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":592,"nodeType":"ExpressionStatement","src":"5696:40:0"},{"assignments":[595],"declarations":[{"constant":false,"id":595,"mutability":"mutable","name":"x","nameLocation":"5753:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5746:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":594,"nodeType":"UserDefinedTypeName","pathNode":{"id":593,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5746:6:0"},"referencedDeclaration":799,"src":"5746:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":601,"initialValue":{"arguments":[{"hexValue":"31323334","id":599,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5768:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":598,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5757:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":597,"nodeType":"UserDefinedTypeName","pathNode":{"id":596,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5761:6:0"},"referencedDeclaration":799,"src":"5761:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":600,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5757:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5746:27:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":607,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":603,"name":"x","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":595,"src":"5791:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":604,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"5791:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":605,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5791:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":606,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5802:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"5791:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e20637265617465206973206e6f742031323334","id":608,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5808:35:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""},"value":"FooBar: foo in create is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_cf44a206a1b0f98235522779025d2df914f464e764b8c79ccaa1efde72c4831c","typeString":"literal_string \"FooBar: foo in create is not 1234\""}],"id":602,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"5783:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":609,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5783:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":610,"nodeType":"ExpressionStatement","src":"5783:61:0"},{"expression":{"arguments":[{"hexValue":"6372656174652032","id":614,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"5867:10:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""},"value":"create 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_4411d6d4ffcd00382a95255a63761e69de9810e1236042a5c64948a7b6c04daa","typeString":"literal_string \"create 2\""}],"expression":{"id":611,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"5855:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":613,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"5855:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":615,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5855:23:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":616,"nodeType":"ExpressionStatement","src":"5855:23:0"},{"expression":{"arguments":[{"arguments":[{"arguments":[{"hexValue":"307863616665","id":624,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5917:6:0","typeDescriptions":{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"},"value":"0xcafe"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_51966_by_1","typeString":"int_const 51966"}],"id":623,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5909:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":622,"name":"uint160","nodeType":"ElementaryTypeName","src":"5909:7:0","typeDescriptions":{}}},"id":625,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5909:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":621,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5901:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":620,"name":"address","nodeType":"ElementaryTypeName","src":"5901:7:0","typeDescriptions":{}}},"id":626,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5901:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":617,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"5888:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":619,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":43,"src":"5888:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_address_$returns$__$","typeString":"function (address) external"}},"id":627,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5888:38:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":628,"nodeType":"ExpressionStatement","src":"5888:38:0"},{"assignments":[631],"declarations":[{"constant":false,"id":631,"mutability":"mutable","name":"y","nameLocation":"5943:1:0","nodeType":"VariableDeclaration","scope":688,"src":"5936:8:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"},"typeName":{"id":630,"nodeType":"UserDefinedTypeName","pathNode":{"id":629,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5936:6:0"},"referencedDeclaration":799,"src":"5936:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"visibility":"internal"}],"id":645,"initialValue":{"arguments":[{"hexValue":"31323334","id":643,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5986:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":634,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"5947:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":633,"nodeType":"UserDefinedTypeName","pathNode":{"id":632,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"5951:6:0"},"referencedDeclaration":799,"src":"5951:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":642,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"names":["salt"],"nodeType":"FunctionCallOptions","options":[{"arguments":[{"arguments":[{"hexValue":"3432","id":639,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"5980:2:0","typeDescriptions":{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"},"value":"42"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_42_by_1","typeString":"int_const 42"}],"id":638,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5972:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":637,"name":"uint256","nodeType":"ElementaryTypeName","src":"5972:7:0","typeDescriptions":{}}},"id":640,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5972:11:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":636,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"5964:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":635,"name":"bytes32","nodeType":"ElementaryTypeName","src":"5964:7:0","typeDescriptions":{}}},"id":641,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5964:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"src":"5947:38:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$salt","typeString":"function (uint256) returns (contract FooBar)"}},"id":644,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"5947:44:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"nodeType":"VariableDeclarationStatement","src":"5936:55:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":651,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":647,"name":"y","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":631,"src":"6009:1:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":648,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"foo","nodeType":"MemberAccess","referencedDeclaration":788,"src":"6009:5:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":649,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6009:7:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31323334","id":650,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6020:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"},"src":"6009:15:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"466f6f4261723a20666f6f20696e2063726561746532206973206e6f742031323334","id":652,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6026:36:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""},"value":"FooBar: foo in create2 is not 1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_a532f8073e029b895a819f6b1992843ca1cc824c13ad4c6484e05780ac0a57b9","typeString":"literal_string \"FooBar: foo in create2 is not 1234\""}],"id":646,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"6001:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":653,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6001:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":654,"nodeType":"ExpressionStatement","src":"6001:62:0"},{"expression":{"arguments":[{"hexValue":"646f6e6521","id":658,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6085:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""},"value":"done!"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_080382d5c9e9e7c5e3d1d33f5e7422740375955180fadff167d8130e0c35f3fc","typeString":"literal_string \"done!\""}],"expression":{"id":655,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6073:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":657,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6073:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":659,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6073:20:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":660,"nodeType":"ExpressionStatement","src":"6073:20:0"},{"expression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":661,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6177:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":663,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"broadcast","nodeType":"MemberAccess","referencedDeclaration":38,"src":"6177:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$__$returns$__$","typeString":"function () external"}},"id":664,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6177:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":665,"nodeType":"ExpressionStatement","src":"6177:14:0"},{"expression":{"arguments":[{"hexValue":"31323334","id":669,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"6212:4:0","typeDescriptions":{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"},"value":"1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1234_by_1","typeString":"int_const 1234"}],"id":668,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"NewExpression","src":"6201:10:0","typeDescriptions":{"typeIdentifier":"t_function_creation_nonpayable$_t_uint256_$returns$_t_contract$_FooBar_$799_$","typeString":"function (uint256) returns (contract FooBar)"},"typeName":{"id":667,"nodeType":"UserDefinedTypeName","pathNode":{"id":666,"name":"FooBar","nodeType":"IdentifierPath","referencedDeclaration":799,"src":"6205:6:0"},"referencedDeclaration":799,"src":"6205:6:0","typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}}},"id":670,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6201:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_FooBar_$799","typeString":"contract FooBar"}},"id":671,"nodeType":"ExpressionStatement","src":"6201:16:0"},{"expression":{"arguments":[{"hexValue":"6e6f6e636520656e64","id":675,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6240:11:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},"value":"nonce end"},{"arguments":[{"arguments":[{"arguments":[{"id":682,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6281:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}],"id":681,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6273:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":680,"name":"address","nodeType":"ElementaryTypeName","src":"6273:7:0","typeDescriptions":{}}},"id":683,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6273:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":678,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":241,"src":"6261:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":679,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"6261:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":684,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6261:26:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint64","typeString":"uint64"}],"id":677,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6253:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":676,"name":"uint256","nodeType":"ElementaryTypeName","src":"6253:7:0","typeDescriptions":{}}},"id":685,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6253:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_fa629e6661ad2a2bdb09cf9a3a276ce0d722482ae5c2887650751be0938847e8","typeString":"literal_string \"nonce end\""},{"typeIdentifier":"t_uint256","typeString":"uint256"}],"expression":{"id":672,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6228:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":674,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":182,"src":"6228:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_uint256_$returns$__$","typeString":"function (string memory,uint256) pure"}},"id":686,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6228:61:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":687,"nodeType":"ExpressionStatement","src":"6228:61:0"}]},"documentation":{"id":457,"nodeType":"StructuredDocumentation","src":"4902:56:0","text":"@notice example function, to test vm.broadcast with."},"functionSelector":"bef03abc","implemented":true,"kind":"function","modifiers":[],"name":"runBroadcast","nameLocation":"4972:12:0","parameters":{"id":458,"nodeType":"ParameterList","parameters":[],"src":"4984:2:0"},"returnParameters":{"id":459,"nodeType":"ParameterList","parameters":[],"src":"4994:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":713,"nodeType":"FunctionDefinition","src":"6391:143:0","nodes":[],"body":{"id":712,"nodeType":"Block","src":"6440:94:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":698,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":692,"src":"6462:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":695,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6450:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":697,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6450:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":699,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6450:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":700,"nodeType":"ExpressionStatement","src":"6450:15:0"},{"expression":{"arguments":[{"hexValue":"68656c6c6f206d73672e73656e646572","id":704,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"6487:18:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},"value":"hello msg.sender"},{"arguments":[{"expression":{"id":707,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"6515:3:0","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":708,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"sender","nodeType":"MemberAccess","src":"6515:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":706,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"6507:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":705,"name":"address","nodeType":"ElementaryTypeName","src":"6507:7:0","typeDescriptions":{}}},"id":709,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6507:19:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b3cc13bc51228b2c4c4334d82a4772908254dc0e1c512893dd16208ef13efb8e","typeString":"literal_string \"hello msg.sender\""},{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":701,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6475:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":703,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":199,"src":"6475:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$_t_address_$returns$__$","typeString":"function (string memory,address) pure"}},"id":710,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6475:52:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":711,"nodeType":"ExpressionStatement","src":"6475:52:0"}]},"documentation":{"id":690,"nodeType":"StructuredDocumentation","src":"6302:84:0","text":"@notice example external function, to force a CALL, and test vm.startPrank with."},"functionSelector":"a777d0dc","implemented":true,"kind":"function","modifiers":[],"name":"hello","nameLocation":"6400:5:0","parameters":{"id":693,"nodeType":"ParameterList","parameters":[{"constant":false,"id":692,"mutability":"mutable","name":"_v","nameLocation":"6422:2:0","nodeType":"VariableDeclaration","scope":713,"src":"6406:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":691,"name":"string","nodeType":"ElementaryTypeName","src":"6406:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6405:20:0"},"returnParameters":{"id":694,"nodeType":"ParameterList","parameters":[],"src":"6440:0:0"},"scope":786,"stateMutability":"view","virtual":false,"visibility":"external"},{"id":728,"nodeType":"FunctionDefinition","src":"6540:95:0","nodes":[],"body":{"id":727,"nodeType":"Block","src":"6584:51:0","nodes":[],"statements":[{"expression":{"id":719,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6594:9:0","subExpression":{"id":718,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6594:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":720,"nodeType":"ExpressionStatement","src":"6594:9:0"},{"expression":{"arguments":[{"id":724,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":715,"src":"6625:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":721,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6613:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":723,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6613:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":725,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6613:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":726,"nodeType":"ExpressionStatement","src":"6613:15:0"}]},"functionSelector":"7e79255d","implemented":true,"kind":"function","modifiers":[],"name":"call1","nameLocation":"6549:5:0","parameters":{"id":716,"nodeType":"ParameterList","parameters":[{"constant":false,"id":715,"mutability":"mutable","name":"_v","nameLocation":"6571:2:0","nodeType":"VariableDeclaration","scope":728,"src":"6555:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":714,"name":"string","nodeType":"ElementaryTypeName","src":"6555:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6554:20:0"},"returnParameters":{"id":717,"nodeType":"ParameterList","parameters":[],"src":"6584:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":743,"nodeType":"FunctionDefinition","src":"6641:95:0","nodes":[],"body":{"id":742,"nodeType":"Block","src":"6685:51:0","nodes":[],"statements":[{"expression":{"id":734,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6695:9:0","subExpression":{"id":733,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6695:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":735,"nodeType":"ExpressionStatement","src":"6695:9:0"},{"expression":{"arguments":[{"id":739,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":730,"src":"6726:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":736,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6714:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":738,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6714:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":740,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6714:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":741,"nodeType":"ExpressionStatement","src":"6714:15:0"}]},"functionSelector":"8d3ef7ca","implemented":true,"kind":"function","modifiers":[],"name":"call2","nameLocation":"6650:5:0","parameters":{"id":731,"nodeType":"ParameterList","parameters":[{"constant":false,"id":730,"mutability":"mutable","name":"_v","nameLocation":"6672:2:0","nodeType":"VariableDeclaration","scope":743,"src":"6656:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":729,"name":"string","nodeType":"ElementaryTypeName","src":"6656:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6655:20:0"},"returnParameters":{"id":732,"nodeType":"ParameterList","parameters":[],"src":"6685:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":758,"nodeType":"FunctionDefinition","src":"6742:98:0","nodes":[],"body":{"id":757,"nodeType":"Block","src":"6788:52:0","nodes":[],"statements":[{"expression":{"id":749,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6798:9:0","subExpression":{"id":748,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6798:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":750,"nodeType":"ExpressionStatement","src":"6798:9:0"},{"expression":{"arguments":[{"id":754,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":745,"src":"6830:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":751,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"6817:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_ScriptExample_$786","typeString":"contract ScriptExample"}},"id":753,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"nested2","nodeType":"MemberAccess","referencedDeclaration":773,"src":"6817:12:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) external"}},"id":755,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6817:16:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":756,"nodeType":"ExpressionStatement","src":"6817:16:0"}]},"functionSelector":"a76ccdfa","implemented":true,"kind":"function","modifiers":[],"name":"nested1","nameLocation":"6751:7:0","parameters":{"id":746,"nodeType":"ParameterList","parameters":[{"constant":false,"id":745,"mutability":"mutable","name":"_v","nameLocation":"6775:2:0","nodeType":"VariableDeclaration","scope":758,"src":"6759:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":744,"name":"string","nodeType":"ElementaryTypeName","src":"6759:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6758:20:0"},"returnParameters":{"id":747,"nodeType":"ParameterList","parameters":[],"src":"6788:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":773,"nodeType":"FunctionDefinition","src":"6846:97:0","nodes":[],"body":{"id":772,"nodeType":"Block","src":"6892:51:0","nodes":[],"statements":[{"expression":{"id":764,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"nodeType":"UnaryOperation","operator":"++","prefix":false,"src":"6902:9:0","subExpression":{"id":763,"name":"counter","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":243,"src":"6902:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":765,"nodeType":"ExpressionStatement","src":"6902:9:0"},{"expression":{"arguments":[{"id":769,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":760,"src":"6933:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":766,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"6921:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":768,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"6921:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":770,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"6921:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":771,"nodeType":"ExpressionStatement","src":"6921:15:0"}]},"functionSelector":"dbf1282f","implemented":true,"kind":"function","modifiers":[],"name":"nested2","nameLocation":"6855:7:0","parameters":{"id":761,"nodeType":"ParameterList","parameters":[{"constant":false,"id":760,"mutability":"mutable","name":"_v","nameLocation":"6879:2:0","nodeType":"VariableDeclaration","scope":773,"src":"6863:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":759,"name":"string","nodeType":"ElementaryTypeName","src":"6863:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6862:20:0"},"returnParameters":{"id":762,"nodeType":"ParameterList","parameters":[],"src":"6892:0:0"},"scope":786,"stateMutability":"nonpayable","virtual":false,"visibility":"external"},{"id":785,"nodeType":"FunctionDefinition","src":"6949:84:0","nodes":[],"body":{"id":784,"nodeType":"Block","src":"7001:32:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":781,"name":"_v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":775,"src":"7023:2:0","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_string_calldata_ptr","typeString":"string calldata"}],"expression":{"id":778,"name":"console","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":220,"src":"7011:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_console_$220_$","typeString":"type(library console)"}},"id":780,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"log","nodeType":"MemberAccess","referencedDeclaration":148,"src":"7011:11:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_string_memory_ptr_$returns$__$","typeString":"function (string memory) pure"}},"id":782,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7011:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":783,"nodeType":"ExpressionStatement","src":"7011:15:0"}]},"functionSelector":"7f8b915c","implemented":true,"kind":"function","modifiers":[],"name":"callPure","nameLocation":"6958:8:0","parameters":{"id":776,"nodeType":"ParameterList","parameters":[{"constant":false,"id":775,"mutability":"mutable","name":"_v","nameLocation":"6983:2:0","nodeType":"VariableDeclaration","scope":785,"src":"6967:18:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_string_calldata_ptr","typeString":"string"},"typeName":{"id":774,"name":"string","nodeType":"ElementaryTypeName","src":"6967:6:0","typeDescriptions":{"typeIdentifier":"t_string_storage_ptr","typeString":"string"}},"visibility":"internal"}],"src":"6966:20:0"},"returnParameters":{"id":777,"nodeType":"ParameterList","parameters":[],"src":"7001:0:0"},"scope":786,"stateMutability":"pure","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ScriptExample","contractDependencies":[799],"contractKind":"contract","documentation":{"id":221,"nodeType":"StructuredDocumentation","src":"2997:126:0","text":"@title ScriptExample\n @notice ScriptExample is an example script. The Go forge script code tests that it can run this."},"fullyImplemented":true,"linearizedBaseContracts":[786],"name":"ScriptExample","nameLocation":"3132:13:0","scope":969,"usedErrors":[]},{"id":799,"nodeType":"ContractDefinition","src":"7037:96:0","nodes":[{"id":788,"nodeType":"VariableDeclaration","src":"7059:18:0","nodes":[],"constant":false,"functionSelector":"c2985578","mutability":"mutable","name":"foo","nameLocation":"7074:3:0","scope":799,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":787,"name":"uint256","nodeType":"ElementaryTypeName","src":"7059:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"id":798,"nodeType":"FunctionDefinition","src":"7084:47:0","nodes":[],"body":{"id":797,"nodeType":"Block","src":"7107:24:0","nodes":[],"statements":[{"expression":{"id":795,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":793,"name":"foo","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":788,"src":"7117:3:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"id":794,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":790,"src":"7123:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"7117:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":796,"nodeType":"ExpressionStatement","src":"7117:7:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":791,"nodeType":"ParameterList","parameters":[{"constant":false,"id":790,"mutability":"mutable","name":"v","nameLocation":"7104:1:0","nodeType":"VariableDeclaration","scope":798,"src":"7096:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":789,"name":"uint256","nodeType":"ElementaryTypeName","src":"7096:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7095:11:0"},"returnParameters":{"id":792,"nodeType":"ParameterList","parameters":[],"src":"7107:0:0"},"scope":799,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"FooBar","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[799],"name":"FooBar","nameLocation":"7046:6:0","scope":969,"usedErrors":[]},{"id":833,"nodeType":"ContractDefinition","src":"7135:281:0","nodes":[{"id":813,"nodeType":"VariableDeclaration","src":"7162:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7188:10:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":800,"name":"address","nodeType":"ElementaryTypeName","src":"7162:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":808,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7235:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":807,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7225:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":809,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7225:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":806,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7217:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":805,"name":"uint256","nodeType":"ElementaryTypeName","src":"7217:7:0","typeDescriptions":{}}},"id":810,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7217:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":804,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7209:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":803,"name":"uint160","nodeType":"ElementaryTypeName","src":"7209:7:0","typeDescriptions":{}}},"id":811,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7209:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":802,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7201:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":801,"name":"address","nodeType":"ElementaryTypeName","src":"7201:7:0","typeDescriptions":{}}},"id":812,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7201:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":819,"nodeType":"VariableDeclaration","src":"7262:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7283:2:0","scope":833,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":815,"nodeType":"UserDefinedTypeName","pathNode":{"id":814,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7262:2:0"},"referencedDeclaration":83,"src":"7262:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":817,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":813,"src":"7291:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":816,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7288:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":818,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7288:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":832,"nodeType":"FunctionDefinition","src":"7309:105:0","nodes":[],"body":{"id":831,"nodeType":"Block","src":"7372:42:0","nodes":[],"statements":[{"expression":{"arguments":[{"id":828,"name":"_addr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":821,"src":"7401:5:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":826,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":819,"src":"7389:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":827,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7389:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":829,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7389:18:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"functionReturnParameters":825,"id":830,"nodeType":"Return","src":"7382:25:0"}]},"functionSelector":"2d0335ab","implemented":true,"kind":"function","modifiers":[],"name":"getNonce","nameLocation":"7318:8:0","parameters":{"id":822,"nodeType":"ParameterList","parameters":[{"constant":false,"id":821,"mutability":"mutable","name":"_addr","nameLocation":"7335:5:0","nodeType":"VariableDeclaration","scope":832,"src":"7327:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":820,"name":"address","nodeType":"ElementaryTypeName","src":"7327:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"src":"7326:15:0"},"returnParameters":{"id":825,"nodeType":"ParameterList","parameters":[{"constant":false,"id":824,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":832,"src":"7363:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":823,"name":"uint256","nodeType":"ElementaryTypeName","src":"7363:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7362:9:0"},"scope":833,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"NonceGetter","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[833],"name":"NonceGetter","nameLocation":"7144:11:0","scope":969,"usedErrors":[]},{"id":852,"nodeType":"ContractDefinition","src":"7418:174:0","nodes":[{"id":835,"nodeType":"VariableDeclaration","src":"7448:18:0","nodes":[],"constant":false,"mutability":"mutable","name":"v","nameLocation":"7465:1:0","scope":852,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":834,"name":"uint256","nodeType":"ElementaryTypeName","src":"7448:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"id":843,"nodeType":"FunctionDefinition","src":"7473:36:0","nodes":[],"body":{"id":842,"nodeType":"Block","src":"7487:22:0","nodes":[],"statements":[{"expression":{"id":840,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":838,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7497:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"hexValue":"31","id":839,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7501:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"7497:5:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":841,"nodeType":"ExpressionStatement","src":"7497:5:0"}]},"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","parameters":{"id":836,"nodeType":"ParameterList","parameters":[],"src":"7484:2:0"},"returnParameters":{"id":837,"nodeType":"ParameterList","parameters":[],"src":"7487:0:0"},"scope":852,"stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"id":851,"nodeType":"FunctionDefinition","src":"7515:75:0","nodes":[],"body":{"id":850,"nodeType":"Block","src":"7565:25:0","nodes":[],"statements":[{"expression":{"id":848,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":835,"src":"7582:1:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"functionReturnParameters":847,"id":849,"nodeType":"Return","src":"7575:8:0"}]},"functionSelector":"20965255","implemented":true,"kind":"function","modifiers":[],"name":"getValue","nameLocation":"7524:8:0","parameters":{"id":844,"nodeType":"ParameterList","parameters":[],"src":"7532:2:0"},"returnParameters":{"id":847,"nodeType":"ParameterList","parameters":[{"constant":false,"id":846,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":851,"src":"7556:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":845,"name":"uint256","nodeType":"ElementaryTypeName","src":"7556:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"7555:9:0"},"scope":852,"stateMutability":"view","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkedContract","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[852],"name":"ForkedContract","nameLocation":"7427:14:0","scope":969,"usedErrors":[]},{"id":968,"nodeType":"ContractDefinition","src":"7594:813:0","nodes":[{"id":866,"nodeType":"VariableDeclaration","src":"7620:94:0","nodes":[],"constant":true,"mutability":"constant","name":"VM_ADDRESS","nameLocation":"7646:10:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":853,"name":"address","nodeType":"ElementaryTypeName","src":"7620:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"hexValue":"6865766d20636865617420636f6465","id":861,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7693:17:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""},"value":"hevm cheat code"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_885cb69240a935d632d79c317109709ecfa91a80626ff3989d68f67f5b1dd12d","typeString":"literal_string \"hevm cheat code\""}],"id":860,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"7683:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":862,"isConstant":false,"isLValue":false,"isPure":true,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7683:28:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":859,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7675:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":858,"name":"uint256","nodeType":"ElementaryTypeName","src":"7675:7:0","typeDescriptions":{}}},"id":863,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7675:37:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":857,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7667:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":856,"name":"uint160","nodeType":"ElementaryTypeName","src":"7667:7:0","typeDescriptions":{}}},"id":864,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7667:46:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":855,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7659:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":854,"name":"address","nodeType":"ElementaryTypeName","src":"7659:7:0","typeDescriptions":{}}},"id":865,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7659:55:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"id":872,"nodeType":"VariableDeclaration","src":"7720:40:0","nodes":[],"constant":true,"mutability":"constant","name":"vm","nameLocation":"7741:2:0","scope":968,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"},"typeName":{"id":868,"nodeType":"UserDefinedTypeName","pathNode":{"id":867,"name":"Vm","nodeType":"IdentifierPath","referencedDeclaration":83,"src":"7720:2:0"},"referencedDeclaration":83,"src":"7720:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"value":{"arguments":[{"id":870,"name":"VM_ADDRESS","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":866,"src":"7749:10:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":869,"name":"Vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":83,"src":"7746:2:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_Vm_$83_$","typeString":"type(contract Vm)"}},"id":871,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7746:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"visibility":"internal"},{"id":967,"nodeType":"FunctionDefinition","src":"7767:638:0","nodes":[],"body":{"id":966,"nodeType":"Block","src":"7791:614:0","nodes":[],"statements":[{"assignments":[876],"declarations":[{"constant":false,"id":876,"mutability":"mutable","name":"testAddr","nameLocation":"7809:8:0","nodeType":"VariableDeclaration","scope":966,"src":"7801:16:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":875,"name":"address","nodeType":"ElementaryTypeName","src":"7801:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"}],"id":884,"initialValue":{"arguments":[{"arguments":[{"hexValue":"307831323334","id":881,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7836:6:0","typeDescriptions":{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"},"value":"0x1234"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_4660_by_1","typeString":"int_const 4660"}],"id":880,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7828:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":879,"name":"uint160","nodeType":"ElementaryTypeName","src":"7828:7:0","typeDescriptions":{}}},"id":882,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7828:15:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":878,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"7820:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":877,"name":"address","nodeType":"ElementaryTypeName","src":"7820:7:0","typeDescriptions":{}}},"id":883,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7820:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"VariableDeclarationStatement","src":"7801:43:0"},{"assignments":[887],"declarations":[{"constant":false,"id":887,"mutability":"mutable","name":"fc","nameLocation":"7869:2:0","nodeType":"VariableDeclaration","scope":966,"src":"7854:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"},"typeName":{"id":886,"nodeType":"UserDefinedTypeName","pathNode":{"id":885,"name":"ForkedContract","nodeType":"IdentifierPath","referencedDeclaration":852,"src":"7854:14:0"},"referencedDeclaration":852,"src":"7854:14:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"visibility":"internal"}],"id":891,"initialValue":{"arguments":[{"id":889,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7889:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":888,"name":"ForkedContract","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":852,"src":"7874:14:0","typeDescriptions":{"typeIdentifier":"t_type$_t_contract$_ForkedContract_$852_$","typeString":"type(contract ForkedContract)"}},"id":890,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7874:24:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"nodeType":"VariableDeclarationStatement","src":"7854:44:0"},{"expression":{"arguments":[{"hexValue":"666f726b31","id":895,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7929:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},"value":"fork1"},{"hexValue":"3132333435","id":896,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7938:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_b6acbb7ba3bf910295048af2ccd655ff20a445d705d49fd56157c24aab14c1a1","typeString":"literal_string \"fork1\""},{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"}],"expression":{"id":892,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7909:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":894,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"7909:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":897,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7909:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":898,"nodeType":"ExpressionStatement","src":"7909:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":905,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":902,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"7974:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":900,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"7962:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":901,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"7962:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":903,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7962:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3132333435","id":904,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"7987:5:0","typeDescriptions":{"typeIdentifier":"t_rational_12345_by_1","typeString":"int_const 12345"},"value":"12345"},"src":"7962:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":906,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"7994:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":899,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"7954:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":907,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"7954:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":908,"nodeType":"ExpressionStatement","src":"7954:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":914,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":910,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8036:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":911,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8036:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":912,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8036:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"31","id":913,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8053:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"src":"8036:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652031","id":915,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8056:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""},"value":"value should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_244bd39a8f8426ed26a6cae45b2ada0383deda0bbc513dfe29f31ab8529d5c7a","typeString":"literal_string \"value should be 1\""}],"id":909,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8028:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":916,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8028:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":917,"nodeType":"ExpressionStatement","src":"8028:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":925,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":919,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8094:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":920,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8094:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"31","id":923,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8122:1:0","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"}],"id":922,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8114:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":921,"name":"uint256","nodeType":"ElementaryTypeName","src":"8114:7:0","typeDescriptions":{}}},"id":924,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8114:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8094:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652031","id":926,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8126:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""},"value":"balance should be 1"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675b86838b72d956fe80c51e424164ea5e48d46b089cf53543fefe5ee2c684bf","typeString":"literal_string \"balance should be 1\""}],"id":918,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8086:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":927,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8086:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":928,"nodeType":"ExpressionStatement","src":"8086:62:0"},{"expression":{"arguments":[{"hexValue":"666f726b32","id":932,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8179:7:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},"value":"fork2"},{"hexValue":"3233343536","id":933,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8188:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_stringliteral_261b052a4950a8ec6afce52cd61229704be48859b7177f79ca612a21277827f8","typeString":"literal_string \"fork2\""},{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"}],"expression":{"id":929,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8159:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":931,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"createSelectFork","nodeType":"MemberAccess","referencedDeclaration":82,"src":"8159:19:0","typeDescriptions":{"typeIdentifier":"t_function_external_nonpayable$_t_string_memory_ptr_$_t_uint256_$returns$_t_uint256_$","typeString":"function (string memory,uint256) external returns (uint256)"}},"id":934,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8159:35:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":935,"nodeType":"ExpressionStatement","src":"8159:35:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint64","typeString":"uint64"},"id":942,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[{"id":939,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8224:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"expression":{"id":937,"name":"vm","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":872,"src":"8212:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_Vm_$83","typeString":"contract Vm"}},"id":938,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getNonce","nodeType":"MemberAccess","referencedDeclaration":17,"src":"8212:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$_t_address_$returns$_t_uint64_$","typeString":"function (address) view external returns (uint64)"}},"id":940,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8212:21:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint64","typeString":"uint64"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"3233343536","id":941,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8237:5:0","typeDescriptions":{"typeIdentifier":"t_rational_23456_by_1","typeString":"int_const 23456"},"value":"23456"},"src":"8212:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"6e6f6e63652073686f756c64206265203132333435","id":943,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8244:23:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""},"value":"nonce should be 12345"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_675408ff346f993e251ba3ee09efb90c23d0de302269ea6afde722ac077acbdb","typeString":"literal_string \"nonce should be 12345\""}],"id":936,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8204:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":944,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8204:64:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":945,"nodeType":"ExpressionStatement","src":"8204:64:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":951,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"arguments":[],"expression":{"argumentTypes":[],"expression":{"id":947,"name":"fc","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":887,"src":"8286:2:0","typeDescriptions":{"typeIdentifier":"t_contract$_ForkedContract_$852","typeString":"contract ForkedContract"}},"id":948,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"getValue","nodeType":"MemberAccess","referencedDeclaration":851,"src":"8286:11:0","typeDescriptions":{"typeIdentifier":"t_function_external_view$__$returns$_t_uint256_$","typeString":"function () view external returns (uint256)"}},"id":949,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8286:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"hexValue":"32","id":950,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8303:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"},"src":"8286:18:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"76616c75652073686f756c642062652032","id":952,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8306:19:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""},"value":"value should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_989f7bdcf9093cc756fd0c37255cb127d8c8369545d3f3456d0571522c208b6d","typeString":"literal_string \"value should be 2\""}],"id":946,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8278:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":953,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8278:48:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":954,"nodeType":"ExpressionStatement","src":"8278:48:0"},{"expression":{"arguments":[{"commonType":{"typeIdentifier":"t_uint256","typeString":"uint256"},"id":962,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftExpression":{"expression":{"id":956,"name":"testAddr","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":876,"src":"8344:8:0","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":957,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberName":"balance","nodeType":"MemberAccess","src":"8344:16:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"nodeType":"BinaryOperation","operator":"==","rightExpression":{"arguments":[{"hexValue":"32","id":960,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"8372:1:0","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"}],"id":959,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"8364:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":958,"name":"uint256","nodeType":"ElementaryTypeName","src":"8364:7:0","typeDescriptions":{}}},"id":961,"isConstant":false,"isLValue":false,"isPure":true,"kind":"typeConversion","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8364:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"src":"8344:30:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"62616c616e63652073686f756c642062652032","id":963,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"8376:21:0","typeDescriptions":{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""},"value":"balance should be 2"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_4c35c4bb929f7c1c753e1326d2d04380b315ea3b8a63106213ab37dd0832958a","typeString":"literal_string \"balance should be 2\""}],"id":955,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"8336:7:0","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":964,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"names":[],"nodeType":"FunctionCall","src":"8336:62:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":965,"nodeType":"ExpressionStatement","src":"8336:62:0"}]},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"7776:3:0","parameters":{"id":873,"nodeType":"ParameterList","parameters":[],"src":"7779:2:0"},"returnParameters":{"id":874,"nodeType":"ParameterList","parameters":[],"src":"7791:0:0"},"scope":968,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ForkTester","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[968],"name":"ForkTester","nameLocation":"7603:10:0","scope":969,"usedErrors":[]}],"license":"MIT"},"id":0} \ No newline at end of file diff --git a/op-chain-ops/script/with.go b/op-chain-ops/script/with.go index 00560d5a6b6e8..0823bf9b7fbd8 100644 --- a/op-chain-ops/script/with.go +++ b/op-chain-ops/script/with.go @@ -3,6 +3,8 @@ package script import ( "fmt" + "github.com/ethereum-optimism/optimism/op-chain-ops/script/addresses" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -26,10 +28,13 @@ func WithScript[B any](h *Host, name string, contract string) (b *B, cleanup fun return nil, nil, fmt.Errorf("could not load script artifact: %w", err) } - deployer := ScriptDeployer + deployer := addresses.ScriptDeployer deployNonce := h.state.GetNonce(deployer) // compute address of script contract to be deployed addr := crypto.CreateAddress(deployer, deployNonce) + h.Label(addr, contract) + h.AllowCheatcodes(addr) // before constructor execution, give our script cheatcode access + h.state.MakeExcluded(addr) // scripts are persistent across forks // init bindings (with ABI check) bindings, err := MakeBindings[B](h.ScriptBackendFn(addr), func(abiDef string) bool { @@ -51,7 +56,6 @@ func WithScript[B any](h *Host, name string, contract string) (b *B, cleanup fun return nil, nil, fmt.Errorf("deployed to unexpected address %s, expected %s", deployedAddr, addr) } h.RememberArtifact(addr, artifact, contract) - h.Label(addr, contract) return bindings, func() { h.Wipe(addr) }, nil diff --git a/op-chain-ops/srcmap/solutil.go b/op-chain-ops/srcmap/solutil.go index 6d1aa4c64a3e7..929632cbfd5f6 100644 --- a/op-chain-ops/srcmap/solutil.go +++ b/op-chain-ops/srcmap/solutil.go @@ -238,6 +238,16 @@ func (s *SourceMapTracer) info(codeAddr common.Address, pc uint64) string { func (s *SourceMapTracer) OnOpCode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { op := vm.OpCode(opcode) + var top []string + stk := scope.StackData() + for i := len(stk) - 1; i >= 0; i-- { + top = append(top, stk[i].Hex()) + if len(top) == 4 { + break + } + } + stkInfo := fmt.Sprintf("[%s]", strings.Join(top, ", ")) + if op.IsPush() { var val []byte sc, ok := scope.(*vm.ScopeContext) @@ -248,10 +258,10 @@ func (s *SourceMapTracer) OnOpCode(pc uint64, opcode byte, gas, cost uint64, sco } else { val = []byte("N/A") } - fmt.Fprintf(s.out, "%-40s : pc %x opcode %s (%x)\n", s.info(scope.Address(), pc), pc, op.String(), val) + fmt.Fprintf(s.out, "%-40s : pc %x opcode %s (%x) \t| stk[:%d] %s\n", s.info(scope.Address(), pc), pc, op.String(), val, len(top), stkInfo) return } - fmt.Fprintf(s.out, "%-40s : pc %x opcode %s\n", s.info(scope.Address(), pc), pc, op.String()) + fmt.Fprintf(s.out, "%-40s : pc %x opcode %s \t\t| stk[:%d] %s\n", s.info(scope.Address(), pc), pc, op.String(), len(top), stkInfo) } func (s *SourceMapTracer) OnFault(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { diff --git a/op-challenger/README.md b/op-challenger/README.md index 69420e419cfa3..5efbbd85b3d3e 100644 --- a/op-challenger/README.md +++ b/op-challenger/README.md @@ -1,7 +1,7 @@ # op-challenger The `op-challenger` is a modular **op-stack** challenge agent written in -golang for dispute games including, but not limited to,attestation games, +golang for dispute games including, but not limited to, attestation games, fault games, and validity games. To learn more about dispute games, visit the [fault proof specs][proof-specs]. @@ -23,6 +23,7 @@ accessed by running `./op-challenger --help`. To run `op-challenger` against the local devnet, first clean and run the devnet from the root of the repository. + ```shell make devnet-clean make devnet-up @@ -31,6 +32,7 @@ make devnet-up Then build the `op-challenger` with `make op-challenger`. Run the `op-challenger` with: + ```shell DISPUTE_GAME_FACTORY=$(jq -r .DisputeGameFactoryProxy .devnet/addresses.json) ./op-challenger/bin/op-challenger \ @@ -85,6 +87,9 @@ in the L2 output oracle. Optionally, you may specify the game type (aka "trace type") using the `--trace-type` flag, which is set to the cannon trace type by default. +For known networks, the `--game-factory-address` option can be replaced by `--network`. See the `--help` output for a +list of predefined networks. + ### move The `move` subcommand can be run with either the `--attack` or `--defend` flag, @@ -154,7 +159,7 @@ If the game is resolved successfully, the result is printed. ```shell ./bin/op-challenger list-games \ --l1-eth-rpc \ - --network + --game-factory-address ``` Prints the games created by the game factory along with their current status. @@ -162,6 +167,9 @@ Prints the games created by the game factory along with their current status. * `L1_ETH_RPC` - the RPC endpoint of the L1 endpoint to use (e.g. `http://localhost:8545`). * `GAME_FACTORY_ADDRESS` - the address of the dispute game factory contract on L1. +For known networks, the `--game-factory-address` option can be replaced by `--network`. See the `--help` output for a +list of predefined networks. + ### list-claims ```shell @@ -174,3 +182,39 @@ Prints the list of current claims in a dispute game. * `L1_ETH_RPC` - the RPC endpoint of the L1 endpoint to use (e.g. `http://localhost:8545`). * `GAME_ADDRESS` - the address of the dispute game to list the move in. + +### run-trace + +```shell +./bin/op-challenger run-trace \ + --network= \ + --l1-eth-rpc= \ + --l1-beacon= \ + --l2-eth-rpc= \ + --rollup-rpc= \ + --data-dir= \ + --prestates-url= \ + --run= +``` + +* `NETWORK_NAME` - the name of a predefined L2 network. +* `L1_ETH_RPC` - the RPC endpoint of the L1 endpoint to use (e.g. `http://localhost:8545`). +* `L1_BEACON` - the REST endpoint of the L1 beacon node to use (e.g. `http://localhost:5100`). +* `L2_ETH_RPC` - the RPC endpoint of the L2 execution client to use +* `ROLLUP_RPC` - the RPC endpoint of the L2 consensus client to use +* `DATA_DIR` - the directory to use to store data +* `PRESTATES_URL` - the base URL to download required prestates from +* `RUN_CONFIG` - the trace providers and prestates to run. e.g. `cannon,asterisc-kona/kona-0.1.0-alpha.5/0x03c50fbef46a05f93ea7665fa89015c2108e10c1b4501799c0663774bd35a9c5` + +Testing utility that continuously runs the specified trace providers against real chain data. The trace providers can be +configured with multiple different prestates. This allows testing both the current and potential future prestates with +the fault proofs virtual machine used by the trace provider. + +The same CLI options as `op-challenger` itself are supported to configure the trace providers. The additional `--run` +option allows specifying which prestates to use. The format is `traceType/name/prestateHash` where traceType is the +trace type to use with the prestate (e.g cannon or asterisc-kona), name is an arbitrary name for the prestate to use +when reporting metrics and prestateHash is the hex encoded absolute prestate commitment to use. If name is omitted the +trace type name is used.If the prestateHash is omitted, the absolute prestate hash used for new games on-chain. + +For example to run both the production cannon prestate and a custom +prestate, use `--run cannon,cannon/next-prestate/0x03c1f0d45248190f80430a4c31e24f8108f05f80ff8b16ecb82d20df6b1b43f3`. diff --git a/op-challenger/cmd/main_test.go b/op-challenger/cmd/main_test.go index d471f45dc5948..1de92468306c1 100644 --- a/op-challenger/cmd/main_test.go +++ b/op-challenger/cmd/main_test.go @@ -937,6 +937,18 @@ func TestAdditionalBondClaimants(t *testing.T) { }) } +func TestSignerTLS(t *testing.T) { + t.Run("EnabledByDefault", func(t *testing.T) { + cfg := configForArgs(t, addRequiredArgs(types.TraceTypeAlphabet)) + require.True(t, cfg.TxMgrConfig.SignerCLIConfig.TLSConfig.Enabled) + }) + + t.Run("Disabled", func(t *testing.T) { + cfg := configForArgs(t, addRequiredArgs(types.TraceTypeAlphabet, "--signer.tls.enabled=false")) + require.False(t, cfg.TxMgrConfig.SignerCLIConfig.TLSConfig.Enabled) + }) +} + func verifyArgsInvalid(t *testing.T, messageContains string, cliArgs []string) { _, _, err := dryRunWithArgs(cliArgs) require.ErrorContains(t, err, messageContains) @@ -1010,7 +1022,6 @@ func addRequiredCannonArgs(args map[string]string) { args["--cannon-bin"] = cannonBin args["--cannon-server"] = cannonServer args["--cannon-prestate"] = cannonPreState - args["--l2-eth-rpc"] = l2EthRpc } func addRequiredAsteriscArgs(args map[string]string) { @@ -1018,7 +1029,6 @@ func addRequiredAsteriscArgs(args map[string]string) { args["--asterisc-bin"] = asteriscBin args["--asterisc-server"] = asteriscServer args["--asterisc-prestate"] = asteriscPreState - args["--l2-eth-rpc"] = l2EthRpc } func addRequiredAsteriscKonaArgs(args map[string]string) { @@ -1026,7 +1036,6 @@ func addRequiredAsteriscKonaArgs(args map[string]string) { args["--asterisc-bin"] = asteriscBin args["--asterisc-kona-server"] = asteriscServer args["--asterisc-kona-prestate"] = asteriscPreState - args["--l2-eth-rpc"] = l2EthRpc } func toArgList(req map[string]string) []string { diff --git a/op-challenger/runner/runner.go b/op-challenger/runner/runner.go index 289bb0cfe1056..312981430413b 100644 --- a/op-challenger/runner/runner.go +++ b/op-challenger/runner/runner.go @@ -199,6 +199,9 @@ func (r *Runner) createGameInputs(ctx context.Context, client *sources.RollupCli // This only matters if op-node is behind and hasn't processed all finalized L1 blocks yet. l1Head = status.CurrentL1 } + if l1Head.Number == 0 { + return utils.LocalGameInputs{}, errors.New("l1 head is 0") + } blockNumber, err := r.findL2BlockNumberToDispute(ctx, client, l1Head.Number, status.FinalizedL2.Number) if err != nil { return utils.LocalGameInputs{}, fmt.Errorf("failed to find l2 block number to dispute: %w", err) diff --git a/op-conductor/README.md b/op-conductor/README.md index 084899e2fe4b7..497156b8eee85 100644 --- a/op-conductor/README.md +++ b/op-conductor/README.md @@ -13,6 +13,8 @@ The design will provide below guarantees: 2. No unsafe head stall during network partition 3. 100% uptime with no more than 1 node failure (for a standard 3 node setup) +For configuration and runbook, please refer to [RUNBOOK.md](./RUNBOOK.md) + ## Design ### Architecture diff --git a/op-conductor/RUNBOOK.md b/op-conductor/RUNBOOK.md new file mode 100644 index 0000000000000..00b8757a338eb --- /dev/null +++ b/op-conductor/RUNBOOK.md @@ -0,0 +1,78 @@ +## op-conductor runbook + +### conductor configurations + +In order to setup op-conductor, you need to configure the following env vars for both op-conductor and op-node service: + +#### op-node + +```env +OP_NODE_CONDUCTOR_ENABLED=true +OP_NODE_CONDUCTOR_RPC= # for example http://conductor:8545 +``` + +#### op-conductor + +```env +# prefix for the server id, used to identify the server in the raft cluster +RAFT_SERVER_ID_PREFIX= # for example, sequencer-1, sequencer-2, etc +OP_CONDUCTOR_RAFT_STORAGE_DIR= +OP_CONDUCTOR_RPC_ADDR= # for example, 0.0.0.0 +OP_CONDUCTOR_RPC_PORT= # for example, 8545 +OP_CONDUCTOR_METRICS_ENABLED=true/false +OP_CONDUCTOR_METRICS_ADDR= # for example 0.0.0.0 +OP_CONDUCTOR_METRICS_PORT= # for example 7300 +OP_CONDUCTOR_CONSENSUS_PORT= # for example 50050 +OP_CONDUCTOR_PAUSED=true # set to true to start conductor in paused state +OP_CONDUCTOR_NODE_RPC= # for example, http://op-node:8545 +OP_CONDUCTOR_EXECUTION_RPC= # for example, http://op-geth:8545 +OP_CONDUCTOR_NETWORK= # for example, base-mainnet, op-mainnet, etc, should be same as OP_NODE_NETWORK +OP_CONDUCTOR_HEALTHCHECK_INTERVAL= # in seconds +OP_CONDUCTOR_HEALTHCHECK_UNSAFE_INTERVAL= # Interval allowed between unsafe head and now measured in seconds +OP_CONDUCTOR_HEALTHCHECK_MIN_PEER_COUNT= # minimum number of peers required to be considered healthy +OP_CONDUCTOR_RAFT_BOOTSTRAP=true/false # set to true if you want to bootstrap the raft cluster +``` + +### How to bootstrap a sequencer cluster from scratch + +In normal situations, you probably have a running sequencer already and you want to turn it into a HA cluster. What you need to do in this situation is to: + +1. start a completely new sequencer with above mentioned configurations and + 1. `OP_CONDUCTOR_RAFT_BOOTSTRAP=true` set on op-conductor + 2. `OP_CONDUCTOR_PAUSED=true` set on op-conductor + 3. `OP_NODE_SEQUENCER_ENABLED=true` set on op-node +2. wait for the new sequencer to start and get synced up with the rest of the nodes +3. once the new sequencer is synced up, manually or use automation to stop sequencing on the old sequencer and start sequencing on the new sequencer +4. resume the conductor on the new sequencer by calling `conductor_resume` json rpc method on op-conductor +5. set `OP_CONDUCTOR_RAFT_BOOTSTRAP=false` on the sequencer so that it doesn't attempt to bootstrap the cluster during redeploy + +Now you have a single HA sequencer which treats itself as the cluster leader! Next steps would be to add more sequencers to the cluster depending on your needs. For example, we want a 3-node cluster, you can follow the same process to add 2 more sequencers. + +1. start a new sequencer with + 1. `OP_CONDUCTOR_RAFT_BOOTSTRAP=false` set on op-conductor + 2. `OP_CONDUCTOR_PAUSED=true` set on op-conductor +2. wait for the new sequencer to start and get synced up with the rest of the nodes +3. once the new sequencer is synced up, manually or use automation to add it to the cluster by calling `conductor_addServerAsVoter` json rpc method on the leader sequencer +4. call `conductor_clusterMembership` json rpc method on the leader sequencer to get the updated cluster membership +5. resume the conductor on the new sequencer by calling `conductor_resume` json rpc method on op-conductor + +Once finished, you should have a 3-node HA sequencer cluster! + +### Redeploy a HA sequencer + +For every redeploy, depending on your underlying infrastructure, you need to make sure to: + +1. `OP_CONDUCTOR_PAUSED=true` set on op-conductor so that conductor doesn't attempt to control sequencer while it's still syncing / redeploying +2. make sure sequencer is caught up with the rest of the nodes (this step isn't strictly necessary as conductor could handle this, but from a HA perspective, it does not make sense to have a sequencer that is lagging behind to join the cluster to potentially become the leader) +3. resume conductor after it's caught up with the rest of the nodes so that conductor can start managing the sequencer + +### Disaster recovery + +Whenever there are a disaster situation that you see no route to have 2 healthy conductor in the cluster communicating with each other, you need to manually intervene to resume sequencing. The steps are as follows: + +1. call `conductor_pause` json rpc method on the all conductors so that they don't attempt to start / stop sequencer +2. choose a sequencer that can be used to resume sequencing +3. call `conductor_overrideLeader` json rpc method on the conductor to force it to treat itself as the leader +4. If no conductor is functioning, call `admin_overrideLeader` json rpc method on the op-node to force it to treat itself as the leader +5. manually start sequencing on the chosen sequencer +6. Go back to bootstrap step to re-bootstrap the cluster. diff --git a/op-conductor/conductor/config.go b/op-conductor/conductor/config.go index ca18de7d1a18f..98e3ad83440ef 100644 --- a/op-conductor/conductor/config.go +++ b/op-conductor/conductor/config.go @@ -19,12 +19,19 @@ import ( ) type Config struct { - // ConsensusAddr is the address to listen for consensus connections. + // ConsensusAddr is the address, excluding port, to listen on for consensus connections. + // E.g. 0.0.0.0 to bind to the external-facing network interface. ConsensusAddr string - // ConsensusPort is the port to listen for consensus connections. + // ConsensusPort is the port to listen on for consensus connections. + // If 0, the server binds to a port selected by the system. ConsensusPort int + // ConsensusAdvertisedAddr is the network address, including port, to advertise to other peers. + // This is optional: if empty, the address that the server network transport binds to is used instead. + // E.g. local tests may use temporary addresses, rather than preset known addresses. + ConsensusAdvertisedAddr string + // RaftServerID is the unique ID for this server used by raft consensus. RaftServerID string @@ -117,8 +124,11 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*Config, error) { } return &Config{ - ConsensusAddr: ctx.String(flags.ConsensusAddr.Name), - ConsensusPort: ctx.Int(flags.ConsensusPort.Name), + ConsensusAddr: ctx.String(flags.ConsensusAddr.Name), + ConsensusPort: ctx.Int(flags.ConsensusPort.Name), + // The consensus server will advertise the address it binds to if this is empty/unspecified. + ConsensusAdvertisedAddr: ctx.String(flags.AdvertisedFullAddr.Name), + RaftBootstrap: ctx.Bool(flags.RaftBootstrap.Name), RaftServerID: ctx.String(flags.RaftServerID.Name), RaftStorageDir: ctx.String(flags.RaftStorageDir.Name), diff --git a/op-conductor/conductor/service.go b/op-conductor/conductor/service.go index 565096a9b45b2..cccba2c76ac92 100644 --- a/op-conductor/conductor/service.go +++ b/op-conductor/conductor/service.go @@ -169,10 +169,12 @@ func (c *OpConductor) initConsensus(ctx context.Context) error { return nil } - serverAddr := fmt.Sprintf("%s:%d", c.cfg.ConsensusAddr, c.cfg.ConsensusPort) raftConsensusConfig := &consensus.RaftConsensusConfig{ - ServerID: c.cfg.RaftServerID, - ServerAddr: serverAddr, + ServerID: c.cfg.RaftServerID, + // AdvertisedAddr may be empty: the server will then default to what it binds to. + AdvertisedAddr: raft.ServerAddress(c.cfg.ConsensusAdvertisedAddr), + ListenAddr: c.cfg.ConsensusAddr, + ListenPort: c.cfg.ConsensusPort, StorageDir: c.cfg.RaftStorageDir, Bootstrap: c.cfg.RaftBootstrap, RollupCfg: &c.cfg.RollupCfg, @@ -247,6 +249,11 @@ func (oc *OpConductor) initRPCServer(ctx context.Context) error { Namespace: conductorrpc.ExecutionRPCNamespace, Service: executionProxy, }) + execMinerProxy := conductorrpc.NewExecutionMinerProxyBackend(oc.log, oc, execClient) + server.AddAPI(rpc.API{ + Namespace: conductorrpc.ExecutionMinerRPCNamespace, + Service: execMinerProxy, + }) nodeClient, err := dial.DialRollupClientWithTimeout(ctx, 1*time.Minute, oc.log, oc.cfg.NodeRPC) if err != nil { @@ -467,6 +474,12 @@ func (oc *OpConductor) Paused() bool { return oc.paused.Load() } +// ConsensusEndpoint returns the raft consensus server address to connect to. +func (oc *OpConductor) ConsensusEndpoint() string { + return oc.cons.Addr() +} + +// HTTPEndpoint returns the HTTP RPC endpoint func (oc *OpConductor) HTTPEndpoint() string { if oc.rpcServer == nil { return "" @@ -608,7 +621,8 @@ func (oc *OpConductor) handleHealthUpdate(hcerr error) { oc.queueAction() } - if oc.healthy.Swap(healthy) != healthy { + if old := oc.healthy.Swap(healthy); old != healthy { + oc.log.Info("Health state changed", "old", old, "new", healthy) // queue an action if health status changed. oc.queueAction() } diff --git a/op-conductor/conductor/service_test.go b/op-conductor/conductor/service_test.go index 49a05e9027639..87df417a4683e 100644 --- a/op-conductor/conductor/service_test.go +++ b/op-conductor/conductor/service_test.go @@ -30,7 +30,7 @@ func mockConfig(t *testing.T) Config { now := uint64(time.Now().Unix()) return Config{ ConsensusAddr: "127.0.0.1", - ConsensusPort: 50050, + ConsensusPort: 0, RaftServerID: "SequencerA", RaftStorageDir: "/tmp/raft", RaftBootstrap: false, diff --git a/op-conductor/consensus/iface.go b/op-conductor/consensus/iface.go index 69b9506c50b26..e0dcb6efd5a7e 100644 --- a/op-conductor/consensus/iface.go +++ b/op-conductor/consensus/iface.go @@ -42,6 +42,9 @@ type ServerInfo struct { // //go:generate mockery --name Consensus --output mocks/ --with-expecter=true type Consensus interface { + // Addr returns the address of this consensus server. + // Internally the server may override what is advertised, or fall back to the address it listens to. + Addr() string // AddVoter adds a voting member into the cluster, voter is eligible to become leader. // If version is non-zero, this will only be applied if the current cluster version matches the expected version. AddVoter(id, addr string, version uint64) error diff --git a/op-conductor/consensus/mocks/Consensus.go b/op-conductor/consensus/mocks/Consensus.go index ca1397a690e1f..902174435146a 100644 --- a/op-conductor/consensus/mocks/Consensus.go +++ b/op-conductor/consensus/mocks/Consensus.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.46.0. DO NOT EDIT. package mocks @@ -118,6 +118,51 @@ func (_c *Consensus_AddVoter_Call) RunAndReturn(run func(string, string, uint64) return _c } +// Addr provides a mock function with given fields: +func (_m *Consensus) Addr() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Addr") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Consensus_Addr_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Addr' +type Consensus_Addr_Call struct { + *mock.Call +} + +// Addr is a helper method to define mock.On call +func (_e *Consensus_Expecter) Addr() *Consensus_Addr_Call { + return &Consensus_Addr_Call{Call: _e.mock.On("Addr")} +} + +func (_c *Consensus_Addr_Call) Run(run func()) *Consensus_Addr_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Consensus_Addr_Call) Return(_a0 string) *Consensus_Addr_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Consensus_Addr_Call) RunAndReturn(run func() string) *Consensus_Addr_Call { + _c.Call.Return(run) + return _c +} + // ClusterMembership provides a mock function with given fields: func (_m *Consensus) ClusterMembership() (*consensus.ClusterMembership, error) { ret := _m.Called() diff --git a/op-conductor/consensus/raft.go b/op-conductor/consensus/raft.go index f6acc0fb76f17..86b32ea00f8c5 100644 --- a/op-conductor/consensus/raft.go +++ b/op-conductor/consensus/raft.go @@ -29,12 +29,30 @@ type RaftConsensus struct { serverID raft.ServerID r *raft.Raft + transport *raft.NetworkTransport + // advertisedAddr is the host & port to contact this server. + // If empty, the address of the transport should be used instead. + advertisedAddr string + unsafeTracker *unsafeHeadTracker } type RaftConsensusConfig struct { - ServerID string - ServerAddr string + ServerID string + + // AdvertisedAddr is the address to advertise, + // i.e. the address external raft peers use to contact us. + // If left empty, it defaults to the resulting + // local address that we bind the underlying transport to. + AdvertisedAddr raft.ServerAddress + + // ListenPort is the port to bind the server to. + // This may be 0, an available port will then be selected by the system. + ListenPort int + // ListenAddr is the address to bind the server to. + // E.g. use 0.0.0.0 to bind to an external-facing network. + ListenAddr string + StorageDir string Bootstrap bool RollupCfg *rollup.Config @@ -86,18 +104,31 @@ func NewRaftConsensus(log log.Logger, cfg *RaftConsensusConfig) (*RaftConsensus, return nil, fmt.Errorf(`raft.NewFileSnapshotStore(%q): %w`, baseDir, err) } - addr, err := net.ResolveTCPAddr("tcp", cfg.ServerAddr) - if err != nil { - return nil, errors.Wrap(err, "failed to resolve tcp address") + var advertiseAddr net.Addr + if cfg.AdvertisedAddr == "" { + log.Warn("No advertised address specified. Advertising local address.") + } else { + x, err := net.ResolveTCPAddr("tcp", string(cfg.AdvertisedAddr)) + if err != nil { + return nil, fmt.Errorf("failed to resolve advertised TCP address %q: %w", string(cfg.AdvertisedAddr), err) + } + advertiseAddr = x + log.Info("Resolved advertising address", "adAddr", cfg.AdvertisedAddr, + "adIP", x.IP, "adPort", x.Port, "adZone", x.Zone) } + bindAddr := fmt.Sprintf("%s:%d", cfg.ListenAddr, cfg.ListenPort) + log.Info("Binding raft server to network transport", "listenAddr", bindAddr) + maxConnPool := 10 timeout := 5 * time.Second - bindAddr := fmt.Sprintf("0.0.0.0:%d", addr.Port) - transport, err := raft.NewTCPTransportWithLogger(bindAddr, addr, maxConnPool, timeout, rc.Logger) + + // When advertiseAddr == nil, the transport will use the local address that it is bound to. + transport, err := raft.NewTCPTransportWithLogger(bindAddr, advertiseAddr, maxConnPool, timeout, rc.Logger) if err != nil { return nil, errors.Wrap(err, "failed to create raft tcp transport") } + log.Info("Raft server network transport is up", "addr", transport.LocalAddr()) fsm := NewUnsafeHeadTracker(log) @@ -110,11 +141,19 @@ func NewRaftConsensus(log log.Logger, cfg *RaftConsensusConfig) (*RaftConsensus, // If bootstrap = true, start raft in bootstrap mode, this will allow the current node to elect itself as leader when there's no other participants // and allow other nodes to join the cluster. if cfg.Bootstrap { + var advertisedAddr raft.ServerAddress + if cfg.AdvertisedAddr == "" { + advertisedAddr = transport.LocalAddr() + } else { + advertisedAddr = cfg.AdvertisedAddr + } + log.Info("Bootstrapping raft consensus cluster with self", "addr", advertisedAddr) + raftCfg := raft.Configuration{ Servers: []raft.Server{ { ID: rc.LocalID, - Address: raft.ServerAddress(cfg.ServerAddr), + Address: advertisedAddr, Suffrage: raft.Voter, }, }, @@ -132,9 +171,20 @@ func NewRaftConsensus(log log.Logger, cfg *RaftConsensusConfig) (*RaftConsensus, serverID: raft.ServerID(cfg.ServerID), unsafeTracker: fsm, rollupCfg: cfg.RollupCfg, + transport: transport, }, nil } +// Addr returns the address to contact this raft consensus server. +// If no explicit address to advertise was configured, +// the local network address that the raft-consensus server is listening on will be used. +func (rc *RaftConsensus) Addr() string { + if rc.advertisedAddr != "" { + return rc.advertisedAddr + } + return string(rc.transport.LocalAddr()) +} + // AddNonVoter implements Consensus, it tries to add a non-voting member into the cluster. func (rc *RaftConsensus) AddNonVoter(id string, addr string, version uint64) error { if err := checkTCPPortOpen(addr); err != nil { diff --git a/op-conductor/consensus/raft_test.go b/op-conductor/consensus/raft_test.go index fbd9c7cb3bc81..9c8ca48247efe 100644 --- a/op-conductor/consensus/raft_test.go +++ b/op-conductor/consensus/raft_test.go @@ -28,7 +28,9 @@ func TestCommitAndRead(t *testing.T) { } raftConsensusConfig := &RaftConsensusConfig{ ServerID: "SequencerA", - ServerAddr: "127.0.0.1:0", + ListenPort: 0, + ListenAddr: "127.0.0.1", // local test, don't bind to external interface + AdvertisedAddr: "", // use local address that the server binds to StorageDir: storageDir, Bootstrap: true, RollupCfg: rollupCfg, diff --git a/op-conductor/flags/flags.go b/op-conductor/flags/flags.go index 249e8a676e079..7c29bfcab2c3a 100644 --- a/op-conductor/flags/flags.go +++ b/op-conductor/flags/flags.go @@ -19,16 +19,22 @@ const EnvVarPrefix = "OP_CONDUCTOR" var ( ConsensusAddr = &cli.StringFlag{ Name: "consensus.addr", - Usage: "Address to listen for consensus connections", + Usage: "Address (excluding port) to listen for consensus connections.", EnvVars: opservice.PrefixEnvVar(EnvVarPrefix, "CONSENSUS_ADDR"), Value: "127.0.0.1", } ConsensusPort = &cli.IntFlag{ Name: "consensus.port", - Usage: "Port to listen for consensus connections", + Usage: "Port to listen for consensus connections. May be 0 to let the system select a port.", EnvVars: opservice.PrefixEnvVar(EnvVarPrefix, "CONSENSUS_PORT"), Value: 50050, } + AdvertisedFullAddr = &cli.StringFlag{ + Name: "consensus.advertised", + Usage: "Full address (host and port) for other peers to contact the consensus server. Optional: if left empty, the local address is advertised.", + EnvVars: opservice.PrefixEnvVar(EnvVarPrefix, "CONSENSUS_ADVERTISED"), + Value: "", + } RaftBootstrap = &cli.BoolFlag{ Name: "raft.bootstrap", Usage: "If this node should bootstrap a new raft cluster", @@ -127,6 +133,7 @@ var requiredFlags = []cli.Flag{ } var optionalFlags = []cli.Flag{ + AdvertisedFullAddr, Paused, RPCEnableProxy, RaftBootstrap, diff --git a/op-conductor/rpc/api.go b/op-conductor/rpc/api.go index eafec9ac304b0..a8b62e3b74fdd 100644 --- a/op-conductor/rpc/api.go +++ b/op-conductor/rpc/api.go @@ -4,6 +4,7 @@ import ( "context" "errors" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum-optimism/optimism/op-conductor/consensus" @@ -61,13 +62,19 @@ type API interface { CommitUnsafePayload(ctx context.Context, payload *eth.ExecutionPayloadEnvelope) error } -// ExecutionProxyAPI defines the methods proxied to the execution rpc backend +// ExecutionProxyAPI defines the methods proxied to the execution 'eth_' rpc backend // This should include all methods that are called by op-batcher or op-proposer type ExecutionProxyAPI interface { GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) } -// NodeProxyAPI defines the methods proxied to the node rpc backend +// ExecutionMinerProxyAPI defines the methods proxied to the execution 'miner_' rpc backend +// This should include all methods that are called by op-batcher or op-proposer +type ExecutionMinerProxyAPI interface { + SetMaxDASize(ctx context.Context, maxTxSize hexutil.Big, maxBlockSize hexutil.Big) bool +} + +// NodeProxyAPI defines the methods proxied to the node 'optimism_' rpc backend // This should include all methods that are called by op-batcher or op-proposer type NodeProxyAPI interface { OutputAtBlock(ctx context.Context, blockNumString string) (*eth.OutputResponse, error) @@ -75,7 +82,7 @@ type NodeProxyAPI interface { RollupConfig(ctx context.Context) (*rollup.Config, error) } -// NodeProxyAPI defines the methods proxied to the node rpc backend +// NodeAdminProxyAPI defines the methods proxied to the node 'admin_' rpc backend // This should include all methods that are called by op-batcher or op-proposer type NodeAdminProxyAPI interface { SequencerActive(ctx context.Context) (bool, error) diff --git a/op-conductor/rpc/excecution_miner_proxy.go b/op-conductor/rpc/excecution_miner_proxy.go new file mode 100644 index 0000000000000..9594e790b3227 --- /dev/null +++ b/op-conductor/rpc/excecution_miner_proxy.go @@ -0,0 +1,40 @@ +package rpc + +import ( + "context" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" +) + +var ExecutionMinerRPCNamespace = "miner" + +// ExecutionMinerProxyBackend implements an execution rpc proxy with a leadership check before each call. +type ExecutionMinerProxyBackend struct { + log log.Logger + con conductor + client *ethclient.Client +} + +var _ ExecutionMinerProxyAPI = (*ExecutionMinerProxyBackend)(nil) + +func NewExecutionMinerProxyBackend(log log.Logger, con conductor, client *ethclient.Client) *ExecutionMinerProxyBackend { + return &ExecutionMinerProxyBackend{ + log: log, + con: con, + client: client, + } +} + +func (api *ExecutionMinerProxyBackend) SetMaxDASize(ctx context.Context, maxTxSize hexutil.Big, maxBlockSize hexutil.Big) bool { + var result bool + if !api.con.Leader(ctx) { + return false + } + err := api.client.Client().Call(&result, "miner_setMaxDASize", maxTxSize, maxBlockSize) + if err != nil { + return false + } + return result +} diff --git a/op-deployer/.goreleaser.yaml b/op-deployer/.goreleaser.yaml index a17f171783b42..5040ed4bc4d42 100644 --- a/op-deployer/.goreleaser.yaml +++ b/op-deployer/.goreleaser.yaml @@ -1,9 +1,4 @@ -# This is an example .goreleaser.yml file with some sensible defaults. -# Make sure to check the documentation at https://goreleaser.com - -# The lines below are called `modelines`. See `:help modeline` -# Feel free to remove those if you don't want/need to use them. -# yaml-language-server: $schema=https://goreleaser.com/static/schema.json +# yaml-language-server: $schema=https://goreleaser.com/static/schema-pro.json # vim: set ts=2 sw=2 tw=0 fo=cnqoj version: 2 @@ -50,6 +45,20 @@ archives: - goos: windows format: zip +dockers: + - id: default + goos: linux + goarch: amd64 + dockerfile: Dockerfile.default + image_templates: + - "us-docker.pkg.dev/oplabs-tools-artifacts/images/op-deployer:{{ .Tag }}" + - id: minimal + goos: linux + goarch: amd64 + dockerfile: Dockerfile.minimal + image_templates: + - "us-docker.pkg.dev/oplabs-tools-artifacts/images/op-deployer:{{ .Tag }}-minimal" + changelog: sort: asc filters: diff --git a/op-deployer/Dockerfile.default b/op-deployer/Dockerfile.default new file mode 100644 index 0000000000000..cc5ca8d95e4fd --- /dev/null +++ b/op-deployer/Dockerfile.default @@ -0,0 +1,3 @@ +FROM debian:bookworm-20240812-slim +ENTRYPOINT ["/op-deployer"] +COPY op-deployer /op-deployer \ No newline at end of file diff --git a/op-deployer/Dockerfile.minimal b/op-deployer/Dockerfile.minimal new file mode 100644 index 0000000000000..9e8811980090c --- /dev/null +++ b/op-deployer/Dockerfile.minimal @@ -0,0 +1,3 @@ +FROM scratch +ENTRYPOINT ["/op-deployer"] +COPY op-deployer /op-deployer \ No newline at end of file diff --git a/op-deployer/pkg/deployer/apply.go b/op-deployer/pkg/deployer/apply.go index 95db427d8efba..f02716c655a54 100644 --- a/op-deployer/pkg/deployer/apply.go +++ b/op-deployer/pkg/deployer/apply.go @@ -8,6 +8,14 @@ import ( "strings" "github.com/ethereum-optimism/optimism/op-chain-ops/foundry" + "github.com/ethereum-optimism/optimism/op-chain-ops/script" + "github.com/ethereum-optimism/optimism/op-chain-ops/script/forking" + "github.com/ethereum/go-ethereum/rpc" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" "github.com/ethereum/go-ethereum/common" @@ -100,69 +108,62 @@ func Apply(ctx context.Context, cfg ApplyConfig) error { return fmt.Errorf("failed to read state: %w", err) } - var l1Client *ethclient.Client - var deployer common.Address - var bcaster broadcaster.Broadcaster - var startingNonce uint64 - if intent.DeploymentStrategy == state.DeploymentStrategyLive { - if err := cfg.CheckLive(); err != nil { - return fmt.Errorf("invalid config for apply: %w", err) - } - - l1Client, err = ethclient.Dial(cfg.L1RPCUrl) - if err != nil { - return fmt.Errorf("failed to connect to L1 RPC: %w", err) - } + if err := ApplyPipeline(ctx, ApplyPipelineOpts{ + L1RPCUrl: cfg.L1RPCUrl, + DeployerPrivateKey: cfg.privateKeyECDSA, + Intent: intent, + State: st, + Logger: cfg.Logger, + StateWriter: pipeline.WorkdirStateWriter(cfg.Workdir), + }); err != nil { + return err + } - chainID, err := l1Client.ChainID(ctx) - if err != nil { - return fmt.Errorf("failed to get chain ID: %w", err) - } + return nil +} - signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(cfg.privateKeyECDSA, chainID)) - deployer = crypto.PubkeyToAddress(cfg.privateKeyECDSA.PublicKey) +type pipelineStage struct { + name string + apply func() error +} - bcaster, err = broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{ - Logger: cfg.Logger, - ChainID: new(big.Int).SetUint64(intent.L1ChainID), - Client: l1Client, - Signer: signer, - From: deployer, - }) - if err != nil { - return fmt.Errorf("failed to create broadcaster: %w", err) - } +type ApplyPipelineOpts struct { + L1RPCUrl string + DeployerPrivateKey *ecdsa.PrivateKey + Intent *state.Intent + State *state.State + Logger log.Logger + StateWriter pipeline.StateWriter +} - startingNonce, err = l1Client.NonceAt(ctx, deployer, nil) - if err != nil { - return fmt.Errorf("failed to get starting nonce: %w", err) - } - } else { - deployer = common.Address{0x01} - bcaster = broadcaster.NoopBroadcaster() - } +func ApplyPipeline( + ctx context.Context, + opts ApplyPipelineOpts, +) error { + intent := opts.Intent + st := opts.State progressor := func(curr, total int64) { - cfg.Logger.Info("artifacts download progress", "current", curr, "total", total) + opts.Logger.Info("artifacts download progress", "current", curr, "total", total) } - l1ArtifactsFS, cleanupL1, err := pipeline.DownloadArtifacts(ctx, intent.L1ContractsLocator, progressor) + l1ArtifactsFS, cleanupL1, err := artifacts.Download(ctx, intent.L1ContractsLocator, progressor) if err != nil { return fmt.Errorf("failed to download L1 artifacts: %w", err) } defer func() { if err := cleanupL1(); err != nil { - cfg.Logger.Warn("failed to clean up L1 artifacts", "err", err) + opts.Logger.Warn("failed to clean up L1 artifacts", "err", err) } }() - l2ArtifactsFS, cleanupL2, err := pipeline.DownloadArtifacts(ctx, intent.L2ContractsLocator, progressor) + l2ArtifactsFS, cleanupL2, err := artifacts.Download(ctx, intent.L2ContractsLocator, progressor) if err != nil { return fmt.Errorf("failed to download L2 artifacts: %w", err) } defer func() { if err := cleanupL2(); err != nil { - cfg.Logger.Warn("failed to clean up L2 artifacts", "err", err) + opts.Logger.Warn("failed to clean up L2 artifacts", "err", err) } }() @@ -171,52 +172,101 @@ func Apply(ctx context.Context, cfg ApplyConfig) error { L2: l2ArtifactsFS, } - l1Host, err := pipeline.DefaultScriptHost(bcaster, cfg.Logger, deployer, bundle.L1, startingNonce) - if err != nil { - return fmt.Errorf("failed to create L1 script host: %w", err) + var deployer common.Address + var bcaster broadcaster.Broadcaster + var l1Client *ethclient.Client + var l1Host *script.Host + if intent.DeploymentStrategy == state.DeploymentStrategyLive { + l1RPC, err := rpc.Dial(opts.L1RPCUrl) + if err != nil { + return fmt.Errorf("failed to connect to L1 RPC: %w", err) + } + + l1Client = ethclient.NewClient(l1RPC) + + chainID, err := l1Client.ChainID(ctx) + if err != nil { + return fmt.Errorf("failed to get chain ID: %w", err) + } + + signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(opts.DeployerPrivateKey, chainID)) + deployer = crypto.PubkeyToAddress(opts.DeployerPrivateKey.PublicKey) + + bcaster, err = broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{ + Logger: opts.Logger, + ChainID: new(big.Int).SetUint64(intent.L1ChainID), + Client: l1Client, + Signer: signer, + From: deployer, + }) + if err != nil { + return fmt.Errorf("failed to create broadcaster: %w", err) + } + + l1Host, err = env.DefaultScriptHost( + bcaster, + opts.Logger, + deployer, + bundle.L1, + script.WithForkHook(func(cfg *script.ForkConfig) (forking.ForkSource, error) { + src, err := forking.RPCSourceByNumber(cfg.URLOrAlias, l1RPC, *cfg.BlockNumber) + if err != nil { + return nil, fmt.Errorf("failed to create RPC fork source: %w", err) + } + return forking.Cache(src), nil + }), + ) + if err != nil { + return fmt.Errorf("failed to create L1 script host: %w", err) + } + + latest, err := l1Client.HeaderByNumber(ctx, nil) + if err != nil { + return fmt.Errorf("failed to get latest block: %w", err) + } + + if _, err := l1Host.CreateSelectFork( + script.ForkWithURLOrAlias("main"), + script.ForkWithBlockNumberU256(latest.Number), + ); err != nil { + return fmt.Errorf("failed to select fork: %w", err) + } + } else { + deployer = common.Address{0x01} + bcaster = broadcaster.NoopBroadcaster() + l1Host, err = env.DefaultScriptHost( + bcaster, + opts.Logger, + deployer, + bundle.L1, + ) + if err != nil { + return fmt.Errorf("failed to create L1 script host: %w", err) + } } - env := &pipeline.Env{ - StateWriter: pipeline.WorkdirStateWriter(cfg.Workdir), + pEnv := &pipeline.Env{ + StateWriter: opts.StateWriter, L1ScriptHost: l1Host, L1Client: l1Client, - Logger: cfg.Logger, + Logger: opts.Logger, Broadcaster: bcaster, Deployer: deployer, } - if err := ApplyPipeline(ctx, env, bundle, intent, st); err != nil { - return err - } - - return nil -} - -type pipelineStage struct { - name string - apply func() error -} - -func ApplyPipeline( - ctx context.Context, - env *pipeline.Env, - bundle pipeline.ArtifactsBundle, - intent *state.Intent, - st *state.State, -) error { pline := []pipelineStage{ {"init", func() error { if intent.DeploymentStrategy == state.DeploymentStrategyLive { - return pipeline.InitLiveStrategy(ctx, env, intent, st) + return pipeline.InitLiveStrategy(ctx, pEnv, intent, st) } else { - return pipeline.InitGenesisStrategy(env, intent, st) + return pipeline.InitGenesisStrategy(pEnv, intent, st) } }}, {"deploy-superchain", func() error { - return pipeline.DeploySuperchain(env, intent, st) + return pipeline.DeploySuperchain(pEnv, intent, st) }}, {"deploy-implementations", func() error { - return pipeline.DeployImplementations(env, intent, st) + return pipeline.DeployImplementations(pEnv, intent, st) }}, } @@ -226,16 +276,17 @@ func ApplyPipeline( pline = append(pline, pipelineStage{ fmt.Sprintf("deploy-opchain-%s", chainID.Hex()), func() error { - if intent.DeploymentStrategy == state.DeploymentStrategyLive { - return pipeline.DeployOPChainLiveStrategy(ctx, env, bundle, intent, st, chainID) - } else { - return pipeline.DeployOPChainGenesisStrategy(env, intent, st, chainID) - } + return pipeline.DeployOPChain(pEnv, intent, st, chainID) + }, + }, pipelineStage{ + fmt.Sprintf("deploy-alt-da-%s", chainID.Hex()), + func() error { + return pipeline.DeployAltDA(pEnv, intent, st, chainID) }, }, pipelineStage{ fmt.Sprintf("generate-l2-genesis-%s", chainID.Hex()), func() error { - return pipeline.GenerateL2Genesis(env, intent, bundle, st, chainID) + return pipeline.GenerateL2Genesis(pEnv, intent, bundle, st, chainID) }, }) } @@ -248,9 +299,9 @@ func ApplyPipeline( fmt.Sprintf("set-start-block-%s", chainID.Hex()), func() error { if intent.DeploymentStrategy == state.DeploymentStrategyLive { - return pipeline.SetStartBlockLiveStrategy(ctx, env, st, chainID) + return pipeline.SetStartBlockLiveStrategy(ctx, pEnv, st, chainID) } else { - return pipeline.SetStartBlockGenesisStrategy(env, st, chainID) + return pipeline.SetStartBlockGenesisStrategy(pEnv, st, chainID) } }, }) @@ -262,23 +313,27 @@ func ApplyPipeline( if err := stage.apply(); err != nil { return fmt.Errorf("error in pipeline stage apply: %w", err) } - dump, err := env.L1ScriptHost.StateDump() - if err != nil { - return fmt.Errorf("failed to dump state: %w", err) - } - st.L1StateDump = &state.GzipData[foundry.ForgeAllocs]{ - Data: dump, + + if intent.DeploymentStrategy == state.DeploymentStrategyGenesis { + dump, err := pEnv.L1ScriptHost.StateDump() + if err != nil { + return fmt.Errorf("failed to dump state: %w", err) + } + st.L1StateDump = &state.GzipData[foundry.ForgeAllocs]{ + Data: dump, + } } - if _, err := env.Broadcaster.Broadcast(ctx); err != nil { + + if _, err := pEnv.Broadcaster.Broadcast(ctx); err != nil { return fmt.Errorf("failed to broadcast stage %s: %w", stage.name, err) } - if err := env.StateWriter.WriteState(st); err != nil { + if err := pEnv.StateWriter.WriteState(st); err != nil { return fmt.Errorf("failed to write state: %w", err) } } st.AppliedIntent = intent - if err := env.StateWriter.WriteState(st); err != nil { + if err := pEnv.StateWriter.WriteState(st); err != nil { return fmt.Errorf("failed to write state: %w", err) } diff --git a/op-deployer/pkg/deployer/pipeline/downloader.go b/op-deployer/pkg/deployer/artifacts/downloader.go similarity index 94% rename from op-deployer/pkg/deployer/pipeline/downloader.go rename to op-deployer/pkg/deployer/artifacts/downloader.go index 370817e8366a2..1303adbe86aa8 100644 --- a/op-deployer/pkg/deployer/pipeline/downloader.go +++ b/op-deployer/pkg/deployer/artifacts/downloader.go @@ -1,4 +1,4 @@ -package pipeline +package artifacts import ( "archive/tar" @@ -15,9 +15,9 @@ import ( "strings" "time" - "github.com/ethereum/go-ethereum/log" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-chain-ops/foundry" ) @@ -38,11 +38,11 @@ func LogProgressor(lgr log.Logger) DownloadProgressor { } } -func DownloadArtifacts(ctx context.Context, loc *opcm.ArtifactsLocator, progress DownloadProgressor) (foundry.StatDirFs, CleanupFunc, error) { +func Download(ctx context.Context, loc *Locator, progress DownloadProgressor) (foundry.StatDirFs, CleanupFunc, error) { var u *url.URL var err error if loc.IsTag() { - u, err = opcm.StandardArtifactsURLForTag(loc.Tag) + u, err = standard.ArtifactsURLForTag(loc.Tag) if err != nil { return nil, nil, fmt.Errorf("failed to get standard artifacts URL for tag %s: %w", loc.Tag, err) } diff --git a/op-deployer/pkg/deployer/pipeline/downloader_test.go b/op-deployer/pkg/deployer/artifacts/downloader_test.go similarity index 82% rename from op-deployer/pkg/deployer/pipeline/downloader_test.go rename to op-deployer/pkg/deployer/artifacts/downloader_test.go index 36183fe5afa5e..e66b41f96a814 100644 --- a/op-deployer/pkg/deployer/pipeline/downloader_test.go +++ b/op-deployer/pkg/deployer/artifacts/downloader_test.go @@ -1,4 +1,4 @@ -package pipeline +package artifacts import ( "context" @@ -9,8 +9,6 @@ import ( "os" "testing" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" - "github.com/stretchr/testify/require" ) @@ -29,11 +27,11 @@ func TestDownloadArtifacts(t *testing.T) { ctx := context.Background() artifactsURL, err := url.Parse(ts.URL) require.NoError(t, err) - loc := &opcm.ArtifactsLocator{ + loc := &Locator{ URL: artifactsURL, } - fs, cleanup, err := DownloadArtifacts(ctx, loc, nil) + fs, cleanup, err := Download(ctx, loc, nil) require.NoError(t, err) require.NotNil(t, fs) defer func() { diff --git a/op-deployer/pkg/deployer/artifacts/locator.go b/op-deployer/pkg/deployer/artifacts/locator.go new file mode 100644 index 0000000000000..aa44d43644c8d --- /dev/null +++ b/op-deployer/pkg/deployer/artifacts/locator.go @@ -0,0 +1,104 @@ +package artifacts + +import ( + "fmt" + "net/url" + "strings" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" +) + +type schemeUnmarshaler func(string) (*Locator, error) + +var schemeUnmarshalerDispatch = map[string]schemeUnmarshaler{ + "tag": unmarshalTag, + "file": unmarshalURL, + "https": unmarshalURL, +} + +var DefaultL1ContractsLocator = &Locator{ + Tag: standard.DefaultL1ContractsTag, +} + +var DefaultL2ContractsLocator = &Locator{ + Tag: standard.DefaultL2ContractsTag, +} + +func NewLocatorFromTag(tag string) (*Locator, error) { + loc := new(Locator) + if err := loc.UnmarshalText([]byte("tag://" + tag)); err != nil { + return nil, fmt.Errorf("failed to unmarshal tag: %w", err) + } + return loc, nil +} + +func MustNewLocatorFromTag(tag string) *Locator { + loc, err := NewLocatorFromTag(tag) + if err != nil { + panic(err) + } + return loc +} + +type Locator struct { + URL *url.URL + Tag string +} + +func (a *Locator) UnmarshalText(text []byte) error { + str := string(text) + + for scheme, unmarshaler := range schemeUnmarshalerDispatch { + if !strings.HasPrefix(str, scheme+"://") { + continue + } + + loc, err := unmarshaler(str) + if err != nil { + return err + } + + *a = *loc + return nil + } + + return fmt.Errorf("unsupported scheme") +} + +func (a *Locator) MarshalText() ([]byte, error) { + if a.URL != nil { + return []byte(a.URL.String()), nil + } + + if a.Tag != "" { + return []byte("tag://" + a.Tag), nil + } + + return nil, fmt.Errorf("no URL, path or tag set") +} + +func (a *Locator) IsTag() bool { + return a.Tag != "" +} + +func unmarshalTag(tag string) (*Locator, error) { + tag = strings.TrimPrefix(tag, "tag://") + if !strings.HasPrefix(tag, "op-contracts/") { + return nil, fmt.Errorf("invalid tag: %s", tag) + } + + if _, err := standard.ArtifactsURLForTag(tag); err != nil { + return nil, err + } + + return &Locator{Tag: tag}, nil +} + +func unmarshalURL(text string) (*Locator, error) { + u, err := url.Parse(text) + if err != nil { + return nil, err + } + + return &Locator{URL: u}, nil +} diff --git a/op-deployer/pkg/deployer/opcm/artifacts_locator_test.go b/op-deployer/pkg/deployer/artifacts/locator_test.go similarity index 88% rename from op-deployer/pkg/deployer/opcm/artifacts_locator_test.go rename to op-deployer/pkg/deployer/artifacts/locator_test.go index 8771fad32ec91..678e2c252b32b 100644 --- a/op-deployer/pkg/deployer/opcm/artifacts_locator_test.go +++ b/op-deployer/pkg/deployer/artifacts/locator_test.go @@ -1,4 +1,4 @@ -package opcm +package artifacts import ( "net/url" @@ -7,17 +7,17 @@ import ( "github.com/stretchr/testify/require" ) -func TestArtifactsLocator_Marshaling(t *testing.T) { +func TestLocator_Marshaling(t *testing.T) { tests := []struct { name string in string - out *ArtifactsLocator + out *Locator err bool }{ { name: "valid tag", in: "tag://op-contracts/v1.6.0", - out: &ArtifactsLocator{ + out: &Locator{ Tag: "op-contracts/v1.6.0", }, err: false, @@ -37,7 +37,7 @@ func TestArtifactsLocator_Marshaling(t *testing.T) { { name: "valid HTTPS URL", in: "https://example.com", - out: &ArtifactsLocator{ + out: &Locator{ URL: parseUrl(t, "https://example.com"), }, err: false, @@ -45,7 +45,7 @@ func TestArtifactsLocator_Marshaling(t *testing.T) { { name: "valid file URL", in: "file:///tmp/artifacts", - out: &ArtifactsLocator{ + out: &Locator{ URL: parseUrl(t, "file:///tmp/artifacts"), }, err: false, @@ -71,7 +71,7 @@ func TestArtifactsLocator_Marshaling(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var a ArtifactsLocator + var a Locator err := a.UnmarshalText([]byte(tt.in)) if tt.err { require.Error(t, err) diff --git a/op-deployer/pkg/deployer/pipeline/testdata/artifacts.tar.gz b/op-deployer/pkg/deployer/artifacts/testdata/artifacts.tar.gz similarity index 100% rename from op-deployer/pkg/deployer/pipeline/testdata/artifacts.tar.gz rename to op-deployer/pkg/deployer/artifacts/testdata/artifacts.tar.gz diff --git a/op-deployer/pkg/deployer/bootstrap/delayed_weth.go b/op-deployer/pkg/deployer/bootstrap/delayed_weth.go new file mode 100644 index 0000000000000..451b0741f2452 --- /dev/null +++ b/op-deployer/pkg/deployer/bootstrap/delayed_weth.go @@ -0,0 +1,204 @@ +package bootstrap + +import ( + "context" + "crypto/ecdsa" + "fmt" + "math/big" + "strings" + + artifacts2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" + opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto" + "github.com/ethereum-optimism/optimism/op-service/ctxinterrupt" + "github.com/ethereum-optimism/optimism/op-service/ioutil" + "github.com/ethereum-optimism/optimism/op-service/jsonutil" + oplog "github.com/ethereum-optimism/optimism/op-service/log" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "github.com/urfave/cli/v2" +) + +type DelayedWETHConfig struct { + L1RPCUrl string + PrivateKey string + Logger log.Logger + ArtifactsLocator *artifacts2.Locator + + privateKeyECDSA *ecdsa.PrivateKey +} + +func (c *DelayedWETHConfig) Check() error { + if c.L1RPCUrl == "" { + return fmt.Errorf("l1RPCUrl must be specified") + } + + if c.PrivateKey == "" { + return fmt.Errorf("private key must be specified") + } + + privECDSA, err := crypto.HexToECDSA(strings.TrimPrefix(c.PrivateKey, "0x")) + if err != nil { + return fmt.Errorf("failed to parse private key: %w", err) + } + c.privateKeyECDSA = privECDSA + + if c.Logger == nil { + return fmt.Errorf("logger must be specified") + } + + if c.ArtifactsLocator == nil { + return fmt.Errorf("artifacts locator must be specified") + } + + return nil +} + +func DelayedWETHCLI(cliCtx *cli.Context) error { + logCfg := oplog.ReadCLIConfig(cliCtx) + l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg) + oplog.SetGlobalLogHandler(l.Handler()) + + l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName) + privateKey := cliCtx.String(deployer.PrivateKeyFlagName) + artifactsURLStr := cliCtx.String(ArtifactsLocatorFlagName) + artifactsLocator := new(artifacts2.Locator) + if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil { + return fmt.Errorf("failed to parse artifacts URL: %w", err) + } + + ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context) + + return DelayedWETH(ctx, DelayedWETHConfig{ + L1RPCUrl: l1RPCUrl, + PrivateKey: privateKey, + Logger: l, + ArtifactsLocator: artifactsLocator, + }) +} + +func DelayedWETH(ctx context.Context, cfg DelayedWETHConfig) error { + if err := cfg.Check(); err != nil { + return fmt.Errorf("invalid config for DelayedWETH: %w", err) + } + + lgr := cfg.Logger + progressor := func(curr, total int64) { + lgr.Info("artifacts download progress", "current", curr, "total", total) + } + + artifactsFS, cleanup, err := artifacts2.Download(ctx, cfg.ArtifactsLocator, progressor) + if err != nil { + return fmt.Errorf("failed to download artifacts: %w", err) + } + defer func() { + if err := cleanup(); err != nil { + lgr.Warn("failed to clean up artifacts", "err", err) + } + }() + + l1Client, err := ethclient.Dial(cfg.L1RPCUrl) + if err != nil { + return fmt.Errorf("failed to connect to L1 RPC: %w", err) + } + + chainID, err := l1Client.ChainID(ctx) + if err != nil { + return fmt.Errorf("failed to get chain ID: %w", err) + } + chainIDU64 := chainID.Uint64() + + superCfg, err := standard.SuperchainFor(chainIDU64) + if err != nil { + return fmt.Errorf("error getting superchain config: %w", err) + } + standardVersionsTOML, err := standard.L1VersionsDataFor(chainIDU64) + if err != nil { + return fmt.Errorf("error getting standard versions TOML: %w", err) + } + proxyAdmin, err := standard.ManagerOwnerAddrFor(chainIDU64) + if err != nil { + return fmt.Errorf("error getting superchain proxy admin: %w", err) + } + delayedWethOwner, err := standard.SystemOwnerAddrFor(chainIDU64) + if err != nil { + return fmt.Errorf("error getting superchain system owner: %w", err) + } + + signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(cfg.privateKeyECDSA, chainID)) + chainDeployer := crypto.PubkeyToAddress(cfg.privateKeyECDSA.PublicKey) + + bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{ + Logger: lgr, + ChainID: chainID, + Client: l1Client, + Signer: signer, + From: chainDeployer, + }) + if err != nil { + return fmt.Errorf("failed to create broadcaster: %w", err) + } + + nonce, err := l1Client.NonceAt(ctx, chainDeployer, nil) + if err != nil { + return fmt.Errorf("failed to get starting nonce: %w", err) + } + + host, err := env.DefaultScriptHost( + bcaster, + lgr, + chainDeployer, + artifactsFS, + ) + if err != nil { + return fmt.Errorf("failed to create script host: %w", err) + } + host.SetNonce(chainDeployer, nonce) + + var release string + if cfg.ArtifactsLocator.IsTag() { + release = cfg.ArtifactsLocator.Tag + } else { + release = "dev" + } + + lgr.Info("deploying DelayedWETH", "release", release) + + superchainConfigAddr := common.Address(*superCfg.Config.SuperchainConfigAddr) + + dwo, err := opcm.DeployDelayedWETH( + host, + opcm.DeployDelayedWETHInput{ + Release: release, + StandardVersionsToml: standardVersionsTOML, + ProxyAdmin: proxyAdmin, + SuperchainConfigProxy: superchainConfigAddr, + DelayedWethOwner: delayedWethOwner, + DelayedWethDelay: big.NewInt(604800), + }, + ) + if err != nil { + return fmt.Errorf("error deploying DelayedWETH: %w", err) + } + + if _, err := bcaster.Broadcast(ctx); err != nil { + return fmt.Errorf("failed to broadcast: %w", err) + } + + lgr.Info("deployed DelayedWETH") + + if err := jsonutil.WriteJSON(dwo, ioutil.ToStdOut()); err != nil { + return fmt.Errorf("failed to write output: %w", err) + } + return nil +} diff --git a/op-deployer/pkg/deployer/bootstrap/dispute_game.go b/op-deployer/pkg/deployer/bootstrap/dispute_game.go new file mode 100644 index 0000000000000..d3efe36f9ca8e --- /dev/null +++ b/op-deployer/pkg/deployer/bootstrap/dispute_game.go @@ -0,0 +1,216 @@ +package bootstrap + +import ( + "context" + "crypto/ecdsa" + "fmt" + "strings" + + artifacts2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" + opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto" + "github.com/ethereum-optimism/optimism/op-service/ctxinterrupt" + "github.com/ethereum-optimism/optimism/op-service/ioutil" + "github.com/ethereum-optimism/optimism/op-service/jsonutil" + oplog "github.com/ethereum-optimism/optimism/op-service/log" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "github.com/urfave/cli/v2" +) + +type DisputeGameConfig struct { + L1RPCUrl string + PrivateKey string + Logger log.Logger + ArtifactsLocator *artifacts2.Locator + + privateKeyECDSA *ecdsa.PrivateKey + + MinProposalSizeBytes uint64 + ChallengePeriodSeconds uint64 + MipsVersion uint64 + GameKind string + GameType uint32 + AbsolutePrestate common.Hash + MaxGameDepth uint64 + SplitDepth uint64 + ClockExtension uint64 + MaxClockDuration uint64 + DelayedWethProxy common.Address + AnchorStateRegistryProxy common.Address + L2ChainId uint64 + Proposer common.Address + Challenger common.Address +} + +func (c *DisputeGameConfig) Check() error { + if c.L1RPCUrl == "" { + return fmt.Errorf("l1RPCUrl must be specified") + } + + if c.PrivateKey == "" { + return fmt.Errorf("private key must be specified") + } + + privECDSA, err := crypto.HexToECDSA(strings.TrimPrefix(c.PrivateKey, "0x")) + if err != nil { + return fmt.Errorf("failed to parse private key: %w", err) + } + c.privateKeyECDSA = privECDSA + + if c.Logger == nil { + return fmt.Errorf("logger must be specified") + } + + if c.ArtifactsLocator == nil { + return fmt.Errorf("artifacts locator must be specified") + } + + return nil +} + +func DisputeGameCLI(cliCtx *cli.Context) error { + logCfg := oplog.ReadCLIConfig(cliCtx) + l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg) + oplog.SetGlobalLogHandler(l.Handler()) + + l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName) + privateKey := cliCtx.String(deployer.PrivateKeyFlagName) + artifactsURLStr := cliCtx.String(ArtifactsLocatorFlagName) + artifactsLocator := new(artifacts2.Locator) + if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil { + return fmt.Errorf("failed to parse artifacts URL: %w", err) + } + + ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context) + + return DisputeGame(ctx, DisputeGameConfig{ + L1RPCUrl: l1RPCUrl, + PrivateKey: privateKey, + Logger: l, + ArtifactsLocator: artifactsLocator, + }) +} + +func DisputeGame(ctx context.Context, cfg DisputeGameConfig) error { + if err := cfg.Check(); err != nil { + return fmt.Errorf("invalid config for DisputeGame: %w", err) + } + + lgr := cfg.Logger + progressor := func(curr, total int64) { + lgr.Info("artifacts download progress", "current", curr, "total", total) + } + + artifactsFS, cleanup, err := artifacts2.Download(ctx, cfg.ArtifactsLocator, progressor) + if err != nil { + return fmt.Errorf("failed to download artifacts: %w", err) + } + defer func() { + if err := cleanup(); err != nil { + lgr.Warn("failed to clean up artifacts", "err", err) + } + }() + + l1Client, err := ethclient.Dial(cfg.L1RPCUrl) + if err != nil { + return fmt.Errorf("failed to connect to L1 RPC: %w", err) + } + + chainID, err := l1Client.ChainID(ctx) + if err != nil { + return fmt.Errorf("failed to get chain ID: %w", err) + } + chainIDU64 := chainID.Uint64() + + standardVersionsTOML, err := standard.L1VersionsDataFor(chainIDU64) + if err != nil { + return fmt.Errorf("error getting standard versions TOML: %w", err) + } + + signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(cfg.privateKeyECDSA, chainID)) + chainDeployer := crypto.PubkeyToAddress(cfg.privateKeyECDSA.PublicKey) + + bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{ + Logger: lgr, + ChainID: chainID, + Client: l1Client, + Signer: signer, + From: chainDeployer, + }) + if err != nil { + return fmt.Errorf("failed to create broadcaster: %w", err) + } + + nonce, err := l1Client.NonceAt(ctx, chainDeployer, nil) + if err != nil { + return fmt.Errorf("failed to get starting nonce: %w", err) + } + + host, err := env.DefaultScriptHost( + bcaster, + lgr, + chainDeployer, + artifactsFS, + ) + if err != nil { + return fmt.Errorf("failed to create script host: %w", err) + } + host.SetNonce(chainDeployer, nonce) + + var release string + if cfg.ArtifactsLocator.IsTag() { + release = cfg.ArtifactsLocator.Tag + } else { + release = "dev" + } + + lgr.Info("deploying dispute game", "release", release) + + dgo, err := opcm.DeployDisputeGame( + host, + opcm.DeployDisputeGameInput{ + Release: release, + StandardVersionsToml: standardVersionsTOML, + MipsVersion: cfg.MipsVersion, + MinProposalSizeBytes: cfg.MinProposalSizeBytes, + ChallengePeriodSeconds: cfg.ChallengePeriodSeconds, + GameKind: cfg.GameKind, + GameType: cfg.GameType, + AbsolutePrestate: cfg.AbsolutePrestate, + MaxGameDepth: cfg.MaxGameDepth, + SplitDepth: cfg.SplitDepth, + ClockExtension: cfg.ClockExtension, + MaxClockDuration: cfg.MaxClockDuration, + DelayedWethProxy: cfg.DelayedWethProxy, + AnchorStateRegistryProxy: cfg.AnchorStateRegistryProxy, + L2ChainId: cfg.L2ChainId, + Proposer: cfg.Proposer, + Challenger: cfg.Challenger, + }, + ) + if err != nil { + return fmt.Errorf("error deploying dispute game: %w", err) + } + + if _, err := bcaster.Broadcast(ctx); err != nil { + return fmt.Errorf("failed to broadcast: %w", err) + } + + lgr.Info("deployed dispute game") + + if err := jsonutil.WriteJSON(dgo, ioutil.ToStdOut()); err != nil { + return fmt.Errorf("failed to write output: %w", err) + } + return nil +} diff --git a/op-deployer/pkg/deployer/bootstrap/flags.go b/op-deployer/pkg/deployer/bootstrap/flags.go index b76b798b5b0f4..73f99e7b43250 100644 --- a/op-deployer/pkg/deployer/bootstrap/flags.go +++ b/op-deployer/pkg/deployer/bootstrap/flags.go @@ -2,12 +2,33 @@ package bootstrap import ( "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum-optimism/optimism/op-service/cliapp" + "github.com/ethereum/go-ethereum/common" "github.com/urfave/cli/v2" ) const ( - ArtifactsLocatorFlagName = "artifacts-locator" + ArtifactsLocatorFlagName = "artifacts-locator" + WithdrawalDelaySecondsFlagName = "withdrawal-delay-seconds" + MinProposalSizeBytesFlagName = "min-proposal-size-bytes" + ChallengePeriodSecondsFlagName = "challenge-period-seconds" + ProofMaturityDelaySecondsFlagName = "proof-maturity-delay-seconds" + DisputeGameFinalityDelaySecondsFlagName = "dispute-game-finality-delay-seconds" + MIPSVersionFlagName = "mips-version" + GameKindFlagName = "game-kind" + GameTypeFlagName = "game-type" + AbsolutePrestateFlagName = "absolute-prestate" + MaxGameDepthFlagName = "max-game-depth" + SplitDepthFlagName = "split-depth" + ClockExtensionFlagName = "clock-extension" + MaxClockDurationFlagName = "max-clock-duration" + DelayedWethProxyFlagName = "delayed-weth-proxy" + AnchorStateRegistryProxyFlagName = "anchor-state-registry-proxy" + L2ChainIdFlagName = "l2-chain-id" + ProposerFlagName = "proposer" + ChallengerFlagName = "challenger" + PreimageOracleFlagName = "preimage-oracle" ) var ( @@ -16,12 +37,163 @@ var ( Usage: "Locator for artifacts.", EnvVars: deployer.PrefixEnvVar("ARTIFACTS_LOCATOR"), } + WithdrawalDelaySecondsFlag = &cli.Uint64Flag{ + Name: WithdrawalDelaySecondsFlagName, + Usage: "Withdrawal delay in seconds.", + EnvVars: deployer.PrefixEnvVar("WITHDRAWAL_DELAY_SECONDS"), + Value: standard.WithdrawalDelaySeconds, + } + MinProposalSizeBytesFlag = &cli.Uint64Flag{ + Name: MinProposalSizeBytesFlagName, + Usage: "Minimum proposal size in bytes.", + EnvVars: deployer.PrefixEnvVar("MIN_PROPOSAL_SIZE_BYTES"), + Value: standard.MinProposalSizeBytes, + } + ChallengePeriodSecondsFlag = &cli.Uint64Flag{ + Name: ChallengePeriodSecondsFlagName, + Usage: "Challenge period in seconds.", + EnvVars: deployer.PrefixEnvVar("CHALLENGE_PERIOD_SECONDS"), + Value: standard.ChallengePeriodSeconds, + } + ProofMaturityDelaySecondsFlag = &cli.Uint64Flag{ + Name: ProofMaturityDelaySecondsFlagName, + Usage: "Proof maturity delay in seconds.", + EnvVars: deployer.PrefixEnvVar("PROOF_MATURITY_DELAY_SECONDS"), + Value: standard.ProofMaturityDelaySeconds, + } + DisputeGameFinalityDelaySecondsFlag = &cli.Uint64Flag{ + Name: DisputeGameFinalityDelaySecondsFlagName, + Usage: "Dispute game finality delay in seconds.", + EnvVars: deployer.PrefixEnvVar("DISPUTE_GAME_FINALITY_DELAY_SECONDS"), + Value: standard.DisputeGameFinalityDelaySeconds, + } + MIPSVersionFlag = &cli.Uint64Flag{ + Name: MIPSVersionFlagName, + Usage: "MIPS version.", + EnvVars: deployer.PrefixEnvVar("MIPS_VERSION"), + Value: standard.MIPSVersion, + } + GameKindFlag = &cli.StringFlag{ + Name: GameKindFlagName, + Usage: "Game kind (FaultDisputeGame or PermissionedDisputeGame).", + EnvVars: deployer.PrefixEnvVar("GAME_KIND"), + Value: "FaultDisputeGame", + } + GameTypeFlag = &cli.StringFlag{ + Name: GameTypeFlagName, + Usage: "Game type (integer or fractional).", + EnvVars: deployer.PrefixEnvVar("GAME_TYPE"), + } + AbsolutePrestateFlag = &cli.StringFlag{ + Name: AbsolutePrestateFlagName, + Usage: "Absolute prestate.", + EnvVars: deployer.PrefixEnvVar("ABSOLUTE_PRESTATE"), + Value: standard.DisputeAbsolutePrestate.Hex(), + } + MaxGameDepthFlag = &cli.Uint64Flag{ + Name: MaxGameDepthFlagName, + Usage: "Max game depth.", + EnvVars: deployer.PrefixEnvVar("MAX_GAME_DEPTH"), + Value: standard.DisputeMaxGameDepth, + } + SplitDepthFlag = &cli.Uint64Flag{ + Name: SplitDepthFlagName, + Usage: "Split depth.", + EnvVars: deployer.PrefixEnvVar("SPLIT_DEPTH"), + Value: standard.DisputeSplitDepth, + } + ClockExtensionFlag = &cli.Uint64Flag{ + Name: ClockExtensionFlagName, + Usage: "Clock extension.", + EnvVars: deployer.PrefixEnvVar("CLOCK_EXTENSION"), + Value: standard.DisputeClockExtension, + } + MaxClockDurationFlag = &cli.Uint64Flag{ + Name: MaxClockDurationFlagName, + Usage: "Max clock duration.", + EnvVars: deployer.PrefixEnvVar("MAX_CLOCK_DURATION"), + Value: standard.DisputeMaxClockDuration, + } + DelayedWethProxyFlag = &cli.StringFlag{ + Name: DelayedWethProxyFlagName, + Usage: "Delayed WETH proxy.", + EnvVars: deployer.PrefixEnvVar("DELAYED_WETH_PROXY"), + } + AnchorStateRegistryProxyFlag = &cli.StringFlag{ + Name: AnchorStateRegistryProxyFlagName, + Usage: "Anchor state registry proxy.", + EnvVars: deployer.PrefixEnvVar("ANCHOR_STATE_REGISTRY_PROXY"), + } + L2ChainIdFlag = &cli.Uint64Flag{ + Name: L2ChainIdFlagName, + Usage: "L2 chain ID.", + EnvVars: deployer.PrefixEnvVar("L2_CHAIN_ID"), + } + ProposerFlag = &cli.StringFlag{ + Name: ProposerFlagName, + Usage: "Proposer address (permissioned game only).", + EnvVars: deployer.PrefixEnvVar("PROPOSER"), + Value: common.Address{}.Hex(), + } + ChallengerFlag = &cli.StringFlag{ + Name: ChallengerFlagName, + Usage: "Challenger address (permissioned game only).", + EnvVars: deployer.PrefixEnvVar("CHALLENGER"), + Value: common.Address{}.Hex(), + } + PreimageOracleFlag = &cli.StringFlag{ + Name: PreimageOracleFlagName, + Usage: "Preimage oracle address.", + EnvVars: deployer.PrefixEnvVar("PREIMAGE_ORACLE"), + Value: common.Address{}.Hex(), + } ) var OPCMFlags = []cli.Flag{ deployer.L1RPCURLFlag, deployer.PrivateKeyFlag, ArtifactsLocatorFlag, + WithdrawalDelaySecondsFlag, + MinProposalSizeBytesFlag, + ChallengePeriodSecondsFlag, + ProofMaturityDelaySecondsFlag, + DisputeGameFinalityDelaySecondsFlag, + MIPSVersionFlag, +} + +var DelayedWETHFlags = []cli.Flag{ + deployer.L1RPCURLFlag, + deployer.PrivateKeyFlag, + ArtifactsLocatorFlag, +} + +var DisputeGameFlags = []cli.Flag{ + deployer.L1RPCURLFlag, + deployer.PrivateKeyFlag, + ArtifactsLocatorFlag, + MinProposalSizeBytesFlag, + ChallengePeriodSecondsFlag, + MIPSVersionFlag, + GameKindFlag, + GameTypeFlag, + AbsolutePrestateFlag, + MaxGameDepthFlag, + SplitDepthFlag, + ClockExtensionFlag, + MaxClockDurationFlag, + DelayedWethProxyFlag, + AnchorStateRegistryProxyFlag, + L2ChainIdFlag, + ProposerFlag, + ChallengerFlag, +} + +var MIPSFlags = []cli.Flag{ + deployer.L1RPCURLFlag, + deployer.PrivateKeyFlag, + ArtifactsLocatorFlag, + PreimageOracleFlag, + MIPSVersionFlag, } var Commands = []*cli.Command{ @@ -31,4 +203,22 @@ var Commands = []*cli.Command{ Flags: cliapp.ProtectFlags(OPCMFlags), Action: OPCMCLI, }, + { + Name: "delayedweth", + Usage: "Bootstrap an instance of DelayedWETH.", + Flags: cliapp.ProtectFlags(DelayedWETHFlags), + Action: DelayedWETHCLI, + }, + { + Name: "disputegame", + Usage: "Bootstrap an instance of a FaultDisputeGame or PermissionedDisputeGame.", + Flags: cliapp.ProtectFlags(DisputeGameFlags), + Action: DisputeGameCLI, + }, + { + Name: "mips", + Usage: "Bootstrap an instance of MIPS.", + Flags: cliapp.ProtectFlags(MIPSFlags), + Action: MIPSCLI, + }, } diff --git a/op-deployer/pkg/deployer/bootstrap/mips.go b/op-deployer/pkg/deployer/bootstrap/mips.go new file mode 100644 index 0000000000000..efc1fd1c6e042 --- /dev/null +++ b/op-deployer/pkg/deployer/bootstrap/mips.go @@ -0,0 +1,196 @@ +package bootstrap + +import ( + "context" + "crypto/ecdsa" + "fmt" + "strings" + + artifacts2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" + "github.com/ethereum/go-ethereum/common" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" + opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto" + "github.com/ethereum-optimism/optimism/op-service/ctxinterrupt" + "github.com/ethereum-optimism/optimism/op-service/ioutil" + "github.com/ethereum-optimism/optimism/op-service/jsonutil" + oplog "github.com/ethereum-optimism/optimism/op-service/log" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "github.com/urfave/cli/v2" +) + +type MIPSConfig struct { + L1RPCUrl string + PrivateKey string + Logger log.Logger + ArtifactsLocator *artifacts2.Locator + + privateKeyECDSA *ecdsa.PrivateKey + + PreimageOracle common.Address + MipsVersion uint64 +} + +func (c *MIPSConfig) Check() error { + if c.L1RPCUrl == "" { + return fmt.Errorf("l1RPCUrl must be specified") + } + + if c.PrivateKey == "" { + return fmt.Errorf("private key must be specified") + } + + privECDSA, err := crypto.HexToECDSA(strings.TrimPrefix(c.PrivateKey, "0x")) + if err != nil { + return fmt.Errorf("failed to parse private key: %w", err) + } + c.privateKeyECDSA = privECDSA + + if c.Logger == nil { + return fmt.Errorf("logger must be specified") + } + + if c.ArtifactsLocator == nil { + return fmt.Errorf("artifacts locator must be specified") + } + + if c.PreimageOracle == (common.Address{}) { + return fmt.Errorf("preimage oracle must be specified") + } + + if c.MipsVersion == 0 { + return fmt.Errorf("mips version must be specified") + } + if c.MipsVersion != 1 && c.MipsVersion != 2 { + return fmt.Errorf("mips version must be either 1 or 2") + } + + return nil +} + +func MIPSCLI(cliCtx *cli.Context) error { + logCfg := oplog.ReadCLIConfig(cliCtx) + l := oplog.NewLogger(oplog.AppOut(cliCtx), logCfg) + oplog.SetGlobalLogHandler(l.Handler()) + + l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName) + privateKey := cliCtx.String(deployer.PrivateKeyFlagName) + artifactsURLStr := cliCtx.String(ArtifactsLocatorFlagName) + artifactsLocator := new(artifacts2.Locator) + if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil { + return fmt.Errorf("failed to parse artifacts URL: %w", err) + } + + mipsVersion := cliCtx.Uint64(MIPSVersionFlagName) + preimageOracle := common.HexToAddress(cliCtx.String(PreimageOracleFlagName)) + + ctx := ctxinterrupt.WithCancelOnInterrupt(cliCtx.Context) + + return MIPS(ctx, MIPSConfig{ + L1RPCUrl: l1RPCUrl, + PrivateKey: privateKey, + Logger: l, + ArtifactsLocator: artifactsLocator, + MipsVersion: mipsVersion, + PreimageOracle: preimageOracle, + }) +} + +func MIPS(ctx context.Context, cfg MIPSConfig) error { + if err := cfg.Check(); err != nil { + return fmt.Errorf("invalid config for MIPS: %w", err) + } + + lgr := cfg.Logger + progressor := func(curr, total int64) { + lgr.Info("artifacts download progress", "current", curr, "total", total) + } + + artifactsFS, cleanup, err := artifacts2.Download(ctx, cfg.ArtifactsLocator, progressor) + if err != nil { + return fmt.Errorf("failed to download artifacts: %w", err) + } + defer func() { + if err := cleanup(); err != nil { + lgr.Warn("failed to clean up artifacts", "err", err) + } + }() + + l1Client, err := ethclient.Dial(cfg.L1RPCUrl) + if err != nil { + return fmt.Errorf("failed to connect to L1 RPC: %w", err) + } + + chainID, err := l1Client.ChainID(ctx) + if err != nil { + return fmt.Errorf("failed to get chain ID: %w", err) + } + + signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(cfg.privateKeyECDSA, chainID)) + chainDeployer := crypto.PubkeyToAddress(cfg.privateKeyECDSA.PublicKey) + + bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{ + Logger: lgr, + ChainID: chainID, + Client: l1Client, + Signer: signer, + From: chainDeployer, + }) + if err != nil { + return fmt.Errorf("failed to create broadcaster: %w", err) + } + + nonce, err := l1Client.NonceAt(ctx, chainDeployer, nil) + if err != nil { + return fmt.Errorf("failed to get starting nonce: %w", err) + } + + host, err := env.DefaultScriptHost( + bcaster, + lgr, + chainDeployer, + artifactsFS, + ) + if err != nil { + return fmt.Errorf("failed to create script host: %w", err) + } + host.SetNonce(chainDeployer, nonce) + + var release string + if cfg.ArtifactsLocator.IsTag() { + release = cfg.ArtifactsLocator.Tag + } else { + release = "dev" + } + + lgr.Info("deploying dispute game", "release", release) + + dgo, err := opcm.DeployMIPS( + host, + opcm.DeployMIPSInput{ + MipsVersion: cfg.MipsVersion, + PreimageOracle: cfg.PreimageOracle, + }, + ) + if err != nil { + return fmt.Errorf("error deploying dispute game: %w", err) + } + + if _, err := bcaster.Broadcast(ctx); err != nil { + return fmt.Errorf("failed to broadcast: %w", err) + } + + lgr.Info("deployed dispute game") + + if err := jsonutil.WriteJSON(dgo, ioutil.ToStdOut()); err != nil { + return fmt.Errorf("failed to write output: %w", err) + } + return nil +} diff --git a/op-deployer/pkg/deployer/bootstrap/bootstrap.go b/op-deployer/pkg/deployer/bootstrap/opcm.go similarity index 68% rename from op-deployer/pkg/deployer/bootstrap/bootstrap.go rename to op-deployer/pkg/deployer/bootstrap/opcm.go index 8bc61698e2a78..89a8c3df5123e 100644 --- a/op-deployer/pkg/deployer/bootstrap/bootstrap.go +++ b/op-deployer/pkg/deployer/bootstrap/opcm.go @@ -8,6 +8,12 @@ import ( "math/big" "strings" + artifacts2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" @@ -28,10 +34,12 @@ import ( ) type OPCMConfig struct { + pipeline.SuperchainProofParams + L1RPCUrl string PrivateKey string Logger log.Logger - ArtifactsLocator *opcm.ArtifactsLocator + ArtifactsLocator *artifacts2.Locator privateKeyECDSA *ecdsa.PrivateKey } @@ -59,6 +67,30 @@ func (c *OPCMConfig) Check() error { return fmt.Errorf("artifacts locator must be specified") } + if c.WithdrawalDelaySeconds == 0 { + c.WithdrawalDelaySeconds = standard.WithdrawalDelaySeconds + } + + if c.MinProposalSizeBytes == 0 { + c.MinProposalSizeBytes = standard.MinProposalSizeBytes + } + + if c.ChallengePeriodSeconds == 0 { + c.ChallengePeriodSeconds = standard.ChallengePeriodSeconds + } + + if c.ProofMaturityDelaySeconds == 0 { + c.ProofMaturityDelaySeconds = standard.ProofMaturityDelaySeconds + } + + if c.DisputeGameFinalityDelaySeconds == 0 { + c.DisputeGameFinalityDelaySeconds = standard.DisputeGameFinalityDelaySeconds + } + + if c.MIPSVersion == 0 { + c.MIPSVersion = standard.MIPSVersion + } + return nil } @@ -70,7 +102,7 @@ func OPCMCLI(cliCtx *cli.Context) error { l1RPCUrl := cliCtx.String(deployer.L1RPCURLFlagName) privateKey := cliCtx.String(deployer.PrivateKeyFlagName) artifactsURLStr := cliCtx.String(ArtifactsLocatorFlagName) - artifactsLocator := new(opcm.ArtifactsLocator) + artifactsLocator := new(artifacts2.Locator) if err := artifactsLocator.UnmarshalText([]byte(artifactsURLStr)); err != nil { return fmt.Errorf("failed to parse artifacts URL: %w", err) } @@ -82,6 +114,14 @@ func OPCMCLI(cliCtx *cli.Context) error { PrivateKey: privateKey, Logger: l, ArtifactsLocator: artifactsLocator, + SuperchainProofParams: pipeline.SuperchainProofParams{ + WithdrawalDelaySeconds: cliCtx.Uint64(WithdrawalDelaySecondsFlagName), + MinProposalSizeBytes: cliCtx.Uint64(MinProposalSizeBytesFlagName), + ChallengePeriodSeconds: cliCtx.Uint64(ChallengePeriodSecondsFlagName), + ProofMaturityDelaySeconds: cliCtx.Uint64(ProofMaturityDelaySecondsFlagName), + DisputeGameFinalityDelaySeconds: cliCtx.Uint64(DisputeGameFinalityDelaySecondsFlagName), + MIPSVersion: cliCtx.Uint64(MIPSVersionFlagName), + }, }) } @@ -95,7 +135,7 @@ func OPCM(ctx context.Context, cfg OPCMConfig) error { lgr.Info("artifacts download progress", "current", curr, "total", total) } - artifactsFS, cleanup, err := pipeline.DownloadArtifacts(ctx, cfg.ArtifactsLocator, progressor) + artifactsFS, cleanup, err := artifacts2.Download(ctx, cfg.ArtifactsLocator, progressor) if err != nil { return fmt.Errorf("failed to download artifacts: %w", err) } @@ -116,18 +156,14 @@ func OPCM(ctx context.Context, cfg OPCMConfig) error { } chainIDU64 := chainID.Uint64() - superCfg, err := opcm.SuperchainFor(chainIDU64) + superCfg, err := standard.SuperchainFor(chainIDU64) if err != nil { return fmt.Errorf("error getting superchain config: %w", err) } - standardVersionsTOML, err := opcm.StandardL1VersionsDataFor(chainIDU64) + standardVersionsTOML, err := standard.L1VersionsDataFor(chainIDU64) if err != nil { return fmt.Errorf("error getting standard versions TOML: %w", err) } - opcmProxyOwnerAddr, err := opcm.ManagerOwnerAddrFor(chainIDU64) - if err != nil { - return fmt.Errorf("error getting superchain proxy admin: %w", err) - } signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(cfg.privateKeyECDSA, chainID)) chainDeployer := crypto.PubkeyToAddress(cfg.privateKeyECDSA.PublicKey) @@ -148,25 +184,25 @@ func OPCM(ctx context.Context, cfg OPCMConfig) error { return fmt.Errorf("failed to get starting nonce: %w", err) } - host, err := pipeline.DefaultScriptHost( + host, err := env.DefaultScriptHost( bcaster, lgr, chainDeployer, artifactsFS, - nonce, ) if err != nil { return fmt.Errorf("failed to create script host: %w", err) } + host.SetNonce(chainDeployer, nonce) - var release string + var l1ContractsRelease string if cfg.ArtifactsLocator.IsTag() { - release = cfg.ArtifactsLocator.Tag + l1ContractsRelease = cfg.ArtifactsLocator.Tag } else { - release = "dev" + l1ContractsRelease = "dev" } - lgr.Info("deploying OPCM", "release", release) + lgr.Info("deploying OPCM", "l1ContractsRelease", l1ContractsRelease) // We need to etch the Superchain addresses so that they have nonzero code // and the checks in the OPCM constructor pass. @@ -192,15 +228,15 @@ func OPCM(ctx context.Context, cfg OPCMConfig) error { host, opcm.DeployImplementationsInput{ Salt: salt, - WithdrawalDelaySeconds: big.NewInt(604800), - MinProposalSizeBytes: big.NewInt(126000), - ChallengePeriodSeconds: big.NewInt(86400), - ProofMaturityDelaySeconds: big.NewInt(604800), - DisputeGameFinalityDelaySeconds: big.NewInt(302400), - Release: release, + WithdrawalDelaySeconds: new(big.Int).SetUint64(cfg.WithdrawalDelaySeconds), + MinProposalSizeBytes: new(big.Int).SetUint64(cfg.MinProposalSizeBytes), + ChallengePeriodSeconds: new(big.Int).SetUint64(cfg.ChallengePeriodSeconds), + ProofMaturityDelaySeconds: new(big.Int).SetUint64(cfg.ProofMaturityDelaySeconds), + DisputeGameFinalityDelaySeconds: new(big.Int).SetUint64(cfg.DisputeGameFinalityDelaySeconds), + MipsVersion: new(big.Int).SetUint64(cfg.MIPSVersion), + L1ContractsRelease: l1ContractsRelease, SuperchainConfigProxy: superchainConfigAddr, ProtocolVersionsProxy: protocolVersionsAddr, - OpcmProxyOwner: opcmProxyOwnerAddr, StandardVersionsToml: standardVersionsTOML, UseInterop: false, }, diff --git a/op-deployer/pkg/deployer/broadcaster/keyed.go b/op-deployer/pkg/deployer/broadcaster/keyed.go index f5797d9391560..c9bb27fcf0cec 100644 --- a/op-deployer/pkg/deployer/broadcaster/keyed.go +++ b/op-deployer/pkg/deployer/broadcaster/keyed.go @@ -90,6 +90,9 @@ func NewKeyedBroadcaster(cfg KeyedBroadcasterOpts) (*KeyedBroadcaster, error) { } func (t *KeyedBroadcaster) Hook(bcast script.Broadcast) { + if bcast.Type != script.BroadcastCreate2 && bcast.From != t.mgr.From() { + panic(fmt.Sprintf("invalid from for broadcast:%v, expected:%v", bcast.From, t.mgr.From())) + } t.mtx.Lock() t.bcasts = append(t.bcasts, bcast) t.mtx.Unlock() diff --git a/op-deployer/pkg/deployer/init.go b/op-deployer/pkg/deployer/init.go index a81ef6f48a24d..3a8ae27d2ae79 100644 --- a/op-deployer/pkg/deployer/init.go +++ b/op-deployer/pkg/deployer/init.go @@ -7,7 +7,8 @@ import ( "path" "strings" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" op_service "github.com/ethereum-optimism/optimism/op-service" @@ -89,8 +90,8 @@ func Init(cfg InitConfig) error { DeploymentStrategy: cfg.DeploymentStrategy, L1ChainID: cfg.L1ChainID, FundDevAccounts: true, - L1ContractsLocator: opcm.DefaultL1ContractsLocator, - L2ContractsLocator: opcm.DefaultL2ContractsLocator, + L1ContractsLocator: artifacts.DefaultL1ContractsLocator, + L2ContractsLocator: artifacts.DefaultL2ContractsLocator, } l1ChainIDBig := intent.L1ChainIDBig() @@ -118,9 +119,9 @@ func Init(cfg InitConfig) error { l2ChainIDBig := l2ChainID.Big() intent.Chains = append(intent.Chains, &state.ChainIntent{ ID: l2ChainID, - BaseFeeVaultRecipient: common.Address{}, - L1FeeVaultRecipient: common.Address{}, - SequencerFeeVaultRecipient: common.Address{}, + BaseFeeVaultRecipient: addrFor(devkeys.BaseFeeVaultRecipientRole.Key(l2ChainIDBig)), + L1FeeVaultRecipient: addrFor(devkeys.L1FeeVaultRecipientRole.Key(l2ChainIDBig)), + SequencerFeeVaultRecipient: addrFor(devkeys.SequencerFeeVaultRecipientRole.Key(l2ChainIDBig)), Eip1559Denominator: 50, Eip1559Elasticity: 6, Roles: state.ChainRoles{ diff --git a/op-deployer/pkg/deployer/inspect/deploy_config.go b/op-deployer/pkg/deployer/inspect/deploy_config.go index ead006c7d6222..575576633ab71 100644 --- a/op-deployer/pkg/deployer/inspect/deploy_config.go +++ b/op-deployer/pkg/deployer/inspect/deploy_config.go @@ -3,10 +3,12 @@ package inspect import ( "fmt" + "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" "github.com/ethereum-optimism/optimism/op-service/ioutil" "github.com/ethereum-optimism/optimism/op-service/jsonutil" + "github.com/ethereum/go-ethereum/common" "github.com/urfave/cli/v2" ) @@ -18,29 +20,40 @@ func DeployConfigCLI(cliCtx *cli.Context) error { globalState, err := pipeline.ReadState(cliCfg.Workdir) if err != nil { - return fmt.Errorf("failed to read intent: %w", err) + return fmt.Errorf("failed to read globalState: %w", err) } - chainState, err := globalState.Chain(cliCfg.ChainID) + + config, err := DeployConfig(globalState, cliCfg.ChainID) if err != nil { - return fmt.Errorf("failed to find chain state: %w", err) + return fmt.Errorf("failed to generate deploy config: %w", err) + } + + if err := jsonutil.WriteJSON(config, ioutil.ToStdOutOrFileOrNoop(cliCfg.Outfile, 0o666)); err != nil { + return fmt.Errorf("failed to write deploy config: %w", err) + } + + return nil +} + +func DeployConfig(globalState *state.State, chainID common.Hash) (*genesis.DeployConfig, error) { + chainState, err := globalState.Chain(chainID) + if err != nil { + return nil, fmt.Errorf("failed to find chain state: %w", err) } intent := globalState.AppliedIntent if intent == nil { - return fmt.Errorf("can only run this command following a full apply") + return nil, fmt.Errorf("can only run this command following a full apply") } - chainIntent, err := intent.Chain(cliCfg.ChainID) + chainIntent, err := intent.Chain(chainID) if err != nil { - return fmt.Errorf("failed to find chain intent: %w", err) + return nil, fmt.Errorf("failed to find chain intent: %w", err) } config, err := state.CombineDeployConfig(intent, chainIntent, globalState, chainState) if err != nil { - return fmt.Errorf("failed to generate deploy config: %w", err) - } - if err := jsonutil.WriteJSON(config, ioutil.ToStdOutOrFileOrNoop(cliCfg.Outfile, 0o666)); err != nil { - return fmt.Errorf("failed to write deploy config: %w", err) + return nil, fmt.Errorf("failed to generate deploy config: %w", err) } - return nil + return &config, nil } diff --git a/op-deployer/pkg/deployer/inspect/flags.go b/op-deployer/pkg/deployer/inspect/flags.go index 2f94edc088e58..3f74e1d759b2f 100644 --- a/op-deployer/pkg/deployer/inspect/flags.go +++ b/op-deployer/pkg/deployer/inspect/flags.go @@ -69,6 +69,14 @@ var Commands = []*cli.Command{ Action: L2SemversCLI, Flags: Flags, }, + { + Name: "superchain-registry", + Usage: "outputs the .env file expected by superchain-registry add-chain tool", + Args: true, + ArgsUsage: "", + Action: SuperchainRegistryCLI, + Flags: Flags, + }, } type cliConfig struct { diff --git a/op-deployer/pkg/deployer/inspect/l1.go b/op-deployer/pkg/deployer/inspect/l1.go index a5391810aec54..4883e83486c35 100644 --- a/op-deployer/pkg/deployer/inspect/l1.go +++ b/op-deployer/pkg/deployer/inspect/l1.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" "github.com/ethereum-optimism/optimism/op-service/ioutil" "github.com/ethereum-optimism/optimism/op-service/jsonutil" @@ -37,14 +38,14 @@ type OpChainDeployment struct { DisputeGameFactoryProxyAddress common.Address `json:"disputeGameFactoryProxyAddress"` AnchorStateRegistryProxyAddress common.Address `json:"anchorStateRegistryProxyAddress"` AnchorStateRegistryImplAddress common.Address `json:"anchorStateRegistryImplAddress"` - // FaultDisputeGameAddress common.Address `json:"faultDisputeGameAddress"` - PermissionedDisputeGameAddress common.Address `json:"permissionedDisputeGameAddress"` - DelayedWETHPermissionedGameProxyAddress common.Address `json:"delayedWETHPermissionedGameProxyAddress"` + FaultDisputeGameAddress common.Address `json:"faultDisputeGameAddress"` + PermissionedDisputeGameAddress common.Address `json:"permissionedDisputeGameAddress"` + DelayedWETHPermissionedGameProxyAddress common.Address `json:"delayedWETHPermissionedGameProxyAddress"` // DelayedWETHPermissionlessGameProxyAddress common.Address `json:"delayedWETHPermissionlessGameProxyAddress"` } type ImplementationsDeployment struct { - OpcmProxyAddress common.Address `json:"opcmProxyAddress"` + OpcmAddress common.Address `json:"opcmAddress"` DelayedWETHImplAddress common.Address `json:"delayedWETHImplAddress"` OptimismPortalImplAddress common.Address `json:"optimismPortalImplAddress"` PreimageOracleSingletonAddress common.Address `json:"preimageOracleSingletonAddress"` @@ -68,9 +69,22 @@ func L1CLI(cliCtx *cli.Context) error { return fmt.Errorf("failed to read intent: %w", err) } - chainState, err := globalState.Chain(cfg.ChainID) + l1Contracts, err := L1(globalState, cfg.ChainID) if err != nil { - return fmt.Errorf("failed to get chain state for ID %s: %w", cfg.ChainID.String(), err) + return fmt.Errorf("failed to generate l1Contracts: %w", err) + } + + if err := jsonutil.WriteJSON(l1Contracts, ioutil.ToStdOutOrFileOrNoop(cfg.Outfile, 0o666)); err != nil { + return fmt.Errorf("failed to write L1 contract addresses: %w", err) + } + + return nil +} + +func L1(globalState *state.State, chainID common.Hash) (*L1Contracts, error) { + chainState, err := globalState.Chain(chainID) + if err != nil { + return nil, fmt.Errorf("failed to get chain state for ID %s: %w", chainID.String(), err) } l1Contracts := L1Contracts{ @@ -93,13 +107,13 @@ func L1CLI(cliCtx *cli.Context) error { DisputeGameFactoryProxyAddress: chainState.DisputeGameFactoryProxyAddress, AnchorStateRegistryProxyAddress: chainState.AnchorStateRegistryProxyAddress, AnchorStateRegistryImplAddress: chainState.AnchorStateRegistryImplAddress, - // FaultDisputeGameAddress: chainState.FaultDisputeGameAddress, - PermissionedDisputeGameAddress: chainState.PermissionedDisputeGameAddress, - DelayedWETHPermissionedGameProxyAddress: chainState.DelayedWETHPermissionedGameProxyAddress, + FaultDisputeGameAddress: chainState.FaultDisputeGameAddress, + PermissionedDisputeGameAddress: chainState.PermissionedDisputeGameAddress, + DelayedWETHPermissionedGameProxyAddress: chainState.DelayedWETHPermissionedGameProxyAddress, // DelayedWETHPermissionlessGameProxyAddress: chainState.DelayedWETHPermissionlessGameProxyAddress, }, ImplementationsDeployment: ImplementationsDeployment{ - OpcmProxyAddress: globalState.ImplementationsDeployment.OpcmProxyAddress, + OpcmAddress: globalState.ImplementationsDeployment.OpcmAddress, DelayedWETHImplAddress: globalState.ImplementationsDeployment.DelayedWETHImplAddress, OptimismPortalImplAddress: globalState.ImplementationsDeployment.OptimismPortalImplAddress, PreimageOracleSingletonAddress: globalState.ImplementationsDeployment.PreimageOracleSingletonAddress, @@ -113,9 +127,5 @@ func L1CLI(cliCtx *cli.Context) error { }, } - if err := jsonutil.WriteJSON(l1Contracts, ioutil.ToStdOutOrFileOrNoop(cfg.Outfile, 0o666)); err != nil { - return fmt.Errorf("failed to write L1 contract addresses: %w", err) - } - - return nil + return &l1Contracts, nil } diff --git a/op-deployer/pkg/deployer/inspect/rollup.go b/op-deployer/pkg/deployer/inspect/rollup.go index 59e49c9045412..d094427d951f7 100644 --- a/op-deployer/pkg/deployer/inspect/rollup.go +++ b/op-deployer/pkg/deployer/inspect/rollup.go @@ -22,6 +22,9 @@ func RollupCLI(cliCtx *cli.Context) error { } _, rollupConfig, err := GenesisAndRollup(globalState, cfg.ChainID) + if rollupConfig.HoloceneTime == nil { + rollupConfig.Genesis.SystemConfig.MarshalPreHolocene = true + } if err != nil { return fmt.Errorf("failed to generate rollup config: %w", err) } diff --git a/op-deployer/pkg/deployer/inspect/semvers.go b/op-deployer/pkg/deployer/inspect/semvers.go index f88f2c01476a5..48e16d21dbc43 100644 --- a/op-deployer/pkg/deployer/inspect/semvers.go +++ b/op-deployer/pkg/deployer/inspect/semvers.go @@ -8,6 +8,14 @@ import ( "regexp" "time" + "github.com/ethereum-optimism/optimism/op-chain-ops/foundry" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" + "github.com/ethereum/go-ethereum/log" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + "github.com/ethereum-optimism/optimism/op-chain-ops/script" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" @@ -21,8 +29,6 @@ import ( "github.com/urfave/cli/v2" ) -var versionSelector = []byte{0x54, 0xfd, 0x4d, 0x50} - func L2SemversCLI(cliCtx *cli.Context) error { cliCfg, err := readConfig(cliCtx) if err != nil { @@ -53,7 +59,7 @@ func L2SemversCLI(cliCtx *cli.Context) error { return fmt.Errorf("chain state does not have allocs") } - artifactsFS, cleanup, err := pipeline.DownloadArtifacts(ctx, intent.L2ContractsLocator, pipeline.LogProgressor(l)) + artifactsFS, cleanup, err := artifacts.Download(ctx, intent.L2ContractsLocator, artifacts.LogProgressor(l)) if err != nil { return fmt.Errorf("failed to download L2 artifacts: %w", err) } @@ -63,93 +69,150 @@ func L2SemversCLI(cliCtx *cli.Context) error { } }() - host, err := pipeline.DefaultScriptHost( + ps, err := L2Semvers(L2SemversConfig{ + Lgr: l, + Artifacts: artifactsFS, + ChainState: chainState, + }) + if err != nil { + return fmt.Errorf("failed to get L2 semvers: %w", err) + } + + if err := jsonutil.WriteJSON(ps, ioutil.ToStdOutOrFileOrNoop(cliCfg.Outfile, 0o666)); err != nil { + return fmt.Errorf("failed to write rollup config: %w", err) + } + + return nil +} + +type L2SemversConfig struct { + Lgr log.Logger + Artifacts foundry.StatDirFs + ChainState *state.ChainState +} + +type L2PredeploySemvers struct { + L2ToL1MessagePasser string + DeployerWhitelist string + WETH string + L2CrossDomainMessenger string + L2StandardBridge string + SequencerFeeVault string + OptimismMintableERC20Factory string + L1BlockNumber string + GasPriceOracle string + L1Block string + LegacyMessagePasser string + L2ERC721Bridge string + OptimismMintableERC721Factory string + BaseFeeVault string + L1FeeVault string + SchemaRegistry string + EAS string + CrossL2Inbox string + L2toL2CrossDomainMessenger string + SuperchainWETH string + ETHLiquidity string + SuperchainTokenBridge string + OptimismMintableERC20 string + OptimismMintableERC721 string +} + +func L2Semvers(cfg L2SemversConfig) (*L2PredeploySemvers, error) { + l := cfg.Lgr + artifactsFS := cfg.Artifacts + chainState := cfg.ChainState + + host, err := env.DefaultScriptHost( broadcaster.NoopBroadcaster(), l, common.Address{19: 0x01}, artifactsFS, - 0, ) if err != nil { - return fmt.Errorf("failed to create script host: %w", err) + return nil, fmt.Errorf("failed to create script host: %w", err) } host.ImportState(chainState.Allocs.Data) - addr := common.Address{19: 0x01} - type contractToCheck struct { - Address common.Address - Name string + Address common.Address + FieldPtr *string + Name string } - contractsOutput := make(map[string]string) + var ps L2PredeploySemvers - // The gov token and the proxy admin do not have semvers. contracts := []contractToCheck{ - {predeploys.L2ToL1MessagePasserAddr, "L2ToL1MessagePasser"}, - {predeploys.DeployerWhitelistAddr, "DeployerWhitelist"}, - {predeploys.WETHAddr, "WETH"}, - {predeploys.L2CrossDomainMessengerAddr, "L2CrossDomainMessenger"}, - {predeploys.L2StandardBridgeAddr, "L2StandardBridge"}, - {predeploys.SequencerFeeVaultAddr, "SequencerFeeVault"}, - {predeploys.OptimismMintableERC20FactoryAddr, "OptimismMintableERC20Factory"}, - {predeploys.L1BlockNumberAddr, "L1BlockNumber"}, - {predeploys.GasPriceOracleAddr, "GasPriceOracle"}, - {predeploys.L1BlockAddr, "L1Block"}, - {predeploys.LegacyMessagePasserAddr, "LegacyMessagePasser"}, - {predeploys.L2ERC721BridgeAddr, "L2ERC721Bridge"}, - {predeploys.OptimismMintableERC721FactoryAddr, "OptimismMintableERC721Factory"}, - {predeploys.BaseFeeVaultAddr, "BaseFeeVault"}, - {predeploys.L1FeeVaultAddr, "L1FeeVault"}, - {predeploys.SchemaRegistryAddr, "SchemaRegistry"}, - {predeploys.EASAddr, "EAS"}, - {predeploys.WETHAddr, "WETH"}, + {predeploys.L2ToL1MessagePasserAddr, &ps.L2ToL1MessagePasser, "L2ToL1MessagePasser"}, + {predeploys.DeployerWhitelistAddr, &ps.DeployerWhitelist, "DeployerWhitelist"}, + {predeploys.WETHAddr, &ps.WETH, "WETH"}, + {predeploys.L2CrossDomainMessengerAddr, &ps.L2CrossDomainMessenger, "L2CrossDomainMessenger"}, + {predeploys.L2StandardBridgeAddr, &ps.L2StandardBridge, "L2StandardBridge"}, + {predeploys.SequencerFeeVaultAddr, &ps.SequencerFeeVault, "SequencerFeeVault"}, + {predeploys.OptimismMintableERC20FactoryAddr, &ps.OptimismMintableERC20Factory, "OptimismMintableERC20Factory"}, + {predeploys.L1BlockNumberAddr, &ps.L1BlockNumber, "L1BlockNumber"}, + {predeploys.GasPriceOracleAddr, &ps.GasPriceOracle, "GasPriceOracle"}, + {predeploys.L1BlockAddr, &ps.L1Block, "L1Block"}, + {predeploys.LegacyMessagePasserAddr, &ps.LegacyMessagePasser, "LegacyMessagePasser"}, + {predeploys.L2ERC721BridgeAddr, &ps.L2ERC721Bridge, "L2ERC721Bridge"}, + {predeploys.OptimismMintableERC721FactoryAddr, &ps.OptimismMintableERC721Factory, "OptimismMintableERC721Factory"}, + {predeploys.BaseFeeVaultAddr, &ps.BaseFeeVault, "BaseFeeVault"}, + {predeploys.L1FeeVaultAddr, &ps.L1FeeVault, "L1FeeVault"}, + {predeploys.SchemaRegistryAddr, &ps.SchemaRegistry, "SchemaRegistry"}, + {predeploys.EASAddr, &ps.EAS, "EAS"}, } for _, contract := range contracts { - data, _, err := host.Call( - addr, - contract.Address, - bytes.Clone(versionSelector), - 1_000_000_000, - uint256.NewInt(0), - ) + semver, err := ReadSemver(host, contract.Address) if err != nil { - return fmt.Errorf("failed to call version on %s: %w", contract.Name, err) - } - - // The second 32 bytes contain the length of the string - length := new(big.Int).SetBytes(data[32:64]).Int64() - // Start of the string data (after offset and length) - stringStart := 64 - stringEnd := int64(stringStart) + length - - // Bounds check - if stringEnd > int64(len(data)) { - return fmt.Errorf("string data out of bounds") + return nil, fmt.Errorf("failed to read semver for %s: %w", contract.Name, err) } - contractsOutput[contract.Name] = string(data[stringStart:stringEnd]) + *contract.FieldPtr = semver } erc20Semver, err := findSemverBytecode(host, predeploys.OptimismMintableERC20FactoryAddr) if err == nil { - contractsOutput["OptimismMintableERC20"] = erc20Semver + ps.OptimismMintableERC20 = erc20Semver } else { l.Warn("failed to find semver for OptimismMintableERC20", "err", err) } erc721Semver, err := findSemverBytecode(host, predeploys.OptimismMintableERC721FactoryAddr) if err == nil { - contractsOutput["OptimismMintableERC721"] = erc721Semver + ps.OptimismMintableERC721 = erc721Semver } else { l.Warn("failed to find semver for OptimismMintableERC721", "err", err) } - if err := jsonutil.WriteJSON(contractsOutput, ioutil.ToStdOutOrFileOrNoop(cliCfg.Outfile, 0o666)); err != nil { - return fmt.Errorf("failed to write rollup config: %w", err) + return &ps, nil +} + +var versionSelector = []byte{0x54, 0xfd, 0x4d, 0x50} + +func ReadSemver(host *script.Host, addr common.Address) (string, error) { + data, _, err := host.Call( + common.Address{19: 0x01}, + addr, + bytes.Clone(versionSelector), + 1_000_000_000, + uint256.NewInt(0), + ) + if err != nil { + return "", fmt.Errorf("failed to call version on %s: %w", addr, err) } - return nil + // The second 32 bytes contain the length of the string + length := new(big.Int).SetBytes(data[32:64]).Int64() + // Start of the string data (after offset and length) + stringStart := 64 + stringEnd := int64(stringStart) + length + + // Bounds check + if stringEnd > int64(len(data)) { + return "", fmt.Errorf("string data out of bounds") + } + + return string(data[stringStart:stringEnd]), nil } const patternLen = 24 diff --git a/op-deployer/pkg/deployer/inspect/superchain_registry.go b/op-deployer/pkg/deployer/inspect/superchain_registry.go new file mode 100644 index 0000000000000..7a6fe384db648 --- /dev/null +++ b/op-deployer/pkg/deployer/inspect/superchain_registry.go @@ -0,0 +1,173 @@ +package inspect + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" + "github.com/ethereum-optimism/optimism/op-service/ioutil" + "github.com/ethereum-optimism/optimism/op-service/jsonutil" + "github.com/ethereum/go-ethereum/common" + + "github.com/ethereum-optimism/superchain-registry/superchain" + + "github.com/urfave/cli/v2" +) + +func SuperchainRegistryCLI(cliCtx *cli.Context) error { + cfg, err := readConfig(cliCtx) + if err != nil { + return err + } + + globalIntent, err := pipeline.ReadIntent(cfg.Workdir) + if err != nil { + return fmt.Errorf("failed to read intent: %w", err) + } + + envVars := map[string]string{} + envVars["SCR_CHAIN_NAME"] = "" + envVars["SCR_CHAIN_SHORT_NAME"] = "" + envVars["SCR_PUBLIC_RPC"] = "" + envVars["SCR_SEQUENCER_RPC"] = "" + envVars["SCR_EXPLORER"] = "" + envVars["SCR_STANDARD_CHAIN_CANDIDATE"] = "false" + + creationCommit, err := standard.CommitForDeployTag(globalIntent.L2ContractsLocator.Tag) + if err != nil { + return fmt.Errorf("failed to get commit for deploy tag: %w", err) + } + envVars["SCR_GENESIS_CREATION_COMMIT"] = creationCommit + + l1ChainName, err := standard.ChainNameFor(globalIntent.L1ChainID) + if err != nil { + return fmt.Errorf("failed to get l1 chain name: %w", err) + } + envVars["SCR_SUPERCHAIN_TARGET"] = l1ChainName + + globalState, err := pipeline.ReadState(cfg.Workdir) + if err != nil { + return fmt.Errorf("failed to read state: %w", err) + } + + genesis, rollup, err := GenesisAndRollup(globalState, cfg.ChainID) + if err != nil { + return fmt.Errorf("failed to generate genesis and rollup: %w", err) + } + genesisFilepath := filepath.Join(cfg.Workdir, "genesis.json") + if err := jsonutil.WriteJSON(genesis, ioutil.ToStdOutOrFileOrNoop(genesisFilepath, 0o666)); err != nil { + return fmt.Errorf("failed to write genesis: %w", err) + } + rollupFilepath := filepath.Join(cfg.Workdir, "rollup.json") + if err := jsonutil.WriteJSON(rollup, ioutil.ToStdOutOrFileOrNoop(rollupFilepath, 0o666)); err != nil { + return fmt.Errorf("failed to write rollup: %w", err) + } + + deployConfig, err := DeployConfig(globalState, cfg.ChainID) + if err != nil { + return fmt.Errorf("failed to generate deploy config: %w", err) + } + deployConfigFilepath := filepath.Join(cfg.Workdir, "deploy-config.json") + if err := jsonutil.WriteJSON(deployConfig, ioutil.ToStdOutOrFileOrNoop(deployConfigFilepath, 0o666)); err != nil { + return fmt.Errorf("failed to write rollup: %w", err) + } + + l1Contracts, err := L1(globalState, cfg.ChainID) + if err != nil { + return fmt.Errorf("failed to generate l1 contracts: %w", err) + } + + addressList, err := createAddressList(l1Contracts, globalState.AppliedIntent, cfg.ChainID) + if err != nil { + return fmt.Errorf("failed to create address list: %w", err) + } + + addressListFilepath := filepath.Join(cfg.Workdir, "addresses.json") + if err := jsonutil.WriteJSON(addressList, ioutil.ToStdOutOrFileOrNoop(addressListFilepath, 0o666)); err != nil { + return fmt.Errorf("failed to write address list: %w", err) + } + + envVars["SCR_GENESIS"] = genesisFilepath + envVars["SCR_ROLLUP_CONFIG"] = rollupFilepath + envVars["SCR_DEPLOY_CONFIG"] = deployConfigFilepath + envVars["SCR_DEPLOYMENTS_DIR"] = addressListFilepath + + envFilepath := filepath.Join(cfg.Workdir, "superchain-registry.env") + err = writeEnvFile(envFilepath, envVars) + if err != nil { + return fmt.Errorf("failed to write .env file: %w", err) + } + + fmt.Printf("---------------------------------------------------\n"+ + "Please populate any empty values in your .env file\n"+ + "before creating your pull-request to add this chain\n"+ + "to the superchain-registry repo.\n\n"+ + " * %s\n"+ + "---------------------------------------------------\n", envFilepath, + ) + + return nil +} + +func writeEnvFile(filepath string, envVars map[string]string) error { + file, err := os.Create(filepath) + if err != nil { + return err + } + defer file.Close() + + for key, value := range envVars { + _, err := file.WriteString(fmt.Sprintf("%s=\"%s\"\n", key, value)) + if err != nil { + return err + } + } + + return nil +} + +func createAddressList(l1Contracts *L1Contracts, appliedIntent *state.Intent, chainId common.Hash) (*superchain.AddressList, error) { + chainIntent, err := appliedIntent.Chain(chainId) + if err != nil { + return nil, fmt.Errorf("failed to get applied chain intent: %w", err) + } + + addressList := superchain.AddressList{ + // Roles + Roles: superchain.Roles{ + Guardian: superchain.Address(appliedIntent.SuperchainRoles.Guardian), + SystemConfigOwner: superchain.Address(chainIntent.Roles.SystemConfigOwner), + ProxyAdminOwner: superchain.Address(chainIntent.Roles.L1ProxyAdminOwner), + Challenger: superchain.Address(chainIntent.Roles.Challenger), + Proposer: superchain.Address(chainIntent.Roles.Proposer), + UnsafeBlockSigner: superchain.Address(chainIntent.Roles.UnsafeBlockSigner), + BatchSubmitter: superchain.Address(chainIntent.Roles.Batcher), + }, + + // Contracts + AddressManager: superchain.Address(l1Contracts.OpChainDeployment.AddressManagerAddress), + L1CrossDomainMessengerProxy: superchain.Address(l1Contracts.OpChainDeployment.L1CrossDomainMessengerProxyAddress), + L1ERC721BridgeProxy: superchain.Address(l1Contracts.OpChainDeployment.L1ERC721BridgeProxyAddress), + L1StandardBridgeProxy: superchain.Address(l1Contracts.OpChainDeployment.L1StandardBridgeProxyAddress), + OptimismMintableERC20FactoryProxy: superchain.Address(l1Contracts.OpChainDeployment.OptimismMintableERC20FactoryProxyAddress), + OptimismPortalProxy: superchain.Address(l1Contracts.OpChainDeployment.OptimismPortalProxyAddress), + SystemConfigProxy: superchain.Address(l1Contracts.OpChainDeployment.SystemConfigProxyAddress), + + ProxyAdmin: superchain.Address(l1Contracts.OpChainDeployment.ProxyAdminAddress), + SuperchainConfig: superchain.Address(l1Contracts.SuperchainDeployment.SuperchainConfigProxyAddress), + + // Fault proof contracts + AnchorStateRegistryProxy: superchain.Address(l1Contracts.OpChainDeployment.AnchorStateRegistryProxyAddress), + DelayedWETHProxy: superchain.Address(l1Contracts.OpChainDeployment.L1CrossDomainMessengerProxyAddress), + DisputeGameFactoryProxy: superchain.Address(l1Contracts.OpChainDeployment.DisputeGameFactoryProxyAddress), + FaultDisputeGame: superchain.Address(l1Contracts.OpChainDeployment.FaultDisputeGameAddress), + MIPS: superchain.Address(l1Contracts.ImplementationsDeployment.MipsSingletonAddress), + PermissionedDisputeGame: superchain.Address(l1Contracts.OpChainDeployment.PermissionedDisputeGameAddress), + PreimageOracle: superchain.Address(l1Contracts.ImplementationsDeployment.PreimageOracleSingletonAddress), + } + + return &addressList, nil +} diff --git a/op-deployer/pkg/deployer/integration_test/apply_test.go b/op-deployer/pkg/deployer/integration_test/apply_test.go index e820603dfaf46..7f4c0cb06deb6 100644 --- a/op-deployer/pkg/deployer/integration_test/apply_test.go +++ b/op-deployer/pkg/deployer/integration_test/apply_test.go @@ -1,29 +1,34 @@ package integration_test import ( + "bufio" "bytes" + "compress/gzip" "context" + "crypto/rand" "encoding/hex" + "encoding/json" "fmt" "log/slog" + "maps" "math/big" - "net/url" "os" - "path" - "runtime" "testing" "time" - "github.com/ethereum-optimism/optimism/op-chain-ops/script" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" - "github.com/ethereum-optimism/optimism/op-service/testutils/anvil" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" + altda "github.com/ethereum-optimism/optimism/op-alt-da" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/inspect" + "github.com/ethereum-optimism/optimism/op-node/rollup" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/testutil" + "github.com/ethereum-optimism/optimism/op-service/testutils/anvil" + "github.com/ethereum/go-ethereum/crypto" op_e2e "github.com/ethereum-optimism/optimism/op-e2e" @@ -31,7 +36,6 @@ import ( "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" - opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto" "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testutils/kurtosisutil" @@ -100,36 +104,25 @@ func TestEndToEndApply(t *testing.T) { require.NoError(t, err) pk, err := dk.Secret(depKey) require.NoError(t, err) - signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(pk, l1ChainID)) l2ChainID1 := uint256.NewInt(1) l2ChainID2 := uint256.NewInt(2) - deployerAddr, err := dk.Address(depKey) - require.NoError(t, err) - - loc := localArtifactsLocator(t) - - bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{ - Logger: log.NewLogger(log.DiscardHandler()), - ChainID: l1ChainID, - Client: l1Client, - Signer: signer, - From: deployerAddr, - }) - require.NoError(t, err) - - env, bundle, _ := createEnv(t, ctx, lgr, l1Client, bcaster, deployerAddr) + loc, _ := testutil.LocalArtifacts(t) intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc) cg := ethClientCodeGetter(ctx, l1Client) t.Run("initial chain", func(t *testing.T) { require.NoError(t, deployer.ApplyPipeline( ctx, - env, - bundle, - intent, - st, + deployer.ApplyPipelineOpts{ + L1RPCUrl: rpcURL, + DeployerPrivateKey: pk, + Intent: intent, + State: st, + Logger: lgr, + StateWriter: pipeline.NoopStateWriter(), + }, )) validateSuperchainDeployment(t, st, cg) @@ -139,82 +132,514 @@ func TestEndToEndApply(t *testing.T) { t.Run("subsequent chain", func(t *testing.T) { // create a new environment with wiped state to ensure we can continue using the // state from the previous deployment - env, bundle, _ = createEnv(t, ctx, lgr, l1Client, bcaster, deployerAddr) intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID2)) require.NoError(t, deployer.ApplyPipeline( ctx, - env, - bundle, - intent, - st, + deployer.ApplyPipelineOpts{ + L1RPCUrl: rpcURL, + DeployerPrivateKey: pk, + Intent: intent, + State: st, + Logger: lgr, + StateWriter: pipeline.NoopStateWriter(), + }, )) validateOPChainDeployment(t, cg, st, intent) }) } -func localArtifactsLocator(t *testing.T) *opcm.ArtifactsLocator { - _, testFilename, _, ok := runtime.Caller(0) - require.Truef(t, ok, "failed to get test filename") - monorepoDir := path.Join(path.Dir(testFilename), "..", "..", "..", "..") - artifactsDir := path.Join(monorepoDir, "packages", "contracts-bedrock", "forge-artifacts") - artifactsURL, err := url.Parse(fmt.Sprintf("file://%s", artifactsDir)) +func TestApplyExistingOPCM(t *testing.T) { + anvil.Test(t) + + forkRPCUrl := os.Getenv("SEPOLIA_RPC_URL") + if forkRPCUrl == "" { + t.Skip("no fork RPC URL provided") + } + + lgr := testlog.Logger(t, slog.LevelDebug) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + + runner, err := anvil.New( + forkRPCUrl, + lgr, + ) + require.NoError(t, err) + + require.NoError(t, runner.Start(ctx)) + t.Cleanup(func() { + require.NoError(t, runner.Stop()) + }) + + l1Client, err := ethclient.Dial(runner.RPCUrl()) + require.NoError(t, err) + + l1ChainID := big.NewInt(11155111) + dk, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic) + require.NoError(t, err) + // index 0 from Anvil's test set + pk, err := crypto.HexToECDSA("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") + require.NoError(t, err) + + l2ChainID := uint256.NewInt(1) + + // Hardcode the below tags to ensure the test is validating the correct + // version even if the underlying tag changes + intent, st := newIntent( + t, + l1ChainID, + dk, + l2ChainID, + artifacts.MustNewLocatorFromTag("op-contracts/v1.6.0"), + artifacts.MustNewLocatorFromTag("op-contracts/v1.7.0-beta.1+l2-contracts"), + ) + // Define a new create2 salt to avoid contract address collisions + _, err = rand.Read(st.Create2Salt[:]) + require.NoError(t, err) + + require.NoError(t, deployer.ApplyPipeline( + ctx, + deployer.ApplyPipelineOpts{ + L1RPCUrl: runner.RPCUrl(), + DeployerPrivateKey: pk, + Intent: intent, + State: st, + Logger: lgr, + StateWriter: pipeline.NoopStateWriter(), + }, + )) + + validateOPChainDeployment(t, ethClientCodeGetter(ctx, l1Client), st, intent) + + releases := standard.L1VersionsSepolia.Releases["op-contracts/v1.6.0"] + + implTests := []struct { + name string + expAddr common.Address + actAddr common.Address + }{ + {"OptimismPortal", releases.OptimismPortal.ImplementationAddress, st.ImplementationsDeployment.OptimismPortalImplAddress}, + {"SystemConfig,", releases.SystemConfig.ImplementationAddress, st.ImplementationsDeployment.SystemConfigImplAddress}, + {"L1CrossDomainMessenger", releases.L1CrossDomainMessenger.ImplementationAddress, st.ImplementationsDeployment.L1CrossDomainMessengerImplAddress}, + {"L1ERC721Bridge", releases.L1ERC721Bridge.ImplementationAddress, st.ImplementationsDeployment.L1ERC721BridgeImplAddress}, + {"L1StandardBridge", releases.L1StandardBridge.ImplementationAddress, st.ImplementationsDeployment.L1StandardBridgeImplAddress}, + {"OptimismMintableERC20Factory", releases.OptimismMintableERC20Factory.ImplementationAddress, st.ImplementationsDeployment.OptimismMintableERC20FactoryImplAddress}, + {"DisputeGameFactory", releases.DisputeGameFactory.ImplementationAddress, st.ImplementationsDeployment.DisputeGameFactoryImplAddress}, + {"MIPS", releases.MIPS.Address, st.ImplementationsDeployment.MipsSingletonAddress}, + {"PreimageOracle", releases.PreimageOracle.Address, st.ImplementationsDeployment.PreimageOracleSingletonAddress}, + {"DelayedWETH", releases.DelayedWETH.ImplementationAddress, st.ImplementationsDeployment.DelayedWETHImplAddress}, + } + for _, tt := range implTests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expAddr, tt.actAddr) + }) + } + + artifactsFSL2, cleanupL2, err := artifacts.Download( + ctx, + intent.L2ContractsLocator, + artifacts.LogProgressor(lgr), + ) require.NoError(t, err) - loc := &opcm.ArtifactsLocator{ - URL: artifactsURL, + t.Cleanup(func() { + require.NoError(t, cleanupL2()) + }) + + chainState := st.Chains[0] + chainIntent := intent.Chains[0] + + semvers, err := inspect.L2Semvers(inspect.L2SemversConfig{ + Lgr: lgr, + Artifacts: artifactsFSL2, + ChainState: chainState, + }) + require.NoError(t, err) + + expectedSemversL2 := &inspect.L2PredeploySemvers{ + L2ToL1MessagePasser: "1.1.1-beta.1", + DeployerWhitelist: "1.1.1-beta.1", + WETH: "1.0.0-beta.1", + L2CrossDomainMessenger: "2.1.1-beta.1", + L2StandardBridge: "1.11.1-beta.1", + SequencerFeeVault: "1.5.0-beta.2", + OptimismMintableERC20Factory: "1.10.1-beta.2", + L1BlockNumber: "1.1.1-beta.1", + GasPriceOracle: "1.3.1-beta.1", + L1Block: "1.5.1-beta.1", + LegacyMessagePasser: "1.1.1-beta.1", + L2ERC721Bridge: "1.7.1-beta.2", + OptimismMintableERC721Factory: "1.4.1-beta.1", + BaseFeeVault: "1.5.0-beta.2", + L1FeeVault: "1.5.0-beta.2", + SchemaRegistry: "1.3.1-beta.1", + EAS: "1.4.1-beta.1", + CrossL2Inbox: "", + L2toL2CrossDomainMessenger: "", + SuperchainWETH: "", + ETHLiquidity: "", + SuperchainTokenBridge: "", + OptimismMintableERC20: "1.4.0-beta.1", + OptimismMintableERC721: "1.3.1-beta.1", } - return loc -} -func createEnv( - t *testing.T, - ctx context.Context, - lgr log.Logger, - l1Client *ethclient.Client, - bcaster broadcaster.Broadcaster, - deployerAddr common.Address, -) (*pipeline.Env, pipeline.ArtifactsBundle, *script.Host) { - _, testFilename, _, ok := runtime.Caller(0) - require.Truef(t, ok, "failed to get test filename") - monorepoDir := path.Join(path.Dir(testFilename), "..", "..", "..", "..") - artifactsDir := path.Join(monorepoDir, "packages", "contracts-bedrock", "forge-artifacts") - artifactsURL, err := url.Parse(fmt.Sprintf("file://%s", artifactsDir)) + require.EqualValues(t, expectedSemversL2, semvers) + + f, err := os.Open("./testdata/allocs-l2-v160.json.gz") + require.NoError(t, err) + defer f.Close() + gzr, err := gzip.NewReader(f) require.NoError(t, err) - artifactsLocator := &opcm.ArtifactsLocator{ - URL: artifactsURL, + defer gzr.Close() + dec := json.NewDecoder(bufio.NewReader(gzr)) + var expAllocs types.GenesisAlloc + require.NoError(t, dec.Decode(&expAllocs)) + + type storageCheckerFunc func(addr common.Address, actStorage map[common.Hash]common.Hash) + + storageDiff := func(addr common.Address, expStorage, actStorage map[common.Hash]common.Hash) { + require.EqualValues(t, expStorage, actStorage, "storage for %s differs", addr) } - artifactsFS, cleanupArtifacts, err := pipeline.DownloadArtifacts(ctx, artifactsLocator, pipeline.NoopDownloadProgressor) + defaultStorageChecker := func(addr common.Address, actStorage map[common.Hash]common.Hash) { + storageDiff(addr, expAllocs[addr].Storage, actStorage) + } + + overrideStorageChecker := func(addr common.Address, actStorage, overrides map[common.Hash]common.Hash) { + expStorage := make(map[common.Hash]common.Hash) + maps.Copy(expStorage, expAllocs[addr].Storage) + maps.Copy(expStorage, overrides) + storageDiff(addr, expStorage, actStorage) + } + + storageCheckers := map[common.Address]storageCheckerFunc{ + predeploys.L2CrossDomainMessengerAddr: func(addr common.Address, actStorage map[common.Hash]common.Hash) { + overrideStorageChecker(addr, actStorage, map[common.Hash]common.Hash{ + {31: 0xcf}: common.BytesToHash(chainState.L1CrossDomainMessengerProxyAddress.Bytes()), + }) + }, + predeploys.L2StandardBridgeAddr: func(addr common.Address, actStorage map[common.Hash]common.Hash) { + overrideStorageChecker(addr, actStorage, map[common.Hash]common.Hash{ + {31: 0x04}: common.BytesToHash(chainState.L1StandardBridgeProxyAddress.Bytes()), + }) + }, + predeploys.L2ERC721BridgeAddr: func(addr common.Address, actStorage map[common.Hash]common.Hash) { + overrideStorageChecker(addr, actStorage, map[common.Hash]common.Hash{ + {31: 0x02}: common.BytesToHash(chainState.L1ERC721BridgeProxyAddress.Bytes()), + }) + }, + predeploys.ProxyAdminAddr: func(addr common.Address, actStorage map[common.Hash]common.Hash) { + overrideStorageChecker(addr, actStorage, map[common.Hash]common.Hash{ + {}: common.BytesToHash(intent.Chains[0].Roles.L2ProxyAdminOwner.Bytes()), + }) + }, + // The ProxyAdmin owner is also set on the ProxyAdmin contract's implementation address, see + // L2Genesis.s.sol line 292. + common.HexToAddress("0xc0d3c0d3c0d3c0d3c0d3c0d3c0d3c0d3c0d30018"): func(addr common.Address, actStorage map[common.Hash]common.Hash) { + overrideStorageChecker(addr, actStorage, map[common.Hash]common.Hash{ + {}: common.BytesToHash(chainIntent.Roles.L2ProxyAdminOwner.Bytes()), + }) + }, + } + + //Use a custom equality function to compare the genesis allocs + //because the reflect-based one is really slow + actAllocs := st.Chains[0].Allocs.Data.Accounts + require.Equal(t, len(expAllocs), len(actAllocs)) + for addr, expAcc := range expAllocs { + actAcc, ok := actAllocs[addr] + require.True(t, ok) + require.True(t, expAcc.Balance.Cmp(actAcc.Balance) == 0, "balance for %s differs", addr) + require.Equal(t, expAcc.Nonce, actAcc.Nonce, "nonce for %s differs", addr) + require.Equal(t, hex.EncodeToString(expAllocs[addr].Code), hex.EncodeToString(actAcc.Code), "code for %s differs", addr) + + storageChecker, ok := storageCheckers[addr] + if !ok { + storageChecker = defaultStorageChecker + } + storageChecker(addr, actAcc.Storage) + } +} + +func TestL2BlockTimeOverride(t *testing.T) { + op_e2e.InitParallel(t) + kurtosisutil.Test(t) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + opts, intent, st := setupGenesisChain(t) + intent.GlobalDeployOverrides = map[string]interface{}{ + "l2BlockTime": float64(3), + } + + require.NoError(t, deployer.ApplyPipeline(ctx, opts)) + + cfg, err := state.CombineDeployConfig(intent, intent.Chains[0], st, st.Chains[0]) require.NoError(t, err) - defer func() { - require.NoError(t, cleanupArtifacts()) - }() + require.Equal(t, uint64(3), cfg.L2InitializationConfig.L2CoreDeployConfig.L2BlockTime, "L2 block time should be 3 seconds") +} - host, err := pipeline.DefaultScriptHost( - bcaster, - lgr, - deployerAddr, - artifactsFS, - 0, - ) +func TestApplyGenesisStrategy(t *testing.T) { + op_e2e.InitParallel(t) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + opts, intent, st := setupGenesisChain(t) + + require.NoError(t, deployer.ApplyPipeline(ctx, opts)) + + cg := stateDumpCodeGetter(st) + validateSuperchainDeployment(t, st, cg) + + for i := range intent.Chains { + t.Run(fmt.Sprintf("chain-%d", i), func(t *testing.T) { + validateOPChainDeployment(t, cg, st, intent) + }) + } +} + +func TestProofParamOverrides(t *testing.T) { + op_e2e.InitParallel(t) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + opts, intent, st := setupGenesisChain(t) + intent.GlobalDeployOverrides = map[string]any{ + "withdrawalDelaySeconds": standard.WithdrawalDelaySeconds + 1, + "minProposalSizeBytes": standard.MinProposalSizeBytes + 1, + "challengePeriodSeconds": standard.ChallengePeriodSeconds + 1, + "proofMaturityDelaySeconds": standard.ProofMaturityDelaySeconds + 1, + "disputeGameFinalityDelaySeconds": standard.DisputeGameFinalityDelaySeconds + 1, + "mipsVersion": standard.MIPSVersion + 1, + "disputeGameType": standard.DisputeGameType, // This must be set to the permissioned game + "disputeAbsolutePrestate": common.Hash{'A', 'B', 'S', 'O', 'L', 'U', 'T', 'E'}, + "disputeMaxGameDepth": standard.DisputeMaxGameDepth + 1, + "disputeSplitDepth": standard.DisputeSplitDepth + 1, + "disputeClockExtension": standard.DisputeClockExtension + 1, + "disputeMaxClockDuration": standard.DisputeMaxClockDuration + 1, + "dangerouslyAllowCustomDisputeParameters": true, + } + + require.NoError(t, deployer.ApplyPipeline(ctx, opts)) + + allocs := st.L1StateDump.Data.Accounts + chainState := st.Chains[0] + + uint64Caster := func(t *testing.T, val any) common.Hash { + return common.BigToHash(new(big.Int).SetUint64(val.(uint64))) + } + + tests := []struct { + name string + caster func(t *testing.T, val any) common.Hash + address common.Address + }{ + { + "withdrawalDelaySeconds", + uint64Caster, + st.ImplementationsDeployment.DelayedWETHImplAddress, + }, + { + "minProposalSizeBytes", + uint64Caster, + st.ImplementationsDeployment.PreimageOracleSingletonAddress, + }, + { + "challengePeriodSeconds", + uint64Caster, + st.ImplementationsDeployment.PreimageOracleSingletonAddress, + }, + { + "proofMaturityDelaySeconds", + uint64Caster, + st.ImplementationsDeployment.OptimismPortalImplAddress, + }, + { + "disputeGameFinalityDelaySeconds", + uint64Caster, + st.ImplementationsDeployment.OptimismPortalImplAddress, + }, + { + "disputeAbsolutePrestate", + func(t *testing.T, val any) common.Hash { + return val.(common.Hash) + }, + chainState.PermissionedDisputeGameAddress, + }, + { + "disputeMaxGameDepth", + uint64Caster, + chainState.PermissionedDisputeGameAddress, + }, + { + "disputeSplitDepth", + uint64Caster, + chainState.PermissionedDisputeGameAddress, + }, + { + "disputeClockExtension", + uint64Caster, + chainState.PermissionedDisputeGameAddress, + }, + { + "disputeMaxClockDuration", + uint64Caster, + chainState.PermissionedDisputeGameAddress, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + checkImmutable(t, allocs, tt.address, tt.caster(t, intent.GlobalDeployOverrides[tt.name])) + }) + } +} + +func TestInteropDeployment(t *testing.T) { + op_e2e.InitParallel(t) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + opts, intent, st := setupGenesisChain(t) + intent.UseInterop = true + + require.NoError(t, deployer.ApplyPipeline(ctx, opts)) + + chainState := st.Chains[0] + depManagerSlot := common.HexToHash("0x1708e077affb93e89be2665fb0fb72581be66f84dc00d25fed755ae911905b1c") + checkImmutable(t, st.L1StateDump.Data.Accounts, st.ImplementationsDeployment.SystemConfigImplAddress, depManagerSlot) + proxyAdminOwnerHash := common.BytesToHash(intent.Chains[0].Roles.SystemConfigOwner.Bytes()) + checkStorageSlot(t, st.L1StateDump.Data.Accounts, chainState.SystemConfigProxyAddress, depManagerSlot, proxyAdminOwnerHash) +} + +func TestAltDADeployment(t *testing.T) { + op_e2e.InitParallel(t) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + opts, intent, st := setupGenesisChain(t) + altDACfg := genesis.AltDADeployConfig{ + UseAltDA: true, + DACommitmentType: altda.KeccakCommitmentString, + DAChallengeWindow: 10, + DAResolveWindow: 10, + DABondSize: 100, + DAResolverRefundPercentage: 50, + } + intent.Chains[0].DangerousAltDAConfig = altDACfg + + require.NoError(t, deployer.ApplyPipeline(ctx, opts)) + + chainState := st.Chains[0] + require.NotEmpty(t, chainState.DataAvailabilityChallengeProxyAddress) + require.NotEmpty(t, chainState.DataAvailabilityChallengeImplAddress) + + _, rollupCfg, err := inspect.GenesisAndRollup(st, chainState.ID) require.NoError(t, err) + require.EqualValues(t, &rollup.AltDAConfig{ + CommitmentType: altda.KeccakCommitmentString, + DAChallengeWindow: altDACfg.DAChallengeWindow, + DAChallengeAddress: chainState.DataAvailabilityChallengeProxyAddress, + DAResolveWindow: altDACfg.DAResolveWindow, + }, rollupCfg.AltDAConfig) +} + +func TestInvalidL2Genesis(t *testing.T) { + op_e2e.InitParallel(t) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // these tests were generated by grepping all usages of the deploy + // config in L2Genesis.s.sol. + tests := []struct { + name string + overrides map[string]any + }{ + { + name: "L2 proxy admin owner not set", + overrides: map[string]any{ + "proxyAdminOwner": nil, + }, + }, + { + name: "base fee vault recipient not set", + overrides: map[string]any{ + "baseFeeVaultRecipient": nil, + }, + }, + { + name: "l1 fee vault recipient not set", + overrides: map[string]any{ + "l1FeeVaultRecipient": nil, + }, + }, + { + name: "sequencer fee vault recipient not set", + overrides: map[string]any{ + "sequencerFeeVaultRecipient": nil, + }, + }, + { + name: "l1 chain ID not set", + overrides: map[string]any{ + "l1ChainID": nil, + }, + }, + { + name: "l2 chain ID not set", + overrides: map[string]any{ + "l2ChainID": nil, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + opts, intent, _ := setupGenesisChain(t) + intent.DeploymentStrategy = state.DeploymentStrategyGenesis + intent.GlobalDeployOverrides = tt.overrides - env := &pipeline.Env{ - StateWriter: pipeline.NoopStateWriter(), - L1ScriptHost: host, - L1Client: l1Client, - Broadcaster: bcaster, - Deployer: deployerAddr, - Logger: lgr, + err := deployer.ApplyPipeline(ctx, opts) + require.Error(t, err) + require.ErrorContains(t, err, "failed to combine L2 init config") + }) } +} - bundle := pipeline.ArtifactsBundle{ - L1: artifactsFS, - L2: artifactsFS, +func setupGenesisChain(t *testing.T) (deployer.ApplyPipelineOpts, *state.Intent, *state.State) { + lgr := testlog.Logger(t, slog.LevelDebug) + + depKey := new(deployerKey) + l1ChainID := big.NewInt(77799777) + dk, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic) + require.NoError(t, err) + + l2ChainID1 := uint256.NewInt(1) + + priv, err := dk.Secret(depKey) + require.NoError(t, err) + + loc, _ := testutil.LocalArtifacts(t) + + intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc) + intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID1)) + intent.DeploymentStrategy = state.DeploymentStrategyGenesis + + opts := deployer.ApplyPipelineOpts{ + DeployerPrivateKey: priv, + Intent: intent, + State: st, + Logger: lgr, + StateWriter: pipeline.NoopStateWriter(), } - return env, bundle, host + return opts, intent, st } func addrFor(t *testing.T, dk *devkeys.MnemonicDevKeys, key devkeys.Key) common.Address { @@ -228,8 +653,8 @@ func newIntent( l1ChainID *big.Int, dk *devkeys.MnemonicDevKeys, l2ChainID *uint256.Int, - l1Loc *opcm.ArtifactsLocator, - l2Loc *opcm.ArtifactsLocator, + l1Loc *artifacts.Locator, + l2Loc *artifacts.Locator, ) (*state.Intent, *state.State) { intent := &state.Intent{ DeploymentStrategy: state.DeploymentStrategyLive, @@ -300,7 +725,7 @@ func validateSuperchainDeployment(t *testing.T, st *state.State, cg codeGetter) {"SuperchainConfigImpl", st.SuperchainDeployment.SuperchainConfigImplAddress}, {"ProtocolVersionsProxy", st.SuperchainDeployment.ProtocolVersionsProxyAddress}, {"ProtocolVersionsImpl", st.SuperchainDeployment.ProtocolVersionsImplAddress}, - {"OpcmProxy", st.ImplementationsDeployment.OpcmProxyAddress}, + {"Opcm", st.ImplementationsDeployment.OpcmAddress}, {"PreimageOracleSingleton", st.ImplementationsDeployment.PreimageOracleSingletonAddress}, {"MipsSingleton", st.ImplementationsDeployment.MipsSingletonAddress}, } @@ -368,10 +793,10 @@ func validateOPChainDeployment(t *testing.T, cg codeGetter, st *state.State, int alloc := chainState.Allocs.Data.Accounts chainIntent := intent.Chains[i] - checkImmutable(t, alloc, predeploys.BaseFeeVaultAddr, chainIntent.BaseFeeVaultRecipient) - checkImmutable(t, alloc, predeploys.L1FeeVaultAddr, chainIntent.L1FeeVaultRecipient) - checkImmutable(t, alloc, predeploys.SequencerFeeVaultAddr, chainIntent.SequencerFeeVaultRecipient) - checkImmutable(t, alloc, predeploys.OptimismMintableERC721FactoryAddr, common.BigToHash(new(big.Int).SetUint64(intent.L1ChainID))) + checkImmutableBehindProxy(t, alloc, predeploys.BaseFeeVaultAddr, chainIntent.BaseFeeVaultRecipient) + checkImmutableBehindProxy(t, alloc, predeploys.L1FeeVaultAddr, chainIntent.L1FeeVaultRecipient) + checkImmutableBehindProxy(t, alloc, predeploys.SequencerFeeVaultAddr, chainIntent.SequencerFeeVaultRecipient) + checkImmutableBehindProxy(t, alloc, predeploys.OptimismMintableERC721FactoryAddr, common.BigToHash(new(big.Int).SetUint64(intent.L1ChainID))) // ownership slots var addrAsSlot common.Hash @@ -399,8 +824,12 @@ type bytesMarshaler interface { Bytes() []byte } -func checkImmutable(t *testing.T, allocations types.GenesisAlloc, proxyContract common.Address, thing bytesMarshaler) { +func checkImmutableBehindProxy(t *testing.T, allocations types.GenesisAlloc, proxyContract common.Address, thing bytesMarshaler) { implementationAddress := getEIP1967ImplementationAddress(t, allocations, proxyContract) + checkImmutable(t, allocations, implementationAddress, thing) +} + +func checkImmutable(t *testing.T, allocations types.GenesisAlloc, implementationAddress common.Address, thing bytesMarshaler) { account, ok := allocations[implementationAddress] require.True(t, ok, "%s not found in allocations", implementationAddress) require.NotEmpty(t, account.Code, "%s should have code", implementationAddress) @@ -422,277 +851,3 @@ func checkStorageSlot(t *testing.T, allocs types.GenesisAlloc, address common.Ad require.True(t, ok, "slot %s not found for account %s", slot, address) require.Equal(t, expected, value, "slot %s for account %s should be %s", slot, address, expected) } - -func TestApplyExistingOPCM(t *testing.T) { - anvil.Test(t) - - forkRPCUrl := os.Getenv("SEPOLIA_RPC_URL") - if forkRPCUrl == "" { - t.Skip("no fork RPC URL provided") - } - - lgr := testlog.Logger(t, slog.LevelDebug) - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) - defer cancel() - - runner, err := anvil.New( - forkRPCUrl, - lgr, - ) - require.NoError(t, err) - - require.NoError(t, runner.Start(ctx)) - t.Cleanup(func() { - require.NoError(t, runner.Stop()) - }) - - l1Client, err := ethclient.Dial(runner.RPCUrl()) - require.NoError(t, err) - - l1ChainID := big.NewInt(11155111) - dk, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic) - require.NoError(t, err) - // index 0 from Anvil's test set - priv, err := crypto.HexToECDSA("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") - require.NoError(t, err) - signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(priv, l1ChainID)) - deployerAddr := common.HexToAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266") - - l2ChainID := uint256.NewInt(1) - - bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{ - Logger: lgr, - ChainID: l1ChainID, - Client: l1Client, - Signer: signer, - From: deployerAddr, - }) - require.NoError(t, err) - - env, bundle, _ := createEnv(t, ctx, lgr, l1Client, bcaster, deployerAddr) - - intent, st := newIntent( - t, - l1ChainID, - dk, - l2ChainID, - opcm.DefaultL1ContractsLocator, - opcm.DefaultL2ContractsLocator, - ) - - require.NoError(t, deployer.ApplyPipeline( - ctx, - env, - bundle, - intent, - st, - )) - - validateOPChainDeployment(t, ethClientCodeGetter(ctx, l1Client), st, intent) -} - -func TestL2BlockTimeOverride(t *testing.T) { - op_e2e.InitParallel(t) - kurtosisutil.Test(t) - - lgr := testlog.Logger(t, slog.LevelDebug) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - enclaveCtx := kurtosisutil.StartEnclave(t, ctx, lgr, "github.com/ethpandaops/ethereum-package", TestParams) - - service, err := enclaveCtx.GetServiceContext("el-1-geth-lighthouse") - require.NoError(t, err) - - ip := service.GetMaybePublicIPAddress() - ports := service.GetPublicPorts() - rpcURL := fmt.Sprintf("http://%s:%d", ip, ports["rpc"].GetNumber()) - l1Client, err := ethclient.Dial(rpcURL) - require.NoError(t, err) - - depKey := new(deployerKey) - l1ChainID := big.NewInt(77799777) - dk, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic) - require.NoError(t, err) - pk, err := dk.Secret(depKey) - require.NoError(t, err) - signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(pk, l1ChainID)) - - l2ChainID := uint256.NewInt(1) - - deployerAddr, err := dk.Address(depKey) - require.NoError(t, err) - - loc := localArtifactsLocator(t) - - bcaster, err := broadcaster.NewKeyedBroadcaster(broadcaster.KeyedBroadcasterOpts{ - Logger: lgr, - ChainID: l1ChainID, - Client: l1Client, - Signer: signer, - From: deployerAddr, - }) - require.NoError(t, err) - - env, bundle, _ := createEnv(t, ctx, lgr, l1Client, bcaster, deployerAddr) - - intent, st := newIntent( - t, - l1ChainID, - dk, - l2ChainID, - loc, - loc, - ) - - intent.GlobalDeployOverrides = map[string]interface{}{ - "l2BlockTime": float64(3), - } - - require.NoError(t, deployer.ApplyPipeline( - ctx, - env, - bundle, - intent, - st, - )) - - chainIntent, err := intent.Chain(l2ChainID.Bytes32()) - require.NoError(t, err) - chainState, err := st.Chain(l2ChainID.Bytes32()) - require.NoError(t, err) - cfg, err := state.CombineDeployConfig(intent, chainIntent, st, chainState) - require.NoError(t, err) - - require.Equal(t, uint64(3), cfg.L2InitializationConfig.L2CoreDeployConfig.L2BlockTime, "L2 block time should be 3 seconds") -} - -func TestApplyGenesisStrategy(t *testing.T) { - op_e2e.InitParallel(t) - - lgr := testlog.Logger(t, slog.LevelDebug) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - depKey := new(deployerKey) - l1ChainID := big.NewInt(77799777) - dk, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic) - require.NoError(t, err) - - l2ChainID1 := uint256.NewInt(1) - l2ChainID2 := uint256.NewInt(2) - - deployerAddr, err := dk.Address(depKey) - require.NoError(t, err) - - loc := localArtifactsLocator(t) - - env, bundle, _ := createEnv(t, ctx, lgr, nil, broadcaster.NoopBroadcaster(), deployerAddr) - intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc) - intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID2)) - intent.DeploymentStrategy = state.DeploymentStrategyGenesis - - require.NoError(t, deployer.ApplyPipeline( - ctx, - env, - bundle, - intent, - st, - )) - - cg := stateDumpCodeGetter(st) - validateSuperchainDeployment(t, st, cg) - - for i := range intent.Chains { - t.Run(fmt.Sprintf("chain-%d", i), func(t *testing.T) { - validateOPChainDeployment(t, cg, st, intent) - }) - } -} - -func TestInvalidL2Genesis(t *testing.T) { - op_e2e.InitParallel(t) - - lgr := testlog.Logger(t, slog.LevelDebug) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - depKey := new(deployerKey) - l1ChainID := big.NewInt(77799777) - dk, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic) - require.NoError(t, err) - - l2ChainID1 := uint256.NewInt(1) - - deployerAddr, err := dk.Address(depKey) - require.NoError(t, err) - - loc := localArtifactsLocator(t) - - // these tests were generated by grepping all usages of the deploy - // config in L2Genesis.s.sol. - tests := []struct { - name string - overrides map[string]any - }{ - { - name: "L2 proxy admin owner not set", - overrides: map[string]any{ - "proxyAdminOwner": nil, - }, - }, - { - name: "base fee vault recipient not set", - overrides: map[string]any{ - "baseFeeVaultRecipient": nil, - }, - }, - { - name: "l1 fee vault recipient not set", - overrides: map[string]any{ - "l1FeeVaultRecipient": nil, - }, - }, - { - name: "sequencer fee vault recipient not set", - overrides: map[string]any{ - "sequencerFeeVaultRecipient": nil, - }, - }, - { - name: "l1 chain ID not set", - overrides: map[string]any{ - "l1ChainID": nil, - }, - }, - { - name: "l2 chain ID not set", - overrides: map[string]any{ - "l2ChainID": nil, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - env, bundle, _ := createEnv(t, ctx, lgr, nil, broadcaster.NoopBroadcaster(), deployerAddr) - intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc) - intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID1)) - intent.DeploymentStrategy = state.DeploymentStrategyGenesis - intent.GlobalDeployOverrides = tt.overrides - - err := deployer.ApplyPipeline( - ctx, - env, - bundle, - intent, - st, - ) - require.Error(t, err) - require.ErrorContains(t, err, "failed to combine L2 init config") - }) - } -} diff --git a/op-deployer/pkg/deployer/integration_test/testdata/allocs-l2-v160.json.gz b/op-deployer/pkg/deployer/integration_test/testdata/allocs-l2-v160.json.gz new file mode 100644 index 0000000000000..545dc3397bdd3 Binary files /dev/null and b/op-deployer/pkg/deployer/integration_test/testdata/allocs-l2-v160.json.gz differ diff --git a/op-deployer/pkg/deployer/opcm/alt_da.go b/op-deployer/pkg/deployer/opcm/alt_da.go new file mode 100644 index 0000000000000..7c05a42a7a5a2 --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/alt_da.go @@ -0,0 +1,63 @@ +package opcm + +import ( + "fmt" + "math/big" + + "github.com/ethereum-optimism/optimism/op-chain-ops/script" + "github.com/ethereum/go-ethereum/common" +) + +type DeployAltDAInput struct { + Salt common.Hash + ProxyAdmin common.Address + ChallengeContractOwner common.Address + ChallengeWindow *big.Int + ResolveWindow *big.Int + BondSize *big.Int + ResolverRefundPercentage *big.Int +} + +type DeployAltDAOutput struct { + DataAvailabilityChallengeProxy common.Address + DataAvailabilityChallengeImpl common.Address +} + +type DeployAltDAScript struct { + Run func(input, output common.Address) error +} + +func DeployAltDA( + host *script.Host, + input DeployAltDAInput, +) (DeployAltDAOutput, error) { + var output DeployAltDAOutput + inputAddr := host.NewScriptAddress() + outputAddr := host.NewScriptAddress() + + cleanupInput, err := script.WithPrecompileAtAddress[*DeployAltDAInput](host, inputAddr, &input) + if err != nil { + return output, fmt.Errorf("failed to insert DeployAltDAInput precompile: %w", err) + } + defer cleanupInput() + + cleanupOutput, err := script.WithPrecompileAtAddress[*DeployAltDAOutput](host, outputAddr, &output, + script.WithFieldSetter[*DeployAltDAOutput]) + if err != nil { + return output, fmt.Errorf("failed to insert DeployAltDAOutput precompile: %w", err) + } + defer cleanupOutput() + + implContract := "DeployAltDA" + deployScript, cleanupDeploy, err := script.WithScript[DeployAltDAScript](host, "DeployAltDA.s.sol", implContract) + if err != nil { + return output, fmt.Errorf("failed to laod %s script: %w", implContract, err) + } + defer cleanupDeploy() + + if err := deployScript.Run(inputAddr, outputAddr); err != nil { + return output, fmt.Errorf("failed to run %s script: %w", implContract, err) + } + + return output, nil +} diff --git a/op-deployer/pkg/deployer/opcm/alt_da_test.go b/op-deployer/pkg/deployer/opcm/alt_da_test.go new file mode 100644 index 0000000000000..97e2b485b900e --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/alt_da_test.go @@ -0,0 +1,42 @@ +package opcm + +import ( + "math/big" + "testing" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/testutil" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" +) + +func TestDeployAltDA(t *testing.T) { + _, artifacts := testutil.LocalArtifacts(t) + + host, err := env.DefaultScriptHost( + broadcaster.NoopBroadcaster(), + testlog.Logger(t, log.LevelInfo), + common.Address{'D'}, + artifacts, + ) + require.NoError(t, err) + + input := DeployAltDAInput{ + Salt: common.HexToHash("0x1234"), + ProxyAdmin: common.Address{'P'}, + ChallengeContractOwner: common.Address{'O'}, + ChallengeWindow: big.NewInt(100), + ResolveWindow: big.NewInt(200), + BondSize: big.NewInt(300), + ResolverRefundPercentage: big.NewInt(50), // must be < 100 + } + + output, err := DeployAltDA(host, input) + require.NoError(t, err) + + require.NotEmpty(t, output.DataAvailabilityChallengeProxy) + require.NotEmpty(t, output.DataAvailabilityChallengeImpl) +} diff --git a/op-deployer/pkg/deployer/opcm/artifacts_locator.go b/op-deployer/pkg/deployer/opcm/artifacts_locator.go deleted file mode 100644 index 1db025393e621..0000000000000 --- a/op-deployer/pkg/deployer/opcm/artifacts_locator.go +++ /dev/null @@ -1,78 +0,0 @@ -package opcm - -import ( - "fmt" - "net/url" - "strings" -) - -type schemeUnmarshaler func(string) (*ArtifactsLocator, error) - -var schemeUnmarshalerDispatch = map[string]schemeUnmarshaler{ - "tag": unmarshalTag, - "file": unmarshalURL, - "https": unmarshalURL, -} - -type ArtifactsLocator struct { - URL *url.URL - Tag string -} - -func (a *ArtifactsLocator) UnmarshalText(text []byte) error { - str := string(text) - - for scheme, unmarshaler := range schemeUnmarshalerDispatch { - if !strings.HasPrefix(str, scheme+"://") { - continue - } - - loc, err := unmarshaler(str) - if err != nil { - return err - } - - *a = *loc - return nil - } - - return fmt.Errorf("unsupported scheme") -} - -func (a *ArtifactsLocator) MarshalText() ([]byte, error) { - if a.URL != nil { - return []byte(a.URL.String()), nil - } - - if a.Tag != "" { - return []byte("tag://" + a.Tag), nil - } - - return nil, fmt.Errorf("no URL, path or tag set") -} - -func (a *ArtifactsLocator) IsTag() bool { - return a.Tag != "" -} - -func unmarshalTag(tag string) (*ArtifactsLocator, error) { - tag = strings.TrimPrefix(tag, "tag://") - if !strings.HasPrefix(tag, "op-contracts/") { - return nil, fmt.Errorf("invalid tag: %s", tag) - } - - if _, err := StandardArtifactsURLForTag(tag); err != nil { - return nil, err - } - - return &ArtifactsLocator{Tag: tag}, nil -} - -func unmarshalURL(text string) (*ArtifactsLocator, error) { - u, err := url.Parse(text) - if err != nil { - return nil, err - } - - return &ArtifactsLocator{URL: u}, nil -} diff --git a/op-deployer/pkg/deployer/opcm/contract.go b/op-deployer/pkg/deployer/opcm/contract.go index b90db5814192b..8d02f77e8e0ac 100644 --- a/op-deployer/pkg/deployer/opcm/contract.go +++ b/op-deployer/pkg/deployer/opcm/contract.go @@ -48,57 +48,6 @@ func (c *Contract) GenericAddressGetter(ctx context.Context, functionName string return c.callContractMethod(ctx, functionName, abi.Arguments{}) } -// GetImplementation retrieves the Implementation struct for a given release and contract name. -func (c *Contract) GetOPCMImplementationAddress(ctx context.Context, release, contractName string) (common.Address, error) { - methodName := "implementations" - method := abi.NewMethod( - methodName, - methodName, - abi.Function, - "view", - true, - false, - abi.Arguments{ - {Name: "release", Type: mustType("string")}, - {Name: "contractName", Type: mustType("string")}, - }, - abi.Arguments{ - {Name: "logic", Type: mustType("address")}, - {Name: "initializer", Type: mustType("bytes4")}, - }, - ) - - calldata, err := method.Inputs.Pack(release, contractName) - if err != nil { - return common.Address{}, fmt.Errorf("failed to pack inputs: %w", err) - } - - msg := ethereum.CallMsg{ - To: &c.addr, - Data: append(bytes.Clone(method.ID), calldata...), - } - - result, err := c.client.CallContract(ctx, msg, nil) - if err != nil { - return common.Address{}, fmt.Errorf("failed to call contract: %w", err) - } - - out, err := method.Outputs.Unpack(result) - if err != nil { - return common.Address{}, fmt.Errorf("failed to unpack result: %w", err) - } - if len(out) != 2 { - return common.Address{}, fmt.Errorf("unexpected output length: %d", len(out)) - } - - logic, ok := out[0].(common.Address) - if !ok { - return common.Address{}, fmt.Errorf("unexpected type for logic: %T", out[0]) - } - - return logic, nil -} - func (c *Contract) callContractMethod(ctx context.Context, methodName string, inputs abi.Arguments, args ...interface{}) (common.Address, error) { method := abi.NewMethod( methodName, diff --git a/op-deployer/pkg/deployer/opcm/delayed_weth.go b/op-deployer/pkg/deployer/opcm/delayed_weth.go new file mode 100644 index 0000000000000..d94e25cb90925 --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/delayed_weth.go @@ -0,0 +1,71 @@ +package opcm + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + + "github.com/ethereum-optimism/optimism/op-chain-ops/script" +) + +type DeployDelayedWETHInput struct { + Release string + StandardVersionsToml string + ProxyAdmin common.Address + SuperchainConfigProxy common.Address + DelayedWethOwner common.Address + DelayedWethDelay *big.Int +} + +func (input *DeployDelayedWETHInput) InputSet() bool { + return true +} + +type DeployDelayedWETHOutput struct { + DelayedWethImpl common.Address + DelayedWethProxy common.Address +} + +func (output *DeployDelayedWETHOutput) CheckOutput(input common.Address) error { + return nil +} + +type DeployDelayedWETHScript struct { + Run func(input, output common.Address) error +} + +func DeployDelayedWETH( + host *script.Host, + input DeployDelayedWETHInput, +) (DeployDelayedWETHOutput, error) { + var output DeployDelayedWETHOutput + inputAddr := host.NewScriptAddress() + outputAddr := host.NewScriptAddress() + + cleanupInput, err := script.WithPrecompileAtAddress[*DeployDelayedWETHInput](host, inputAddr, &input) + if err != nil { + return output, fmt.Errorf("failed to insert DeployDelayedWETHInput precompile: %w", err) + } + defer cleanupInput() + + cleanupOutput, err := script.WithPrecompileAtAddress[*DeployDelayedWETHOutput](host, outputAddr, &output, + script.WithFieldSetter[*DeployDelayedWETHOutput]) + if err != nil { + return output, fmt.Errorf("failed to insert DeployDelayedWETHOutput precompile: %w", err) + } + defer cleanupOutput() + + implContract := "DeployDelayedWETH" + deployScript, cleanupDeploy, err := script.WithScript[DeployDelayedWETHScript](host, "DeployDelayedWETH.s.sol", implContract) + if err != nil { + return output, fmt.Errorf("failed to load %s script: %w", implContract, err) + } + defer cleanupDeploy() + + if err := deployScript.Run(inputAddr, outputAddr); err != nil { + return output, fmt.Errorf("failed to run %s script: %w", implContract, err) + } + + return output, nil +} diff --git a/op-deployer/pkg/deployer/opcm/delayed_weth_test.go b/op-deployer/pkg/deployer/opcm/delayed_weth_test.go new file mode 100644 index 0000000000000..071afe89fdbed --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/delayed_weth_test.go @@ -0,0 +1,45 @@ +package opcm + +import ( + "math/big" + "testing" + + "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/testutil" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" +) + +func TestDeployDelayedWETH(t *testing.T) { + _, artifacts := testutil.LocalArtifacts(t) + + host, err := env.DefaultScriptHost( + broadcaster.NoopBroadcaster(), + testlog.Logger(t, log.LevelInfo), + common.Address{'D'}, + artifacts, + ) + require.NoError(t, err) + + standardVersionsTOML, err := standard.L1VersionsDataFor(11155111) + require.NoError(t, err) + + input := DeployDelayedWETHInput{ + Release: "dev", + StandardVersionsToml: standardVersionsTOML, + ProxyAdmin: common.Address{'P'}, + SuperchainConfigProxy: common.Address{'S'}, + DelayedWethOwner: common.Address{'O'}, + DelayedWethDelay: big.NewInt(100), + } + + output, err := DeployDelayedWETH(host, input) + require.NoError(t, err) + + require.NotEmpty(t, output.DelayedWethImpl) + require.NotEmpty(t, output.DelayedWethProxy) +} diff --git a/op-deployer/pkg/deployer/opcm/dispute_game.go b/op-deployer/pkg/deployer/opcm/dispute_game.go new file mode 100644 index 0000000000000..0e117c040d83d --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/dispute_game.go @@ -0,0 +1,82 @@ +package opcm + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + + "github.com/ethereum-optimism/optimism/op-chain-ops/script" +) + +type DeployDisputeGameInput struct { + Release string + StandardVersionsToml string + MipsVersion uint64 + MinProposalSizeBytes uint64 + ChallengePeriodSeconds uint64 + GameKind string + GameType uint32 + AbsolutePrestate common.Hash + MaxGameDepth uint64 + SplitDepth uint64 + ClockExtension uint64 + MaxClockDuration uint64 + DelayedWethProxy common.Address + AnchorStateRegistryProxy common.Address + L2ChainId uint64 + Proposer common.Address + Challenger common.Address +} + +func (input *DeployDisputeGameInput) InputSet() bool { + return true +} + +type DeployDisputeGameOutput struct { + DisputeGameImpl common.Address + MipsSingleton common.Address + PreimageOracleSingleton common.Address +} + +func (output *DeployDisputeGameOutput) CheckOutput(input common.Address) error { + return nil +} + +type DeployDisputeGameScript struct { + Run func(input, output common.Address) error +} + +func DeployDisputeGame( + host *script.Host, + input DeployDisputeGameInput, +) (DeployDisputeGameOutput, error) { + var output DeployDisputeGameOutput + inputAddr := host.NewScriptAddress() + outputAddr := host.NewScriptAddress() + + cleanupInput, err := script.WithPrecompileAtAddress[*DeployDisputeGameInput](host, inputAddr, &input) + if err != nil { + return output, fmt.Errorf("failed to insert DeployDisputeGameInput precompile: %w", err) + } + defer cleanupInput() + + cleanupOutput, err := script.WithPrecompileAtAddress[*DeployDisputeGameOutput](host, outputAddr, &output, + script.WithFieldSetter[*DeployDisputeGameOutput]) + if err != nil { + return output, fmt.Errorf("failed to insert DeployDisputeGameOutput precompile: %w", err) + } + defer cleanupOutput() + + implContract := "DeployDisputeGame" + deployScript, cleanupDeploy, err := script.WithScript[DeployDisputeGameScript](host, "DeployDisputeGame.s.sol", implContract) + if err != nil { + return output, fmt.Errorf("failed to load %s script: %w", implContract, err) + } + defer cleanupDeploy() + + if err := deployScript.Run(inputAddr, outputAddr); err != nil { + return output, fmt.Errorf("failed to run %s script: %w", implContract, err) + } + + return output, nil +} diff --git a/op-deployer/pkg/deployer/opcm/dispute_game_test.go b/op-deployer/pkg/deployer/opcm/dispute_game_test.go new file mode 100644 index 0000000000000..f39849be4403a --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/dispute_game_test.go @@ -0,0 +1,56 @@ +package opcm + +import ( + "testing" + + "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/testutil" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" +) + +func TestDeployDisputeGame(t *testing.T) { + _, artifacts := testutil.LocalArtifacts(t) + + host, err := env.DefaultScriptHost( + broadcaster.NoopBroadcaster(), + testlog.Logger(t, log.LevelInfo), + common.Address{'D'}, + artifacts, + ) + require.NoError(t, err) + + standardVersionsTOML, err := standard.L1VersionsDataFor(11155111) + require.NoError(t, err) + + input := DeployDisputeGameInput{ + Release: "dev", + StandardVersionsToml: standardVersionsTOML, + MipsVersion: 1, + MinProposalSizeBytes: standard.MinProposalSizeBytes, + ChallengePeriodSeconds: standard.ChallengePeriodSeconds, + GameKind: "PermissionedDisputeGame", + GameType: 1, + AbsolutePrestate: common.Hash{'A'}, + MaxGameDepth: standard.DisputeMaxGameDepth, + SplitDepth: standard.DisputeSplitDepth, + ClockExtension: standard.DisputeClockExtension, + MaxClockDuration: standard.DisputeMaxClockDuration, + DelayedWethProxy: common.Address{'D'}, + AnchorStateRegistryProxy: common.Address{'A'}, + L2ChainId: 69, + Proposer: common.Address{'P'}, + Challenger: common.Address{'C'}, + } + + output, err := DeployDisputeGame(host, input) + require.NoError(t, err) + + require.NotEmpty(t, output.DisputeGameImpl) + require.NotEmpty(t, output.MipsSingleton) + require.NotEmpty(t, output.PreimageOracleSingleton) +} diff --git a/op-deployer/pkg/deployer/opcm/implementations.go b/op-deployer/pkg/deployer/opcm/implementations.go index 8dd072eef246a..413452b1d3480 100644 --- a/op-deployer/pkg/deployer/opcm/implementations.go +++ b/op-deployer/pkg/deployer/opcm/implementations.go @@ -18,12 +18,11 @@ type DeployImplementationsInput struct { DisputeGameFinalityDelaySeconds *big.Int MipsVersion *big.Int // Release version to set OPCM implementations for, of the format `op-contracts/vX.Y.Z`. - Release string + L1ContractsRelease string SuperchainConfigProxy common.Address ProtocolVersionsProxy common.Address UseInterop bool // if true, deploy Interop implementations - OpcmProxyOwner common.Address StandardVersionsToml string // contents of 'standard-versions-mainnet.toml' or 'standard-versions-sepolia.toml' file } @@ -32,8 +31,7 @@ func (input *DeployImplementationsInput) InputSet() bool { } type DeployImplementationsOutput struct { - OpcmProxy common.Address - OpcmImpl common.Address + Opcm common.Address DelayedWETHImpl common.Address OptimismPortalImpl common.Address PreimageOracleSingleton common.Address diff --git a/op-deployer/pkg/deployer/opcm/mips.go b/op-deployer/pkg/deployer/opcm/mips.go new file mode 100644 index 0000000000000..5d1a7798cedbf --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/mips.go @@ -0,0 +1,65 @@ +package opcm + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + + "github.com/ethereum-optimism/optimism/op-chain-ops/script" +) + +type DeployMIPSInput struct { + MipsVersion uint64 + PreimageOracle common.Address +} + +func (input *DeployMIPSInput) InputSet() bool { + return true +} + +type DeployMIPSOutput struct { + MipsSingleton common.Address +} + +func (output *DeployMIPSOutput) CheckOutput(input common.Address) error { + return nil +} + +type DeployMIPSScript struct { + Run func(input, output common.Address) error +} + +func DeployMIPS( + host *script.Host, + input DeployMIPSInput, +) (DeployMIPSOutput, error) { + var output DeployMIPSOutput + inputAddr := host.NewScriptAddress() + outputAddr := host.NewScriptAddress() + + cleanupInput, err := script.WithPrecompileAtAddress[*DeployMIPSInput](host, inputAddr, &input) + if err != nil { + return output, fmt.Errorf("failed to insert DeployMIPSInput precompile: %w", err) + } + defer cleanupInput() + + cleanupOutput, err := script.WithPrecompileAtAddress[*DeployMIPSOutput](host, outputAddr, &output, + script.WithFieldSetter[*DeployMIPSOutput]) + if err != nil { + return output, fmt.Errorf("failed to insert DeployMIPSOutput precompile: %w", err) + } + defer cleanupOutput() + + implContract := "DeployMIPS" + deployScript, cleanupDeploy, err := script.WithScript[DeployMIPSScript](host, "DeployMIPS.s.sol", implContract) + if err != nil { + return output, fmt.Errorf("failed to load %s script: %w", implContract, err) + } + defer cleanupDeploy() + + if err := deployScript.Run(inputAddr, outputAddr); err != nil { + return output, fmt.Errorf("failed to run %s script: %w", implContract, err) + } + + return output, nil +} diff --git a/op-deployer/pkg/deployer/opcm/mips_test.go b/op-deployer/pkg/deployer/opcm/mips_test.go new file mode 100644 index 0000000000000..848b463565258 --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/mips_test.go @@ -0,0 +1,35 @@ +package opcm + +import ( + "testing" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/testutil" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" +) + +func TestDeployMIPS(t *testing.T) { + _, artifacts := testutil.LocalArtifacts(t) + + host, err := env.DefaultScriptHost( + broadcaster.NoopBroadcaster(), + testlog.Logger(t, log.LevelInfo), + common.Address{'D'}, + artifacts, + ) + require.NoError(t, err) + + input := DeployMIPSInput{ + MipsVersion: 1, + PreimageOracle: common.Address{0xab}, + } + + output, err := DeployMIPS(host, input) + require.NoError(t, err) + + require.NotEmpty(t, output.MipsSingleton) +} diff --git a/op-deployer/pkg/deployer/opcm/opchain.go b/op-deployer/pkg/deployer/opcm/opchain.go index beefad5f2630e..8c7e60fec4d25 100644 --- a/op-deployer/pkg/deployer/opcm/opchain.go +++ b/op-deployer/pkg/deployer/opcm/opchain.go @@ -1,20 +1,12 @@ package opcm import ( - "context" + _ "embed" "fmt" "math/big" - "strings" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" - - "github.com/ethereum-optimism/optimism/op-chain-ops/foundry" "github.com/ethereum-optimism/optimism/op-chain-ops/script" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/holiman/uint256" ) // PermissionedGameStartingAnchorRoots is a root of bytes32(hex"dead") for the permissioned game at block 0, @@ -23,7 +15,7 @@ var PermissionedGameStartingAnchorRoots = []byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xde, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } -type DeployOPChainInput struct { +type DeployOPChainInputV160 struct { OpChainProxyAdminOwner common.Address SystemConfigOwner common.Address Batcher common.Address @@ -34,26 +26,32 @@ type DeployOPChainInput struct { BasefeeScalar uint32 BlobBaseFeeScalar uint32 L2ChainId *big.Int - OpcmProxy common.Address + Opcm common.Address SaltMixer string GasLimit uint64 - DisputeGameType uint32 - DisputeAbsolutePrestate common.Hash - DisputeMaxGameDepth uint64 - DisputeSplitDepth uint64 - DisputeClockExtension uint64 - DisputeMaxClockDuration uint64 + DisputeGameType uint32 + DisputeAbsolutePrestate common.Hash + DisputeMaxGameDepth uint64 + DisputeSplitDepth uint64 + DisputeClockExtension uint64 + DisputeMaxClockDuration uint64 + AllowCustomDisputeParameters bool } -func (input *DeployOPChainInput) InputSet() bool { +func (input *DeployOPChainInputV160) InputSet() bool { return true } -func (input *DeployOPChainInput) StartingAnchorRoots() []byte { +func (input *DeployOPChainInputV160) StartingAnchorRoots() []byte { return PermissionedGameStartingAnchorRoots } +type DeployOPChainInputIsthmus struct { + DeployOPChainInputV160 + SystemConfigFeeAdmin common.Address +} + type DeployOPChainOutput struct { OpChainProxyAdmin common.Address AddressManager common.Address @@ -81,12 +79,20 @@ type DeployOPChainScript struct { Run func(input, output common.Address) error } -func DeployOPChain(host *script.Host, input DeployOPChainInput) (DeployOPChainOutput, error) { +func DeployOPChainV160(host *script.Host, input DeployOPChainInputV160) (DeployOPChainOutput, error) { + return deployOPChain(host, input) +} + +func DeployOPChainIsthmus(host *script.Host, input DeployOPChainInputIsthmus) (DeployOPChainOutput, error) { + return deployOPChain(host, input) +} + +func deployOPChain[T any](host *script.Host, input T) (DeployOPChainOutput, error) { var dco DeployOPChainOutput inputAddr := host.NewScriptAddress() outputAddr := host.NewScriptAddress() - cleanupInput, err := script.WithPrecompileAtAddress[*DeployOPChainInput](host, inputAddr, &input) + cleanupInput, err := script.WithPrecompileAtAddress[*T](host, inputAddr, &input) if err != nil { return dco, fmt.Errorf("failed to insert DeployOPChainInput precompile: %w", err) } @@ -114,218 +120,58 @@ func DeployOPChain(host *script.Host, input DeployOPChainInput) (DeployOPChainOu return dco, nil } -// opcmRoles is an internal struct used to pass the roles to OPSM. See opcmDeployInput for more info. -type opcmRoles struct { - OpChainProxyAdminOwner common.Address - SystemConfigOwner common.Address - Batcher common.Address - UnsafeBlockSigner common.Address - Proposer common.Address - Challenger common.Address +type ReadImplementationAddressesInput struct { + DeployOPChainOutput + Opcm common.Address + Release string } -// opcmDeployInput is the input struct for the deploy method of the OPStackManager contract. We -// define a separate struct here to match what the OPSM contract expects. -type opcmDeployInput struct { - Roles opcmRoles - BasefeeScalar uint32 - BlobBasefeeScalar uint32 - L2ChainId *big.Int - StartingAnchorRoots []byte - SaltMixer string - GasLimit uint64 - DisputeGameType uint32 - DisputeAbsolutePrestate common.Hash - DisputeMaxGameDepth *big.Int - DisputeSplitDepth *big.Int - DisputeClockExtension uint64 - DisputeMaxClockDuration uint64 +type ReadImplementationAddressesOutput struct { + DelayedWETH common.Address + OptimismPortal common.Address + SystemConfig common.Address + L1CrossDomainMessenger common.Address + L1ERC721Bridge common.Address + L1StandardBridge common.Address + OptimismMintableERC20Factory common.Address + DisputeGameFactory common.Address + MipsSingleton common.Address + PreimageOracleSingleton common.Address } -// decodeOutputABIJSON defines an ABI for a fake method called "decodeOutput" that returns the -// DeployOutput struct. This allows the code in the deployer to decode directly into a struct -// using Geth's ABI library. -const decodeOutputABIJSON = ` -[ - { - "type": "function", - "name": "decodeOutput", - "inputs": [], - "outputs": [ - { - "name": "output", - "indexed": false, - "type": "tuple", - "components": [ - { - "name": "opChainProxyAdmin", - "type": "address" - }, - { - "name": "addressManager", - "type": "address" - }, - { - "name": "l1ERC721BridgeProxy", - "type": "address" - }, - { - "name": "systemConfigProxy", - "type": "address" - }, - { - "name": "optimismMintableERC20FactoryProxy", - "type": "address" - }, - { - "name": "l1StandardBridgeProxy", - "type": "address" - }, - { - "name": "l1CrossDomainMessengerProxy", - "type": "address" - }, - { - "name": "optimismPortalProxy", - "type": "address" - }, - { - "name": "disputeGameFactoryProxy", - "type": "address" - }, - { - "name": "anchorStateRegistryProxy", - "type": "address" - }, - { - "name": "anchorStateRegistryImpl", - "type": "address" - }, - { - "name": "faultDisputeGame", - "type": "address", - "internalType": "contract FaultDisputeGame" - }, - { - "name": "permissionedDisputeGame", - "type": "address" - }, - { - "name": "delayedWETHPermissionedGameProxy", - "type": "address" - }, - { - "name": "delayedWETHPermissionlessGameProxy", - "type": "address" - } - ] - } - ] - } -] -` - -var decodeOutputABI abi.ABI - -// DeployOPChainRaw deploys an OP Chain using a raw call to a pre-deployed OPSM contract. -func DeployOPChainRaw( - ctx context.Context, - l1 *ethclient.Client, - bcast broadcaster.Broadcaster, - deployer common.Address, - artifacts foundry.StatDirFs, - input DeployOPChainInput, -) (DeployOPChainOutput, error) { - var out DeployOPChainOutput +type ReadImplementationAddressesScript struct { + Run func(input, output common.Address) error +} - artifactsFS := &foundry.ArtifactsFS{FS: artifacts} - opcmArtifacts, err := artifactsFS.ReadArtifact("OPContractsManager.sol", "OPContractsManager") - if err != nil { - return out, fmt.Errorf("failed to read OPStackManager artifact: %w", err) - } +func ReadImplementationAddresses(host *script.Host, input ReadImplementationAddressesInput) (ReadImplementationAddressesOutput, error) { + var rio ReadImplementationAddressesOutput + inputAddr := host.NewScriptAddress() + outputAddr := host.NewScriptAddress() - opcmABI := opcmArtifacts.ABI - calldata, err := opcmABI.Pack("deploy", opcmDeployInput{ - Roles: opcmRoles{ - OpChainProxyAdminOwner: input.OpChainProxyAdminOwner, - SystemConfigOwner: input.SystemConfigOwner, - Batcher: input.Batcher, - UnsafeBlockSigner: input.UnsafeBlockSigner, - Proposer: input.Proposer, - Challenger: input.Challenger, - }, - BasefeeScalar: input.BasefeeScalar, - BlobBasefeeScalar: input.BlobBaseFeeScalar, - L2ChainId: input.L2ChainId, - StartingAnchorRoots: input.StartingAnchorRoots(), - SaltMixer: input.SaltMixer, - GasLimit: input.GasLimit, - DisputeGameType: input.DisputeGameType, - DisputeAbsolutePrestate: input.DisputeAbsolutePrestate, - DisputeMaxGameDepth: new(big.Int).SetUint64(input.DisputeMaxGameDepth), - DisputeSplitDepth: new(big.Int).SetUint64(input.DisputeSplitDepth), - DisputeClockExtension: input.DisputeClockExtension, - DisputeMaxClockDuration: input.DisputeMaxClockDuration, - }) + cleanupInput, err := script.WithPrecompileAtAddress[*ReadImplementationAddressesInput](host, inputAddr, &input) if err != nil { - return out, fmt.Errorf("failed to pack deploy input: %w", err) + return rio, fmt.Errorf("failed to insert ReadImplementationAddressesInput precompile: %w", err) } + defer cleanupInput() + host.Label(inputAddr, "ReadImplementationAddressesInput") - nonce, err := l1.NonceAt(ctx, deployer, nil) + cleanupOutput, err := script.WithPrecompileAtAddress[*ReadImplementationAddressesOutput](host, outputAddr, &rio, + script.WithFieldSetter[*ReadImplementationAddressesOutput]) if err != nil { - return out, fmt.Errorf("failed to read nonce: %w", err) + return rio, fmt.Errorf("failed to insert ReadImplementationAddressesOutput precompile: %w", err) } + defer cleanupOutput() + host.Label(outputAddr, "ReadImplementationAddressesOutput") - bcast.Hook(script.Broadcast{ - From: deployer, - To: input.OpcmProxy, - Input: calldata, - Value: (*hexutil.U256)(uint256.NewInt(0)), - // use hardcoded 19MM gas for now since this is roughly what we've seen this deployment cost. - GasUsed: 19_000_000, - Type: script.BroadcastCall, - Nonce: nonce, - }) - - results, err := bcast.Broadcast(ctx) + deployScript, cleanupDeploy, err := script.WithScript[ReadImplementationAddressesScript](host, "ReadImplementationAddresses.s.sol", "ReadImplementationAddresses") if err != nil { - return out, fmt.Errorf("failed to broadcast OP chain deployment: %w", err) + return rio, fmt.Errorf("failed to load ReadImplementationAddresses script: %w", err) } + defer cleanupDeploy() - deployedEvent := opcmABI.Events["Deployed"] - res := results[0] - - for _, log := range res.Receipt.Logs { - if log.Topics[0] != deployedEvent.ID { - continue - } - - type EventData struct { - DeployOutput []byte - } - var data EventData - if err := opcmABI.UnpackIntoInterface(&data, "Deployed", log.Data); err != nil { - return out, fmt.Errorf("failed to unpack Deployed event: %w", err) - } - - type OutputData struct { - Output DeployOPChainOutput - } - var outData OutputData - if err := decodeOutputABI.UnpackIntoInterface(&outData, "decodeOutput", data.DeployOutput); err != nil { - return out, fmt.Errorf("failed to unpack DeployOutput: %w", err) - } - - return outData.Output, nil + if err := deployScript.Run(inputAddr, outputAddr); err != nil { + return rio, fmt.Errorf("failed to run ReadImplementationAddresses script: %w", err) } - return out, fmt.Errorf("failed to find Deployed event") -} - -func init() { - var err error - decodeOutputABI, err = abi.JSON(strings.NewReader(decodeOutputABIJSON)) - if err != nil { - panic(fmt.Sprintf("failed to parse decodeOutput ABI: %v", err)) - } + return rio, nil } diff --git a/op-deployer/pkg/deployer/opcm/standard.go b/op-deployer/pkg/deployer/opcm/standard.go deleted file mode 100644 index 5d85db942770d..0000000000000 --- a/op-deployer/pkg/deployer/opcm/standard.go +++ /dev/null @@ -1,144 +0,0 @@ -package opcm - -import ( - "embed" - "fmt" - "net/url" - - "github.com/BurntSushi/toml" - - "github.com/ethereum-optimism/superchain-registry/superchain" - "github.com/ethereum/go-ethereum/common" -) - -//go:embed standard-versions-mainnet.toml -var StandardVersionsMainnetData string - -//go:embed standard-versions-sepolia.toml -var StandardVersionsSepoliaData string - -var StandardL1VersionsSepolia StandardL1Versions - -var StandardL1VersionsMainnet StandardL1Versions - -var DefaultL1ContractsLocator = &ArtifactsLocator{ - Tag: "op-contracts/v1.6.0", -} - -var DefaultL2ContractsLocator = &ArtifactsLocator{ - Tag: "op-contracts/v1.7.0-beta.1+l2-contracts", -} - -type StandardL1Versions struct { - Releases map[string]StandardL1VersionsReleases `toml:"releases"` -} - -type StandardL1VersionsReleases struct { - OptimismPortal StandardVersionRelease `toml:"optimism_portal"` - SystemConfig StandardVersionRelease `toml:"system_config"` - AnchorStateRegistry StandardVersionRelease `toml:"anchor_state_registry"` - DelayedWETH StandardVersionRelease `toml:"delayed_weth"` - DisputeGameFactory StandardVersionRelease `toml:"dispute_game_factory"` - FaultDisputeGame StandardVersionRelease `toml:"fault_dispute_game"` - PermissionedDisputeGame StandardVersionRelease `toml:"permissioned_dispute_game"` - MIPS StandardVersionRelease `toml:"mips"` - PreimageOracle StandardVersionRelease `toml:"preimage_oracle"` - L1CrossDomainMessenger StandardVersionRelease `toml:"l1_cross_domain_messenger"` - L1ERC721Bridge StandardVersionRelease `toml:"l1_erc721_bridge"` - L1StandardBridge StandardVersionRelease `toml:"l1_standard_bridge"` - OptimismMintableERC20Factory StandardVersionRelease `toml:"optimism_mintable_erc20_factory"` -} - -type StandardVersionRelease struct { - Version string `toml:"version"` - ImplementationAddress common.Address `toml:"implementation_address"` - Address common.Address `toml:"address"` -} - -var _ embed.FS - -func StandardL1VersionsDataFor(chainID uint64) (string, error) { - switch chainID { - case 1: - return StandardVersionsMainnetData, nil - case 11155111: - return StandardVersionsSepoliaData, nil - default: - return "", fmt.Errorf("unsupported chain ID: %d", chainID) - } -} - -func StandardL1VersionsFor(chainID uint64) (StandardL1Versions, error) { - switch chainID { - case 1: - return StandardL1VersionsMainnet, nil - case 11155111: - return StandardL1VersionsSepolia, nil - default: - return StandardL1Versions{}, fmt.Errorf("unsupported chain ID: %d", chainID) - } -} - -func SuperchainFor(chainID uint64) (*superchain.Superchain, error) { - switch chainID { - case 1: - return superchain.Superchains["mainnet"], nil - case 11155111: - return superchain.Superchains["sepolia"], nil - default: - return nil, fmt.Errorf("unsupported chain ID: %d", chainID) - } -} - -func ManagerImplementationAddrFor(chainID uint64) (common.Address, error) { - switch chainID { - case 1: - // Generated using the bootstrap command on 10/18/2024. - return common.HexToAddress("0x18cec91779995ad14c880e4095456b9147160790"), nil - case 11155111: - // Generated using the bootstrap command on 10/18/2024. - return common.HexToAddress("0xf564eea7960ea244bfebcbbb17858748606147bf"), nil - default: - return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID) - } -} - -func ManagerOwnerAddrFor(chainID uint64) (common.Address, error) { - switch chainID { - case 1: - // Set to superchain proxy admin - return common.HexToAddress("0x543bA4AADBAb8f9025686Bd03993043599c6fB04"), nil - case 11155111: - // Set to development multisig - return common.HexToAddress("0xDEe57160aAfCF04c34C887B5962D0a69676d3C8B"), nil - default: - return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID) - } -} - -func StandardArtifactsURLForTag(tag string) (*url.URL, error) { - switch tag { - case "op-contracts/v1.6.0": - return url.Parse(standardArtifactsURL("ee07c78c3d8d4cd8f7a933c050f5afeebaa281b57b226cc6f092b19de2a8d61f")) - case "op-contracts/v1.7.0-beta.1+l2-contracts": - return url.Parse(standardArtifactsURL("b0fb1f6f674519d637cff39a22187a5993d7f81a6d7b7be6507a0b50a5e38597")) - default: - return nil, fmt.Errorf("unsupported tag: %s", tag) - } -} - -func standardArtifactsURL(checksum string) string { - return fmt.Sprintf("https://storage.googleapis.com/oplabs-contract-artifacts/artifacts-v1-%s.tar.gz", checksum) -} - -func init() { - StandardL1VersionsMainnet = StandardL1Versions{} - if err := toml.Unmarshal([]byte(StandardVersionsMainnetData), &StandardL1VersionsMainnet); err != nil { - panic(err) - } - - StandardL1VersionsSepolia = StandardL1Versions{} - if err := toml.Unmarshal([]byte(StandardVersionsSepoliaData), &StandardL1VersionsSepolia); err != nil { - panic(err) - } -} diff --git a/op-deployer/pkg/deployer/pipeline/alt_da.go b/op-deployer/pkg/deployer/pipeline/alt_da.go new file mode 100644 index 0000000000000..b364126209451 --- /dev/null +++ b/op-deployer/pkg/deployer/pipeline/alt_da.go @@ -0,0 +1,56 @@ +package pipeline + +import ( + "fmt" + "math/big" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" + "github.com/ethereum/go-ethereum/common" +) + +func DeployAltDA(env *Env, intent *state.Intent, st *state.State, chainID common.Hash) error { + lgr := env.Logger.New("stage", "deploy-alt-da") + + chainIntent, err := intent.Chain(chainID) + if err != nil { + return fmt.Errorf("failed to get chain intent: %w", err) + } + + chainState, err := st.Chain(chainID) + if err != nil { + return fmt.Errorf("failed to get chain state: %w", err) + } + + if !shouldDeployAltDA(chainIntent, chainState) { + lgr.Info("alt-da deployment not needed") + return nil + } + + var dao opcm.DeployAltDAOutput + lgr.Info("deploying alt-da contracts") + dao, err = opcm.DeployAltDA(env.L1ScriptHost, opcm.DeployAltDAInput{ + Salt: st.Create2Salt, + ProxyAdmin: chainState.ProxyAdminAddress, + ChallengeContractOwner: chainIntent.Roles.L1ProxyAdminOwner, + ChallengeWindow: new(big.Int).SetUint64(chainIntent.DangerousAltDAConfig.DAChallengeWindow), + ResolveWindow: new(big.Int).SetUint64(chainIntent.DangerousAltDAConfig.DAResolveWindow), + BondSize: new(big.Int).SetUint64(chainIntent.DangerousAltDAConfig.DABondSize), + ResolverRefundPercentage: new(big.Int).SetUint64(chainIntent.DangerousAltDAConfig.DAResolverRefundPercentage), + }) + if err != nil { + return fmt.Errorf("failed to deploy alt-da contracts: %w", err) + } + + chainState.DataAvailabilityChallengeProxyAddress = dao.DataAvailabilityChallengeProxy + chainState.DataAvailabilityChallengeImplAddress = dao.DataAvailabilityChallengeImpl + return nil +} + +func shouldDeployAltDA(chainIntent *state.ChainIntent, chainState *state.ChainState) bool { + if !chainIntent.DangerousAltDAConfig.UseAltDA { + return false + } + + return chainState.DataAvailabilityChallengeImplAddress == common.Address{} +} diff --git a/op-deployer/pkg/deployer/pipeline/env.go b/op-deployer/pkg/deployer/pipeline/env.go index 0b6ca536dd8b4..20d8daaf76fa1 100644 --- a/op-deployer/pkg/deployer/pipeline/env.go +++ b/op-deployer/pkg/deployer/pipeline/env.go @@ -23,7 +23,6 @@ type Env struct { L1ScriptHost *script.Host L1Client *ethclient.Client Broadcaster broadcaster.Broadcaster - Host *script.Host Deployer common.Address Logger log.Logger } diff --git a/op-deployer/pkg/deployer/pipeline/implementations.go b/op-deployer/pkg/deployer/pipeline/implementations.go index 17628ec605cd6..9e65fd4f54a36 100644 --- a/op-deployer/pkg/deployer/pipeline/implementations.go +++ b/op-deployer/pkg/deployer/pipeline/implementations.go @@ -4,10 +4,22 @@ import ( "fmt" "math/big" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" + "github.com/ethereum-optimism/optimism/op-service/jsonutil" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" ) +type SuperchainProofParams struct { + WithdrawalDelaySeconds uint64 `json:"withdrawalDelaySeconds" toml:"withdrawalDelaySeconds"` + MinProposalSizeBytes uint64 `json:"minProposalSizeBytes" toml:"minProposalSizeBytes"` + ChallengePeriodSeconds uint64 `json:"challengePeriodSeconds" toml:"challengePeriodSeconds"` + ProofMaturityDelaySeconds uint64 `json:"proofMaturityDelaySeconds" toml:"proofMaturityDelaySeconds"` + DisputeGameFinalityDelaySeconds uint64 `json:"disputeGameFinalityDelaySeconds" toml:"disputeGameFinalityDelaySeconds"` + MIPSVersion uint64 `json:"mipsVersion" toml:"mipsVersion"` +} + func DeployImplementations(env *Env, intent *state.Intent, st *state.State) error { lgr := env.Logger.New("stage", "deploy-implementations") @@ -22,7 +34,7 @@ func DeployImplementations(env *Env, intent *state.Intent, st *state.State) erro var contractsRelease string var err error if intent.L1ContractsLocator.IsTag() && intent.DeploymentStrategy == state.DeploymentStrategyLive { - standardVersionsTOML, err = opcm.StandardL1VersionsDataFor(intent.L1ChainID) + standardVersionsTOML, err = standard.L1VersionsDataFor(intent.L1ChainID) if err != nil { return fmt.Errorf("error getting standard versions TOML: %w", err) } @@ -31,24 +43,36 @@ func DeployImplementations(env *Env, intent *state.Intent, st *state.State) erro contractsRelease = "dev" } - env.L1ScriptHost.ImportState(st.L1StateDump.Data) + proofParams, err := jsonutil.MergeJSON( + SuperchainProofParams{ + WithdrawalDelaySeconds: standard.WithdrawalDelaySeconds, + MinProposalSizeBytes: standard.MinProposalSizeBytes, + ChallengePeriodSeconds: standard.ChallengePeriodSeconds, + ProofMaturityDelaySeconds: standard.ProofMaturityDelaySeconds, + DisputeGameFinalityDelaySeconds: standard.DisputeGameFinalityDelaySeconds, + MIPSVersion: standard.MIPSVersion, + }, + intent.GlobalDeployOverrides, + ) + if err != nil { + return fmt.Errorf("error merging proof params from overrides: %w", err) + } dio, err := opcm.DeployImplementations( env.L1ScriptHost, opcm.DeployImplementationsInput{ Salt: st.Create2Salt, - WithdrawalDelaySeconds: big.NewInt(604800), - MinProposalSizeBytes: big.NewInt(126000), - ChallengePeriodSeconds: big.NewInt(86400), - ProofMaturityDelaySeconds: big.NewInt(604800), - DisputeGameFinalityDelaySeconds: big.NewInt(302400), - MipsVersion: big.NewInt(1), - Release: contractsRelease, + WithdrawalDelaySeconds: new(big.Int).SetUint64(proofParams.WithdrawalDelaySeconds), + MinProposalSizeBytes: new(big.Int).SetUint64(proofParams.MinProposalSizeBytes), + ChallengePeriodSeconds: new(big.Int).SetUint64(proofParams.ChallengePeriodSeconds), + ProofMaturityDelaySeconds: new(big.Int).SetUint64(proofParams.ProofMaturityDelaySeconds), + DisputeGameFinalityDelaySeconds: new(big.Int).SetUint64(proofParams.DisputeGameFinalityDelaySeconds), + MipsVersion: new(big.Int).SetUint64(proofParams.MIPSVersion), + L1ContractsRelease: contractsRelease, SuperchainConfigProxy: st.SuperchainDeployment.SuperchainConfigProxyAddress, ProtocolVersionsProxy: st.SuperchainDeployment.ProtocolVersionsProxyAddress, - OpcmProxyOwner: st.SuperchainDeployment.ProxyAdminAddress, StandardVersionsToml: standardVersionsTOML, - UseInterop: false, + UseInterop: intent.UseInterop, }, ) if err != nil { @@ -56,7 +80,7 @@ func DeployImplementations(env *Env, intent *state.Intent, st *state.State) erro } st.ImplementationsDeployment = &state.ImplementationsDeployment{ - OpcmProxyAddress: dio.OpcmProxy, + OpcmAddress: dio.Opcm, DelayedWETHImplAddress: dio.DelayedWETHImpl, OptimismPortalImplAddress: dio.OptimismPortalImpl, PreimageOracleSingletonAddress: dio.PreimageOracleSingleton, diff --git a/op-deployer/pkg/deployer/pipeline/init.go b/op-deployer/pkg/deployer/pipeline/init.go index 9d5f2324fa453..b5c37c246f294 100644 --- a/op-deployer/pkg/deployer/pipeline/init.go +++ b/op-deployer/pkg/deployer/pipeline/init.go @@ -5,7 +5,8 @@ import ( "crypto/rand" "fmt" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" "github.com/ethereum-optimism/optimism/op-chain-ops/script" @@ -26,12 +27,12 @@ func InitLiveStrategy(ctx context.Context, env *Env, intent *state.Intent, st *s } if intent.L1ContractsLocator.IsTag() { - superCfg, err := opcm.SuperchainFor(intent.L1ChainID) + superCfg, err := standard.SuperchainFor(intent.L1ChainID) if err != nil { return fmt.Errorf("error getting superchain config: %w", err) } - proxyAdmin, err := opcm.ManagerOwnerAddrFor(intent.L1ChainID) + proxyAdmin, err := standard.ManagerOwnerAddrFor(intent.L1ChainID) if err != nil { return fmt.Errorf("error getting superchain proxy admin address: %w", err) } @@ -44,12 +45,12 @@ func InitLiveStrategy(ctx context.Context, env *Env, intent *state.Intent, st *s SuperchainConfigProxyAddress: common.Address(*superCfg.Config.SuperchainConfigAddr), } - opcmProxy, err := opcm.ManagerImplementationAddrFor(intent.L1ChainID) + opcmAddress, err := standard.ManagerImplementationAddrFor(intent.L1ChainID) if err != nil { return fmt.Errorf("error getting OPCM proxy address: %w", err) } st.ImplementationsDeployment = &state.ImplementationsDeployment{ - OpcmProxyAddress: opcmProxy, + OpcmAddress: opcmAddress, } } diff --git a/op-deployer/pkg/deployer/pipeline/l2genesis.go b/op-deployer/pkg/deployer/pipeline/l2genesis.go index 4fa8755df6eee..945cb5af8ff09 100644 --- a/op-deployer/pkg/deployer/pipeline/l2genesis.go +++ b/op-deployer/pkg/deployer/pipeline/l2genesis.go @@ -3,6 +3,8 @@ package pipeline import ( "fmt" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + "github.com/ethereum-optimism/optimism/op-chain-ops/foundry" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" @@ -11,8 +13,8 @@ import ( "github.com/ethereum/go-ethereum/common" ) -func GenerateL2Genesis(env *Env, intent *state.Intent, bundle ArtifactsBundle, st *state.State, chainID common.Hash) error { - lgr := env.Logger.New("stage", "generate-l2-genesis") +func GenerateL2Genesis(pEnv *Env, intent *state.Intent, bundle ArtifactsBundle, st *state.State, chainID common.Hash) error { + lgr := pEnv.Logger.New("stage", "generate-l2-genesis") thisIntent, err := intent.Chain(chainID) if err != nil { @@ -36,12 +38,11 @@ func GenerateL2Genesis(env *Env, intent *state.Intent, bundle ArtifactsBundle, s return fmt.Errorf("failed to combine L2 init config: %w", err) } - host, err := DefaultScriptHost( + host, err := env.DefaultScriptHost( broadcaster.NoopBroadcaster(), - env.Logger, - env.Deployer, + pEnv.Logger, + pEnv.Deployer, bundle.L2, - 0, ) if err != nil { return fmt.Errorf("failed to create L2 script host: %w", err) @@ -58,7 +59,7 @@ func GenerateL2Genesis(env *Env, intent *state.Intent, bundle ArtifactsBundle, s return fmt.Errorf("failed to call L2Genesis script: %w", err) } - host.Wipe(env.Deployer) + host.Wipe(pEnv.Deployer) dump, err := host.StateDump() if err != nil { diff --git a/op-deployer/pkg/deployer/pipeline/opchain.go b/op-deployer/pkg/deployer/pipeline/opchain.go index 5152eca3208a1..90cc665e077dd 100644 --- a/op-deployer/pkg/deployer/pipeline/opchain.go +++ b/op-deployer/pkg/deployer/pipeline/opchain.go @@ -1,20 +1,18 @@ package pipeline import ( - "context" - "encoding/hex" - "errors" "fmt" - "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" + "github.com/ethereum-optimism/optimism/op-service/jsonutil" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" ) -func DeployOPChainLiveStrategy(ctx context.Context, env *Env, bundle ArtifactsBundle, intent *state.Intent, st *state.State, chainID common.Hash) error { - lgr := env.Logger.New("stage", "deploy-opchain", "strategy", "live") +func DeployOPChain(env *Env, intent *state.Intent, st *state.State, chainID common.Hash) error { + lgr := env.Logger.New("stage", "deploy-opchain") if !shouldDeployOPChain(st, chainID) { lgr.Info("opchain deployment not needed") @@ -26,172 +24,131 @@ func DeployOPChainLiveStrategy(ctx context.Context, env *Env, bundle ArtifactsBu return fmt.Errorf("failed to get chain intent: %w", err) } - input := makeDCI(thisIntent, chainID, st) + var opcmAddr common.Address + var deployFunc func() (opcm.DeployOPChainOutput, error) + switch intent.L1ContractsLocator.Tag { + case standard.ContractsV160Tag, standard.ContractsV170Beta1L2Tag: + deployFunc = func() (opcm.DeployOPChainOutput, error) { + input, err := makeDCIV160(intent, thisIntent, chainID, st) + if err != nil { + return opcm.DeployOPChainOutput{}, fmt.Errorf("error making deploy OP chain input: %w", err) + } + + opcmAddr = input.Opcm + return opcm.DeployOPChainV160(env.L1ScriptHost, input) + } + default: + deployFunc = func() (opcm.DeployOPChainOutput, error) { + input, err := makeDCIIsthmus(intent, thisIntent, chainID, st) + if err != nil { + return opcm.DeployOPChainOutput{}, fmt.Errorf("error making deploy OP chain input: %w", err) + } + + opcmAddr = input.Opcm + return opcm.DeployOPChainIsthmus(env.L1ScriptHost, input) + } + } var dco opcm.DeployOPChainOutput - lgr.Info("deploying OP chain using existing OPCM", "id", chainID.Hex(), "opcmAddress", st.ImplementationsDeployment.OpcmProxyAddress.Hex()) - dco, err = opcm.DeployOPChainRaw( - ctx, - env.L1Client, - env.Broadcaster, - env.Deployer, - bundle.L1, - input, - ) + lgr.Info("deploying OP chain using local allocs", "id", chainID.Hex()) + dco, err = deployFunc() if err != nil { return fmt.Errorf("error deploying OP chain: %w", err) } st.Chains = append(st.Chains, makeChainState(chainID, dco)) - opcmProxyAddress := st.ImplementationsDeployment.OpcmProxyAddress - err = conditionallySetImplementationAddresses(ctx, env.L1Client, intent, st, dco, opcmProxyAddress) - if err != nil { - return fmt.Errorf("failed to set implementation addresses: %w", err) - } - return nil -} - -// Only try to set the implementation addresses if we reused existing implementations from a release tag. -// The reason why these addresses could be empty is because only DeployOPChain.s.sol is invoked as part of the pipeline. -func conditionallySetImplementationAddresses(ctx context.Context, client *ethclient.Client, intent *state.Intent, st *state.State, dco opcm.DeployOPChainOutput, opcmProxyAddress common.Address) error { - if !intent.L1ContractsLocator.IsTag() { - return nil + var release string + if intent.L1ContractsLocator.IsTag() { + release = intent.L1ContractsLocator.Tag + } else { + release = "dev" } - block, err := client.BlockByNumber(ctx, nil) - if err != nil { - return fmt.Errorf("failed to get latest block by number: %w", err) - } - currentBlockHash := block.Hash() - - errCh := make(chan error, 8) - - setImplementationAddressTasks := []func(){ - func() { - setEIP1967ImplementationAddress(ctx, client, errCh, dco.DelayedWETHPermissionedGameProxy, currentBlockHash, &st.ImplementationsDeployment.DelayedWETHImplAddress) - }, - func() { - setEIP1967ImplementationAddress(ctx, client, errCh, dco.OptimismPortalProxy, currentBlockHash, &st.ImplementationsDeployment.OptimismPortalImplAddress) - }, - func() { - setEIP1967ImplementationAddress(ctx, client, errCh, dco.SystemConfigProxy, currentBlockHash, &st.ImplementationsDeployment.SystemConfigImplAddress) - }, - func() { - setRDPImplementationAddress(ctx, client, errCh, dco.AddressManager, &st.ImplementationsDeployment.L1CrossDomainMessengerImplAddress, "OVM_L1CrossDomainMessenger") - }, - func() { - setEIP1967ImplementationAddress(ctx, client, errCh, dco.L1ERC721BridgeProxy, currentBlockHash, &st.ImplementationsDeployment.L1ERC721BridgeImplAddress) - }, - func() { - setEIP1967ImplementationAddress(ctx, client, errCh, dco.L1StandardBridgeProxy, currentBlockHash, &st.ImplementationsDeployment.L1StandardBridgeImplAddress) - }, - func() { - setEIP1967ImplementationAddress(ctx, client, errCh, dco.OptimismMintableERC20FactoryProxy, currentBlockHash, &st.ImplementationsDeployment.OptimismMintableERC20FactoryImplAddress) - }, - func() { - setEIP1967ImplementationAddress(ctx, client, errCh, dco.DisputeGameFactoryProxy, currentBlockHash, &st.ImplementationsDeployment.DisputeGameFactoryImplAddress) - }, - func() { - setMipsSingletonAddress(ctx, client, intent.L1ContractsLocator, errCh, opcmProxyAddress, &st.ImplementationsDeployment.MipsSingletonAddress) - setPreimageOracleAddress(ctx, client, errCh, st.ImplementationsDeployment.MipsSingletonAddress, &st.ImplementationsDeployment.PreimageOracleSingletonAddress) - }, + readInput := opcm.ReadImplementationAddressesInput{ + DeployOPChainOutput: dco, + Opcm: opcmAddr, + Release: release, } - - for _, task := range setImplementationAddressTasks { - go task() + impls, err := opcm.ReadImplementationAddresses(env.L1ScriptHost, readInput) + if err != nil { + return fmt.Errorf("failed to read implementation addresses: %w", err) } - var lastTaskErr error - for i := 0; i < len(setImplementationAddressTasks); i++ { - taskErr := <-errCh - if taskErr != nil { - lastTaskErr = taskErr - } - } - if lastTaskErr != nil { - return fmt.Errorf("failed to set implementation addresses: %w", lastTaskErr) - } + st.ImplementationsDeployment.DelayedWETHImplAddress = impls.DelayedWETH + st.ImplementationsDeployment.OptimismPortalImplAddress = impls.OptimismPortal + st.ImplementationsDeployment.SystemConfigImplAddress = impls.SystemConfig + st.ImplementationsDeployment.L1CrossDomainMessengerImplAddress = impls.L1CrossDomainMessenger + st.ImplementationsDeployment.L1ERC721BridgeImplAddress = impls.L1ERC721Bridge + st.ImplementationsDeployment.L1StandardBridgeImplAddress = impls.L1StandardBridge + st.ImplementationsDeployment.OptimismMintableERC20FactoryImplAddress = impls.OptimismMintableERC20Factory + st.ImplementationsDeployment.DisputeGameFactoryImplAddress = impls.DisputeGameFactory + st.ImplementationsDeployment.MipsSingletonAddress = impls.MipsSingleton + st.ImplementationsDeployment.PreimageOracleSingletonAddress = impls.PreimageOracleSingleton return nil } -func setMipsSingletonAddress(ctx context.Context, client *ethclient.Client, l1ArtifactsLocator *opcm.ArtifactsLocator, errCh chan error, opcmProxyAddress common.Address, singletonAddress *common.Address) { - if !l1ArtifactsLocator.IsTag() { - errCh <- errors.New("L1 contracts locator is not a tag, cannot set MIPS singleton address") - return - } - opcmContract := opcm.NewContract(opcmProxyAddress, client) - mipsSingletonAddress, err := opcmContract.GetOPCMImplementationAddress(ctx, l1ArtifactsLocator.Tag, "MIPS") - - if err == nil { - *singletonAddress = mipsSingletonAddress - } - errCh <- err +type ChainProofParams struct { + DisputeGameType uint32 `json:"disputeGameType" toml:"disputeGameType"` + DisputeAbsolutePrestate common.Hash `json:"disputeAbsolutePrestate" toml:"disputeAbsolutePrestate"` + DisputeMaxGameDepth uint64 `json:"disputeMaxGameDepth" toml:"disputeMaxGameDepth"` + DisputeSplitDepth uint64 `json:"disputeSplitDepth" toml:"disputeSplitDepth"` + DisputeClockExtension uint64 `json:"disputeClockExtension" toml:"disputeClockExtension"` + DisputeMaxClockDuration uint64 `json:"disputeMaxClockDuration" toml:"disputeMaxClockDuration"` + DangerouslyAllowCustomDisputeParameters bool `json:"dangerouslyAllowCustomDisputeParameters" toml:"dangerouslyAllowCustomDisputeParameters"` } -func setPreimageOracleAddress(ctx context.Context, client *ethclient.Client, errCh chan error, mipsSingletonAddress common.Address, preimageOracleAddress *common.Address) { - opcmContract := opcm.NewContract(mipsSingletonAddress, client) - preimageOracle, err := opcmContract.GenericAddressGetter(ctx, "oracle") - if err == nil { - *preimageOracleAddress = preimageOracle - } - errCh <- err -} - -func DeployOPChainGenesisStrategy(env *Env, intent *state.Intent, st *state.State, chainID common.Hash) error { - lgr := env.Logger.New("stage", "deploy-opchain", "strategy", "genesis") - - if !shouldDeployOPChain(st, chainID) { - lgr.Info("opchain deployment not needed") - return nil - } - - thisIntent, err := intent.Chain(chainID) - if err != nil { - return fmt.Errorf("failed to get chain intent: %w", err) - } - - input := makeDCI(thisIntent, chainID, st) - - env.L1ScriptHost.ImportState(st.L1StateDump.Data) - - var dco opcm.DeployOPChainOutput - lgr.Info("deploying OP chain using local allocs", "id", chainID.Hex()) - dco, err = opcm.DeployOPChain( - env.L1ScriptHost, - input, +func makeDCIV160(intent *state.Intent, thisIntent *state.ChainIntent, chainID common.Hash, st *state.State) (opcm.DeployOPChainInputV160, error) { + proofParams, err := jsonutil.MergeJSON( + ChainProofParams{ + DisputeGameType: standard.DisputeGameType, + DisputeAbsolutePrestate: standard.DisputeAbsolutePrestate, + DisputeMaxGameDepth: standard.DisputeMaxGameDepth, + DisputeSplitDepth: standard.DisputeSplitDepth, + DisputeClockExtension: standard.DisputeClockExtension, + DisputeMaxClockDuration: standard.DisputeMaxClockDuration, + }, + intent.GlobalDeployOverrides, + thisIntent.DeployOverrides, ) if err != nil { - return fmt.Errorf("error deploying OP chain: %w", err) - } - - st.Chains = append(st.Chains, makeChainState(chainID, dco)) - - return nil + return opcm.DeployOPChainInputV160{}, fmt.Errorf("error merging proof params from overrides: %w", err) + } + + return opcm.DeployOPChainInputV160{ + OpChainProxyAdminOwner: thisIntent.Roles.L1ProxyAdminOwner, + SystemConfigOwner: thisIntent.Roles.SystemConfigOwner, + Batcher: thisIntent.Roles.Batcher, + UnsafeBlockSigner: thisIntent.Roles.UnsafeBlockSigner, + Proposer: thisIntent.Roles.Proposer, + Challenger: thisIntent.Roles.Challenger, + BasefeeScalar: standard.BasefeeScalar, + BlobBaseFeeScalar: standard.BlobBaseFeeScalar, + L2ChainId: chainID.Big(), + Opcm: st.ImplementationsDeployment.OpcmAddress, + SaltMixer: st.Create2Salt.String(), // passing through salt generated at state initialization + GasLimit: standard.GasLimit, + DisputeGameType: proofParams.DisputeGameType, + DisputeAbsolutePrestate: proofParams.DisputeAbsolutePrestate, + DisputeMaxGameDepth: proofParams.DisputeMaxGameDepth, + DisputeSplitDepth: proofParams.DisputeSplitDepth, + DisputeClockExtension: proofParams.DisputeClockExtension, // 3 hours (input in seconds) + DisputeMaxClockDuration: proofParams.DisputeMaxClockDuration, // 3.5 days (input in seconds) + AllowCustomDisputeParameters: proofParams.DangerouslyAllowCustomDisputeParameters, + }, nil } -func makeDCI(thisIntent *state.ChainIntent, chainID common.Hash, st *state.State) opcm.DeployOPChainInput { - return opcm.DeployOPChainInput{ - OpChainProxyAdminOwner: thisIntent.Roles.L1ProxyAdminOwner, - SystemConfigOwner: thisIntent.Roles.SystemConfigOwner, - Batcher: thisIntent.Roles.Batcher, - UnsafeBlockSigner: thisIntent.Roles.UnsafeBlockSigner, - Proposer: thisIntent.Roles.Proposer, - Challenger: thisIntent.Roles.Challenger, - BasefeeScalar: 1368, - BlobBaseFeeScalar: 801949, - L2ChainId: chainID.Big(), - OpcmProxy: st.ImplementationsDeployment.OpcmProxyAddress, - SaltMixer: st.Create2Salt.String(), // passing through salt generated at state initialization - 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) +func makeDCIIsthmus(intent *state.Intent, thisIntent *state.ChainIntent, chainID common.Hash, st *state.State) (opcm.DeployOPChainInputIsthmus, error) { + dci, err := makeDCIV160(intent, thisIntent, chainID, st) + if err != nil { + return opcm.DeployOPChainInputIsthmus{}, fmt.Errorf("error making deploy OP chain input: %w", err) } + + return opcm.DeployOPChainInputIsthmus{ + DeployOPChainInputV160: dci, + SystemConfigFeeAdmin: common.Address{'D', 'E', 'A', 'D'}, + }, nil } func makeChainState(chainID common.Hash, dco opcm.DeployOPChainOutput) *state.ChainState { @@ -215,33 +172,6 @@ func makeChainState(chainID common.Hash, dco opcm.DeployOPChainOutput) *state.Ch } } -func setRDPImplementationAddress(ctx context.Context, client *ethclient.Client, errCh chan error, addressManager common.Address, implAddress *common.Address, getNameArg string) { - if *implAddress != (common.Address{}) { - errCh <- nil - return - } - - addressManagerContract := opcm.NewContract(addressManager, client) - address, err := addressManagerContract.GetAddressByNameViaAddressManager(ctx, getNameArg) - if err == nil { - *implAddress = address - } - errCh <- err -} - -func setEIP1967ImplementationAddress(ctx context.Context, client *ethclient.Client, errCh chan error, proxy common.Address, currentBlockHash common.Hash, implAddress *common.Address) { - if *implAddress != (common.Address{}) { - errCh <- nil - return - } - - storageValue, err := client.StorageAtHash(ctx, proxy, genesis.ImplementationSlot, currentBlockHash) - if err == nil { - *implAddress = common.HexToAddress(hex.EncodeToString(storageValue)) - } - errCh <- err -} - func shouldDeployOPChain(st *state.State, chainID common.Hash) bool { for _, chain := range st.Chains { if chain.ID == chainID { diff --git a/op-deployer/pkg/deployer/opcm/standard-versions-mainnet.toml b/op-deployer/pkg/deployer/standard/standard-versions-mainnet.toml similarity index 100% rename from op-deployer/pkg/deployer/opcm/standard-versions-mainnet.toml rename to op-deployer/pkg/deployer/standard/standard-versions-mainnet.toml diff --git a/op-deployer/pkg/deployer/opcm/standard-versions-sepolia.toml b/op-deployer/pkg/deployer/standard/standard-versions-sepolia.toml similarity index 100% rename from op-deployer/pkg/deployer/opcm/standard-versions-sepolia.toml rename to op-deployer/pkg/deployer/standard/standard-versions-sepolia.toml diff --git a/op-deployer/pkg/deployer/standard/standard.go b/op-deployer/pkg/deployer/standard/standard.go new file mode 100644 index 0000000000000..516bdb6502833 --- /dev/null +++ b/op-deployer/pkg/deployer/standard/standard.go @@ -0,0 +1,197 @@ +package standard + +import ( + "embed" + "fmt" + "net/url" + + "github.com/BurntSushi/toml" + + "github.com/ethereum-optimism/superchain-registry/superchain" + "github.com/ethereum/go-ethereum/common" +) + +const ( + GasLimit uint64 = 60_000_000 + BasefeeScalar uint32 = 1368 + BlobBaseFeeScalar uint32 = 801949 + WithdrawalDelaySeconds uint64 = 604800 + MinProposalSizeBytes uint64 = 126000 + ChallengePeriodSeconds uint64 = 86400 + ProofMaturityDelaySeconds uint64 = 604800 + DisputeGameFinalityDelaySeconds uint64 = 302400 + MIPSVersion uint64 = 1 + DisputeGameType uint32 = 1 // PERMISSIONED game type + DisputeMaxGameDepth uint64 = 73 + DisputeSplitDepth uint64 = 30 + DisputeClockExtension uint64 = 10800 + DisputeMaxClockDuration uint64 = 302400 + + ContractsV160Tag = "op-contracts/v1.6.0" + ContractsV170Beta1L2Tag = "op-contracts/v1.7.0-beta.1+l2-contracts" +) + +var DisputeAbsolutePrestate = common.HexToHash("0x038512e02c4c3f7bdaec27d00edf55b7155e0905301e1a88083e4e0a6764d54c") + +//go:embed standard-versions-mainnet.toml +var VersionsMainnetData string + +//go:embed standard-versions-sepolia.toml +var VersionsSepoliaData string + +var L1VersionsSepolia L1Versions + +var L1VersionsMainnet L1Versions + +var DefaultL1ContractsTag = ContractsV160Tag + +var DefaultL2ContractsTag = ContractsV170Beta1L2Tag + +type L1Versions struct { + Releases map[string]L1VersionsReleases `toml:"releases"` +} + +type L1VersionsReleases struct { + OptimismPortal VersionRelease `toml:"optimism_portal"` + SystemConfig VersionRelease `toml:"system_config"` + AnchorStateRegistry VersionRelease `toml:"anchor_state_registry"` + DelayedWETH VersionRelease `toml:"delayed_weth"` + DisputeGameFactory VersionRelease `toml:"dispute_game_factory"` + FaultDisputeGame VersionRelease `toml:"fault_dispute_game"` + PermissionedDisputeGame VersionRelease `toml:"permissioned_dispute_game"` + MIPS VersionRelease `toml:"mips"` + PreimageOracle VersionRelease `toml:"preimage_oracle"` + L1CrossDomainMessenger VersionRelease `toml:"l1_cross_domain_messenger"` + L1ERC721Bridge VersionRelease `toml:"l1_erc721_bridge"` + L1StandardBridge VersionRelease `toml:"l1_standard_bridge"` + OptimismMintableERC20Factory VersionRelease `toml:"optimism_mintable_erc20_factory"` +} + +type VersionRelease struct { + Version string `toml:"version"` + ImplementationAddress common.Address `toml:"implementation_address"` + Address common.Address `toml:"address"` +} + +var _ embed.FS + +func L1VersionsDataFor(chainID uint64) (string, error) { + switch chainID { + case 1: + return VersionsMainnetData, nil + case 11155111: + return VersionsSepoliaData, nil + default: + return "", fmt.Errorf("unsupported chain ID: %d", chainID) + } +} + +func L1VersionsFor(chainID uint64) (L1Versions, error) { + switch chainID { + case 1: + return L1VersionsMainnet, nil + case 11155111: + return L1VersionsSepolia, nil + default: + return L1Versions{}, fmt.Errorf("unsupported chain ID: %d", chainID) + } +} + +func SuperchainFor(chainID uint64) (*superchain.Superchain, error) { + switch chainID { + case 1: + return superchain.Superchains["mainnet"], nil + case 11155111: + return superchain.Superchains["sepolia"], nil + default: + return nil, fmt.Errorf("unsupported chain ID: %d", chainID) + } +} + +func ChainNameFor(chainID uint64) (string, error) { + switch chainID { + case 1: + return "mainnet", nil + case 11155111: + return "sepolia", nil + default: + return "", fmt.Errorf("unrecognized chain ID: %d", chainID) + } +} + +func CommitForDeployTag(tag string) (string, error) { + switch tag { + case "op-contracts/v1.6.0": + return "33f06d2d5e4034125df02264a5ffe84571bd0359", nil + case "op-contracts/v1.7.0-beta.1+l2-contracts": + return "5e14a61547a45eef2ebeba677aee4a049f106ed8", nil + default: + return "", fmt.Errorf("unsupported tag: %s", tag) + } +} + +func ManagerImplementationAddrFor(chainID uint64) (common.Address, error) { + switch chainID { + case 1: + // Generated using the bootstrap command on 11/18/2024. + return common.HexToAddress("0x9bc0a1ed534bfb31a6be69e5b767cba332f14347"), nil + case 11155111: + // Generated using the bootstrap command on 11/15/2024. + return common.HexToAddress("0xde9eacb994a6eb12997445f8a63a22772c5c4313"), nil + default: + return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID) + } +} + +func ManagerOwnerAddrFor(chainID uint64) (common.Address, error) { + switch chainID { + case 1: + // Set to superchain proxy admin + return common.HexToAddress("0x543bA4AADBAb8f9025686Bd03993043599c6fB04"), nil + case 11155111: + // Set to development multisig + return common.HexToAddress("0xDEe57160aAfCF04c34C887B5962D0a69676d3C8B"), nil + default: + return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID) + } +} + +func SystemOwnerAddrFor(chainID uint64) (common.Address, error) { + switch chainID { + case 1: + // Set to owner of superchain proxy admin + return common.HexToAddress("0x5a0Aae59D09fccBdDb6C6CcEB07B7279367C3d2A"), nil + case 11155111: + // Set to development multisig + return common.HexToAddress("0xDEe57160aAfCF04c34C887B5962D0a69676d3C8B"), nil + default: + return common.Address{}, fmt.Errorf("unsupported chain ID: %d", chainID) + } +} + +func ArtifactsURLForTag(tag string) (*url.URL, error) { + switch tag { + case "op-contracts/v1.6.0": + return url.Parse(standardArtifactsURL("e1f0c4020618c4a98972e7124c39686cab2e31d5d7846f9ce5e0d5eed0f5ff32")) + case "op-contracts/v1.7.0-beta.1+l2-contracts": + return url.Parse(standardArtifactsURL("b0fb1f6f674519d637cff39a22187a5993d7f81a6d7b7be6507a0b50a5e38597")) + default: + return nil, fmt.Errorf("unsupported tag: %s", tag) + } +} + +func standardArtifactsURL(checksum string) string { + return fmt.Sprintf("https://storage.googleapis.com/oplabs-contract-artifacts/artifacts-v1-%s.tar.gz", checksum) +} + +func init() { + L1VersionsMainnet = L1Versions{} + if err := toml.Unmarshal([]byte(VersionsMainnetData), &L1VersionsMainnet); err != nil { + panic(err) + } + + L1VersionsSepolia = L1Versions{} + if err := toml.Unmarshal([]byte(VersionsSepoliaData), &L1VersionsSepolia); err != nil { + panic(err) + } +} diff --git a/op-deployer/pkg/deployer/state/deploy_config.go b/op-deployer/pkg/deployer/state/deploy_config.go index 2bc8307ab9d87..1a03c21d7e94b 100644 --- a/op-deployer/pkg/deployer/state/deploy_config.go +++ b/op-deployer/pkg/deployer/state/deploy_config.go @@ -1,10 +1,11 @@ package state import ( - "encoding/json" "fmt" "math/big" + "github.com/ethereum-optimism/optimism/op-service/jsonutil" + "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/common" @@ -69,7 +70,7 @@ func CombineDeployConfig(intent *Intent, chainIntent *ChainIntent, state *State, L2GenesisEcotoneTimeOffset: u64UtilPtr(0), L2GenesisFjordTimeOffset: u64UtilPtr(0), L2GenesisGraniteTimeOffset: u64UtilPtr(0), - UseInterop: false, + UseInterop: intent.UseInterop, }, L2CoreDeployConfig: genesis.L2CoreDeployConfig{ L1ChainID: intent.L1ChainID, @@ -101,6 +102,10 @@ func CombineDeployConfig(intent *Intent, chainIntent *ChainIntent, state *State, }, } + if intent.UseInterop { + cfg.L2InitializationConfig.UpgradeScheduleDeployConfig.L2GenesisInteropTimeOffset = u64UtilPtr(0) + } + if chainState.StartBlock == nil { // These are dummy variables - see below for rationale. num := rpc.LatestBlockNumber @@ -114,6 +119,11 @@ func CombineDeployConfig(intent *Intent, chainIntent *ChainIntent, state *State, } } + if chainIntent.DangerousAltDAConfig.UseAltDA { + cfg.AltDADeployConfig = chainIntent.DangerousAltDAConfig + cfg.L1DependenciesConfig.DAChallengeProxy = chainState.DataAvailabilityChallengeProxyAddress + } + // The below dummy variables are set in order to allow the deploy // config to pass validation. The validation checks are useful to // ensure that the L2 is properly configured. They are not used by @@ -135,7 +145,7 @@ func CombineDeployConfig(intent *Intent, chainIntent *ChainIntent, state *State, // Apply overrides after setting the main values. var err error if len(intent.GlobalDeployOverrides) > 0 { - cfg, err = mergeJSON(cfg, intent.GlobalDeployOverrides) + cfg, err = jsonutil.MergeJSON(cfg, intent.GlobalDeployOverrides) if err != nil { return genesis.DeployConfig{}, fmt.Errorf("error merging global L2 overrides: %w", err) @@ -143,7 +153,7 @@ func CombineDeployConfig(intent *Intent, chainIntent *ChainIntent, state *State, } if len(chainIntent.DeployOverrides) > 0 { - cfg, err = mergeJSON(cfg, chainIntent.DeployOverrides) + cfg, err = jsonutil.MergeJSON(cfg, chainIntent.DeployOverrides) if err != nil { return genesis.DeployConfig{}, fmt.Errorf("error merging chain L2 overrides: %w", err) } @@ -156,40 +166,6 @@ func CombineDeployConfig(intent *Intent, chainIntent *ChainIntent, state *State, return cfg, nil } -// mergeJSON merges the provided overrides into the input struct. Fields -// must be JSON-serializable for this to work. Overrides are applied in -// order of precedence - i.e., the last overrides will override keys from -// all preceding overrides. -func mergeJSON[T any](in T, overrides ...map[string]any) (T, error) { - var out T - inJSON, err := json.Marshal(in) - if err != nil { - return out, err - } - - var tmpMap map[string]interface{} - if err := json.Unmarshal(inJSON, &tmpMap); err != nil { - return out, err - } - - for _, override := range overrides { - for k, v := range override { - tmpMap[k] = v - } - } - - inJSON, err = json.Marshal(tmpMap) - if err != nil { - return out, err - } - - if err := json.Unmarshal(inJSON, &out); err != nil { - return out, err - } - - return out, nil -} - func mustHexBigFromHex(hex string) *hexutil.Big { num := hexutil.MustDecodeBig(hex) hexBig := hexutil.Big(*num) diff --git a/op-deployer/pkg/deployer/state/intent.go b/op-deployer/pkg/deployer/state/intent.go index f43e9ff26caec..860944666e9e5 100644 --- a/op-deployer/pkg/deployer/state/intent.go +++ b/op-deployer/pkg/deployer/state/intent.go @@ -4,7 +4,11 @@ import ( "fmt" "math/big" - "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/opcm" + "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard" "github.com/ethereum-optimism/optimism/op-service/ioutil" "github.com/ethereum-optimism/optimism/op-service/jsonutil" @@ -38,9 +42,11 @@ type Intent struct { FundDevAccounts bool `json:"fundDevAccounts" toml:"fundDevAccounts"` - L1ContractsLocator *opcm.ArtifactsLocator `json:"l1ContractsLocator" toml:"l1ContractsLocator"` + UseInterop bool `json:"useInterop" toml:"useInterop"` + + L1ContractsLocator *artifacts.Locator `json:"l1ContractsLocator" toml:"l1ContractsLocator"` - L2ContractsLocator *opcm.ArtifactsLocator `json:"l2ContractsLocator" toml:"l2ContractsLocator"` + L2ContractsLocator *artifacts.Locator `json:"l2ContractsLocator" toml:"l2ContractsLocator"` Chains []*ChainIntent `json:"chains" toml:"chains"` @@ -61,11 +67,11 @@ func (c *Intent) Check() error { } if c.L1ContractsLocator == nil { - c.L1ContractsLocator = opcm.DefaultL1ContractsLocator + c.L1ContractsLocator = artifacts.DefaultL1ContractsLocator } if c.L2ContractsLocator == nil { - c.L2ContractsLocator = opcm.DefaultL2ContractsLocator + c.L2ContractsLocator = artifacts.DefaultL2ContractsLocator } var err error @@ -102,7 +108,7 @@ func (c *Intent) WriteToFile(path string) error { } func (c *Intent) checkL1Prod() error { - versions, err := opcm.StandardL1VersionsFor(c.L1ChainID) + versions, err := standard.L1VersionsFor(c.L1ChainID) if err != nil { return err } @@ -131,7 +137,7 @@ func (c *Intent) checkL1Dev() error { } func (c *Intent) checkL2Prod() error { - _, err := opcm.StandardArtifactsURLForTag(c.L2ContractsLocator.Tag) + _, err := standard.ArtifactsURLForTag(c.L2ContractsLocator.Tag) return err } @@ -159,6 +165,8 @@ type ChainIntent struct { Roles ChainRoles `json:"roles" toml:"roles"` DeployOverrides map[string]any `json:"deployOverrides" toml:"deployOverrides"` + + DangerousAltDAConfig genesis.AltDADeployConfig `json:"dangerousAltDAConfig,omitempty" toml:"dangerousAltDAConfig,omitempty"` } type ChainRoles struct { @@ -203,5 +211,9 @@ func (c *ChainIntent) Check() error { return fmt.Errorf("batcher must be set") } + if c.DangerousAltDAConfig.UseAltDA { + return c.DangerousAltDAConfig.Check(nil) + } + return nil } diff --git a/op-deployer/pkg/deployer/state/state.go b/op-deployer/pkg/deployer/state/state.go index 3df543c56cdde..e17ed6184c5d3 100644 --- a/op-deployer/pkg/deployer/state/state.go +++ b/op-deployer/pkg/deployer/state/state.go @@ -64,7 +64,7 @@ type SuperchainDeployment struct { } type ImplementationsDeployment struct { - OpcmProxyAddress common.Address `json:"opcmProxyAddress"` + OpcmAddress common.Address `json:"opcmAddress"` DelayedWETHImplAddress common.Address `json:"delayedWETHImplAddress"` OptimismPortalImplAddress common.Address `json:"optimismPortalImplAddress"` PreimageOracleSingletonAddress common.Address `json:"preimageOracleSingletonAddress"` @@ -95,6 +95,8 @@ type ChainState struct { PermissionedDisputeGameAddress common.Address `json:"permissionedDisputeGameAddress"` DelayedWETHPermissionedGameProxyAddress common.Address `json:"delayedWETHPermissionedGameProxyAddress"` DelayedWETHPermissionlessGameProxyAddress common.Address `json:"delayedWETHPermissionlessGameProxyAddress"` + DataAvailabilityChallengeProxyAddress common.Address `json:"dataAvailabilityChallengeProxyAddress"` + DataAvailabilityChallengeImplAddress common.Address `json:"dataAvailabilityChallengeImplAddress"` Allocs *GzipData[foundry.ForgeAllocs] `json:"allocs"` diff --git a/op-deployer/pkg/deployer/testutil/env.go b/op-deployer/pkg/deployer/testutil/env.go new file mode 100644 index 0000000000000..6b289c4503b71 --- /dev/null +++ b/op-deployer/pkg/deployer/testutil/env.go @@ -0,0 +1,37 @@ +package testutil + +import ( + "context" + "fmt" + "net/url" + "path" + "runtime" + "testing" + + artifacts2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" + + "github.com/ethereum-optimism/optimism/op-chain-ops/foundry" + op_service "github.com/ethereum-optimism/optimism/op-service" + "github.com/stretchr/testify/require" +) + +func LocalArtifacts(t *testing.T) (*artifacts2.Locator, foundry.StatDirFs) { + _, testFilename, _, ok := runtime.Caller(0) + require.Truef(t, ok, "failed to get test filename") + monorepoDir, err := op_service.FindMonorepoRoot(testFilename) + require.NoError(t, err) + artifactsDir := path.Join(monorepoDir, "packages", "contracts-bedrock", "forge-artifacts") + artifactsURL, err := url.Parse(fmt.Sprintf("file://%s", artifactsDir)) + require.NoError(t, err) + loc := &artifacts2.Locator{ + URL: artifactsURL, + } + + artifactsFS, cleanupArtifacts, err := artifacts2.Download(context.Background(), loc, artifacts2.NoopDownloadProgressor) + require.NoError(t, err) + t.Cleanup(func() { + _ = cleanupArtifacts() + }) + + return loc, artifactsFS +} diff --git a/op-deployer/pkg/deployer/pipeline/host.go b/op-deployer/pkg/env/host.go similarity index 77% rename from op-deployer/pkg/deployer/pipeline/host.go rename to op-deployer/pkg/env/host.go index df8e6c9c789be..61d30b4ce2534 100644 --- a/op-deployer/pkg/deployer/pipeline/host.go +++ b/op-deployer/pkg/env/host.go @@ -1,4 +1,4 @@ -package pipeline +package env import ( "fmt" @@ -16,7 +16,7 @@ func DefaultScriptHost( lgr log.Logger, deployer common.Address, artifacts foundry.StatDirFs, - startingNonce uint64, + additionalOpts ...script.HostOption, ) (*script.Host, error) { scriptCtx := script.DefaultContext scriptCtx.Sender = deployer @@ -26,16 +26,16 @@ func DefaultScriptHost( &foundry.ArtifactsFS{FS: artifacts}, nil, scriptCtx, - script.WithBroadcastHook(bcaster.Hook), - script.WithIsolatedBroadcasts(), - script.WithCreate2Deployer(), + append([]script.HostOption{ + script.WithBroadcastHook(bcaster.Hook), + script.WithIsolatedBroadcasts(), + script.WithCreate2Deployer(), + }, additionalOpts...)..., ) if err := h.EnableCheats(); err != nil { return nil, fmt.Errorf("failed to enable cheats: %w", err) } - h.SetNonce(deployer, startingNonce) - return h, nil } diff --git a/op-dispute-mon/metrics/metrics.go b/op-dispute-mon/metrics/metrics.go index b76c23c4ca268..aa8cd99479051 100644 --- a/op-dispute-mon/metrics/metrics.go +++ b/op-dispute-mon/metrics/metrics.go @@ -183,6 +183,8 @@ type Metricer interface { RecordL2Challenges(agreement bool, count int) + RecordOldestGameUpdateTime(t time.Time) + caching.Metrics contractMetrics.ContractMetricer } @@ -215,7 +217,8 @@ type Metrics struct { credits prometheus.GaugeVec honestWithdrawableAmounts prometheus.GaugeVec - lastOutputFetch prometheus.Gauge + lastOutputFetch prometheus.Gauge + oldestGameUpdateTime prometheus.Gauge gamesAgreement prometheus.GaugeVec latestValidProposalL2Block prometheus.Gauge @@ -269,6 +272,12 @@ func NewMetrics() *Metrics { Name: "last_output_fetch", Help: "Timestamp of the last output fetch", }), + oldestGameUpdateTime: factory.NewGauge(prometheus.GaugeOpts{ + Namespace: Namespace, + Name: "oldest_game_update_time", + Help: "Timestamp the least recently updated game " + + "or the time of the last update cycle if there were no games in the monitoring window", + }), honestActorClaims: *factory.NewGaugeVec(prometheus.GaugeOpts{ Namespace: Namespace, Name: "honest_actor_claims", @@ -499,6 +508,10 @@ func (m *Metrics) RecordOutputFetchTime(timestamp float64) { m.lastOutputFetch.Set(timestamp) } +func (m *Metrics) RecordOldestGameUpdateTime(t time.Time) { + m.oldestGameUpdateTime.Set(float64(t.Unix())) +} + func (m *Metrics) RecordGameAgreement(status GameAgreementStatus, count int) { m.gamesAgreement.WithLabelValues(labelValuesFor(status)...).Set(float64(count)) } diff --git a/op-dispute-mon/metrics/noop.go b/op-dispute-mon/metrics/noop.go index 6b4982ff26ba3..4459fdd9c1fbb 100644 --- a/op-dispute-mon/metrics/noop.go +++ b/op-dispute-mon/metrics/noop.go @@ -36,6 +36,8 @@ func (*NoopMetricsImpl) RecordWithdrawalRequests(_ common.Address, _ bool, _ int func (*NoopMetricsImpl) RecordOutputFetchTime(_ float64) {} +func (*NoopMetricsImpl) RecordOldestGameUpdateTime(_ time.Time) {} + func (*NoopMetricsImpl) RecordGameAgreement(_ GameAgreementStatus, _ int) {} func (*NoopMetricsImpl) RecordLatestValidProposalL2Block(_ uint64) {} diff --git a/op-dispute-mon/mon/extract/extractor.go b/op-dispute-mon/mon/extract/extractor.go index d19cab340b66b..c40b31ccb6c51 100644 --- a/op-dispute-mon/mon/extract/extractor.go +++ b/op-dispute-mon/mon/extract/extractor.go @@ -9,9 +9,11 @@ import ( gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types" monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types" + "github.com/ethereum-optimism/optimism/op-service/clock" "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" + "golang.org/x/exp/maps" ) var ( @@ -29,20 +31,23 @@ type Enricher interface { type Extractor struct { logger log.Logger + clock clock.Clock createContract CreateGameCaller fetchGames FactoryGameFetcher maxConcurrency int enrichers []Enricher ignoredGames map[common.Address]bool + latestGameData map[common.Address]*monTypes.EnrichedGameData } -func NewExtractor(logger log.Logger, creator CreateGameCaller, fetchGames FactoryGameFetcher, ignoredGames []common.Address, maxConcurrency uint, enrichers ...Enricher) *Extractor { +func NewExtractor(logger log.Logger, cl clock.Clock, creator CreateGameCaller, fetchGames FactoryGameFetcher, ignoredGames []common.Address, maxConcurrency uint, enrichers ...Enricher) *Extractor { ignored := make(map[common.Address]bool) for _, game := range ignoredGames { ignored[game] = true } return &Extractor{ logger: logger, + clock: cl, createContract: creator, fetchGames: fetchGames, maxConcurrency: int(maxConcurrency), @@ -61,7 +66,6 @@ func (e *Extractor) Extract(ctx context.Context, blockHash common.Hash, minTimes } func (e *Extractor) enrichGames(ctx context.Context, blockHash common.Hash, games []gameTypes.GameMetadata) ([]*monTypes.EnrichedGameData, int, int) { - var enrichedGames []*monTypes.EnrichedGameData var ignored atomic.Int32 var failed atomic.Int32 @@ -101,8 +105,14 @@ func (e *Extractor) enrichGames(ctx context.Context, blockHash common.Hash, game }() } - // Push each game into the channel + // Create a new store for game data. This ensures any games no longer in the monitoring set are dropped. + updatedGameData := make(map[common.Address]*monTypes.EnrichedGameData) + // Push each game into the channel and store the latest cached game data as a default if fetching fails for _, game := range games { + previousData := e.latestGameData[game.Proxy] + if previousData != nil { + updatedGameData[game.Proxy] = previousData + } gameCh <- game } close(gameCh) @@ -112,9 +122,10 @@ func (e *Extractor) enrichGames(ctx context.Context, blockHash common.Hash, game // Read the results for enrichedGame := range enrichedCh { - enrichedGames = append(enrichedGames, enrichedGame) + updatedGameData[enrichedGame.Proxy] = enrichedGame } - return enrichedGames, int(ignored.Load()), int(failed.Load()) + e.latestGameData = updatedGameData + return maps.Values(updatedGameData), int(ignored.Load()), int(failed.Load()) } func (e *Extractor) enrichGame(ctx context.Context, blockHash common.Hash, game gameTypes.GameMetadata) (*monTypes.EnrichedGameData, error) { @@ -138,6 +149,7 @@ func (e *Extractor) enrichGame(ctx context.Context, blockHash common.Hash, game enrichedClaims[i] = monTypes.EnrichedClaim{Claim: claim} } enrichedGame := &monTypes.EnrichedGameData{ + LastUpdateTime: e.clock.Now(), GameMetadata: game, L1Head: meta.L1Head, L2BlockNumber: meta.L2BlockNum, diff --git a/op-dispute-mon/mon/extract/extractor_test.go b/op-dispute-mon/mon/extract/extractor_test.go index 361aeb57420e3..cc0605714a04a 100644 --- a/op-dispute-mon/mon/extract/extractor_test.go +++ b/op-dispute-mon/mon/extract/extractor_test.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts" monTypes "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types" + "github.com/ethereum-optimism/optimism/op-service/clock" "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" "github.com/stretchr/testify/require" @@ -26,7 +27,7 @@ var ( func TestExtractor_Extract(t *testing.T) { t.Run("FetchGamesError", func(t *testing.T) { - extractor, _, games, _ := setupExtractorTest(t) + extractor, _, games, _, _ := setupExtractorTest(t) games.err = errors.New("boom") _, _, _, err := extractor.Extract(context.Background(), common.Hash{}, 0) require.ErrorIs(t, err, games.err) @@ -34,7 +35,7 @@ func TestExtractor_Extract(t *testing.T) { }) t.Run("CreateGameErrorLog", func(t *testing.T) { - extractor, creator, games, logs := setupExtractorTest(t) + extractor, creator, games, logs, _ := setupExtractorTest(t) games.games = []gameTypes.GameMetadata{{}} creator.err = errors.New("boom") enriched, ignored, failed, err := extractor.Extract(context.Background(), common.Hash{}, 0) @@ -50,7 +51,7 @@ func TestExtractor_Extract(t *testing.T) { }) t.Run("MetadataFetchErrorLog", func(t *testing.T) { - extractor, creator, games, logs := setupExtractorTest(t) + extractor, creator, games, logs, _ := setupExtractorTest(t) games.games = []gameTypes.GameMetadata{{}} creator.caller.metadataErr = errors.New("boom") enriched, ignored, failed, err := extractor.Extract(context.Background(), common.Hash{}, 0) @@ -66,7 +67,7 @@ func TestExtractor_Extract(t *testing.T) { }) t.Run("ClaimsFetchErrorLog", func(t *testing.T) { - extractor, creator, games, logs := setupExtractorTest(t) + extractor, creator, games, logs, _ := setupExtractorTest(t) games.games = []gameTypes.GameMetadata{{}} creator.caller.claimsErr = errors.New("boom") enriched, ignored, failed, err := extractor.Extract(context.Background(), common.Hash{}, 0) @@ -82,7 +83,7 @@ func TestExtractor_Extract(t *testing.T) { }) t.Run("Success", func(t *testing.T) { - extractor, creator, games, _ := setupExtractorTest(t) + extractor, creator, games, _, _ := setupExtractorTest(t) games.games = []gameTypes.GameMetadata{{}} enriched, ignored, failed, err := extractor.Extract(context.Background(), common.Hash{}, 0) require.NoError(t, err) @@ -97,7 +98,7 @@ func TestExtractor_Extract(t *testing.T) { t.Run("EnricherFails", func(t *testing.T) { enricher := &mockEnricher{err: errors.New("whoops")} - extractor, _, games, logs := setupExtractorTest(t, enricher) + extractor, _, games, logs, _ := setupExtractorTest(t, enricher) games.games = []gameTypes.GameMetadata{{}} enriched, ignored, failed, err := extractor.Extract(context.Background(), common.Hash{}, 0) require.NoError(t, err) @@ -110,7 +111,7 @@ func TestExtractor_Extract(t *testing.T) { t.Run("EnricherSuccess", func(t *testing.T) { enricher := &mockEnricher{} - extractor, _, games, _ := setupExtractorTest(t, enricher) + extractor, _, games, _, _ := setupExtractorTest(t, enricher) games.games = []gameTypes.GameMetadata{{}} enriched, ignored, failed, err := extractor.Extract(context.Background(), common.Hash{}, 0) require.NoError(t, err) @@ -123,8 +124,8 @@ func TestExtractor_Extract(t *testing.T) { t.Run("MultipleEnrichersMultipleGames", func(t *testing.T) { enricher1 := &mockEnricher{} enricher2 := &mockEnricher{} - extractor, _, games, _ := setupExtractorTest(t, enricher1, enricher2) - games.games = []gameTypes.GameMetadata{{}, {}} + extractor, _, games, _, _ := setupExtractorTest(t, enricher1, enricher2) + games.games = []gameTypes.GameMetadata{{Proxy: common.Address{0xaa}}, {Proxy: common.Address{0xbb}}} enriched, ignored, failed, err := extractor.Extract(context.Background(), common.Hash{}, 0) require.NoError(t, err) require.Zero(t, ignored) @@ -136,7 +137,7 @@ func TestExtractor_Extract(t *testing.T) { t.Run("IgnoreGames", func(t *testing.T) { enricher1 := &mockEnricher{} - extractor, _, games, logs := setupExtractorTest(t, enricher1) + extractor, _, games, logs, _ := setupExtractorTest(t, enricher1) // Two games, one of which is ignored games.games = []gameTypes.GameMetadata{{Proxy: ignoredGames[0]}, {Proxy: common.Address{0xaa}}} enriched, ignored, failed, err := extractor.Extract(context.Background(), common.Hash{}, 0) @@ -152,6 +153,61 @@ func TestExtractor_Extract(t *testing.T) { testlog.NewMessageFilter("Ignoring game"), testlog.NewAttributesFilter("game", ignoredGames[0].Hex()))) }) + + t.Run("UseCachedValueOnFailure", func(t *testing.T) { + enricher := &mockEnricher{ + action: func(game *monTypes.EnrichedGameData) error { + game.Status = gameTypes.GameStatusDefenderWon + return nil + }, + } + extractor, _, games, _, cl := setupExtractorTest(t, enricher) + gameA := common.Address{0xaa} + gameB := common.Address{0xbb} + games.games = []gameTypes.GameMetadata{{Proxy: gameA}, {Proxy: gameB}} + + // First fetch succeeds and the results should be cached + enriched, ignored, failed, err := extractor.Extract(context.Background(), common.Hash{}, 0) + require.NoError(t, err) + require.Zero(t, ignored) + require.Zero(t, failed) + require.Len(t, enriched, 2) + require.Equal(t, 2, enricher.calls) + firstUpdateTime := cl.Now() + // All results should have current LastUpdateTime + for _, data := range enriched { + require.Equal(t, firstUpdateTime, data.LastUpdateTime) + } + + cl.AdvanceTime(2 * time.Minute) + secondUpdateTime := cl.Now() + enricher.action = func(game *monTypes.EnrichedGameData) error { + if game.Proxy == gameA { + return errors.New("boom") + } + // Updated games will have a different status + game.Status = gameTypes.GameStatusChallengerWon + return nil + } + // Second fetch fails for one of the two games, it's cached value should be used. + enriched, ignored, failed, err = extractor.Extract(context.Background(), common.Hash{}, 0) + require.NoError(t, err) + require.Zero(t, ignored) + require.Equal(t, 1, failed) + require.Len(t, enriched, 2) + require.Equal(t, 4, enricher.calls) + // The returned games are not in a fixed order, create a map to look up the game we need to assert + actual := make(map[common.Address]*monTypes.EnrichedGameData) + for _, data := range enriched { + actual[data.Proxy] = data + } + require.Contains(t, actual, gameA) + require.Contains(t, actual, gameB) + require.Equal(t, actual[gameA].Status, gameTypes.GameStatusDefenderWon) // Uses cached value from game A + require.Equal(t, actual[gameB].Status, gameTypes.GameStatusChallengerWon) // Updates game B + require.Equal(t, firstUpdateTime, actual[gameA].LastUpdateTime) + require.Equal(t, secondUpdateTime, actual[gameB].LastUpdateTime) + }) } func verifyLogs(t *testing.T, logs *testlog.CapturingHandler, createErr, metadataErr, claimsErr, durationErr int) { @@ -170,20 +226,22 @@ func verifyLogs(t *testing.T, logs *testlog.CapturingHandler, createErr, metadat require.Len(t, l, durationErr) } -func setupExtractorTest(t *testing.T, enrichers ...Enricher) (*Extractor, *mockGameCallerCreator, *mockGameFetcher, *testlog.CapturingHandler) { +func setupExtractorTest(t *testing.T, enrichers ...Enricher) (*Extractor, *mockGameCallerCreator, *mockGameFetcher, *testlog.CapturingHandler, *clock.DeterministicClock) { logger, capturedLogs := testlog.CaptureLogger(t, log.LvlDebug) games := &mockGameFetcher{} caller := &mockGameCaller{rootClaim: mockRootClaim} creator := &mockGameCallerCreator{caller: caller} + cl := clock.NewDeterministicClock(time.Unix(48294294, 58)) extractor := NewExtractor( logger, + cl, creator.CreateGameCaller, games.FetchGames, ignoredGames, 5, enrichers..., ) - return extractor, creator, games, capturedLogs + return extractor, creator, games, capturedLogs, cl } type mockGameFetcher struct { @@ -311,11 +369,15 @@ func (m *mockGameCaller) IsResolved(_ context.Context, _ rpcblock.Block, claims } type mockEnricher struct { - err error - calls int + err error + calls int + action func(game *monTypes.EnrichedGameData) error } -func (m *mockEnricher) Enrich(_ context.Context, _ rpcblock.Block, _ GameCaller, _ *monTypes.EnrichedGameData) error { +func (m *mockEnricher) Enrich(_ context.Context, _ rpcblock.Block, _ GameCaller, game *monTypes.EnrichedGameData) error { m.calls++ + if m.action != nil { + return m.action(game) + } return m.err } diff --git a/op-dispute-mon/mon/monitor.go b/op-dispute-mon/mon/monitor.go index 039255608c73e..5f7764adccbd3 100644 --- a/op-dispute-mon/mon/monitor.go +++ b/op-dispute-mon/mon/monitor.go @@ -14,8 +14,6 @@ import ( ) type ForecastResolution func(games []*types.EnrichedGameData, ignoredCount, failedCount int) -type Bonds func(games []*types.EnrichedGameData) -type Resolutions func(games []*types.EnrichedGameData) type Monitor func(games []*types.EnrichedGameData) type BlockHashFetcher func(ctx context.Context, number *big.Int) (common.Hash, error) type BlockNumberFetcher func(ctx context.Context) (uint64, error) @@ -38,11 +36,7 @@ type gameMonitor struct { monitorInterval time.Duration forecast ForecastResolution - bonds Bonds - resolutions Resolutions - claims Monitor - withdrawals Monitor - l2Challenges Monitor + monitors []Monitor extract Extract fetchBlockHash BlockHashFetcher fetchBlockNumber BlockNumberFetcher @@ -55,16 +49,11 @@ func newGameMonitor( metrics MonitorMetrics, monitorInterval time.Duration, gameWindow time.Duration, - forecast ForecastResolution, - bonds Bonds, - resolutions Resolutions, - claims Monitor, - withdrawals Monitor, - l2Challenges Monitor, - extract Extract, - fetchBlockNumber BlockNumberFetcher, fetchBlockHash BlockHashFetcher, -) *gameMonitor { + fetchBlockNumber BlockNumberFetcher, + extract Extract, + forecast ForecastResolution, + monitors ...Monitor) *gameMonitor { return &gameMonitor{ logger: logger, clock: cl, @@ -74,11 +63,7 @@ func newGameMonitor( monitorInterval: monitorInterval, gameWindow: gameWindow, forecast: forecast, - bonds: bonds, - resolutions: resolutions, - claims: claims, - withdrawals: withdrawals, - l2Challenges: l2Challenges, + monitors: monitors, extract: extract, fetchBlockNumber: fetchBlockNumber, fetchBlockHash: fetchBlockHash, @@ -101,12 +86,10 @@ func (m *gameMonitor) monitorGames() error { if err != nil { return fmt.Errorf("failed to load games: %w", err) } - m.resolutions(enrichedGames) m.forecast(enrichedGames, ignored, failed) - m.bonds(enrichedGames) - m.claims(enrichedGames) - m.withdrawals(enrichedGames) - m.l2Challenges(enrichedGames) + for _, monitor := range m.monitors { + monitor(enrichedGames) + } timeTaken := m.clock.Since(start) m.metrics.RecordMonitorDuration(timeTaken) m.logger.Info("Completed monitoring update", "blockNumber", blockNumber, "blockHash", blockHash, "duration", timeTaken, "games", len(enrichedGames), "ignored", ignored, "failed", failed) diff --git a/op-dispute-mon/mon/monitor_test.go b/op-dispute-mon/mon/monitor_test.go index 180c29bb26ce6..1181c57b4ecb1 100644 --- a/op-dispute-mon/mon/monitor_test.go +++ b/op-dispute-mon/mon/monitor_test.go @@ -25,7 +25,7 @@ func TestMonitor_MonitorGames(t *testing.T) { t.Parallel() t.Run("FailedFetchBlocknumber", func(t *testing.T) { - monitor, _, _, _, _, _, _, _ := setupMonitorTest(t) + monitor, _, _, _ := setupMonitorTest(t) boom := errors.New("boom") monitor.fetchBlockNumber = func(ctx context.Context) (uint64, error) { return 0, boom @@ -35,7 +35,7 @@ func TestMonitor_MonitorGames(t *testing.T) { }) t.Run("FailedFetchBlockHash", func(t *testing.T) { - monitor, _, _, _, _, _, _, _ := setupMonitorTest(t) + monitor, _, _, _ := setupMonitorTest(t) boom := errors.New("boom") monitor.fetchBlockHash = func(ctx context.Context, number *big.Int) (common.Hash, error) { return common.Hash{}, boom @@ -45,29 +45,25 @@ func TestMonitor_MonitorGames(t *testing.T) { }) t.Run("MonitorsWithNoGames", func(t *testing.T) { - monitor, factory, forecast, bonds, withdrawals, resolutions, claims, l2Challenges := setupMonitorTest(t) + monitor, factory, forecast, monitors := setupMonitorTest(t) factory.games = []*monTypes.EnrichedGameData{} err := monitor.monitorGames() require.NoError(t, err) require.Equal(t, 1, forecast.calls) - require.Equal(t, 1, bonds.calls) - require.Equal(t, 1, resolutions.calls) - require.Equal(t, 1, claims.calls) - require.Equal(t, 1, withdrawals.calls) - require.Equal(t, 1, l2Challenges.calls) + for _, m := range monitors { + require.Equal(t, 1, m.calls) + } }) t.Run("MonitorsMultipleGames", func(t *testing.T) { - monitor, factory, forecast, bonds, withdrawals, resolutions, claims, l2Challenges := setupMonitorTest(t) + monitor, factory, forecast, monitors := setupMonitorTest(t) factory.games = []*monTypes.EnrichedGameData{{}, {}, {}} err := monitor.monitorGames() require.NoError(t, err) require.Equal(t, 1, forecast.calls) - require.Equal(t, 1, bonds.calls) - require.Equal(t, 1, resolutions.calls) - require.Equal(t, 1, claims.calls) - require.Equal(t, 1, withdrawals.calls) - require.Equal(t, 1, l2Challenges.calls) + for _, m := range monitors { + require.Equal(t, 1, m.calls) + } }) } @@ -75,7 +71,7 @@ func TestMonitor_StartMonitoring(t *testing.T) { t.Run("MonitorsGames", func(t *testing.T) { addr1 := common.Address{0xaa} addr2 := common.Address{0xbb} - monitor, factory, forecaster, _, _, _, _, _ := setupMonitorTest(t) + monitor, factory, forecaster, _ := setupMonitorTest(t) factory.games = []*monTypes.EnrichedGameData{newEnrichedGameData(addr1, 9999), newEnrichedGameData(addr2, 9999)} factory.maxSuccess = len(factory.games) // Only allow two successful fetches @@ -88,7 +84,7 @@ func TestMonitor_StartMonitoring(t *testing.T) { }) t.Run("FailsToFetchGames", func(t *testing.T) { - monitor, factory, forecaster, _, _, _, _, _ := setupMonitorTest(t) + monitor, factory, forecaster, _ := setupMonitorTest(t) factory.fetchErr = errors.New("boom") monitor.StartMonitoring() @@ -110,7 +106,7 @@ func newEnrichedGameData(proxy common.Address, timestamp uint64) *monTypes.Enric } } -func setupMonitorTest(t *testing.T) (*gameMonitor, *mockExtractor, *mockForecast, *mockBonds, *mockMonitor, *mockResolutionMonitor, *mockMonitor, *mockMonitor) { +func setupMonitorTest(t *testing.T) (*gameMonitor, *mockExtractor, *mockForecast, []*mockMonitor) { logger := testlog.Logger(t, log.LvlDebug) fetchBlockNum := func(ctx context.Context) (uint64, error) { return 1, nil @@ -123,37 +119,12 @@ func setupMonitorTest(t *testing.T) (*gameMonitor, *mockExtractor, *mockForecast cl.Start() extractor := &mockExtractor{} forecast := &mockForecast{} - bonds := &mockBonds{} - resolutions := &mockResolutionMonitor{} - claims := &mockMonitor{} - withdrawals := &mockMonitor{} - l2Challenges := &mockMonitor{} - monitor := newGameMonitor( - context.Background(), - logger, - cl, - metrics.NoopMetrics, - monitorInterval, - 10*time.Second, - forecast.Forecast, - bonds.CheckBonds, - resolutions.CheckResolutions, - claims.Check, - withdrawals.Check, - l2Challenges.Check, - extractor.Extract, - fetchBlockNum, - fetchBlockHash, - ) - return monitor, extractor, forecast, bonds, withdrawals, resolutions, claims, l2Challenges -} - -type mockResolutionMonitor struct { - calls int -} - -func (m *mockResolutionMonitor) CheckResolutions(games []*monTypes.EnrichedGameData) { - m.calls++ + monitor1 := &mockMonitor{} + monitor2 := &mockMonitor{} + monitor3 := &mockMonitor{} + monitor := newGameMonitor(context.Background(), logger, cl, metrics.NoopMetrics, monitorInterval, 10*time.Second, fetchBlockHash, fetchBlockNum, + extractor.Extract, forecast.Forecast, monitor1.Check, monitor2.Check, monitor3.Check) + return monitor, extractor, forecast, []*mockMonitor{monitor1, monitor2, monitor3} } type mockMonitor struct { @@ -172,14 +143,6 @@ func (m *mockForecast) Forecast(_ []*monTypes.EnrichedGameData, _, _ int) { m.calls++ } -type mockBonds struct { - calls int -} - -func (m *mockBonds) CheckBonds(_ []*monTypes.EnrichedGameData) { - m.calls++ -} - type mockExtractor struct { fetchErr error calls int diff --git a/op-dispute-mon/mon/service.go b/op-dispute-mon/mon/service.go index 8ce97b7b8dd92..083e391b91119 100644 --- a/op-dispute-mon/mon/service.go +++ b/op-dispute-mon/mon/service.go @@ -126,6 +126,7 @@ func (s *Service) initGameCallerCreator() { func (s *Service) initExtractor(cfg *config.Config) { s.extractor = extract.NewExtractor( s.logger, + s.cl, s.game.CreateContract, s.factoryContract.GetGamesAtOrAfter, cfg.IgnoredGames, @@ -217,23 +218,17 @@ func (s *Service) initMonitor(ctx context.Context, cfg *config.Config) { return block.Hash(), nil } l2ChallengesMonitor := NewL2ChallengesMonitor(s.logger, s.metrics) - s.monitor = newGameMonitor( - ctx, - s.logger, - s.cl, - s.metrics, - cfg.MonitorInterval, - cfg.GameWindow, + updateTimeMonitor := NewUpdateTimeMonitor(s.cl, s.metrics) + s.monitor = newGameMonitor(ctx, s.logger, s.cl, s.metrics, cfg.MonitorInterval, cfg.GameWindow, blockHashFetcher, + s.l1Client.BlockNumber, + s.extractor.Extract, s.forecast.Forecast, s.bonds.CheckBonds, s.resolutions.CheckResolutions, s.claims.CheckClaims, s.withdrawals.CheckWithdrawals, l2ChallengesMonitor.CheckL2Challenges, - s.extractor.Extract, - s.l1Client.BlockNumber, - blockHashFetcher, - ) + updateTimeMonitor.CheckUpdateTimes) } func (s *Service) Start(ctx context.Context) error { diff --git a/op-dispute-mon/mon/types/types.go b/op-dispute-mon/mon/types/types.go index dff06dab90bf9..774ad3908cf7c 100644 --- a/op-dispute-mon/mon/types/types.go +++ b/op-dispute-mon/mon/types/types.go @@ -18,6 +18,7 @@ type EnrichedClaim struct { type EnrichedGameData struct { types.GameMetadata + LastUpdateTime time.Time L1Head common.Hash L1HeadNum uint64 L2BlockNumber uint64 diff --git a/op-dispute-mon/mon/update_times.go b/op-dispute-mon/mon/update_times.go new file mode 100644 index 0000000000000..3482775757b06 --- /dev/null +++ b/op-dispute-mon/mon/update_times.go @@ -0,0 +1,34 @@ +package mon + +import ( + "time" + + "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types" + "github.com/ethereum-optimism/optimism/op-service/clock" +) + +type UpdateTimeMetrics interface { + RecordOldestGameUpdateTime(t time.Time) +} + +type UpdateTimeMonitor struct { + metrics UpdateTimeMetrics + clock clock.Clock +} + +func NewUpdateTimeMonitor(cl clock.Clock, metrics UpdateTimeMetrics) *UpdateTimeMonitor { + return &UpdateTimeMonitor{clock: cl, metrics: metrics} +} + +func (m *UpdateTimeMonitor) CheckUpdateTimes(games []*types.EnrichedGameData) { + // Report the current time if there are no games + // Otherwise the last update time would drop to 0 when there are no games, making it appear there were errors + earliest := m.clock.Now() + + for _, game := range games { + if game.LastUpdateTime.Before(earliest) { + earliest = game.LastUpdateTime + } + } + m.metrics.RecordOldestGameUpdateTime(earliest) +} diff --git a/op-dispute-mon/mon/update_times_test.go b/op-dispute-mon/mon/update_times_test.go new file mode 100644 index 0000000000000..a16da62b3c2e0 --- /dev/null +++ b/op-dispute-mon/mon/update_times_test.go @@ -0,0 +1,43 @@ +package mon + +import ( + "testing" + "time" + + "github.com/ethereum-optimism/optimism/op-dispute-mon/mon/types" + "github.com/ethereum-optimism/optimism/op-service/clock" + "github.com/stretchr/testify/require" +) + +func TestUpdateTimeMonitor_NoGames(t *testing.T) { + m := &mockUpdateTimeMetrics{} + cl := clock.NewDeterministicClock(time.UnixMilli(45892)) + monitor := NewUpdateTimeMonitor(cl, m) + monitor.CheckUpdateTimes(nil) + require.Equal(t, cl.Now(), m.oldestUpdateTime) + + cl.AdvanceTime(time.Minute) + monitor.CheckUpdateTimes([]*types.EnrichedGameData{}) + require.Equal(t, cl.Now(), m.oldestUpdateTime) +} + +func TestUpdateTimeMonitor_ReportsOldestUpdateTime(t *testing.T) { + m := &mockUpdateTimeMetrics{} + cl := clock.NewDeterministicClock(time.UnixMilli(45892)) + monitor := NewUpdateTimeMonitor(cl, m) + monitor.CheckUpdateTimes([]*types.EnrichedGameData{ + {LastUpdateTime: time.UnixMilli(4)}, + {LastUpdateTime: time.UnixMilli(3)}, + {LastUpdateTime: time.UnixMilli(7)}, + {LastUpdateTime: time.UnixMilli(9)}, + }) + require.Equal(t, time.UnixMilli(3), m.oldestUpdateTime) +} + +type mockUpdateTimeMetrics struct { + oldestUpdateTime time.Time +} + +func (m *mockUpdateTimeMetrics) RecordOldestGameUpdateTime(t time.Time) { + m.oldestUpdateTime = t +} diff --git a/op-e2e/Makefile b/op-e2e/Makefile index 7ddbb42528bd2..4c808ac45c04f 100644 --- a/op-e2e/Makefile +++ b/op-e2e/Makefile @@ -69,6 +69,8 @@ clean: .PHONY: clean fuzz: - go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFjordCostFunction ./opgeth - go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFastLzGethSolidity ./opgeth - go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFastLzCgo ./opgeth + printf "%s\n" \ + "go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFjordCostFunction ./opgeth" \ + "go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFastLzGethSolidity ./opgeth" \ + "go test -run NOTAREALTEST -tags cgo_test -v -fuzztime 10s -fuzz FuzzFastLzCgo ./opgeth" \ + | parallel -j 8 {} diff --git a/op-e2e/actions/altda/altda_test.go b/op-e2e/actions/altda/altda_test.go index 21dcbf6b9038e..3c7e06a380fcf 100644 --- a/op-e2e/actions/altda/altda_test.go +++ b/op-e2e/actions/altda/altda_test.go @@ -72,7 +72,7 @@ func NewL2AltDA(t helpers.Testing, params ...AltDAParam) *L2AltDA { l1Client := miner.EthClient() jwtPath := e2eutils.WriteDefaultJWT(t) - engine := helpers.NewL2Engine(t, log, sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath) + engine := helpers.NewL2Engine(t, log, sd.L2Cfg, jwtPath) engCl := engine.EngineClient(t, sd.RollupCfg) storage := &altda.DAErrFaker{Client: altda.NewMockDAClient(log)} @@ -136,7 +136,7 @@ func (a *L2AltDA) StorageClient() *altda.DAErrFaker { func (a *L2AltDA) NewVerifier(t helpers.Testing) *helpers.L2Verifier { jwtPath := e2eutils.WriteDefaultJWT(t) - engine := helpers.NewL2Engine(t, a.log, a.sd.L2Cfg, a.sd.RollupCfg.Genesis.L1, jwtPath) + engine := helpers.NewL2Engine(t, a.log, a.sd.L2Cfg, jwtPath) engCl := engine.EngineClient(t, a.sd.RollupCfg) l1F, err := sources.NewL1Client(a.miner.RPCClient(), a.log, nil, sources.L1ClientDefaultConfig(a.sd.RollupCfg, false, sources.RPCKindBasic)) require.NoError(t, err) diff --git a/op-e2e/actions/derivation/blocktime_test.go b/op-e2e/actions/derivation/blocktime_test.go index 1855013aad6da..bd5594864af55 100644 --- a/op-e2e/actions/derivation/blocktime_test.go +++ b/op-e2e/actions/derivation/blocktime_test.go @@ -7,6 +7,7 @@ import ( actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" upgradesHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/upgrades/helpers" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" + "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" @@ -163,11 +164,13 @@ func LargeL1Gaps(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { dp.DeployConfig.L2BlockTime = 2 dp.DeployConfig.SequencerWindowSize = 4 dp.DeployConfig.MaxSequencerDrift = 32 - dp.DeployConfig.L2GenesisEcotoneTimeOffset = nil - dp.DeployConfig.L2GenesisFjordTimeOffset = nil + if deltaTimeOffset != nil { + dp.DeployConfig.ActivateForkAtOffset(rollup.Delta, uint64(*deltaTimeOffset)) + } else { + dp.DeployConfig.ActivateForkAtGenesis(rollup.Canyon) + } // TODO(client-pod#831): The Ecotone (and Fjord) activation blocks don't include user txs, // so disabling these forks for now. - upgradesHelpers.ApplyDeltaTimeOffset(dp, deltaTimeOffset) sd := e2eutils.Setup(t, dp, actionsHelpers.DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) diff --git a/op-e2e/actions/derivation/reorg_test.go b/op-e2e/actions/derivation/reorg_test.go index 10155a471a6f2..09135151d3b20 100644 --- a/op-e2e/actions/derivation/reorg_test.go +++ b/op-e2e/actions/derivation/reorg_test.go @@ -592,7 +592,7 @@ func RestartOpGeth(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { l1F, err := sources.NewL1Client(miner.RPCClient(), log, nil, sources.L1ClientDefaultConfig(sd.RollupCfg, false, sources.RPCKindStandard)) require.NoError(t, err) // Sequencer - seqEng := actionsHelpers.NewL2Engine(t, log, sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath, dbOption) + seqEng := actionsHelpers.NewL2Engine(t, log, sd.L2Cfg, jwtPath, dbOption) engRpc := &rpcWrapper{seqEng.RPCClient()} l2Cl, err := sources.NewEngineClient(engRpc, log, nil, sources.EngineClientDefaultConfig(sd.RollupCfg)) require.NoError(t, err) @@ -647,7 +647,7 @@ func RestartOpGeth(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { // close the sequencer engine require.NoError(t, seqEng.Close()) // and start a new one with same db path - seqEngNew := actionsHelpers.NewL2Engine(t, log, sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath, dbOption) + seqEngNew := actionsHelpers.NewL2Engine(t, log, sd.L2Cfg, jwtPath, dbOption) // swap in the new rpc. This is as close as we can get to reconnecting to a new in-memory rpc connection engRpc.RPC = seqEngNew.RPCClient() @@ -679,7 +679,7 @@ func ConflictingL2Blocks(gt *testing.T, deltaTimeOffset *hexutil.Uint64) { // Extra setup: a full alternative sequencer, sequencer engine, and batcher jwtPath := e2eutils.WriteDefaultJWT(t) - altSeqEng := actionsHelpers.NewL2Engine(t, log, sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath) + altSeqEng := actionsHelpers.NewL2Engine(t, log, sd.L2Cfg, jwtPath) altSeqEngCl, err := sources.NewEngineClient(altSeqEng.RPCClient(), log, nil, sources.EngineClientDefaultConfig(sd.RollupCfg)) require.NoError(t, err) l1F, err := sources.NewL1Client(miner.RPCClient(), log, nil, sources.L1ClientDefaultConfig(sd.RollupCfg, false, sources.RPCKindStandard)) diff --git a/op-e2e/actions/helpers/env.go b/op-e2e/actions/helpers/env.go new file mode 100644 index 0000000000000..77911aa80bf5c --- /dev/null +++ b/op-e2e/actions/helpers/env.go @@ -0,0 +1,118 @@ +package helpers + +import ( + "math/rand" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" + + "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + 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-node/rollup/sync" + "github.com/ethereum-optimism/optimism/op-service/testlog" +) + +type Env struct { + Log log.Logger + Logs *testlog.CapturingHandler + + DeployParams *e2eutils.DeployParams + SetupData *e2eutils.SetupData + + Miner *L1Miner + Seq *L2Sequencer + SeqEngine *L2Engine + Verifier *L2Verifier + VerifEngine *L2Engine + Batcher *L2Batcher + Alice *CrossLayerUser + + AddressCorpora []common.Address +} + +type EnvOpt struct { + DeployConfigMod func(*genesis.DeployConfig) +} + +func WithActiveFork(fork rollup.ForkName, offset uint64) EnvOpt { + return EnvOpt{ + DeployConfigMod: func(d *genesis.DeployConfig) { + d.ActivateForkAtOffset(fork, offset) + }, + } +} + +func WithActiveGenesisFork(fork rollup.ForkName) EnvOpt { + return WithActiveFork(fork, 0) +} + +// DefaultFork specifies the default fork to use when setting up the action test environment. +// Currently manually set to Holocene. +// Replace with `var DefaultFork = func() rollup.ForkName { return rollup.AllForks[len(rollup.AllForks)-1] }()` after Interop launch. +const DefaultFork = rollup.Holocene + +// SetupEnv sets up a default action test environment. If no fork is specified, the default fork as +// specified by the package variable [defaultFork] is used. +func SetupEnv(t Testing, opts ...EnvOpt) (env Env) { + dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams()) + env.DeployParams = dp + + log, logs := testlog.CaptureLogger(t, log.LevelDebug) + env.Log, env.Logs = log, logs + + dp.DeployConfig.ActivateForkAtGenesis(DefaultFork) + for _, opt := range opts { + if dcMod := opt.DeployConfigMod; dcMod != nil { + dcMod(dp.DeployConfig) + } + } + + sd := e2eutils.Setup(t, dp, DefaultAlloc) + env.SetupData = sd + env.AddressCorpora = e2eutils.CollectAddresses(sd, dp) + + env.Miner, env.SeqEngine, env.Seq = SetupSequencerTest(t, sd, log) + env.Miner.ActL1SetFeeRecipient(common.Address{'A'}) + env.VerifEngine, env.Verifier = SetupVerifier(t, sd, log, env.Miner.L1Client(t, sd.RollupCfg), env.Miner.BlobStore(), &sync.Config{}) + rollupSeqCl := env.Seq.RollupClient() + env.Batcher = NewL2Batcher(log, sd.RollupCfg, DefaultBatcherCfg(dp), + rollupSeqCl, env.Miner.EthClient(), env.SeqEngine.EthClient(), env.SeqEngine.EngineClient(t, sd.RollupCfg)) + + alice := NewCrossLayerUser(log, dp.Secrets.Alice, rand.New(rand.NewSource(0xa57b)), e2ecfg.AllocTypeStandard) + alice.L1.SetUserEnv(env.L1UserEnv(t)) + alice.L2.SetUserEnv(env.L2UserEnv(t)) + env.Alice = alice + + return +} + +func (env Env) L1UserEnv(t Testing) *BasicUserEnv[*L1Bindings] { + l1EthCl := env.Miner.EthClient() + return &BasicUserEnv[*L1Bindings]{ + EthCl: l1EthCl, + Signer: types.LatestSigner(env.SetupData.L1Cfg.Config), + AddressCorpora: env.AddressCorpora, + Bindings: NewL1Bindings(t, l1EthCl, e2ecfg.AllocTypeStandard), + } +} + +func (env Env) L2UserEnv(t Testing) *BasicUserEnv[*L2Bindings] { + l2EthCl := env.SeqEngine.EthClient() + return &BasicUserEnv[*L2Bindings]{ + EthCl: l2EthCl, + Signer: types.LatestSigner(env.SetupData.L2Cfg.Config), + AddressCorpora: env.AddressCorpora, + Bindings: NewL2Bindings(t, l2EthCl, env.SeqEngine.GethClient()), + } +} + +func (env Env) ActBatchSubmitAllAndMine(t Testing) (l1InclusionBlock *types.Block) { + env.Batcher.ActSubmitAll(t) + batchTx := env.Batcher.LastSubmitted + env.Miner.ActL1StartBlock(12)(t) + env.Miner.ActL1IncludeTxByHash(batchTx.Hash())(t) + return env.Miner.ActL1EndBlock(t) +} diff --git a/op-e2e/actions/helpers/l1_miner.go b/op-e2e/actions/helpers/l1_miner.go index bf1bb415fe4ff..108c11d3e1667 100644 --- a/op-e2e/actions/helpers/l1_miner.go +++ b/op-e2e/actions/helpers/l1_miner.go @@ -203,10 +203,10 @@ func (s *L1Miner) ActL1SetFeeRecipient(coinbase common.Address) { } // ActL1EndBlock finishes the new L1 block, and applies it to the chain as unsafe block -func (s *L1Miner) ActL1EndBlock(t Testing) { +func (s *L1Miner) ActL1EndBlock(t Testing) *types.Block { if !s.l1Building { t.InvalidAction("cannot end L1 block when not building block") - return + return nil } s.l1Building = false @@ -253,11 +253,12 @@ func (s *L1Miner) ActL1EndBlock(t Testing) { if err != nil { t.Fatalf("failed to insert block into l1 chain") } + return block } -func (s *L1Miner) ActEmptyBlock(t Testing) { +func (s *L1Miner) ActEmptyBlock(t Testing) *types.Block { s.ActL1StartBlock(12)(t) - s.ActL1EndBlock(t) + return s.ActL1EndBlock(t) } func (s *L1Miner) Close() error { diff --git a/op-e2e/actions/helpers/l2_batcher.go b/op-e2e/actions/helpers/l2_batcher.go index a106c56876635..9fc9971a26e26 100644 --- a/op-e2e/actions/helpers/l2_batcher.go +++ b/op-e2e/actions/helpers/l2_batcher.go @@ -146,11 +146,52 @@ func (s *L2Batcher) Reset() { // ActL2BatchBuffer adds the next L2 block to the batch buffer. // If the buffer is being submitted, the buffer is wiped. -func (s *L2Batcher) ActL2BatchBuffer(t Testing) { - require.NoError(t, s.Buffer(t), "failed to add block to channel") +func (s *L2Batcher) ActL2BatchBuffer(t Testing, opts ...BlockModifier) { + require.NoError(t, s.Buffer(t, opts...), "failed to add block to channel") } -type BlockModifier = func(block *types.Block) +// ActCreateChannel creates a channel if we don't have one yet. +func (s *L2Batcher) ActCreateChannel(t Testing, useSpanChannelOut bool) { + var err error + if s.L2ChannelOut == nil { + var ch ChannelOutIface + if s.l2BatcherCfg.GarbageCfg != nil { + ch, err = NewGarbageChannelOut(s.l2BatcherCfg.GarbageCfg) + } else { + target := batcher.MaxDataSize(1, s.l2BatcherCfg.MaxL1TxSize) + c, e := compressor.NewShadowCompressor(compressor.Config{ + TargetOutputSize: target, + CompressionAlgo: derive.Zlib, + }) + require.NoError(t, e, "failed to create compressor") + + if s.l2BatcherCfg.ForceSubmitSingularBatch && s.l2BatcherCfg.ForceSubmitSpanBatch { + t.Fatalf("ForceSubmitSingularBatch and ForceSubmitSpanBatch cannot be set to true at the same time") + } else { + chainSpec := rollup.NewChainSpec(s.rollupCfg) + // use span batch if we're forcing it or if we're at/beyond delta + if s.l2BatcherCfg.ForceSubmitSpanBatch || useSpanChannelOut { + ch, err = derive.NewSpanChannelOut(target, derive.Zlib, chainSpec) + // use singular batches in all other cases + } else { + ch, err = derive.NewSingularChannelOut(c, chainSpec) + } + } + } + require.NoError(t, err, "failed to create channel") + s.L2ChannelOut = ch + } +} + +type BlockModifier = func(block *types.Block) *types.Block + +func BlockLogger(t e2eutils.TestingBase) BlockModifier { + f := func(block *types.Block) *types.Block { + t.Log("added block", "num", block.Number(), "txs", block.Transactions(), "time", block.Time()) + return block + } + return f +} func (s *L2Batcher) Buffer(t Testing, opts ...BlockModifier) error { if s.l2Submitting { // break ongoing submitting work if necessary @@ -197,38 +238,13 @@ func (s *L2Batcher) Buffer(t Testing, opts ...BlockModifier) error { // Apply modifications to the block for _, f := range opts { - f(block) + if f != nil { + block = f(block) + } } - // Create channel if we don't have one yet - if s.L2ChannelOut == nil { - var ch ChannelOutIface - if s.l2BatcherCfg.GarbageCfg != nil { - ch, err = NewGarbageChannelOut(s.l2BatcherCfg.GarbageCfg) - } else { - target := batcher.MaxDataSize(1, s.l2BatcherCfg.MaxL1TxSize) - c, e := compressor.NewShadowCompressor(compressor.Config{ - TargetOutputSize: target, - CompressionAlgo: derive.Zlib, - }) - require.NoError(t, e, "failed to create compressor") + s.ActCreateChannel(t, s.rollupCfg.IsDelta(block.Time())) - if s.l2BatcherCfg.ForceSubmitSingularBatch && s.l2BatcherCfg.ForceSubmitSpanBatch { - t.Fatalf("ForceSubmitSingularBatch and ForceSubmitSpanBatch cannot be set to true at the same time") - } else { - chainSpec := rollup.NewChainSpec(s.rollupCfg) - // use span batch if we're forcing it or if we're at/beyond delta - if s.l2BatcherCfg.ForceSubmitSpanBatch || s.rollupCfg.IsDelta(block.Time()) { - ch, err = derive.NewSpanChannelOut(target, derive.Zlib, chainSpec) - // use singular batches in all other cases - } else { - ch, err = derive.NewSingularChannelOut(c, chainSpec) - } - } - } - require.NoError(t, err, "failed to create channel") - s.L2ChannelOut = ch - } if _, err := s.L2ChannelOut.AddBlock(s.rollupCfg, block); err != nil { return err } @@ -238,6 +254,30 @@ func (s *L2Batcher) Buffer(t Testing, opts ...BlockModifier) error { return nil } +// ActAddBlockByNumber causes the batcher to pull the block with the provided +// number, and add it to its ChannelOut. +func (s *L2Batcher) ActAddBlockByNumber(t Testing, blockNumber int64, opts ...BlockModifier) { + block, err := s.l2.BlockByNumber(t.Ctx(), big.NewInt(blockNumber)) + require.NoError(t, err) + require.NotNil(t, block) + + // cache block hash before we modify the block + blockHash := block.Hash() + + // Apply modifications to the block + for _, f := range opts { + if f != nil { + block = f(block) + } + } + + _, err = s.L2ChannelOut.AddBlock(s.rollupCfg, block) + require.NoError(t, err) + ref, err := s.engCl.L2BlockRefByHash(t.Ctx(), blockHash) + require.NoError(t, err, "failed to get L2BlockRef") + s.L2BufferedBlock = ref +} + func (s *L2Batcher) ActL2ChannelClose(t Testing) { // Don't run this action if there's no data to submit if s.L2ChannelOut == nil { diff --git a/op-e2e/actions/helpers/l2_engine.go b/op-e2e/actions/helpers/l2_engine.go index 5839a20798d31..8d2f318a08dc9 100644 --- a/op-e2e/actions/helpers/l2_engine.go +++ b/op-e2e/actions/helpers/l2_engine.go @@ -24,7 +24,6 @@ import ( "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/client" - "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum-optimism/optimism/op-service/testutils" ) @@ -37,8 +36,6 @@ type L2Engine struct { node *node.Node Eth *geth.Ethereum - rollupGenesis *rollup.Genesis - // L2 evm / chain l2Chain *core.BlockChain l2Signer types.Signer @@ -50,20 +47,14 @@ type L2Engine struct { type EngineOption func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error -func NewL2Engine(t Testing, log log.Logger, genesis *core.Genesis, rollupGenesisL1 eth.BlockID, jwtPath string, options ...EngineOption) *L2Engine { +func NewL2Engine(t Testing, log log.Logger, genesis *core.Genesis, jwtPath string, options ...EngineOption) *L2Engine { n, ethBackend, apiBackend := newBackend(t, genesis, jwtPath, options) engineApi := engineapi.NewL2EngineAPI(log, apiBackend, ethBackend.Downloader()) chain := ethBackend.BlockChain() - genesisBlock := chain.Genesis() eng := &L2Engine{ - log: log, - node: n, - Eth: ethBackend, - rollupGenesis: &rollup.Genesis{ - L1: rollupGenesisL1, - L2: eth.BlockID{Hash: genesisBlock.Hash(), Number: genesisBlock.NumberU64()}, - L2Time: genesis.Timestamp, - }, + log: log, + node: n, + Eth: ethBackend, l2Chain: chain, l2Signer: types.LatestSigner(genesis.Config), EngineApi: engineApi, @@ -200,9 +191,30 @@ func (e *L2Engine) ActL2RPCFail(t Testing, err error) { } } +// ActL2IncludeTx includes the next transaction from the given address in the block that is being built, +// skipping the usual check for e.EngineApi.ForcedEmpty() +func (e *L2Engine) ActL2IncludeTxIgnoreForcedEmpty(from common.Address) Action { + return func(t Testing) { + if e.EngineApi.ForcedEmpty() { + e.log.Info("Ignoring e.L2ForceEmpty=true") + } + + tx := firstValidTx(t, from, e.EngineApi.PendingIndices, e.Eth.TxPool().ContentFrom, e.EthClient().NonceAt) + err := e.EngineApi.IncludeTx(tx, from) + if errors.Is(err, engineapi.ErrNotBuildingBlock) { + t.InvalidAction(err.Error()) + } else if errors.Is(err, engineapi.ErrUsesTooMuchGas) { + t.InvalidAction("included tx uses too much gas: %v", err) + } else if err != nil { + require.NoError(t, err, "include tx") + } + } +} + // ActL2IncludeTx includes the next transaction from the given address in the block that is being built func (e *L2Engine) ActL2IncludeTx(from common.Address) Action { return func(t Testing) { + if e.EngineApi.ForcedEmpty() { e.log.Info("Skipping including a transaction because e.L2ForceEmpty is true") return diff --git a/op-e2e/actions/helpers/l2_engine_test.go b/op-e2e/actions/helpers/l2_engine_test.go index b859b393b6217..115921bea94bd 100644 --- a/op-e2e/actions/helpers/l2_engine_test.go +++ b/op-e2e/actions/helpers/l2_engine_test.go @@ -40,7 +40,7 @@ func TestL2EngineAPI(gt *testing.T) { tdb := triedb.NewDatabase(db, &triedb.Config{HashDB: hashdb.Defaults}) sd.L2Cfg.MustCommit(db, tdb) - engine := NewL2Engine(t, log, sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath) + engine := NewL2Engine(t, log, sd.L2Cfg, jwtPath) l2Cl, err := sources.NewEngineClient(engine.RPCClient(), log, nil, sources.EngineClientDefaultConfig(sd.RollupCfg)) require.NoError(t, err) @@ -115,7 +115,7 @@ func TestL2EngineAPIBlockBuilding(gt *testing.T) { tdb := triedb.NewDatabase(db, &triedb.Config{HashDB: hashdb.Defaults}) sd.L2Cfg.MustCommit(db, tdb) - engine := NewL2Engine(t, log, sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath) + engine := NewL2Engine(t, log, sd.L2Cfg, jwtPath) t.Cleanup(func() { _ = engine.Close() }) @@ -211,7 +211,7 @@ func TestL2EngineAPIFail(gt *testing.T) { dp := e2eutils.MakeDeployParams(t, DefaultRollupTestParams()) sd := e2eutils.Setup(t, dp, DefaultAlloc) log := testlog.Logger(t, log.LevelDebug) - engine := NewL2Engine(t, log, sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath) + engine := NewL2Engine(t, log, sd.L2Cfg, jwtPath) // mock an RPC failure mockErr := errors.New("mock L2 RPC error") engine.ActL2RPCFail(t, mockErr) diff --git a/op-e2e/actions/helpers/l2_sequencer.go b/op-e2e/actions/helpers/l2_sequencer.go index 1950c0ed03ac4..1b8699db856db 100644 --- a/op-e2e/actions/helpers/l2_sequencer.go +++ b/op-e2e/actions/helpers/l2_sequencer.go @@ -43,7 +43,8 @@ func (m *MockL1OriginSelector) FindL1Origin(ctx context.Context, l2Head eth.L2Bl type L2Sequencer struct { *L2Verifier - sequencer *sequencing.Sequencer + sequencer *sequencing.Sequencer + attrBuilder *derive.FetchingAttributesBuilder failL2GossipUnsafeBlock error // mock error @@ -52,7 +53,8 @@ type L2Sequencer struct { func NewL2Sequencer(t Testing, log log.Logger, l1 derive.L1Fetcher, blobSrc derive.L1BlobsFetcher, altDASrc driver.AltDAIface, eng L2API, cfg *rollup.Config, seqConfDepth uint64, - interopBackend interop.InteropBackend) *L2Sequencer { + interopBackend interop.InteropBackend, +) *L2Sequencer { ver := NewL2Verifier(t, log, l1, blobSrc, altDASrc, eng, cfg, &sync.Config{}, safedb.Disabled, interopBackend) attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, eng) seqConfDepthL1 := confdepth.NewConfDepth(seqConfDepth, ver.syncStatus.L1Head, l1) @@ -84,6 +86,7 @@ func NewL2Sequencer(t Testing, log log.Logger, l1 derive.L1Fetcher, blobSrc deri return &L2Sequencer{ L2Verifier: ver, sequencer: seq, + attrBuilder: attrBuilder, mockL1OriginSelector: l1OriginSelector, failL2GossipUnsafeBlock: nil, } @@ -130,21 +133,36 @@ func (s *L2Sequencer) ActL2EndBlock(t Testing) { "sync status must be accurate after block building") } +func (s *L2Sequencer) ActL2EmptyBlock(t Testing) { + s.ActL2StartBlock(t) + s.ActL2EndBlock(t) +} + // ActL2KeepL1Origin makes the sequencer use the current L1 origin, even if the next origin is available. func (s *L2Sequencer) ActL2KeepL1Origin(t Testing) { parent := s.engine.UnsafeL2Head() - // force old origin, for testing purposes + // force old origin oldOrigin, err := s.l1.L1BlockRefByHash(t.Ctx(), parent.L1Origin.Hash) require.NoError(t, err, "failed to get current origin: %s", parent.L1Origin) s.mockL1OriginSelector.originOverride = oldOrigin } +// ActL2ForceAdvanceL1Origin forces the sequencer to advance the current L1 origin, even if the next origin's timestamp is too new. +func (s *L2Sequencer) ActL2ForceAdvanceL1Origin(t Testing) { + s.attrBuilder.TestSkipL1OriginCheck() // skip check in attributes builder + parent := s.engine.UnsafeL2Head() + // force next origin + nextNum := parent.L1Origin.Number + 1 + nextOrigin, err := s.l1.L1BlockRefByNumber(t.Ctx(), nextNum) + require.NoError(t, err, "failed to get next origin by number: %d", nextNum) + s.mockL1OriginSelector.originOverride = nextOrigin +} + // ActBuildToL1Head builds empty blocks until (incl.) the L1 head becomes the L2 origin func (s *L2Sequencer) ActBuildToL1Head(t Testing) { for s.engine.UnsafeL2Head().L1Origin.Number < s.syncStatus.L1Head().Number { s.ActL2PipelineFull(t) - s.ActL2StartBlock(t) - s.ActL2EndBlock(t) + s.ActL2EmptyBlock(t) } } @@ -152,8 +170,7 @@ func (s *L2Sequencer) ActBuildToL1Head(t Testing) { func (s *L2Sequencer) ActBuildToL1HeadUnsafe(t Testing) { for s.engine.UnsafeL2Head().L1Origin.Number < s.syncStatus.L1Head().Number { // Note: the derivation pipeline does not run, we are just sequencing a block on top of the existing L2 chain. - s.ActL2StartBlock(t) - s.ActL2EndBlock(t) + s.ActL2EmptyBlock(t) } } @@ -166,8 +183,7 @@ func (s *L2Sequencer) ActBuildToL1HeadExcl(t Testing) { if nextOrigin.Number >= s.syncStatus.L1Head().Number { break } - s.ActL2StartBlock(t) - s.ActL2EndBlock(t) + s.ActL2EmptyBlock(t) } } @@ -180,44 +196,40 @@ func (s *L2Sequencer) ActBuildToL1HeadExclUnsafe(t Testing) { if nextOrigin.Number >= s.syncStatus.L1Head().Number { break } - s.ActL2StartBlock(t) - s.ActL2EndBlock(t) + s.ActL2EmptyBlock(t) } } func (s *L2Sequencer) ActBuildL2ToTime(t Testing, target uint64) { for s.L2Unsafe().Time < target { - s.ActL2StartBlock(t) - s.ActL2EndBlock(t) + s.ActL2EmptyBlock(t) } } func (s *L2Sequencer) ActBuildL2ToEcotone(t Testing) { require.NotNil(t, s.RollupCfg.EcotoneTime, "cannot activate Ecotone when it is not scheduled") for s.L2Unsafe().Time < *s.RollupCfg.EcotoneTime { - s.ActL2StartBlock(t) - s.ActL2EndBlock(t) + s.ActL2EmptyBlock(t) } } + func (s *L2Sequencer) ActBuildL2ToFjord(t Testing) { require.NotNil(t, s.RollupCfg.FjordTime, "cannot activate FjordTime when it is not scheduled") for s.L2Unsafe().Time < *s.RollupCfg.FjordTime { - s.ActL2StartBlock(t) - s.ActL2EndBlock(t) + s.ActL2EmptyBlock(t) } } + func (s *L2Sequencer) ActBuildL2ToGranite(t Testing) { require.NotNil(t, s.RollupCfg.GraniteTime, "cannot activate GraniteTime when it is not scheduled") for s.L2Unsafe().Time < *s.RollupCfg.GraniteTime { - s.ActL2StartBlock(t) - s.ActL2EndBlock(t) + s.ActL2EmptyBlock(t) } } func (s *L2Sequencer) ActBuildL2ToHolocene(t Testing) { require.NotNil(t, s.RollupCfg.HoloceneTime, "cannot activate HoloceneTime when it is not scheduled") for s.L2Unsafe().Time < *s.RollupCfg.HoloceneTime { - s.ActL2StartBlock(t) - s.ActL2EndBlock(t) + s.ActL2EmptyBlock(t) } } diff --git a/op-e2e/actions/helpers/setups.go b/op-e2e/actions/helpers/setups.go index 26e19eae82a05..3322dea4223e0 100644 --- a/op-e2e/actions/helpers/setups.go +++ b/op-e2e/actions/helpers/setups.go @@ -25,7 +25,7 @@ func SetupSequencerTest(t Testing, sd *e2eutils.SetupData, log log.Logger, opts l1F, err := sources.NewL1Client(miner.RPCClient(), log, nil, sources.L1ClientDefaultConfig(sd.RollupCfg, false, sources.RPCKindStandard)) require.NoError(t, err) - engine := NewL2Engine(t, log.New("role", "sequencer-engine"), sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath, EngineWithP2P()) + engine := NewL2Engine(t, log.New("role", "sequencer-engine"), sd.L2Cfg, jwtPath, EngineWithP2P()) l2Cl, err := sources.NewEngineClient(engine.RPCClient(), log, nil, sources.EngineClientDefaultConfig(sd.RollupCfg)) require.NoError(t, err) @@ -40,7 +40,7 @@ func SetupVerifier(t Testing, sd *e2eutils.SetupData, log log.Logger, opt(cfg) } jwtPath := e2eutils.WriteDefaultJWT(t) - engine := NewL2Engine(t, log.New("role", "verifier-engine"), sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath, EngineWithP2P()) + engine := NewL2Engine(t, log.New("role", "verifier-engine"), sd.L2Cfg, jwtPath, EngineWithP2P()) engCl := engine.EngineClient(t, sd.RollupCfg) verifier := NewL2Verifier(t, log.New("role", "verifier"), l1F, blobSrc, altda.Disabled, engCl, sd.RollupCfg, syncCfg, cfg.SafeHeadListener, cfg.InteropBackend) return engine, verifier diff --git a/op-e2e/actions/interop/interop.go b/op-e2e/actions/interop/interop.go new file mode 100644 index 0000000000000..4ac2b0cb80ffc --- /dev/null +++ b/op-e2e/actions/interop/interop.go @@ -0,0 +1,236 @@ +package interop + +import ( + "context" + "os" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "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-chain-ops/devkeys" + "github.com/ethereum-optimism/optimism/op-chain-ops/foundry" + "github.com/ethereum-optimism/optimism/op-chain-ops/interopgen" + "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" + "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-node/rollup/interop" + "github.com/ethereum-optimism/optimism/op-service/sources" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum-optimism/optimism/op-supervisor/config" + "github.com/ethereum-optimism/optimism/op-supervisor/metrics" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/frontend" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" +) + +const ( + foundryArtifactsDir = "../../../packages/contracts-bedrock/forge-artifacts" + sourceMapDir = "../../../packages/contracts-bedrock" +) + +// Chain holds the most common per-chain action-test data and actors +type Chain struct { + ChainID types.ChainID + + RollupCfg *rollup.Config + ChainCfg *params.ChainConfig + BatcherAddr common.Address + + Sequencer *helpers.L2Sequencer + SequencerEngine *helpers.L2Engine + Batcher *helpers.L2Batcher +} + +// InteropSetup holds the chain deployment and config contents, before instantiating any services. +type InteropSetup struct { + Log log.Logger + Deployment *interopgen.WorldDeployment + Out *interopgen.WorldOutput + DepSet *depset.StaticConfigDependencySet + Keys devkeys.Keys + T helpers.Testing +} + +// InteropActors holds a bundle of global actors and actors of 2 chains. +type InteropActors struct { + L1Miner *helpers.L1Miner + Supervisor *SupervisorActor + ChainA *Chain + ChainB *Chain +} + +// SetupInterop creates an InteropSetup to instantiate actors on, with 2 L2 chains. +func SetupInterop(t helpers.Testing) *InteropSetup { + logger := testlog.Logger(t, log.LevelDebug) + + recipe := interopgen.InteropDevRecipe{ + L1ChainID: 900100, + L2ChainIDs: []uint64{900200, 900201}, + GenesisTimestamp: uint64(time.Now().Unix() + 3), + } + hdWallet, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic) + require.NoError(t, err) + worldCfg, err := recipe.Build(hdWallet) + require.NoError(t, err) + + // create the foundry artifacts and source map + foundryArtifacts := foundry.OpenArtifactsDir(foundryArtifactsDir) + sourceMap := foundry.NewSourceMapFS(os.DirFS(sourceMapDir)) + + // deploy the world, using the logger, foundry artifacts, source map, and world configuration + worldDeployment, worldOutput, err := interopgen.Deploy(logger, foundryArtifacts, sourceMap, worldCfg) + require.NoError(t, err) + + return &InteropSetup{ + Log: logger, + Deployment: worldDeployment, + Out: worldOutput, + DepSet: worldToDepSet(t, worldOutput), + Keys: hdWallet, + T: t, + } +} + +func (is *InteropSetup) CreateActors() *InteropActors { + l1Miner := helpers.NewL1Miner(is.T, is.Log.New("role", "l1Miner"), is.Out.L1.Genesis) + supervisorAPI := NewSupervisor(is.T, is.Log, is.DepSet) + require.NoError(is.T, supervisorAPI.Start(is.T.Ctx())) + is.T.Cleanup(func() { + require.NoError(is.T, supervisorAPI.Stop(context.Background())) + }) + chainA := createL2Services(is.T, is.Log, l1Miner, is.Keys, is.Out.L2s["900200"], supervisorAPI) + chainB := createL2Services(is.T, is.Log, l1Miner, is.Keys, is.Out.L2s["900201"], supervisorAPI) + // Hook up L2 RPCs to supervisor, to fetch event data from + require.NoError(is.T, supervisorAPI.AddL2RPC(is.T.Ctx(), chainA.SequencerEngine.HTTPEndpoint())) + require.NoError(is.T, supervisorAPI.AddL2RPC(is.T.Ctx(), chainB.SequencerEngine.HTTPEndpoint())) + return &InteropActors{ + L1Miner: l1Miner, + Supervisor: supervisorAPI, + ChainA: chainA, + ChainB: chainB, + } +} + +// SupervisorActor represents a supervisor, instrumented to run synchronously for action-test purposes. +type SupervisorActor struct { + backend *backend.SupervisorBackend + frontend.QueryFrontend + frontend.AdminFrontend + frontend.UpdatesFrontend +} + +func (sa *SupervisorActor) SyncEvents(t helpers.Testing, chainID types.ChainID) { + require.NoError(t, sa.backend.SyncEvents(chainID)) +} + +func (sa *SupervisorActor) SyncCrossUnsafe(t helpers.Testing, chainID types.ChainID) { + require.NoError(t, sa.backend.SyncCrossUnsafe(chainID)) +} + +func (sa *SupervisorActor) SyncCrossSafe(t helpers.Testing, chainID types.ChainID) { + require.NoError(t, sa.backend.SyncCrossSafe(chainID)) +} + +// worldToDepSet converts a set of chain configs into a dependency-set for the supervisor. +func worldToDepSet(t helpers.Testing, worldOutput *interopgen.WorldOutput) *depset.StaticConfigDependencySet { + depSetCfg := make(map[types.ChainID]*depset.StaticConfigDependency) + for _, out := range worldOutput.L2s { + depSetCfg[types.ChainIDFromBig(out.Genesis.Config.ChainID)] = &depset.StaticConfigDependency{ + ChainIndex: types.ChainIndex(out.Genesis.Config.ChainID.Uint64()), + ActivationTime: 0, + HistoryMinTime: 0, + } + } + depSet, err := depset.NewStaticConfigDependencySet(depSetCfg) + require.NoError(t, err) + return depSet +} + +// NewSupervisor creates a new SupervisorActor, to action-test the supervisor with. +func NewSupervisor(t helpers.Testing, logger log.Logger, depSet depset.DependencySetSource) *SupervisorActor { + logger = logger.New("role", "supervisor") + supervisorDataDir := t.TempDir() + logger.Info("supervisor data dir", "dir", supervisorDataDir) + svCfg := &config.Config{ + DependencySetSource: depSet, + SynchronousProcessors: true, + Datadir: supervisorDataDir, + } + b, err := backend.NewSupervisorBackend(t.Ctx(), + logger.New("role", "supervisor"), metrics.NoopMetrics, svCfg) + require.NoError(t, err) + return &SupervisorActor{ + backend: b, + QueryFrontend: frontend.QueryFrontend{ + Supervisor: b, + }, + AdminFrontend: frontend.AdminFrontend{ + Supervisor: b, + }, + UpdatesFrontend: frontend.UpdatesFrontend{ + Supervisor: b, + }, + } +} + +// createL2Services creates a Chain bundle, with the given configs, and attached to the given L1 miner. +func createL2Services( + t helpers.Testing, + logger log.Logger, + l1Miner *helpers.L1Miner, + keys devkeys.Keys, + output *interopgen.L2Output, + interopBackend interop.InteropBackend, +) *Chain { + logger = logger.New("chain", output.Genesis.Config.ChainID) + + jwtPath := e2eutils.WriteDefaultJWT(t) + + eng := helpers.NewL2Engine(t, logger.New("role", "engine"), output.Genesis, jwtPath) + + seqCl, err := sources.NewEngineClient(eng.RPCClient(), logger, nil, sources.EngineClientDefaultConfig(output.RollupCfg)) + require.NoError(t, err) + + l1F, err := sources.NewL1Client(l1Miner.RPCClient(), logger, nil, + sources.L1ClientDefaultConfig(output.RollupCfg, false, sources.RPCKindStandard)) + require.NoError(t, err) + + seq := helpers.NewL2Sequencer(t, logger.New("role", "sequencer"), l1F, + l1Miner.BlobStore(), altda.Disabled, seqCl, output.RollupCfg, + 0, interopBackend) + + batcherKey, err := keys.Secret(devkeys.ChainOperatorKey{ + ChainID: output.Genesis.Config.ChainID, + Role: devkeys.BatcherRole, + }) + require.NoError(t, err) + + batcherCfg := &helpers.BatcherCfg{ + MinL1TxSize: 0, + MaxL1TxSize: 128_000, + BatcherKey: batcherKey, + DataAvailabilityType: batcherFlags.CalldataType, + } + + batcher := helpers.NewL2Batcher(logger.New("role", "batcher"), output.RollupCfg, batcherCfg, + seq.RollupClient(), l1Miner.EthClient(), + eng.EthClient(), eng.EngineClient(t, output.RollupCfg)) + + return &Chain{ + ChainID: types.ChainIDFromBig(output.Genesis.Config.ChainID), + RollupCfg: output.RollupCfg, + ChainCfg: output.Genesis.Config, + BatcherAddr: crypto.PubkeyToAddress(batcherKey.PublicKey), + Sequencer: seq, + SequencerEngine: eng, + Batcher: batcher, + } +} diff --git a/op-e2e/actions/interop/interop_test.go b/op-e2e/actions/interop/interop_test.go index c345404907b02..a39da702db8c5 100644 --- a/op-e2e/actions/interop/interop_test.go +++ b/op-e2e/actions/interop/interop_test.go @@ -1,186 +1,109 @@ package interop import ( - "context" "testing" "github.com/stretchr/testify/require" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" - "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" - "github.com/ethereum-optimism/optimism/op-node/rollup/interop" - "github.com/ethereum-optimism/optimism/op-node/rollup/sync" - "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-service/testlog" - "github.com/ethereum-optimism/optimism/op-service/testutils" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) -var _ interop.InteropBackend = (*testutils.FakeInteropBackend)(nil) - -func TestInteropVerifier(gt *testing.T) { +func TestFullInterop(gt *testing.T) { t := helpers.NewDefaultTesting(gt) - dp := e2eutils.MakeDeployParams(t, helpers.DefaultRollupTestParams()) - sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc) - // Temporary work-around: interop needs to be active, for cross-safety to not be instant. - // The state genesis in this test is pre-interop however. - sd.RollupCfg.InteropTime = new(uint64) - logger := testlog.Logger(t, log.LevelDebug) - seqMockBackend := &testutils.FakeInteropBackend{} - l1Miner, seqEng, seq := helpers.SetupSequencerTest(t, sd, logger, - helpers.WithVerifierOpts(helpers.WithInteropBackend(seqMockBackend))) - - batcher := helpers.NewL2Batcher(logger, sd.RollupCfg, helpers.DefaultBatcherCfg(dp), - seq.RollupClient(), l1Miner.EthClient(), seqEng.EthClient(), seqEng.EngineClient(t, sd.RollupCfg)) - - verMockBackend := &testutils.FakeInteropBackend{} - _, ver := helpers.SetupVerifier(t, sd, logger, - l1Miner.L1Client(t, sd.RollupCfg), l1Miner.BlobStore(), &sync.Config{}, - helpers.WithInteropBackend(verMockBackend)) - seq.ActL2PipelineFull(t) - ver.ActL2PipelineFull(t) - - l2ChainID := types.ChainIDFromBig(sd.RollupCfg.L2ChainID) - seqMockBackend.UpdateLocalUnsafeFn = func(ctx context.Context, chainID types.ChainID, head eth.L2BlockRef) error { - require.Equal(t, chainID, l2ChainID) - require.Equal(t, uint64(1), head.Number) - return nil - } - seqMockBackend.UnsafeViewFn = func(ctx context.Context, chainID types.ChainID, unsafe types.ReferenceView) (types.ReferenceView, error) { - require.Equal(t, chainID, l2ChainID) - require.Equal(t, uint64(1), unsafe.Local.Number) - require.Equal(t, uint64(0), unsafe.Cross.Number) - return unsafe, nil - } - // create an unsafe L2 block - seq.ActL2StartBlock(t) - seq.ActL2EndBlock(t) - seq.ActL2PipelineFull(t) - status := seq.SyncStatus() - require.Equal(t, uint64(1), status.UnsafeL2.Number) + is := SetupInterop(t) + actors := is.CreateActors() + + // get both sequencers set up + actors.ChainA.Sequencer.ActL2PipelineFull(t) + actors.ChainB.Sequencer.ActL2PipelineFull(t) + + // No blocks yet + status := actors.ChainA.Sequencer.SyncStatus() + require.Equal(t, uint64(0), status.UnsafeL2.Number) + + // sync chain A + actors.Supervisor.SyncEvents(t, actors.ChainA.ChainID) + actors.Supervisor.SyncCrossUnsafe(t, actors.ChainA.ChainID) + actors.Supervisor.SyncCrossSafe(t, actors.ChainA.ChainID) + + // sync chain B + actors.Supervisor.SyncEvents(t, actors.ChainB.ChainID) + actors.Supervisor.SyncCrossUnsafe(t, actors.ChainB.ChainID) + actors.Supervisor.SyncCrossSafe(t, actors.ChainB.ChainID) + + // Build L2 block on chain A + actors.ChainA.Sequencer.ActL2StartBlock(t) + actors.ChainA.Sequencer.ActL2EndBlock(t) + status = actors.ChainA.Sequencer.SyncStatus() + head := status.UnsafeL2.ID() + require.Equal(t, uint64(1), head.Number) require.Equal(t, uint64(0), status.CrossUnsafeL2.Number) require.Equal(t, uint64(0), status.LocalSafeL2.Number) require.Equal(t, uint64(0), status.SafeL2.Number) + require.Equal(t, uint64(0), status.FinalizedL2.Number) - // promote it to cross-unsafe in the backend - // and see if the node picks up on it - seqMockBackend.UnsafeViewFn = func(ctx context.Context, chainID types.ChainID, unsafe types.ReferenceView) (types.ReferenceView, error) { - require.Equal(t, chainID, l2ChainID) - require.Equal(t, uint64(1), unsafe.Local.Number) - require.Equal(t, uint64(0), unsafe.Cross.Number) - out := unsafe - out.Cross = unsafe.Local - return out, nil - } - seq.ActInteropBackendCheck(t) - seq.ActL2PipelineFull(t) - status = seq.SyncStatus() - require.Equal(t, uint64(1), status.UnsafeL2.Number) - require.Equal(t, uint64(1), status.CrossUnsafeL2.Number, "cross unsafe now") + // Verify as cross-unsafe with supervisor + actors.Supervisor.SyncEvents(t, actors.ChainA.ChainID) + actors.Supervisor.SyncCrossUnsafe(t, actors.ChainA.ChainID) + actors.ChainA.Sequencer.ActL2PipelineFull(t) + status = actors.ChainA.Sequencer.SyncStatus() + require.Equal(t, head, status.UnsafeL2.ID()) + require.Equal(t, head, status.CrossUnsafeL2.ID()) require.Equal(t, uint64(0), status.LocalSafeL2.Number) require.Equal(t, uint64(0), status.SafeL2.Number) + require.Equal(t, uint64(0), status.FinalizedL2.Number) - // submit all new L2 blocks - batcher.ActSubmitAll(t) - // new L1 block with L2 batch - l1Miner.ActL1StartBlock(12)(t) - l1Miner.ActL1IncludeTx(sd.RollupCfg.Genesis.SystemConfig.BatcherAddr)(t) - l1Miner.ActL1EndBlock(t) - - // Sync the L1 block, to verify the L2 block as local-safe. - seqMockBackend.UpdateLocalUnsafeFn = nil - seqMockBackend.UpdateLocalSafeFn = func(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.L2BlockRef) error { - require.Equal(t, uint64(1), lastDerived.Number) - return nil - } - seqMockBackend.SafeViewFn = func(ctx context.Context, chainID types.ChainID, safe types.ReferenceView) (types.ReferenceView, error) { - require.Equal(t, chainID, l2ChainID) - require.Equal(t, uint64(1), safe.Local.Number) - require.Equal(t, uint64(0), safe.Cross.Number) - return safe, nil - } - seq.ActL1HeadSignal(t) - l1Head := seq.SyncStatus().HeadL1 - seq.ActL2PipelineFull(t) - - status = seq.SyncStatus() - require.Equal(t, uint64(1), status.UnsafeL2.Number) - require.Equal(t, uint64(1), status.CrossUnsafeL2.Number) - require.Equal(t, uint64(1), status.LocalSafeL2.Number, "local safe changed") + // Submit the L2 block, sync the local-safe data + actors.ChainA.Batcher.ActSubmitAll(t) + actors.L1Miner.ActL1StartBlock(12)(t) + actors.L1Miner.ActL1IncludeTx(actors.ChainA.BatcherAddr)(t) + actors.L1Miner.ActL1EndBlock(t) + actors.ChainA.Sequencer.ActL1HeadSignal(t) + actors.ChainA.Sequencer.ActL2PipelineFull(t) + status = actors.ChainA.Sequencer.SyncStatus() + require.Equal(t, head, status.UnsafeL2.ID()) + require.Equal(t, head, status.CrossUnsafeL2.ID()) + require.Equal(t, head, status.LocalSafeL2.ID()) require.Equal(t, uint64(0), status.SafeL2.Number) - - // Now mark it as cross-safe - seqMockBackend.SafeViewFn = func(ctx context.Context, chainID types.ChainID, request types.ReferenceView) (types.ReferenceView, error) { - require.Equal(t, chainID, l2ChainID) - require.Equal(t, uint64(1), request.Local.Number) - require.Equal(t, uint64(0), request.Cross.Number) - out := request - out.Cross = request.Local - return out, nil - } - seqMockBackend.DerivedFromFn = func(ctx context.Context, chainID types.ChainID, blockHash common.Hash, blockNumber uint64) (eth.L1BlockRef, error) { - require.Equal(t, uint64(1), blockNumber) - return l1Head, nil - } - seqMockBackend.FinalizedFn = func(ctx context.Context, chainID types.ChainID) (eth.BlockID, error) { - return seq.RollupCfg.Genesis.L1, nil - } - seq.ActInteropBackendCheck(t) - seq.ActL2PipelineFull(t) - - status = seq.SyncStatus() - require.Equal(t, uint64(1), status.UnsafeL2.Number) - require.Equal(t, uint64(1), status.CrossUnsafeL2.Number) - require.Equal(t, uint64(1), status.LocalSafeL2.Number) - require.Equal(t, uint64(1), status.SafeL2.Number, "cross-safe reached") require.Equal(t, uint64(0), status.FinalizedL2.Number) - - verMockBackend.UpdateLocalUnsafeFn = func(ctx context.Context, chainID types.ChainID, head eth.L2BlockRef) error { - require.Equal(t, uint64(1), head.Number) - return nil - } - verMockBackend.UpdateLocalSafeFn = func(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.L2BlockRef) error { - require.Equal(t, uint64(1), lastDerived.Number) - require.Equal(t, l1Head.ID(), derivedFrom.ID()) - return nil - } - // The verifier might not see the L2 block that was just derived from L1 as cross-verified yet. - verMockBackend.UnsafeViewFn = func(ctx context.Context, chainID types.ChainID, request types.ReferenceView) (types.ReferenceView, error) { - require.Equal(t, uint64(1), request.Local.Number) - require.Equal(t, uint64(0), request.Cross.Number) - // Don't promote the Cross value yet - return request, nil - } - verMockBackend.SafeViewFn = func(ctx context.Context, chainID types.ChainID, request types.ReferenceView) (types.ReferenceView, error) { - require.Equal(t, uint64(1), request.Local.Number) - require.Equal(t, uint64(0), request.Cross.Number) - // Don't promote the Cross value yet - return request, nil - } - ver.ActL1HeadSignal(t) - ver.ActL2PipelineFull(t) - status = ver.SyncStatus() - require.Equal(t, uint64(1), status.UnsafeL2.Number, "synced the block") - require.Equal(t, uint64(0), status.CrossUnsafeL2.Number, "not cross-verified yet") - require.Equal(t, uint64(1), status.LocalSafeL2.Number, "derived from L1, thus local-safe") - require.Equal(t, uint64(0), status.SafeL2.Number, "not yet cross-safe") + // Local-safe does not count as "safe" in RPC + n := actors.ChainA.SequencerEngine.L2Chain().CurrentSafeBlock().Number.Uint64() + require.Equal(t, uint64(0), n) + + // Cross-safe verify it + actors.Supervisor.SyncCrossSafe(t, actors.ChainA.ChainID) + actors.ChainA.Sequencer.ActInteropBackendCheck(t) + actors.ChainA.Sequencer.ActL2PipelineFull(t) + status = actors.ChainA.Sequencer.SyncStatus() + require.Equal(t, head, status.UnsafeL2.ID()) + require.Equal(t, head, status.CrossUnsafeL2.ID()) + require.Equal(t, head, status.LocalSafeL2.ID()) + require.Equal(t, head, status.SafeL2.ID()) require.Equal(t, uint64(0), status.FinalizedL2.Number) - - seqMockBackend.UpdateFinalizedL1Fn = func(ctx context.Context, chainID types.ChainID, finalized eth.L1BlockRef) error { - require.Equal(t, l1Head, finalized) - return nil - } - // signal that L1 finalized; the cross-safe block we have should get finalized too - l1Miner.ActL1SafeNext(t) - l1Miner.ActL1FinalizeNext(t) - seq.ActL1SafeSignal(t) - seq.ActL1FinalizedSignal(t) - seq.ActL2PipelineFull(t) - - status = seq.SyncStatus() - require.Equal(t, uint64(1), status.FinalizedL2.Number, "finalized the block") + h := actors.ChainA.SequencerEngine.L2Chain().CurrentSafeBlock().Hash() + require.Equal(t, head.Hash, h) + + // Finalize L1, and see how the op-node forwards it to the supervisor. + // The supervisor then determines finality, which the op-node can use. + actors.L1Miner.ActL1SafeNext(t) + actors.L1Miner.ActL1FinalizeNext(t) + actors.ChainA.Sequencer.ActL1SafeSignal(t) + actors.ChainA.Sequencer.ActL1FinalizedSignal(t) + actors.ChainA.Sequencer.ActL2PipelineFull(t) + finalizedL2BlockID, err := actors.Supervisor.Finalized(t.Ctx(), actors.ChainA.ChainID) + require.NoError(t, err) + require.Equal(t, head, finalizedL2BlockID) + + // The op-node needs a poke to look at the updated supervisor finality state + actors.ChainA.Sequencer.ActInteropBackendCheck(t) + actors.ChainA.Sequencer.ActL2PipelineFull(t) + h = actors.ChainA.SequencerEngine.L2Chain().CurrentFinalBlock().Hash() + require.Equal(t, head.Hash, h) + status = actors.ChainA.Sequencer.SyncStatus() + require.Equal(t, head, status.UnsafeL2.ID()) + require.Equal(t, head, status.CrossUnsafeL2.ID()) + require.Equal(t, head, status.LocalSafeL2.ID()) + require.Equal(t, head, status.SafeL2.ID()) + require.Equal(t, head, status.FinalizedL2.ID()) } diff --git a/op-e2e/actions/proofs/bad_tx_in_batch_test.go b/op-e2e/actions/proofs/bad_tx_in_batch_test.go index f67e216f76cb0..ce6e37469c1b3 100644 --- a/op-e2e/actions/proofs/bad_tx_in_batch_test.go +++ b/op-e2e/actions/proofs/bad_tx_in_batch_test.go @@ -26,14 +26,14 @@ func runBadTxInBatchTest(gt *testing.T, testCfg *helpers.TestCfg[any]) { env.Alice.L2.ActCheckReceiptStatusOfLastTx(true)(t) // Instruct the batcher to submit a faulty channel, with an invalid tx. - err := env.Batcher.Buffer(t, func(block *types.Block) { + env.Batcher.ActL2BatchBuffer(t, func(block *types.Block) *types.Block { // Replace the tx with one that has a bad signature. txs := block.Transactions() newTx, err := txs[1].WithSignature(env.Alice.L2.Signer(), make([]byte, 65)) txs[1] = newTx require.NoError(t, err) + return block }) - require.NoError(t, err) env.Batcher.ActL2ChannelClose(t) env.Batcher.ActL2BatchSubmit(t) @@ -91,12 +91,13 @@ func runBadTxInBatch_ResubmitBadFirstFrame_Test(gt *testing.T, testCfg *helpers. // Instruct the batcher to submit a faulty channel, with an invalid tx in the second block // within the span batch. env.Batcher.ActL2BatchBuffer(t) - err := env.Batcher.Buffer(t, func(block *types.Block) { + err := env.Batcher.Buffer(t, func(block *types.Block) *types.Block { // Replace the tx with one that has a bad signature. txs := block.Transactions() newTx, err := txs[1].WithSignature(env.Alice.L2.Signer(), make([]byte, 65)) txs[1] = newTx require.NoError(t, err) + return block }) require.NoError(t, err) env.Batcher.ActL2ChannelClose(t) @@ -144,14 +145,14 @@ func Test_ProgramAction_BadTxInBatch(gt *testing.T) { matrix.AddTestCase( "HonestClaim", nil, - helpers.LatestForkOnly, + helpers.NewForkMatrix(helpers.Granite), runBadTxInBatchTest, helpers.ExpectNoError(), ) matrix.AddTestCase( "JunkClaim", nil, - helpers.LatestForkOnly, + helpers.NewForkMatrix(helpers.Granite), runBadTxInBatchTest, helpers.ExpectError(claim.ErrClaimNotValid), helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), @@ -159,14 +160,14 @@ func Test_ProgramAction_BadTxInBatch(gt *testing.T) { matrix.AddTestCase( "ResubmitBadFirstFrame-HonestClaim", nil, - helpers.LatestForkOnly, + helpers.NewForkMatrix(helpers.Granite), runBadTxInBatch_ResubmitBadFirstFrame_Test, helpers.ExpectNoError(), ) matrix.AddTestCase( "ResubmitBadFirstFrame-JunkClaim", nil, - helpers.LatestForkOnly, + helpers.NewForkMatrix(helpers.Granite), runBadTxInBatch_ResubmitBadFirstFrame_Test, helpers.ExpectError(claim.ErrClaimNotValid), helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), diff --git a/op-e2e/actions/proofs/helpers/env.go b/op-e2e/actions/proofs/helpers/env.go index 4283d0d1e1628..7027647e142b2 100644 --- a/op-e2e/actions/proofs/helpers/env.go +++ b/op-e2e/actions/proofs/helpers/env.go @@ -4,6 +4,7 @@ import ( "context" "math/rand" + "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" e2ecfg "github.com/ethereum-optimism/optimism/op-e2e/config" altda "github.com/ethereum-optimism/optimism/op-alt-da" @@ -28,6 +29,7 @@ import ( // L2FaultProofEnv is a test harness for a fault provable L2 chain. type L2FaultProofEnv struct { log log.Logger + Logs *testlog.CapturingHandler Batcher *helpers.L2Batcher Sequencer *helpers.L2Sequencer Engine *helpers.L2Engine @@ -39,8 +41,11 @@ type L2FaultProofEnv struct { Bob *helpers.CrossLayerUser } -func NewL2FaultProofEnv[c any](t helpers.Testing, testCfg *TestCfg[c], tp *e2eutils.TestParams, batcherCfg *helpers.BatcherCfg) *L2FaultProofEnv { - log := testlog.Logger(t, log.LvlDebug) +type deployConfigOverride func(*genesis.DeployConfig) + +func NewL2FaultProofEnv[c any](t helpers.Testing, testCfg *TestCfg[c], tp *e2eutils.TestParams, batcherCfg *helpers.BatcherCfg, deployConfigOverrides ...deployConfigOverride) *L2FaultProofEnv { + log, logs := testlog.CaptureLogger(t, log.LevelDebug) + dp := NewDeployParams(t, tp, func(dp *e2eutils.DeployParams) { genesisBlock := hexutil.Uint64(0) @@ -64,6 +69,10 @@ func NewL2FaultProofEnv[c any](t helpers.Testing, testCfg *TestCfg[c], tp *e2eut case Holocene: dp.DeployConfig.L2GenesisHoloceneTimeOffset = &genesisBlock } + + for _, override := range deployConfigOverrides { + override(dp.DeployConfig) + } }) sd := e2eutils.Setup(t, dp, helpers.DefaultAlloc) @@ -74,7 +83,7 @@ func NewL2FaultProofEnv[c any](t helpers.Testing, testCfg *TestCfg[c], tp *e2eut l1Cl, err := sources.NewL1Client(miner.RPCClient(), log, nil, sources.L1ClientDefaultConfig(sd.RollupCfg, false, sources.RPCKindStandard)) require.NoError(t, err) - engine := helpers.NewL2Engine(t, log.New("role", "sequencer-engine"), sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath, helpers.EngineWithP2P()) + engine := helpers.NewL2Engine(t, log.New("role", "sequencer-engine"), sd.L2Cfg, jwtPath, helpers.EngineWithP2P()) l2EngineCl, err := sources.NewEngineClient(engine.RPCClient(), log, nil, sources.EngineClientDefaultConfig(sd.RollupCfg)) require.NoError(t, err) @@ -111,6 +120,7 @@ func NewL2FaultProofEnv[c any](t helpers.Testing, testCfg *TestCfg[c], tp *e2eut return &L2FaultProofEnv{ log: log, + Logs: logs, Batcher: batcher, Sequencer: sequencer, Engine: engine, @@ -145,9 +155,20 @@ func WithL2Claim(claim common.Hash) FixtureInputParam { } } +func WithL2BlockNumber(num uint64) FixtureInputParam { + return func(f *FixtureInputs) { + f.L2BlockNumber = num + } +} + func (env *L2FaultProofEnv) RunFaultProofProgram(t helpers.Testing, l2ClaimBlockNum uint64, checkResult CheckResult, fixtureInputParams ...FixtureInputParam) { // Fetch the pre and post output roots for the fault proof. - preRoot, err := env.Sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum-1) + l2PreBlockNum := l2ClaimBlockNum - 1 + if l2ClaimBlockNum == 0 { + // If we are at genesis, we assert that we don't move the chain at all. + l2PreBlockNum = 0 + } + preRoot, err := env.Sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2PreBlockNum) require.NoError(t, err) claimRoot, err := env.Sequencer.RollupClient().OutputAtBlock(t.Ctx(), l2ClaimBlockNum) require.NoError(t, err) @@ -195,7 +216,7 @@ func (env *L2FaultProofEnv) RunFaultProofProgram(t helpers.Testing, l2ClaimBlock l2RPC := env.Engine.RPCClient() l2Client, err := host.NewL2Client(l2RPC, env.log, nil, &host.L2ClientConfig{L2ClientConfig: l2ClCfg, L2Head: cfg.L2Head}) require.NoError(t, err, "failed to create L2 client") - l2DebugCl := &host.L2Source{L2Client: l2Client, DebugClient: sources.NewDebugClient(l2RPC.CallContext)} + l2DebugCl := host.NewL2SourceWithClient(logger, l2Client, sources.NewDebugClient(l2RPC.CallContext)) return prefetcher.NewPrefetcher(logger, l1Cl, l1BlobFetcher, l2DebugCl, kv), nil }) diff --git a/op-e2e/actions/proofs/helpers/matrix.go b/op-e2e/actions/proofs/helpers/matrix.go index 2b4ed5a0ded22..ff6bf2ad77b64 100644 --- a/op-e2e/actions/proofs/helpers/matrix.go +++ b/op-e2e/actions/proofs/helpers/matrix.go @@ -89,9 +89,12 @@ var ( Granite = &Hardfork{Name: "Granite", Precedence: 6} Holocene = &Hardfork{Name: "Holocene", Precedence: 7} ) -var Hardforks = ForkMatrix{Regolith, Canyon, Delta, Ecotone, Fjord, Granite, Holocene} -var LatestForkOnly = ForkMatrix{Hardforks[len(Hardforks)-1]} +var ( + Hardforks = ForkMatrix{Regolith, Canyon, Delta, Ecotone, Fjord, Granite, Holocene} + LatestFork = Hardforks[len(Hardforks)-1] + LatestForkOnly = ForkMatrix{LatestFork} +) func NewForkMatrix(forks ...*Hardfork) ForkMatrix { return append(ForkMatrix{}, forks...) diff --git a/op-e2e/actions/proofs/holocene_activation_test.go b/op-e2e/actions/proofs/holocene_activation_test.go new file mode 100644 index 0000000000000..55b8c1162de3b --- /dev/null +++ b/op-e2e/actions/proofs/holocene_activation_test.go @@ -0,0 +1,117 @@ +package proofs + +import ( + "testing" + + "github.com/ethereum-optimism/optimism/op-chain-ops/genesis" + actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" + "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" + "github.com/ethereum-optimism/optimism/op-program/client/claim" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/stretchr/testify/require" +) + +func Test_ProgramAction_HoloceneActivation(gt *testing.T) { + + runHoloceneDerivationTest := func(gt *testing.T, testCfg *helpers.TestCfg[any]) { + t := actionsHelpers.NewDefaultTesting(gt) + + // Define override to activate Holocene 14 seconds after genesis + var setHoloceneTime = func(dc *genesis.DeployConfig) { + fourteen := hexutil.Uint64(14) + dc.L2GenesisHoloceneTimeOffset = &fourteen + } + + env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(), helpers.NewBatcherCfg(), setHoloceneTime) + + t.Log("HoloceneTime: ", env.Sequencer.RollupCfg.HoloceneTime) + + // Build the L2 chain + blocks := []uint{1, 2} + targetHeadNumber := 2 + for env.Engine.L2Chain().CurrentBlock().Number.Uint64() < uint64(targetHeadNumber) { + env.Sequencer.ActL2StartBlock(t) + // Send an L2 tx + env.Alice.L2.ActResetTxOpts(t) + env.Alice.L2.ActSetTxToAddr(&env.Dp.Addresses.Bob) + env.Alice.L2.ActMakeTx(t) + env.Engine.ActL2IncludeTx(env.Alice.Address())(t) + env.Sequencer.ActL2EndBlock(t) + } + + // Build up a local list of frames + orderedFrames := make([][]byte, 0, 2) + // Buffer the blocks in the batcher and populate orderedFrames list + env.Batcher.ActCreateChannel(t, false) + for i, blockNum := range blocks { + env.Batcher.ActAddBlockByNumber(t, int64(blockNum), actionsHelpers.BlockLogger(t)) + if i == len(blocks)-1 { + env.Batcher.ActL2ChannelClose(t) + } + frame := env.Batcher.ReadNextOutputFrame(t) + require.NotEmpty(t, frame, "frame %d", i) + orderedFrames = append(orderedFrames, frame) + } + + includeBatchTx := func() { + // Include the last transaction submitted by the batcher. + env.Miner.ActL1StartBlock(12)(t) + env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t) + env.Miner.ActL1EndBlock(t) + } + + // Submit first frame + env.Batcher.ActL2BatchSubmitRaw(t, orderedFrames[0]) + includeBatchTx() // block should have a timestamp of 12s after genesis + + // Holocene should activate 14s after genesis, so that the previous l1 block + // was before HoloceneTime and the next l1 block is after it + + // Submit final frame + env.Batcher.ActL2BatchSubmitRaw(t, orderedFrames[1]) + includeBatchTx() // block should have a timestamp of 24s after genesis + + // Instruct the sequencer to derive the L2 chain from the data on L1 that the batcher just posted. + env.Sequencer.ActL1HeadSignal(t) + env.Sequencer.ActL2PipelineFull(t) + + l2SafeHead := env.Sequencer.L2Safe() + require.EqualValues(t, uint64(0), l2SafeHead.Number) // channel should be dropped, so no safe head progression + t.Log("Safe head progressed as expected", "l2SafeHeadNumber", l2SafeHead.Number) + + // Log assertions + filters := []string{ + "FrameQueue: resetting with Holocene activation", + "ChannelMux: transforming to Holocene stage", + "BatchMux: transforming to Holocene stage", + "dropping non-first frame without channel", + } + for _, filter := range filters { + recs := env.Logs.FindLogs(testlog.NewMessageContainsFilter(filter), testlog.NewAttributesFilter("role", "sequencer")) + require.Len(t, recs, 1, "searching for %d instances of '%s' in logs from role %s", 1, filter, "sequencer") + } + + env.RunFaultProofProgram(t, l2SafeHead.Number, testCfg.CheckResult, testCfg.InputParams...) + } + + matrix := helpers.NewMatrix[any]() + defer matrix.Run(gt) + + matrix.AddTestCase( + "HonestClaim-HoloceneActivation", + nil, + helpers.NewForkMatrix(helpers.Granite), + runHoloceneDerivationTest, + helpers.ExpectNoError(), + ) + matrix.AddTestCase( + "JunkClaim-HoloceneActivation", + nil, + helpers.NewForkMatrix(helpers.Granite), + runHoloceneDerivationTest, + helpers.ExpectError(claim.ErrClaimNotValid), + helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), + ) +} diff --git a/op-e2e/actions/proofs/holocene_batches_test.go b/op-e2e/actions/proofs/holocene_batches_test.go new file mode 100644 index 0000000000000..8028aa0f5b905 --- /dev/null +++ b/op-e2e/actions/proofs/holocene_batches_test.go @@ -0,0 +1,155 @@ +package proofs + +import ( + "fmt" + "testing" + + actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" + "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" + "github.com/ethereum-optimism/optimism/op-program/client/claim" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func Test_ProgramAction_HoloceneBatches(gt *testing.T) { + type testCase struct { + name string + blocks []uint // blocks is an ordered list of blocks (by number) to add to a single channel. + isSpanBatch bool + holoceneExpectations + } + + // Depending on the blocks list, we expect a different + // progression of the safe head under Holocene + // derivation rules, compared with pre Holocene. + testCases := []testCase{ + // Standard channel composition + { + name: "ordered", blocks: []uint{1, 2, 3}, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 3}, + holocene: expectations{safeHead: 3}, + }, + }, + + // Non-standard channel composition + { + name: "disordered-a", blocks: []uint{1, 3, 2}, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 3}, // batches are buffered, so the block ordering does not matter + holocene: expectations{safeHead: 1, // batch for block 3 is considered invalid because it is from the future. This batch + remaining channel is dropped. + logs: append( + sequencerOnce("dropping future batch"), + sequencerOnce("Dropping invalid singular batch, flushing channel")..., + )}, + }, + }, + { + name: "disordered-b", blocks: []uint{2, 1, 3}, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 3}, // batches are buffered, so the block ordering does not matter + holocene: expectations{safeHead: 0, // batch for block 2 is considered invalid because it is from the future. This batch + remaining channel is dropped. + logs: append( + sequencerOnce("dropping future batch"), + sequencerOnce("Dropping invalid singular batch, flushing channel")..., + )}, + }, + }, + + { + name: "duplicates-a", blocks: []uint{1, 1, 2, 3}, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 3}, // duplicate batches are dropped, so this reduces to the "ordered" case + holocene: expectations{safeHead: 3, // duplicate batches are dropped, so this reduces to the "ordered" case + logs: sequencerOnce("dropping past batch with old timestamp")}, + }, + }, + { + name: "duplicates-b", blocks: []uint{2, 2, 1, 3}, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 3}, // duplicate batches are silently dropped, so this reduces to disordered-2b + holocene: expectations{safeHead: 0, // duplicate batches are silently dropped, so this reduces to disordered-2b + logs: append( + sequencerOnce("dropping future batch"), + sequencerOnce("Dropping invalid singular batch, flushing channel")..., + )}, + }, + }, + } + + runHoloceneDerivationTest := func(gt *testing.T, testCfg *helpers.TestCfg[testCase]) { + t := actionsHelpers.NewDefaultTesting(gt) + env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(), helpers.NewBatcherCfg()) + + includeBatchTx := func() { + // Include the last transaction submitted by the batcher. + env.Miner.ActL1StartBlock(12)(t) + env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t) + env.Miner.ActL1EndBlock(t) + } + + max := func(input []uint) uint { + max := uint(0) + for _, val := range input { + if val > max { + max = val + } + } + return max + } + + targetHeadNumber := max(testCfg.Custom.blocks) + for env.Engine.L2Chain().CurrentBlock().Number.Uint64() < uint64(targetHeadNumber) { + env.Sequencer.ActL2StartBlock(t) + // Send an L2 tx + env.Alice.L2.ActResetTxOpts(t) + env.Alice.L2.ActSetTxToAddr(&env.Dp.Addresses.Bob) + env.Alice.L2.ActMakeTx(t) + env.Engine.ActL2IncludeTx(env.Alice.Address())(t) + env.Sequencer.ActL2EndBlock(t) + } + + // Buffer the blocks in the batcher. + env.Batcher.ActCreateChannel(t, testCfg.Custom.isSpanBatch) + for _, blockNum := range testCfg.Custom.blocks { + env.Batcher.ActAddBlockByNumber(t, int64(blockNum), actionsHelpers.BlockLogger(t)) + } + env.Batcher.ActL2ChannelClose(t) + frame := env.Batcher.ReadNextOutputFrame(t) + require.NotEmpty(t, frame) + env.Batcher.ActL2BatchSubmitRaw(t, frame) + includeBatchTx() + + // Instruct the sequencer to derive the L2 chain from the data on L1 that the batcher just posted. + env.Sequencer.ActL1HeadSignal(t) + env.Sequencer.ActL2PipelineFull(t) + + l2SafeHead := env.Sequencer.L2Safe() + isHolocene := testCfg.Hardfork.Precedence >= helpers.Holocene.Precedence + testCfg.Custom.RequireExpectedProgressAndLogs(t, l2SafeHead, isHolocene, env.Engine, env.Logs) + t.Log("Safe head progressed as expected", "l2SafeHeadNumber", l2SafeHead.Number) + + env.RunFaultProofProgram(t, l2SafeHead.Number, testCfg.CheckResult, testCfg.InputParams...) + } + + matrix := helpers.NewMatrix[testCase]() + defer matrix.Run(gt) + + for _, ordering := range testCases { + matrix.AddTestCase( + fmt.Sprintf("HonestClaim-%s", ordering.name), + ordering, + helpers.NewForkMatrix(helpers.Granite, helpers.LatestFork), + runHoloceneDerivationTest, + helpers.ExpectNoError(), + ) + matrix.AddTestCase( + fmt.Sprintf("JunkClaim-%s", ordering.name), + ordering, + helpers.NewForkMatrix(helpers.Granite, helpers.LatestFork), + runHoloceneDerivationTest, + helpers.ExpectError(claim.ErrClaimNotValid), + helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), + ) + } +} diff --git a/op-e2e/actions/proofs/holocene_frame_test.go b/op-e2e/actions/proofs/holocene_frame_test.go new file mode 100644 index 0000000000000..2eb843d62ef83 --- /dev/null +++ b/op-e2e/actions/proofs/holocene_frame_test.go @@ -0,0 +1,138 @@ +package proofs + +import ( + "fmt" + "testing" + + actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" + "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" + "github.com/ethereum-optimism/optimism/op-program/client/claim" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func Test_ProgramAction_HoloceneFrames(gt *testing.T) { + type testCase struct { + name string + frames []uint + holoceneExpectations + } + + // An ordered list of frames to read from the channel and submit + // on L1. We expect a different progression of the safe head under Holocene + // derivation rules, compared with pre Holocene. + testCases := []testCase{ + // Standard frame submission, + { + name: "ordered", frames: []uint{0, 1, 2}, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 3}, + holocene: expectations{safeHead: 3}, + }, + }, + + // Non-standard frame submission + { + name: "disordered-a", frames: []uint{2, 1, 0}, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 3}, // frames are buffered, so ordering does not matter + holocene: expectations{safeHead: 0}, // non-first frames will be dropped b/c it is the first seen with that channel Id. The safe head won't move until the channel is closed/completed. + }, + }, + { + name: "disordered-b", frames: []uint{0, 1, 0, 2}, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 3}, // frames are buffered, so ordering does not matter + holocene: expectations{safeHead: 0}, // non-first frames will be dropped b/c it is the first seen with that channel Id. The safe head won't move until the channel is closed/completed. + }, + }, + { + name: "duplicates", frames: []uint{0, 1, 1, 2}, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 3}, // frames are buffered, so ordering does not matter + holocene: expectations{safeHead: 3}, // non-contiguous frames are dropped. So this reduces to case-0. + }, + }, + } + + runHoloceneDerivationTest := func(gt *testing.T, testCfg *helpers.TestCfg[testCase]) { + t := actionsHelpers.NewDefaultTesting(gt) + env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(), helpers.NewBatcherCfg()) + + blocks := []uint{1, 2, 3} + targetHeadNumber := 3 + for env.Engine.L2Chain().CurrentBlock().Number.Uint64() < uint64(targetHeadNumber) { + env.Sequencer.ActL2StartBlock(t) + // Send an L2 tx + env.Alice.L2.ActResetTxOpts(t) + env.Alice.L2.ActSetTxToAddr(&env.Dp.Addresses.Bob) + env.Alice.L2.ActMakeTx(t) + env.Engine.ActL2IncludeTx(env.Alice.Address())(t) + env.Sequencer.ActL2EndBlock(t) + } + + // Build up a local list of frames + orderedFrames := make([][]byte, 0, len(testCfg.Custom.frames)) + // Buffer the blocks in the batcher and populat orderedFrames list + env.Batcher.ActCreateChannel(t, false) + for i, blockNum := range blocks { + env.Batcher.ActAddBlockByNumber(t, int64(blockNum), actionsHelpers.BlockLogger(t)) + if i == len(blocks)-1 { + env.Batcher.ActL2ChannelClose(t) + } + frame := env.Batcher.ReadNextOutputFrame(t) + require.NotEmpty(t, frame, "frame %d", i) + orderedFrames = append(orderedFrames, frame) + } + + includeBatchTx := func() { + // Include the last transaction submitted by the batcher. + env.Miner.ActL1StartBlock(12)(t) + env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t) + env.Miner.ActL1EndBlock(t) + + // Finalize the block with the first channel frame on L1. + env.Miner.ActL1SafeNext(t) + env.Miner.ActL1FinalizeNext(t) + } + + // Submit frames in specified order order + for _, j := range testCfg.Custom.frames { + env.Batcher.ActL2BatchSubmitRaw(t, orderedFrames[j]) + includeBatchTx() + } + + // Instruct the sequencer to derive the L2 chain from the data on L1 that the batcher just posted. + env.Sequencer.ActL1HeadSignal(t) + env.Sequencer.ActL2PipelineFull(t) + + l2SafeHead := env.Sequencer.L2Safe() + + isHolocene := testCfg.Hardfork.Precedence >= helpers.Holocene.Precedence + testCfg.Custom.RequireExpectedProgressAndLogs(t, l2SafeHead, isHolocene, env.Engine, env.Logs) + t.Log("Safe head progressed as expected", "l2SafeHeadNumber", l2SafeHead.Number) + + env.RunFaultProofProgram(t, l2SafeHead.Number, testCfg.CheckResult, testCfg.InputParams...) + } + + matrix := helpers.NewMatrix[testCase]() + defer matrix.Run(gt) + + for _, ordering := range testCases { + matrix.AddTestCase( + fmt.Sprintf("HonestClaim-%s", ordering.name), + ordering, + helpers.NewForkMatrix(helpers.Granite, helpers.LatestFork), + runHoloceneDerivationTest, + helpers.ExpectNoError(), + ) + matrix.AddTestCase( + fmt.Sprintf("JunkClaim-%s", ordering.name), + ordering, + helpers.NewForkMatrix(helpers.Granite, helpers.LatestFork), + runHoloceneDerivationTest, + helpers.ExpectError(claim.ErrClaimNotValid), + helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), + ) + } +} diff --git a/op-e2e/actions/proofs/holocene_helpers_test.go b/op-e2e/actions/proofs/holocene_helpers_test.go new file mode 100644 index 0000000000000..4b19185fe357e --- /dev/null +++ b/op-e2e/actions/proofs/holocene_helpers_test.go @@ -0,0 +1,45 @@ +package proofs + +import ( + actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/stretchr/testify/require" +) + +type logExpectations struct { + role string + filter string + num int +} +type expectations struct { + safeHead uint64 + logs []logExpectations +} +type holoceneExpectations struct { + preHolocene, holocene expectations +} + +func (h holoceneExpectations) RequireExpectedProgressAndLogs(t actionsHelpers.StatefulTesting, actualSafeHead eth.L2BlockRef, isHolocene bool, engine *actionsHelpers.L2Engine, logs *testlog.CapturingHandler) { + var exp expectations + if isHolocene { + exp = h.holocene + } else { + exp = h.preHolocene + } + + require.Equal(t, exp.safeHead, actualSafeHead.Number) + expectedHash := engine.L2Chain().GetBlockByNumber(exp.safeHead).Hash() + require.Equal(t, expectedHash, actualSafeHead.Hash) + + for _, l := range exp.logs { + t.Helper() + recs := logs.FindLogs(testlog.NewMessageContainsFilter(l.filter), testlog.NewAttributesFilter("role", l.role)) + require.Len(t, recs, l.num, "searching for %d instances of '%s' in logs from role %s", l.num, l.filter, l.role) + } + +} + +func sequencerOnce(filter string) []logExpectations { + return []logExpectations{{filter: filter, role: "sequencer", num: 1}} +} diff --git a/op-e2e/actions/proofs/holocene_invalid_batch_test.go b/op-e2e/actions/proofs/holocene_invalid_batch_test.go new file mode 100644 index 0000000000000..202861401c9cb --- /dev/null +++ b/op-e2e/actions/proofs/holocene_invalid_batch_test.go @@ -0,0 +1,258 @@ +package proofs + +import ( + "fmt" + "math/big" + "testing" + + actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" + "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils" + "github.com/ethereum-optimism/optimism/op-program/client/claim" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" +) + +func Test_ProgramAction_HoloceneInvalidBatch(gt *testing.T) { + type testCase struct { + name string + blocks []uint // An ordered list of blocks (by number) to add to a single channel. + useSpanBatch bool + blockModifiers []actionsHelpers.BlockModifier + breachMaxSequencerDrift bool + overAdvanceL1Origin int // block number at which to over-advance + holoceneExpectations + } + + // invalidPayload invalidates the signature for the second transaction in the block. + // This should result in an invalid payload in the engine queue. + invalidPayload := func(block *types.Block) *types.Block { + alice := types.NewCancunSigner(big.NewInt(901)) + txs := block.Transactions() + newTx, err := txs[1].WithSignature(alice, make([]byte, 65)) + if err != nil { + panic(err) + } + txs[1] = newTx + return block + } + + // invalidParentHash invalidates the parentHash of the block. + // This should result in an invalid batch being derived, + // but only for singular (not for span) batches. + invalidParentHash := func(block *types.Block) *types.Block { + headerCopy := block.Header() + headerCopy.ParentHash = common.MaxHash + return block.WithSeal(headerCopy) + } + + k := 2000 + twoThousandBlocks := make([]uint, k) + for i := 0; i < k; i++ { + twoThousandBlocks[i] = uint(i) + 1 + } + + // Depending on the blocks list, whether the channel is built as + // as span batch channel, and whether the blocks are modified / invalidated + // we expect a different progression of the safe head under Holocene + // derivation rules, compared with pre Holocene. + testCases := []testCase{ + // Standard frame submission, standard channel composition + { + name: "valid", blocks: []uint{1, 2, 3}, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 3}, holocene: expectations{safeHead: 3}, + }, + }, + + { + name: "invalid-payload", blocks: []uint{1, 2, 3}, blockModifiers: []actionsHelpers.BlockModifier{nil, invalidPayload, nil}, + useSpanBatch: false, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 1, // Invalid signature in block 2 causes an invalid _payload_ in the engine queue. Entire span batch is invalidated. + logs: sequencerOnce("could not process payload attributes"), + }, + holocene: expectations{safeHead: 2, // We expect the safe head to move to 2 due to creation of a deposit-only block. + logs: append( + sequencerOnce("Holocene active, requesting deposits-only attributes"), + sequencerOnce("could not process payload attributes")..., + ), + }, + }, + }, + { + name: "invalid-payload-span", blocks: []uint{1, 2, 3}, blockModifiers: []actionsHelpers.BlockModifier{nil, invalidPayload, nil}, + useSpanBatch: true, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 0, // Invalid signature in block 2 causes an invalid _payload_ in the engine queue. Entire span batch is invalidated. + logs: sequencerOnce("could not process payload attributes"), + }, + + holocene: expectations{safeHead: 2, // We expect the safe head to move to 2 due to creation of an deposit-only block. + logs: sequencerOnce("could not process payload attributes"), + }, + }, + }, + + { + name: "invalid-parent-hash", blocks: []uint{1, 2, 3}, blockModifiers: []actionsHelpers.BlockModifier{nil, invalidParentHash, nil}, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 1, // Invalid parentHash in block 2 causes an invalid batch to be dropped. + logs: sequencerOnce("ignoring batch with mismatching parent hash")}, + holocene: expectations{safeHead: 1, // Same with Holocene. + logs: sequencerOnce("Dropping invalid singular batch, flushing channel")}, + }, + }, + { + name: "seq-drift-span", blocks: twoThousandBlocks, // if we artificially stall the l1 origin, this should be enough to trigger violation of the max sequencer drift + useSpanBatch: true, + breachMaxSequencerDrift: true, + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 0, // Entire span batch invalidated. + logs: sequencerOnce("batch exceeded sequencer time drift without adopting next origin, and next L1 origin would have been valid"), + }, + holocene: expectations{safeHead: 1800, // We expect partial validity until we hit sequencer drift. + logs: sequencerOnce("batch exceeded sequencer time drift without adopting next origin, and next L1 origin would have been valid"), + }, + }, + }, + { + name: "future-l1-origin-span", + blocks: []uint{1, 2, 3, 4}, + useSpanBatch: true, + overAdvanceL1Origin: 3, // this will over-advance the L1 origin of block 3 + holoceneExpectations: holoceneExpectations{ + preHolocene: expectations{safeHead: 0, // Entire span batch invalidated. + logs: sequencerOnce("block timestamp is less than L1 origin timestamp"), + }, + holocene: expectations{safeHead: 2, // We expect partial validity, safe head should move to block 2, dropping invalid block 3 and remaining channel. + logs: sequencerOnce("batch timestamp is less than L1 origin timestamp"), + }, + }, + }, + } + + runHoloceneDerivationTest := func(gt *testing.T, testCfg *helpers.TestCfg[testCase]) { + t := actionsHelpers.NewDefaultTesting(gt) + tp := helpers.NewTestParams(func(tp *e2eutils.TestParams) { + // Set the channel timeout to 10 blocks, 12x lower than the sequencing window. + tp.ChannelTimeout = 10 + }) + + env := helpers.NewL2FaultProofEnv(t, testCfg, tp, helpers.NewBatcherCfg()) + + includeBatchTx := func() { + // Include the last transaction submitted by the batcher. + env.Miner.ActL1StartBlock(12)(t) + env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t) + env.Miner.ActL1EndBlock(t) + // Finalize the block with the first channel frame on L1. + env.Miner.ActL1SafeNext(t) + env.Miner.ActL1FinalizeNext(t) + } + + env.Batcher.ActCreateChannel(t, testCfg.Custom.useSpanBatch) + + max := func(input []uint) uint { + max := uint(0) + for _, val := range input { + if val > max { + max = val + } + } + return max + } + + if testCfg.Custom.overAdvanceL1Origin > 0 { + // Generate future L1 origin or we cannot advance to it. + env.Miner.ActEmptyBlock(t) + } + + targetHeadNumber := max(testCfg.Custom.blocks) + for env.Engine.L2Chain().CurrentBlock().Number.Uint64() < uint64(targetHeadNumber) { + parentNum := env.Engine.L2Chain().CurrentBlock().Number.Uint64() + + if testCfg.Custom.breachMaxSequencerDrift { + // prevent L1 origin from progressing + env.Sequencer.ActL2KeepL1Origin(t) + } else if oa := testCfg.Custom.overAdvanceL1Origin; oa > 0 && oa == int(parentNum)+1 { + env.Sequencer.ActL2ForceAdvanceL1Origin(t) + } + + env.Sequencer.ActL2StartBlock(t) + + if !testCfg.Custom.breachMaxSequencerDrift { + // Send an L2 tx + env.Alice.L2.ActResetTxOpts(t) + env.Alice.L2.ActSetTxToAddr(&env.Dp.Addresses.Bob) + env.Alice.L2.ActMakeTx(t) + env.Engine.ActL2IncludeTx(env.Alice.Address())(t) + } + + if testCfg.Custom.breachMaxSequencerDrift && + parentNum == 1799 || + parentNum == 1800 || + parentNum == 1801 { + // Send an L2 tx and force sequencer to include it + env.Alice.L2.ActResetTxOpts(t) + env.Alice.L2.ActSetTxToAddr(&env.Dp.Addresses.Bob) + env.Alice.L2.ActMakeTx(t) + env.Engine.ActL2IncludeTxIgnoreForcedEmpty(env.Alice.Address())(t) + } + + env.Sequencer.ActL2EndBlock(t) + } + + // Buffer the blocks in the batcher. + for i, blockNum := range testCfg.Custom.blocks { + var blockModifier actionsHelpers.BlockModifier + if len(testCfg.Custom.blockModifiers) > i { + blockModifier = testCfg.Custom.blockModifiers[i] + } + env.Batcher.ActAddBlockByNumber(t, int64(blockNum), blockModifier, actionsHelpers.BlockLogger(t)) + + } + + env.Batcher.ActL2ChannelClose(t) + frame := env.Batcher.ReadNextOutputFrame(t) + require.NotEmpty(t, frame) + env.Batcher.ActL2BatchSubmitRaw(t, frame) + includeBatchTx() + + // Instruct the sequencer to derive the L2 chain from the data on L1 that the batcher just posted. + env.Sequencer.ActL1HeadSignal(t) + env.Sequencer.ActL2PipelineFull(t) + + l2SafeHead := env.Sequencer.L2Safe() + + isHolocene := testCfg.Hardfork.Precedence >= helpers.Holocene.Precedence + testCfg.Custom.RequireExpectedProgressAndLogs(t, l2SafeHead, isHolocene, env.Engine, env.Logs) + t.Log("Safe head progressed as expected", "l2SafeHeadNumber", l2SafeHead.Number) + + if safeHeadNumber := l2SafeHead.Number; safeHeadNumber > 0 { + env.RunFaultProofProgram(t, safeHeadNumber, testCfg.CheckResult, testCfg.InputParams...) + } + } + + matrix := helpers.NewMatrix[testCase]() + defer matrix.Run(gt) + + for _, ordering := range testCases { + matrix.AddTestCase( + fmt.Sprintf("HonestClaim-%s", ordering.name), + ordering, + helpers.NewForkMatrix(helpers.Granite, helpers.LatestFork), + runHoloceneDerivationTest, + helpers.ExpectNoError(), + ) + matrix.AddTestCase( + fmt.Sprintf("JunkClaim-%s", ordering.name), + ordering, + helpers.NewForkMatrix(helpers.Granite, helpers.LatestFork), + runHoloceneDerivationTest, + helpers.ExpectError(claim.ErrClaimNotValid), + helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), + ) + } +} diff --git a/op-e2e/actions/proofs/l1_lookback_test.go b/op-e2e/actions/proofs/l1_lookback_test.go index b40635ac55097..3e9c6fdcd52b9 100644 --- a/op-e2e/actions/proofs/l1_lookback_test.go +++ b/op-e2e/actions/proofs/l1_lookback_test.go @@ -73,11 +73,12 @@ func runL1LookbackTest_ReopenChannel(gt *testing.T, testCfg *helpers.TestCfg[any env.Miner.ActL1SafeNext(t) // Re-submit the first L2 block frame w/ different transaction data. - err := env.Batcher.Buffer(t, func(block *types.Block) { + err := env.Batcher.Buffer(t, func(block *types.Block) *types.Block { env.Bob.L2.ActResetTxOpts(t) env.Bob.L2.ActSetTxToAddr(&env.Dp.Addresses.Mallory) tx := env.Bob.L2.MakeTransaction(t) block.Transactions()[1] = tx + return block }) require.NoError(t, err) env.Batcher.ActL2BatchSubmit(t) diff --git a/op-e2e/actions/proofs/sequence_window_expiry_test.go b/op-e2e/actions/proofs/sequence_window_expiry_test.go index 3f5ca9562d4bf..cb702fe8eb6a4 100644 --- a/op-e2e/actions/proofs/sequence_window_expiry_test.go +++ b/op-e2e/actions/proofs/sequence_window_expiry_test.go @@ -132,17 +132,18 @@ func Test_ProgramAction_SequenceWindowExpired(gt *testing.T) { matrix := helpers.NewMatrix[any]() defer matrix.Run(gt) + forks := helpers.ForkMatrix{helpers.Granite, helpers.LatestFork} matrix.AddTestCase( "HonestClaim", nil, - helpers.LatestForkOnly, + forks, runSequenceWindowExpireTest, helpers.ExpectNoError(), ) matrix.AddTestCase( "JunkClaim", nil, - helpers.LatestForkOnly, + forks, runSequenceWindowExpireTest, helpers.ExpectError(claim.ErrClaimNotValid), helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), @@ -150,14 +151,14 @@ func Test_ProgramAction_SequenceWindowExpired(gt *testing.T) { matrix.AddTestCase( "ChannelCloseAfterWindowExpiry-HonestClaim", nil, - helpers.LatestForkOnly, + forks, runSequenceWindowExpire_ChannelCloseAfterWindowExpiry_Test, helpers.ExpectNoError(), ) matrix.AddTestCase( "ChannelCloseAfterWindowExpiry-JunkClaim", nil, - helpers.LatestForkOnly, + forks, runSequenceWindowExpire_ChannelCloseAfterWindowExpiry_Test, helpers.ExpectError(claim.ErrClaimNotValid), helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), diff --git a/op-e2e/actions/proofs/trace_extension_test.go b/op-e2e/actions/proofs/trace_extension_test.go new file mode 100644 index 0000000000000..7dac46594d2cf --- /dev/null +++ b/op-e2e/actions/proofs/trace_extension_test.go @@ -0,0 +1,68 @@ +package proofs + +import ( + "testing" + + actionsHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" + "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers" + "github.com/ethereum-optimism/optimism/op-program/client/claim" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func runSafeHeadTraceExtensionTest(gt *testing.T, testCfg *helpers.TestCfg[any]) { + t := actionsHelpers.NewDefaultTesting(gt) + env := helpers.NewL2FaultProofEnv(t, testCfg, helpers.NewTestParams(), helpers.NewBatcherCfg()) + + // Build an empty block on L2 + env.Sequencer.ActL2StartBlock(t) + env.Sequencer.ActL2EndBlock(t) + + // Instruct the batcher to submit the block to L1, and include the transaction. + env.Batcher.ActSubmitAll(t) + env.Miner.ActL1StartBlock(12)(t) + env.Miner.ActL1IncludeTxByHash(env.Batcher.LastSubmitted.Hash())(t) + env.Miner.ActL1EndBlock(t) + + // Instruct the sequencer to derive the L2 chain from the data on L1 that the batcher just posted. + env.Sequencer.ActL1HeadSignal(t) + env.Sequencer.ActL2PipelineFull(t) + + l1Head := env.Miner.L1Chain().CurrentBlock() + l2SafeHead := env.Engine.L2Chain().CurrentSafeBlock() + + // Ensure there is only 1 block on L1. + require.Equal(t, uint64(1), l1Head.Number.Uint64()) + // Ensure the block is marked as safe before we attempt to fault prove it. + require.Equal(t, uint64(1), l2SafeHead.Number.Uint64()) + + // Set claimed L2 block number to be past the actual safe head (still using the safe head output as the claim) + params := []helpers.FixtureInputParam{helpers.WithL2BlockNumber(l2SafeHead.Number.Uint64() + 1)} + params = append(params, testCfg.InputParams...) + env.RunFaultProofProgram(t, l2SafeHead.Number.Uint64(), testCfg.CheckResult, params...) +} + +// Test_ProgramAction_SafeHeadTraceExtension checks that op-program correctly handles the trace extension case where +// the claimed l2 block number is after the safe head. The honest actor should repeat the output root from the safe head +// and op-program should consider it valid even though the claimed l2 block number is not reached. +// Output roots other than from the safe head should be invalid if the claimed l2 block number is not reached. +func Test_ProgramAction_SafeHeadTraceExtension(gt *testing.T) { + matrix := helpers.NewMatrix[any]() + defer matrix.Run(gt) + + matrix.AddTestCase( + "HonestClaim", + nil, + helpers.LatestForkOnly, + runSafeHeadTraceExtensionTest, + helpers.ExpectNoError(), + ) + matrix.AddTestCase( + "JunkClaim", + nil, + helpers.LatestForkOnly, + runSafeHeadTraceExtensionTest, + helpers.ExpectError(claim.ErrClaimNotValid), + helpers.WithL2Claim(common.HexToHash("0xdeadbeef")), + ) +} diff --git a/op-e2e/actions/sync/sync_test.go b/op-e2e/actions/sync/sync_test.go index 95f55d63fcdd3..b9c29404dca56 100644 --- a/op-e2e/actions/sync/sync_test.go +++ b/op-e2e/actions/sync/sync_test.go @@ -618,8 +618,8 @@ func TestBackupUnsafeReorgForkChoiceNotInputError(gt *testing.T) { // check pendingSafe is reset require.Equal(t, sequencer.L2PendingSafe().Number, uint64(0)) // check backupUnsafe is applied - require.Equal(t, sequencer.L2Unsafe().Hash, targetUnsafeHeadHash) - require.Equal(t, sequencer.L2Unsafe().Number, uint64(5)) + require.Equal(t, uint64(5), sequencer.L2Unsafe().Number) + require.Equal(t, targetUnsafeHeadHash, sequencer.L2Unsafe().Hash) // safe head cannot be advanced because batch contained invalid blocks require.Equal(t, sequencer.L2Safe().Number, uint64(0)) } diff --git a/op-e2e/actions/upgrades/dencun_fork_test.go b/op-e2e/actions/upgrades/dencun_fork_test.go index adc995c0636d1..60f59abedcc6e 100644 --- a/op-e2e/actions/upgrades/dencun_fork_test.go +++ b/op-e2e/actions/upgrades/dencun_fork_test.go @@ -190,7 +190,7 @@ func aliceSimpleBlobTx(t helpers.Testing, dp *e2eutils.DeployParams) *types.Tran func newEngine(t helpers.Testing, sd *e2eutils.SetupData, log log.Logger) *helpers.L2Engine { jwtPath := e2eutils.WriteDefaultJWT(t) - return helpers.NewL2Engine(t, log, sd.L2Cfg, sd.RollupCfg.Genesis.L1, jwtPath) + return helpers.NewL2Engine(t, log, sd.L2Cfg, jwtPath) } // TestDencunBlobTxRPC tries to send a Blob tx to the L2 engine via RPC, it should not be accepted. diff --git a/op-e2e/actions/upgrades/helpers/config.go b/op-e2e/actions/upgrades/helpers/config.go index 1c844afd32658..c09d0be48b6c2 100644 --- a/op-e2e/actions/upgrades/helpers/config.go +++ b/op-e2e/actions/upgrades/helpers/config.go @@ -8,7 +8,6 @@ import ( // ApplyDeltaTimeOffset adjusts fork configuration to not conflict with the delta overrides func ApplyDeltaTimeOffset(dp *e2eutils.DeployParams, deltaTimeOffset *hexutil.Uint64) { dp.DeployConfig.L2GenesisDeltaTimeOffset = deltaTimeOffset - dp.DeployConfig.L2GenesisGraniteTimeOffset = nil // configure Ecotone to not be before Delta accidentally if dp.DeployConfig.L2GenesisEcotoneTimeOffset != nil { if deltaTimeOffset == nil { @@ -17,6 +16,7 @@ func ApplyDeltaTimeOffset(dp *e2eutils.DeployParams, deltaTimeOffset *hexutil.Ui dp.DeployConfig.L2GenesisEcotoneTimeOffset = deltaTimeOffset } } + // configure Fjord to not be before Delta accidentally if dp.DeployConfig.L2GenesisFjordTimeOffset != nil { if deltaTimeOffset == nil { @@ -25,4 +25,22 @@ func ApplyDeltaTimeOffset(dp *e2eutils.DeployParams, deltaTimeOffset *hexutil.Ui dp.DeployConfig.L2GenesisFjordTimeOffset = deltaTimeOffset } } + + // configure Granite to not be before Delta accidentally + if dp.DeployConfig.L2GenesisGraniteTimeOffset != nil { + if deltaTimeOffset == nil { + dp.DeployConfig.L2GenesisGraniteTimeOffset = nil + } else if *dp.DeployConfig.L2GenesisGraniteTimeOffset < *deltaTimeOffset { + dp.DeployConfig.L2GenesisGraniteTimeOffset = deltaTimeOffset + } + } + + // configure Holocene to not be before Delta accidentally + if dp.DeployConfig.L2GenesisHoloceneTimeOffset != nil { + if deltaTimeOffset == nil { + dp.DeployConfig.L2GenesisHoloceneTimeOffset = nil + } else if *dp.DeployConfig.L2GenesisHoloceneTimeOffset < *deltaTimeOffset { + dp.DeployConfig.L2GenesisHoloceneTimeOffset = deltaTimeOffset + } + } } diff --git a/op-e2e/actions/upgrades/holocene_fork_test.go b/op-e2e/actions/upgrades/holocene_fork_test.go new file mode 100644 index 0000000000000..12c0dcde6d194 --- /dev/null +++ b/op-e2e/actions/upgrades/holocene_fork_test.go @@ -0,0 +1,216 @@ +package upgrades + +import ( + "context" + "math/big" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/core/types" + + "github.com/ethereum-optimism/optimism/op-e2e/actions/helpers" + "github.com/ethereum-optimism/optimism/op-e2e/system/e2esys" + "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-service/testlog" +) + +func TestHoloceneActivationAtGenesis(gt *testing.T) { + t := helpers.NewDefaultTesting(gt) + env := helpers.SetupEnv(t, helpers.WithActiveGenesisFork(rollup.Holocene)) + + // Start op-nodes + env.Seq.ActL2PipelineFull(t) + env.Verifier.ActL2PipelineFull(t) + + // Verify Holocene is active at genesis + l2Head := env.Seq.L2Unsafe() + require.NotZero(t, l2Head.Hash) + require.True(t, env.SetupData.RollupCfg.IsHolocene(l2Head.Time), "Holocene should be active at genesis") + + // build empty L1 block + env.Miner.ActEmptyBlock(t) + + // Build L2 chain and advance safe head + env.Seq.ActL1HeadSignal(t) + env.Seq.ActBuildToL1Head(t) + + // verify in logs that correct stage got activated + recs := env.Logs.FindLogs(testlog.NewMessageContainsFilter("activating Holocene stage during reset"), testlog.NewAttributesFilter("role", e2esys.RoleSeq)) + require.Len(t, recs, 2) + recs = env.Logs.FindLogs(testlog.NewMessageContainsFilter("activating Holocene stage during reset"), testlog.NewAttributesFilter("role", e2esys.RoleVerif)) + require.Len(t, recs, 2) + + env.ActBatchSubmitAllAndMine(t) + + // verifier picks up the L2 chain that was submitted + env.Verifier.ActL1HeadSignal(t) + env.Verifier.ActL2PipelineFull(t) + require.Equal(t, env.Verifier.L2Safe(), env.Seq.L2Unsafe(), "verifier syncs from sequencer via L1") + require.NotEqual(t, env.Seq.L2Safe(), env.Seq.L2Unsafe(), "sequencer has not processed L1 yet") +} + +func TestHoloceneLateActivationAndReset(gt *testing.T) { + t := helpers.NewDefaultTesting(gt) + holoceneOffset := uint64(24) + env := helpers.SetupEnv(t, helpers.WithActiveFork(rollup.Holocene, holoceneOffset)) + + requireHoloceneTransformationLogs := func(role string, expNumLogs int) { + recs := env.Logs.FindLogs(testlog.NewMessageContainsFilter("transforming to Holocene"), testlog.NewAttributesFilter("role", role)) + require.Len(t, recs, expNumLogs) + if expNumLogs > 0 { + fqRecs := env.Logs.FindLogs(testlog.NewMessageFilter("FrameQueue: resetting with Holocene activation"), testlog.NewAttributesFilter("role", role)) + require.Len(t, fqRecs, 1) + } + } + + requirePreHoloceneActivationLogs := func(role string, expNumLogs int) { + recs := env.Logs.FindLogs(testlog.NewMessageContainsFilter("activating pre-Holocene stage during reset"), testlog.NewAttributesFilter("role", role)) + require.Len(t, recs, expNumLogs) + } + + // Start op-nodes + env.Seq.ActL2PipelineFull(t) + env.Verifier.ActL2PipelineFull(t) + + // Verify Holocene is not active at genesis yet + l2Head := env.Seq.L2Unsafe() + require.NotZero(t, l2Head.Hash) + require.True(t, env.SetupData.RollupCfg.IsGranite(l2Head.Time), "Granite should be active at genesis") + require.False(t, env.SetupData.RollupCfg.IsHolocene(l2Head.Time), "Holocene should not be active at genesis") + + requirePreHoloceneActivationLogs(e2esys.RoleSeq, 2) + requirePreHoloceneActivationLogs(e2esys.RoleVerif, 2) + // Verify no stage transformations took place yet + requireHoloceneTransformationLogs(e2esys.RoleSeq, 0) + requireHoloceneTransformationLogs(e2esys.RoleVerif, 0) + + env.Seq.ActL2EmptyBlock(t) + l1PreHolocene := env.ActBatchSubmitAllAndMine(t) + require.False(t, env.SetupData.RollupCfg.IsHolocene(l1PreHolocene.Time()), + "Holocene should not be active at the first L1 inclusion block") + + // Build a few L2 blocks. We only need the L1 inclusion to advance past Holocene and Holocene + // shouldn't activate with L2 time. + env.Seq.ActBuildL2ToHolocene(t) + + // verify in logs that stage transformations hasn't happened yet, activates by L1 inclusion block + requireHoloceneTransformationLogs(e2esys.RoleSeq, 0) + requireHoloceneTransformationLogs(e2esys.RoleVerif, 0) + + // Submit L2 + l1Head := env.ActBatchSubmitAllAndMine(t) + require.True(t, env.SetupData.RollupCfg.IsHolocene(l1Head.Time())) + + // verifier picks up the L2 chain that was submitted + env.Verifier.ActL1HeadSignal(t) + env.Verifier.ActL2PipelineFull(t) + l2Safe := env.Verifier.L2Safe() + require.Equal(t, l2Safe, env.Seq.L2Unsafe(), "verifier syncs from sequencer via L1") + require.NotEqual(t, env.Seq.L2Safe(), env.Seq.L2Unsafe(), "sequencer has not processed L1 yet") + require.True(t, env.SetupData.RollupCfg.IsHolocene(l2Safe.Time), "Holocene should now be active") + requireHoloceneTransformationLogs(e2esys.RoleSeq, 0) + requireHoloceneTransformationLogs(e2esys.RoleVerif, 2) + + // sequencer also picks up L2 safe chain + env.Seq.ActL1HeadSignal(t) + env.Seq.ActL2PipelineFull(t) + requireHoloceneTransformationLogs(e2esys.RoleSeq, 2) + require.Equal(t, env.Seq.L2Safe(), env.Seq.L2Unsafe(), "sequencer has processed L1") + + // reorg L1 without batch submission + env.Miner.ActL1RewindToParent(t) + env.Miner.ActEmptyBlock(t) + env.Miner.ActEmptyBlock(t) + + env.Seq.ActL1HeadSignal(t) + env.Verifier.ActL1HeadSignal(t) + env.Seq.ActL2PipelineFull(t) + env.Verifier.ActL2PipelineFull(t) + + // duplicate activation logs + requirePreHoloceneActivationLogs(e2esys.RoleSeq, 4) + requirePreHoloceneActivationLogs(e2esys.RoleVerif, 4) +} + +func TestHoloceneInvalidPayload(gt *testing.T) { + t := helpers.NewDefaultTesting(gt) + env := helpers.SetupEnv(t, helpers.WithActiveGenesisFork(rollup.Holocene)) + ctx := context.Background() + + requireDepositOnlyLogs := func(role string, expNumLogs int) { + t.Helper() + recs := env.Logs.FindLogs(testlog.NewMessageContainsFilter("deposits-only attributes"), testlog.NewAttributesFilter("role", role)) + require.Len(t, recs, expNumLogs) + } + + // Start op-nodes + env.Seq.ActL2PipelineFull(t) + + // generate and batch buffer two empty blocks + env.Seq.ActL2EmptyBlock(t) // 1 - genesis is 0 + env.Batcher.ActL2BatchBuffer(t) + env.Seq.ActL2EmptyBlock(t) // 2 + env.Batcher.ActL2BatchBuffer(t) + + // send and include a single transaction + env.Alice.L2.ActResetTxOpts(t) + env.Alice.L2.ActSetTxToAddr(&env.DeployParams.Addresses.Bob) + env.Alice.L2.ActMakeTx(t) + + env.Seq.ActL2StartBlock(t) + env.SeqEngine.ActL2IncludeTx(env.Alice.Address())(t) + env.Seq.ActL2EndBlock(t) // 3 + env.Alice.L2.ActCheckReceiptStatusOfLastTx(true)(t) + l2Unsafe := env.Seq.L2Unsafe() + const invalidNum = 3 + require.EqualValues(t, invalidNum, l2Unsafe.Number) + b, err := env.SeqEngine.EthClient().BlockByNumber(ctx, big.NewInt(invalidNum)) + require.NoError(t, err) + require.Len(t, b.Transactions(), 2) + + // buffer into the batcher, invalidating the tx via signature zeroing + env.Batcher.ActL2BatchBuffer(t, func(block *types.Block) *types.Block { + // Replace the tx with one that has a bad signature. + txs := block.Transactions() + newTx, err := txs[1].WithSignature(env.Alice.L2.Signer(), make([]byte, 65)) + require.NoError(t, err) + txs[1] = newTx + return block + }) + + // generate two more empty blocks + env.Seq.ActL2EmptyBlock(t) // 4 + env.Seq.ActL2EmptyBlock(t) // 5 + require.EqualValues(t, 5, env.Seq.L2Unsafe().Number) + + // submit it all + env.ActBatchSubmitAllAndMine(t) + + // derive chain on sequencer + env.Seq.ActL1HeadSignal(t) + env.Seq.ActL2PipelineFull(t) + + l2Safe := env.Seq.L2Safe() + require.EqualValues(t, invalidNum, l2Safe.Number) + require.NotEqual(t, l2Safe.Hash, l2Unsafe.Hash, // old L2Unsafe above + "block-3 should have been replaced by deposit-only version") + requireDepositOnlyLogs(e2esys.RoleSeq, 2) + require.Equal(t, l2Safe, env.Seq.L2Unsafe(), "unsafe chain should have reorg'd") + b, err = env.SeqEngine.EthClient().BlockByNumber(ctx, big.NewInt(invalidNum)) + require.NoError(t, err) + require.Len(t, b.Transactions(), 1) + + // test that building on top of reorg'd chain and deriving further works + + env.Seq.ActL2EmptyBlock(t) // 4 + env.Seq.ActL2EmptyBlock(t) // 5 + l2Unsafe = env.Seq.L2Unsafe() + require.EqualValues(t, 5, l2Unsafe.Number) + + env.Batcher.Reset() // need to reset batcher to become aware of reorg + env.ActBatchSubmitAllAndMine(t) + env.Seq.ActL1HeadSignal(t) + env.Seq.ActL2PipelineFull(t) + require.Equal(t, l2Unsafe, env.Seq.L2Safe()) +} diff --git a/op-e2e/bindings/delayedvetoable.go b/op-e2e/bindings/delayedvetoable.go deleted file mode 100644 index 989bb0278d205..0000000000000 --- a/op-e2e/bindings/delayedvetoable.go +++ /dev/null @@ -1,928 +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 -) - -// DelayedVetoableMetaData contains all meta data concerning the DelayedVetoable contract. -var DelayedVetoableMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"vetoer_\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"initiator_\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"target_\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operatingDelay_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"fallback\",\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"delay\",\"inputs\":[],\"outputs\":[{\"name\":\"delay_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"initiator\",\"inputs\":[],\"outputs\":[{\"name\":\"initiator_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"queuedAt\",\"inputs\":[{\"name\":\"callHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"queuedAt_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"target\",\"inputs\":[],\"outputs\":[{\"name\":\"target_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"vetoer\",\"inputs\":[],\"outputs\":[{\"name\":\"vetoer_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"DelayActivated\",\"inputs\":[{\"name\":\"delay\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Forwarded\",\"inputs\":[{\"name\":\"callHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"data\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initiated\",\"inputs\":[{\"name\":\"callHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"data\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Vetoed\",\"inputs\":[{\"name\":\"callHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"data\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"ForwardingEarly\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"Unauthorized\",\"inputs\":[{\"name\":\"expected\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"actual\",\"type\":\"address\",\"internalType\":\"address\"}]}]", - Bin: "0x61010060405234801561001157600080fd5b506040516108ff3803806108ff8339810160408190526100309161006e565b6001600160a01b0393841660a05291831660c05290911660805260e0526100b9565b80516001600160a01b038116811461006957600080fd5b919050565b6000806000806080858703121561008457600080fd5b61008d85610052565b935061009b60208601610052565b92506100a960408601610052565b6060959095015193969295505050565b60805160a05160c05160e0516107dc610123600039600061023f01526000818161015f01528181610205015281816102cd0152818161045801526105050152600081816101a001528181610384015261059d01526000818161057101526105ff01526107dc6000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063b912de5d11610050578063b912de5d14610111578063d4b8399214610124578063d8bff4401461012c57610072565b806354fd4d501461007c5780635c39fcc1146100ce5780636a42b8f8146100fb575b61007a610134565b005b6100b86040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516100c591906106a7565b60405180910390f35b6100d66104fb565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c5565b610103610532565b6040519081526020016100c5565b61010361011f36600461071a565b610540565b6100d6610567565b6100d6610593565b361580156101425750600054155b15610298573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148015906101c357503373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614155b1561023d576040517f295a81c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660048201523360248201526044015b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000060008190556040519081527febf28bfb587e28dfffd9173cf71c32ba5d3f0544a0117b5539c9b274a5bba2a89060200160405180910390a1565b600080366040516102aa929190610733565b60405190819003902090503373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161480156103065750600081815260016020526040902054155b1561036c5760005460000361031e5761031e816105bf565b6000818152600160205260408082204290555182917f87a332a414acbc7da074543639ce7ae02ff1ea72e88379da9f261b080beb5a139161036191903690610743565b60405180910390a250565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161480156103be575060008181526001602052604090205415155b15610406576000818152600160205260408082208290555182917fbede6852c1d97d93ff557f676de76670cd0dec861e7fe8beb13aa0ba2b0ab0409161036191903690610743565b600081815260016020526040812054900361048b576040517f295a81c100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166004820152336024820152604401610234565b60008054828252600160205260409091205442916104a891610790565b11156104e0576040517f43dc986d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818152600160205260408120556104f8816105bf565b50565b60003361052757507f000000000000000000000000000000000000000000000000000000000000000090565b61052f610134565b90565b600033610527575060005490565b60003361055a575060009081526001602052604090205490565b610562610134565b919050565b60003361052757507f000000000000000000000000000000000000000000000000000000000000000090565b60003361052757507f000000000000000000000000000000000000000000000000000000000000000090565b807f4c109d85bcd0bb5c735b4be850953d652afe4cd9aa2e0b1426a65a4dcb2e12296000366040516105f2929190610743565b60405180910390a26000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16600036604051610645929190610733565b6000604051808303816000865af19150503d8060008114610682576040519150601f19603f3d011682016040523d82523d6000602084013e610687565b606091505b50909250905081151560010361069f57805160208201f35b805160208201fd5b600060208083528351808285015260005b818110156106d4578581018301518582016040015282016106b8565b818111156106e6576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b60006020828403121561072c57600080fd5b5035919050565b8183823760009101908152919050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b600082198211156107ca577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b50019056fea164736f6c634300080f000a", -} - -// DelayedVetoableABI is the input ABI used to generate the binding from. -// Deprecated: Use DelayedVetoableMetaData.ABI instead. -var DelayedVetoableABI = DelayedVetoableMetaData.ABI - -// DelayedVetoableBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use DelayedVetoableMetaData.Bin instead. -var DelayedVetoableBin = DelayedVetoableMetaData.Bin - -// DeployDelayedVetoable deploys a new Ethereum contract, binding an instance of DelayedVetoable to it. -func DeployDelayedVetoable(auth *bind.TransactOpts, backend bind.ContractBackend, vetoer_ common.Address, initiator_ common.Address, target_ common.Address, operatingDelay_ *big.Int) (common.Address, *types.Transaction, *DelayedVetoable, error) { - parsed, err := DelayedVetoableMetaData.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(DelayedVetoableBin), backend, vetoer_, initiator_, target_, operatingDelay_) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &DelayedVetoable{DelayedVetoableCaller: DelayedVetoableCaller{contract: contract}, DelayedVetoableTransactor: DelayedVetoableTransactor{contract: contract}, DelayedVetoableFilterer: DelayedVetoableFilterer{contract: contract}}, nil -} - -// DelayedVetoable is an auto generated Go binding around an Ethereum contract. -type DelayedVetoable struct { - DelayedVetoableCaller // Read-only binding to the contract - DelayedVetoableTransactor // Write-only binding to the contract - DelayedVetoableFilterer // Log filterer for contract events -} - -// DelayedVetoableCaller is an auto generated read-only Go binding around an Ethereum contract. -type DelayedVetoableCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// DelayedVetoableTransactor is an auto generated write-only Go binding around an Ethereum contract. -type DelayedVetoableTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// DelayedVetoableFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type DelayedVetoableFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// DelayedVetoableSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type DelayedVetoableSession struct { - Contract *DelayedVetoable // 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 -} - -// DelayedVetoableCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type DelayedVetoableCallerSession struct { - Contract *DelayedVetoableCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// DelayedVetoableTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type DelayedVetoableTransactorSession struct { - Contract *DelayedVetoableTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// DelayedVetoableRaw is an auto generated low-level Go binding around an Ethereum contract. -type DelayedVetoableRaw struct { - Contract *DelayedVetoable // Generic contract binding to access the raw methods on -} - -// DelayedVetoableCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type DelayedVetoableCallerRaw struct { - Contract *DelayedVetoableCaller // Generic read-only contract binding to access the raw methods on -} - -// DelayedVetoableTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type DelayedVetoableTransactorRaw struct { - Contract *DelayedVetoableTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewDelayedVetoable creates a new instance of DelayedVetoable, bound to a specific deployed contract. -func NewDelayedVetoable(address common.Address, backend bind.ContractBackend) (*DelayedVetoable, error) { - contract, err := bindDelayedVetoable(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &DelayedVetoable{DelayedVetoableCaller: DelayedVetoableCaller{contract: contract}, DelayedVetoableTransactor: DelayedVetoableTransactor{contract: contract}, DelayedVetoableFilterer: DelayedVetoableFilterer{contract: contract}}, nil -} - -// NewDelayedVetoableCaller creates a new read-only instance of DelayedVetoable, bound to a specific deployed contract. -func NewDelayedVetoableCaller(address common.Address, caller bind.ContractCaller) (*DelayedVetoableCaller, error) { - contract, err := bindDelayedVetoable(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &DelayedVetoableCaller{contract: contract}, nil -} - -// NewDelayedVetoableTransactor creates a new write-only instance of DelayedVetoable, bound to a specific deployed contract. -func NewDelayedVetoableTransactor(address common.Address, transactor bind.ContractTransactor) (*DelayedVetoableTransactor, error) { - contract, err := bindDelayedVetoable(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &DelayedVetoableTransactor{contract: contract}, nil -} - -// NewDelayedVetoableFilterer creates a new log filterer instance of DelayedVetoable, bound to a specific deployed contract. -func NewDelayedVetoableFilterer(address common.Address, filterer bind.ContractFilterer) (*DelayedVetoableFilterer, error) { - contract, err := bindDelayedVetoable(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &DelayedVetoableFilterer{contract: contract}, nil -} - -// bindDelayedVetoable binds a generic wrapper to an already deployed contract. -func bindDelayedVetoable(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(DelayedVetoableABI)) - 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 (_DelayedVetoable *DelayedVetoableRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _DelayedVetoable.Contract.DelayedVetoableCaller.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 (_DelayedVetoable *DelayedVetoableRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _DelayedVetoable.Contract.DelayedVetoableTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_DelayedVetoable *DelayedVetoableRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _DelayedVetoable.Contract.DelayedVetoableTransactor.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 (_DelayedVetoable *DelayedVetoableCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _DelayedVetoable.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 (_DelayedVetoable *DelayedVetoableTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _DelayedVetoable.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_DelayedVetoable *DelayedVetoableTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _DelayedVetoable.Contract.contract.Transact(opts, method, params...) -} - -// Version is a free data retrieval call binding the contract method 0x54fd4d50. -// -// Solidity: function version() view returns(string) -func (_DelayedVetoable *DelayedVetoableCaller) Version(opts *bind.CallOpts) (string, error) { - var out []interface{} - err := _DelayedVetoable.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() view returns(string) -func (_DelayedVetoable *DelayedVetoableSession) Version() (string, error) { - return _DelayedVetoable.Contract.Version(&_DelayedVetoable.CallOpts) -} - -// Version is a free data retrieval call binding the contract method 0x54fd4d50. -// -// Solidity: function version() view returns(string) -func (_DelayedVetoable *DelayedVetoableCallerSession) Version() (string, error) { - return _DelayedVetoable.Contract.Version(&_DelayedVetoable.CallOpts) -} - -// Delay is a paid mutator transaction binding the contract method 0x6a42b8f8. -// -// Solidity: function delay() returns(uint256 delay_) -func (_DelayedVetoable *DelayedVetoableTransactor) Delay(opts *bind.TransactOpts) (*types.Transaction, error) { - return _DelayedVetoable.contract.Transact(opts, "delay") -} - -// Delay is a paid mutator transaction binding the contract method 0x6a42b8f8. -// -// Solidity: function delay() returns(uint256 delay_) -func (_DelayedVetoable *DelayedVetoableSession) Delay() (*types.Transaction, error) { - return _DelayedVetoable.Contract.Delay(&_DelayedVetoable.TransactOpts) -} - -// Delay is a paid mutator transaction binding the contract method 0x6a42b8f8. -// -// Solidity: function delay() returns(uint256 delay_) -func (_DelayedVetoable *DelayedVetoableTransactorSession) Delay() (*types.Transaction, error) { - return _DelayedVetoable.Contract.Delay(&_DelayedVetoable.TransactOpts) -} - -// Initiator is a paid mutator transaction binding the contract method 0x5c39fcc1. -// -// Solidity: function initiator() returns(address initiator_) -func (_DelayedVetoable *DelayedVetoableTransactor) Initiator(opts *bind.TransactOpts) (*types.Transaction, error) { - return _DelayedVetoable.contract.Transact(opts, "initiator") -} - -// Initiator is a paid mutator transaction binding the contract method 0x5c39fcc1. -// -// Solidity: function initiator() returns(address initiator_) -func (_DelayedVetoable *DelayedVetoableSession) Initiator() (*types.Transaction, error) { - return _DelayedVetoable.Contract.Initiator(&_DelayedVetoable.TransactOpts) -} - -// Initiator is a paid mutator transaction binding the contract method 0x5c39fcc1. -// -// Solidity: function initiator() returns(address initiator_) -func (_DelayedVetoable *DelayedVetoableTransactorSession) Initiator() (*types.Transaction, error) { - return _DelayedVetoable.Contract.Initiator(&_DelayedVetoable.TransactOpts) -} - -// QueuedAt is a paid mutator transaction binding the contract method 0xb912de5d. -// -// Solidity: function queuedAt(bytes32 callHash) returns(uint256 queuedAt_) -func (_DelayedVetoable *DelayedVetoableTransactor) QueuedAt(opts *bind.TransactOpts, callHash [32]byte) (*types.Transaction, error) { - return _DelayedVetoable.contract.Transact(opts, "queuedAt", callHash) -} - -// QueuedAt is a paid mutator transaction binding the contract method 0xb912de5d. -// -// Solidity: function queuedAt(bytes32 callHash) returns(uint256 queuedAt_) -func (_DelayedVetoable *DelayedVetoableSession) QueuedAt(callHash [32]byte) (*types.Transaction, error) { - return _DelayedVetoable.Contract.QueuedAt(&_DelayedVetoable.TransactOpts, callHash) -} - -// QueuedAt is a paid mutator transaction binding the contract method 0xb912de5d. -// -// Solidity: function queuedAt(bytes32 callHash) returns(uint256 queuedAt_) -func (_DelayedVetoable *DelayedVetoableTransactorSession) QueuedAt(callHash [32]byte) (*types.Transaction, error) { - return _DelayedVetoable.Contract.QueuedAt(&_DelayedVetoable.TransactOpts, callHash) -} - -// Target is a paid mutator transaction binding the contract method 0xd4b83992. -// -// Solidity: function target() returns(address target_) -func (_DelayedVetoable *DelayedVetoableTransactor) Target(opts *bind.TransactOpts) (*types.Transaction, error) { - return _DelayedVetoable.contract.Transact(opts, "target") -} - -// Target is a paid mutator transaction binding the contract method 0xd4b83992. -// -// Solidity: function target() returns(address target_) -func (_DelayedVetoable *DelayedVetoableSession) Target() (*types.Transaction, error) { - return _DelayedVetoable.Contract.Target(&_DelayedVetoable.TransactOpts) -} - -// Target is a paid mutator transaction binding the contract method 0xd4b83992. -// -// Solidity: function target() returns(address target_) -func (_DelayedVetoable *DelayedVetoableTransactorSession) Target() (*types.Transaction, error) { - return _DelayedVetoable.Contract.Target(&_DelayedVetoable.TransactOpts) -} - -// Vetoer is a paid mutator transaction binding the contract method 0xd8bff440. -// -// Solidity: function vetoer() returns(address vetoer_) -func (_DelayedVetoable *DelayedVetoableTransactor) Vetoer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _DelayedVetoable.contract.Transact(opts, "vetoer") -} - -// Vetoer is a paid mutator transaction binding the contract method 0xd8bff440. -// -// Solidity: function vetoer() returns(address vetoer_) -func (_DelayedVetoable *DelayedVetoableSession) Vetoer() (*types.Transaction, error) { - return _DelayedVetoable.Contract.Vetoer(&_DelayedVetoable.TransactOpts) -} - -// Vetoer is a paid mutator transaction binding the contract method 0xd8bff440. -// -// Solidity: function vetoer() returns(address vetoer_) -func (_DelayedVetoable *DelayedVetoableTransactorSession) Vetoer() (*types.Transaction, error) { - return _DelayedVetoable.Contract.Vetoer(&_DelayedVetoable.TransactOpts) -} - -// Fallback is a paid mutator transaction binding the contract fallback function. -// -// Solidity: fallback() returns() -func (_DelayedVetoable *DelayedVetoableTransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { - return _DelayedVetoable.contract.RawTransact(opts, calldata) -} - -// Fallback is a paid mutator transaction binding the contract fallback function. -// -// Solidity: fallback() returns() -func (_DelayedVetoable *DelayedVetoableSession) Fallback(calldata []byte) (*types.Transaction, error) { - return _DelayedVetoable.Contract.Fallback(&_DelayedVetoable.TransactOpts, calldata) -} - -// Fallback is a paid mutator transaction binding the contract fallback function. -// -// Solidity: fallback() returns() -func (_DelayedVetoable *DelayedVetoableTransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { - return _DelayedVetoable.Contract.Fallback(&_DelayedVetoable.TransactOpts, calldata) -} - -// DelayedVetoableDelayActivatedIterator is returned from FilterDelayActivated and is used to iterate over the raw logs and unpacked data for DelayActivated events raised by the DelayedVetoable contract. -type DelayedVetoableDelayActivatedIterator struct { - Event *DelayedVetoableDelayActivated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *DelayedVetoableDelayActivatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(DelayedVetoableDelayActivated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(DelayedVetoableDelayActivated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *DelayedVetoableDelayActivatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *DelayedVetoableDelayActivatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// DelayedVetoableDelayActivated represents a DelayActivated event raised by the DelayedVetoable contract. -type DelayedVetoableDelayActivated struct { - Delay *big.Int - Raw types.Log // Blockchain specific contextual infos -} - -// FilterDelayActivated is a free log retrieval operation binding the contract event 0xebf28bfb587e28dfffd9173cf71c32ba5d3f0544a0117b5539c9b274a5bba2a8. -// -// Solidity: event DelayActivated(uint256 delay) -func (_DelayedVetoable *DelayedVetoableFilterer) FilterDelayActivated(opts *bind.FilterOpts) (*DelayedVetoableDelayActivatedIterator, error) { - - logs, sub, err := _DelayedVetoable.contract.FilterLogs(opts, "DelayActivated") - if err != nil { - return nil, err - } - return &DelayedVetoableDelayActivatedIterator{contract: _DelayedVetoable.contract, event: "DelayActivated", logs: logs, sub: sub}, nil -} - -// WatchDelayActivated is a free log subscription operation binding the contract event 0xebf28bfb587e28dfffd9173cf71c32ba5d3f0544a0117b5539c9b274a5bba2a8. -// -// Solidity: event DelayActivated(uint256 delay) -func (_DelayedVetoable *DelayedVetoableFilterer) WatchDelayActivated(opts *bind.WatchOpts, sink chan<- *DelayedVetoableDelayActivated) (event.Subscription, error) { - - logs, sub, err := _DelayedVetoable.contract.WatchLogs(opts, "DelayActivated") - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(DelayedVetoableDelayActivated) - if err := _DelayedVetoable.contract.UnpackLog(event, "DelayActivated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseDelayActivated is a log parse operation binding the contract event 0xebf28bfb587e28dfffd9173cf71c32ba5d3f0544a0117b5539c9b274a5bba2a8. -// -// Solidity: event DelayActivated(uint256 delay) -func (_DelayedVetoable *DelayedVetoableFilterer) ParseDelayActivated(log types.Log) (*DelayedVetoableDelayActivated, error) { - event := new(DelayedVetoableDelayActivated) - if err := _DelayedVetoable.contract.UnpackLog(event, "DelayActivated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// DelayedVetoableForwardedIterator is returned from FilterForwarded and is used to iterate over the raw logs and unpacked data for Forwarded events raised by the DelayedVetoable contract. -type DelayedVetoableForwardedIterator struct { - Event *DelayedVetoableForwarded // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *DelayedVetoableForwardedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(DelayedVetoableForwarded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(DelayedVetoableForwarded) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *DelayedVetoableForwardedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *DelayedVetoableForwardedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// DelayedVetoableForwarded represents a Forwarded event raised by the DelayedVetoable contract. -type DelayedVetoableForwarded struct { - CallHash [32]byte - Data []byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterForwarded is a free log retrieval operation binding the contract event 0x4c109d85bcd0bb5c735b4be850953d652afe4cd9aa2e0b1426a65a4dcb2e1229. -// -// Solidity: event Forwarded(bytes32 indexed callHash, bytes data) -func (_DelayedVetoable *DelayedVetoableFilterer) FilterForwarded(opts *bind.FilterOpts, callHash [][32]byte) (*DelayedVetoableForwardedIterator, error) { - - var callHashRule []interface{} - for _, callHashItem := range callHash { - callHashRule = append(callHashRule, callHashItem) - } - - logs, sub, err := _DelayedVetoable.contract.FilterLogs(opts, "Forwarded", callHashRule) - if err != nil { - return nil, err - } - return &DelayedVetoableForwardedIterator{contract: _DelayedVetoable.contract, event: "Forwarded", logs: logs, sub: sub}, nil -} - -// WatchForwarded is a free log subscription operation binding the contract event 0x4c109d85bcd0bb5c735b4be850953d652afe4cd9aa2e0b1426a65a4dcb2e1229. -// -// Solidity: event Forwarded(bytes32 indexed callHash, bytes data) -func (_DelayedVetoable *DelayedVetoableFilterer) WatchForwarded(opts *bind.WatchOpts, sink chan<- *DelayedVetoableForwarded, callHash [][32]byte) (event.Subscription, error) { - - var callHashRule []interface{} - for _, callHashItem := range callHash { - callHashRule = append(callHashRule, callHashItem) - } - - logs, sub, err := _DelayedVetoable.contract.WatchLogs(opts, "Forwarded", callHashRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(DelayedVetoableForwarded) - if err := _DelayedVetoable.contract.UnpackLog(event, "Forwarded", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseForwarded is a log parse operation binding the contract event 0x4c109d85bcd0bb5c735b4be850953d652afe4cd9aa2e0b1426a65a4dcb2e1229. -// -// Solidity: event Forwarded(bytes32 indexed callHash, bytes data) -func (_DelayedVetoable *DelayedVetoableFilterer) ParseForwarded(log types.Log) (*DelayedVetoableForwarded, error) { - event := new(DelayedVetoableForwarded) - if err := _DelayedVetoable.contract.UnpackLog(event, "Forwarded", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// DelayedVetoableInitiatedIterator is returned from FilterInitiated and is used to iterate over the raw logs and unpacked data for Initiated events raised by the DelayedVetoable contract. -type DelayedVetoableInitiatedIterator struct { - Event *DelayedVetoableInitiated // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *DelayedVetoableInitiatedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(DelayedVetoableInitiated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(DelayedVetoableInitiated) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *DelayedVetoableInitiatedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *DelayedVetoableInitiatedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// DelayedVetoableInitiated represents a Initiated event raised by the DelayedVetoable contract. -type DelayedVetoableInitiated struct { - CallHash [32]byte - Data []byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterInitiated is a free log retrieval operation binding the contract event 0x87a332a414acbc7da074543639ce7ae02ff1ea72e88379da9f261b080beb5a13. -// -// Solidity: event Initiated(bytes32 indexed callHash, bytes data) -func (_DelayedVetoable *DelayedVetoableFilterer) FilterInitiated(opts *bind.FilterOpts, callHash [][32]byte) (*DelayedVetoableInitiatedIterator, error) { - - var callHashRule []interface{} - for _, callHashItem := range callHash { - callHashRule = append(callHashRule, callHashItem) - } - - logs, sub, err := _DelayedVetoable.contract.FilterLogs(opts, "Initiated", callHashRule) - if err != nil { - return nil, err - } - return &DelayedVetoableInitiatedIterator{contract: _DelayedVetoable.contract, event: "Initiated", logs: logs, sub: sub}, nil -} - -// WatchInitiated is a free log subscription operation binding the contract event 0x87a332a414acbc7da074543639ce7ae02ff1ea72e88379da9f261b080beb5a13. -// -// Solidity: event Initiated(bytes32 indexed callHash, bytes data) -func (_DelayedVetoable *DelayedVetoableFilterer) WatchInitiated(opts *bind.WatchOpts, sink chan<- *DelayedVetoableInitiated, callHash [][32]byte) (event.Subscription, error) { - - var callHashRule []interface{} - for _, callHashItem := range callHash { - callHashRule = append(callHashRule, callHashItem) - } - - logs, sub, err := _DelayedVetoable.contract.WatchLogs(opts, "Initiated", callHashRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(DelayedVetoableInitiated) - if err := _DelayedVetoable.contract.UnpackLog(event, "Initiated", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseInitiated is a log parse operation binding the contract event 0x87a332a414acbc7da074543639ce7ae02ff1ea72e88379da9f261b080beb5a13. -// -// Solidity: event Initiated(bytes32 indexed callHash, bytes data) -func (_DelayedVetoable *DelayedVetoableFilterer) ParseInitiated(log types.Log) (*DelayedVetoableInitiated, error) { - event := new(DelayedVetoableInitiated) - if err := _DelayedVetoable.contract.UnpackLog(event, "Initiated", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} - -// DelayedVetoableVetoedIterator is returned from FilterVetoed and is used to iterate over the raw logs and unpacked data for Vetoed events raised by the DelayedVetoable contract. -type DelayedVetoableVetoedIterator struct { - Event *DelayedVetoableVetoed // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *DelayedVetoableVetoedIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(DelayedVetoableVetoed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(DelayedVetoableVetoed) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *DelayedVetoableVetoedIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *DelayedVetoableVetoedIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// DelayedVetoableVetoed represents a Vetoed event raised by the DelayedVetoable contract. -type DelayedVetoableVetoed struct { - CallHash [32]byte - Data []byte - Raw types.Log // Blockchain specific contextual infos -} - -// FilterVetoed is a free log retrieval operation binding the contract event 0xbede6852c1d97d93ff557f676de76670cd0dec861e7fe8beb13aa0ba2b0ab040. -// -// Solidity: event Vetoed(bytes32 indexed callHash, bytes data) -func (_DelayedVetoable *DelayedVetoableFilterer) FilterVetoed(opts *bind.FilterOpts, callHash [][32]byte) (*DelayedVetoableVetoedIterator, error) { - - var callHashRule []interface{} - for _, callHashItem := range callHash { - callHashRule = append(callHashRule, callHashItem) - } - - logs, sub, err := _DelayedVetoable.contract.FilterLogs(opts, "Vetoed", callHashRule) - if err != nil { - return nil, err - } - return &DelayedVetoableVetoedIterator{contract: _DelayedVetoable.contract, event: "Vetoed", logs: logs, sub: sub}, nil -} - -// WatchVetoed is a free log subscription operation binding the contract event 0xbede6852c1d97d93ff557f676de76670cd0dec861e7fe8beb13aa0ba2b0ab040. -// -// Solidity: event Vetoed(bytes32 indexed callHash, bytes data) -func (_DelayedVetoable *DelayedVetoableFilterer) WatchVetoed(opts *bind.WatchOpts, sink chan<- *DelayedVetoableVetoed, callHash [][32]byte) (event.Subscription, error) { - - var callHashRule []interface{} - for _, callHashItem := range callHash { - callHashRule = append(callHashRule, callHashItem) - } - - logs, sub, err := _DelayedVetoable.contract.WatchLogs(opts, "Vetoed", callHashRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(DelayedVetoableVetoed) - if err := _DelayedVetoable.contract.UnpackLog(event, "Vetoed", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -} - -// ParseVetoed is a log parse operation binding the contract event 0xbede6852c1d97d93ff557f676de76670cd0dec861e7fe8beb13aa0ba2b0ab040. -// -// Solidity: event Vetoed(bytes32 indexed callHash, bytes data) -func (_DelayedVetoable *DelayedVetoableFilterer) ParseVetoed(log types.Log) (*DelayedVetoableVetoed, error) { - event := new(DelayedVetoableVetoed) - if err := _DelayedVetoable.contract.UnpackLog(event, "Vetoed", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil -} diff --git a/op-e2e/e2e.go b/op-e2e/e2e.go index 54533cf4fef9f..f603b97f6fbda 100644 --- a/op-e2e/e2e.go +++ b/op-e2e/e2e.go @@ -52,6 +52,13 @@ func UsesCannon(t e2eutils.TestingBase) { } } +// IsSlow indicates that the test is too expensive to run on the main CI workflow +func IsSlow(t e2eutils.TestingBase) { + if os.Getenv("OP_E2E_SKIP_SLOW_TEST") == "true" { + t.Skip("Skipping slow test") + } +} + type executorInfo struct { total uint64 idx uint64 diff --git a/op-e2e/e2eutils/disputegame/helper.go b/op-e2e/e2eutils/disputegame/helper.go index 07ee4c659ff90..658eedffc5145 100644 --- a/op-e2e/e2eutils/disputegame/helper.go +++ b/op-e2e/e2eutils/disputegame/helper.go @@ -291,7 +291,7 @@ func (h *FactoryHelper) WaitForBlock(l2Node string, l2BlockNumber uint64, cfg *G l2Client := h.System.NodeClient(l2Node) if cfg.allowUnsafe { - _, err := geth.WaitForBlock(new(big.Int).SetUint64(l2BlockNumber), l2Client, 1*time.Minute) + _, err := geth.WaitForBlock(new(big.Int).SetUint64(l2BlockNumber), l2Client, geth.WithAbsoluteTimeout(time.Minute)) h.Require.NoErrorf(err, "Block number %v did not become unsafe", l2BlockNumber) } else { _, err := geth.WaitForBlockToBeSafe(new(big.Int).SetUint64(l2BlockNumber), l2Client, 1*time.Minute) diff --git a/op-e2e/e2eutils/fakebeacon/blobs.go b/op-e2e/e2eutils/fakebeacon/blobs.go index a96042bc7add4..4ec5169267425 100644 --- a/op-e2e/e2eutils/fakebeacon/blobs.go +++ b/op-e2e/e2eutils/fakebeacon/blobs.go @@ -127,6 +127,7 @@ func (f *FakeBeacon) Start(addr string) error { Slot: eth.Uint64String(slot), }, }, + InclusionProof: make([]eth.Bytes32, 0), } copy(sidecars[i].Blob[:], bundle.Blobs[ix]) } diff --git a/op-e2e/e2eutils/geth/geth.go b/op-e2e/e2eutils/geth/geth.go index de5b12b77d3c7..b210949803bb6 100644 --- a/op-e2e/e2eutils/geth/geth.go +++ b/op-e2e/e2eutils/geth/geth.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/txpool/blobpool" + "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/catalyst" "github.com/ethereum/go-ethereum/eth/ethconfig" @@ -49,8 +50,8 @@ func InitL1(blockTime uint64, finalizedDistance uint64, genesis *core.Genesis, c HTTPPort: 0, WSHost: "127.0.0.1", WSPort: 0, - WSModules: []string{"debug", "admin", "eth", "txpool", "net", "rpc", "web3", "personal", "engine"}, - HTTPModules: []string{"debug", "admin", "eth", "txpool", "net", "rpc", "web3", "personal", "engine"}, + WSModules: []string{"debug", "admin", "eth", "txpool", "net", "rpc", "web3", "personal", "engine", "miner"}, + HTTPModules: []string{"debug", "admin", "eth", "txpool", "net", "rpc", "web3", "personal", "engine", "miner"}, } gethInstance, err := createGethNode(false, nodeConfig, ethConfig, opts...) @@ -82,8 +83,8 @@ func defaultNodeConfig(name string, jwtPath string) *node.Config { AuthPort: 0, HTTPHost: "127.0.0.1", HTTPPort: 0, - WSModules: []string{"debug", "admin", "eth", "txpool", "net", "rpc", "web3", "personal", "engine"}, - HTTPModules: []string{"debug", "admin", "eth", "txpool", "net", "rpc", "web3", "personal", "engine"}, + WSModules: []string{"debug", "admin", "eth", "txpool", "net", "rpc", "web3", "personal", "engine", "miner"}, + HTTPModules: []string{"debug", "admin", "eth", "txpool", "net", "rpc", "web3", "personal", "engine", "miner"}, JWTSecret: jwtPath, } } @@ -104,6 +105,9 @@ func InitL2(name string, genesis *core.Genesis, jwtPath string, opts ...GethOpti // enough to build blocks within 1 second, but high enough to avoid unnecessary test CPU cycles. Recommit: time.Millisecond * 400, }, + TxPool: legacypool.Config{ + NoLocals: true, + }, } nodeConfig := defaultNodeConfig(fmt.Sprintf("l2-geth-%v", name), jwtPath) return createGethNode(true, nodeConfig, ethConfig, opts...) diff --git a/op-e2e/e2eutils/geth/wait.go b/op-e2e/e2eutils/geth/wait.go index 267e589f021c1..8356058afda75 100644 --- a/op-e2e/e2eutils/geth/wait.go +++ b/op-e2e/e2eutils/geth/wait.go @@ -17,7 +17,10 @@ import ( "github.com/ethereum/go-ethereum/rpc" ) -const errStrTxIdxingInProgress = "transaction indexing is in progress" +const ( + errStrTxIdxingInProgress = "transaction indexing is in progress" + waitForBlockMaxRetries = 3 +) // errTimeout represents a timeout var errTimeout = errors.New("timeout") @@ -83,25 +86,80 @@ func WaitForTransaction(hash common.Hash, client *ethclient.Client, timeout time } } -func WaitForBlock(number *big.Int, client *ethclient.Client, timeout time.Duration) (*types.Block, error) { - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() +type waitForBlockOptions struct { + noChangeTimeout time.Duration + absoluteTimeout time.Duration +} - headChan := make(chan *types.Header, 100) - headSub, err := client.SubscribeNewHead(ctx, headChan) - if err != nil { - return nil, err +func WithNoChangeTimeout(timeout time.Duration) WaitForBlockOption { + return func(o *waitForBlockOptions) { + o.noChangeTimeout = timeout } - defer headSub.Unsubscribe() +} + +func WithAbsoluteTimeout(timeout time.Duration) WaitForBlockOption { + return func(o *waitForBlockOptions) { + o.absoluteTimeout = timeout + } +} + +type WaitForBlockOption func(*waitForBlockOptions) + +// WaitForBlock waits for the chain to advance to the provided block number. It can be configured with +// two different timeout: an absolute timeout, and a no change timeout. The absolute timeout caps +// the maximum amount of time this method will run. The no change timeout will return an error if the +// block number does not change within that time window. This is useful to bail out early in the event +// of a stuck chain, but allow things to continue if the chain is still advancing. +// +// This function will also retry fetch errors up to three times before returning an error in order to +// protect against transient network problems. This function uses polling rather than websockets. +func WaitForBlock(number *big.Int, client *ethclient.Client, opts ...WaitForBlockOption) (*types.Block, error) { + defaultOpts := &waitForBlockOptions{ + noChangeTimeout: 30 * time.Second, + absoluteTimeout: 3 * time.Minute, + } + for _, opt := range opts { + opt(defaultOpts) + } + + ctx, cancel := context.WithTimeout(context.Background(), defaultOpts.absoluteTimeout) + defer cancel() + + lastAdvancement := time.Now() + lastBlockNumber := big.NewInt(0) + + pollTicker := time.NewTicker(500 * time.Millisecond) + defer pollTicker.Stop() + var errCount int for { - select { - case head := <-headChan: - if head.Number.Cmp(number) >= 0 { - return client.BlockByNumber(ctx, number) + head, err := client.BlockByNumber(ctx, nil) + if err != nil { + errCount++ + if errCount >= waitForBlockMaxRetries { + return nil, fmt.Errorf("head fetching exceeded max retries. last error: %w", err) } - case err := <-headSub.Err(): - return nil, fmt.Errorf("error in head subscription: %w", err) + continue + } + + errCount = 0 + + if head.Number().Cmp(number) >= 0 { + return client.BlockByNumber(ctx, number) + } + + if head.Number().Cmp(lastBlockNumber) != 0 { + lastBlockNumber = head.Number() + lastAdvancement = time.Now() + } + + if time.Since(lastAdvancement) > defaultOpts.noChangeTimeout { + return nil, fmt.Errorf("block number %d has not changed in %s", lastBlockNumber, defaultOpts.noChangeTimeout) + } + + select { + case <-pollTicker.C: + continue case <-ctx.Done(): return nil, ctx.Err() } diff --git a/op-e2e/interop/contracts/emit.go b/op-e2e/e2eutils/interop/contracts/bindings/emit/emit.go similarity index 99% rename from op-e2e/interop/contracts/emit.go rename to op-e2e/e2eutils/interop/contracts/bindings/emit/emit.go index ceae2412659bc..7755ef5fd18fd 100644 --- a/op-e2e/interop/contracts/emit.go +++ b/op-e2e/e2eutils/interop/contracts/bindings/emit/emit.go @@ -26,7 +26,6 @@ var ( _ = common.Big1 _ = types.BloomLookup _ = event.NewSubscription - _ = abi.ConvertType ) // EmitMetaData contains all meta data concerning the Emit contract. @@ -157,11 +156,11 @@ func NewEmitFilterer(address common.Address, filterer bind.ContractFilterer) (*E // bindEmit binds a generic wrapper to an already deployed contract. func bindEmit(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := EmitMetaData.GetAbi() + parsed, err := abi.JSON(strings.NewReader(EmitABI)) if err != nil { return nil, err } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil } // Call invokes the (constant) contract method with params as input values and diff --git a/op-e2e/e2eutils/interop/contracts/bindings/inbox/inbox.go b/op-e2e/e2eutils/interop/contracts/bindings/inbox/inbox.go new file mode 100644 index 0000000000000..f73fd56355e4e --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/bindings/inbox/inbox.go @@ -0,0 +1,231 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package inbox + +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 +) + +// Identifier is an auto generated low-level Go binding around an user-defined struct. +type Identifier struct { + Origin common.Address + BlockNumber *big.Int + LogIndex *big.Int + Timestamp *big.Int + ChainId *big.Int +} + +// InboxMetaData contains all meta data concerning the Inbox contract. +var InboxMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"function\",\"name\":\"executeMessage\",\"inputs\":[{\"name\":\"_id\",\"type\":\"tuple\",\"internalType\":\"structIdentifier\",\"components\":[{\"name\":\"origin\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"blockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"logIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"timestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"chainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"_target\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_message\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"validateMessage\",\"inputs\":[{\"name\":\"_id\",\"type\":\"tuple\",\"internalType\":\"structIdentifier\",\"components\":[{\"name\":\"origin\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"blockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"logIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"timestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"chainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"name\":\"_msgHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"}]", +} + +// InboxABI is the input ABI used to generate the binding from. +// Deprecated: Use InboxMetaData.ABI instead. +var InboxABI = InboxMetaData.ABI + +// Inbox is an auto generated Go binding around an Ethereum contract. +type Inbox struct { + InboxCaller // Read-only binding to the contract + InboxTransactor // Write-only binding to the contract + InboxFilterer // Log filterer for contract events +} + +// InboxCaller is an auto generated read-only Go binding around an Ethereum contract. +type InboxCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// InboxTransactor is an auto generated write-only Go binding around an Ethereum contract. +type InboxTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// InboxFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type InboxFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// InboxSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type InboxSession struct { + Contract *Inbox // 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 +} + +// InboxCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type InboxCallerSession struct { + Contract *InboxCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// InboxTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type InboxTransactorSession struct { + Contract *InboxTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// InboxRaw is an auto generated low-level Go binding around an Ethereum contract. +type InboxRaw struct { + Contract *Inbox // Generic contract binding to access the raw methods on +} + +// InboxCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type InboxCallerRaw struct { + Contract *InboxCaller // Generic read-only contract binding to access the raw methods on +} + +// InboxTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type InboxTransactorRaw struct { + Contract *InboxTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewInbox creates a new instance of Inbox, bound to a specific deployed contract. +func NewInbox(address common.Address, backend bind.ContractBackend) (*Inbox, error) { + contract, err := bindInbox(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Inbox{InboxCaller: InboxCaller{contract: contract}, InboxTransactor: InboxTransactor{contract: contract}, InboxFilterer: InboxFilterer{contract: contract}}, nil +} + +// NewInboxCaller creates a new read-only instance of Inbox, bound to a specific deployed contract. +func NewInboxCaller(address common.Address, caller bind.ContractCaller) (*InboxCaller, error) { + contract, err := bindInbox(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &InboxCaller{contract: contract}, nil +} + +// NewInboxTransactor creates a new write-only instance of Inbox, bound to a specific deployed contract. +func NewInboxTransactor(address common.Address, transactor bind.ContractTransactor) (*InboxTransactor, error) { + contract, err := bindInbox(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &InboxTransactor{contract: contract}, nil +} + +// NewInboxFilterer creates a new log filterer instance of Inbox, bound to a specific deployed contract. +func NewInboxFilterer(address common.Address, filterer bind.ContractFilterer) (*InboxFilterer, error) { + contract, err := bindInbox(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &InboxFilterer{contract: contract}, nil +} + +// bindInbox binds a generic wrapper to an already deployed contract. +func bindInbox(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(InboxABI)) + 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 (_Inbox *InboxRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Inbox.Contract.InboxCaller.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 (_Inbox *InboxRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Inbox.Contract.InboxTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Inbox *InboxRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Inbox.Contract.InboxTransactor.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 (_Inbox *InboxCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Inbox.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 (_Inbox *InboxTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Inbox.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Inbox *InboxTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Inbox.Contract.contract.Transact(opts, method, params...) +} + +// ExecuteMessage is a paid mutator transaction binding the contract method 0x5984c53e. +// +// Solidity: function executeMessage((address,uint256,uint256,uint256,uint256) _id, address _target, bytes _message) payable returns() +func (_Inbox *InboxTransactor) ExecuteMessage(opts *bind.TransactOpts, _id Identifier, _target common.Address, _message []byte) (*types.Transaction, error) { + return _Inbox.contract.Transact(opts, "executeMessage", _id, _target, _message) +} + +// ExecuteMessage is a paid mutator transaction binding the contract method 0x5984c53e. +// +// Solidity: function executeMessage((address,uint256,uint256,uint256,uint256) _id, address _target, bytes _message) payable returns() +func (_Inbox *InboxSession) ExecuteMessage(_id Identifier, _target common.Address, _message []byte) (*types.Transaction, error) { + return _Inbox.Contract.ExecuteMessage(&_Inbox.TransactOpts, _id, _target, _message) +} + +// ExecuteMessage is a paid mutator transaction binding the contract method 0x5984c53e. +// +// Solidity: function executeMessage((address,uint256,uint256,uint256,uint256) _id, address _target, bytes _message) payable returns() +func (_Inbox *InboxTransactorSession) ExecuteMessage(_id Identifier, _target common.Address, _message []byte) (*types.Transaction, error) { + return _Inbox.Contract.ExecuteMessage(&_Inbox.TransactOpts, _id, _target, _message) +} + +// ValidateMessage is a paid mutator transaction binding the contract method 0xab4d6f75. +// +// Solidity: function validateMessage((address,uint256,uint256,uint256,uint256) _id, bytes32 _msgHash) returns() +func (_Inbox *InboxTransactor) ValidateMessage(opts *bind.TransactOpts, _id Identifier, _msgHash [32]byte) (*types.Transaction, error) { + return _Inbox.contract.Transact(opts, "validateMessage", _id, _msgHash) +} + +// ValidateMessage is a paid mutator transaction binding the contract method 0xab4d6f75. +// +// Solidity: function validateMessage((address,uint256,uint256,uint256,uint256) _id, bytes32 _msgHash) returns() +func (_Inbox *InboxSession) ValidateMessage(_id Identifier, _msgHash [32]byte) (*types.Transaction, error) { + return _Inbox.Contract.ValidateMessage(&_Inbox.TransactOpts, _id, _msgHash) +} + +// ValidateMessage is a paid mutator transaction binding the contract method 0xab4d6f75. +// +// Solidity: function validateMessage((address,uint256,uint256,uint256,uint256) _id, bytes32 _msgHash) returns() +func (_Inbox *InboxTransactorSession) ValidateMessage(_id Identifier, _msgHash [32]byte) (*types.Transaction, error) { + return _Inbox.Contract.ValidateMessage(&_Inbox.TransactOpts, _id, _msgHash) +} diff --git a/op-e2e/e2eutils/interop/contracts/bindings/systemconfig/systemconfig.go b/op-e2e/e2eutils/interop/contracts/bindings/systemconfig/systemconfig.go new file mode 100644 index 0000000000000..9e29cc4700e59 --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/bindings/systemconfig/systemconfig.go @@ -0,0 +1,201 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package systemconfig + +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 +) + +// SystemconfigMetaData contains all meta data concerning the Systemconfig contract. +var SystemconfigMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"function\",\"name\":\"addDependency\",\"inputs\":[{\"name\":\"_chainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"}]", +} + +// SystemconfigABI is the input ABI used to generate the binding from. +// Deprecated: Use SystemconfigMetaData.ABI instead. +var SystemconfigABI = SystemconfigMetaData.ABI + +// Systemconfig is an auto generated Go binding around an Ethereum contract. +type Systemconfig struct { + SystemconfigCaller // Read-only binding to the contract + SystemconfigTransactor // Write-only binding to the contract + SystemconfigFilterer // Log filterer for contract events +} + +// SystemconfigCaller is an auto generated read-only Go binding around an Ethereum contract. +type SystemconfigCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SystemconfigTransactor is an auto generated write-only Go binding around an Ethereum contract. +type SystemconfigTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SystemconfigFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SystemconfigFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SystemconfigSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SystemconfigSession struct { + Contract *Systemconfig // 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 +} + +// SystemconfigCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SystemconfigCallerSession struct { + Contract *SystemconfigCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SystemconfigTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SystemconfigTransactorSession struct { + Contract *SystemconfigTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SystemconfigRaw is an auto generated low-level Go binding around an Ethereum contract. +type SystemconfigRaw struct { + Contract *Systemconfig // Generic contract binding to access the raw methods on +} + +// SystemconfigCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SystemconfigCallerRaw struct { + Contract *SystemconfigCaller // Generic read-only contract binding to access the raw methods on +} + +// SystemconfigTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SystemconfigTransactorRaw struct { + Contract *SystemconfigTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewSystemconfig creates a new instance of Systemconfig, bound to a specific deployed contract. +func NewSystemconfig(address common.Address, backend bind.ContractBackend) (*Systemconfig, error) { + contract, err := bindSystemconfig(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Systemconfig{SystemconfigCaller: SystemconfigCaller{contract: contract}, SystemconfigTransactor: SystemconfigTransactor{contract: contract}, SystemconfigFilterer: SystemconfigFilterer{contract: contract}}, nil +} + +// NewSystemconfigCaller creates a new read-only instance of Systemconfig, bound to a specific deployed contract. +func NewSystemconfigCaller(address common.Address, caller bind.ContractCaller) (*SystemconfigCaller, error) { + contract, err := bindSystemconfig(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SystemconfigCaller{contract: contract}, nil +} + +// NewSystemconfigTransactor creates a new write-only instance of Systemconfig, bound to a specific deployed contract. +func NewSystemconfigTransactor(address common.Address, transactor bind.ContractTransactor) (*SystemconfigTransactor, error) { + contract, err := bindSystemconfig(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SystemconfigTransactor{contract: contract}, nil +} + +// NewSystemconfigFilterer creates a new log filterer instance of Systemconfig, bound to a specific deployed contract. +func NewSystemconfigFilterer(address common.Address, filterer bind.ContractFilterer) (*SystemconfigFilterer, error) { + contract, err := bindSystemconfig(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SystemconfigFilterer{contract: contract}, nil +} + +// bindSystemconfig binds a generic wrapper to an already deployed contract. +func bindSystemconfig(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(SystemconfigABI)) + 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 (_Systemconfig *SystemconfigRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Systemconfig.Contract.SystemconfigCaller.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 (_Systemconfig *SystemconfigRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Systemconfig.Contract.SystemconfigTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Systemconfig *SystemconfigRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Systemconfig.Contract.SystemconfigTransactor.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 (_Systemconfig *SystemconfigCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Systemconfig.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 (_Systemconfig *SystemconfigTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Systemconfig.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Systemconfig *SystemconfigTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Systemconfig.Contract.contract.Transact(opts, method, params...) +} + +// AddDependency is a paid mutator transaction binding the contract method 0xa89c793c. +// +// Solidity: function addDependency(uint256 _chainId) returns() +func (_Systemconfig *SystemconfigTransactor) AddDependency(opts *bind.TransactOpts, _chainId *big.Int) (*types.Transaction, error) { + return _Systemconfig.contract.Transact(opts, "addDependency", _chainId) +} + +// AddDependency is a paid mutator transaction binding the contract method 0xa89c793c. +// +// Solidity: function addDependency(uint256 _chainId) returns() +func (_Systemconfig *SystemconfigSession) AddDependency(_chainId *big.Int) (*types.Transaction, error) { + return _Systemconfig.Contract.AddDependency(&_Systemconfig.TransactOpts, _chainId) +} + +// AddDependency is a paid mutator transaction binding the contract method 0xa89c793c. +// +// Solidity: function addDependency(uint256 _chainId) returns() +func (_Systemconfig *SystemconfigTransactorSession) AddDependency(_chainId *big.Int) (*types.Transaction, error) { + return _Systemconfig.Contract.AddDependency(&_Systemconfig.TransactOpts, _chainId) +} diff --git a/op-e2e/e2eutils/interop/contracts/build/ICrossL2Inbox.sol/ICrossL2Inbox.abi b/op-e2e/e2eutils/interop/contracts/build/ICrossL2Inbox.sol/ICrossL2Inbox.abi new file mode 100644 index 0000000000000..b724169ec6fa4 --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/build/ICrossL2Inbox.sol/ICrossL2Inbox.abi @@ -0,0 +1,97 @@ +[ + { + "type": "function", + "name": "executeMessage", + "inputs": [ + { + "name": "_id", + "type": "tuple", + "internalType": "struct Identifier", + "components": [ + { + "name": "origin", + "type": "address", + "internalType": "address" + }, + { + "name": "blockNumber", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "logIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "_target", + "type": "address", + "internalType": "address" + }, + { + "name": "_message", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "validateMessage", + "inputs": [ + { + "name": "_id", + "type": "tuple", + "internalType": "struct Identifier", + "components": [ + { + "name": "origin", + "type": "address", + "internalType": "address" + }, + { + "name": "blockNumber", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "logIndex", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "timestamp", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "chainId", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "name": "_msgHash", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + } +] diff --git a/op-e2e/e2eutils/interop/contracts/build/ICrossL2Inbox.sol/ICrossL2Inbox.bin b/op-e2e/e2eutils/interop/contracts/build/ICrossL2Inbox.sol/ICrossL2Inbox.bin new file mode 100644 index 0000000000000..ec687260b8517 --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/build/ICrossL2Inbox.sol/ICrossL2Inbox.bin @@ -0,0 +1 @@ +0x diff --git a/op-e2e/e2eutils/interop/contracts/build/ICrossL2Inbox.sol/ICrossL2Inbox.json b/op-e2e/e2eutils/interop/contracts/build/ICrossL2Inbox.sol/ICrossL2Inbox.json new file mode 100644 index 0000000000000..96c8d6ddb036c --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/build/ICrossL2Inbox.sol/ICrossL2Inbox.json @@ -0,0 +1 @@ +{"abi":[{"type":"function","name":"executeMessage","inputs":[{"name":"_id","type":"tuple","internalType":"struct Identifier","components":[{"name":"origin","type":"address","internalType":"address"},{"name":"blockNumber","type":"uint256","internalType":"uint256"},{"name":"logIndex","type":"uint256","internalType":"uint256"},{"name":"timestamp","type":"uint256","internalType":"uint256"},{"name":"chainId","type":"uint256","internalType":"uint256"}]},{"name":"_target","type":"address","internalType":"address"},{"name":"_message","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"validateMessage","inputs":[{"name":"_id","type":"tuple","internalType":"struct Identifier","components":[{"name":"origin","type":"address","internalType":"address"},{"name":"blockNumber","type":"uint256","internalType":"uint256"},{"name":"logIndex","type":"uint256","internalType":"uint256"},{"name":"timestamp","type":"uint256","internalType":"uint256"},{"name":"chainId","type":"uint256","internalType":"uint256"}]},{"name":"_msgHash","type":"bytes32","internalType":"bytes32"}],"outputs":[],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"executeMessage((address,uint256,uint256,uint256,uint256),address,bytes)":"5984c53e","validateMessage((address,uint256,uint256,uint256,uint256),bytes32)":"ab4d6f75"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"origin\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"logIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"}],\"internalType\":\"struct Identifier\",\"name\":\"_id\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_message\",\"type\":\"bytes\"}],\"name\":\"executeMessage\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"origin\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"logIndex\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"chainId\",\"type\":\"uint256\"}],\"internalType\":\"struct Identifier\",\"name\":\"_id\",\"type\":\"tuple\"},{\"internalType\":\"bytes32\",\"name\":\"_msgHash\",\"type\":\"bytes32\"}],\"name\":\"validateMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"executeMessage((address,uint256,uint256,uint256,uint256),address,bytes)\":{\"params\":{\"_id\":\"An Identifier pointing to the initiating message.\",\"_message\":\"The message payload, matching the initiating message.\",\"_target\":\"Account that is called with _msg.\"}},\"validateMessage((address,uint256,uint256,uint256,uint256),bytes32)\":{\"params\":{\"_id\":\"Identifier of the message.\",\"_msgHash\":\"Hash of the message payload to call target with.\"}}},\"title\":\"ICrossL2Inbox\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"executeMessage((address,uint256,uint256,uint256,uint256),address,bytes)\":{\"notice\":\"Executes a cross chain message on the destination chain.\"},\"validateMessage((address,uint256,uint256,uint256,uint256),bytes32)\":{\"notice\":\"Validates a cross chain message on the destination chain and emits an ExecutingMessage event. This function is useful for applications that understand the schema of the _message payload and want to process it in a custom way.\"}},\"notice\":\"Interface for the CrossL2Inbox contract.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/ICrossL2Inbox.sol\":\"ICrossL2Inbox\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"src/ICrossL2Inbox.sol\":{\"keccak256\":\"0x97daf76e4a10b96d8062e71df352cbfa7577593fa96676fd43b40f4a0aca9b7f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://74518c974318070da4e118cd28aa86d7f0702ed8cccc39d60906b93197687248\",\"dweb:/ipfs/QmWimBXYsDWDtNgzhjaLUx4xEiTMvbx5635E2TfNBKoV1E\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.25+commit.b61c2a91"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"struct Identifier","name":"_id","type":"tuple","components":[{"internalType":"address","name":"origin","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"logIndex","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"chainId","type":"uint256"}]},{"internalType":"address","name":"_target","type":"address"},{"internalType":"bytes","name":"_message","type":"bytes"}],"stateMutability":"payable","type":"function","name":"executeMessage"},{"inputs":[{"internalType":"struct Identifier","name":"_id","type":"tuple","components":[{"internalType":"address","name":"origin","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"logIndex","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"chainId","type":"uint256"}]},{"internalType":"bytes32","name":"_msgHash","type":"bytes32"}],"stateMutability":"nonpayable","type":"function","name":"validateMessage"}],"devdoc":{"kind":"dev","methods":{"executeMessage((address,uint256,uint256,uint256,uint256),address,bytes)":{"params":{"_id":"An Identifier pointing to the initiating message.","_message":"The message payload, matching the initiating message.","_target":"Account that is called with _msg."}},"validateMessage((address,uint256,uint256,uint256,uint256),bytes32)":{"params":{"_id":"Identifier of the message.","_msgHash":"Hash of the message payload to call target with."}}},"version":1},"userdoc":{"kind":"user","methods":{"executeMessage((address,uint256,uint256,uint256,uint256),address,bytes)":{"notice":"Executes a cross chain message on the destination chain."},"validateMessage((address,uint256,uint256,uint256,uint256),bytes32)":{"notice":"Validates a cross chain message on the destination chain and emits an ExecutingMessage event. This function is useful for applications that understand the schema of the _message payload and want to process it in a custom way."}},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"src/ICrossL2Inbox.sol":"ICrossL2Inbox"},"evmVersion":"cancun","libraries":{}},"sources":{"src/ICrossL2Inbox.sol":{"keccak256":"0x97daf76e4a10b96d8062e71df352cbfa7577593fa96676fd43b40f4a0aca9b7f","urls":["bzz-raw://74518c974318070da4e118cd28aa86d7f0702ed8cccc39d60906b93197687248","dweb:/ipfs/QmWimBXYsDWDtNgzhjaLUx4xEiTMvbx5635E2TfNBKoV1E"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[],"types":{}},"userdoc":{"version":1,"kind":"user","methods":{"executeMessage((address,uint256,uint256,uint256,uint256),address,bytes)":{"notice":"Executes a cross chain message on the destination chain."},"validateMessage((address,uint256,uint256,uint256,uint256),bytes32)":{"notice":"Validates a cross chain message on the destination chain and emits an ExecutingMessage event. This function is useful for applications that understand the schema of the _message payload and want to process it in a custom way."}},"notice":"Interface for the CrossL2Inbox contract."},"devdoc":{"version":1,"kind":"dev","methods":{"executeMessage((address,uint256,uint256,uint256,uint256),address,bytes)":{"params":{"_id":"An Identifier pointing to the initiating message.","_message":"The message payload, matching the initiating message.","_target":"Account that is called with _msg."}},"validateMessage((address,uint256,uint256,uint256,uint256),bytes32)":{"params":{"_id":"Identifier of the message.","_msgHash":"Hash of the message payload to call target with."}}},"title":"ICrossL2Inbox"},"ast":{"absolutePath":"src/ICrossL2Inbox.sol","id":35,"exportedSymbols":{"ICrossL2Inbox":[34],"Identifier":[12]},"nodeType":"SourceUnit","src":"32:1153:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","^","0.8",".0"]},{"id":12,"nodeType":"StructDefinition","src":"57:132:0","nodes":[],"canonicalName":"Identifier","members":[{"constant":false,"id":3,"mutability":"mutable","name":"origin","nameLocation":"89:6:0","nodeType":"VariableDeclaration","scope":12,"src":"81:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":2,"name":"address","nodeType":"ElementaryTypeName","src":"81:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":5,"mutability":"mutable","name":"blockNumber","nameLocation":"109:11:0","nodeType":"VariableDeclaration","scope":12,"src":"101:19:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":4,"name":"uint256","nodeType":"ElementaryTypeName","src":"101:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":7,"mutability":"mutable","name":"logIndex","nameLocation":"134:8:0","nodeType":"VariableDeclaration","scope":12,"src":"126:16:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":6,"name":"uint256","nodeType":"ElementaryTypeName","src":"126:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":9,"mutability":"mutable","name":"timestamp","nameLocation":"156:9:0","nodeType":"VariableDeclaration","scope":12,"src":"148:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":8,"name":"uint256","nodeType":"ElementaryTypeName","src":"148:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":11,"mutability":"mutable","name":"chainId","nameLocation":"179:7:0","nodeType":"VariableDeclaration","scope":12,"src":"171:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":10,"name":"uint256","nodeType":"ElementaryTypeName","src":"171:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"name":"Identifier","nameLocation":"64:10:0","scope":35,"visibility":"public"},{"id":34,"nodeType":"ContractDefinition","src":"269:915:0","nodes":[{"id":24,"nodeType":"FunctionDefinition","src":"577:108:0","nodes":[],"documentation":{"id":14,"nodeType":"StructuredDocumentation","src":"300:272:0","text":"@notice Executes a cross chain message on the destination chain.\n @param _id An Identifier pointing to the initiating message.\n @param _target Account that is called with _msg.\n @param _message The message payload, matching the initiating message."},"functionSelector":"5984c53e","implemented":false,"kind":"function","modifiers":[],"name":"executeMessage","nameLocation":"586:14:0","parameters":{"id":22,"nodeType":"ParameterList","parameters":[{"constant":false,"id":17,"mutability":"mutable","name":"_id","nameLocation":"621:3:0","nodeType":"VariableDeclaration","scope":24,"src":"601:23:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_struct$_Identifier_$12_calldata_ptr","typeString":"struct Identifier"},"typeName":{"id":16,"nodeType":"UserDefinedTypeName","pathNode":{"id":15,"name":"Identifier","nameLocations":["601:10:0"],"nodeType":"IdentifierPath","referencedDeclaration":12,"src":"601:10:0"},"referencedDeclaration":12,"src":"601:10:0","typeDescriptions":{"typeIdentifier":"t_struct$_Identifier_$12_storage_ptr","typeString":"struct Identifier"}},"visibility":"internal"},{"constant":false,"id":19,"mutability":"mutable","name":"_target","nameLocation":"634:7:0","nodeType":"VariableDeclaration","scope":24,"src":"626:15:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":18,"name":"address","nodeType":"ElementaryTypeName","src":"626:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":21,"mutability":"mutable","name":"_message","nameLocation":"658:8:0","nodeType":"VariableDeclaration","scope":24,"src":"643:23:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":20,"name":"bytes","nodeType":"ElementaryTypeName","src":"643:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"600:67:0"},"returnParameters":{"id":23,"nodeType":"ParameterList","parameters":[],"src":"684:0:0"},"scope":34,"stateMutability":"payable","virtual":false,"visibility":"external"},{"id":33,"nodeType":"FunctionDefinition","src":"1105:77:0","nodes":[],"documentation":{"id":25,"nodeType":"StructuredDocumentation","src":"691:409:0","text":"@notice Validates a cross chain message on the destination chain\n and emits an ExecutingMessage event. This function is useful\n for applications that understand the schema of the _message payload and want to\n process it in a custom way.\n @param _id Identifier of the message.\n @param _msgHash Hash of the message payload to call target with."},"functionSelector":"ab4d6f75","implemented":false,"kind":"function","modifiers":[],"name":"validateMessage","nameLocation":"1114:15:0","parameters":{"id":31,"nodeType":"ParameterList","parameters":[{"constant":false,"id":28,"mutability":"mutable","name":"_id","nameLocation":"1150:3:0","nodeType":"VariableDeclaration","scope":33,"src":"1130:23:0","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_struct$_Identifier_$12_calldata_ptr","typeString":"struct Identifier"},"typeName":{"id":27,"nodeType":"UserDefinedTypeName","pathNode":{"id":26,"name":"Identifier","nameLocations":["1130:10:0"],"nodeType":"IdentifierPath","referencedDeclaration":12,"src":"1130:10:0"},"referencedDeclaration":12,"src":"1130:10:0","typeDescriptions":{"typeIdentifier":"t_struct$_Identifier_$12_storage_ptr","typeString":"struct Identifier"}},"visibility":"internal"},{"constant":false,"id":30,"mutability":"mutable","name":"_msgHash","nameLocation":"1163:8:0","nodeType":"VariableDeclaration","scope":33,"src":"1155:16:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":29,"name":"bytes32","nodeType":"ElementaryTypeName","src":"1155:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"}],"src":"1129:43:0"},"returnParameters":{"id":32,"nodeType":"ParameterList","parameters":[],"src":"1181:0:0"},"scope":34,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ICrossL2Inbox","contractDependencies":[],"contractKind":"interface","documentation":{"id":13,"nodeType":"StructuredDocumentation","src":"191:78:0","text":"@title ICrossL2Inbox\n @notice Interface for the CrossL2Inbox contract."},"fullyImplemented":false,"linearizedBaseContracts":[34],"name":"ICrossL2Inbox","nameLocation":"279:13:0","scope":35,"usedErrors":[],"usedEvents":[]}],"license":"MIT"},"id":0} \ No newline at end of file diff --git a/op-e2e/e2eutils/interop/contracts/build/ISystemConfig.sol/ISystemConfig.abi b/op-e2e/e2eutils/interop/contracts/build/ISystemConfig.sol/ISystemConfig.abi new file mode 100644 index 0000000000000..7a7bffc2ca656 --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/build/ISystemConfig.sol/ISystemConfig.abi @@ -0,0 +1,15 @@ +[ + { + "type": "function", + "name": "addDependency", + "inputs": [ + { + "name": "_chainId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + } +] diff --git a/op-e2e/e2eutils/interop/contracts/build/ISystemConfig.sol/ISystemConfig.bin b/op-e2e/e2eutils/interop/contracts/build/ISystemConfig.sol/ISystemConfig.bin new file mode 100644 index 0000000000000..ec687260b8517 --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/build/ISystemConfig.sol/ISystemConfig.bin @@ -0,0 +1 @@ +0x diff --git a/op-e2e/e2eutils/interop/contracts/build/ISystemConfig.sol/ISystemConfig.json b/op-e2e/e2eutils/interop/contracts/build/ISystemConfig.sol/ISystemConfig.json new file mode 100644 index 0000000000000..fef67d0a40fd0 --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/build/ISystemConfig.sol/ISystemConfig.json @@ -0,0 +1 @@ +{"abi":[{"type":"function","name":"addDependency","inputs":[{"name":"_chainId","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"addDependency(uint256)":"a89c793c"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_chainId\",\"type\":\"uint256\"}],\"name\":\"addDependency\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"addDependency(uint256)\":{\"params\":{\"_chainId\":\"Chain ID of chain to add.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"addDependency(uint256)\":{\"notice\":\"Adds a chain to the interop dependency set. Can only be called by the dependency manager.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/ISystemConfig.sol\":\"ISystemConfig\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"src/ISystemConfig.sol\":{\"keccak256\":\"0x764ea7e528e9e5ab907515b4da22738a49a3d5d8ffb948def86d0cbb9e7765be\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9307f5fd1e826f8d059f4aa9141c360aef54612ba8562ec996e7f078ef1d1cf2\",\"dweb:/ipfs/QmbzFSWWLoQUyeuD6U7detgjPy36L3DHJp9BPpaUZqVs68\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.25+commit.b61c2a91"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"addDependency"}],"devdoc":{"kind":"dev","methods":{"addDependency(uint256)":{"params":{"_chainId":"Chain ID of chain to add."}}},"version":1},"userdoc":{"kind":"user","methods":{"addDependency(uint256)":{"notice":"Adds a chain to the interop dependency set. Can only be called by the dependency manager."}},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"src/ISystemConfig.sol":"ISystemConfig"},"evmVersion":"cancun","libraries":{}},"sources":{"src/ISystemConfig.sol":{"keccak256":"0x764ea7e528e9e5ab907515b4da22738a49a3d5d8ffb948def86d0cbb9e7765be","urls":["bzz-raw://9307f5fd1e826f8d059f4aa9141c360aef54612ba8562ec996e7f078ef1d1cf2","dweb:/ipfs/QmbzFSWWLoQUyeuD6U7detgjPy36L3DHJp9BPpaUZqVs68"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[],"types":{}},"userdoc":{"version":1,"kind":"user","methods":{"addDependency(uint256)":{"notice":"Adds a chain to the interop dependency set. Can only be called by the dependency manager."}}},"devdoc":{"version":1,"kind":"dev","methods":{"addDependency(uint256)":{"params":{"_chainId":"Chain ID of chain to add."}}}},"ast":{"absolutePath":"src/ISystemConfig.sol","id":9,"exportedSymbols":{"ISystemConfig":[8]},"nodeType":"SourceUnit","src":"32:264:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"32:23:0","nodes":[],"literals":["solidity","^","0.8",".0"]},{"id":8,"nodeType":"ContractDefinition","src":"57:238:0","nodes":[{"id":7,"nodeType":"FunctionDefinition","src":"243:50:0","nodes":[],"documentation":{"id":2,"nodeType":"StructuredDocumentation","src":"87:151:0","text":"@notice Adds a chain to the interop dependency set. Can only be called by the dependency manager.\n @param _chainId Chain ID of chain to add."},"functionSelector":"a89c793c","implemented":false,"kind":"function","modifiers":[],"name":"addDependency","nameLocation":"252:13:0","parameters":{"id":5,"nodeType":"ParameterList","parameters":[{"constant":false,"id":4,"mutability":"mutable","name":"_chainId","nameLocation":"274:8:0","nodeType":"VariableDeclaration","scope":7,"src":"266:16:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":3,"name":"uint256","nodeType":"ElementaryTypeName","src":"266:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"265:18:0"},"returnParameters":{"id":6,"nodeType":"ParameterList","parameters":[],"src":"292:0:0"},"scope":8,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"ISystemConfig","contractDependencies":[],"contractKind":"interface","fullyImplemented":false,"linearizedBaseContracts":[8],"name":"ISystemConfig","nameLocation":"67:13:0","scope":9,"usedErrors":[],"usedEvents":[]}],"license":"MIT"},"id":0} \ No newline at end of file diff --git a/op-e2e/e2eutils/interop/contracts/build/emit.sol/EmitEvent.abi b/op-e2e/e2eutils/interop/contracts/build/emit.sol/EmitEvent.abi new file mode 100644 index 0000000000000..d30fa8fca93be --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/build/emit.sol/EmitEvent.abi @@ -0,0 +1,28 @@ +[ + { + "type": "function", + "name": "emitData", + "inputs": [ + { + "name": "_data", + "type": "bytes", + "internalType": "bytes" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "DataEmitted", + "inputs": [ + { + "name": "_data", + "type": "bytes", + "indexed": true, + "internalType": "bytes" + } + ], + "anonymous": false + } +] diff --git a/op-e2e/interop/contracts/test-artifacts/emit.sol/EmitEvent.bin b/op-e2e/e2eutils/interop/contracts/build/emit.sol/EmitEvent.bin similarity index 100% rename from op-e2e/interop/contracts/test-artifacts/emit.sol/EmitEvent.bin rename to op-e2e/e2eutils/interop/contracts/build/emit.sol/EmitEvent.bin diff --git a/op-e2e/e2eutils/interop/contracts/build/emit.sol/EmitEvent.json b/op-e2e/e2eutils/interop/contracts/build/emit.sol/EmitEvent.json new file mode 100644 index 0000000000000..465823afa3309 --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/build/emit.sol/EmitEvent.json @@ -0,0 +1 @@ +{"abi":[{"type":"function","name":"emitData","inputs":[{"name":"_data","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"DataEmitted","inputs":[{"name":"_data","type":"bytes","indexed":true,"internalType":"bytes"}],"anonymous":false}],"bytecode":{"object":"0x6080604052348015600e575f80fd5b5060ff8061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063d836083e14602a575b5f80fd5b60396035366004607c565b603b565b005b8181604051604992919060e3565b604051908190038120907fe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c905f90a25050565b5f8060208385031215608c575f80fd5b823567ffffffffffffffff8082111560a2575f80fd5b818501915085601f83011260b4575f80fd5b81358181111560c1575f80fd5b86602082850101111560d1575f80fd5b60209290920196919550909350505050565b818382375f910190815291905056fea164736f6c6343000819000a","sourceMap":"58:278:1:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x6080604052348015600e575f80fd5b50600436106026575f3560e01c8063d836083e14602a575b5f80fd5b60396035366004607c565b603b565b005b8181604051604992919060e3565b604051908190038120907fe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c905f90a25050565b5f8060208385031215608c575f80fd5b823567ffffffffffffffff8082111560a2575f80fd5b818501915085601f83011260b4575f80fd5b81358181111560c1575f80fd5b86602082850101111560d1575f80fd5b60209290920196919550909350505050565b818382375f910190815291905056fea164736f6c6343000819000a","sourceMap":"58:278:1:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;245:89;;;;;;:::i;:::-;;:::i;:::-;;;321:5;;309:18;;;;;;;:::i;:::-;;;;;;;;;;;;;;;245:89;;:::o;14:591:2:-;84:6;92;145:2;133:9;124:7;120:23;116:32;113:52;;;161:1;158;151:12;113:52;201:9;188:23;230:18;271:2;263:6;260:14;257:34;;;287:1;284;277:12;257:34;325:6;314:9;310:22;300:32;;370:7;363:4;359:2;355:13;351:27;341:55;;392:1;389;382:12;341:55;432:2;419:16;458:2;450:6;447:14;444:34;;;474:1;471;464:12;444:34;519:7;514:2;505:6;501:2;497:15;493:24;490:37;487:57;;;540:1;537;530:12;487:57;571:2;563:11;;;;;593:6;;-1:-1:-1;14:591:2;;-1:-1:-1;;;;14:591:2:o;610:271::-;793:6;785;780:3;767:33;749:3;819:16;;844:13;;;819:16;610:271;-1:-1:-1;610:271:2:o","linkReferences":{}},"methodIdentifiers":{"emitData(bytes)":"d836083e"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"DataEmitted\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"emitData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/emit.sol\":\"EmitEvent\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":999999},\"remappings\":[]},\"sources\":{\"src/emit.sol\":{\"keccak256\":\"0xe078378fd445ed0cbbf1087c5013110412ab6a44850af24a15bcde945467accc\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://66c218de0059688c75903c2ba6d4066661dc6f5fa17a329dd7c385d151f3993a\",\"dweb:/ipfs/Qmby4S4N44naZ2miw3Tgdpq5Qbj4DwzJbcGapgqtd7qd26\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.25+commit.b61c2a91"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes","indexed":true}],"type":"event","name":"DataEmitted","anonymous":false},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"emitData"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":[],"optimizer":{"enabled":true,"runs":999999},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"src/emit.sol":"EmitEvent"},"evmVersion":"cancun","libraries":{}},"sources":{"src/emit.sol":{"keccak256":"0xe078378fd445ed0cbbf1087c5013110412ab6a44850af24a15bcde945467accc","urls":["bzz-raw://66c218de0059688c75903c2ba6d4066661dc6f5fa17a329dd7c385d151f3993a","dweb:/ipfs/Qmby4S4N44naZ2miw3Tgdpq5Qbj4DwzJbcGapgqtd7qd26"],"license":"MIT"}},"version":1},"storageLayout":{"storage":[],"types":{}},"userdoc":{"version":1,"kind":"user"},"devdoc":{"version":1,"kind":"dev"},"ast":{"absolutePath":"src/emit.sol","id":52,"exportedSymbols":{"EmitEvent":[51]},"nodeType":"SourceUnit","src":"32:305:1","nodes":[{"id":36,"nodeType":"PragmaDirective","src":"32:24:1","nodes":[],"literals":["solidity","^","0.8",".15"]},{"id":51,"nodeType":"ContractDefinition","src":"58:278:1","nodes":[{"id":40,"nodeType":"EventDefinition","src":"133:39:1","nodes":[],"anonymous":false,"eventSelector":"e00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c","name":"DataEmitted","nameLocation":"139:11:1","parameters":{"id":39,"nodeType":"ParameterList","parameters":[{"constant":false,"id":38,"indexed":true,"mutability":"mutable","name":"_data","nameLocation":"165:5:1","nodeType":"VariableDeclaration","scope":40,"src":"151:19:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":37,"name":"bytes","nodeType":"ElementaryTypeName","src":"151:5:1","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"150:21:1"}},{"id":50,"nodeType":"FunctionDefinition","src":"245:89:1","nodes":[],"body":{"id":49,"nodeType":"Block","src":"294:40:1","nodes":[],"statements":[{"eventCall":{"arguments":[{"id":46,"name":"_data","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":42,"src":"321:5:1","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}],"id":45,"name":"DataEmitted","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":40,"src":"309:11:1","typeDescriptions":{"typeIdentifier":"t_function_event_nonpayable$_t_bytes_memory_ptr_$returns$__$","typeString":"function (bytes memory)"}},"id":47,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"309:18:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":48,"nodeType":"EmitStatement","src":"304:23:1"}]},"functionSelector":"d836083e","implemented":true,"kind":"function","modifiers":[],"name":"emitData","nameLocation":"254:8:1","parameters":{"id":43,"nodeType":"ParameterList","parameters":[{"constant":false,"id":42,"mutability":"mutable","name":"_data","nameLocation":"278:5:1","nodeType":"VariableDeclaration","scope":50,"src":"263:20:1","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":41,"name":"bytes","nodeType":"ElementaryTypeName","src":"263:5:1","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"src":"262:22:1"},"returnParameters":{"id":44,"nodeType":"ParameterList","parameters":[],"src":"294:0:1"},"scope":51,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"EmitEvent","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[51],"name":"EmitEvent","nameLocation":"67:9:1","scope":52,"usedErrors":[],"usedEvents":[40]}],"license":"MIT"},"id":1} \ No newline at end of file diff --git a/op-e2e/interop/contracts/foundry.toml b/op-e2e/e2eutils/interop/contracts/foundry.toml similarity index 100% rename from op-e2e/interop/contracts/foundry.toml rename to op-e2e/e2eutils/interop/contracts/foundry.toml diff --git a/op-e2e/e2eutils/interop/contracts/generate.sh b/op-e2e/e2eutils/interop/contracts/generate.sh new file mode 100755 index 0000000000000..d6107df9cc867 --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/generate.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +set -euo + +forge build + +cd build/emit.sol +cat EmitEvent.json | jq -r '.bytecode.object' > EmitEvent.bin +cat EmitEvent.json | jq '.abi' > EmitEvent.abi +cd ../.. + +mkdir -p bindings/emit +abigen --abi ./build/emit.sol/EmitEvent.abi --bin ./build/emit.sol/EmitEvent.bin --pkg emit --out ./bindings/emit/emit.go + +cd build/ICrossL2Inbox.sol +cat ICrossL2Inbox.json | jq -r '.bytecode.object' > ICrossL2Inbox.bin +cat ICrossL2Inbox.json | jq '.abi' > ICrossL2Inbox.abi +cd ../.. + +mkdir -p bindings/inbox +abigen --abi ./build/ICrossL2Inbox.sol/ICrossL2Inbox.abi --bin ./build/ICrossL2Inbox.sol/ICrossL2Inbox.bin --pkg inbox --out ./bindings/inbox/inbox.go + +cd build/ISystemConfig.sol +cat ISystemConfig.json | jq -r '.bytecode.object' > ISystemConfig.bin +cat ISystemConfig.json | jq '.abi' > ISystemConfig.abi +cd ../.. + +mkdir -p bindings/systemconfig +abigen --abi ./build/ISystemConfig.sol/ISystemConfig.abi --bin ./build/ISystemConfig.sol/ISystemConfig.bin --pkg systemconfig --out ./bindings/systemconfig/systemconfig.go diff --git a/op-e2e/e2eutils/interop/contracts/src/ICrossL2Inbox.sol b/op-e2e/e2eutils/interop/contracts/src/ICrossL2Inbox.sol new file mode 100644 index 0000000000000..780b43d9753b0 --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/src/ICrossL2Inbox.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +struct Identifier { + address origin; + uint256 blockNumber; + uint256 logIndex; + uint256 timestamp; + uint256 chainId; +} + +/// @title ICrossL2Inbox +/// @notice Interface for the CrossL2Inbox contract. +interface ICrossL2Inbox { + + /// @notice Executes a cross chain message on the destination chain. + /// @param _id An Identifier pointing to the initiating message. + /// @param _target Account that is called with _msg. + /// @param _message The message payload, matching the initiating message. + function executeMessage(Identifier calldata _id, address _target, bytes calldata _message) external payable; + + /// @notice Validates a cross chain message on the destination chain + /// and emits an ExecutingMessage event. This function is useful + /// for applications that understand the schema of the _message payload and want to + /// process it in a custom way. + /// @param _id Identifier of the message. + /// @param _msgHash Hash of the message payload to call target with. + function validateMessage(Identifier calldata _id, bytes32 _msgHash) external; +} diff --git a/op-e2e/e2eutils/interop/contracts/src/ISystemConfig.sol b/op-e2e/e2eutils/interop/contracts/src/ISystemConfig.sol new file mode 100644 index 0000000000000..fd14f919b2d0d --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/src/ISystemConfig.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface ISystemConfig { + /// @notice Adds a chain to the interop dependency set. Can only be called by the dependency manager. + /// @param _chainId Chain ID of chain to add. + function addDependency(uint256 _chainId) external; +} diff --git a/op-e2e/interop/contracts/src/emit.sol b/op-e2e/e2eutils/interop/contracts/src/emit.sol similarity index 100% rename from op-e2e/interop/contracts/src/emit.sol rename to op-e2e/e2eutils/interop/contracts/src/emit.sol diff --git a/op-e2e/interop/contracts/test-artifacts/emit.sol/EmitEvent.abi b/op-e2e/e2eutils/interop/contracts/test-artifacts/emit.sol/EmitEvent.abi similarity index 100% rename from op-e2e/interop/contracts/test-artifacts/emit.sol/EmitEvent.abi rename to op-e2e/e2eutils/interop/contracts/test-artifacts/emit.sol/EmitEvent.abi diff --git a/op-e2e/e2eutils/interop/contracts/test-artifacts/emit.sol/EmitEvent.bin b/op-e2e/e2eutils/interop/contracts/test-artifacts/emit.sol/EmitEvent.bin new file mode 100644 index 0000000000000..f4c15ab05dca7 --- /dev/null +++ b/op-e2e/e2eutils/interop/contracts/test-artifacts/emit.sol/EmitEvent.bin @@ -0,0 +1 @@ +0x6080604052348015600e575f80fd5b5060ff8061001b5f395ff3fe6080604052348015600e575f80fd5b50600436106026575f3560e01c8063d836083e14602a575b5f80fd5b60396035366004607c565b603b565b005b8181604051604992919060e3565b604051908190038120907fe00bbfe6f6f8f1bbed2da38e3f5a139c6f9da594ab248a3cf8b44fc73627772c905f90a25050565b5f8060208385031215608c575f80fd5b823567ffffffffffffffff8082111560a2575f80fd5b818501915085601f83011260b4575f80fd5b81358181111560c1575f80fd5b86602082850101111560d1575f80fd5b60209290920196919550909350505050565b818382375f910190815291905056fea164736f6c6343000819000a diff --git a/op-e2e/interop/contracts/test-artifacts/emit.sol/EmitEvent.json b/op-e2e/e2eutils/interop/contracts/test-artifacts/emit.sol/EmitEvent.json similarity index 100% rename from op-e2e/interop/contracts/test-artifacts/emit.sol/EmitEvent.json rename to op-e2e/e2eutils/interop/contracts/test-artifacts/emit.sol/EmitEvent.json diff --git a/op-e2e/e2eutils/wait/waits.go b/op-e2e/e2eutils/wait/waits.go index 3c0e29466cea3..9b03e0bba7f9a 100644 --- a/op-e2e/e2eutils/wait/waits.go +++ b/op-e2e/e2eutils/wait/waits.go @@ -9,6 +9,8 @@ import ( "strings" "time" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -164,3 +166,27 @@ func AndGet[T interface{}](ctx context.Context, pollRate time.Duration, get func } } } + +func ForNodeUp(ctx context.Context, client *ethclient.Client, lgr log.Logger) error { + for { + select { + case <-ctx.Done(): + return ctx.Err() + default: + // Create a new context deliberately. The shorter timeout is used to detect + // potential I/O timeouts on the RPC so we can retry. + callCtx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) + _, err := client.BlockNumber(callCtx) + cancel() + if err == nil { + lgr.Info("node is up") + return nil + } + if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, os.ErrDeadlineExceeded) { + lgr.Info("timeout waiting for node come up, trying again") + continue + } + return err + } + } +} diff --git a/op-e2e/faultproofs/output_alphabet_test.go b/op-e2e/faultproofs/output_alphabet_test.go index 9255214ff39b7..258066305ef3e 100644 --- a/op-e2e/faultproofs/output_alphabet_test.go +++ b/op-e2e/faultproofs/output_alphabet_test.go @@ -167,7 +167,7 @@ func TestOutputAlphabetGame_ValidOutputRoot(t *testing.T) { } func TestChallengerCompleteExhaustiveDisputeGame(t *testing.T) { - op_e2e.InitParallel(t) + op_e2e.InitParallel(t, op_e2e.IsSlow) testCase := func(t *testing.T, isRootCorrect bool) { ctx := context.Background() diff --git a/op-e2e/faultproofs/output_cannon_test.go b/op-e2e/faultproofs/output_cannon_test.go index 80dea8bfb8ddd..0b0aea509feb4 100644 --- a/op-e2e/faultproofs/output_cannon_test.go +++ b/op-e2e/faultproofs/output_cannon_test.go @@ -252,9 +252,7 @@ func testOutputCannonDefendStep(t *testing.T, allocType config.AllocType) { sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx)) require.NoError(t, wait.ForNextBlock(ctx, l1Client)) - game.WaitForInactivity(ctx, 10, true) - game.LogGameData(ctx) - require.EqualValues(t, gameTypes.GameStatusChallengerWon, game.Status(ctx)) + game.WaitForGameStatus(ctx, gameTypes.GameStatusChallengerWon) } func TestOutputCannonStepWithLargePreimage_Standard(t *testing.T) { @@ -502,9 +500,7 @@ func testOutputCannonProposedOutputRootValid(t *testing.T, allocType config.Allo sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx)) require.NoError(t, wait.ForNextBlock(ctx, l1Client)) - game.WaitForInactivity(ctx, 10, true) - game.LogGameData(ctx) - require.EqualValues(t, gameTypes.GameStatusDefenderWon, game.Status(ctx)) + game.WaitForGameStatus(ctx, gameTypes.GameStatusDefenderWon) }) } } @@ -1003,9 +999,7 @@ func testOutputCannonHonestSafeTraceExtensionValidRoot(t *testing.T, allocType c sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx)) require.NoError(t, wait.ForNextBlock(ctx, l1Client)) - game.WaitForInactivity(ctx, 10, true) - game.LogGameData(ctx) - require.EqualValues(t, gameTypes.GameStatusDefenderWon, game.Status(ctx)) + game.WaitForGameStatus(ctx, gameTypes.GameStatusDefenderWon) } func TestOutputCannonHonestSafeTraceExtension_InvalidRoot_Standard(t *testing.T) { @@ -1052,9 +1046,7 @@ func testOutputCannonHonestSafeTraceExtensionInvalidRoot(t *testing.T, allocType sys.TimeTravelClock.AdvanceTime(game.MaxClockDuration(ctx)) require.NoError(t, wait.ForNextBlock(ctx, l1Client)) - game.WaitForInactivity(ctx, 10, true) - game.LogGameData(ctx) - require.EqualValues(t, gameTypes.GameStatusChallengerWon, game.Status(ctx)) + game.WaitForGameStatus(ctx, gameTypes.GameStatusChallengerWon) } func TestAgreeFirstBlockWithOriginOf1_Standard(t *testing.T) { diff --git a/op-e2e/faultproofs/precompile_test.go b/op-e2e/faultproofs/precompile_test.go index 6d116bfa0993b..2beabfba54d66 100644 --- a/op-e2e/faultproofs/precompile_test.go +++ b/op-e2e/faultproofs/precompile_test.go @@ -1,9 +1,12 @@ package faultproofs import ( + "bytes" "context" + "encoding/json" "math" "math/big" + "os/exec" "path/filepath" "testing" @@ -12,7 +15,6 @@ import ( "github.com/ethereum-optimism/optimism/op-e2e/system/e2esys" "github.com/ethereum-optimism/optimism/op-e2e/system/helpers" - "github.com/ethereum-optimism/optimism/cannon/mipsevm/versions" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" @@ -276,9 +278,29 @@ func runCannon(t *testing.T, ctx context.Context, sys *e2esys.System, inputs uti err := executor.DoGenerateProof(ctx, proofsDir, math.MaxUint, math.MaxUint, extraVmArgs...) require.NoError(t, err, "failed to generate proof") - state, err := versions.LoadStateFromFile(vm.FinalStatePath(proofsDir, cfg.Cannon.BinarySnapshots)) - require.NoError(t, err, "failed to parse state") - require.True(t, state.GetExited(), "cannon did not exit") - require.Zero(t, state.GetExitCode(), "cannon failed with exit code %d", state.GetExitCode()) - t.Logf("Completed in %d steps", state.GetStep()) + stdOut, _, err := runCmd(ctx, cfg.Cannon.VmBin, "witness", "--input", vm.FinalStatePath(proofsDir, cfg.Cannon.BinarySnapshots)) + require.NoError(t, err, "failed to run witness cmd") + type stateData struct { + Step uint64 `json:"step"` + ExitCode uint8 `json:"exitCode"` + Exited bool `json:"exited"` + } + var data stateData + err = json.Unmarshal([]byte(stdOut), &data) + require.NoError(t, err, "failed to parse state data") + require.True(t, data.Exited, "cannon did not exit") + require.Zero(t, data.ExitCode, "cannon failed with exit code %d", data.ExitCode) + t.Logf("Completed in %d steps", data.Step) +} + +func runCmd(ctx context.Context, binary string, args ...string) (stdOut string, stdErr string, err error) { + var outBuf bytes.Buffer + var errBuf bytes.Buffer + cmd := exec.CommandContext(ctx, binary, args...) + cmd.Stdout = &outBuf + cmd.Stderr = &errBuf + err = cmd.Run() + stdOut = outBuf.String() + stdErr = errBuf.String() + return } diff --git a/op-e2e/interop/contracts/generate.sh b/op-e2e/interop/contracts/generate.sh deleted file mode 100755 index bba960153ec62..0000000000000 --- a/op-e2e/interop/contracts/generate.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -set -euo - -forge build - -cd build/emit.sol -cat EmitEvent.json | jq -r '.bytecode.object' > EmitEvent.bin -cat EmitEvent.json | jq '.abi' > EmitEvent.abi -cd ../.. - -abigen --abi ./build/emit.sol/EmitEvent.abi --bin ./build/emit.sol/EmitEvent.bin --pkg emit --out ./emit.go diff --git a/op-e2e/interop/interop_test.go b/op-e2e/interop/interop_test.go index 20428e31e3882..302413dd98ed8 100644 --- a/op-e2e/interop/interop_test.go +++ b/op-e2e/interop/interop_test.go @@ -3,22 +3,30 @@ package interop import ( "context" "math/big" + "sync" "testing" "time" + "github.com/ethereum-optimism/optimism/op-service/dial" + oplog "github.com/ethereum-optimism/optimism/op-service/log" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/log" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" "github.com/ethereum-optimism/optimism/op-chain-ops/interopgen" "github.com/ethereum-optimism/optimism/op-e2e/system/helpers" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" + gethCore "github.com/ethereum/go-ethereum/core" + gethTypes "github.com/ethereum/go-ethereum/core/types" ) -// TestInteropTrivial tests a simple interop scenario -// Chains A and B exist, but no messages are sent between them -// and in fact no event-logs are emitted by either chain at all. -// A transaction is sent from Alice to Bob on Chain A. -// The balance of Bob on Chain A is checked before and after the tx. -// The balance of Bob on Chain B is checked after the tx. -func TestInteropTrivial(t *testing.T) { +// setupAndRun is a helper function that sets up a SuperSystem +// which contains two L2 Chains, and two users on each chain. +func setupAndRun(t *testing.T, config SuperSystemConfig, fn func(*testing.T, SuperSystem)) { recipe := interopgen.InteropDevRecipe{ L1ChainID: 900100, L2ChainIDs: []uint64{900200, 900201}, @@ -31,67 +39,283 @@ func TestInteropTrivial(t *testing.T) { // create a super system from the recipe // and get the L2 IDs for use in the test - s2 := NewSuperSystem(t, &recipe, worldResources) - ids := s2.L2IDs() - - // chainA is the first L2 chain - chainA := ids[0] - // chainB is the second L2 chain - chainB := ids[1] + s2 := NewSuperSystem(t, &recipe, worldResources, config) // create two users on all L2 chains s2.AddUser("Alice") s2.AddUser("Bob") - bobAddr := s2.Address(chainA, "Bob") - - // check the balance of Bob - clientA := s2.L2GethClient(chainA) - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() - bobBalance, err := clientA.BalanceAt(ctx, bobAddr, nil) - require.NoError(t, err) - expectedBalance, _ := big.NewInt(0).SetString("10000000000000000000000000", 10) - require.Equal(t, expectedBalance, bobBalance) - - // send a tx from Alice to Bob - s2.SendL2Tx( - chainA, - "Alice", - func(l2Opts *helpers.TxOpts) { - l2Opts.ToAddr = &bobAddr - l2Opts.Value = big.NewInt(1000000) - l2Opts.GasFeeCap = big.NewInt(1_000_000_000) - l2Opts.GasTipCap = big.NewInt(1_000_000_000) - }, - ) - - // check the balance of Bob after the tx - ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() - bobBalance, err = clientA.BalanceAt(ctx, bobAddr, nil) - require.NoError(t, err) - expectedBalance, _ = big.NewInt(0).SetString("10000000000000000001000000", 10) - require.Equal(t, expectedBalance, bobBalance) - - // check that the balance of Bob on ChainB hasn't changed - bobAddrB := s2.Address(chainB, "Bob") - clientB := s2.L2GethClient(chainB) - ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() - bobBalance, err = clientB.BalanceAt(ctx, bobAddrB, nil) - require.NoError(t, err) - expectedBalance, _ = big.NewInt(0).SetString("10000000000000000000000000", 10) - require.Equal(t, expectedBalance, bobBalance) - - s2.DeployEmitterContract(chainA, "Alice") - s2.DeployEmitterContract(chainB, "Alice") - for i := 0; i < 1; i++ { - s2.EmitData(chainA, "Alice", "0x1234567890abcdef") - - s2.EmitData(chainB, "Alice", "0x1234567890abcdef") + // run the test + fn(t, s2) +} + +// TestInterop_IsolatedChains tests a simple interop scenario +// Chains A and B exist, but no messages are sent between them +// a transaction is sent from Alice to Bob on Chain A, +// and only Chain A is affected. +func TestInterop_IsolatedChains(t *testing.T) { + test := func(t *testing.T, s2 SuperSystem) { + ids := s2.L2IDs() + chainA := ids[0] + chainB := ids[1] + + // check the balance of Bob + bobAddr := s2.Address(chainA, "Bob") + clientA := s2.L2GethClient(chainA) + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + bobBalance, err := clientA.BalanceAt(ctx, bobAddr, nil) + require.NoError(t, err) + expectedBalance, _ := big.NewInt(0).SetString("10000000000000000000000000", 10) + require.Equal(t, expectedBalance, bobBalance) + + // send a tx from Alice to Bob + s2.SendL2Tx( + chainA, + "Alice", + func(l2Opts *helpers.TxOpts) { + l2Opts.ToAddr = &bobAddr + l2Opts.Value = big.NewInt(1000000) + l2Opts.GasFeeCap = big.NewInt(1_000_000_000) + l2Opts.GasTipCap = big.NewInt(1_000_000_000) + }, + ) + + // check the balance of Bob after the tx + ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + bobBalance, err = clientA.BalanceAt(ctx, bobAddr, nil) + require.NoError(t, err) + expectedBalance, _ = big.NewInt(0).SetString("10000000000000000001000000", 10) + require.Equal(t, expectedBalance, bobBalance) + + // check that the balance of Bob on ChainB hasn't changed + bobAddrB := s2.Address(chainB, "Bob") + clientB := s2.L2GethClient(chainB) + ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + bobBalance, err = clientB.BalanceAt(ctx, bobAddrB, nil) + require.NoError(t, err) + expectedBalance, _ = big.NewInt(0).SetString("10000000000000000000000000", 10) + require.Equal(t, expectedBalance, bobBalance) + } + config := SuperSystemConfig{ + mempoolFiltering: false, + } + setupAndRun(t, config, test) +} + +// TestInterop_EmitLogs tests a simple interop scenario +// Chains A and B exist, but no messages are sent between them. +// A contract is deployed on each chain, and logs are emitted repeatedly. +func TestInterop_EmitLogs(t *testing.T) { + test := func(t *testing.T, s2 SuperSystem) { + ids := s2.L2IDs() + chainA := ids[0] + chainB := ids[1] + EmitterA := s2.DeployEmitterContract(chainA, "Alice") + EmitterB := s2.DeployEmitterContract(chainB, "Alice") + payload1 := "SUPER JACKPOT!" + numEmits := 10 + // emit logs on both chains in parallel + var emitParallel sync.WaitGroup + emitOn := func(chainID string) { + for i := 0; i < numEmits; i++ { + s2.EmitData(chainID, "Alice", payload1) + } + emitParallel.Done() + } + emitParallel.Add(2) + go emitOn(chainA) + go emitOn(chainB) + emitParallel.Wait() + + clientA := s2.L2GethClient(chainA) + clientB := s2.L2GethClient(chainB) + // check that the logs are emitted on chain A + qA := ethereum.FilterQuery{ + Addresses: []common.Address{EmitterA}, + } + logsA, err := clientA.FilterLogs(context.Background(), qA) + require.NoError(t, err) + require.Len(t, logsA, numEmits) + + // check that the logs are emitted on chain B + qB := ethereum.FilterQuery{ + Addresses: []common.Address{EmitterB}, + } + logsB, err := clientB.FilterLogs(context.Background(), qB) + require.NoError(t, err) + require.Len(t, logsB, numEmits) + + // wait for cross-safety to settle + // I've tried 30s but not all logs are cross-safe by then + time.Sleep(60 * time.Second) + + supervisor := s2.SupervisorClient() + + // requireMessage checks the safety level of a log against the supervisor + // it also checks that the error is as expected + requireMessage := func(chainID string, log gethTypes.Log, expectedSafety types.SafetyLevel, expectedError error) { + client := s2.L2GethClient(chainID) + // construct the expected hash of the log's payload + // (topics concatenated with data) + msgPayload := make([]byte, 0) + for _, topic := range log.Topics { + msgPayload = append(msgPayload, topic.Bytes()...) + } + msgPayload = append(msgPayload, log.Data...) + expectedHash := common.BytesToHash(crypto.Keccak256(msgPayload)) + + // get block for the log (for timestamp) + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) + defer cancel() + block, err := client.BlockByHash(ctx, log.BlockHash) + require.NoError(t, err) + + // make an identifier out of the sample log + identifier := types.Identifier{ + Origin: log.Address, + BlockNumber: log.BlockNumber, + LogIndex: uint32(log.Index), + Timestamp: block.Time(), + ChainID: types.ChainIDFromBig(s2.ChainID(chainID)), + } + + safety, err := supervisor.CheckMessage(context.Background(), + identifier, + expectedHash, + ) + require.ErrorIs(t, err, expectedError) + // the supervisor could progress the safety level more quickly than we expect, + // which is why we check for a minimum safety level + require.True(t, safety.AtLeastAsSafe(expectedSafety), "log: %v should be at least %s, but is %s", log, expectedSafety.String(), safety.String()) + } + // all logs should be cross-safe + for _, log := range logsA { + requireMessage(chainA, log, types.CrossSafe, nil) + } + for _, log := range logsB { + requireMessage(chainB, log, types.CrossSafe, nil) + } + } + config := SuperSystemConfig{ + mempoolFiltering: false, + } + setupAndRun(t, config, test) +} + +func TestInteropBlockBuilding(t *testing.T) { + logger := testlog.Logger(t, log.LevelInfo) + oplog.SetGlobalLogHandler(logger.Handler()) + + test := func(t *testing.T, s2 SuperSystem) { + ids := s2.L2IDs() + chainA := ids[0] + chainB := ids[1] + // We will initiate on chain A, and execute on chain B + s2.DeployEmitterContract(chainA, "Alice") + + // Add chain A as dependency to chain B, + // such that we can execute a message on B that was initiated on A. + depRec := s2.AddDependency(chainB, s2.ChainID(chainA)) + t.Logf("Dependency set in L1 block %d", depRec.BlockNumber) + + rollupClA, err := dial.DialRollupClientWithTimeout(context.Background(), time.Second*15, logger, s2.OpNode(chainA).UserRPC().RPC()) + require.NoError(t, err) + + // Now wait for the dependency to be visible in the L2 (receipt needs to be picked up) + require.Eventually(t, func() bool { + status, err := rollupClA.SyncStatus(context.Background()) + require.NoError(t, err) + return status.CrossUnsafeL2.L1Origin.Number >= depRec.BlockNumber.Uint64() + }, time.Second*30, time.Second, "wait for L1 origin to match dependency L1 block") + t.Log("Dependency information has been processed in L2 block") + + // emit log on chain A + emitRec := s2.EmitData(chainA, "Alice", "hello world") + t.Logf("Emitted a log event in block %d", emitRec.BlockNumber.Uint64()) + + // Wait for initiating side to become cross-unsafe + require.Eventually(t, func() bool { + status, err := rollupClA.SyncStatus(context.Background()) + require.NoError(t, err) + return status.CrossUnsafeL2.Number >= emitRec.BlockNumber.Uint64() + }, time.Second*60, time.Second, "wait for emitted data to become cross-unsafe") + t.Logf("Reached cross-unsafe block %d", emitRec.BlockNumber.Uint64()) + + // Identify the log + require.Len(t, emitRec.Logs, 1) + ev := emitRec.Logs[0] + ethCl := s2.L2GethClient(chainA) + header, err := ethCl.HeaderByHash(context.Background(), emitRec.BlockHash) + require.NoError(t, err) + identifier := types.Identifier{ + Origin: ev.Address, + BlockNumber: ev.BlockNumber, + LogIndex: uint32(ev.Index), + Timestamp: header.Time, + ChainID: types.ChainIDFromBig(s2.ChainID(chainA)), + } + + msgPayload := types.LogToMessagePayload(ev) + payloadHash := crypto.Keccak256Hash(msgPayload) + logHash := types.PayloadHashToLogHash(payloadHash, identifier.Origin) + t.Logf("expected payload hash: %s", payloadHash) + t.Logf("expected log hash: %s", logHash) + + invalidPayload := []byte("test invalid message") + invalidPayloadHash := crypto.Keccak256Hash(invalidPayload) + invalidLogHash := types.PayloadHashToLogHash(invalidPayloadHash, identifier.Origin) + t.Logf("invalid payload hash: %s", invalidPayloadHash) + t.Logf("invalid log hash: %s", invalidLogHash) + + // submit executing txs on B + + t.Log("Testing invalid message") + { + bobAddr := s2.Address(chainA, "Bob") // direct it to a random account without code + ctx, cancel := context.WithTimeout(context.Background(), time.Second*15) + defer cancel() + // Send an executing message, but with different payload. + if s2.(*interopE2ESystem).config.mempoolFiltering { + // We expect the traqnsaction to be filtered out by the mempool if mempool filtering is enabled. + // ExecuteMessage the ErrTxFilteredOut error is checked when sending the tx. + _, err := s2.ExecuteMessage(ctx, chainB, "Alice", identifier, bobAddr, invalidPayload, gethCore.ErrTxFilteredOut) + require.ErrorContains(t, err, gethCore.ErrTxFilteredOut.Error()) + } else { + // We expect the miner to be unable to include this tx, and confirmation to thus time out, if mempool filtering is disabled. + _, err := s2.ExecuteMessage(ctx, chainB, "Alice", identifier, bobAddr, invalidPayload, nil) + require.ErrorIs(t, err, ctx.Err()) + require.ErrorIs(t, ctx.Err(), context.DeadlineExceeded) + } + } + + t.Log("Testing valid message now") + { + bobAddr := s2.Address(chainA, "Bob") // direct it to a random account without code + ctx, cancel := context.WithTimeout(context.Background(), time.Second*15) + defer cancel() + // Send an executing message with the correct identifier / payload + rec, err := s2.ExecuteMessage(ctx, chainB, "Alice", identifier, bobAddr, msgPayload, nil) + require.NoError(t, err, "expecting tx to be confirmed") + t.Logf("confirmed executing msg in block %s", rec.BlockNumber) + } + t.Log("Done") } - time.Sleep(60 * time.Second) + t.Run("without mempool filtering", func(t *testing.T) { + config := SuperSystemConfig{ + mempoolFiltering: false, + } + setupAndRun(t, config, test) + }) + t.Run("with mempool filtering", func(t *testing.T) { + config := SuperSystemConfig{ + mempoolFiltering: true, + } + // run again with mempool filtering to observe the behavior of the mempool filter + setupAndRun(t, config, test) + }) } diff --git a/op-e2e/interop/supersystem.go b/op-e2e/interop/supersystem.go index b973a30d50cc6..de7e25bb9c7b4 100644 --- a/op-e2e/interop/supersystem.go +++ b/op-e2e/interop/supersystem.go @@ -7,9 +7,13 @@ import ( "os" "path" "path/filepath" + "sort" "testing" "time" + "github.com/ethereum/go-ethereum/eth/ethconfig" + gn "github.com/ethereum/go-ethereum/node" + "github.com/stretchr/testify/require" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -21,6 +25,12 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/interop/contracts/bindings/emit" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/interop/contracts/bindings/inbox" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/interop/contracts/bindings/systemconfig" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" + "github.com/ethereum-optimism/optimism/op-service/predeploys" + bss "github.com/ethereum-optimism/optimism/op-batcher/batcher" batcherFlags "github.com/ethereum-optimism/optimism/op-batcher/flags" "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" @@ -32,7 +42,6 @@ import ( "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/opnode" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/services" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/setuputils" - emit "github.com/ethereum-optimism/optimism/op-e2e/interop/contracts" "github.com/ethereum-optimism/optimism/op-e2e/system/helpers" "github.com/ethereum-optimism/optimism/op-node/node" "github.com/ethereum-optimism/optimism/op-node/p2p" @@ -79,8 +88,10 @@ type SuperSystem interface { L2GethClient(network string) *ethclient.Client // get the secret for a network and role L2OperatorKey(network string, role devkeys.ChainOperatorRole) ecdsa.PrivateKey - // get the list of network IDs + // get the list of network IDs as key-strings L2IDs() []string + // get the chain ID for a network + ChainID(network string) *big.Int // register a username to an account on all L2s AddUser(username string) // get the user key for a user on an L2 @@ -93,13 +104,28 @@ type SuperSystem interface { DeployEmitterContract(network string, username string) common.Address // Use the Emitter Contract to emit an Event Log EmitData(network string, username string, data string) *types.Receipt + // AddDependency adds a dependency (by chain ID) to the given chain + AddDependency(network string, dep *big.Int) *types.Receipt + // ExecuteMessage calls the CrossL2Inbox executeMessage function + ExecuteMessage( + ctx context.Context, + id string, + sender string, + msgIdentifier supervisortypes.Identifier, + target common.Address, + message []byte, + expectedError error, + ) (*types.Receipt, error) // Access a contract on a network by name Contract(network string, contractName string) interface{} } +type SuperSystemConfig struct { + mempoolFiltering bool +} // NewSuperSystem creates a new SuperSystem from a recipe. It creates an interopE2ESystem. -func NewSuperSystem(t *testing.T, recipe *interopgen.InteropDevRecipe, w worldResourcePaths) SuperSystem { - s2 := &interopE2ESystem{recipe: recipe} +func NewSuperSystem(t *testing.T, recipe *interopgen.InteropDevRecipe, w worldResourcePaths, config SuperSystemConfig) SuperSystem { + s2 := &interopE2ESystem{recipe: recipe, config: &config} s2.prepare(t, w) return s2 } @@ -118,9 +144,11 @@ type interopE2ESystem struct { beacon *fakebeacon.FakeBeacon l1 *geth.GethInstance l2s map[string]l2Set + l1GethClient *ethclient.Client l2GethClients map[string]*ethclient.Client supervisor *supervisor.SupervisorService superClient *sources.SupervisorClient + config *SuperSystemConfig } // l2Set is a set of resources for an L2 chain @@ -197,6 +225,7 @@ func (s *interopE2ESystem) prepareL1() (*fakebeacon.FakeBeacon, *geth.GethInstan require.NoError(s.t, err) require.NoError(s.t, l1Geth.Node.Start()) s.t.Cleanup(func() { + s.t.Logf("Closing L1 geth") _ = l1Geth.Close() }) return bcn, l1Geth @@ -236,11 +265,18 @@ func (s *interopE2ESystem) newOperatorKeysForL2(l2Out *interopgen.L2Output) map[ func (s *interopE2ESystem) newGethForL2(id string, l2Out *interopgen.L2Output) *geth.GethInstance { jwtPath := writeDefaultJWT(s.t) name := "l2-" + id - l2Geth, err := geth.InitL2(name, l2Out.Genesis, jwtPath) + l2Geth, err := geth.InitL2(name, l2Out.Genesis, jwtPath, + func(ethCfg *ethconfig.Config, nodeCfg *gn.Config) error { + ethCfg.InteropMessageRPC = s.supervisor.RPC() + ethCfg.InteropMempoolFiltering = s.config.mempoolFiltering + return nil + }) require.NoError(s.t, err) require.NoError(s.t, l2Geth.Node.Start()) s.t.Cleanup(func() { - _ = l2Geth.Close() + s.t.Logf("Closing L2 geth of chain %s", id) + closeErr := l2Geth.Close() + s.t.Logf("Closed L2 geth of chain %s: %v", id, closeErr) }) return l2Geth } @@ -303,7 +339,9 @@ func (s *interopE2ESystem) newNodeForL2( s.t.Cleanup(func() { ctx, cancel := context.WithCancel(context.Background()) cancel() // force-quit + s.t.Logf("Closing op-node of chain %s", id) _ = opNode.Stop(ctx) + s.t.Logf("Closed op-node of chain %s", id) }) return opNode } @@ -387,7 +425,9 @@ func (s *interopE2ESystem) newBatcherForL2( s.t.Cleanup(func() { ctx, cancel := context.WithCancel(context.Background()) cancel() // force-quit + s.t.Logf("Closing batcher of chain %s", id) _ = batcher.Stop(ctx) + s.t.Logf("Closed batcher of chain %s", id) }) return batcher } @@ -415,6 +455,10 @@ func (s *interopE2ESystem) newL2(id string, l2Out *interopgen.L2Output) l2Set { } } +func (s *interopE2ESystem) ChainID(network string) *big.Int { + return s.l2s[network].chainID +} + // prepareSupervisor creates a new supervisor for the system func (s *interopE2ESystem) prepareSupervisor() *supervisor.SupervisorService { // Be verbose with op-supervisor, it's in early test phase @@ -438,18 +482,23 @@ func (s *interopE2ESystem) prepareSupervisor() *supervisor.SupervisorService { L2RPCs: []string{}, Datadir: path.Join(s.t.TempDir(), "supervisor"), } - depSet := &depset.StaticConfigDependencySet{ - Dependencies: make(map[supervisortypes.ChainID]*depset.StaticConfigDependency), - } + depSet := make(map[supervisortypes.ChainID]*depset.StaticConfigDependency) + // Iterate over the L2 chain configs. The L2 nodes don't exist yet. for _, l2Out := range s.worldOutput.L2s { chainID := supervisortypes.ChainIDFromBig(l2Out.Genesis.Config.ChainID) - depSet.Dependencies[chainID] = &depset.StaticConfigDependency{ + index, err := chainID.ToUInt32() + require.NoError(s.t, err) + depSet[chainID] = &depset.StaticConfigDependency{ + ChainIndex: supervisortypes.ChainIndex(index), ActivationTime: 0, HistoryMinTime: 0, } } - cfg.DependencySetSource = depSet + stDepSet, err := depset.NewStaticConfigDependencySet(depSet) + require.NoError(s.t, err) + cfg.DependencySetSource = stDepSet + // Create the supervisor with the configuration super, err := supervisor.SupervisorFromConfig(context.Background(), cfg, logger) require.NoError(s.t, err) @@ -459,7 +508,9 @@ func (s *interopE2ESystem) prepareSupervisor() *supervisor.SupervisorService { s.t.Cleanup(func() { ctx, cancel := context.WithCancel(context.Background()) cancel() // force-quit - _ = super.Stop(ctx) + s.t.Logf("Closing supervisor") + closeErr := super.Stop(ctx) + s.t.Logf("Closed supervisor: %v", closeErr) }) return super } @@ -491,12 +542,23 @@ func (s *interopE2ESystem) prepare(t *testing.T, w worldResourcePaths) { s.beacon, s.l1 = s.prepareL1() s.l2s = s.prepareL2s() + s.prepareContracts() + // add the L2 RPCs to the supervisor now that the L2s are created ctx := context.Background() for _, l2 := range s.l2s { err := s.SupervisorClient().AddL2RPC(ctx, l2.l2Geth.UserRPC().RPC()) require.NoError(s.t, err, "failed to add L2 RPC to supervisor") } + + // Try to close the op-supervisor first + s.t.Cleanup(func() { + ctx, cancel := context.WithCancel(context.Background()) + cancel() // force-quit + s.t.Logf("Closing supervisor") + closeErr := s.supervisor.Stop(ctx) + s.t.Logf("Closed supervisor: %v", closeErr) + }) } // AddUser adds a user to the system by creating a user key for each L2. @@ -540,6 +602,44 @@ func (s *interopE2ESystem) prepareL2s() map[string]l2Set { return l2s } +// prepareContracts prepares contract-bindings for the L2s +func (s *interopE2ESystem) prepareContracts() { + // Add bindings to common contracts for each L2 + l1GethClient := s.L1GethClient() + for id, l2Dep := range s.worldDeployment.L2s { + { + contract, err := inbox.NewInbox(predeploys.CrossL2InboxAddr, s.L2GethClient(id)) + require.NoError(s.t, err) + s.l2s[id].contracts["inbox"] = contract + } + { + contract, err := systemconfig.NewSystemconfig(l2Dep.SystemConfigProxy, l1GethClient) + require.NoError(s.t, err) + s.l2s[id].contracts["systemconfig"] = contract + } + } +} + +func (s *interopE2ESystem) L1GethClient() *ethclient.Client { + if s.l1GethClient != nil { + return s.l1GethClient + } + rpcEndpoint := s.l1.UserRPC() + rpcCl := endpoint.DialRPC( + endpoint.PreferAnyRPC, + rpcEndpoint, + func(v string) *rpc.Client { + logger := testlog.Logger(s.t, log.LevelInfo) + cl, err := dial.DialRPCClientWithTimeout(context.Background(), 30*time.Second, logger, v) + require.NoError(s.t, err, "failed to dial L1 eth node instance") + return cl + }) + nodeClient := ethclient.NewClient(rpcCl) + // register the client so it can be reused + s.l1GethClient = nodeClient + return nodeClient +} + func (s *interopE2ESystem) L2GethClient(id string) *ethclient.Client { // guard: check if the client already exists and return it in that case nodeClient, ok := s.l2GethClients[id] @@ -599,6 +699,7 @@ func (s *interopE2ESystem) L2IDs() []string { for id := range s.l2s { ids = append(ids, id) } + sort.Strings(ids) return ids } @@ -626,6 +727,74 @@ func (s *interopE2ESystem) SendL2Tx( newApply) } +// ExecuteMessage calls the CrossL2Inbox executeMessage function +// it uses the L2's chain ID, username key, and geth client. +// expectedError represents the error returned by `ExecuteMessage` if it is expected. +// the returned err is related to `WaitMined` +func (s *interopE2ESystem) ExecuteMessage( + ctx context.Context, + id string, + sender string, + msgIdentifier supervisortypes.Identifier, + target common.Address, + message []byte, + expectedError error, +) (*types.Receipt, error) { + secret := s.UserKey(id, sender) + auth, err := bind.NewKeyedTransactorWithChainID(&secret, s.l2s[id].chainID) + + require.NoError(s.t, err) + + auth.GasLimit = uint64(3000_000) + auth.GasPrice = big.NewInt(20_000_000_000) + + contract := s.Contract(id, "inbox").(*inbox.Inbox) + identifier := inbox.Identifier{ + Origin: msgIdentifier.Origin, + BlockNumber: new(big.Int).SetUint64(msgIdentifier.BlockNumber), + LogIndex: new(big.Int).SetUint64(uint64(msgIdentifier.LogIndex)), + Timestamp: new(big.Int).SetUint64(msgIdentifier.Timestamp), + ChainId: msgIdentifier.ChainID.ToBig(), + } + tx, err := contract.InboxTransactor.ExecuteMessage(auth, identifier, target, message) + if expectedError != nil { + require.ErrorContains(s.t, err, expectedError.Error()) + return nil, err + } else { + require.NoError(s.t, err) + } + s.logger.Info("Executing message", "tx", tx.Hash(), "to", tx.To(), "target", target, "data", hexutil.Bytes(tx.Data())) + return bind.WaitMined(ctx, s.L2GethClient(id), tx) +} + +func (s *interopE2ESystem) AddDependency(id string, dep *big.Int) *types.Receipt { + // There is a note in OPContractsManagerInterop that the proxy-admin is used for now, + // even though it should be a separate dependency-set-manager address. + secret, err := s.hdWallet.Secret(devkeys.ChainOperatorKey{ + ChainID: s.l2s[id].chainID, + Role: devkeys.SystemConfigOwner, + }) + require.NoError(s.t, err) + + auth, err := bind.NewKeyedTransactorWithChainID(secret, s.worldOutput.L1.Genesis.Config.ChainID) + require.NoError(s.t, err) + + balance, err := s.l1GethClient.BalanceAt(context.Background(), crypto.PubkeyToAddress(secret.PublicKey), nil) + require.NoError(s.t, err) + require.False(s.t, balance.Sign() == 0, "system config owner needs a balance") + + auth.GasLimit = uint64(3000000) + auth.GasPrice = big.NewInt(20000000000) + + contract := s.Contract(id, "systemconfig").(*systemconfig.Systemconfig) + tx, err := contract.SystemconfigTransactor.AddDependency(auth, dep) + require.NoError(s.t, err) + + receipt, err := wait.ForReceiptOK(context.Background(), s.L1GethClient(), tx.Hash()) + require.NoError(s.t, err) + return receipt +} + func (s *interopE2ESystem) DeployEmitterContract( id string, sender string, diff --git a/op-e2e/opgeth/op_geth_test.go b/op-e2e/opgeth/op_geth_test.go index 16fe6ab417aad..cc6352aff4bcf 100644 --- a/op-e2e/opgeth/op_geth_test.go +++ b/op-e2e/opgeth/op_geth_test.go @@ -8,13 +8,9 @@ import ( "testing" "time" - op_e2e "github.com/ethereum-optimism/optimism/op-e2e" - - "github.com/ethereum-optimism/optimism/op-e2e/system/e2esys" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" - "github.com/ethereum-optimism/optimism/op-node/rollup" - "github.com/ethereum-optimism/optimism/op-node/rollup/derive" - "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/util" "github.com/ethereum/go-ethereum/common" @@ -24,8 +20,13 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "github.com/ethereum/go-ethereum/rpc" + + op_e2e "github.com/ethereum-optimism/optimism/op-e2e" + "github.com/ethereum-optimism/optimism/op-e2e/system/e2esys" + "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-node/rollup/derive" + "github.com/ethereum-optimism/optimism/op-service/eth" ) var ( @@ -53,8 +54,9 @@ func TestMissingGasLimit(t *testing.T) { res, err := opGeth.StartBlockBuilding(ctx, attrs) require.Error(t, err) - require.ErrorIs(t, err, eth.InputError{}) - require.Equal(t, eth.InvalidPayloadAttributes, err.(eth.InputError).Code) + var rpcErr rpc.Error + require.ErrorAs(t, err, &rpcErr) + require.EqualValues(t, eth.InvalidPayloadAttributes, rpcErr.ErrorCode()) require.Nil(t, res) } diff --git a/op-e2e/system/altda/concurrent_test.go b/op-e2e/system/altda/concurrent_test.go index 4d6835b1fc551..32506e5c4a102 100644 --- a/op-e2e/system/altda/concurrent_test.go +++ b/op-e2e/system/altda/concurrent_test.go @@ -43,7 +43,7 @@ func TestBatcherConcurrentAltDARequests(t *testing.T) { l2Seq := sys.NodeClient("sequencer") // we wait for numL1TxsExpected L2 blocks to have been produced, just to make sure the sequencer is working properly - _, err = geth.WaitForBlock(big.NewInt(numL1TxsExpected), l2Seq, time.Duration(cfg.DeployConfig.L2BlockTime*uint64(numL1TxsExpected))*time.Second) + _, err = geth.WaitForBlock(big.NewInt(numL1TxsExpected), l2Seq) require.NoError(t, err, "Waiting for L2 blocks") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -55,23 +55,20 @@ func TestBatcherConcurrentAltDARequests(t *testing.T) { err = driver.StartBatchSubmitting() require.NoError(t, err) - totalBatcherTxsCount := int64(0) - // wait for up to 5 L1 blocks, expecting 10 L2 batcher txs in them. - // usually only 3 is required, but it's possible additional L1 blocks will be created - // before the batcher starts, so we wait additional blocks. - for i := int64(0); i < 5; i++ { - block, err := geth.WaitForBlock(big.NewInt(int64(startingL1BlockNum)+i), l1Client, time.Duration(cfg.DeployConfig.L1BlockTime*2)*time.Second) + // Iterate over up to 10 blocks. The number of transactions sent by the batcher should + // exceed the number of blocks. + checkBlocks := 10 + for i := 0; i < checkBlocks; i++ { + block, err := geth.WaitForBlock(big.NewInt(int64(startingL1BlockNum)+int64(i)), l1Client) require.NoError(t, err, "Waiting for l1 blocks") // there are possibly other services (proposer/challenger) in the background sending txs // so we only count the batcher txs batcherTxCount, err := transactions.TransactionsBySender(block, cfg.DeployConfig.BatchSenderAddress) require.NoError(t, err) - totalBatcherTxsCount += int64(batcherTxCount) - - if totalBatcherTxsCount >= numL1TxsExpected { + if batcherTxCount > 1 { return } } - t.Fatal("Expected at least 10 transactions from the batcher") + t.Fatalf("did not find more than 1 batcher tx per block in %d blocks", checkBlocks) } diff --git a/op-e2e/system/conductor/sequencer_failover_setup.go b/op-e2e/system/conductor/sequencer_failover_setup.go index ea515ecc1e64d..a4e5178e3d3e2 100644 --- a/op-e2e/system/conductor/sequencer_failover_setup.go +++ b/op-e2e/system/conductor/sequencer_failover_setup.go @@ -2,9 +2,8 @@ package conductor import ( "context" + "errors" "fmt" - "math/rand" - "net" "strings" "testing" "time" @@ -51,28 +50,23 @@ const ( var retryStrategy = &retry.FixedStrategy{Dur: 50 * time.Millisecond} type conductor struct { - service *con.OpConductor - client conrpc.API - consensusPort int - rpcPort int + service *con.OpConductor + client conrpc.API } func (c *conductor) ConsensusEndpoint() string { - return fmt.Sprintf("%s:%d", localhost, c.consensusPort) + return c.service.ConsensusEndpoint() } func (c *conductor) RPCEndpoint() string { - return fmt.Sprintf("http://%s:%d", localhost, c.rpcPort) + return c.service.HTTPEndpoint() } func setupSequencerFailoverTest(t *testing.T) (*e2esys.System, map[string]*conductor, func()) { op_e2e.InitParallel(t) ctx := context.Background() - sys, conductors, err := retry.Do2(ctx, maxSetupRetries, retryStrategy, func() (*e2esys.System, map[string]*conductor, error) { - return setupHAInfra(t, ctx) - }) - require.NoError(t, err, "Expected to successfully setup sequencers and conductors after retry") + sys, conductors := setupHAInfra(t, ctx) // form a cluster c1 := conductors[Sequencer1Name] @@ -143,79 +137,80 @@ func setupSequencerFailoverTest(t *testing.T) (*e2esys.System, map[string]*condu } } -func setupHAInfra(t *testing.T, ctx context.Context) (*e2esys.System, map[string]*conductor, error) { +func setupHAInfra(t *testing.T, ctx context.Context) (*e2esys.System, map[string]*conductor) { startTime := time.Now() - - var sys *e2esys.System - var conductors map[string]*conductor - var err error - - // clean up if setup fails due to port in use. defer func() { - if err != nil { - if sys != nil { - sys.Close() - } - - for _, c := range conductors { - if c == nil || c.service == nil { - // pass. Sometimes we can get nil in this map - } else if serr := c.service.Stop(ctx); serr != nil { - t.Log("Failed to stop conductor", "error", serr) - } - } - } t.Logf("setupHAInfra took %s\n", time.Since(startTime)) }() - conductorRpcPorts := map[string]int{ - Sequencer1Name: findAvailablePort(t), - Sequencer2Name: findAvailablePort(t), - Sequencer3Name: findAvailablePort(t), + conductorsReady := map[string]chan string{ + Sequencer1Name: make(chan string, 1), + Sequencer2Name: make(chan string, 1), + Sequencer3Name: make(chan string, 1), } - // 3 sequencers, 1 verifier, 1 active sequencer. - cfg := sequencerFailoverSystemConfig(t, conductorRpcPorts) - if sys, err = cfg.Start(t); err != nil { - return nil, nil, err + // The sequencer op-node & execution engine have to be up first, to get their endpoints running. + // The conductor is then started after, using the endpoints of op-node and execution engine. + // The op-node, while starting, will wait for the conductor to be up and running, to get its endpoint. + // No endpoint is reserved/hardcoded this way, this avoids CI test flakes in the setup. + conductorEndpointFn := func(ctx context.Context, name string) (endpoint string, err error) { + endpointCh, ok := conductorsReady[name] + if !ok { + return "", errors.New("conductor %s is not known") + } + select { + case <-ctx.Done(): + return "", fmt.Errorf("failed to set up conductor timely: %w", err) + case endpoint := <-endpointCh: + return endpoint, nil + } } - // 3 conductors that connects to 1 sequencer each. - conductors = make(map[string]*conductor) + // 3 sequencers, 1 verifier, 1 active sequencer. + cfg := sequencerFailoverSystemConfig(t, conductorEndpointFn) + + // sys is configured to close itself on test cleanup. + sys, err := cfg.Start(t) + require.NoError(t, err, "must start system") + + out := make(map[string]*conductor) + // 3 conductors that connects to 1 sequencer each. // initialize all conductors in paused mode conductorCfgs := []struct { name string - port int bootstrap bool }{ - {Sequencer1Name, conductorRpcPorts[Sequencer1Name], true}, // one in bootstrap mode so that we can form a cluster. - {Sequencer2Name, conductorRpcPorts[Sequencer2Name], false}, - {Sequencer3Name, conductorRpcPorts[Sequencer3Name], false}, + {Sequencer1Name, true}, // one in bootstrap mode so that we can form a cluster. + {Sequencer2Name, false}, + {Sequencer3Name, false}, } for _, cfg := range conductorCfgs { cfg := cfg nodePRC := sys.RollupNodes[cfg.name].UserRPC().RPC() engineRPC := sys.EthInstances[cfg.name].UserRPC().RPC() - if conductors[cfg.name], err = setupConductor(t, cfg.name, t.TempDir(), nodePRC, engineRPC, cfg.port, cfg.bootstrap, *sys.RollupConfig); err != nil { - return nil, nil, err - } + + conduc, err := setupConductor(t, cfg.name, t.TempDir(), nodePRC, engineRPC, cfg.bootstrap, *sys.RollupConfig) + require.NoError(t, err, "failed to set up conductor %s", cfg.name) + out[cfg.name] = conduc + // Signal that the conductor RPC endpoint is ready + conductorsReady[cfg.name] <- conduc.RPCEndpoint() } - return sys, conductors, nil + return sys, out } func setupConductor( t *testing.T, serverID, dir, nodeRPC, engineRPC string, - rpcPort int, bootstrap bool, rollupCfg rollup.Config, ) (*conductor, error) { - consensusPort := findAvailablePort(t) cfg := con.Config{ - ConsensusAddr: localhost, - ConsensusPort: consensusPort, + ConsensusAddr: localhost, + ConsensusPort: 0, // let the system select a port, avoid conflicts + ConsensusAdvertisedAddr: "", // use the local address we bind to + RaftServerID: serverID, RaftStorageDir: dir, RaftBootstrap: bootstrap, @@ -237,17 +232,18 @@ func setupConductor( RollupCfg: rollupCfg, RPCEnableProxy: true, LogConfig: oplog.CLIConfig{ - Level: log.LevelInfo, + Level: log.LevelDebug, Color: false, }, RPC: oprpc.CLIConfig{ ListenAddr: localhost, - ListenPort: rpcPort, + ListenPort: 0, // let the system select a port }, } + logger := testlog.Logger(t, log.LevelDebug) ctx := context.Background() - service, err := con.New(ctx, &cfg, testlog.Logger(t, log.LevelInfo), "0.0.1") + service, err := con.New(ctx, &cfg, logger, "0.0.1") if err != nil { return nil, err } @@ -257,6 +253,8 @@ func setupConductor( return nil, err } + logger.Info("Started conductor", "nodeRPC", nodeRPC, "engineRPC", engineRPC) + rawClient, err := rpc.DialContext(ctx, service.HTTPEndpoint()) if err != nil { return nil, err @@ -265,10 +263,8 @@ func setupConductor( client := conrpc.NewAPIClient(rawClient) return &conductor{ - service: service, - client: client, - consensusPort: consensusPort, - rpcPort: rpcPort, + service: service, + client: client, }, nil } @@ -316,12 +312,18 @@ func setupBatcher(t *testing.T, sys *e2esys.System, conductors map[string]*condu sys.BatchSubmitter = batcher } -func sequencerFailoverSystemConfig(t *testing.T, ports map[string]int) e2esys.SystemConfig { +func sequencerFailoverSystemConfig(t *testing.T, conductorRPCEndpoints func(ctx context.Context, name string) (string, error)) e2esys.SystemConfig { cfg := e2esys.EcotoneSystemConfig(t, new(hexutil.Uint64)) delete(cfg.Nodes, "sequencer") - cfg.Nodes[Sequencer1Name] = sequencerCfg(ports[Sequencer1Name]) - cfg.Nodes[Sequencer2Name] = sequencerCfg(ports[Sequencer2Name]) - cfg.Nodes[Sequencer3Name] = sequencerCfg(ports[Sequencer3Name]) + cfg.Nodes[Sequencer1Name] = sequencerCfg(func(ctx context.Context) (string, error) { + return conductorRPCEndpoints(ctx, Sequencer1Name) + }) + cfg.Nodes[Sequencer2Name] = sequencerCfg(func(ctx context.Context) (string, error) { + return conductorRPCEndpoints(ctx, Sequencer2Name) + }) + cfg.Nodes[Sequencer3Name] = sequencerCfg(func(ctx context.Context) (string, error) { + return conductorRPCEndpoints(ctx, Sequencer3Name) + }) delete(cfg.Loggers, "sequencer") cfg.Loggers[Sequencer1Name] = testlog.Logger(t, log.LevelInfo).New("role", Sequencer1Name) @@ -338,7 +340,7 @@ func sequencerFailoverSystemConfig(t *testing.T, ports map[string]int) e2esys.Sy return cfg } -func sequencerCfg(rpcPort int) *rollupNode.Config { +func sequencerCfg(conductorRPCEndpoint rollupNode.ConductorRPCFunc) *rollupNode.Config { return &rollupNode.Config{ Driver: driver.Config{ VerifierConfDepth: 0, @@ -357,8 +359,8 @@ func sequencerCfg(rpcPort int) *rollupNode.Config { ConfigPersistence: &rollupNode.DisabledConfigPersistence{}, Sync: sync.Config{SyncMode: sync.CLSync}, ConductorEnabled: true, - ConductorRpc: fmt.Sprintf("http://%s:%d", localhost, rpcPort), - ConductorRpcTimeout: 1 * time.Second, + ConductorRpc: conductorRPCEndpoint, + ConductorRpcTimeout: 5 * time.Second, } } @@ -453,26 +455,6 @@ func sequencerActive(t *testing.T, ctx context.Context, rollupClient *sources.Ro return active } -func findAvailablePort(t *testing.T) int { - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) - defer cancel() - for { - select { - case <-ctx.Done(): - t.Error("Failed to find available port") - default: - // private / ephemeral ports are in the range 49152-65535 - port := rand.Intn(65535-49152) + 49152 - addr := fmt.Sprintf("127.0.0.1:%d", port) - l, err := net.Listen("tcp", addr) - if err == nil { - l.Close() // Close the listener and return the port if it's available - return port - } - } - } -} - func findLeader(t *testing.T, conductors map[string]*conductor) (string, *conductor) { for id, con := range conductors { if leader(t, context.Background(), con) { diff --git a/op-e2e/system/conductor/sequencer_failover_test.go b/op-e2e/system/conductor/sequencer_failover_test.go index 74047fcc6fdd4..5722dc3b82e9c 100644 --- a/op-e2e/system/conductor/sequencer_failover_test.go +++ b/op-e2e/system/conductor/sequencer_failover_test.go @@ -103,7 +103,6 @@ func TestSequencerFailover_ConductorRPC(t *testing.T) { t, VerifierName, t.TempDir(), sys.RollupEndpoint(Sequencer3Name).RPC(), sys.NodeEndpoint(Sequencer3Name).RPC(), - findAvailablePort(t), false, *sys.RollupConfig, ) diff --git a/op-e2e/system/da/brotli_batcher_test.go b/op-e2e/system/da/brotli_batcher_test.go index a55e5bced8ade..fe9b4a9fab978 100644 --- a/op-e2e/system/da/brotli_batcher_test.go +++ b/op-e2e/system/da/brotli_batcher_test.go @@ -8,6 +8,7 @@ import ( "time" op_e2e "github.com/ethereum-optimism/optimism/op-e2e" + "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-e2e/system/e2esys" "github.com/ethereum-optimism/optimism/op-e2e/system/helpers" @@ -67,7 +68,7 @@ func TestBrotliBatcherFjord(t *testing.T) { cfg.DeployConfig.L2GenesisFjordTimeOffset = &genesisActivation // set up batcher to use brotli - sys, err := cfg.Start(t, e2esys.StartOption{Key: "compressionAlgo", Role: "brotli", Action: nil}) + sys, err := cfg.Start(t, e2esys.WithBatcherCompressionAlgo(derive.Brotli)) require.Nil(t, err, "Error starting up system") log := testlog.Logger(t, log.LevelInfo) diff --git a/op-e2e/system/da/da_throttling_test.go b/op-e2e/system/da/da_throttling_test.go new file mode 100644 index 0000000000000..e98ad9d3338d2 --- /dev/null +++ b/op-e2e/system/da/da_throttling_test.go @@ -0,0 +1,192 @@ +package da + +import ( + "context" + "crypto/ecdsa" + "crypto/rand" + "math/big" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/node" + + "github.com/ethereum-optimism/optimism/op-batcher/batcher" + op_e2e "github.com/ethereum-optimism/optimism/op-e2e" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" + "github.com/ethereum-optimism/optimism/op-e2e/system/e2esys" + "github.com/ethereum-optimism/optimism/op-service/sources" +) + +const ( + bigTxSize = 10000 // amount of incompressible calldata to put in a "big" transaction +) + +func TestDATxThrottling(t *testing.T) { + op_e2e.InitParallel(t) + + cfg, rollupClient, l2Seq, l2Verif, batcher := setupTest(t, 100, 0) + + sendTx := func(senderKey *ecdsa.PrivateKey, nonce uint64, size int) *types.Receipt { + hash := sendTx(t, senderKey, nonce, size, cfg.L2ChainIDBig(), l2Seq) + return waitForReceipt(t, hash, l2Seq) + } + + // send a big transaction before throttling could have started, this transaction should land + receipt := sendTx(cfg.Secrets.Alice, 0, bigTxSize) + + // start batch submission, which should trigger throttling future large transactions + err := batcher.StartBatchSubmitting() + require.NoError(t, err) + + // wait until the block containing the above tx shows up as safe to confirm batcher is running. + waitForBlock(t, receipt.BlockNumber, l2Verif, rollupClient) + + // send another big tx, this one should get "stuck" so we wait for its receipt in a parallel goroutine. + done := make(chan bool, 1) + var bigReceipt *types.Receipt + go func() { + bigReceipt = sendTx(cfg.Secrets.Alice, 1, bigTxSize) + done <- true + }() + + safeBlockInclusionDuration := time.Duration(6*cfg.DeployConfig.L1BlockTime) * time.Second + time.Sleep(safeBlockInclusionDuration) + require.Nil(t, bigReceipt, "large tx did not get throttled") + + // Send a small tx, it should get included before the earlier one as long as it's from another sender + r := sendTx(cfg.Secrets.Bob, 0, 0) + // wait until the block the tx was first included in shows up in the safe chain on the verifier + waitForBlock(t, r.BlockNumber, l2Verif, rollupClient) + + // second tx should still be throttled + require.Nil(t, bigReceipt, "large tx did not get throttled") + + // disable throttling to let big tx through + batcher.Config.ThrottleTxSize = 0 + <-done + require.NotNil(t, bigReceipt, "large tx did not get throttled") +} + +func TestDABlockThrottling(t *testing.T) { + op_e2e.InitParallel(t) + cfg, rollupClient, l2Seq, l2Verif, batcher := setupTest(t, 0, bigTxSize+bigTxSize/10) + + sendTx := func(senderKey *ecdsa.PrivateKey, nonce uint64, size int) common.Hash { + return sendTx(t, senderKey, nonce, size, cfg.L2ChainIDBig(), l2Seq) + } + + // Send three big transactions before throttling could have started and make sure some eventually appear in the same + // block to confirm there is no block-level DA throttling active. This usually happens the first try but might + // require a second iteration in some cases due to stochasticity. + nonce := uint64(0) + for { + h1 := sendTx(cfg.Secrets.Alice, nonce, bigTxSize) + h2 := sendTx(cfg.Secrets.Bob, nonce, bigTxSize) + h3 := sendTx(cfg.Secrets.Mallory, nonce, bigTxSize) + nonce++ + + r1 := waitForReceipt(t, h1, l2Seq) + r2 := waitForReceipt(t, h2, l2Seq) + r3 := waitForReceipt(t, h3, l2Seq) + + // wait until the blocks containing the above txs show up in the unsafe chain + waitForBlock(t, r1.BlockNumber, l2Seq, rollupClient) + waitForBlock(t, r2.BlockNumber, l2Seq, rollupClient) + waitForBlock(t, r3.BlockNumber, l2Seq, rollupClient) + t.Log("Some block numbers should be the same:", r1.BlockNumber, r2.BlockNumber, r3.BlockNumber) + + if r1.BlockNumber.Cmp(r2.BlockNumber) == 0 || r1.BlockNumber.Cmp(r3.BlockNumber) == 0 || r2.BlockNumber.Cmp(r3.BlockNumber) == 0 { + // At least 2 transactions appeared in the same block, so we can exit the loop. + // But first we start batch submission, which will enabling DA throttling. + err := batcher.StartBatchSubmitting() + require.NoError(t, err) + // wait for a safe block containing one of the above transactions to ensure the batcher is running + waitForBlock(t, r1.BlockNumber, l2Verif, rollupClient) + break + } + t.Log("Another iteration required:", nonce) + } + + // Send 3 more big transactions at a time, but this time they must all appear in different blocks due to the + // block-level DA limit. Repeat the test 3 times to reduce the probability this happened just due to bad luck. + for i := 0; i < 3; i++ { + h1 := sendTx(cfg.Secrets.Alice, nonce, bigTxSize) + h2 := sendTx(cfg.Secrets.Bob, nonce, bigTxSize) + h3 := sendTx(cfg.Secrets.Mallory, nonce, bigTxSize) + nonce++ + + r1 := waitForReceipt(t, h1, l2Seq) + r2 := waitForReceipt(t, h2, l2Seq) + r3 := waitForReceipt(t, h3, l2Seq) + t.Log("Block numbers should all be different:", r1.BlockNumber, r2.BlockNumber, r3.BlockNumber) + + require.NotEqual(t, 0, r1.BlockNumber.Cmp(r2.BlockNumber)) + require.NotEqual(t, 0, r1.BlockNumber.Cmp(r3.BlockNumber)) + require.NotEqual(t, 0, r2.BlockNumber.Cmp(r3.BlockNumber)) + } +} + +func setupTest(t *testing.T, maxTxSize, maxBlockSize uint64) (e2esys.SystemConfig, *sources.RollupClient, *ethclient.Client, *ethclient.Client, *batcher.TestBatchSubmitter) { + cfg := e2esys.DefaultSystemConfig(t) + cfg.GethOptions["sequencer"] = append(cfg.GethOptions["sequencer"], []geth.GethOption{ + func(ethCfg *ethconfig.Config, nodeCfg *node.Config) error { + ethCfg.Miner.GasCeil = 30_000_000 + return nil + }, + }...) + // disable batcher because we start it manually later + cfg.DisableBatcher = true + + sys, err := cfg.Start(t, + e2esys.WithBatcherThrottling(500*time.Millisecond, 1, maxTxSize, maxBlockSize)) + require.NoError(t, err, "Error starting up system") + + rollupClient := sys.RollupClient("verifier") + l2Seq := sys.NodeClient("sequencer") + l2Verif := sys.NodeClient("verifier") + batcher := sys.BatchSubmitter.ThrottlingTestDriver() + + return cfg, rollupClient, l2Seq, l2Verif, batcher +} + +// sendTx sends a tx containing the 'size' amount of random calldata +func sendTx(t *testing.T, senderKey *ecdsa.PrivateKey, nonce uint64, size int, chainID *big.Int, cl *ethclient.Client) common.Hash { + randomBytes := make([]byte, size) + _, err := rand.Read(randomBytes) + if err != nil { + panic(err) + } + tx := types.MustSignNewTx(senderKey, types.LatestSignerForChainID(chainID), &types.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + To: &common.Address{0xff, 0xff}, + Value: big.NewInt(1_000_000_000), + GasTipCap: big.NewInt(10), + GasFeeCap: big.NewInt(200), + Gas: 21_000 + uint64(len(randomBytes))*16, + Data: randomBytes, + }) + err = cl.SendTransaction(context.Background(), tx) + require.NoError(t, err, "sending L2 tx") + return tx.Hash() +} + +func waitForReceipt(t *testing.T, hash common.Hash, cl *ethclient.Client) *types.Receipt { + receipt, err := wait.ForReceiptOK(context.Background(), cl, hash) + require.NoError(t, err, "waiting for L2 tx") + require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status, "tx not successful") + return receipt +} + +func waitForBlock(t *testing.T, blockNumber *big.Int, cl *ethclient.Client, rc *sources.RollupClient) { + _, err := geth.WaitForBlock(blockNumber, cl) + require.NoError(t, err, "Waiting for block on verifier") + require.NoError(t, wait.ForProcessingFullBatch(context.Background(), rc)) +} diff --git a/op-e2e/system/da/multi_test.go b/op-e2e/system/da/multi_test.go index 8272930da765b..461270282008b 100644 --- a/op-e2e/system/da/multi_test.go +++ b/op-e2e/system/da/multi_test.go @@ -29,13 +29,11 @@ func TestBatcherMultiTx(t *testing.T) { l1Client := sys.NodeClient("l1") l2Seq := sys.NodeClient("sequencer") - _, err = geth.WaitForBlock(big.NewInt(10), l2Seq, time.Duration(cfg.DeployConfig.L2BlockTime*15)*time.Second) + _, err = geth.WaitForBlock(big.NewInt(10), l2Seq) require.NoError(t, err, "Waiting for L2 blocks") - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() - l1Number, err := l1Client.BlockNumber(ctx) - require.NoError(t, err) // start batch submission driver := sys.BatchSubmitter.TestDriver() @@ -43,21 +41,33 @@ func TestBatcherMultiTx(t *testing.T) { require.NoError(t, err) totalBatcherTxsCount := int64(0) - // wait for up to 5 L1 blocks, usually only 3 is required, but it's - // possible additional L1 blocks will be created before the batcher starts, - // so we wait additional blocks. - for i := int64(0); i < 5; i++ { - block, err := geth.WaitForBlock(big.NewInt(int64(l1Number)+i), l1Client, time.Duration(cfg.DeployConfig.L1BlockTime*2)*time.Second) - require.NoError(t, err, "Waiting for l1 blocks") - // there are possibly other services (proposer/challenger) in the background sending txs - // so we only count the batcher txs - batcherTxCount, err := transactions.TransactionsBySender(block, cfg.DeployConfig.BatchSenderAddress) - require.NoError(t, err) - totalBatcherTxsCount += int64(batcherTxCount) - if totalBatcherTxsCount >= 10 { - return + headNum, err := l1Client.BlockNumber(ctx) + require.NoError(t, err) + stopNum := headNum + 10 + startBlock := uint64(1) + + for { + for i := startBlock; i <= headNum; i++ { + block, err := l1Client.BlockByNumber(ctx, big.NewInt(int64(i))) + require.NoError(t, err) + + batcherTxCount, err := transactions.TransactionsBySender(block, cfg.DeployConfig.BatchSenderAddress) + require.NoError(t, err) + totalBatcherTxsCount += batcherTxCount + + if totalBatcherTxsCount >= 10 { + return + } + } + + headNum++ + if headNum > stopNum { + break } + startBlock = headNum + _, err = geth.WaitForBlock(big.NewInt(int64(headNum)), l1Client) + require.NoError(t, err) } t.Fatal("Expected at least 10 transactions from the batcher") diff --git a/op-e2e/system/da/startstop_test.go b/op-e2e/system/da/startstop_test.go index e085029983af1..2a5e0826f06ef 100644 --- a/op-e2e/system/da/startstop_test.go +++ b/op-e2e/system/da/startstop_test.go @@ -72,7 +72,7 @@ func testStartStopBatcher(t *testing.T, cfgMod func(*e2esys.SystemConfig)) { // wait until the block the tx was first included in shows up in the safe chain on the verifier safeBlockInclusionDuration := time.Duration(6*cfg.DeployConfig.L1BlockTime) * time.Second - _, err = geth.WaitForBlock(receipt.BlockNumber, l2Verif, safeBlockInclusionDuration) + _, err = geth.WaitForBlock(receipt.BlockNumber, l2Verif) require.NoError(t, err, "Waiting for block on verifier") require.NoError(t, wait.ForProcessingFullBatch(context.Background(), rollupClient)) @@ -111,7 +111,7 @@ func testStartStopBatcher(t *testing.T, cfgMod func(*e2esys.SystemConfig)) { receipt = sendTx() // wait until the block the tx was first included in shows up in the safe chain on the verifier - _, err = geth.WaitForBlock(receipt.BlockNumber, l2Verif, safeBlockInclusionDuration) + _, err = geth.WaitForBlock(receipt.BlockNumber, l2Verif) require.NoError(t, err, "Waiting for block on verifier") require.NoError(t, wait.ForProcessingFullBatch(context.Background(), rollupClient)) diff --git a/op-e2e/system/e2esys/setup.go b/op-e2e/system/e2esys/setup.go index 077e45855b98c..e59401d905760 100644 --- a/op-e2e/system/e2esys/setup.go +++ b/op-e2e/system/e2esys/setup.go @@ -16,6 +16,8 @@ import ( "testing" "time" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" + "github.com/stretchr/testify/require" "golang.org/x/exp/maps" @@ -483,6 +485,9 @@ type StartOption struct { Key string Role string Action SystemConfigHook + + // Batcher CLIConfig modifications to apply before starting the batcher. + BatcherMod func(*bss.CLIConfig) } type startOptions struct { @@ -503,6 +508,25 @@ func parseStartOptions(_opts []StartOption) (startOptions, error) { }, nil } +func WithBatcherCompressionAlgo(ca derive.CompressionAlgo) StartOption { + return StartOption{ + BatcherMod: func(cfg *bss.CLIConfig) { + cfg.CompressionAlgo = ca + }, + } +} + +func WithBatcherThrottling(interval time.Duration, threshold, txSize, blockSize uint64) StartOption { + return StartOption{ + BatcherMod: func(cfg *bss.CLIConfig) { + cfg.ThrottleInterval = interval + cfg.ThrottleThreshold = threshold + cfg.ThrottleTxSize = txSize + cfg.ThrottleBlockSize = blockSize + }, + } +} + func (s *startOptions) Get(key, role string) (SystemConfigHook, bool) { v, ok := s.opts[key+":"+role] return v, ok @@ -661,6 +685,14 @@ func (cfg SystemConfig) Start(t *testing.T, startOpts ...StartOption) (*System, return nil, err } + sysLogger := testlog.Logger(t, log.LevelInfo).New("role", "system") + + l1UpCtx, l1UpCancel := context.WithTimeout(context.Background(), 30*time.Second) + defer l1UpCancel() + if err := wait.ForNodeUp(l1UpCtx, sys.NodeClient(RoleL1), sysLogger); err != nil { + return nil, fmt.Errorf("l1 never came up: %w", err) + } + // Ordered such that the Sequencer is initialized first. Setup this way so that // the `RollupSequencerHTTP` GethOption can be supplied to any sentry nodes. l2Nodes := []string{RoleSeq} @@ -702,7 +734,7 @@ func (cfg SystemConfig) Start(t *testing.T, startOpts ...StartOption) (*System, } l1Client := sys.NodeClient(RoleL1) - _, err = geth.WaitForBlock(big.NewInt(2), l1Client, 6*time.Second*time.Duration(cfg.DeployConfig.L1BlockTime)) + _, err = geth.WaitForBlock(big.NewInt(2), l1Client) if err != nil { return nil, fmt.Errorf("waiting for blocks: %w", err) } @@ -871,12 +903,6 @@ func (cfg SystemConfig) Start(t *testing.T, startOpts ...StartOption) (*System, batcherTargetNumFrames = 1 } - var compressionAlgo derive.CompressionAlgo = derive.Zlib - // if opt has brotli key, set the compression algo as brotli - if _, ok := parsedStartOpts.Get("compressionAlgo", "brotli"); ok { - compressionAlgo = derive.Brotli10 - } - var batcherAltDACLIConfig altda.CLIConfig if cfg.DeployConfig.UseAltDA { fakeAltDAServer := altda.NewFakeDAServer("127.0.0.1", 0, sys.Cfg.Loggers["da-server"]) @@ -914,9 +940,17 @@ func (cfg SystemConfig) Start(t *testing.T, startOpts ...StartOption) (*System, BatchType: cfg.BatcherBatchType, MaxBlocksPerSpanBatch: cfg.BatcherMaxBlocksPerSpanBatch, DataAvailabilityType: sys.Cfg.DataAvailabilityType, - CompressionAlgo: compressionAlgo, + CompressionAlgo: derive.Zlib, AltDA: batcherAltDACLIConfig, } + + // Apply batcher cli modifications + for _, opt := range startOpts { + if opt.BatcherMod != nil { + opt.BatcherMod(batcherCLIConfig) + } + } + // Batch Submitter batcher, err := bss.BatcherServiceFromCLIConfig(context.Background(), "0.0.1", batcherCLIConfig, sys.Cfg.Loggers["batcher"]) if err != nil { diff --git a/op-e2e/system/fees/eip1559params_test.go b/op-e2e/system/fees/eip1559params_test.go index b9f5d66f02fb2..e1b1098cac129 100644 --- a/op-e2e/system/fees/eip1559params_test.go +++ b/op-e2e/system/fees/eip1559params_test.go @@ -95,7 +95,7 @@ func TestEIP1559Params(t *testing.T) { delta := ((gasTarget - int64(h.GasUsed)) * h.BaseFee.Int64() / gasTarget / int64(expectedDenom)) expectedNextFee := h.BaseFee.Int64() - delta - b, err := geth.WaitForBlock(big.NewInt(h.Number.Int64()+1), l2Seq, txTimeoutDuration) + b, err := geth.WaitForBlock(big.NewInt(h.Number.Int64()+1), l2Seq) require.NoError(t, err, "waiting for next L2 block") require.Equal(t, expectedNextFee, b.Header().BaseFee.Int64()) diff --git a/op-e2e/system/fees/fees_test.go b/op-e2e/system/fees/fees_test.go index 61590313cbc4f..6296b0ee7ab4f 100644 --- a/op-e2e/system/fees/fees_test.go +++ b/op-e2e/system/fees/fees_test.go @@ -4,7 +4,6 @@ import ( "context" "math/big" "testing" - "time" op_e2e "github.com/ethereum-optimism/optimism/op-e2e" @@ -90,7 +89,7 @@ func testFees(t *testing.T, cfg e2esys.SystemConfig) { l1 := sys.NodeClient("l1") // Wait for first block after genesis. The genesis block has zero L1Block values and will throw off the GPO checks - _, err = geth.WaitForBlock(big.NewInt(1), l2Verif, time.Minute) + _, err = geth.WaitForBlock(big.NewInt(1), l2Verif) require.NoError(t, err) config := sys.L2Genesis().Config diff --git a/op-e2e/system/fees/l1info_test.go b/op-e2e/system/fees/l1info_test.go index 2fdd3f70747a0..a4fc16d94a595 100644 --- a/op-e2e/system/fees/l1info_test.go +++ b/op-e2e/system/fees/l1info_test.go @@ -113,9 +113,9 @@ func TestL1InfoContract(t *testing.T) { endVerifBlockNumber := big.NewInt(4) endSeqBlockNumber := big.NewInt(6) - endVerifBlock, err := geth.WaitForBlock(endVerifBlockNumber, l2Verif, time.Minute) + endVerifBlock, err := geth.WaitForBlock(endVerifBlockNumber, l2Verif) require.Nil(t, err) - endSeqBlock, err := geth.WaitForBlock(endSeqBlockNumber, l2Seq, time.Minute) + endSeqBlock, err := geth.WaitForBlock(endSeqBlockNumber, l2Seq) require.Nil(t, err) seqL1Info, err := bindings.NewL1Block(cfg.L1InfoPredeployAddress, l2Seq) diff --git a/op-e2e/system/p2p/txpool_test.go b/op-e2e/system/p2p/txpool_test.go index dde89ecdefb11..bb5b3e4ef339c 100644 --- a/op-e2e/system/p2p/txpool_test.go +++ b/op-e2e/system/p2p/txpool_test.go @@ -3,7 +3,6 @@ package p2p import ( "math/big" "testing" - "time" op_e2e "github.com/ethereum-optimism/optimism/op-e2e" @@ -31,7 +30,7 @@ func TestTxGossip(t *testing.T) { geth.ConnectP2P(t, seqClient, verifClient) // This prevents the below tx-sending from flaking in CI - _, err = geth.WaitForBlock(big.NewInt(10), verifClient, time.Minute) + _, err = geth.WaitForBlock(big.NewInt(10), verifClient) require.NoError(t, err) // Send a transaction to the verifier and it should be gossiped to the sequencer and included in a block. diff --git a/op-e2e/system/proofs/proposer_fp_test.go b/op-e2e/system/proofs/proposer_fp_test.go index 6be17baaaf25c..971ed06a46303 100644 --- a/op-e2e/system/proofs/proposer_fp_test.go +++ b/op-e2e/system/proofs/proposer_fp_test.go @@ -40,7 +40,7 @@ func TestL2OutputSubmitterFaultProofs(t *testing.T) { require.Nil(t, err) l2Verif := sys.NodeClient("verifier") - _, err = geth.WaitForBlock(big.NewInt(6), l2Verif, 10*time.Duration(cfg.DeployConfig.L2BlockTime)*time.Second) + _, err = geth.WaitForBlock(big.NewInt(6), l2Verif) require.Nil(t, err) timeoutCh := time.After(15 * time.Second) diff --git a/op-e2e/system/proofs/proposer_l2oo_test.go b/op-e2e/system/proofs/proposer_l2oo_test.go index f82c93b64b46c..bf718c616538b 100644 --- a/op-e2e/system/proofs/proposer_l2oo_test.go +++ b/op-e2e/system/proofs/proposer_l2oo_test.go @@ -42,7 +42,7 @@ func TestL2OutputSubmitter(t *testing.T) { // for that block and subsequently reorgs to match what the verifier derives when running the // reconcillation process. l2Verif := sys.NodeClient("verifier") - _, err = geth.WaitForBlock(big.NewInt(6), l2Verif, 20*time.Duration(cfg.DeployConfig.L2BlockTime)*time.Second) + _, err = geth.WaitForBlock(big.NewInt(6), l2Verif) require.Nil(t, err) // Wait for batch submitter to update L2 output oracle. diff --git a/op-e2e/system/verifier/sequencer_window_test.go b/op-e2e/system/verifier/sequencer_window_test.go index aa836402e99b8..04b88c54da94c 100644 --- a/op-e2e/system/verifier/sequencer_window_test.go +++ b/op-e2e/system/verifier/sequencer_window_test.go @@ -48,7 +48,7 @@ func TestMissingBatchE2E(t *testing.T) { }) // Wait until the block it was first included in shows up in the safe chain on the verifier - _, err = geth.WaitForBlock(receipt.BlockNumber, l2Verif, time.Duration((sys.RollupConfig.SeqWindowSize+4)*cfg.DeployConfig.L1BlockTime)*time.Second) + _, err = geth.WaitForBlock(receipt.BlockNumber, l2Verif) require.Nil(t, err, "Waiting for block on verifier") // Assert that the transaction is not found on the verifier diff --git a/op-node/Makefile b/op-node/Makefile index 75b152b2d53ec..c1d480d9b71ac 100644 --- a/op-node/Makefile +++ b/op-node/Makefile @@ -35,19 +35,21 @@ test: go test -v ./... fuzz: - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzL1InfoBedrockRoundTrip ./rollup/derive - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzL1InfoEcotoneRoundTrip ./rollup/derive - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzL1InfoAgainstContract ./rollup/derive - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzUnmarshallLogEvent ./rollup/derive - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzParseFrames ./rollup/derive - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzFrameUnmarshalBinary ./rollup/derive - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzBatchRoundTrip ./rollup/derive - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDeriveDepositsRoundTrip ./rollup/derive - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDeriveDepositsBadVersion ./rollup/derive - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzParseL1InfoDepositTxDataValid ./rollup/derive - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzParseL1InfoDepositTxDataBadLength ./rollup/derive - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzRejectCreateBlockBadTimestamp ./rollup/driver - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDecodeDepositTxDataToL1Info ./rollup/driver + printf "%s\n" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzL1InfoBedrockRoundTrip ./rollup/derive" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzL1InfoEcotoneRoundTrip ./rollup/derive" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzL1InfoAgainstContract ./rollup/derive" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzUnmarshallLogEvent ./rollup/derive" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzParseFrames ./rollup/derive" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzFrameUnmarshalBinary ./rollup/derive" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzBatchRoundTrip ./rollup/derive" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDeriveDepositsRoundTrip ./rollup/derive" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDeriveDepositsBadVersion ./rollup/derive" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzParseL1InfoDepositTxDataValid ./rollup/derive" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzParseL1InfoDepositTxDataBadLength ./rollup/derive" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzRejectCreateBlockBadTimestamp ./rollup/driver" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDecodeDepositTxDataToL1Info ./rollup/driver" \ + | parallel -j 8 {} generate-mocks: go generate ./... diff --git a/op-node/chaincfg/chains_test.go b/op-node/chaincfg/chains_test.go index 7499aa4ba3ee4..bd9956253cd57 100644 --- a/op-node/chaincfg/chains_test.go +++ b/op-node/chaincfg/chains_test.go @@ -89,22 +89,22 @@ var sepoliaCfg = rollup.Config{ GasLimit: 30000000, }, }, - BlockTime: 2, - MaxSequencerDrift: 600, - SeqWindowSize: 3600, - ChannelTimeoutBedrock: 300, - L1ChainID: big.NewInt(11155111), - L2ChainID: big.NewInt(11155420), - BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155420"), - DepositContractAddress: common.HexToAddress("0x16fc5058f25648194471939df75cf27a2fdc48bc"), - L1SystemConfigAddress: common.HexToAddress("0x034edd2a225f7f429a63e0f1d2084b9e0a93b538"), - RegolithTime: u64Ptr(0), - CanyonTime: u64Ptr(1699981200), - DeltaTime: u64Ptr(1703203200), - EcotoneTime: u64Ptr(1708534800), - FjordTime: u64Ptr(1716998400), - GraniteTime: u64Ptr(1723478400), - // HoloceneTime: TBD + BlockTime: 2, + MaxSequencerDrift: 600, + SeqWindowSize: 3600, + ChannelTimeoutBedrock: 300, + L1ChainID: big.NewInt(11155111), + L2ChainID: big.NewInt(11155420), + BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155420"), + DepositContractAddress: common.HexToAddress("0x16fc5058f25648194471939df75cf27a2fdc48bc"), + L1SystemConfigAddress: common.HexToAddress("0x034edd2a225f7f429a63e0f1d2084b9e0a93b538"), + RegolithTime: u64Ptr(0), + CanyonTime: u64Ptr(1699981200), + DeltaTime: u64Ptr(1703203200), + EcotoneTime: u64Ptr(1708534800), + FjordTime: u64Ptr(1716998400), + GraniteTime: u64Ptr(1723478400), + HoloceneTime: u64Ptr(1732633200), ProtocolVersionsAddress: common.HexToAddress("0x79ADD5713B383DAa0a138d3C4780C7A1804a8090"), } @@ -126,22 +126,22 @@ var sepoliaDev0Cfg = rollup.Config{ GasLimit: 30000000, }, }, - BlockTime: 2, - MaxSequencerDrift: 600, - SeqWindowSize: 3600, - ChannelTimeoutBedrock: 300, - L1ChainID: big.NewInt(11155111), - L2ChainID: big.NewInt(11155421), - BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155421"), - DepositContractAddress: common.HexToAddress("0x76114bd29dFcC7a9892240D317E6c7C2A281Ffc6"), - L1SystemConfigAddress: common.HexToAddress("0xa6b72407e2dc9EBF84b839B69A24C88929cf20F7"), - RegolithTime: u64Ptr(0), - CanyonTime: u64Ptr(0), - DeltaTime: u64Ptr(0), - EcotoneTime: u64Ptr(1706634000), - FjordTime: u64Ptr(1715961600), - GraniteTime: u64Ptr(1723046400), - // HoloceneTime: TBD + BlockTime: 2, + MaxSequencerDrift: 600, + SeqWindowSize: 3600, + ChannelTimeoutBedrock: 300, + L1ChainID: big.NewInt(11155111), + L2ChainID: big.NewInt(11155421), + BatchInboxAddress: common.HexToAddress("0xff00000000000000000000000000000011155421"), + DepositContractAddress: common.HexToAddress("0x76114bd29dFcC7a9892240D317E6c7C2A281Ffc6"), + L1SystemConfigAddress: common.HexToAddress("0xa6b72407e2dc9EBF84b839B69A24C88929cf20F7"), + RegolithTime: u64Ptr(0), + CanyonTime: u64Ptr(0), + DeltaTime: u64Ptr(0), + EcotoneTime: u64Ptr(1706634000), + FjordTime: u64Ptr(1715961600), + GraniteTime: u64Ptr(1723046400), + HoloceneTime: u64Ptr(1731682800), ProtocolVersionsAddress: common.HexToAddress("0x252CbE9517F731C618961D890D534183822dcC8d"), } diff --git a/op-node/cmd/interop/interop.go b/op-node/cmd/interop/interop.go new file mode 100644 index 0000000000000..3e6f75d530bb0 --- /dev/null +++ b/op-node/cmd/interop/interop.go @@ -0,0 +1,299 @@ +package interop + +import ( + "fmt" + "math/big" + "os" + "path/filepath" + "strconv" + "strings" + "time" + + "github.com/urfave/cli/v2" + + "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" + "github.com/ethereum-optimism/optimism/op-chain-ops/foundry" + "github.com/ethereum-optimism/optimism/op-chain-ops/interopgen" + op_service "github.com/ethereum-optimism/optimism/op-service" + "github.com/ethereum-optimism/optimism/op-service/cliapp" + "github.com/ethereum-optimism/optimism/op-service/ioutil" + "github.com/ethereum-optimism/optimism/op-service/jsonutil" + oplog "github.com/ethereum-optimism/optimism/op-service/log" + "github.com/ethereum/go-ethereum/crypto" +) + +var EnvPrefix = "OP_INTEROP" + +var ( + l1ChainIDFlag = &cli.Uint64Flag{ + Name: "l1.chainid", + Value: 900100, + EnvVars: op_service.PrefixEnvVar(EnvPrefix, "L1_CHAINID"), + } + l2ChainIDsFlag = &cli.Uint64SliceFlag{ + Name: "l2.chainids", + Value: cli.NewUint64Slice(900200, 900201), + EnvVars: op_service.PrefixEnvVar(EnvPrefix, "L2_CHAINIDS"), + } + timestampFlag = &cli.Uint64Flag{ + Name: "timestamp", + Value: 0, + EnvVars: op_service.PrefixEnvVar(EnvPrefix, "TIMESTAMP"), + Usage: "Will use current timestamp, plus 5 seconds, if not set", + } + artifactsDirFlag = &cli.StringFlag{ + Name: "artifacts-dir", + Value: "packages/contracts-bedrock/forge-artifacts", + EnvVars: op_service.PrefixEnvVar(EnvPrefix, "ARTIFACTS_DIR"), + } + foundryDirFlag = &cli.StringFlag{ + Name: "foundry-dir", + Value: "packages/contracts-bedrock", + EnvVars: op_service.PrefixEnvVar(EnvPrefix, "FOUNDRY_DIR"), + Usage: "Optional, for source-map info during genesis generation", + } + outDirFlag = &cli.StringFlag{ + Name: "out-dir", + Value: ".interop-devnet", + EnvVars: op_service.PrefixEnvVar(EnvPrefix, "OUT_DIR"), + } + // used in both dev-setup and devkey commands + mnemonicFlag = &cli.StringFlag{ + Name: "mnemonic", + Value: devkeys.TestMnemonic, + EnvVars: op_service.PrefixEnvVar(EnvPrefix, "MNEMONIC"), + } + // for devkey command + devkeyDomainFlag = &cli.StringFlag{ + Name: "domain", + Value: "chain-operator", + EnvVars: op_service.PrefixEnvVar(EnvPrefix, "DEVKEY_DOMAIN"), + } + devkeyChainIdFlag = &cli.Uint64Flag{ + Name: "chainid", + Value: 0, + EnvVars: op_service.PrefixEnvVar(EnvPrefix, "DEVKEY_CHAINID"), + } + devkeyNameFlag = &cli.StringFlag{ + Name: "name", + EnvVars: op_service.PrefixEnvVar(EnvPrefix, "DEVKEY_NAME"), + } +) + +var InteropDevSetup = &cli.Command{ + Name: "dev-setup", + Usage: "Generate devnet genesis configs with one L1 and multiple L2s", + Flags: cliapp.ProtectFlags(append([]cli.Flag{ + l1ChainIDFlag, + l2ChainIDsFlag, + timestampFlag, + mnemonicFlag, + artifactsDirFlag, + foundryDirFlag, + outDirFlag, + }, oplog.CLIFlags(EnvPrefix)...)), + Action: func(cliCtx *cli.Context) error { + logCfg := oplog.ReadCLIConfig(cliCtx) + logger := oplog.NewLogger(cliCtx.App.Writer, logCfg) + + recipe := &interopgen.InteropDevRecipe{ + L1ChainID: cliCtx.Uint64(l1ChainIDFlag.Name), + L2ChainIDs: cliCtx.Uint64Slice(l2ChainIDsFlag.Name), + GenesisTimestamp: cliCtx.Uint64(timestampFlag.Name), + } + if recipe.GenesisTimestamp == 0 { + recipe.GenesisTimestamp = uint64(time.Now().Unix() + 5) + } + mnemonic := strings.TrimSpace(cliCtx.String(mnemonicFlag.Name)) + if mnemonic == devkeys.TestMnemonic { + logger.Warn("Using default test mnemonic!") + } + keys, err := devkeys.NewMnemonicDevKeys(mnemonic) + if err != nil { + return fmt.Errorf("failed to setup dev keys from mnemonic: %w", err) + } + worldCfg, err := recipe.Build(keys) + if err != nil { + return fmt.Errorf("failed to build deploy configs from interop recipe: %w", err) + } + if err := worldCfg.Check(logger); err != nil { + return fmt.Errorf("invalid deploy configs: %w", err) + } + artifactsDir := cliCtx.String(artifactsDirFlag.Name) + af := foundry.OpenArtifactsDir(artifactsDir) + var srcFs *foundry.SourceMapFS + if cliCtx.IsSet(foundryDirFlag.Name) { + srcDir := cliCtx.String(foundryDirFlag.Name) + srcFs = foundry.NewSourceMapFS(os.DirFS(srcDir)) + } + worldDeployment, worldOutput, err := interopgen.Deploy(logger, af, srcFs, worldCfg) + if err != nil { + return fmt.Errorf("failed to deploy interop dev setup: %w", err) + } + outDir := cliCtx.String(outDirFlag.Name) + // Write deployments + { + deploymentsDir := filepath.Join(outDir, "deployments") + l1Dir := filepath.Join(deploymentsDir, "l1") + if err := writeJson(filepath.Join(l1Dir, "common.json"), worldDeployment.L1); err != nil { + return fmt.Errorf("failed to write L1 deployment data: %w", err) + } + if err := writeJson(filepath.Join(l1Dir, "superchain.json"), worldDeployment.Superchain); err != nil { + return fmt.Errorf("failed to write Superchain deployment data: %w", err) + } + l2sDir := filepath.Join(deploymentsDir, "l2") + for id, dep := range worldDeployment.L2s { + l2Dir := filepath.Join(l2sDir, id) + if err := writeJson(filepath.Join(l2Dir, "addresses.json"), dep); err != nil { + return fmt.Errorf("failed to write L2 %s deployment data: %w", id, err) + } + } + } + // write genesis + { + genesisDir := filepath.Join(outDir, "genesis") + l1Dir := filepath.Join(genesisDir, "l1") + if err := writeJson(filepath.Join(l1Dir, "genesis.json"), worldOutput.L1.Genesis); err != nil { + return fmt.Errorf("failed to write L1 genesis data: %w", err) + } + l2sDir := filepath.Join(genesisDir, "l2") + for id, dep := range worldOutput.L2s { + l2Dir := filepath.Join(l2sDir, id) + if err := writeJson(filepath.Join(l2Dir, "genesis.json"), dep.Genesis); err != nil { + return fmt.Errorf("failed to write L2 %s genesis config: %w", id, err) + } + if err := writeJson(filepath.Join(l2Dir, "rollup.json"), dep.RollupCfg); err != nil { + return fmt.Errorf("failed to write L2 %s rollup config: %w", id, err) + } + } + } + return nil + }, +} + +func writeJson(path string, content any) error { + return jsonutil.WriteJSON[any](content, ioutil.ToBasicFile(path, 0o755)) +} + +var DevKeySecretCmd = &cli.Command{ + Name: "secret", + Usage: "Retrieve devkey secret, by specifying domain, chain ID, name.", + Flags: cliapp.ProtectFlags([]cli.Flag{ + mnemonicFlag, + devkeyDomainFlag, + devkeyChainIdFlag, + devkeyNameFlag, + }), + Action: func(context *cli.Context) error { + mnemonic := context.String(mnemonicFlag.Name) + domain := context.String(devkeyDomainFlag.Name) + chainID := context.Uint64(devkeyChainIdFlag.Name) + chainIDBig := new(big.Int).SetUint64(chainID) + name := context.String(devkeyNameFlag.Name) + k, err := parseKey(domain, chainIDBig, name) + if err != nil { + return err + } + mnemonicKeys, err := devkeys.NewMnemonicDevKeys(mnemonic) + if err != nil { + return err + } + secret, err := mnemonicKeys.Secret(k) + if err != nil { + return err + } + secretBin := crypto.FromECDSA(secret) + _, err = fmt.Fprintf(context.App.Writer, "%x", secretBin) + if err != nil { + return fmt.Errorf("failed to output secret key: %w", err) + } + return nil + }, +} + +var DevKeyAddressCmd = &cli.Command{ + Name: "address", + Usage: "Retrieve devkey address, by specifying domain, chain ID, name.", + Flags: cliapp.ProtectFlags([]cli.Flag{ + mnemonicFlag, + devkeyDomainFlag, + devkeyChainIdFlag, + devkeyNameFlag, + }), + Action: func(context *cli.Context) error { + mnemonic := context.String(mnemonicFlag.Name) + domain := context.String(devkeyDomainFlag.Name) + chainID := context.Uint64(devkeyChainIdFlag.Name) + chainIDBig := new(big.Int).SetUint64(chainID) + name := context.String(devkeyNameFlag.Name) + k, err := parseKey(domain, chainIDBig, name) + if err != nil { + return err + } + mnemonicKeys, err := devkeys.NewMnemonicDevKeys(mnemonic) + if err != nil { + return err + } + addr, err := mnemonicKeys.Address(k) + if err != nil { + return err + } + _, err = fmt.Fprintf(context.App.Writer, "%s", addr) + if err != nil { + return fmt.Errorf("failed to output address: %w", err) + } + return nil + }, +} + +var DevKeyCmd = &cli.Command{ + Name: "devkey", + Usage: "Retrieve devkey secret or address", + Subcommands: cli.Commands{ + DevKeySecretCmd, + DevKeyAddressCmd, + }, +} + +func parseKey(domain string, chainID *big.Int, name string) (devkeys.Key, error) { + switch domain { + case "user": + index, err := strconv.ParseUint(name, 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse user index: %w", err) + } + return devkeys.ChainUserKey{ + ChainID: chainID, + Index: index, + }, nil + case "chain-operator": + var role devkeys.ChainOperatorRole + if err := role.UnmarshalText([]byte(name)); err != nil { + return nil, fmt.Errorf("failed to parse chain operator role: %w", err) + } + return devkeys.ChainOperatorKey{ + ChainID: chainID, + Role: role, + }, nil + case "superchain-operator": + var role devkeys.SuperchainOperatorRole + if err := role.UnmarshalText([]byte(name)); err != nil { + return nil, fmt.Errorf("failed to parse chain operator role: %w", err) + } + return devkeys.SuperchainOperatorKey{ + ChainID: chainID, + Role: role, + }, nil + default: + return nil, fmt.Errorf("unknown devkey domain %q", domain) + } +} + +var InteropCmd = &cli.Command{ + Name: "interop", + Usage: "Experimental tools for OP-Stack interop networks.", + Subcommands: cli.Commands{ + InteropDevSetup, + DevKeyCmd, + }, +} diff --git a/op-node/cmd/main.go b/op-node/cmd/main.go index 8f6688b51cbf0..b82b3f6babce2 100644 --- a/op-node/cmd/main.go +++ b/op-node/cmd/main.go @@ -12,6 +12,7 @@ import ( opnode "github.com/ethereum-optimism/optimism/op-node" "github.com/ethereum-optimism/optimism/op-node/chaincfg" "github.com/ethereum-optimism/optimism/op-node/cmd/genesis" + "github.com/ethereum-optimism/optimism/op-node/cmd/interop" "github.com/ethereum-optimism/optimism/op-node/cmd/networks" "github.com/ethereum-optimism/optimism/op-node/cmd/p2p" "github.com/ethereum-optimism/optimism/op-node/flags" @@ -62,6 +63,7 @@ func main() { Name: "networks", Subcommands: networks.Subcommands, }, + interop.InteropCmd, } ctx := ctxinterrupt.WithSignalWaiterMain(context.Background()) diff --git a/op-node/flags/flags.go b/op-node/flags/flags.go index da3c95c5fb621..998d1b69fe1be 100644 --- a/op-node/flags/flags.go +++ b/op-node/flags/flags.go @@ -73,6 +73,7 @@ var ( EnvVars: prefixEnvVars("L1_BEACON"), Category: RollupCategory, } + /* Optional Flags */ SupervisorAddr = &cli.StringFlag{ Name: "supervisor", Usage: "RPC address of interop supervisor service for cross-chain safety verification." + @@ -80,7 +81,6 @@ var ( Hidden: true, // hidden for now during early testing. EnvVars: prefixEnvVars("SUPERVISOR"), } - /* Optional Flags */ BeaconHeader = &cli.StringFlag{ Name: "l1.beacon-header", Usage: "Optional HTTP header to add to all requests to the L1 Beacon endpoint. Format: 'X-Key: Value'", diff --git a/op-node/node/conductor.go b/op-node/node/conductor.go index ff5723889b95d..cc45f4bfabc46 100644 --- a/op-node/node/conductor.go +++ b/op-node/node/conductor.go @@ -13,15 +13,17 @@ import ( "github.com/ethereum-optimism/optimism/op-node/rollup/conductor" "github.com/ethereum-optimism/optimism/op-service/dial" "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/locks" "github.com/ethereum-optimism/optimism/op-service/retry" ) // ConductorClient is a client for the op-conductor RPC service. type ConductorClient struct { - cfg *Config - metrics *metrics.Metrics - log log.Logger - apiClient *conductorRpc.APIClient + cfg *Config + metrics *metrics.Metrics + log log.Logger + + apiClient locks.RWValue[*conductorRpc.APIClient] // overrideLeader is used to override the leader check for disaster recovery purposes. // During disaster situations where the cluster is unhealthy (no leader, only 1 or less nodes up), @@ -41,15 +43,23 @@ func NewConductorClient(cfg *Config, log log.Logger, metrics *metrics.Metrics) c } // Initialize initializes the conductor client. -func (c *ConductorClient) initialize() error { - if c.apiClient != nil { +func (c *ConductorClient) initialize(ctx context.Context) error { + c.apiClient.Lock() + defer c.apiClient.Unlock() + if c.apiClient.Value != nil { return nil } - conductorRpcClient, err := dial.DialRPCClientWithTimeout(context.Background(), time.Minute*1, c.log, c.cfg.ConductorRpc) + endpoint, err := retry.Do[string](ctx, 10, retry.Exponential(), func() (string, error) { + return c.cfg.ConductorRpc(ctx) + }) + if err != nil { + return fmt.Errorf("no conductor RPC endpoint available: %w", err) + } + conductorRpcClient, err := dial.DialRPCClientWithTimeout(context.Background(), time.Minute*1, c.log, endpoint) if err != nil { return fmt.Errorf("failed to dial conductor RPC: %w", err) } - c.apiClient = conductorRpc.NewAPIClient(conductorRpcClient) + c.apiClient.Value = conductorRpc.NewAPIClient(conductorRpcClient) return nil } @@ -64,7 +74,7 @@ func (c *ConductorClient) Leader(ctx context.Context) (bool, error) { return true, nil } - if err := c.initialize(); err != nil { + if err := c.initialize(ctx); err != nil { return false, err } ctx, cancel := context.WithTimeout(ctx, c.cfg.ConductorRpcTimeout) @@ -72,8 +82,11 @@ func (c *ConductorClient) Leader(ctx context.Context) (bool, error) { isLeader, err := retry.Do(ctx, 2, retry.Fixed(50*time.Millisecond), func() (bool, error) { record := c.metrics.RecordRPCClientRequest("conductor_leader") - result, err := c.apiClient.Leader(ctx) + result, err := c.apiClient.Get().Leader(ctx) record(err) + if err != nil { + c.log.Error("Failed to check conductor for leadership", "err", err) + } return result, err }) return isLeader, err @@ -85,7 +98,7 @@ func (c *ConductorClient) CommitUnsafePayload(ctx context.Context, payload *eth. return nil } - if err := c.initialize(); err != nil { + if err := c.initialize(ctx); err != nil { return err } ctx, cancel := context.WithTimeout(ctx, c.cfg.ConductorRpcTimeout) @@ -93,7 +106,7 @@ func (c *ConductorClient) CommitUnsafePayload(ctx context.Context, payload *eth. err := retry.Do0(ctx, 2, retry.Fixed(50*time.Millisecond), func() error { record := c.metrics.RecordRPCClientRequest("conductor_commitUnsafePayload") - err := c.apiClient.CommitUnsafePayload(ctx, payload) + err := c.apiClient.Get().CommitUnsafePayload(ctx, payload) record(err) return err }) @@ -107,9 +120,11 @@ func (c *ConductorClient) OverrideLeader(ctx context.Context) error { } func (c *ConductorClient) Close() { - if c.apiClient == nil { + c.apiClient.Lock() + defer c.apiClient.Unlock() + if c.apiClient.Value == nil { return } - c.apiClient.Close() - c.apiClient = nil + c.apiClient.Value.Close() + c.apiClient.Value = nil } diff --git a/op-node/node/config.go b/op-node/node/config.go index 6844ca81cc3f1..a05047acda206 100644 --- a/op-node/node/config.go +++ b/op-node/node/config.go @@ -73,7 +73,7 @@ type Config struct { // Conductor is used to determine this node is the leader sequencer. ConductorEnabled bool - ConductorRpc string + ConductorRpc ConductorRPCFunc ConductorRpcTimeout time.Duration // AltDA config @@ -104,6 +104,9 @@ func (dacConfig *DACConfig) Client() engine.DACClient { return client.New(dacConfig.URLS) } +// ConductorRPCFunc retrieves the endpoint. The RPC may not immediately be available. +type ConductorRPCFunc func(ctx context.Context) (string, error) + type RPCConfig struct { ListenAddr string ListenPort int diff --git a/op-node/node/node.go b/op-node/node/node.go index 66a0cdab1c25b..77b4e254347f6 100644 --- a/op-node/node/node.go +++ b/op-node/node/node.go @@ -447,6 +447,7 @@ func (n *OpNode) initRPCServer(cfg *Config) error { if err := server.Start(); err != nil { return fmt.Errorf("unable to start RPC server: %w", err) } + n.log.Info("Started JSON-RPC server", "addr", server.Addr()) n.server = server return nil } diff --git a/op-node/p2p/config.go b/op-node/p2p/config.go index ee21ba20fc395..10a75881b87d3 100644 --- a/op-node/p2p/config.go +++ b/op-node/p2p/config.go @@ -29,7 +29,6 @@ var DefaultBootnodes = []*enode.Node{ // OP Labs enode.MustParse("enode://869d07b5932f17e8490990f75a3f94195e9504ddb6b85f7189e5a9c0a8fff8b00aecf6f3ac450ecba6cdabdb5858788a94bde2b613e0f2d82e9b395355f76d1a@34.65.67.101:30305"), enode.MustParse("enode://2d4e7e9d48f4dd4efe9342706dd1b0024681bd4c3300d021f86fc75eab7865d4e0cbec6fbc883f011cfd6a57423e7e2f6e104baad2b744c3cafaec6bc7dc92c1@34.65.43.171:30305"), - enode.MustParse("enode://9d7a3efefe442351217e73b3a593bcb8efffb55b4807699972145324eab5e6b382152f8d24f6301baebbfb5ecd4127bd3faab2842c04cd432bdf50ba092f6645@34.65.109.126:30305"), // Base enode.MustParse("enr:-J24QNz9lbrKbN4iSmmjtnr7SjUMk4zB7f1krHZcTZx-JRKZd0kA2gjufUROD6T3sOWDVDnFJRvqBBo62zuF-hYCohOGAYiOoEyEgmlkgnY0gmlwhAPniryHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQKNVFlCxh_B-716tTs-h1vMzZkSs1FTu_OYTNjgufplG4N0Y3CCJAaDdWRwgiQG"), enode.MustParse("enr:-J24QH-f1wt99sfpHy4c0QJM-NfmsIfmlLAMMcgZCUEgKG_BBYFc6FwYgaMJMQN5dsRBJApIok0jFn-9CS842lGpLmqGAYiOoDRAgmlkgnY0gmlwhLhIgb2Hb3BzdGFja4OFQgCJc2VjcDI1NmsxoQJ9FTIv8B9myn1MWaC_2lJ-sMoeCDkusCsk4BYHjjCq04N0Y3CCJAaDdWRwgiQG"), @@ -37,7 +36,9 @@ var DefaultBootnodes = []*enode.Node{ enode.MustParse("enr:-J24QHmGyBwUZXIcsGYMaUqGGSl4CFdx9Tozu-vQCn5bHIQbR7On7dZbU61vYvfrJr30t0iahSqhc64J46MnUO2JvQaGAYiOoCKKgmlkgnY0gmlwhAPnCzSHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQINc4fSijfbNIiGhcgvwjsjxVFJHUstK9L1T8OTKUjgloN0Y3CCJAaDdWRwgiQG"), enode.MustParse("enr:-J24QG3ypT4xSu0gjb5PABCmVxZqBjVw9ca7pvsI8jl4KATYAnxBmfkaIuEqy9sKvDHKuNCsy57WwK9wTt2aQgcaDDyGAYiOoGAXgmlkgnY0gmlwhDbGmZaHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQIeAK_--tcLEiu7HvoUlbV52MspE0uCocsx1f_rYvRenIN0Y3CCJAaDdWRwgiQG"), // Conduit - enode.MustParse("enode://9d7a3efefe442351217e73b3a593bcb8efffb55b4807699972145324eab5e6b382152f8d24f6301baebbfb5ecd4127bd3faab2842c04cd432bdf50ba092f6645@34.65.109.126:30305"), + enode.MustParse("enode://d25ce99435982b04d60c4b41ba256b84b888626db7bee45a9419382300fbe907359ae5ef250346785bff8d3b9d07cd3e017a27e2ee3cfda3bcbb0ba762ac9674@bootnode.conduit.xyz:0?discport=30301"), + enode.MustParse("enode://2d4e7e9d48f4dd4efe9342706dd1b0024681bd4c3300d021f86fc75eab7865d4e0cbec6fbc883f011cfd6a57423e7e2f6e104baad2b744c3cafaec6bc7dc92c1@34.65.43.171:0?discport=30305"), + enode.MustParse("enode://9d7a3efefe442351217e73b3a593bcb8efffb55b4807699972145324eab5e6b382152f8d24f6301baebbfb5ecd4127bd3faab2842c04cd432bdf50ba092f6645@34.65.109.126:0?discport=30305"), } type HostMetrics interface { diff --git a/op-node/p2p/host_test.go b/op-node/p2p/host_test.go index 2bab3239e55e5..85b0c9e605880 100644 --- a/op-node/p2p/host_test.go +++ b/op-node/p2p/host_test.go @@ -6,6 +6,7 @@ import ( "math/big" "net" "slices" + gosync "sync" "testing" "time" @@ -126,9 +127,12 @@ func TestP2PFull(t *testing.T) { conns := make(chan network.Conn, 1) hostA := nodeA.Host() + var once gosync.Once hostA.Network().Notify(&network.NotifyBundle{ ConnectedF: func(n network.Network, conn network.Conn) { - conns <- conn + once.Do(func() { + conns <- conn + }) }}) backend := NewP2PAPIBackend(nodeA, logA, nil) diff --git a/op-node/p2p/sync_test.go b/op-node/p2p/sync_test.go index 7c0b3350df040..2527f48fbc655 100644 --- a/op-node/p2p/sync_test.go +++ b/op-node/p2p/sync_test.go @@ -360,18 +360,24 @@ func TestNetworkNotifyAddPeerAndRemovePeer(t *testing.T) { return nil }, metrics.NoopMetrics, &NoopApplicationScorer{}) - waitChan := make(chan struct{}, 1) + waitChan := make(chan struct{}, 2) + var connectedOnce sync.Once + var disconnectedOnce sync.Once hostA.Network().Notify(&network.NotifyBundle{ ConnectedF: func(nw network.Network, conn network.Conn) { - syncCl.AddPeer(conn.RemotePeer()) - waitChan <- struct{}{} + connectedOnce.Do(func() { + syncCl.AddPeer(conn.RemotePeer()) + waitChan <- struct{}{} + }) }, DisconnectedF: func(nw network.Network, conn network.Conn) { - // only when no connection is available, we can remove the peer - if nw.Connectedness(conn.RemotePeer()) == network.NotConnected { - syncCl.RemovePeer(conn.RemotePeer()) - } - waitChan <- struct{}{} + disconnectedOnce.Do(func() { + // only when no connection is available, we can remove the peer + if nw.Connectedness(conn.RemotePeer()) == network.NotConnected { + syncCl.RemovePeer(conn.RemotePeer()) + } + waitChan <- struct{}{} + }) }, }) syncCl.Start() diff --git a/op-node/rollup/attributes/attributes.go b/op-node/rollup/attributes/attributes.go index 4ebb27050882b..819bc50c24ca1 100644 --- a/op-node/rollup/attributes/attributes.go +++ b/op-node/rollup/attributes/attributes.go @@ -62,6 +62,7 @@ func (eq *AttributesHandler) OnEvent(ev event.Event) bool { eq.onPendingSafeUpdate(x) case derive.DerivedAttributesEvent: eq.attributes = x.Attributes + eq.sentAttributes = false eq.emitter.Emit(derive.ConfirmReceivedAttributesEvent{}) // to make sure we have a pre-state signal to process the attributes from eq.emitter.Emit(engine.PendingSafeRequestEvent{}) @@ -71,7 +72,7 @@ func (eq *AttributesHandler) OnEvent(ev event.Event) bool { case rollup.EngineTemporaryErrorEvent: eq.sentAttributes = false case engine.InvalidPayloadAttributesEvent: - if x.Attributes.DerivedFrom == (eth.L1BlockRef{}) { + if !x.Attributes.IsDerived() { return true // from sequencing } eq.sentAttributes = false @@ -193,7 +194,7 @@ func (eq *AttributesHandler) consolidateNextSafeAttributes(attributes *derive.At } eq.emitter.Emit(engine.PromotePendingSafeEvent{ Ref: ref, - Safe: attributes.IsLastInSpan, + Concluding: attributes.Concluding, DerivedFrom: attributes.DerivedFrom, }) } diff --git a/op-node/rollup/attributes/attributes_test.go b/op-node/rollup/attributes/attributes_test.go index c3ed171ce92f2..05fbd21fe784e 100644 --- a/op-node/rollup/attributes/attributes_test.go +++ b/op-node/rollup/attributes/attributes_test.go @@ -117,9 +117,9 @@ func TestAttributesHandler(t *testing.T) { NoTxPool: false, GasLimit: &payloadA1.ExecutionPayload.GasLimit, }, - Parent: refA0, - IsLastInSpan: true, - DerivedFrom: refB, + Parent: refA0, + Concluding: true, + DerivedFrom: refB, } refA1, err := derive.PayloadToBlockRef(cfg, payloadA1.ExecutionPayload) require.NoError(t, err) @@ -154,9 +154,9 @@ func TestAttributesHandler(t *testing.T) { NoTxPool: false, GasLimit: &payloadA1Alt.ExecutionPayload.GasLimit, }, - Parent: refA0, - IsLastInSpan: true, - DerivedFrom: refBAlt, + Parent: refA0, + Concluding: true, + DerivedFrom: refBAlt, } refA1Alt, err := derive.PayloadToBlockRef(cfg, payloadA1Alt.ExecutionPayload) @@ -272,7 +272,7 @@ func TestAttributesHandler(t *testing.T) { require.Nil(t, ah.attributes, "drop when attributes are successful") }) t.Run("consolidation passes", func(t *testing.T) { - fn := func(t *testing.T, lastInSpan bool) { + fn := func(t *testing.T, concluding bool) { logger := testlog.Logger(t, log.LevelInfo) l2 := &testutils.MockL2Client{} emitter := &testutils.MockEmitter{} @@ -280,10 +280,10 @@ func TestAttributesHandler(t *testing.T) { ah.AttachEmitter(emitter) attr := &derive.AttributesWithParent{ - Attributes: attrA1.Attributes, // attributes will match, passing consolidation - Parent: attrA1.Parent, - IsLastInSpan: lastInSpan, - DerivedFrom: refB, + Attributes: attrA1.Attributes, // attributes will match, passing consolidation + Parent: attrA1.Parent, + Concluding: concluding, + DerivedFrom: refB, } emitter.ExpectOnce(derive.ConfirmReceivedAttributesEvent{}) emitter.ExpectOnce(engine.PendingSafeRequestEvent{}) @@ -296,7 +296,7 @@ func TestAttributesHandler(t *testing.T) { emitter.ExpectOnce(engine.PromotePendingSafeEvent{ Ref: refA1, - Safe: lastInSpan, // last in span becomes safe instantaneously + Concluding: concluding, DerivedFrom: refB, }) ah.OnEvent(engine.PendingSafeUpdateEvent{ @@ -340,7 +340,7 @@ func TestAttributesHandler(t *testing.T) { require.NotNil(t, ah.attributes, "queued up derived attributes") // sanity check test setup - require.True(t, attrA1Alt.IsLastInSpan, "must be last in span for attributes to become safe") + require.True(t, attrA1Alt.Concluding, "must be concluding attributes") // attrA1Alt will fit right on top of A0 emitter.ExpectOnce(engine.BuildStartEvent{Attributes: attrA1Alt}) @@ -396,5 +396,4 @@ func TestAttributesHandler(t *testing.T) { l2.AssertExpectations(t) emitter.AssertExpectations(t) }) - } diff --git a/op-node/rollup/chain_spec.go b/op-node/rollup/chain_spec.go index 66d2e526d0d12..1ddcb31902904 100644 --- a/op-node/rollup/chain_spec.go +++ b/op-node/rollup/chain_spec.go @@ -1,6 +1,7 @@ package rollup import ( + "fmt" "math/big" "github.com/ethereum-optimism/optimism/op-node/params" @@ -41,19 +42,47 @@ const ( Granite ForkName = "granite" Holocene ForkName = "holocene" Interop ForkName = "interop" - None ForkName = "none" + // ADD NEW FORKS TO AllForks BELOW! + None ForkName = "none" ) -var nextFork = map[ForkName]ForkName{ - Bedrock: Regolith, - Regolith: Canyon, - Canyon: Delta, - Delta: Ecotone, - Ecotone: Fjord, - Fjord: Granite, - Granite: Holocene, - Holocene: Interop, - Interop: None, +var AllForks = []ForkName{ + Bedrock, + Regolith, + Canyon, + Delta, + Ecotone, + Fjord, + Granite, + Holocene, + Interop, + // ADD NEW FORKS HERE! +} + +func ForksFrom(fork ForkName) []ForkName { + for i, f := range AllForks { + if f == fork { + return AllForks[i:] + } + } + panic(fmt.Sprintf("invalid fork: %s", fork)) +} + +var nextFork = func() map[ForkName]ForkName { + m := make(map[ForkName]ForkName, len(AllForks)) + for i, f := range AllForks { + if i == len(AllForks)-1 { + m[f] = None + break + } + m[f] = AllForks[i+1] + } + return m +}() + +func IsValidFork(fork ForkName) bool { + _, ok := nextFork[fork] + return ok } type ChainSpec struct { @@ -80,6 +109,11 @@ func (s *ChainSpec) IsCanyon(t uint64) bool { return s.config.IsCanyon(t) } +// IsHolocene returns true if t >= holocene_time +func (s *ChainSpec) IsHolocene(t uint64) bool { + return s.config.IsHolocene(t) +} + // MaxChannelBankSize returns the maximum number of bytes the can allocated inside the channel bank // before pruning occurs at the given timestamp. func (s *ChainSpec) MaxChannelBankSize(t uint64) uint64 { diff --git a/op-node/rollup/derive/attributes.go b/op-node/rollup/derive/attributes.go index e17888201baef..5d859a9fcd596 100644 --- a/op-node/rollup/derive/attributes.go +++ b/op-node/rollup/derive/attributes.go @@ -28,6 +28,8 @@ type FetchingAttributesBuilder struct { rollupCfg *rollup.Config l1 L1ReceiptsFetcher l2 SystemConfigL2Fetcher + // whether to skip the L1 origin timestamp check - only for testing purposes + testSkipL1OriginCheck bool } func NewFetchingAttributesBuilder(rollupCfg *rollup.Config, l1 L1ReceiptsFetcher, l2 SystemConfigL2Fetcher) *FetchingAttributesBuilder { @@ -38,6 +40,12 @@ func NewFetchingAttributesBuilder(rollupCfg *rollup.Config, l1 L1ReceiptsFetcher } } +// TestSkipL1OriginCheck skips the L1 origin timestamp check for testing purposes. +// Must not be used in production! +func (ba *FetchingAttributesBuilder) TestSkipL1OriginCheck() { + ba.testSkipL1OriginCheck = true +} + // PreparePayloadAttributes prepares a PayloadAttributes template that is ready to build a L2 block with deposits only, on top of the given l2Parent, with the given epoch as L1 origin. // The template defaults to NoTxPool=true, and no sequencer transactions: the caller has to modify the template to add transactions, // by setting NoTxPool=false as sequencer, or by appending batch transactions as verifier. @@ -93,9 +101,9 @@ func (ba *FetchingAttributesBuilder) PreparePayloadAttributes(ctx context.Contex seqNumber = l2Parent.SequenceNumber + 1 } - // Sanity check the L1 origin was correctly selected to maintain the time invariant between L1 and L2 nextL2Time := l2Parent.Time + ba.rollupCfg.BlockTime - if nextL2Time < l1Info.Time() { + // Sanity check the L1 origin was correctly selected to maintain the time invariant between L1 and L2 + if !ba.testSkipL1OriginCheck && nextL2Time < l1Info.Time() { return nil, NewResetError(fmt.Errorf("cannot build L2 block on top %s for time %d before L1 origin %s at time %d", l2Parent, nextL2Time, eth.ToBlockID(l1Info), l1Info.Time())) } diff --git a/op-node/rollup/derive/attributes_queue.go b/op-node/rollup/derive/attributes_queue.go index c15079c6bfa9f..dba39ef742ff3 100644 --- a/op-node/rollup/derive/attributes_queue.go +++ b/op-node/rollup/derive/attributes_queue.go @@ -2,6 +2,7 @@ package derive import ( "context" + "errors" "fmt" "io" "time" @@ -28,23 +29,44 @@ type AttributesBuilder interface { } type AttributesWithParent struct { - Attributes *eth.PayloadAttributes - Parent eth.L2BlockRef - IsLastInSpan bool + Attributes *eth.PayloadAttributes + Parent eth.L2BlockRef + Concluding bool // Concluding indicates that the attributes conclude the pending safe phase DerivedFrom eth.L1BlockRef } +// WithDepositsOnly return a shallow clone with all non-Deposit transactions +// stripped from the transactions of its attributes. The order is preserved. +func (a *AttributesWithParent) WithDepositsOnly() *AttributesWithParent { + clone := *a + clone.Attributes = clone.Attributes.WithDepositsOnly() + return &clone +} + +func (a *AttributesWithParent) IsDerived() bool { + return a.DerivedFrom != (eth.L1BlockRef{}) +} + type AttributesQueue struct { - log log.Logger - config *rollup.Config - builder AttributesBuilder - prev *BatchQueue - batch *SingularBatch - isLastInSpan bool + log log.Logger + config *rollup.Config + builder AttributesBuilder + prev SingularBatchProvider + + batch *SingularBatch + concluding bool + lastAttribs *AttributesWithParent } -func NewAttributesQueue(log log.Logger, cfg *rollup.Config, builder AttributesBuilder, prev *BatchQueue) *AttributesQueue { +type SingularBatchProvider interface { + ResettableStage + ChannelFlusher + Origin() eth.L1BlockRef + NextBatch(context.Context, eth.L2BlockRef) (*SingularBatch, bool, error) +} + +func NewAttributesQueue(log log.Logger, cfg *rollup.Config, builder AttributesBuilder, prev SingularBatchProvider) *AttributesQueue { return &AttributesQueue{ log: log, config: cfg, @@ -60,12 +82,12 @@ func (aq *AttributesQueue) Origin() eth.L1BlockRef { func (aq *AttributesQueue) NextAttributes(ctx context.Context, parent eth.L2BlockRef) (*AttributesWithParent, error) { // Get a batch if we need it if aq.batch == nil { - batch, isLastInSpan, err := aq.prev.NextBatch(ctx, parent) + batch, concluding, err := aq.prev.NextBatch(ctx, parent) if err != nil { return nil, err } aq.batch = batch - aq.isLastInSpan = isLastInSpan + aq.concluding = concluding } // Actually generate the next attributes @@ -74,16 +96,16 @@ func (aq *AttributesQueue) NextAttributes(ctx context.Context, parent eth.L2Bloc } else { // Clear out the local state once we will succeed attr := AttributesWithParent{ - Attributes: attrs, - Parent: parent, - IsLastInSpan: aq.isLastInSpan, - DerivedFrom: aq.Origin(), + Attributes: attrs, + Parent: parent, + Concluding: aq.concluding, + DerivedFrom: aq.Origin(), } + aq.lastAttribs = &attr aq.batch = nil - aq.isLastInSpan = false + aq.concluding = false return &attr, nil } - } // createNextAttributes transforms a batch into a payload attributes. This sets `NoTxPool` and appends the batched transactions @@ -114,8 +136,35 @@ func (aq *AttributesQueue) createNextAttributes(ctx context.Context, batch *Sing return attrs, nil } -func (aq *AttributesQueue) Reset(ctx context.Context, _ eth.L1BlockRef, _ eth.SystemConfig) error { +func (aq *AttributesQueue) reset() { aq.batch = nil - aq.isLastInSpan = false // overwritten later, but set for consistency + aq.concluding = false // overwritten later, but set for consistency + aq.lastAttribs = nil +} + +func (aq *AttributesQueue) Reset(ctx context.Context, _ eth.L1BlockRef, _ eth.SystemConfig) error { + aq.reset() return io.EOF } + +func (aq *AttributesQueue) DepositsOnlyAttributes(parent eth.BlockID, derivedFrom eth.L1BlockRef) (*AttributesWithParent, error) { + // Sanity checks - these cannot happen with correct deriver implementations. + if aq.batch != nil { + return nil, fmt.Errorf("unexpected buffered batch, parent hash: %s, epoch: %s", aq.batch.ParentHash, aq.batch.Epoch()) + } else if aq.lastAttribs == nil { + return nil, errors.New("no attributes generated yet") + } else if derivedFrom != aq.lastAttribs.DerivedFrom { + return nil, fmt.Errorf( + "unexpected derivation origin, last_origin: %s, invalid_origin: %s", + aq.lastAttribs.DerivedFrom, derivedFrom) + } else if parent != aq.lastAttribs.Parent.ID() { + return nil, fmt.Errorf( + "unexpected parent: last_parent: %s, invalid_parent: %s", + aq.lastAttribs.Parent.ID(), parent) + } + + aq.prev.FlushChannel() // flush all channel data in previous stages + attrs := aq.lastAttribs.WithDepositsOnly() + aq.lastAttribs = attrs + return attrs, nil +} diff --git a/op-node/rollup/derive/batch_mux.go b/op-node/rollup/derive/batch_mux.go new file mode 100644 index 0000000000000..ea8336a59b1ee --- /dev/null +++ b/op-node/rollup/derive/batch_mux.go @@ -0,0 +1,76 @@ +package derive + +import ( + "context" + "fmt" + + "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum/go-ethereum/log" + "golang.org/x/exp/slices" +) + +// BatchMux multiplexes between different batch stages. +// Stages are swapped on demand during Reset calls, or explicitly with Transform. +// It currently chooses the BatchQueue pre-Holocene and the BatchStage post-Holocene. +type BatchMux struct { + log log.Logger + cfg *rollup.Config + prev NextBatchProvider + l2 SafeBlockFetcher + + // embedded active stage + SingularBatchProvider +} + +var _ SingularBatchProvider = (*BatchMux)(nil) + +// NewBatchMux returns an uninitialized BatchMux. Reset has to be called before +// calling other methods, to activate the right stage for a given L1 origin. +func NewBatchMux(lgr log.Logger, cfg *rollup.Config, prev NextBatchProvider, l2 SafeBlockFetcher) *BatchMux { + return &BatchMux{log: lgr, cfg: cfg, prev: prev, l2: l2} +} + +func (b *BatchMux) Reset(ctx context.Context, base eth.L1BlockRef, sysCfg eth.SystemConfig) error { + // TODO(12490): change to a switch over b.cfg.ActiveFork(base.Time) + switch { + default: + if _, ok := b.SingularBatchProvider.(*BatchQueue); !ok { + b.log.Info("BatchMux: activating pre-Holocene stage during reset", "origin", base) + b.SingularBatchProvider = NewBatchQueue(b.log, b.cfg, b.prev, b.l2) + } + case b.cfg.IsHolocene(base.Time): + if _, ok := b.SingularBatchProvider.(*BatchStage); !ok { + b.log.Info("BatchMux: activating Holocene stage during reset", "origin", base) + b.SingularBatchProvider = NewBatchStage(b.log, b.cfg, b.prev, b.l2) + } + } + return b.SingularBatchProvider.Reset(ctx, base, sysCfg) +} + +func (b *BatchMux) Transform(f rollup.ForkName) { + switch f { + case rollup.Holocene: + b.TransformHolocene() + } +} + +func (b *BatchMux) TransformHolocene() { + switch bp := b.SingularBatchProvider.(type) { + case *BatchQueue: + b.log.Info("BatchMux: transforming to Holocene stage") + bs := NewBatchStage(b.log, b.cfg, b.prev, b.l2) + // Even though any ongoing span batch or queued batches are dropped at Holocene activation, the + // post-Holocene batch stage still needs access to the collected l1Blocks pre-Holocene because + // the first Holocene channel will contain pre-Holocene batches. + bs.l1Blocks = slices.Clone(bp.l1Blocks) + bs.origin = bp.origin + b.SingularBatchProvider = bs + case *BatchStage: + // Even if the pipeline is Reset to the activation block, the previous origin will be the + // same, so transfromStages isn't called. + panic(fmt.Sprintf("Holocene BatchStage already active, old origin: %v", bp.Origin())) + default: + panic(fmt.Sprintf("unknown batch stage type: %T", bp)) + } +} diff --git a/op-node/rollup/derive/batch_mux_test.go b/op-node/rollup/derive/batch_mux_test.go new file mode 100644 index 0000000000000..2afc25a69dc2c --- /dev/null +++ b/op-node/rollup/derive/batch_mux_test.go @@ -0,0 +1,68 @@ +package derive + +import ( + "context" + "io" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" + + "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/testlog" +) + +func TestBatchMux_LaterHolocene(t *testing.T) { + log := testlog.Logger(t, log.LevelTrace) + ctx := context.Background() + l1A := eth.L1BlockRef{Time: 0, Hash: common.Hash{0xaa}} + l1B := eth.L1BlockRef{Time: 12, Hash: common.Hash{0xbb}} + cfg := &rollup.Config{ + HoloceneTime: &l1B.Time, + } + b := NewBatchMux(log, cfg, nil, nil) + + require.Nil(t, b.SingularBatchProvider) + + err := b.Reset(ctx, l1A, eth.SystemConfig{}) + require.Equal(t, io.EOF, err) + require.IsType(t, new(BatchQueue), b.SingularBatchProvider) + require.Equal(t, l1A, b.SingularBatchProvider.(*BatchQueue).origin) + + b.Transform(rollup.Holocene) + require.IsType(t, new(BatchStage), b.SingularBatchProvider) + require.Equal(t, l1A, b.SingularBatchProvider.(*BatchStage).origin) + + err = b.Reset(ctx, l1B, eth.SystemConfig{}) + require.Equal(t, io.EOF, err) + require.IsType(t, new(BatchStage), b.SingularBatchProvider) + require.Equal(t, l1B, b.SingularBatchProvider.(*BatchStage).origin) + + err = b.Reset(ctx, l1A, eth.SystemConfig{}) + require.Equal(t, io.EOF, err) + require.IsType(t, new(BatchQueue), b.SingularBatchProvider) + require.Equal(t, l1A, b.SingularBatchProvider.(*BatchQueue).origin) +} + +func TestBatchMux_ActiveHolocene(t *testing.T) { + log := testlog.Logger(t, log.LevelTrace) + ctx := context.Background() + l1A := eth.L1BlockRef{Time: 42, Hash: common.Hash{0xaa}} + cfg := &rollup.Config{ + HoloceneTime: &l1A.Time, + } + // without the fake input, the panic check later would panic because of the Origin() call + prev := &fakeBatchQueueInput{origin: l1A} + b := NewBatchMux(log, cfg, prev, nil) + + require.Nil(t, b.SingularBatchProvider) + + err := b.Reset(ctx, l1A, eth.SystemConfig{}) + require.Equal(t, io.EOF, err) + require.IsType(t, new(BatchStage), b.SingularBatchProvider) + require.Equal(t, l1A, b.SingularBatchProvider.(*BatchStage).origin) + + require.Panics(t, func() { b.Transform(rollup.Holocene) }) +} diff --git a/op-node/rollup/derive/batch_queue.go b/op-node/rollup/derive/batch_queue.go index b2f27ea27f3a5..3029d1199767a 100644 --- a/op-node/rollup/derive/batch_queue.go +++ b/op-node/rollup/derive/batch_queue.go @@ -27,10 +27,6 @@ import ( // It is internally responsible for making sure that batches with L1 inclusions block outside it's // working range are not considered or pruned. -type ChannelFlusher interface { - FlushChannel() -} - type NextBatchProvider interface { ChannelFlusher Origin() eth.L1BlockRef @@ -49,6 +45,8 @@ type baseBatchStage struct { log log.Logger config *rollup.Config prev NextBatchProvider + l2 SafeBlockFetcher + origin eth.L1BlockRef // l1Blocks contains consecutive eth.L1BlockRef sorted by time. @@ -61,8 +59,6 @@ type baseBatchStage struct { // nextSpan is cached SingularBatches derived from SpanBatch nextSpan []*SingularBatch - - l2 SafeBlockFetcher } func newBaseBatchStage(log log.Logger, cfg *rollup.Config, prev NextBatchProvider, l2 SafeBlockFetcher) baseBatchStage { @@ -86,11 +82,6 @@ func (bs *baseBatchStage) Log() log.Logger { } } -type SingularBatchProvider interface { - ResettableStage - NextBatch(context.Context, eth.L2BlockRef) (*SingularBatch, bool, error) -} - // BatchQueue contains a set of batches for every L1 block. // L1 blocks are contiguous and this does not support reorgs. type BatchQueue struct { @@ -262,10 +253,10 @@ func (bs *baseBatchStage) reset(base eth.L1BlockRef) { // Copy over the Origin from the next stage // It is set in the engine queue (two stages away) such that the L2 Safe Head origin is the progress bs.origin = base + bs.l1Blocks = bs.l1Blocks[:0] // Include the new origin as an origin to build on // Note: This is only for the initialization case. During normal resets we will later // throw out this block. - bs.l1Blocks = bs.l1Blocks[:0] bs.l1Blocks = append(bs.l1Blocks, base) bs.nextSpan = bs.nextSpan[:0] } @@ -276,6 +267,12 @@ func (bq *BatchQueue) Reset(_ context.Context, base eth.L1BlockRef, _ eth.System return io.EOF } +func (bq *BatchQueue) FlushChannel() { + // We need to implement the ChannelFlusher interface with the BatchQueue but it's never called + // of which the BatchMux takes care. + panic("BatchQueue: invalid FlushChannel call") +} + func (bq *BatchQueue) AddBatch(ctx context.Context, batch Batch, parent eth.L2BlockRef) { if len(bq.l1Blocks) == 0 { panic(fmt.Errorf("cannot add batch with timestamp %d, no origin was prepared", batch.GetTimestamp())) diff --git a/op-node/rollup/derive/batch_stage.go b/op-node/rollup/derive/batch_stage.go index 22fdbc1571587..d18efed2278e9 100644 --- a/op-node/rollup/derive/batch_stage.go +++ b/op-node/rollup/derive/batch_stage.go @@ -15,6 +15,8 @@ type BatchStage struct { baseBatchStage } +var _ SingularBatchProvider = (*BatchStage)(nil) + func NewBatchStage(log log.Logger, cfg *rollup.Config, prev NextBatchProvider, l2 SafeBlockFetcher) *BatchStage { return &BatchStage{baseBatchStage: newBaseBatchStage(log, cfg, prev, l2)} } @@ -68,7 +70,8 @@ func (bs *BatchStage) NextBatch(ctx context.Context, parent eth.L2BlockRef) (*Si // We only consider empty batch generation after we've drained all batches from the local // span batch queue and the previous stage. empty, err := bs.deriveNextEmptyBatch(ctx, true, parent) - return empty, false, err + // An empty batch always advances the (local) safe head. + return empty, true, err } else if err != nil { return nil, false, err } @@ -78,7 +81,8 @@ func (bs *BatchStage) NextBatch(ctx context.Context, parent eth.L2BlockRef) (*Si switch validity { case BatchAccept: // continue batch.LogContext(bs.Log()).Debug("Found next singular batch") - return batch, len(bs.nextSpan) == 0, nil + // BatchStage is only used with Holocene, where blocks immediately become (local) safe + return batch, true, nil case BatchPast: batch.LogContext(bs.Log()).Warn("Dropping past singular batch") // NotEnoughData to read in next batch until we're through all past batches diff --git a/op-node/rollup/derive/channel_assembler.go b/op-node/rollup/derive/channel_assembler.go index 6d1424f46a323..be821ca955f40 100644 --- a/op-node/rollup/derive/channel_assembler.go +++ b/op-node/rollup/derive/channel_assembler.go @@ -20,16 +20,16 @@ type ChannelAssembler struct { prev NextFrameProvider } -var _ ResettableStage = (*ChannelAssembler)(nil) +var _ RawChannelProvider = (*ChannelAssembler)(nil) type ChannelStageSpec interface { ChannelTimeout(t uint64) uint64 MaxRLPBytesPerChannel(t uint64) uint64 } -// NewChannelStage creates a Holocene ChannelStage. -// It must only be used for derivation from Holocene activation. -func NewChannelStage(log log.Logger, spec ChannelStageSpec, prev NextFrameProvider, m Metrics) *ChannelAssembler { +// NewChannelAssembler creates the Holocene channel stage. +// It must only be used for derivation from Holocene origins. +func NewChannelAssembler(log log.Logger, spec ChannelStageSpec, prev NextFrameProvider, m Metrics) *ChannelAssembler { return &ChannelAssembler{ log: log, spec: spec, @@ -51,6 +51,10 @@ func (ca *ChannelAssembler) Reset(context.Context, eth.L1BlockRef, eth.SystemCon return io.EOF } +func (ca *ChannelAssembler) FlushChannel() { + ca.resetChannel() +} + func (ca *ChannelAssembler) resetChannel() { ca.channel = nil } @@ -60,7 +64,7 @@ func (ca *ChannelAssembler) channelTimedOut() bool { return ca.channel.OpenBlockNumber()+ca.spec.ChannelTimeout(ca.Origin().Time) < ca.Origin().Number } -func (ca *ChannelAssembler) NextData(ctx context.Context) ([]byte, error) { +func (ca *ChannelAssembler) NextRawChannel(ctx context.Context) ([]byte, error) { if ca.channel != nil && ca.channelTimedOut() { ca.metrics.RecordChannelTimedOut() ca.resetChannel() diff --git a/op-node/rollup/derive/channel_assembler_test.go b/op-node/rollup/derive/channel_assembler_test.go index 77dc1d87f7e34..75429e5bae587 100644 --- a/op-node/rollup/derive/channel_assembler_test.go +++ b/op-node/rollup/derive/channel_assembler_test.go @@ -110,11 +110,11 @@ func TestChannelStage_NextData(t *testing.T) { MaxRLPBytesPerChannelOverride: tc.rlpOverride, } - cs := NewChannelStage(lgr, spec, fq, metrics.NoopMetrics) + cs := NewChannelAssembler(lgr, spec, fq, metrics.NoopMetrics) for i, fs := range tc.frames { fq.AddFrames(fs...) - data, err := cs.NextData(context.Background()) + data, err := cs.NextRawChannel(context.Background()) require.Equal(t, tc.expData[i], string(data)) require.ErrorIs(t, tc.expErr[i], err) // invariant: never holds a ready channel @@ -129,7 +129,7 @@ func TestChannelStage_NextData(t *testing.T) { } // final call should always be io.EOF after exhausting frame queue - data, err := cs.NextData(context.Background()) + data, err := cs.NextRawChannel(context.Background()) require.Nil(t, data) require.Equal(t, io.EOF, err) }) @@ -141,10 +141,10 @@ func TestChannelStage_NextData_Timeout(t *testing.T) { fq := &fakeChannelBankInput{} lgr := testlog.Logger(t, slog.LevelWarn) spec := rollup.NewChainSpec(&rollup.Config{GraniteTime: ptr(uint64(0))}) // const channel timeout - cs := NewChannelStage(lgr, spec, fq, metrics.NoopMetrics) + cs := NewChannelAssembler(lgr, spec, fq, metrics.NoopMetrics) fq.AddFrames("a:0:foo") - data, err := cs.NextData(context.Background()) + data, err := cs.NextRawChannel(context.Background()) require.Nil(data) require.Equal(io.EOF, err) require.NotNil(cs.channel) @@ -153,7 +153,7 @@ func TestChannelStage_NextData_Timeout(t *testing.T) { // move close to timeout fq.origin.Number = spec.ChannelTimeout(0) fq.AddFrames("a:1:bar") - data, err = cs.NextData(context.Background()) + data, err = cs.NextRawChannel(context.Background()) require.Nil(data) require.Equal(io.EOF, err) require.NotNil(cs.channel) @@ -162,7 +162,7 @@ func TestChannelStage_NextData_Timeout(t *testing.T) { // timeout channel by moving origin past timeout fq.origin.Number = spec.ChannelTimeout(0) + 1 fq.AddFrames("a:2:baz!") - data, err = cs.NextData(context.Background()) + data, err = cs.NextRawChannel(context.Background()) require.Nil(data) require.Equal(io.EOF, err) require.Nil(cs.channel) diff --git a/op-node/rollup/derive/channel_bank.go b/op-node/rollup/derive/channel_bank.go index 39582d2712fa2..57ab70096507d 100644 --- a/op-node/rollup/derive/channel_bank.go +++ b/op-node/rollup/derive/channel_bank.go @@ -40,13 +40,13 @@ type ChannelBank struct { prev NextFrameProvider } -var _ ResettableStage = (*ChannelBank)(nil) +var _ RawChannelProvider = (*ChannelBank)(nil) // NewChannelBank creates a ChannelBank, which should be Reset(origin) before use. -func NewChannelBank(log log.Logger, cfg *rollup.Config, prev NextFrameProvider, m Metrics) *ChannelBank { +func NewChannelBank(log log.Logger, spec *rollup.ChainSpec, prev NextFrameProvider, m Metrics) *ChannelBank { return &ChannelBank{ log: log, - spec: rollup.NewChainSpec(cfg), + spec: spec, metrics: m, channels: make(map[ChannelID]*Channel), channelQueue: make([]ChannelID, 0, 10), @@ -170,12 +170,12 @@ func (cb *ChannelBank) tryReadChannelAtIndex(i int) (data []byte, err error) { return data, nil } -// NextData pulls the next piece of data from the channel bank. +// NextRawChannel pulls the next piece of data from the channel bank. // Note that it attempts to pull data out of the channel bank prior to // loading data in (unlike most other stages). This is to ensure maintain // consistency around channel bank pruning which depends upon the order // of operations. -func (cb *ChannelBank) NextData(ctx context.Context) ([]byte, error) { +func (cb *ChannelBank) NextRawChannel(ctx context.Context) ([]byte, error) { // Do the read from the channel bank first data, err := cb.Read() if err == io.EOF { @@ -203,6 +203,12 @@ func (cb *ChannelBank) Reset(ctx context.Context, base eth.L1BlockRef, _ eth.Sys return io.EOF } +func (bq *ChannelBank) FlushChannel() { + // We need to implement the ChannelFlusher interface with the ChannelBank but it's never called + // of which the ChannelMux takes care. + panic("ChannelBank: invalid FlushChannel call") +} + type L1BlockRefByHashFetcher interface { L1BlockRefByHash(context.Context, common.Hash) (eth.L1BlockRef, error) } diff --git a/op-node/rollup/derive/channel_bank_test.go b/op-node/rollup/derive/channel_bank_test.go index 75b7503400b1e..7b0baddf2373c 100644 --- a/op-node/rollup/derive/channel_bank_test.go +++ b/op-node/rollup/derive/channel_bank_test.go @@ -106,32 +106,31 @@ func TestChannelBankSimple(t *testing.T) { input.AddFrames("a:0:first", "a:2:third!") input.AddFrames("a:1:second") - cfg := &rollup.Config{ChannelTimeoutBedrock: 10} - - cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), cfg, input, metrics.NoopMetrics) + spec := rollup.NewChainSpec(&rollup.Config{ChannelTimeoutBedrock: 10}) + cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), spec, input, metrics.NoopMetrics) // Load the first frame - out, err := cb.NextData(context.Background()) + out, err := cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load the third frame - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load the second frame - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Pull out the channel data - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.Nil(t, err) require.Equal(t, "firstsecondthird", string(out)) // No more data - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.Nil(t, out) require.Equal(t, io.EOF, err) } @@ -149,52 +148,51 @@ func TestChannelBankInterleavedPreCanyon(t *testing.T) { input.AddFrames("b:0:premiere") input.AddFrames("a:1:second") - cfg := &rollup.Config{ChannelTimeoutBedrock: 10, CanyonTime: nil} - - cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), cfg, input, metrics.NoopMetrics) + spec := rollup.NewChainSpec(&rollup.Config{ChannelTimeoutBedrock: 10}) + cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), spec, input, metrics.NoopMetrics) // Load a:0 - out, err := cb.NextData(context.Background()) + out, err := cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load b:2 - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load b:1 - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load a:2 - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load b:0 & Channel b is complete, but channel a was opened first - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load a:1 - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Pull out the channel a - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.Nil(t, err) require.Equal(t, "firstsecondthird", string(out)) // Pull out the channel b - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.Nil(t, err) require.Equal(t, "premieredeuxtrois", string(out)) // No more data - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.Nil(t, out) require.Equal(t, io.EOF, err) } @@ -213,52 +211,51 @@ func TestChannelBankInterleaved(t *testing.T) { input.AddFrames("a:1:second") ct := uint64(0) - cfg := &rollup.Config{ChannelTimeoutBedrock: 10, CanyonTime: &ct} - - cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), cfg, input, metrics.NoopMetrics) + spec := rollup.NewChainSpec(&rollup.Config{ChannelTimeoutBedrock: 10, CanyonTime: &ct}) + cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), spec, input, metrics.NoopMetrics) // Load a:0 - out, err := cb.NextData(context.Background()) + out, err := cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load b:2 - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load b:1 - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load a:2 - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load b:0 & Channel b is complete. Channel a was opened first but isn't ready - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Pull out the channel b because it's ready first. - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.Nil(t, err) require.Equal(t, "premieredeuxtrois", string(out)) // Load a:1 - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Pull out the channel a - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.Nil(t, err) require.Equal(t, "firstsecondthird", string(out)) // No more data - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.Nil(t, out) require.Equal(t, io.EOF, err) } @@ -272,40 +269,39 @@ func TestChannelBankDuplicates(t *testing.T) { input.AddFrames("a:0:altfirst", "a:2:altthird!") input.AddFrames("a:1:second") - cfg := &rollup.Config{ChannelTimeoutBedrock: 10} - - cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), cfg, input, metrics.NoopMetrics) + spec := rollup.NewChainSpec(&rollup.Config{ChannelTimeoutBedrock: 10}) + cb := NewChannelBank(testlog.Logger(t, log.LevelCrit), spec, input, metrics.NoopMetrics) // Load the first frame - out, err := cb.NextData(context.Background()) + out, err := cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load the third frame - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load the duplicate frames - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Load the second frame - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.ErrorIs(t, err, NotEnoughData) require.Equal(t, []byte(nil), out) // Pull out the channel data. Expect to see the original set & not the duplicates - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.Nil(t, err) require.Equal(t, "firstsecondthird", string(out)) // No more data - out, err = cb.NextData(context.Background()) + out, err = cb.NextRawChannel(context.Background()) require.Nil(t, out) require.Equal(t, io.EOF, err) } diff --git a/op-node/rollup/derive/channel_in_reader.go b/op-node/rollup/derive/channel_in_reader.go index 2aabf6bc9fdde..cdb648c3b870b 100644 --- a/op-node/rollup/derive/channel_in_reader.go +++ b/op-node/rollup/derive/channel_in_reader.go @@ -21,7 +21,7 @@ type ChannelInReader struct { spec *rollup.ChainSpec cfg *rollup.Config nextBatchFn func() (*BatchData, error) - prev *ChannelBank + prev RawChannelProvider metrics Metrics } @@ -30,8 +30,15 @@ var ( _ ChannelFlusher = (*ChannelInReader)(nil) ) +type RawChannelProvider interface { + ResettableStage + ChannelFlusher + Origin() eth.L1BlockRef + NextRawChannel(ctx context.Context) ([]byte, error) +} + // NewChannelInReader creates a ChannelInReader, which should be Reset(origin) before use. -func NewChannelInReader(cfg *rollup.Config, log log.Logger, prev *ChannelBank, metrics Metrics) *ChannelInReader { +func NewChannelInReader(cfg *rollup.Config, log log.Logger, prev RawChannelProvider, metrics Metrics) *ChannelInReader { return &ChannelInReader{ spec: rollup.NewChainSpec(cfg), cfg: cfg, @@ -68,7 +75,7 @@ func (cr *ChannelInReader) NextChannel() { // It will return a temporary error if it needs to be called again to advance some internal state. func (cr *ChannelInReader) NextBatch(ctx context.Context) (Batch, error) { if cr.nextBatchFn == nil { - if data, err := cr.prev.NextData(ctx); err == io.EOF { + if data, err := cr.prev.NextRawChannel(ctx); err == io.EOF { return nil, io.EOF } else if err != nil { return nil, err @@ -128,5 +135,5 @@ func (cr *ChannelInReader) Reset(ctx context.Context, _ eth.L1BlockRef, _ eth.Sy func (cr *ChannelInReader) FlushChannel() { cr.nextBatchFn = nil - // TODO(12157): cr.prev.FlushChannel() - when we do wiring with ChannelStage + cr.prev.FlushChannel() } diff --git a/op-node/rollup/derive/channel_mux.go b/op-node/rollup/derive/channel_mux.go new file mode 100644 index 0000000000000..cb5ce66baffed --- /dev/null +++ b/op-node/rollup/derive/channel_mux.go @@ -0,0 +1,74 @@ +package derive + +import ( + "context" + "fmt" + + "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum/go-ethereum/log" +) + +// ChannelMux multiplexes between different channel stages. +// Stages are swapped on demand during Reset calls, or explicitly with Transform. +// It currently chooses the ChannelBank pre-Holocene and the ChannelAssembler post-Holocene. +type ChannelMux struct { + log log.Logger + spec *rollup.ChainSpec + prev NextFrameProvider + m Metrics + + // embedded active stage + RawChannelProvider +} + +var _ RawChannelProvider = (*ChannelMux)(nil) + +// NewChannelMux returns a ChannelMux with the ChannelBank as activated stage. Reset has to be called before +// calling other methods, to activate the right stage for a given L1 origin. +func NewChannelMux(log log.Logger, spec *rollup.ChainSpec, prev NextFrameProvider, m Metrics) *ChannelMux { + return &ChannelMux{ + log: log, + spec: spec, + prev: prev, + m: m, + } +} + +func (c *ChannelMux) Reset(ctx context.Context, base eth.L1BlockRef, sysCfg eth.SystemConfig) error { + // TODO(12490): change to a switch over c.cfg.ActiveFork(base.Time) + switch { + default: + if _, ok := c.RawChannelProvider.(*ChannelBank); !ok { + c.log.Info("ChannelMux: activating pre-Holocene stage during reset", "origin", base) + c.RawChannelProvider = NewChannelBank(c.log, c.spec, c.prev, c.m) + } + case c.spec.IsHolocene(base.Time): + if _, ok := c.RawChannelProvider.(*ChannelAssembler); !ok { + c.log.Info("ChannelMux: activating Holocene stage during reset", "origin", base) + c.RawChannelProvider = NewChannelAssembler(c.log, c.spec, c.prev, c.m) + } + } + return c.RawChannelProvider.Reset(ctx, base, sysCfg) +} + +func (c *ChannelMux) Transform(f rollup.ForkName) { + switch f { + case rollup.Holocene: + c.TransformHolocene() + } +} + +func (c *ChannelMux) TransformHolocene() { + switch cp := c.RawChannelProvider.(type) { + case *ChannelBank: + c.log.Info("ChannelMux: transforming to Holocene stage") + c.RawChannelProvider = NewChannelAssembler(c.log, c.spec, c.prev, c.m) + case *ChannelAssembler: + // Even if the pipeline is Reset to the activation block, the previous origin will be the + // same, so transfromStages isn't called. + panic(fmt.Sprintf("Holocene ChannelAssembler already active, old origin: %v", cp.Origin())) + default: + panic(fmt.Sprintf("unknown channel stage type: %T", cp)) + } +} diff --git a/op-node/rollup/derive/channel_mux_test.go b/op-node/rollup/derive/channel_mux_test.go new file mode 100644 index 0000000000000..59fd669922ae7 --- /dev/null +++ b/op-node/rollup/derive/channel_mux_test.go @@ -0,0 +1,69 @@ +package derive + +import ( + "context" + "io" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + + "github.com/ethereum-optimism/optimism/op-node/metrics" + "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/testlog" +) + +func TestChannelMux_LaterHolocene(t *testing.T) { + log := testlog.Logger(t, log.LevelTrace) + ctx := context.Background() + l1A := eth.L1BlockRef{Time: 0, Hash: common.Hash{0xaa}} + l1B := eth.L1BlockRef{Time: 12, Hash: common.Hash{0xbb}} + cfg := &rollup.Config{ + HoloceneTime: &l1B.Time, + } + spec := rollup.NewChainSpec(cfg) + m := metrics.NoopMetrics + c := NewChannelMux(log, spec, nil, m) + + require.Nil(t, c.RawChannelProvider) + + err := c.Reset(ctx, l1A, eth.SystemConfig{}) + require.Equal(t, io.EOF, err) + require.IsType(t, new(ChannelBank), c.RawChannelProvider) + + c.Transform(rollup.Holocene) + require.IsType(t, new(ChannelAssembler), c.RawChannelProvider) + + err = c.Reset(ctx, l1B, eth.SystemConfig{}) + require.Equal(t, io.EOF, err) + require.IsType(t, new(ChannelAssembler), c.RawChannelProvider) + + err = c.Reset(ctx, l1A, eth.SystemConfig{}) + require.Equal(t, io.EOF, err) + require.IsType(t, new(ChannelBank), c.RawChannelProvider) +} + +func TestChannelMux_ActiveHolocene(t *testing.T) { + log := testlog.Logger(t, log.LevelTrace) + ctx := context.Background() + l1A := eth.L1BlockRef{Time: 42, Hash: common.Hash{0xaa}} + cfg := &rollup.Config{ + HoloceneTime: &l1A.Time, + } + spec := rollup.NewChainSpec(cfg) + // without the fake input, the panic check later would panic because of the Origin() call + prev := &fakeChannelBankInput{} + m := metrics.NoopMetrics + c := NewChannelMux(log, spec, prev, m) + + require.Nil(t, c.RawChannelProvider) + + err := c.Reset(ctx, l1A, eth.SystemConfig{}) + require.Equal(t, io.EOF, err) + require.IsType(t, new(ChannelAssembler), c.RawChannelProvider) + + require.Panics(t, func() { c.Transform(rollup.Holocene) }) +} diff --git a/op-node/rollup/derive/deriver.go b/op-node/rollup/derive/deriver.go index 760891648524c..d95fdf3017f7c 100644 --- a/op-node/rollup/derive/deriver.go +++ b/op-node/rollup/derive/deriver.go @@ -3,6 +3,7 @@ package derive import ( "context" "errors" + "fmt" "io" "github.com/ethereum-optimism/optimism/op-node/rollup" @@ -20,6 +21,7 @@ func (d DeriverIdleEvent) String() string { type DeriverL1StatusEvent struct { Origin eth.L1BlockRef + LastL2 eth.L2BlockRef } func (d DeriverL1StatusEvent) String() string { @@ -63,6 +65,18 @@ func (ev PipelineStepEvent) String() string { return "pipeline-step" } +// DepositsOnlyPayloadAttributesRequestEvent requests a deposits-only version of the attributes from +// the pipeline. It is sent by the engine deriver and received by the PipelineDeriver. +// This event got introduced with Holocene. +type DepositsOnlyPayloadAttributesRequestEvent struct { + Parent eth.BlockID + DerivedFrom eth.L1BlockRef +} + +func (ev DepositsOnlyPayloadAttributesRequestEvent) String() string { + return "deposits-only-payload-attributes-request" +} + type PipelineDeriver struct { pipeline *DerivationPipeline @@ -99,7 +113,7 @@ func (d *PipelineDeriver) OnEvent(ev event.Event) bool { attrib, err := d.pipeline.Step(d.ctx, x.PendingSafe) postOrigin := d.pipeline.Origin() if preOrigin != postOrigin { - d.emitter.Emit(DeriverL1StatusEvent{Origin: postOrigin}) + d.emitter.Emit(DeriverL1StatusEvent{Origin: postOrigin, LastL2: x.PendingSafe}) } if err == io.EOF { d.pipeline.log.Debug("Derivation process went idle", "progress", d.pipeline.Origin(), "err", err) @@ -121,8 +135,7 @@ func (d *PipelineDeriver) OnEvent(ev event.Event) bool { d.emitter.Emit(rollup.EngineTemporaryErrorEvent{Err: err}) } else { if attrib != nil { - d.needAttributesConfirmation = true - d.emitter.Emit(DerivedAttributesEvent{Attributes: attrib}) + d.emitDerivedAttributesEvent(attrib) } else { d.emitter.Emit(DeriverMoreEvent{}) // continue with the next step if we can } @@ -131,8 +144,21 @@ func (d *PipelineDeriver) OnEvent(ev event.Event) bool { d.pipeline.ConfirmEngineReset() case ConfirmReceivedAttributesEvent: d.needAttributesConfirmation = false + case DepositsOnlyPayloadAttributesRequestEvent: + d.pipeline.log.Warn("Deriving deposits-only attributes", "origin", d.pipeline.Origin()) + attrib, err := d.pipeline.DepositsOnlyAttributes(x.Parent, x.DerivedFrom) + if err != nil { + d.emitter.Emit(rollup.CriticalErrorEvent{Err: fmt.Errorf("deriving deposits-only attributes: %w", err)}) + return true + } + d.emitDerivedAttributesEvent(attrib) default: return false } return true } + +func (d *PipelineDeriver) emitDerivedAttributesEvent(attrib *AttributesWithParent) { + d.needAttributesConfirmation = true + d.emitter.Emit(DerivedAttributesEvent{Attributes: attrib}) +} diff --git a/op-node/rollup/derive/doc.go b/op-node/rollup/derive/doc.go index 387508c77e0d9..fce2d9f1ce0d5 100644 --- a/op-node/rollup/derive/doc.go +++ b/op-node/rollup/derive/doc.go @@ -2,7 +2,7 @@ // and turn it into L2 blocks and results. Certain L2 data is also able to // turned back into L1 data. // -// The flow is data is as follows +// The data flow is as follows: // receipts, batches -> eth.PayloadAttributes, by parsing the L1 data and deriving L2 inputs // l2.PayloadAttributes -> l2.ExecutionPayload, by running the EVM (using an Execution Engine) // L2 block -> Corresponding L1 block info, by parsing the first deposited transaction diff --git a/op-node/rollup/derive/frame_queue.go b/op-node/rollup/derive/frame_queue.go index 77a2703290ce3..361f1cfda886b 100644 --- a/op-node/rollup/derive/frame_queue.go +++ b/op-node/rollup/derive/frame_queue.go @@ -10,7 +10,10 @@ import ( "github.com/ethereum-optimism/optimism/op-service/eth" ) -var _ NextFrameProvider = &FrameQueue{} +var ( + _ NextFrameProvider = (*FrameQueue)(nil) + _ ForkTransformer = (*FrameQueue)(nil) +) //go:generate mockery --name NextDataProvider --case snake type NextDataProvider interface { @@ -33,13 +36,20 @@ func NewFrameQueue(log log.Logger, cfg *rollup.Config, prev NextDataProvider) *F } } +func (fq *FrameQueue) Transform(f rollup.ForkName) { + switch f { + case rollup.Holocene: + fq.log.Info("FrameQueue: resetting with Holocene activation") + // With Holocene activation, the frame queue is simply reset + fq.reset() + } +} + func (fq *FrameQueue) Origin() eth.L1BlockRef { return fq.prev.Origin() } func (fq *FrameQueue) NextFrame(ctx context.Context) (Frame, error) { - // TODO(12157): reset frame queue once at Holocene L1 origin block - // Only load more frames if necessary if len(fq.frames) == 0 { if err := fq.loadNextFrames(ctx); err != nil { @@ -129,7 +139,11 @@ func pruneFrameQueue(frames []Frame) []Frame { return frames } -func (fq *FrameQueue) Reset(_ context.Context, _ eth.L1BlockRef, _ eth.SystemConfig) error { - fq.frames = fq.frames[:0] +func (fq *FrameQueue) Reset(context.Context, eth.L1BlockRef, eth.SystemConfig) error { + fq.reset() return io.EOF } + +func (fq *FrameQueue) reset() { + fq.frames = fq.frames[:0] +} diff --git a/op-node/rollup/derive/pipeline.go b/op-node/rollup/derive/pipeline.go index f114e2a4b0d36..e85366fd0f0e2 100644 --- a/op-node/rollup/derive/pipeline.go +++ b/op-node/rollup/derive/pipeline.go @@ -38,6 +38,17 @@ type ResettableStage interface { Reset(ctx context.Context, base eth.L1BlockRef, baseCfg eth.SystemConfig) error } +// A ChannelFlusher flushes all internal state related to the current channel and then +// calls FlushChannel on the stage it owns. Note that this is in contrast to Reset, which +// is called by the owning Pipeline in a loop over all stages. +type ChannelFlusher interface { + FlushChannel() +} + +type ForkTransformer interface { + Transform(rollup.ForkName) +} + type L2Source interface { PayloadByHash(context.Context, common.Hash) (*eth.ExecutionPayloadEnvelope, error) PayloadByNumber(context.Context, uint64) (*eth.ExecutionPayloadEnvelope, error) @@ -79,21 +90,22 @@ type DerivationPipeline struct { func NewDerivationPipeline(log log.Logger, rollupCfg *rollup.Config, l1Fetcher L1Fetcher, l1Blobs L1BlobsFetcher, altDA AltDAInputFetcher, l2Source L2Source, metrics Metrics, ) *DerivationPipeline { + spec := rollup.NewChainSpec(rollupCfg) // Pull stages l1Traversal := NewL1Traversal(log, rollupCfg, l1Fetcher) dataSrc := NewDataSourceFactory(log, rollupCfg, l1Fetcher, l1Blobs, altDA) // auxiliary stage for L1Retrieval l1Src := NewL1Retrieval(log, dataSrc, l1Traversal) frameQueue := NewFrameQueue(log, rollupCfg, l1Src) - bank := NewChannelBank(log, rollupCfg, frameQueue, metrics) - chInReader := NewChannelInReader(rollupCfg, log, bank, metrics) - batchQueue := NewBatchQueue(log, rollupCfg, chInReader, l2Source) + channelMux := NewChannelMux(log, spec, frameQueue, metrics) + chInReader := NewChannelInReader(rollupCfg, log, channelMux, metrics) + batchMux := NewBatchMux(log, rollupCfg, chInReader, l2Source) attrBuilder := NewFetchingAttributesBuilder(rollupCfg, l1Fetcher, l2Source) - attributesQueue := NewAttributesQueue(log, rollupCfg, attrBuilder, batchQueue) + attributesQueue := NewAttributesQueue(log, rollupCfg, attrBuilder, batchMux) // Reset from ResetEngine then up from L1 Traversal. The stages do not talk to each other during // the ResetEngine, but after the ResetEngine, this is the order in which the stages could talk to each other. // Note: The ResetEngine is the only reset that can fail. - stages := []ResettableStage{l1Traversal, l1Src, altDA, frameQueue, bank, chInReader, batchQueue, attributesQueue} + stages := []ResettableStage{l1Traversal, l1Src, altDA, frameQueue, channelMux, chInReader, batchMux, attributesQueue} return &DerivationPipeline{ log: log, @@ -122,6 +134,10 @@ func (dp *DerivationPipeline) Reset() { dp.engineIsReset = false } +func (dp *DerivationPipeline) DepositsOnlyAttributes(parent eth.BlockID, derivedFrom eth.L1BlockRef) (*AttributesWithParent, error) { + return dp.attrib.DepositsOnlyAttributes(parent, derivedFrom) +} + // Origin is the L1 block of the inner-most stage of the derivation pipeline, // i.e. the L1 chain up to and including this point included and/or produced all the safe L2 blocks. func (dp *DerivationPipeline) Origin() eth.L1BlockRef { @@ -177,6 +193,7 @@ func (dp *DerivationPipeline) Step(ctx context.Context, pendingSafeHead eth.L2Bl if err := VerifyNewL1Origin(ctx, prevOrigin, dp.l1Fetcher, newOrigin); err != nil { return nil, fmt.Errorf("failed to verify L1 origin transition: %w", err) } + dp.transformStages(prevOrigin, newOrigin) dp.origin = newOrigin } @@ -238,6 +255,20 @@ func (dp *DerivationPipeline) initialReset(ctx context.Context, resetL2Safe eth. return nil } +func (db *DerivationPipeline) transformStages(oldOrigin, newOrigin eth.L1BlockRef) { + fork := db.rollupCfg.IsActivationBlock(oldOrigin.Time, newOrigin.Time) + if fork == "" { + return + } + + db.log.Info("Transforming stages", "fork", fork) + for _, stage := range db.stages { + if tf, ok := stage.(ForkTransformer); ok { + tf.Transform(fork) + } + } +} + func (dp *DerivationPipeline) ConfirmEngineReset() { dp.engineIsReset = true } diff --git a/op-node/rollup/engine/build_cancel.go b/op-node/rollup/engine/build_cancel.go index 7c9995c28e854..4215e2d6c7f82 100644 --- a/op-node/rollup/engine/build_cancel.go +++ b/op-node/rollup/engine/build_cancel.go @@ -2,6 +2,9 @@ package engine import ( "context" + "errors" + + "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/eth" @@ -23,7 +26,9 @@ func (eq *EngDeriver) onBuildCancel(ev BuildCancelEvent) { eq.log.Warn("cancelling old block building job", "info", ev.Info) _, err := eq.ec.engine.GetPayload(ctx, ev.Info) if err != nil { - if x, ok := err.(eth.InputError); ok && x.Code == eth.UnknownPayload { //nolint:all + var rpcErr rpc.Error + if errors.As(err, &rpcErr) && eth.ErrorCode(rpcErr.ErrorCode()) == eth.UnknownPayload { + eq.log.Warn("tried cancelling unknown block building job", "info", ev.Info, "err", err) return // if unknown, then it did not need to be cancelled anymore. } eq.log.Error("failed to cancel block building job", "info", ev.Info, "err", err) diff --git a/op-node/rollup/engine/build_invalid.go b/op-node/rollup/engine/build_invalid.go index e684f2de2eade..4e58b50b105d4 100644 --- a/op-node/rollup/engine/build_invalid.go +++ b/op-node/rollup/engine/build_invalid.go @@ -3,10 +3,9 @@ package engine import ( "fmt" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" + "github.com/ethereum-optimism/optimism/op-service/eth" ) // BuildInvalidEvent is an internal engine event, to post-process upon invalid attributes. @@ -33,20 +32,19 @@ func (ev InvalidPayloadAttributesEvent) String() string { func (eq *EngDeriver) onBuildInvalid(ev BuildInvalidEvent) { eq.log.Warn("could not process payload attributes", "err", ev.Err) - // Count the number of deposits to see if the tx list is deposit only. - depositCount := 0 - for _, tx := range ev.Attributes.Attributes.Transactions { - if len(tx) > 0 && tx[0] == types.DepositTxType { - depositCount += 1 - } - } // Deposit transaction execution errors are suppressed in the execution engine, but if the // block is somehow invalid, there is nothing we can do to recover & we should exit. - if len(ev.Attributes.Attributes.Transactions) == depositCount { + if ev.Attributes.Attributes.IsDepositsOnly() { eq.log.Error("deposit only block was invalid", "parent", ev.Attributes.Parent, "err", ev.Err) eq.emitter.Emit(rollup.CriticalErrorEvent{Err: fmt.Errorf("failed to process block with only deposit transactions: %w", ev.Err)}) return } + + if ev.Attributes.IsDerived() && eq.cfg.IsHolocene(ev.Attributes.DerivedFrom.Time) { + eq.emitDepositsOnlyPayloadAttributesRequest(ev.Attributes.Parent.ID(), ev.Attributes.DerivedFrom) + return + } + // Revert the pending safe head to the safe head. eq.ec.SetPendingSafeL2Head(eq.ec.SafeL2Head()) // suppress the error b/c we want to retry with the next batch from the batch queue @@ -61,3 +59,12 @@ func (eq *EngDeriver) onBuildInvalid(ev BuildInvalidEvent) { // Signal that we deemed the attributes as unfit eq.emitter.Emit(InvalidPayloadAttributesEvent(ev)) } + +func (eq *EngDeriver) emitDepositsOnlyPayloadAttributesRequest(parent eth.BlockID, derivedFrom eth.L1BlockRef) { + eq.log.Warn("Holocene active, requesting deposits-only attributes", "parent", parent, "derived_from", derivedFrom) + // request deposits-only version + eq.emitter.Emit(derive.DepositsOnlyPayloadAttributesRequestEvent{ + Parent: parent, + DerivedFrom: derivedFrom, + }) +} diff --git a/op-node/rollup/engine/build_seal.go b/op-node/rollup/engine/build_seal.go index a5c72c74fdb76..b292681e13f12 100644 --- a/op-node/rollup/engine/build_seal.go +++ b/op-node/rollup/engine/build_seal.go @@ -2,9 +2,12 @@ package engine import ( "context" + "errors" "fmt" "time" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/eth" ) @@ -14,8 +17,8 @@ type PayloadSealInvalidEvent struct { Info eth.PayloadInfo Err error - IsLastInSpan bool - DerivedFrom eth.L1BlockRef + Concluding bool + DerivedFrom eth.L1BlockRef } func (ev PayloadSealInvalidEvent) String() string { @@ -30,8 +33,8 @@ type PayloadSealExpiredErrorEvent struct { Info eth.PayloadInfo Err error - IsLastInSpan bool - DerivedFrom eth.L1BlockRef + Concluding bool + DerivedFrom eth.L1BlockRef } func (ev PayloadSealExpiredErrorEvent) String() string { @@ -42,7 +45,7 @@ type BuildSealEvent struct { Info eth.PayloadInfo BuildStarted time.Time // if payload should be promoted to safe (must also be pending safe, see DerivedFrom) - IsLastInSpan bool + Concluding bool // payload is promoted to pending-safe if non-zero DerivedFrom eth.L1BlockRef } @@ -58,7 +61,8 @@ func (eq *EngDeriver) onBuildSeal(ev BuildSealEvent) { sealingStart := time.Now() envelope, err := eq.ec.engine.GetPayload(ctx, ev.Info) if err != nil { - if x, ok := err.(eth.InputError); ok && x.Code == eth.UnknownPayload { //nolint:all + var rpcErr rpc.Error + if errors.As(err, &rpcErr) && eth.ErrorCode(rpcErr.ErrorCode()) == eth.UnknownPayload { eq.log.Warn("Cannot seal block, payload ID is unknown", "payloadID", ev.Info.ID, "payload_time", ev.Info.Timestamp, "started_time", ev.BuildStarted) @@ -69,10 +73,10 @@ func (eq *EngDeriver) onBuildSeal(ev BuildSealEvent) { // same attributes with a new block-building job from here to recover from this error. // We name it "expired", as this generally identifies a timeout, unknown job, or otherwise invalidated work. eq.emitter.Emit(PayloadSealExpiredErrorEvent{ - Info: ev.Info, - Err: fmt.Errorf("failed to seal execution payload (ID: %s): %w", ev.Info.ID, err), - IsLastInSpan: ev.IsLastInSpan, - DerivedFrom: ev.DerivedFrom, + Info: ev.Info, + Err: fmt.Errorf("failed to seal execution payload (ID: %s): %w", ev.Info.ID, err), + Concluding: ev.Concluding, + DerivedFrom: ev.DerivedFrom, }) return } @@ -82,8 +86,8 @@ func (eq *EngDeriver) onBuildSeal(ev BuildSealEvent) { Info: ev.Info, Err: fmt.Errorf("failed sanity-check of execution payload contents (ID: %s, blockhash: %s): %w", ev.Info.ID, envelope.ExecutionPayload.BlockHash, err), - IsLastInSpan: ev.IsLastInSpan, - DerivedFrom: ev.DerivedFrom, + Concluding: ev.Concluding, + DerivedFrom: ev.DerivedFrom, }) return } @@ -91,10 +95,10 @@ func (eq *EngDeriver) onBuildSeal(ev BuildSealEvent) { ref, err := derive.PayloadToBlockRef(eq.cfg, envelope.ExecutionPayload) if err != nil { eq.emitter.Emit(PayloadSealInvalidEvent{ - Info: ev.Info, - Err: fmt.Errorf("failed to decode L2 block ref from payload: %w", err), - IsLastInSpan: ev.IsLastInSpan, - DerivedFrom: ev.DerivedFrom, + Info: ev.Info, + Err: fmt.Errorf("failed to decode L2 block ref from payload: %w", err), + Concluding: ev.Concluding, + DerivedFrom: ev.DerivedFrom, }) return } @@ -112,10 +116,10 @@ func (eq *EngDeriver) onBuildSeal(ev BuildSealEvent) { "txs", txnCount, "time", ref.Time, "seal_time", sealTime, "build_time", buildTime) eq.emitter.Emit(BuildSealedEvent{ - IsLastInSpan: ev.IsLastInSpan, - DerivedFrom: ev.DerivedFrom, - Info: ev.Info, - Envelope: envelope, - Ref: ref, + Concluding: ev.Concluding, + DerivedFrom: ev.DerivedFrom, + Info: ev.Info, + Envelope: envelope, + Ref: ref, }) } diff --git a/op-node/rollup/engine/build_sealed.go b/op-node/rollup/engine/build_sealed.go index d588d77b7f223..eb2680850a759 100644 --- a/op-node/rollup/engine/build_sealed.go +++ b/op-node/rollup/engine/build_sealed.go @@ -7,8 +7,8 @@ import ( // BuildSealedEvent is emitted by the engine when a payload finished building, // but is not locally inserted as canonical block yet type BuildSealedEvent struct { - // if payload should be promoted to safe (must also be pending safe, see DerivedFrom) - IsLastInSpan bool + // if payload should be promoted to (local) safe (must also be pending safe, see DerivedFrom) + Concluding bool // payload is promoted to pending-safe if non-zero DerivedFrom eth.L1BlockRef @@ -25,10 +25,10 @@ func (eq *EngDeriver) onBuildSealed(ev BuildSealedEvent) { // If a (pending) safe block, immediately process the block if ev.DerivedFrom != (eth.L1BlockRef{}) { eq.emitter.Emit(PayloadProcessEvent{ - IsLastInSpan: ev.IsLastInSpan, - DerivedFrom: ev.DerivedFrom, - Envelope: ev.Envelope, - Ref: ev.Ref, + Concluding: ev.Concluding, + DerivedFrom: ev.DerivedFrom, + Envelope: ev.Envelope, + Ref: ev.Ref, }) } } diff --git a/op-node/rollup/engine/build_start.go b/op-node/rollup/engine/build_start.go index 22c178d36cd0f..2c36053e1bbce 100644 --- a/op-node/rollup/engine/build_start.go +++ b/op-node/rollup/engine/build_start.go @@ -68,7 +68,7 @@ func (eq *EngDeriver) onBuildStart(ev BuildStartEvent) { eq.emitter.Emit(BuildStartedEvent{ Info: eth.PayloadInfo{ID: id, Timestamp: uint64(ev.Attributes.Attributes.Timestamp)}, BuildStarted: buildStartTime, - IsLastInSpan: ev.Attributes.IsLastInSpan, + Concluding: ev.Attributes.Concluding, DerivedFrom: ev.Attributes.DerivedFrom, Parent: ev.Attributes.Parent, }) diff --git a/op-node/rollup/engine/build_started.go b/op-node/rollup/engine/build_started.go index 78b737d214c77..1193c09fb3519 100644 --- a/op-node/rollup/engine/build_started.go +++ b/op-node/rollup/engine/build_started.go @@ -13,8 +13,8 @@ type BuildStartedEvent struct { Parent eth.L2BlockRef - // if payload should be promoted to safe (must also be pending safe, see DerivedFrom) - IsLastInSpan bool + // if payload should be promoted to (local) safe (must also be pending safe, see DerivedFrom) + Concluding bool // payload is promoted to pending-safe if non-zero DerivedFrom eth.L1BlockRef } @@ -29,7 +29,7 @@ func (eq *EngDeriver) onBuildStarted(ev BuildStartedEvent) { eq.emitter.Emit(BuildSealEvent{ Info: ev.Info, BuildStarted: ev.BuildStarted, - IsLastInSpan: ev.IsLastInSpan, + Concluding: ev.Concluding, DerivedFrom: ev.DerivedFrom, }) } diff --git a/op-node/rollup/engine/engine_controller.go b/op-node/rollup/engine/engine_controller.go index 64fe944f140a9..9261e6a84a6b9 100644 --- a/op-node/rollup/engine/engine_controller.go +++ b/op-node/rollup/engine/engine_controller.go @@ -9,6 +9,7 @@ import ( "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-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" @@ -90,7 +91,8 @@ type EngineController struct { } func NewEngineController(engine ExecEngine, log log.Logger, metrics derive.Metrics, - rollupCfg *rollup.Config, syncCfg *sync.Config, emitter event.Emitter) *EngineController { + rollupCfg *rollup.Config, syncCfg *sync.Config, emitter event.Emitter, +) *EngineController { syncStatus := syncStatusCL if syncCfg.SyncMode == sync.ELSync { syncStatus = syncStatusWillStartEL @@ -287,11 +289,11 @@ func (e *EngineController) TryUpdateEngine(ctx context.Context) error { defer logFn() fcRes, err := e.engine.ForkchoiceUpdate(ctx, &fc, nil) if err != nil { - var inputErr eth.InputError - if errors.As(err, &inputErr) { - switch inputErr.Code { + var rpcErr rpc.Error + if errors.As(err, &rpcErr) { + switch eth.ErrorCode(rpcErr.ErrorCode()) { case eth.InvalidForkchoiceState: - return derive.NewResetError(fmt.Errorf("forkchoice update was inconsistent with engine, need reset to resolve: %w", inputErr.Unwrap())) + return derive.NewResetError(fmt.Errorf("forkchoice update was inconsistent with engine, need reset to resolve: %w", rpcErr)) default: return derive.NewTemporaryError(fmt.Errorf("unexpected error code in forkchoice-updated response: %w", err)) } @@ -365,11 +367,11 @@ func (e *EngineController) InsertUnsafePayload(ctx context.Context, envelope *et defer logFn() fcRes, err := e.engine.ForkchoiceUpdate(ctx, &fc, nil) if err != nil { - var inputErr eth.InputError - if errors.As(err, &inputErr) { - switch inputErr.Code { + var rpcErr rpc.Error + if errors.As(err, &rpcErr) { + switch eth.ErrorCode(rpcErr.ErrorCode()) { case eth.InvalidForkchoiceState: - return derive.NewResetError(fmt.Errorf("pre-unsafe-block forkchoice update was inconsistent with engine, need reset to resolve: %w", inputErr.Unwrap())) + return derive.NewResetError(fmt.Errorf("pre-unsafe-block forkchoice update was inconsistent with engine, need reset to resolve: %w", rpcErr)) default: return derive.NewTemporaryError(fmt.Errorf("unexpected error code in forkchoice-updated response: %w", err)) } @@ -443,13 +445,16 @@ func (e *EngineController) TryBackupUnsafeReorg(ctx context.Context) (bool, erro defer logFn() fcRes, err := e.engine.ForkchoiceUpdate(ctx, &fc, nil) if err != nil { - var inputErr eth.InputError - if errors.As(err, &inputErr) { - e.SetBackupUnsafeL2Head(eth.L2BlockRef{}, false) - switch inputErr.Code { + var rpcErr rpc.Error + if errors.As(err, &rpcErr) { + switch eth.ErrorCode(rpcErr.ErrorCode()) { case eth.InvalidForkchoiceState: - return true, derive.NewResetError(fmt.Errorf("forkchoice update was inconsistent with engine, need reset to resolve: %w", inputErr.Unwrap())) + e.SetBackupUnsafeL2Head(eth.L2BlockRef{}, false) + return true, derive.NewResetError(fmt.Errorf("forkchoice update was inconsistent with engine, need reset to resolve: %w", rpcErr)) default: + // Retry when forkChoiceUpdate returns non-input error. + // Do not reset backupUnsafeHead because it will be used again. + e.needFCUCallForBackupUnsafeReorg = true return true, derive.NewTemporaryError(fmt.Errorf("unexpected error code in forkchoice-updated response: %w", err)) } } else { diff --git a/op-node/rollup/engine/engine_update.go b/op-node/rollup/engine/engine_update.go index c79dbdcd0f4d0..dbf578d303768 100644 --- a/op-node/rollup/engine/engine_update.go +++ b/op-node/rollup/engine/engine_update.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rpc" ) // isDepositTx checks an opaqueTx to determine if it is a Deposit Transaction @@ -84,15 +85,15 @@ const ( func startPayload(ctx context.Context, eng ExecEngine, fc eth.ForkchoiceState, attrs *eth.PayloadAttributes) (id eth.PayloadID, errType BlockInsertionErrType, err error) { fcRes, err := eng.ForkchoiceUpdate(ctx, &fc, attrs) if err != nil { - var inputErr eth.InputError - if errors.As(err, &inputErr) { - switch inputErr.Code { + var rpcErr rpc.Error + if errors.As(err, &rpcErr) { + switch code := eth.ErrorCode(rpcErr.ErrorCode()); code { case eth.InvalidForkchoiceState: - return eth.PayloadID{}, BlockInsertPrestateErr, fmt.Errorf("pre-block-creation forkchoice update was inconsistent with engine, need reset to resolve: %w", inputErr.Unwrap()) + return eth.PayloadID{}, BlockInsertPrestateErr, fmt.Errorf("pre-block-creation forkchoice update was inconsistent with engine, need reset to resolve: %w", rpcErr) case eth.InvalidPayloadAttributes: - return eth.PayloadID{}, BlockInsertPayloadErr, fmt.Errorf("payload attributes are not valid, cannot build block: %w", inputErr.Unwrap()) + return eth.PayloadID{}, BlockInsertPayloadErr, fmt.Errorf("payload attributes are not valid, cannot build block: %w", rpcErr) default: - if inputErr.Code.IsEngineError() { + if code.IsEngineError() { return eth.PayloadID{}, BlockInsertPrestateErr, fmt.Errorf("unexpected engine error code in forkchoice-updated response: %w", err) } else { return eth.PayloadID{}, BlockInsertTemporaryErr, fmt.Errorf("unexpected generic error code in forkchoice-updated response: %w", err) diff --git a/op-node/rollup/engine/events.go b/op-node/rollup/engine/events.go index b05410a6dcef8..bb44995648752 100644 --- a/op-node/rollup/engine/events.go +++ b/op-node/rollup/engine/events.go @@ -25,8 +25,7 @@ type Metrics interface { // forkchoice-update event, to signal the latest forkchoice to other derivers. // This helps decouple derivers from the actual engine state, // while also not making the derivers wait for a forkchoice update at random. -type ForkchoiceRequestEvent struct { -} +type ForkchoiceRequestEvent struct{} func (ev ForkchoiceRequestEvent) String() string { return "forkchoice-request" @@ -98,10 +97,19 @@ func (ev PendingSafeUpdateEvent) String() string { return "pending-safe-update" } +type InteropPendingSafeChangedEvent struct { + Ref eth.L2BlockRef + DerivedFrom eth.L1BlockRef +} + +func (ev InteropPendingSafeChangedEvent) String() string { + return "interop-pending-safe-changed" +} + // PromotePendingSafeEvent signals that a block can be marked as pending-safe, and/or safe. type PromotePendingSafeEvent struct { Ref eth.L2BlockRef - Safe bool + Concluding bool // Concludes the pending phase, so can be promoted to (local) safe DerivedFrom eth.L1BlockRef } @@ -175,8 +183,7 @@ func (ev ProcessAttributesEvent) String() string { return "process-attributes" } -type PendingSafeRequestEvent struct { -} +type PendingSafeRequestEvent struct{} func (ev PendingSafeRequestEvent) String() string { return "pending-safe-request" @@ -190,15 +197,13 @@ func (ev ProcessUnsafePayloadEvent) String() string { return "process-unsafe-payload" } -type TryBackupUnsafeReorgEvent struct { -} +type TryBackupUnsafeReorgEvent struct{} func (ev TryBackupUnsafeReorgEvent) String() string { return "try-backup-unsafe-reorg" } -type TryUpdateEngineEvent struct { -} +type TryUpdateEngineEvent struct{} func (ev TryUpdateEngineEvent) String() string { return "try-update-engine" @@ -268,7 +273,8 @@ type EngDeriver struct { var _ event.Deriver = (*EngDeriver)(nil) func NewEngDeriver(log log.Logger, ctx context.Context, cfg *rollup.Config, - metrics Metrics, ec *EngineController) *EngDeriver { + metrics Metrics, ec *EngineController, +) *EngDeriver { return &EngDeriver{ log: log, cfg: cfg, @@ -395,19 +401,26 @@ func (d *EngDeriver) OnEvent(ev event.Event) bool { // Only promote if not already stale. // Resets/overwrites happen through engine-resets, not through promotion. if x.Ref.Number > d.ec.PendingSafeL2Head().Number { + d.log.Debug("Updating pending safe", "pending_safe", x.Ref, "local_safe", d.ec.LocalSafeL2Head(), "unsafe", d.ec.UnsafeL2Head(), "concluding", x.Concluding) d.ec.SetPendingSafeL2Head(x.Ref) d.emitter.Emit(PendingSafeUpdateEvent{ PendingSafe: d.ec.PendingSafeL2Head(), Unsafe: d.ec.UnsafeL2Head(), }) } - if x.Safe && x.Ref.Number > d.ec.LocalSafeL2Head().Number { + if x.Concluding && x.Ref.Number > d.ec.LocalSafeL2Head().Number { d.emitter.Emit(PromoteLocalSafeEvent{ Ref: x.Ref, DerivedFrom: x.DerivedFrom, }) } + // TODO(#12646): temporary interop work-around, assumes Holocene local-safe progression behavior. + d.emitter.Emit(InteropPendingSafeChangedEvent{ + Ref: x.Ref, + DerivedFrom: x.DerivedFrom, + }) case PromoteLocalSafeEvent: + d.log.Debug("Updating local safe", "local_safe", x.Ref, "safe", d.ec.SafeL2Head(), "unsafe", d.ec.UnsafeL2Head()) d.ec.SetLocalSafeHead(x.Ref) d.emitter.Emit(LocalSafeUpdateEvent(x)) case LocalSafeUpdateEvent: @@ -416,6 +429,7 @@ func (d *EngDeriver) OnEvent(ev event.Event) bool { d.emitter.Emit(PromoteSafeEvent(x)) } case PromoteSafeEvent: + d.log.Debug("Updating safe", "safe", x.Ref, "unsafe", d.ec.UnsafeL2Head()) d.ec.SetSafeHead(x.Ref) // Finalizer can pick up this safe cross-block now d.emitter.Emit(SafeDerivedEvent{Safe: x.Ref, DerivedFrom: x.DerivedFrom}) @@ -457,10 +471,10 @@ func (d *EngDeriver) OnEvent(ev event.Event) bool { d.onBuildStart(x) case BuildStartedEvent: d.onBuildStarted(x) - case BuildSealedEvent: - d.onBuildSealed(x) case BuildSealEvent: d.onBuildSeal(x) + case BuildSealedEvent: + d.onBuildSealed(x) case BuildInvalidEvent: d.onBuildInvalid(x) case BuildCancelEvent: diff --git a/op-node/rollup/engine/payload_process.go b/op-node/rollup/engine/payload_process.go index 4102287f3d238..62d7ded47f0d9 100644 --- a/op-node/rollup/engine/payload_process.go +++ b/op-node/rollup/engine/payload_process.go @@ -9,8 +9,8 @@ import ( ) type PayloadProcessEvent struct { - // if payload should be promoted to safe (must also be pending safe, see DerivedFrom) - IsLastInSpan bool + // if payload should be promoted to (local) safe (must also be pending safe, see DerivedFrom) + Concluding bool // payload is promoted to pending-safe if non-zero DerivedFrom eth.L1BlockRef @@ -30,21 +30,31 @@ func (eq *EngDeriver) onPayloadProcess(ev PayloadProcessEvent) { ev.Envelope.ExecutionPayload, ev.Envelope.ParentBeaconBlockRoot) if err != nil { eq.emitter.Emit(rollup.EngineTemporaryErrorEvent{ - Err: fmt.Errorf("failed to insert execution payload: %w", err)}) + Err: fmt.Errorf("failed to insert execution payload: %w", err), + }) return } switch status.Status { case eth.ExecutionInvalid, eth.ExecutionInvalidBlockHash: + // Depending on execution engine, not all block-validity checks run immediately on build-start + // at the time of the forkchoiceUpdated engine-API call, nor during getPayload. + if ev.DerivedFrom != (eth.L1BlockRef{}) && eq.cfg.IsHolocene(ev.DerivedFrom.Time) { + eq.emitDepositsOnlyPayloadAttributesRequest(ev.Ref.ParentID(), ev.DerivedFrom) + return + } + eq.emitter.Emit(PayloadInvalidEvent{ Envelope: ev.Envelope, - Err: eth.NewPayloadErr(ev.Envelope.ExecutionPayload, status)}) + Err: eth.NewPayloadErr(ev.Envelope.ExecutionPayload, status), + }) return case eth.ExecutionValid: eq.emitter.Emit(PayloadSuccessEvent(ev)) return default: eq.emitter.Emit(rollup.EngineTemporaryErrorEvent{ - Err: eth.NewPayloadErr(ev.Envelope.ExecutionPayload, status)}) + Err: eth.NewPayloadErr(ev.Envelope.ExecutionPayload, status), + }) return } } diff --git a/op-node/rollup/engine/payload_success.go b/op-node/rollup/engine/payload_success.go index 7bb4a38307e13..c00d8e81ea77f 100644 --- a/op-node/rollup/engine/payload_success.go +++ b/op-node/rollup/engine/payload_success.go @@ -5,8 +5,8 @@ import ( ) type PayloadSuccessEvent struct { - // if payload should be promoted to safe (must also be pending safe, see DerivedFrom) - IsLastInSpan bool + // if payload should be promoted to (local) safe (must also be pending safe, see DerivedFrom) + Concluding bool // payload is promoted to pending-safe if non-zero DerivedFrom eth.L1BlockRef @@ -25,7 +25,7 @@ func (eq *EngDeriver) onPayloadSuccess(ev PayloadSuccessEvent) { if ev.DerivedFrom != (eth.L1BlockRef{}) { eq.emitter.Emit(PromotePendingSafeEvent{ Ref: ev.Ref, - Safe: ev.IsLastInSpan, + Concluding: ev.Concluding, DerivedFrom: ev.DerivedFrom, }) } @@ -34,7 +34,7 @@ func (eq *EngDeriver) onPayloadSuccess(ev PayloadSuccessEvent) { eq.log.Info("Inserted block", "hash", payload.BlockHash, "number", uint64(payload.BlockNumber), "state_root", payload.StateRoot, "timestamp", uint64(payload.Timestamp), "parent", payload.ParentHash, "prev_randao", payload.PrevRandao, "fee_recipient", payload.FeeRecipient, - "txs", len(payload.Transactions), "last_in_span", ev.IsLastInSpan, "derived_from", ev.DerivedFrom) + "txs", len(payload.Transactions), "concluding", ev.Concluding, "derived_from", ev.DerivedFrom) eq.emitter.Emit(TryUpdateEngineEvent{}) } diff --git a/op-node/rollup/finality/finalizer.go b/op-node/rollup/finality/finalizer.go index 046b94664e055..fb49bf7afd093 100644 --- a/op-node/rollup/finality/finalizer.go +++ b/op-node/rollup/finality/finalizer.go @@ -73,6 +73,8 @@ type Finalizer struct { ctx context.Context + cfg *rollup.Config + emitter event.Emitter // finalizedL1 is the currently perceived finalized L1 block. @@ -98,6 +100,7 @@ func NewFinalizer(ctx context.Context, log log.Logger, cfg *rollup.Config, l1Fet lookback := calcFinalityLookback(cfg) return &Finalizer{ ctx: ctx, + cfg: cfg, log: log, finalizedL1: eth.L1BlockRef{}, triedFinalizeAt: 0, @@ -253,6 +256,14 @@ func (fi *Finalizer) tryFinalize() { func (fi *Finalizer) onDerivedSafeBlock(l2Safe eth.L2BlockRef, derivedFrom eth.L1BlockRef) { fi.mu.Lock() defer fi.mu.Unlock() + + // Stop registering blocks after interop. + // Finality in interop is determined by the superchain backend, + // i.e. the op-supervisor RPC identifies which L2 block may be finalized. + if fi.cfg.IsInterop(l2Safe.Time) { + return + } + // remember the last L2 block that we fully derived from the given finality data if len(fi.finalityData) == 0 || fi.finalityData[len(fi.finalityData)-1].L1Block.Number < derivedFrom.Number { // prune finality data if necessary, before appending any data. diff --git a/op-node/rollup/finality/finalizer_test.go b/op-node/rollup/finality/finalizer_test.go index cdaf4006c0e0f..e65b21abf6236 100644 --- a/op-node/rollup/finality/finalizer_test.go +++ b/op-node/rollup/finality/finalizer_test.go @@ -472,4 +472,35 @@ func TestEngineQueue_Finalize(t *testing.T) { fi.OnEvent(TryFinalizeEvent{}) emitter.AssertExpectations(t) }) + + // The Finalizer does not promote any blocks to finalized status after interop. + // Blocks after interop are finalized with the interop deriver and interop backend. + t.Run("disable-after-interop", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelInfo) + l1F := &testutils.MockL1Source{} + defer l1F.AssertExpectations(t) + l1F.ExpectL1BlockRefByNumber(refD.Number, refD, nil) + l1F.ExpectL1BlockRefByNumber(refD.Number, refD, nil) + + emitter := &testutils.MockEmitter{} + fi := NewFinalizer(context.Background(), logger, &rollup.Config{ + InteropTime: &refC1.Time, + }, l1F) + fi.AttachEmitter(emitter) + + // now say C0 and C1 were included in D and became the new safe head + fi.OnEvent(engine.SafeDerivedEvent{Safe: refC0, DerivedFrom: refD}) + fi.OnEvent(engine.SafeDerivedEvent{Safe: refC1, DerivedFrom: refD}) + fi.OnEvent(derive.DeriverIdleEvent{Origin: refD}) + emitter.AssertExpectations(t) + + emitter.ExpectOnce(TryFinalizeEvent{}) + fi.OnEvent(FinalizeL1Event{FinalizedL1: refD}) + emitter.AssertExpectations(t) + + // C1 was Interop, C0 was not yet interop and can be finalized + emitter.ExpectOnce(engine.PromoteFinalizedEvent{Ref: refC0}) + fi.OnEvent(TryFinalizeEvent{}) + emitter.AssertExpectations(t) + }) } diff --git a/op-node/rollup/interop/interop.go b/op-node/rollup/interop/interop.go index 904f93d941129..a4342b6a19f69 100644 --- a/op-node/rollup/interop/interop.go +++ b/op-node/rollup/interop/interop.go @@ -10,10 +10,13 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-node/rollup/engine" "github.com/ethereum-optimism/optimism/op-node/rollup/event" "github.com/ethereum-optimism/optimism/op-node/rollup/finality" "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/sources" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -24,13 +27,19 @@ type InteropBackend interface { SafeView(ctx context.Context, chainID types.ChainID, safe types.ReferenceView) (types.ReferenceView, error) Finalized(ctx context.Context, chainID types.ChainID) (eth.BlockID, error) - DerivedFrom(ctx context.Context, chainID types.ChainID, blockHash common.Hash, blockNumber uint64) (eth.L1BlockRef, error) + CrossDerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (eth.L1BlockRef, error) - UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.L2BlockRef) error - UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.L2BlockRef) error + UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.BlockRef) error + UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.BlockRef) error UpdateFinalizedL1(ctx context.Context, chainID types.ChainID, finalized eth.L1BlockRef) error } +// For testing usage, the backend of the supervisor implements the interface, no need for RPC. +var _ InteropBackend = (*backend.SupervisorBackend)(nil) + +// For RPC usage, the supervisor client implements the interop backend. +var _ InteropBackend = (*sources.SupervisorClient)(nil) + type L2Source interface { L2BlockRefByNumber(context.Context, uint64) (eth.L2BlockRef, error) L2BlockRefByHash(ctx context.Context, l2Hash common.Hash) (eth.L2BlockRef, error) @@ -83,10 +92,17 @@ func (d *InteropDeriver) OnEvent(ev event.Event) bool { switch x := ev.(type) { case engine.UnsafeUpdateEvent: d.onLocalUnsafeUpdate(x) - case engine.LocalSafeUpdateEvent: - d.onLocalSafeUpdate(x) + case engine.InteropPendingSafeChangedEvent: + d.onInteropPendingSafeChangedEvent(x) case finality.FinalizeL1Event: d.onFinalizedL1(x) + case derive.DeriverL1StatusEvent: + d.log.Debug("deriver L1 traversal event", "l1", x.Origin, "l2", x.LastL2) + // Register traversal of L1, repeat the last local-safe L2 + d.onInteropPendingSafeChangedEvent(engine.InteropPendingSafeChangedEvent{ + Ref: x.LastL2, + DerivedFrom: x.Origin, + }) case engine.CrossUnsafeUpdateEvent: if err := d.onCrossUnsafe(x); err != nil { d.log.Error("Failed to process cross-unsafe update", "err", err) @@ -109,7 +125,7 @@ func (d *InteropDeriver) onLocalUnsafeUpdate(x engine.UnsafeUpdateEvent) { d.log.Debug("Signaling unsafe L2 head update to interop backend", "head", x.Ref) ctx, cancel := context.WithTimeout(d.driverCtx, rpcTimeout) defer cancel() - if err := d.backend.UpdateLocalUnsafe(ctx, d.chainID, x.Ref); err != nil { + if err := d.backend.UpdateLocalUnsafe(ctx, d.chainID, x.Ref.BlockRef()); err != nil { d.log.Warn("Failed to signal unsafe L2 head to interop backend", "head", x.Ref, "err", err) // still continue to try and do a cross-unsafe update } @@ -117,11 +133,11 @@ func (d *InteropDeriver) onLocalUnsafeUpdate(x engine.UnsafeUpdateEvent) { d.emitter.Emit(engine.RequestCrossUnsafeEvent{}) } -func (d *InteropDeriver) onLocalSafeUpdate(x engine.LocalSafeUpdateEvent) { +func (d *InteropDeriver) onInteropPendingSafeChangedEvent(x engine.InteropPendingSafeChangedEvent) { d.log.Debug("Signaling derived-from update to interop backend", "derivedFrom", x.DerivedFrom, "block", x.Ref) ctx, cancel := context.WithTimeout(d.driverCtx, rpcTimeout) defer cancel() - if err := d.backend.UpdateLocalSafe(ctx, d.chainID, x.DerivedFrom, x.Ref); err != nil { + if err := d.backend.UpdateLocalSafe(ctx, d.chainID, x.DerivedFrom, x.Ref.BlockRef()); err != nil { d.log.Debug("Failed to signal derived-from update to interop backend", "derivedFrom", x.DerivedFrom, "block", x.Ref) // still continue to try and do a cross-safe update } @@ -212,10 +228,15 @@ func (d *InteropDeriver) onCrossSafeUpdateEvent(x engine.CrossSafeUpdateEvent) e // and then reset derivation, so this op-node can help get the supervisor back in sync. return nil } - derivedFrom, err := d.backend.DerivedFrom(ctx, d.chainID, result.Cross.Hash, result.Cross.Number) + derived := eth.BlockID{ + Hash: result.Cross.Hash, + Number: result.Cross.Number, + } + derivedFrom, err := d.backend.CrossDerivedFrom(ctx, d.chainID, derived) if err != nil { return fmt.Errorf("failed to get derived-from of %s: %w", result.Cross, err) } + d.log.Info("New cross-safe block", "block", result.Cross.Number) ref, err := d.l2.L2BlockRefByHash(ctx, result.Cross.Hash) if err != nil { return fmt.Errorf("failed to get block ref of %s: %w", result.Cross, err) @@ -252,6 +273,7 @@ func (d *InteropDeriver) onFinalizedUpdate(x engine.FinalizedUpdateEvent) error if err != nil { return fmt.Errorf("failed to get block ref of %s: %w", finalized, err) } + d.log.Info("New finalized block from supervisor", "block", finalized.Number) d.emitter.Emit(engine.PromoteFinalizedEvent{ Ref: ref, }) diff --git a/op-node/rollup/interop/interop_test.go b/op-node/rollup/interop/interop_test.go index 4078e4881a07b..d4fb87f0dd924 100644 --- a/op-node/rollup/interop/interop_test.go +++ b/op-node/rollup/interop/interop_test.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/engine" "github.com/ethereum-optimism/optimism/op-node/rollup/finality" + "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testutils" supervisortypes "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" @@ -35,7 +36,7 @@ func TestInteropDeriver(t *testing.T) { t.Run("local-unsafe blocks push to supervisor and trigger cross-unsafe attempts", func(t *testing.T) { emitter.ExpectOnce(engine.RequestCrossUnsafeEvent{}) unsafeHead := testutils.RandomL2BlockRef(rng) - interopBackend.ExpectUpdateLocalUnsafe(chainID, unsafeHead, nil) + interopBackend.ExpectUpdateLocalUnsafe(chainID, unsafeHead.BlockRef(), nil) interopDeriver.OnEvent(engine.UnsafeUpdateEvent{Ref: unsafeHead}) emitter.AssertExpectations(t) interopBackend.AssertExpectations(t) @@ -92,8 +93,8 @@ func TestInteropDeriver(t *testing.T) { emitter.ExpectOnce(engine.RequestCrossSafeEvent{}) derivedFrom := testutils.RandomBlockRef(rng) localSafe := testutils.RandomL2BlockRef(rng) - interopBackend.ExpectUpdateLocalSafe(chainID, derivedFrom, localSafe, nil) - interopDeriver.OnEvent(engine.LocalSafeUpdateEvent{ + interopBackend.ExpectUpdateLocalSafe(chainID, derivedFrom, localSafe.BlockRef(), nil) + interopDeriver.OnEvent(engine.InteropPendingSafeChangedEvent{ Ref: localSafe, DerivedFrom: derivedFrom, }) @@ -114,7 +115,11 @@ func TestInteropDeriver(t *testing.T) { Cross: nextCrossSafe.ID(), } interopBackend.ExpectSafeView(chainID, localView, supervisorView, nil) - interopBackend.ExpectDerivedFrom(chainID, nextCrossSafe.Hash, nextCrossSafe.Number, derivedFrom, nil) + derived := eth.BlockID{ + Hash: nextCrossSafe.Hash, + Number: nextCrossSafe.Number, + } + interopBackend.ExpectDerivedFrom(chainID, derived, derivedFrom, nil) l2Source.ExpectL2BlockRefByHash(nextCrossSafe.Hash, nextCrossSafe, nil) emitter.ExpectOnce(engine.PromoteSafeEvent{ Ref: nextCrossSafe, diff --git a/op-node/rollup/sequencing/sequencer.go b/op-node/rollup/sequencing/sequencer.go index 2adcd7fcba243..8edd2b0259668 100644 --- a/op-node/rollup/sequencing/sequencer.go +++ b/op-node/rollup/sequencing/sequencer.go @@ -307,10 +307,10 @@ func (d *Sequencer) onBuildSealed(x engine.BuildSealedEvent) { d.asyncGossip.Gossip(x.Envelope) // Now after having gossiped the block, try to put it in our own canonical chain d.emitter.Emit(engine.PayloadProcessEvent{ - IsLastInSpan: x.IsLastInSpan, - DerivedFrom: x.DerivedFrom, - Envelope: x.Envelope, - Ref: x.Ref, + Concluding: x.Concluding, + DerivedFrom: x.DerivedFrom, + Envelope: x.Envelope, + Ref: x.Ref, }) d.latest.Ref = x.Ref d.latestSealed = x.Ref @@ -360,7 +360,7 @@ func (d *Sequencer) onPayloadSuccess(x engine.PayloadSuccessEvent) { d.asyncGossip.Clear() } -func (d *Sequencer) onSequencerAction(x SequencerActionEvent) { +func (d *Sequencer) onSequencerAction(SequencerActionEvent) { d.log.Debug("Sequencer action") payload := d.asyncGossip.Get() if payload != nil { @@ -382,10 +382,10 @@ func (d *Sequencer) onSequencerAction(x SequencerActionEvent) { // meaning that we have seen BuildSealedEvent already. // We can retry processing to make it canonical. d.emitter.Emit(engine.PayloadProcessEvent{ - IsLastInSpan: false, - DerivedFrom: eth.L1BlockRef{}, - Envelope: payload, - Ref: ref, + Concluding: false, + DerivedFrom: eth.L1BlockRef{}, + Envelope: payload, + Ref: ref, }) d.latest.Ref = ref } else { @@ -397,7 +397,7 @@ func (d *Sequencer) onSequencerAction(x SequencerActionEvent) { d.emitter.Emit(engine.BuildSealEvent{ Info: d.latest.Info, BuildStarted: d.latest.Started, - IsLastInSpan: false, + Concluding: false, DerivedFrom: eth.L1BlockRef{}, }) } else if d.latest == (BuildingState{}) { @@ -442,7 +442,7 @@ func (d *Sequencer) onReset(x rollup.ResetEvent) { d.nextActionOK = false } -func (d *Sequencer) onEngineResetConfirmedEvent(x engine.EngineResetConfirmedEvent) { +func (d *Sequencer) onEngineResetConfirmedEvent(engine.EngineResetConfirmedEvent) { d.nextActionOK = d.active.Load() // Before sequencing we can wait a block, // assuming the execution-engine just churned through some work for the reset. @@ -578,10 +578,10 @@ func (d *Sequencer) startBuildingBlock() { // Start a payload building process. withParent := &derive.AttributesWithParent{ - Attributes: attrs, - Parent: l2Head, - IsLastInSpan: false, - DerivedFrom: eth.L1BlockRef{}, // zero, not going to be pending-safe / safe + Attributes: attrs, + Parent: l2Head, + Concluding: false, + DerivedFrom: eth.L1BlockRef{}, // zero, not going to be pending-safe / safe } // Don't try to start building a block again, until we have heard back from this attempt diff --git a/op-node/rollup/sequencing/sequencer_chaos_test.go b/op-node/rollup/sequencing/sequencer_chaos_test.go index 5d64ab101d7cf..d5000fbed339f 100644 --- a/op-node/rollup/sequencing/sequencer_chaos_test.go +++ b/op-node/rollup/sequencing/sequencer_chaos_test.go @@ -91,7 +91,7 @@ func (c *ChaoticEngine) OnEvent(ev event.Event) bool { Info: c.currentPayloadInfo, BuildStarted: c.clock.Now(), Parent: x.Attributes.Parent, - IsLastInSpan: false, + Concluding: false, DerivedFrom: eth.L1BlockRef{}, }) } @@ -124,10 +124,10 @@ func (c *ChaoticEngine) OnEvent(ev event.Event) bool { if c.currentPayloadInfo == (eth.PayloadInfo{}) { c.emitter.Emit(engine.PayloadSealExpiredErrorEvent{ - Info: x.Info, - Err: errors.New("job was cancelled"), - IsLastInSpan: false, - DerivedFrom: eth.L1BlockRef{}, + Info: x.Info, + Err: errors.New("job was cancelled"), + Concluding: false, + DerivedFrom: eth.L1BlockRef{}, }) return true } @@ -142,17 +142,17 @@ func (c *ChaoticEngine) OnEvent(ev event.Event) bool { switch { case p < 0.03: // 3% c.emitter.Emit(engine.PayloadSealInvalidEvent{ - Info: x.Info, - Err: errors.New("mock invalid seal"), - IsLastInSpan: x.IsLastInSpan, - DerivedFrom: x.DerivedFrom, + Info: x.Info, + Err: errors.New("mock invalid seal"), + Concluding: x.Concluding, + DerivedFrom: x.DerivedFrom, }) case p < 0.08: // 5% c.emitter.Emit(engine.PayloadSealExpiredErrorEvent{ - Info: x.Info, - Err: errors.New("mock temp engine error"), - IsLastInSpan: x.IsLastInSpan, - DerivedFrom: x.DerivedFrom, + Info: x.Info, + Err: errors.New("mock temp engine error"), + Concluding: x.Concluding, + DerivedFrom: x.DerivedFrom, }) default: payloadEnvelope := ð.ExecutionPayloadEnvelope{ @@ -178,11 +178,11 @@ func (c *ChaoticEngine) OnEvent(ev event.Event) bool { SequenceNumber: 0, // ignored } c.emitter.Emit(engine.BuildSealedEvent{ - Info: x.Info, - Envelope: payloadEnvelope, - Ref: payloadRef, - IsLastInSpan: x.IsLastInSpan, - DerivedFrom: x.DerivedFrom, + Info: x.Info, + Envelope: payloadEnvelope, + Ref: payloadRef, + Concluding: x.Concluding, + DerivedFrom: x.DerivedFrom, }) } c.currentPayloadInfo = eth.PayloadInfo{} diff --git a/op-node/rollup/sequencing/sequencer_test.go b/op-node/rollup/sequencing/sequencer_test.go index 57642e8484431..6f43d59caa0b5 100644 --- a/op-node/rollup/sequencing/sequencer_test.go +++ b/op-node/rollup/sequencing/sequencer_test.go @@ -46,7 +46,8 @@ func decodeID(data []byte) eth.BlockID { } func (m *FakeAttributesBuilder) PreparePayloadAttributes(ctx context.Context, - l2Parent eth.L2BlockRef, epoch eth.BlockID) (attrs *eth.PayloadAttributes, err error) { + l2Parent eth.L2BlockRef, epoch eth.BlockID, +) (attrs *eth.PayloadAttributes, err error) { gasLimit := eth.Uint64Quantity(30_000_000) attrs = ð.PayloadAttributes{ Timestamp: eth.Uint64Quantity(l2Parent.Time + m.cfg.BlockTime), @@ -315,7 +316,7 @@ func TestSequencer_StaleBuild(t *testing.T) { Info: payloadInfo, BuildStarted: startedTime, Parent: head, - IsLastInSpan: false, + Concluding: false, DerivedFrom: eth.L1BlockRef{}, }) @@ -325,7 +326,7 @@ func TestSequencer_StaleBuild(t *testing.T) { emitter.ExpectOnce(engine.BuildSealEvent{ Info: payloadInfo, BuildStarted: startedTime, - IsLastInSpan: false, + Concluding: false, DerivedFrom: eth.L1BlockRef{}, }) seq.OnEvent(SequencerActionEvent{}) @@ -355,18 +356,18 @@ func TestSequencer_StaleBuild(t *testing.T) { SequenceNumber: 0, } emitter.ExpectOnce(engine.PayloadProcessEvent{ - IsLastInSpan: false, - DerivedFrom: eth.L1BlockRef{}, - Envelope: payloadEnvelope, - Ref: payloadRef, + Concluding: false, + DerivedFrom: eth.L1BlockRef{}, + Envelope: payloadEnvelope, + Ref: payloadRef, }) // And report back the sealing result to the engine seq.OnEvent(engine.BuildSealedEvent{ - IsLastInSpan: false, - DerivedFrom: eth.L1BlockRef{}, - Info: payloadInfo, - Envelope: payloadEnvelope, - Ref: payloadRef, + Concluding: false, + DerivedFrom: eth.L1BlockRef{}, + Info: payloadInfo, + Envelope: payloadEnvelope, + Ref: payloadRef, }) // The sequencer should start processing the payload emitter.AssertExpectations(t) @@ -521,7 +522,7 @@ func TestSequencerBuild(t *testing.T) { Info: payloadInfo, BuildStarted: startedTime, Parent: head, - IsLastInSpan: false, + Concluding: false, DerivedFrom: eth.L1BlockRef{}, }) // The sealing should now be scheduled as next action. @@ -535,7 +536,7 @@ func TestSequencerBuild(t *testing.T) { emitter.ExpectOnce(engine.BuildSealEvent{ Info: payloadInfo, BuildStarted: startedTime, - IsLastInSpan: false, + Concluding: false, DerivedFrom: eth.L1BlockRef{}, }) seq.OnEvent(SequencerActionEvent{}) @@ -564,18 +565,18 @@ func TestSequencerBuild(t *testing.T) { SequenceNumber: 0, } emitter.ExpectOnce(engine.PayloadProcessEvent{ - IsLastInSpan: false, - DerivedFrom: eth.L1BlockRef{}, - Envelope: payloadEnvelope, - Ref: payloadRef, + Concluding: false, + DerivedFrom: eth.L1BlockRef{}, + Envelope: payloadEnvelope, + Ref: payloadRef, }) // And report back the sealing result to the engine seq.OnEvent(engine.BuildSealedEvent{ - IsLastInSpan: false, - DerivedFrom: eth.L1BlockRef{}, - Info: payloadInfo, - Envelope: payloadEnvelope, - Ref: payloadRef, + Concluding: false, + DerivedFrom: eth.L1BlockRef{}, + Info: payloadInfo, + Envelope: payloadEnvelope, + Ref: payloadRef, }) // The sequencer should start processing the payload emitter.AssertExpectations(t) @@ -587,10 +588,10 @@ func TestSequencerBuild(t *testing.T) { // Mock that the processing was successful seq.OnEvent(engine.PayloadSuccessEvent{ - IsLastInSpan: false, - DerivedFrom: eth.L1BlockRef{}, - Envelope: payloadEnvelope, - Ref: payloadRef, + Concluding: false, + DerivedFrom: eth.L1BlockRef{}, + Envelope: payloadEnvelope, + Ref: payloadRef, }) require.Nil(t, deps.asyncGossip.payload, "async gossip should have cleared,"+ " after previous publishing and now having persisted the block ourselves") diff --git a/op-node/rollup/superchain.go b/op-node/rollup/superchain.go index 21a74323c05f7..577a8dab7ceae 100644 --- a/op-node/rollup/superchain.go +++ b/op-node/rollup/superchain.go @@ -12,7 +12,7 @@ import ( "github.com/ethereum-optimism/superchain-registry/superchain" ) -var OPStackSupport = params.ProtocolVersionV0{Build: [8]byte{}, Major: 8, Minor: 0, Patch: 0, PreRelease: 0}.Encode() +var OPStackSupport = params.ProtocolVersionV0{Build: [8]byte{}, Major: 9, Minor: 0, Patch: 0, PreRelease: 1}.Encode() // LoadOPStackRollupConfig loads the rollup configuration of the requested chain ID from the superchain-registry. // Some chains may require a SystemConfigProvider to retrieve any values not part of the registry. @@ -91,6 +91,7 @@ func LoadOPStackRollupConfig(chainID uint64) (*Config, error) { EcotoneTime: chConfig.EcotoneTime, FjordTime: chConfig.FjordTime, GraniteTime: chConfig.GraniteTime, + HoloceneTime: chConfig.HoloceneTime, BatchInboxAddress: common.Address(chConfig.BatchInboxAddr), DepositContractAddress: common.Address(addrs.OptimismPortalProxy), L1SystemConfigAddress: common.Address(addrs.SystemConfigProxy), diff --git a/op-node/rollup/types.go b/op-node/rollup/types.go index 35f8b727e77a7..9e78aeae92301 100644 --- a/op-node/rollup/types.go +++ b/op-node/rollup/types.go @@ -481,6 +481,17 @@ func (c *Config) IsInteropActivationBlock(l2BlockTime uint64) bool { !c.IsInterop(l2BlockTime-c.BlockTime) } +// IsActivationBlock returns the fork which activates at the block with time newTime if the previous +// block's time is oldTime. It return an empty ForkName if no fork activation takes place between +// those timestamps. It can be used for both, L1 and L2 blocks. +// TODO(12490): Currently only supports Holocene. Will be modularized in a follow-up. +func (c *Config) IsActivationBlock(oldTime, newTime uint64) ForkName { + if c.IsHolocene(newTime) && !c.IsHolocene(oldTime) { + return Holocene + } + return "" +} + func (c *Config) ActivateAtGenesis(hardfork ForkName) { // IMPORTANT! ordered from newest to oldest switch hardfork { diff --git a/op-node/rollup/types_test.go b/op-node/rollup/types_test.go index 4b2575afa391d..11c4db505c96b 100644 --- a/op-node/rollup/types_test.go +++ b/op-node/rollup/types_test.go @@ -701,3 +701,19 @@ func TestGetPayloadVersion(t *testing.T) { }) } } + +func TestConfig_IsActivationBlock(t *testing.T) { + ts := uint64(42) + // TODO(12490): Currently only supports Holocene. Will be modularized in a follow-up. + for _, fork := range []ForkName{Holocene} { + cfg := &Config{ + HoloceneTime: &ts, + } + require.Equal(t, fork, cfg.IsActivationBlock(0, ts)) + require.Equal(t, fork, cfg.IsActivationBlock(0, ts+64)) + require.Equal(t, fork, cfg.IsActivationBlock(ts-1, ts)) + require.Equal(t, fork, cfg.IsActivationBlock(ts-1, ts+1)) + require.Zero(t, cfg.IsActivationBlock(0, ts-1)) + require.Zero(t, cfg.IsActivationBlock(ts, ts+1)) + } +} diff --git a/op-node/service.go b/op-node/service.go index 14ff39aff160b..850f9ac2cbd06 100644 --- a/op-node/service.go +++ b/op-node/service.go @@ -1,6 +1,7 @@ package opnode import ( + "context" "crypto/rand" "encoding/json" "errors" @@ -80,7 +81,7 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) { ctx.IsSet(flags.HeartbeatURLFlag.Name) { log.Warn("Heartbeat functionality is not supported anymore, CLI flags will be removed in following release.") } - + conductorRPCEndpoint := ctx.String(flags.ConductorRpcFlag.Name) cfg := &node.Config{ L1: l1Endpoint, L2: l2Endpoint, @@ -108,8 +109,10 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) { Sync: *syncConfig, RollupHalt: haltOption, - ConductorEnabled: ctx.Bool(flags.ConductorEnabledFlag.Name), - ConductorRpc: ctx.String(flags.ConductorRpcFlag.Name), + ConductorEnabled: ctx.Bool(flags.ConductorEnabledFlag.Name), + ConductorRpc: func(context.Context) (string, error) { + return conductorRPCEndpoint, nil + }, ConductorRpcTimeout: ctx.Duration(flags.ConductorRpcTimeoutFlag.Name), AltDA: altda.ReadCLIConfig(ctx), diff --git a/op-program/Dockerfile.repro b/op-program/Dockerfile.repro index e3293b7908f74..fd713162e0136 100644 --- a/op-program/Dockerfile.repro +++ b/op-program/Dockerfile.repro @@ -26,17 +26,16 @@ ARG OP_PROGRAM_VERSION=v0.0.0 ARG TARGETOS TARGETARCH -# Build the cannon, op-program, and op-program-client.elf binaries. +# Build the cannon and op-program-client.elf binaries. RUN --mount=type=cache,target=/root/.cache/go-build cd cannon && make cannon \ GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$CANNON_VERSION" -RUN --mount=type=cache,target=/root/.cache/go-build cd op-program && make op-program-host \ - GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$OP_PROGRAM_VERSION" RUN --mount=type=cache,target=/root/.cache/go-build cd op-program && make op-program-client-mips \ GOOS=linux GOARCH=mips GOMIPS=softfloat GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$OP_PROGRAM_VERSION" # Run the op-program-client.elf binary directly through cannon's load-elf subcommand. -RUN /app/cannon/bin/cannon load-elf --type singlethreaded-2 --path /app/op-program/bin/op-program-client.elf --out /app/op-program/bin/prestate.bin.gz --meta "" -RUN /app/cannon/bin/cannon load-elf --type multithreaded --path /app/op-program/bin/op-program-client.elf --out /app/op-program/bin/prestate-mt.bin.gz --meta "" +RUN /app/cannon/bin/cannon load-elf --type singlethreaded-2 --path /app/op-program/bin/op-program-client.elf --out /app/op-program/bin/prestate.bin.gz --meta "/app/op-program/bin/meta.json" +RUN /app/cannon/bin/cannon load-elf --type multithreaded --path /app/op-program/bin/op-program-client.elf --out /app/op-program/bin/prestate-mt.bin.gz --meta "/app/op-program/bin/meta-mt.json" +RUN /app/cannon/bin/cannon load-elf --type multithreaded64 --path /app/op-program/bin/op-program-client64.elf --out /app/op-program/bin/prestate-mt64.bin.gz --meta "/app/op-program/bin/meta-mt64.json" # Generate the prestate proof containing the absolute pre-state hash. RUN /app/cannon/bin/cannon run --proof-at '=0' --stop-at '=1' --input /app/op-program/bin/prestate.bin.gz --meta "" --proof-fmt '/app/op-program/bin/%d.json' --output "" @@ -45,13 +44,21 @@ RUN mv /app/op-program/bin/0.json /app/op-program/bin/prestate-proof.json RUN /app/cannon/bin/cannon run --proof-at '=0' --stop-at '=1' --input /app/op-program/bin/prestate-mt.bin.gz --meta "" --proof-fmt '/app/op-program/bin/%d-mt.json' --output "" RUN mv /app/op-program/bin/0-mt.json /app/op-program/bin/prestate-proof-mt.json +RUN /app/cannon/bin/cannon run --proof-at '=0' --stop-at '=1' --input /app/op-program/bin/prestate-mt64.bin.gz --meta "" --proof-fmt '/app/op-program/bin/%d-mt64.json' --output "" +RUN mv /app/op-program/bin/0-mt64.json /app/op-program/bin/prestate-proof-mt64.json + # Exports files to the specified output location. # Writing files to host requires buildkit to be enabled. # e.g. `BUILDKIT=1 docker build ...` FROM scratch AS export-stage -COPY --from=builder /app/op-program/bin/op-program . COPY --from=builder /app/op-program/bin/op-program-client.elf . +COPY --from=builder /app/op-program/bin/op-program-client64.elf . +COPY --from=builder /app/op-program/bin/meta.json . COPY --from=builder /app/op-program/bin/prestate.bin.gz . COPY --from=builder /app/op-program/bin/prestate-proof.json . +COPY --from=builder /app/op-program/bin/meta-mt.json . COPY --from=builder /app/op-program/bin/prestate-mt.bin.gz . COPY --from=builder /app/op-program/bin/prestate-proof-mt.json . +COPY --from=builder /app/op-program/bin/meta-mt64.json . +COPY --from=builder /app/op-program/bin/prestate-mt64.bin.gz . +COPY --from=builder /app/op-program/bin/prestate-proof-mt64.json . diff --git a/op-program/Makefile b/op-program/Makefile index 983c795ac929c..30cbaeea4c427 100644 --- a/op-program/Makefile +++ b/op-program/Makefile @@ -26,11 +26,18 @@ op-program-host: op-program-client: env GO111MODULE=on GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -v -ldflags "$(PC_LDFLAGSSTRING)" -o ./bin/op-program-client ./client/cmd/main.go -op-program-client-mips: +op-program-client-mips: op-program-client-mips32 op-program-client-mips64 + +op-program-client-mips32: env GO111MODULE=on GOOS=linux GOARCH=mips GOMIPS=softfloat go build -v -ldflags "$(PC_LDFLAGSSTRING)" -o ./bin/op-program-client.elf ./client/cmd/main.go # verify output with: readelf -h bin/op-program-client.elf # result is mips32, big endian, R3000 +op-program-client-mips64: + env GO111MODULE=on GOOS=linux GOARCH=mips64 GOMIPS64=softfloat go build -v -ldflags "$(PC_LDFLAGSSTRING)" -o ./bin/op-program-client64.elf ./client/cmd/main.go + # verify output with: readelf -h bin/op-program-client64.elf + # result is mips64, big endian, R3000 + op-program-client-riscv: env GO111MODULE=on GOOS=linux GOARCH=riscv64 go build -v -gcflags="all=-d=softfloat" -ldflags "$(PC_LDFLAGSSTRING)" -o ./bin/op-program-client-riscv.elf ./client/cmd/main.go @@ -40,6 +47,8 @@ reproducible-prestate: @cat ./bin/prestate-proof.json | jq -r .pre @echo "MT-Cannon Absolute prestate hash: " @cat ./bin/prestate-proof-mt.json | jq -r .pre + @echo "Cannon64 Absolute prestate hash: " + @cat ./bin/prestate-proof-mt64.json | jq -r .pre .PHONY: reproducible-prestate verify-reproducibility: @@ -101,6 +110,8 @@ verify-compat: verify-sepolia-delta verify-sepolia-ecotone verify-mainnet-genesi op-program-host \ op-program-client \ op-program-client-mips \ + op-program-client-mips32 \ + op-program-client-mips64 \ op-program-client-riscv \ clean \ test \ diff --git a/op-program/README.md b/op-program/README.md index 15e89ffb5cf75..932ec85db22fb 100644 --- a/op-program/README.md +++ b/op-program/README.md @@ -45,6 +45,7 @@ After running `make reproducible-prestate`, the following files can be found in [./bin/](./bin/): - [`op-program`](./bin/op-program) - [`op-program-client.elf`](./bin/op-program-client.elf) +- [`op-program-client64.elf`](./bin/op-program-client64.elf) - [`prestate.bin.gz`](./bin/prestate.bin.gz) - [`prestate-proof.json`](./bin/prestate-proof.json) diff --git a/op-program/client/driver/driver.go b/op-program/client/driver/driver.go index fc232c5fcd43c..56fffb5b155ce 100644 --- a/op-program/client/driver/driver.go +++ b/op-program/client/driver/driver.go @@ -73,15 +73,14 @@ func (d *Driver) Emit(ev event.Event) { d.events = append(d.events, ev) } -var ExhaustErr = errors.New("exhausted events before completing program") - func (d *Driver) RunComplete() error { // Initial reset d.Emit(engine.ResetEngineRequestEvent{}) for !d.end.Closing() { if len(d.events) == 0 { - return ExhaustErr + d.logger.Info("Derivation complete: no further data to process") + return d.end.Result() } if len(d.events) > 10000 { // sanity check, in case of bugs. Better than going OOM. return errors.New("way too many events queued up, something is wrong") diff --git a/op-program/client/driver/driver_test.go b/op-program/client/driver/driver_test.go index 2f1249aff6a4c..8a5d02fe83f9b 100644 --- a/op-program/client/driver/driver_test.go +++ b/op-program/client/driver/driver_test.go @@ -92,7 +92,8 @@ func TestDriver(t *testing.T) { } count += 1 }) - require.ErrorIs(t, ExhaustErr, d.RunComplete()) + // No further processing to be done so evaluate if the claims output root is correct. + require.NoError(t, d.RunComplete()) }) t.Run("queued events", func(t *testing.T) { @@ -104,7 +105,7 @@ func TestDriver(t *testing.T) { } count += 1 }) - require.ErrorIs(t, ExhaustErr, d.RunComplete()) + require.NoError(t, d.RunComplete()) // add 1 for initial event that RunComplete fires require.Equal(t, 1+3*2, count, "must have queued up 2 events 3 times") }) diff --git a/op-program/client/driver/program.go b/op-program/client/driver/program.go index 0ef36f8f6a479..b83a1566c8ce0 100644 --- a/op-program/client/driver/program.go +++ b/op-program/client/driver/program.go @@ -63,9 +63,9 @@ func (d *ProgramDeriver) OnEvent(ev event.Event) bool { d.closing = true } case derive.DeriverIdleEvent: - // Not enough data to reach target - d.closing = true - d.logger.Info("Derivation complete: no further data to process") + // We dont't close the deriver yet, as the engine may still be processing events to reach + // the target. A ForkchoiceUpdateEvent will close the deriver when the target is reached. + d.logger.Info("Derivation complete: no further L1 data to process") case rollup.ResetEvent: d.closing = true d.result = fmt.Errorf("unexpected reset error: %w", x.Err) diff --git a/op-program/client/driver/program_test.go b/op-program/client/driver/program_test.go index 4c9941d754b4d..59206050a7f89 100644 --- a/op-program/client/driver/program_test.go +++ b/op-program/client/driver/program_test.go @@ -104,12 +104,12 @@ func TestProgramDeriver(t *testing.T) { require.NoError(t, p.result) }) }) - // on exhaustion of input data: stop without error + // Do not stop processing when the deriver is idle, the engine may still be busy and create further events. t.Run("deriver idle", func(t *testing.T) { p, m := newProgram(t, 1000) p.OnEvent(derive.DeriverIdleEvent{}) m.AssertExpectations(t) - require.True(t, p.closing) + require.False(t, p.closing) require.Nil(t, p.result) }) // on inconsistent chain data: stop with error diff --git a/op-program/client/l2/engineapi/l2_engine_api.go b/op-program/client/l2/engineapi/l2_engine_api.go index 13910d971c3a5..273483893b375 100644 --- a/op-program/client/l2/engineapi/l2_engine_api.go +++ b/op-program/client/l2/engineapi/l2_engine_api.go @@ -130,9 +130,9 @@ func (ea *L2EngineAPI) IncludeTx(tx *types.Transaction, from common.Address) err if ea.blockProcessor == nil { return ErrNotBuildingBlock } + if ea.l2ForceEmpty { ea.log.Info("Skipping including a transaction because e.L2ForceEmpty is true") - // t.InvalidAction("cannot include any sequencer txs") return nil } diff --git a/op-program/host/cmd/main_test.go b/op-program/host/cmd/main_test.go index cee90a9566463..35ca46d2472d7 100644 --- a/op-program/host/cmd/main_test.go +++ b/op-program/host/cmd/main_test.go @@ -274,6 +274,19 @@ func TestL2Claim(t *testing.T) { }) } +func TestL2Experimental(t *testing.T) { + t.Run("DefaultEmpty", func(t *testing.T) { + cfg := configForArgs(t, addRequiredArgs()) + require.Equal(t, cfg.L2ExperimentalURL, "") + }) + + t.Run("Valid", func(t *testing.T) { + expected := "https://example.com:8545" + cfg := configForArgs(t, replaceRequiredArg("--l2.experimental", expected)) + require.EqualValues(t, expected, cfg.L2ExperimentalURL) + }) +} + func TestL2BlockNumber(t *testing.T) { t.Run("Required", func(t *testing.T) { verifyArgsInvalid(t, "flag l2.blocknumber is required", addRequiredArgsExcept("--l2.blocknumber")) diff --git a/op-program/host/config/config.go b/op-program/host/config/config.go index bb9f9d868e452..46442e07f43d7 100644 --- a/op-program/host/config/config.go +++ b/op-program/host/config/config.go @@ -56,7 +56,11 @@ type Config struct { L2Head common.Hash // L2OutputRoot is the agreed L2 output root to start derivation from L2OutputRoot common.Hash - L2URL string + // L2URL is the URL of the L2 node to fetch L2 data from, this is the canonical URL for L2 data + // This URL is used as a fallback for L2ExperimentalURL if the experimental URL fails or cannot retrieve the desired data + L2URL string + // L2ExperimentalURL is the URL of the L2 node (non hash db archival node, for example, reth archival node) to fetch L2 data from + L2ExperimentalURL string // L2Claim is the claimed L2 output root to verify L2Claim common.Hash // L2ClaimBlockNumber is the block number the claimed L2 output root is from @@ -218,6 +222,7 @@ func NewConfigFromCLI(log log.Logger, ctx *cli.Context) (*Config, error) { DataDir: ctx.String(flags.DataDir.Name), DataFormat: dbFormat, L2URL: ctx.String(flags.L2NodeAddr.Name), + L2ExperimentalURL: ctx.String(flags.L2NodeExperimentalAddr.Name), L2ChainConfig: l2ChainConfig, L2Head: l2Head, L2OutputRoot: l2OutputRoot, diff --git a/op-program/host/flags/flags.go b/op-program/host/flags/flags.go index 15489cf22c949..b7c5984515300 100644 --- a/op-program/host/flags/flags.go +++ b/op-program/host/flags/flags.go @@ -47,6 +47,11 @@ var ( Usage: "Address of L2 JSON-RPC endpoint to use (eth and debug namespace required)", EnvVars: prefixEnvVars("L2_RPC"), } + L2NodeExperimentalAddr = &cli.StringFlag{ + Name: "l2.experimental", + Usage: "Address of L2 JSON-RPC endpoint to use for experimental features (debug_executionWitness)", + EnvVars: prefixEnvVars("L2_RPC_EXPERIMENTAL_RPC"), + } L1Head = &cli.StringFlag{ Name: "l1.head", Usage: "Hash of the L1 head block. Derivation stops after this block is processed.", @@ -131,6 +136,7 @@ var programFlags = []cli.Flag{ DataDir, DataFormat, L2NodeAddr, + L2NodeExperimentalAddr, L2GenesisPath, L1NodeAddr, L1BeaconAddr, diff --git a/op-program/host/host.go b/op-program/host/host.go index d129202755583..cd30421f9383a 100644 --- a/op-program/host/host.go +++ b/op-program/host/host.go @@ -24,11 +24,6 @@ import ( "github.com/ethereum/go-ethereum/log" ) -type L2Source struct { - *L2Client - *sources.DebugClient -} - type Prefetcher interface { Hint(hint string) error GetPreimage(ctx context.Context, key common.Hash) ([]byte, error) @@ -235,26 +230,23 @@ func makeDefaultPrefetcher(ctx context.Context, logger log.Logger, kv kvstore.KV return nil, fmt.Errorf("failed to setup L1 RPC: %w", err) } - logger.Info("Connecting to L2 node", "l2", cfg.L2URL) - l2RPC, err := client.NewRPC(ctx, logger, cfg.L2URL, client.WithDialAttempts(10)) - if err != nil { - return nil, fmt.Errorf("failed to setup L2 RPC: %w", err) - } - l1ClCfg := sources.L1ClientDefaultConfig(cfg.Rollup, cfg.L1TrustRPC, cfg.L1RPCKind) - l2ClCfg := sources.L2ClientDefaultConfig(cfg.Rollup, true) l1Cl, err := sources.NewL1Client(l1RPC, logger, nil, l1ClCfg) if err != nil { return nil, fmt.Errorf("failed to create L1 client: %w", err) } + + logger.Info("Connecting to L1 beacon", "l1", cfg.L1BeaconURL) l1Beacon := sources.NewBeaconHTTPClient(client.NewBasicHTTPClient(cfg.L1BeaconURL, logger)) l1BlobFetcher := sources.NewL1BeaconClient(l1Beacon, sources.L1BeaconClientConfig{FetchAllSidecars: false}) - l2Cl, err := NewL2Client(l2RPC, logger, nil, &L2ClientConfig{L2ClientConfig: l2ClCfg, L2Head: cfg.L2Head}) + + logger.Info("Initializing L2 clients") + l2Client, err := NewL2Source(ctx, logger, cfg) if err != nil { - return nil, fmt.Errorf("failed to create L2 client: %w", err) + return nil, fmt.Errorf("failed to create L2 source: %w", err) } - l2DebugCl := &L2Source{L2Client: l2Cl, DebugClient: sources.NewDebugClient(l2RPC.CallContext)} - return prefetcher.NewPrefetcher(logger, l1Cl, l1BlobFetcher, l2DebugCl, kv), nil + + return prefetcher.NewPrefetcher(logger, l1Cl, l1BlobFetcher, l2Client, kv), nil } func routeHints(logger log.Logger, hHostRW io.ReadWriter, hinter preimage.HintHandler) chan error { diff --git a/op-program/host/l2_source.go b/op-program/host/l2_source.go new file mode 100644 index 0000000000000..38906f70b87a0 --- /dev/null +++ b/op-program/host/l2_source.go @@ -0,0 +1,151 @@ +package host + +import ( + "context" + "time" + + "github.com/ethereum-optimism/optimism/op-program/host/config" + "github.com/ethereum-optimism/optimism/op-program/host/prefetcher" + "github.com/ethereum-optimism/optimism/op-service/client" + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/sources" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" +) + +// L2Source is a source of L2 data, it abstracts away the details of how to fetch L2 data between canonical and experimental sources. +// It also tracks metrics for each of the apis. Once experimental sources are stable, this will only route to the "experimental" source. +type L2Source struct { + logger log.Logger + + // canonical source, used as a fallback if experimental source is enabled but fails + // the underlying node should be a geth hash scheme archival node. + canonicalEthClient *L2Client + canonicalDebugClient *sources.DebugClient + + // experimental source, used as the primary source if enabled + experimentalClient *L2Client +} + +var _ prefetcher.L2Source = &L2Source{} + +// NewL2SourceWithClient creates a new L2 source with the given client as the canonical client. +// This doesn't configure the experimental source, but is useful for testing. +func NewL2SourceWithClient(logger log.Logger, canonicalL2Client *L2Client, canonicalDebugClient *sources.DebugClient) *L2Source { + source := &L2Source{ + logger: logger, + canonicalEthClient: canonicalL2Client, + canonicalDebugClient: canonicalDebugClient, + } + + return source +} + +func NewL2Source(ctx context.Context, logger log.Logger, config *config.Config) (*L2Source, error) { + logger.Info("Connecting to canonical L2 source", "url", config.L2URL) + + // eth_getProof calls are expensive and takes time, so we use a longer timeout + canonicalL2RPC, err := client.NewRPC(ctx, logger, config.L2URL, client.WithDialAttempts(10), client.WithCallTimeout(5*time.Minute)) + if err != nil { + return nil, err + } + canonicalDebugClient := sources.NewDebugClient(canonicalL2RPC.CallContext) + + canonicalL2ClientCfg := sources.L2ClientDefaultConfig(config.Rollup, true) + canonicalL2Client, err := NewL2Client(canonicalL2RPC, logger, nil, &L2ClientConfig{L2ClientConfig: canonicalL2ClientCfg, L2Head: config.L2Head}) + if err != nil { + return nil, err + } + + source := NewL2SourceWithClient(logger, canonicalL2Client, canonicalDebugClient) + + if len(config.L2ExperimentalURL) == 0 { + return source, nil + } + + logger.Info("Connecting to experimental L2 source", "url", config.L2ExperimentalURL) + // debug_executionWitness calls are expensive and takes time, so we use a longer timeout + experimentalRPC, err := client.NewRPC(ctx, logger, config.L2ExperimentalURL, client.WithDialAttempts(10), client.WithCallTimeout(5*time.Minute)) + if err != nil { + return nil, err + } + experimentalL2ClientCfg := sources.L2ClientDefaultConfig(config.Rollup, true) + experimentalL2Client, err := NewL2Client(experimentalRPC, logger, nil, &L2ClientConfig{L2ClientConfig: experimentalL2ClientCfg, L2Head: config.L2Head}) + if err != nil { + return nil, err + } + + source.experimentalClient = experimentalL2Client + + return source, nil +} + +func (l *L2Source) ExperimentalEnabled() bool { + return l.experimentalClient != nil +} + +// CodeByHash implements prefetcher.L2Source. +func (l *L2Source) CodeByHash(ctx context.Context, hash common.Hash) ([]byte, error) { + if l.ExperimentalEnabled() { + // This means experimental source was not able to retrieve relevant information from eth_getProof or debug_executionWitness + // We should fall back to the canonical source, and log a warning, and record a metric + l.logger.Warn("Experimental source failed to retrieve code by hash, falling back to canonical source", "hash", hash) + } + return l.canonicalDebugClient.CodeByHash(ctx, hash) +} + +// NodeByHash implements prefetcher.L2Source. +func (l *L2Source) NodeByHash(ctx context.Context, hash common.Hash) ([]byte, error) { + if l.ExperimentalEnabled() { + // This means experimental source was not able to retrieve relevant information from eth_getProof or debug_executionWitness + // We should fall back to the canonical source, and log a warning, and record a metric + l.logger.Warn("Experimental source failed to retrieve node by hash, falling back to canonical source", "hash", hash) + } + return l.canonicalDebugClient.NodeByHash(ctx, hash) +} + +// InfoAndTxsByHash implements prefetcher.L2Source. +func (l *L2Source) InfoAndTxsByHash(ctx context.Context, blockHash common.Hash) (eth.BlockInfo, types.Transactions, error) { + if l.ExperimentalEnabled() { + return l.experimentalClient.InfoAndTxsByHash(ctx, blockHash) + } + return l.canonicalEthClient.InfoAndTxsByHash(ctx, blockHash) +} + +// OutputByRoot implements prefetcher.L2Source. +func (l *L2Source) OutputByRoot(ctx context.Context, root common.Hash) (eth.Output, error) { + if l.ExperimentalEnabled() { + return l.experimentalClient.OutputByRoot(ctx, root) + } + return l.canonicalEthClient.OutputByRoot(ctx, root) +} + +// ExecutionWitness implements prefetcher.L2Source. +func (l *L2Source) ExecutionWitness(ctx context.Context, blockNum uint64) (*eth.ExecutionWitness, error) { + if !l.ExperimentalEnabled() { + l.logger.Error("Experimental source is not enabled, cannot fetch execution witness", "blockNum", blockNum) + return nil, prefetcher.ErrExperimentalPrefetchDisabled + } + + // log errors, but return standard error so we know to retry with legacy source + witness, err := l.experimentalClient.ExecutionWitness(ctx, blockNum) + if err != nil { + l.logger.Error("Failed to fetch execution witness from experimental source", "blockNum", blockNum, "err", err) + return nil, prefetcher.ErrExperimentalPrefetchFailed + } + return witness, nil +} + +// GetProof implements prefetcher.L2Source. +func (l *L2Source) GetProof(ctx context.Context, address common.Address, storage []common.Hash, blockTag string) (*eth.AccountResult, error) { + if l.ExperimentalEnabled() { + return l.experimentalClient.GetProof(ctx, address, storage, blockTag) + } + proof, err := l.canonicalEthClient.GetProof(ctx, address, storage, blockTag) + if err != nil { + l.logger.Error("Failed to fetch proof from canonical source", "address", address, "storage", storage, "blockTag", blockTag, "err", err) + return nil, prefetcher.ErrExperimentalPrefetchFailed + } + return proof, nil +} diff --git a/op-program/host/prefetcher/prefetcher.go b/op-program/host/prefetcher/prefetcher.go index cb5a52fa88cec..60aa67d633608 100644 --- a/op-program/host/prefetcher/prefetcher.go +++ b/op-program/host/prefetcher/prefetcher.go @@ -28,6 +28,11 @@ var ( precompileFailure = [1]byte{0} ) +var ( + ErrExperimentalPrefetchFailed = errors.New("experimental prefetch failed") + ErrExperimentalPrefetchDisabled = errors.New("experimental prefetch disabled") +) + var acceleratedPrecompiles = []common.Address{ common.BytesToAddress([]byte{0x1}), // ecrecover common.BytesToAddress([]byte{0x8}), // bn256Pairing diff --git a/op-program/prestates/releases.json b/op-program/prestates/releases.json index 9345be39006bf..63c54a0ba5899 100644 --- a/op-program/prestates/releases.json +++ b/op-program/prestates/releases.json @@ -1,4 +1,8 @@ [ + { + "version": "1.4.0-rc.1", + "hash": "0x03925193e3e89f87835bbdf3a813f60b2aa818a36bbe71cd5d8fd7e79f5e8afe" + }, { "version": "1.3.1", "hash": "0x038512e02c4c3f7bdaec27d00edf55b7155e0905301e1a88083e4e0a6764d54c", diff --git a/op-service/Makefile b/op-service/Makefile index 0978529f9b8da..f57c0b6b53a4e 100644 --- a/op-service/Makefile +++ b/op-service/Makefile @@ -10,14 +10,16 @@ generate-mocks: go generate ./... fuzz: - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzExecutionPayloadUnmarshal ./eth - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzExecutionPayloadMarshalUnmarshalV1 ./eth - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzExecutionPayloadMarshalUnmarshalV2 ./eth - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzExecutionPayloadMarshalUnmarshalV3 ./eth - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzOBP01 ./eth - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzEncodeDecodeBlob ./eth - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDetectNonBijectivity ./eth - go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzEncodeScalar ./eth + printf "%s\n" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzExecutionPayloadUnmarshal ./eth" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzExecutionPayloadMarshalUnmarshalV1 ./eth" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzExecutionPayloadMarshalUnmarshalV2 ./eth" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzExecutionPayloadMarshalUnmarshalV3 ./eth" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzOBP01 ./eth" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzEncodeDecodeBlob ./eth" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzDetectNonBijectivity ./eth" \ + "go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz FuzzEncodeScalar ./eth" \ + | parallel -j 8 {} .PHONY: \ test \ diff --git a/op-service/client/client.go b/op-service/client/client.go index 22f71866926b7..9f4dac659424e 100644 --- a/op-service/client/client.go +++ b/op-service/client/client.go @@ -79,43 +79,43 @@ func (ic *InstrumentedClient) RPC() RPC { } func (ic *InstrumentedClient) ChainID(ctx context.Context) (*big.Int, error) { - return instrument2[*big.Int](ic.m, "eth_chainId", func() (*big.Int, error) { + return instrument2(ic.m, "eth_chainId", func() (*big.Int, error) { return ic.c.ChainID(ctx) }) } func (ic *InstrumentedClient) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { - return instrument2[*types.Block](ic.m, "eth_getBlockByHash", func() (*types.Block, error) { + return instrument2(ic.m, "eth_getBlockByHash", func() (*types.Block, error) { return ic.c.BlockByHash(ctx, hash) }) } func (ic *InstrumentedClient) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { - return instrument2[*types.Block](ic.m, "eth_getBlockByNumber", func() (*types.Block, error) { + return instrument2(ic.m, "eth_getBlockByNumber", func() (*types.Block, error) { return ic.c.BlockByNumber(ctx, number) }) } func (ic *InstrumentedClient) BlockNumber(ctx context.Context) (uint64, error) { - return instrument2[uint64](ic.m, "eth_blockNumber", func() (uint64, error) { + return instrument2(ic.m, "eth_blockNumber", func() (uint64, error) { return ic.c.BlockNumber(ctx) }) } func (ic *InstrumentedClient) PeerCount(ctx context.Context) (uint64, error) { - return instrument2[uint64](ic.m, "net_peerCount", func() (uint64, error) { + return instrument2(ic.m, "net_peerCount", func() (uint64, error) { return ic.c.PeerCount(ctx) }) } func (ic *InstrumentedClient) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { - return instrument2[*types.Header](ic.m, "eth_getHeaderByHash", func() (*types.Header, error) { + return instrument2(ic.m, "eth_getHeaderByHash", func() (*types.Header, error) { return ic.c.HeaderByHash(ctx, hash) }) } func (ic *InstrumentedClient) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { - return instrument2[*types.Header](ic.m, "eth_getHeaderByNumber", func() (*types.Header, error) { + return instrument2(ic.m, "eth_getHeaderByNumber", func() (*types.Header, error) { return ic.c.HeaderByNumber(ctx, number) }) } @@ -132,25 +132,25 @@ func (ic *InstrumentedClient) TransactionSender(ctx context.Context, tx *types.T } func (ic *InstrumentedClient) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) { - return instrument2[uint](ic.m, "eth_getTransactionCount", func() (uint, error) { + return instrument2(ic.m, "eth_getTransactionCount", func() (uint, error) { return ic.c.TransactionCount(ctx, blockHash) }) } func (ic *InstrumentedClient) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) { - return instrument2[*types.Transaction](ic.m, "eth_getTransactionByBlockHashAndIndex", func() (*types.Transaction, error) { + return instrument2(ic.m, "eth_getTransactionByBlockHashAndIndex", func() (*types.Transaction, error) { return ic.c.TransactionInBlock(ctx, blockHash, index) }) } func (ic *InstrumentedClient) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { - return instrument2[*types.Receipt](ic.m, "eth_getTransactionReceipt", func() (*types.Receipt, error) { + return instrument2(ic.m, "eth_getTransactionReceipt", func() (*types.Receipt, error) { return ic.c.TransactionReceipt(ctx, txHash) }) } func (ic *InstrumentedClient) SyncProgress(ctx context.Context) (*ethereum.SyncProgress, error) { - return instrument2[*ethereum.SyncProgress](ic.m, "eth_syncing", func() (*ethereum.SyncProgress, error) { + return instrument2(ic.m, "eth_syncing", func() (*ethereum.SyncProgress, error) { return ic.c.SyncProgress(ctx) }) } @@ -160,37 +160,37 @@ func (ic *InstrumentedClient) SubscribeNewHead(ctx context.Context, ch chan<- *t } func (ic *InstrumentedClient) NetworkID(ctx context.Context) (*big.Int, error) { - return instrument2[*big.Int](ic.m, "net_version", func() (*big.Int, error) { + return instrument2(ic.m, "net_version", func() (*big.Int, error) { return ic.c.NetworkID(ctx) }) } func (ic *InstrumentedClient) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { - return instrument2[*big.Int](ic.m, "eth_getBalance", func() (*big.Int, error) { + return instrument2(ic.m, "eth_getBalance", func() (*big.Int, error) { return ic.c.BalanceAt(ctx, account, blockNumber) }) } func (ic *InstrumentedClient) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) { - return instrument2[[]byte](ic.m, "eth_getStorageAt", func() ([]byte, error) { + return instrument2(ic.m, "eth_getStorageAt", func() ([]byte, error) { return ic.c.StorageAt(ctx, account, key, blockNumber) }) } func (ic *InstrumentedClient) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { - return instrument2[[]byte](ic.m, "eth_getCode", func() ([]byte, error) { + return instrument2(ic.m, "eth_getCode", func() ([]byte, error) { return ic.c.CodeAt(ctx, account, blockNumber) }) } func (ic *InstrumentedClient) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { - return instrument2[uint64](ic.m, "eth_getTransactionCount", func() (uint64, error) { + return instrument2(ic.m, "eth_getTransactionCount", func() (uint64, error) { return ic.c.NonceAt(ctx, account, blockNumber) }) } func (ic *InstrumentedClient) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { - return instrument2[[]types.Log](ic.m, "eth_getLogs", func() ([]types.Log, error) { + return instrument2(ic.m, "eth_getLogs", func() ([]types.Log, error) { return ic.c.FilterLogs(ctx, q) }) } @@ -200,67 +200,67 @@ func (ic *InstrumentedClient) SubscribeFilterLogs(ctx context.Context, q ethereu } func (ic *InstrumentedClient) PendingBalanceAt(ctx context.Context, account common.Address) (*big.Int, error) { - return instrument2[*big.Int](ic.m, "eth_getBalance", func() (*big.Int, error) { + return instrument2(ic.m, "eth_getBalance", func() (*big.Int, error) { return ic.c.PendingBalanceAt(ctx, account) }) } func (ic *InstrumentedClient) PendingStorageAt(ctx context.Context, account common.Address, key common.Hash) ([]byte, error) { - return instrument2[[]byte](ic.m, "eth_getStorageAt", func() ([]byte, error) { + return instrument2(ic.m, "eth_getStorageAt", func() ([]byte, error) { return ic.c.PendingStorageAt(ctx, account, key) }) } func (ic *InstrumentedClient) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { - return instrument2[[]byte](ic.m, "eth_getCode", func() ([]byte, error) { + return instrument2(ic.m, "eth_getCode", func() ([]byte, error) { return ic.c.PendingCodeAt(ctx, account) }) } func (ic *InstrumentedClient) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { - return instrument2[uint64](ic.m, "eth_getTransactionCount", func() (uint64, error) { + return instrument2(ic.m, "eth_getTransactionCount", func() (uint64, error) { return ic.c.PendingNonceAt(ctx, account) }) } func (ic *InstrumentedClient) PendingTransactionCount(ctx context.Context) (uint, error) { - return instrument2[uint](ic.m, "eth_getBlockTransactionCountByNumber", func() (uint, error) { + return instrument2(ic.m, "eth_getBlockTransactionCountByNumber", func() (uint, error) { return ic.c.PendingTransactionCount(ctx) }) } func (ic *InstrumentedClient) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { - return instrument2[[]byte](ic.m, "eth_call", func() ([]byte, error) { + return instrument2(ic.m, "eth_call", func() ([]byte, error) { return ic.c.CallContract(ctx, msg, blockNumber) }) } func (ic *InstrumentedClient) CallContractAtHash(ctx context.Context, msg ethereum.CallMsg, blockHash common.Hash) ([]byte, error) { - return instrument2[[]byte](ic.m, "eth_call", func() ([]byte, error) { + return instrument2(ic.m, "eth_call", func() ([]byte, error) { return ic.c.CallContractAtHash(ctx, msg, blockHash) }) } func (ic *InstrumentedClient) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) { - return instrument2[[]byte](ic.m, "eth_call", func() ([]byte, error) { + return instrument2(ic.m, "eth_call", func() ([]byte, error) { return ic.c.PendingCallContract(ctx, msg) }) } func (ic *InstrumentedClient) SuggestGasPrice(ctx context.Context) (*big.Int, error) { - return instrument2[*big.Int](ic.m, "eth_gasPrice", func() (*big.Int, error) { + return instrument2(ic.m, "eth_gasPrice", func() (*big.Int, error) { return ic.c.SuggestGasPrice(ctx) }) } func (ic *InstrumentedClient) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { - return instrument2[*big.Int](ic.m, "eth_maxPriorityFeePerGas", func() (*big.Int, error) { + return instrument2(ic.m, "eth_maxPriorityFeePerGas", func() (*big.Int, error) { return ic.c.SuggestGasPrice(ctx) }) } func (ic *InstrumentedClient) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) { - return instrument2[uint64](ic.m, "eth_estimateGas", func() (uint64, error) { + return instrument2(ic.m, "eth_estimateGas", func() (uint64, error) { return ic.c.EstimateGas(ctx, msg) }) } diff --git a/op-service/dial/ethclient_interface.go b/op-service/dial/ethclient_interface.go index 58a2070974eeb..292c7b07fa4c6 100644 --- a/op-service/dial/ethclient_interface.go +++ b/op-service/dial/ethclient_interface.go @@ -5,12 +5,14 @@ import ( "math/big" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rpc" ) // EthClientInterface is an interface for providing an ethclient.Client // It does not describe all of the functions an ethclient.Client has, only the ones used by callers of the L2 Providers type EthClientInterface interface { BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) + Client() *rpc.Client Close() } diff --git a/op-service/eth/blobs_api.go b/op-service/eth/blobs_api.go index 3dbff1745bc23..239f97528edeb 100644 --- a/op-service/eth/blobs_api.go +++ b/op-service/eth/blobs_api.go @@ -1,5 +1,7 @@ package eth +import "github.com/ethereum/go-ethereum/common/hexutil" + type BlobSidecar struct { Blob Blob `json:"blob"` Index Uint64String `json:"index"` @@ -13,8 +15,7 @@ type APIBlobSidecar struct { KZGCommitment Bytes48 `json:"kzg_commitment"` KZGProof Bytes48 `json:"kzg_proof"` SignedBlockHeader SignedBeaconBlockHeader `json:"signed_block_header"` - // The inclusion-proof of the blob-sidecar into the beacon-block is ignored, - // since we verify blobs by their versioned hashes against the execution-layer block instead. + InclusionProof []Bytes32 `json:"kzg_commitment_inclusion_proof"` } func (sc *APIBlobSidecar) BlobSidecar() *BlobSidecar { @@ -27,8 +28,8 @@ func (sc *APIBlobSidecar) BlobSidecar() *BlobSidecar { } type SignedBeaconBlockHeader struct { - Message BeaconBlockHeader `json:"message"` - // signature is ignored, since we verify blobs against EL versioned-hashes + Message BeaconBlockHeader `json:"message"` + Signature hexutil.Bytes `json:"signature"` } type BeaconBlockHeader struct { diff --git a/op-service/eth/blobs_api_test.go b/op-service/eth/blobs_api_test.go index 7c585cb7ac997..babad4a505375 100644 --- a/op-service/eth/blobs_api_test.go +++ b/op-service/eth/blobs_api_test.go @@ -82,17 +82,19 @@ func TestAPIGetBlobSidecarsResponse(t *testing.T) { var resp eth.APIGetBlobSidecarsResponse require.NoError(json.Unmarshal(jsonStr, &resp)) require.NotEmpty(resp.Data) - require.Equal(5, reflect.TypeOf(*resp.Data[0]).NumField(), "APIBlobSidecar changed, adjust test") - require.Equal(1, reflect.TypeOf(resp.Data[0].SignedBlockHeader).NumField(), "SignedBeaconBlockHeader changed, adjust test") + require.Equal(6, reflect.TypeOf(*resp.Data[0]).NumField(), "APIBlobSidecar changed, adjust test") + require.Equal(2, reflect.TypeOf(resp.Data[0].SignedBlockHeader).NumField(), "SignedBeaconBlockHeader changed, adjust test") require.Equal(5, reflect.TypeOf(resp.Data[0].SignedBlockHeader.Message).NumField(), "BeaconBlockHeader changed, adjust test") require.NotZero(resp.Data[0].Blob) require.NotZero(resp.Data[1].Index) require.NotZero(resp.Data[0].KZGCommitment) require.NotZero(resp.Data[0].KZGProof) + require.NotZero(resp.Data[0].InclusionProof) require.NotZero(resp.Data[0].SignedBlockHeader.Message.Slot) require.NotZero(resp.Data[0].SignedBlockHeader.Message.ParentRoot) require.NotZero(resp.Data[0].SignedBlockHeader.Message.BodyRoot) require.NotZero(resp.Data[0].SignedBlockHeader.Message.ProposerIndex) require.NotZero(resp.Data[0].SignedBlockHeader.Message.StateRoot) + require.NotZero(resp.Data[0].SignedBlockHeader.Signature) } diff --git a/op-service/eth/execution_witness.go b/op-service/eth/execution_witness.go new file mode 100644 index 0000000000000..91f274b23d7e2 --- /dev/null +++ b/op-service/eth/execution_witness.go @@ -0,0 +1,9 @@ +package eth + +import "github.com/ethereum/go-ethereum/common/hexutil" + +type ExecutionWitness struct { + Keys map[string]hexutil.Bytes `json:"keys"` + Codes map[string]hexutil.Bytes `json:"codes"` + State map[string]hexutil.Bytes `json:"state"` +} diff --git a/op-service/eth/id.go b/op-service/eth/id.go index c323d1e69b9a4..3eecdbc3bac1a 100644 --- a/op-service/eth/id.go +++ b/op-service/eth/id.go @@ -49,6 +49,15 @@ func (id L2BlockRef) TerminalString() string { return fmt.Sprintf("%s:%d", id.Hash.TerminalString(), id.Number) } +func (id L2BlockRef) BlockRef() BlockRef { + return BlockRef{ + Hash: id.Hash, + Number: id.Number, + ParentHash: id.ParentHash, + Time: id.Time, + } +} + type L1BlockRef struct { Hash common.Hash `json:"hash"` Number uint64 `json:"number"` diff --git a/op-service/eth/sync_status.go b/op-service/eth/sync_status.go index f9db1f672b824..e16275920e2bf 100644 --- a/op-service/eth/sync_status.go +++ b/op-service/eth/sync_status.go @@ -5,7 +5,7 @@ package eth type SyncStatus struct { // CurrentL1 is the L1 block that the derivation process is last idled at. // This may not be fully derived into L2 data yet. - // The safe L2 blocks were produced/included fully from the L1 chain up to and including this L1 block. + // The safe L2 blocks were produced/included fully from the L1 chain up to _but excluding_ this L1 block. // If the node is synced, this matches the HeadL1, minus the verifier confirmation distance. CurrentL1 L1BlockRef `json:"current_l1"` // CurrentL1Finalized is a legacy sync-status attribute. This is deprecated. diff --git a/op-service/eth/types.go b/op-service/eth/types.go index 80cb9a7b4aa53..79f2da03a0d2b 100644 --- a/op-service/eth/types.go +++ b/op-service/eth/types.go @@ -3,6 +3,7 @@ package eth import ( "bytes" "encoding/binary" + "encoding/json" "errors" "fmt" "math" @@ -24,9 +25,14 @@ func (c ErrorCode) IsEngineError() bool { return -38100 < c && c <= -38000 } +func (c ErrorCode) IsGenericRPCError() bool { + return -32700 < c && c <= -32600 +} + // Engine error codes used to be -3200x, but were rebased to -3800x: // https://github.com/ethereum/execution-apis/pull/214 const ( + MethodNotFound ErrorCode = -32601 // RPC method not found or not available. InvalidParams ErrorCode = -32602 UnknownPayload ErrorCode = -38001 // Payload does not exist / is not available. InvalidForkchoiceState ErrorCode = -38002 // Forkchoice state is invalid / inconsistent. @@ -37,8 +43,7 @@ const ( var ErrBedrockScalarPaddingNotEmpty = errors.New("version 0 scalar value has non-empty padding") -// InputError distinguishes an user-input error from regular rpc errors, -// to help the (Engine) API user divert from accidental input mistakes. +// InputError can be used to create rpc.Error instances with a specific error code. type InputError struct { Inner error Code ErrorCode @@ -48,6 +53,11 @@ func (ie InputError) Error() string { return fmt.Sprintf("input error %d: %s", ie.Code, ie.Inner.Error()) } +// Makes InputError implement the rpc.Error interface +func (ie InputError) ErrorCode() int { + return int(ie.Code) +} + func (ie InputError) Unwrap() error { return ie.Inner } @@ -360,6 +370,31 @@ type PayloadAttributes struct { EIP1559Params *Bytes8 `json:"eip1559Params,omitempty"` } +// IsDepositsOnly returns whether all transactions of the PayloadAttributes are of Deposit +// type. Empty transactions are also considered non-Deposit transactions. +func (a *PayloadAttributes) IsDepositsOnly() bool { + for _, tx := range a.Transactions { + if len(tx) == 0 || tx[0] != types.DepositTxType { + return false + } + } + return true +} + +// WithDepositsOnly return a shallow clone with all non-Deposit transactions stripped from its +// transactions. The order is preserved. +func (a *PayloadAttributes) WithDepositsOnly() *PayloadAttributes { + clone := *a + depositTxs := make([]Data, 0, len(a.Transactions)) + for _, tx := range a.Transactions { + if len(tx) > 0 && tx[0] == types.DepositTxType { + depositTxs = append(depositTxs, tx) + } + } + clone.Transactions = depositTxs + return &clone +} + type ExecutePayloadStatus string const ( @@ -422,8 +457,42 @@ type SystemConfig struct { // EIP1559Params contains the Holocene-encoded EIP-1559 parameters. This // value will be 0 if Holocene is not active, or if derivation has yet to // process any EIP_1559_PARAMS system config update events. - EIP1559Params Bytes8 `json:"eip1559Params,omitempty"` + EIP1559Params Bytes8 `json:"eip1559Params"` // More fields can be added for future SystemConfig versions. + + // MarshalPreHolocene indicates whether or not this struct should be + // marshaled in the pre-Holocene format. The pre-Holocene format does + // not marshal the EIP1559Params field. The presence of this field in + // pre-Holocene codebases causes the rollup config to be rejected. + MarshalPreHolocene bool `json:"-"` +} + +func (sysCfg SystemConfig) MarshalJSON() ([]byte, error) { + if sysCfg.MarshalPreHolocene { + return jsonMarshalPreHolocene(sysCfg) + } + return jsonMarshalHolocene(sysCfg) +} + +func jsonMarshalHolocene(sysCfg SystemConfig) ([]byte, error) { + type sysCfgMarshaling SystemConfig + return json.Marshal(sysCfgMarshaling(sysCfg)) +} + +func jsonMarshalPreHolocene(sysCfg SystemConfig) ([]byte, error) { + type sysCfgMarshaling struct { + BatcherAddr common.Address `json:"batcherAddr"` + Overhead Bytes32 `json:"overhead"` + Scalar Bytes32 `json:"scalar"` + GasLimit uint64 `json:"gasLimit"` + } + sc := sysCfgMarshaling{ + BatcherAddr: sysCfg.BatcherAddr, + Overhead: sysCfg.Overhead, + Scalar: sysCfg.Scalar, + GasLimit: sysCfg.GasLimit, + } + return json.Marshal(sc) } // The Ecotone upgrade introduces a versioned L1 scalar format diff --git a/op-service/eth/types_test.go b/op-service/eth/types_test.go index f62c14691a163..03409e16008d5 100644 --- a/op-service/eth/types_test.go +++ b/op-service/eth/types_test.go @@ -1,10 +1,14 @@ package eth import ( + "encoding/json" "errors" "math" "testing" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rpc" + "github.com/stretchr/testify/require" ) @@ -18,6 +22,10 @@ func TestInputError(t *testing.T) { t.Fatalf("need InputError to be detected as such") } require.ErrorIs(t, err, InputError{}, "need to detect input error with errors.Is") + + var rpcErr rpc.Error + require.ErrorAs(t, err, &rpcErr, "need input error to be rpc.Error with errors.As") + require.EqualValues(t, err.Code, rpcErr.ErrorCode()) } type scalarTest struct { @@ -66,3 +74,21 @@ func FuzzEncodeScalar(f *testing.F) { require.Equal(t, baseFeeScalar, scalars.BaseFeeScalar) }) } + +func TestSystemConfigMarshaling(t *testing.T) { + sysConfig := SystemConfig{ + BatcherAddr: common.Address{'A'}, + Overhead: Bytes32{0x4, 0x5, 0x6}, + Scalar: Bytes32{0x7, 0x8, 0x9}, + GasLimit: 1234, + // Leave EIP1559 params empty to prove that the + // zero value is sent. + } + j, err := json.Marshal(sysConfig) + require.NoError(t, err) + require.Equal(t, `{"batcherAddr":"0x4100000000000000000000000000000000000000","overhead":"0x0405060000000000000000000000000000000000000000000000000000000000","scalar":"0x0708090000000000000000000000000000000000000000000000000000000000","gasLimit":1234,"eip1559Params":"0x0000000000000000"}`, string(j)) + sysConfig.MarshalPreHolocene = true + j, err = json.Marshal(sysConfig) + require.NoError(t, err) + require.Equal(t, `{"batcherAddr":"0x4100000000000000000000000000000000000000","overhead":"0x0405060000000000000000000000000000000000000000000000000000000000","scalar":"0x0708090000000000000000000000000000000000000000000000000000000000","gasLimit":1234}`, string(j)) +} diff --git a/op-service/ioutil/streams.go b/op-service/ioutil/streams.go index 91f122906db0d..c35aefa202ef9 100644 --- a/op-service/ioutil/streams.go +++ b/op-service/ioutil/streams.go @@ -1,8 +1,10 @@ package ioutil import ( + "fmt" "io" "os" + "path/filepath" ) var ( @@ -21,6 +23,20 @@ func NoOutputStream() OutputTarget { } } +func ToBasicFile(path string, perm os.FileMode) OutputTarget { + return func() (io.Writer, io.Closer, Aborter, error) { + outDir := filepath.Dir(path) + if err := os.MkdirAll(outDir, perm); err != nil { + return nil, nil, nil, fmt.Errorf("failed to create dir %q: %w", outDir, err) + } + f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, perm) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to open %q: %w", path, err) + } + return f, f, func() {}, nil + } +} + func ToAtomicFile(path string, perm os.FileMode) OutputTarget { return func() (io.Writer, io.Closer, Aborter, error) { f, err := NewAtomicWriterCompressed(path, perm) diff --git a/op-service/jsonutil/json.go b/op-service/jsonutil/json.go index 5993138595b40..8549c170d42a5 100644 --- a/op-service/jsonutil/json.go +++ b/op-service/jsonutil/json.go @@ -67,6 +67,7 @@ type jsonEncoder struct { func newJSONEncoder(w io.Writer) Encoder { e := json.NewEncoder(w) e.SetIndent("", " ") + e.SetEscapeHTML(false) return &jsonEncoder{ e: e, } diff --git a/op-service/jsonutil/merge.go b/op-service/jsonutil/merge.go new file mode 100644 index 0000000000000..8819b2ad1993c --- /dev/null +++ b/op-service/jsonutil/merge.go @@ -0,0 +1,37 @@ +package jsonutil + +import "encoding/json" + +// MergeJSON merges the provided overrides into the input struct. Fields +// must be JSON-serializable for this to work. Overrides are applied in +// order of precedence - i.e., the last overrides will override keys from +// all preceding overrides. +func MergeJSON[T any](in T, overrides ...map[string]any) (T, error) { + var out T + inJSON, err := json.Marshal(in) + if err != nil { + return out, err + } + + var tmpMap map[string]interface{} + if err := json.Unmarshal(inJSON, &tmpMap); err != nil { + return out, err + } + + for _, override := range overrides { + for k, v := range override { + tmpMap[k] = v + } + } + + inJSON, err = json.Marshal(tmpMap) + if err != nil { + return out, err + } + + if err := json.Unmarshal(inJSON, &out); err != nil { + return out, err + } + + return out, nil +} diff --git a/op-deployer/pkg/deployer/state/deploy_config_test.go b/op-service/jsonutil/merge_test.go similarity index 91% rename from op-deployer/pkg/deployer/state/deploy_config_test.go rename to op-service/jsonutil/merge_test.go index be431b5740cea..da0a400c651cc 100644 --- a/op-deployer/pkg/deployer/state/deploy_config_test.go +++ b/op-service/jsonutil/merge_test.go @@ -1,4 +1,4 @@ -package state +package jsonutil import ( "testing" @@ -13,7 +13,7 @@ func TestMergeJSON(t *testing.T) { C bool `json:"c"` } - out, err := mergeJSON( + out, err := MergeJSON( testStruct{ "hello", 42, diff --git a/op-service/locks/rwmap.go b/op-service/locks/rwmap.go new file mode 100644 index 0000000000000..2a6badf25525a --- /dev/null +++ b/op-service/locks/rwmap.go @@ -0,0 +1,55 @@ +package locks + +import "sync" + +// RWMap is a simple wrapper around a map, with global Read-Write protection. +// For many concurrent reads/writes a sync.Map may be more performant, +// although it does not utilize Go generics. +// The RWMap does not have to be initialized, +// it is immediately ready for reads/writes. +type RWMap[K comparable, V any] struct { + inner map[K]V + mu sync.RWMutex +} + +func (m *RWMap[K, V]) Has(key K) (ok bool) { + m.mu.RLock() + defer m.mu.RUnlock() + _, ok = m.inner[key] + return +} + +func (m *RWMap[K, V]) Get(key K) (value V, ok bool) { + m.mu.RLock() + defer m.mu.RUnlock() + value, ok = m.inner[key] + return +} + +func (m *RWMap[K, V]) Set(key K, value V) { + m.mu.Lock() + defer m.mu.Unlock() + if m.inner == nil { + m.inner = make(map[K]V) + } + m.inner[key] = value +} + +// Range calls f sequentially for each key and value present in the map. +// If f returns false, range stops the iteration. +func (m *RWMap[K, V]) Range(f func(key K, value V) bool) { + m.mu.RLock() + defer m.mu.RUnlock() + for k, v := range m.inner { + if !f(k, v) { + break + } + } +} + +// Clear removes all key-value pairs from the map. +func (m *RWMap[K, V]) Clear() { + m.mu.Lock() + defer m.mu.Unlock() + clear(m.inner) +} diff --git a/op-service/locks/rwmap_test.go b/op-service/locks/rwmap_test.go new file mode 100644 index 0000000000000..c78fab97034b8 --- /dev/null +++ b/op-service/locks/rwmap_test.go @@ -0,0 +1,52 @@ +package locks + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestRWMap(t *testing.T) { + m := &RWMap[uint64, int64]{} + + // get on new map + v, ok := m.Get(123) + require.False(t, ok) + require.Equal(t, int64(0), v) + + // set a value + m.Set(123, 42) + v, ok = m.Get(123) + require.True(t, ok) + require.Equal(t, int64(42), v) + + // overwrite a value + m.Set(123, -42) + v, ok = m.Get(123) + require.True(t, ok) + require.Equal(t, int64(-42), v) + + // add a value + m.Set(10, 100) + + // range over values + got := make(map[uint64]int64) + m.Range(func(key uint64, value int64) bool { + if _, ok := got[key]; ok { + panic("duplicate") + } + got[key] = value + return true + }) + require.Len(t, got, 2) + require.Equal(t, int64(100), got[uint64(10)]) + require.Equal(t, int64(-42), got[uint64(123)]) + + // range and stop early + clear(got) + m.Range(func(key uint64, value int64) bool { + got[key] = value + return false + }) + require.Len(t, got, 1, "stop early") +} diff --git a/op-service/locks/rwvalue.go b/op-service/locks/rwvalue.go new file mode 100644 index 0000000000000..12ca65e61d738 --- /dev/null +++ b/op-service/locks/rwvalue.go @@ -0,0 +1,24 @@ +package locks + +import "sync" + +// RWValue is a simple container struct, to deconflict reads/writes of the value, +// without locking up a bigger structure in the caller. +// It exposes the underlying RWLock and Value for direct access where needed. +type RWValue[E any] struct { + sync.RWMutex + Value E +} + +func (c *RWValue[E]) Get() (out E) { + c.RLock() + defer c.RUnlock() + out = c.Value + return +} + +func (c *RWValue[E]) Set(v E) { + c.Lock() + defer c.Unlock() + c.Value = v +} diff --git a/op-service/locks/rwvalue_test.go b/op-service/locks/rwvalue_test.go new file mode 100644 index 0000000000000..f99d9345a1cc4 --- /dev/null +++ b/op-service/locks/rwvalue_test.go @@ -0,0 +1,16 @@ +package locks + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestRWValue(t *testing.T) { + v := &RWValue[uint64]{} + require.Equal(t, uint64(0), v.Get()) + v.Set(123) + require.Equal(t, uint64(123), v.Get()) + v.Set(42) + require.Equal(t, uint64(42), v.Get()) +} diff --git a/op-service/metrics/factory.go b/op-service/metrics/factory.go index 0bd4da2373dbb..315b7c52e0580 100644 --- a/op-service/metrics/factory.go +++ b/op-service/metrics/factory.go @@ -9,6 +9,7 @@ type Factory interface { NewCounter(opts prometheus.CounterOpts) prometheus.Counter NewCounterVec(opts prometheus.CounterOpts, labelNames []string) *prometheus.CounterVec NewGauge(opts prometheus.GaugeOpts) prometheus.Gauge + NewGaugeFunc(opts prometheus.GaugeOpts, function func() float64) prometheus.GaugeFunc NewGaugeVec(opts prometheus.GaugeOpts, labelNames []string) *prometheus.GaugeVec NewHistogram(opts prometheus.HistogramOpts) prometheus.Histogram NewHistogramVec(opts prometheus.HistogramOpts, labelNames []string) *prometheus.HistogramVec @@ -63,6 +64,15 @@ func (d *documentor) NewGauge(opts prometheus.GaugeOpts) prometheus.Gauge { return d.factory.NewGauge(opts) } +func (d *documentor) NewGaugeFunc(opts prometheus.GaugeOpts, function func() float64) prometheus.GaugeFunc { + d.metrics = append(d.metrics, DocumentedMetric{ + Type: "gauge", + Name: fullName(opts.Namespace, opts.Subsystem, opts.Name), + Help: opts.Help, + }) + return d.factory.NewGaugeFunc(opts, function) +} + func (d *documentor) NewGaugeVec(opts prometheus.GaugeOpts, labelNames []string) *prometheus.GaugeVec { d.metrics = append(d.metrics, DocumentedMetric{ Type: "gauge", diff --git a/op-service/sources/engine_client.go b/op-service/sources/engine_client.go index 3f9faa9a1e345..8e06336b18035 100644 --- a/op-service/sources/engine_client.go +++ b/op-service/sources/engine_client.go @@ -9,7 +9,6 @@ import ( "github.com/ethereum/go-ethereum/eth/catalyst" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-service/client" @@ -86,11 +85,7 @@ func (s *EngineAPIClient) EngineVersionProvider() EngineVersionProvider { return // ForkchoiceUpdate updates the forkchoice on the execution client. If attributes is not nil, the engine client will also begin building a block // based on attributes after the new head block and return the payload ID. -// -// The RPC may return three types of errors: -// 1. Processing error: ForkchoiceUpdatedResult.PayloadStatusV1.ValidationError or other non-success PayloadStatusV1, -// 2. `error` as eth.InputError: the forkchoice state or attributes are not valid. -// 3. Other types of `error`: temporary RPC errors, like timeouts. +// It's the caller's responsibility to check the error type, and in case of an rpc.Error, check the ErrorCode. func (s *EngineAPIClient) ForkchoiceUpdate(ctx context.Context, fc *eth.ForkchoiceState, attributes *eth.PayloadAttributes) (*eth.ForkchoiceUpdatedResult, error) { llog := s.log.New("state", fc) // local logger tlog := llog.New("attr", attributes) // trace logger @@ -100,28 +95,15 @@ func (s *EngineAPIClient) ForkchoiceUpdate(ctx context.Context, fc *eth.Forkchoi var result eth.ForkchoiceUpdatedResult method := s.evp.ForkchoiceUpdatedVersion(attributes) err := s.RPC.CallContext(fcCtx, &result, string(method), fc, attributes) - if err == nil { - tlog.Trace("Shared forkchoice-updated signal") - if attributes != nil { // block building is optional, we only get a payload ID if we are building a block - tlog.Trace("Received payload id", "payloadId", result.PayloadID) - } - return &result, nil - } else { + if err != nil { llog.Warn("Failed to share forkchoice-updated signal", "err", err) - if rpcErr, ok := err.(rpc.Error); ok { - code := eth.ErrorCode(rpcErr.ErrorCode()) - switch code { - case eth.InvalidParams, eth.InvalidForkchoiceState, eth.InvalidPayloadAttributes: - return nil, eth.InputError{ - Inner: err, - Code: code, - } - default: - return nil, fmt.Errorf("unrecognized rpc error: %w", err) - } - } return nil, err } + tlog.Trace("Shared forkchoice-updated signal") + if attributes != nil { // block building is optional, we only get a payload ID if we are building a block + tlog.Trace("Received payload id", "payloadId", result.PayloadID) + } + return &result, nil } // NewPayload executes a full block on the execution engine. @@ -156,9 +138,7 @@ func (s *EngineAPIClient) NewPayload(ctx context.Context, payload *eth.Execution } // GetPayload gets the execution payload associated with the PayloadId. -// There may be two types of error: -// 1. `error` as eth.InputError: the payload ID may be unknown -// 2. Other types of `error`: temporary RPC errors, like timeouts. +// It's the caller's responsibility to check the error type, and in case of an rpc.Error, check the ErrorCode. func (s *EngineAPIClient) GetPayload(ctx context.Context, payloadInfo eth.PayloadInfo) (*eth.ExecutionPayloadEnvelope, error) { e := s.log.New("payload_id", payloadInfo.ID) e.Trace("getting payload") @@ -167,18 +147,6 @@ func (s *EngineAPIClient) GetPayload(ctx context.Context, payloadInfo eth.Payloa err := s.RPC.CallContext(ctx, &result, string(method), payloadInfo.ID) if err != nil { e.Warn("Failed to get payload", "payload_id", payloadInfo.ID, "err", err) - if rpcErr, ok := err.(rpc.Error); ok { - code := eth.ErrorCode(rpcErr.ErrorCode()) - switch code { - case eth.UnknownPayload: - return nil, eth.InputError{ - Inner: err, - Code: code, - } - default: - return nil, fmt.Errorf("unrecognized rpc error: %w", err) - } - } return nil, err } e.Trace("Received payload") diff --git a/op-service/sources/eth_client.go b/op-service/sources/eth_client.go index 0c83b52336a66..39587fd197504 100644 --- a/op-service/sources/eth_client.go +++ b/op-service/sources/eth_client.go @@ -315,6 +315,22 @@ func (s *EthClient) FetchReceipts(ctx context.Context, blockHash common.Hash) (e return info, receipts, nil } +// ExecutionWitness fetches execution witness data for a block number. +func (s *EthClient) ExecutionWitness(ctx context.Context, blockNum uint64) (*eth.ExecutionWitness, error) { + var witness *eth.ExecutionWitness + + err := s.client.CallContext(ctx, &witness, "debug_executionWitness", hexutil.EncodeUint64(blockNum), true) + if err != nil { + return nil, err + } + + if witness == nil { + return nil, ethereum.NotFound + } + + return witness, nil +} + // GetProof returns an account proof result, with any optional requested storage proofs. // The retrieval does sanity-check that storage proofs for the expected keys are present in the response, // but does not verify the result. Call accountResult.Verify(stateRoot) to verify the result. diff --git a/op-service/sources/receipts_basic_test.go b/op-service/sources/receipts_basic_test.go index ca2f00f9aa216..ad1ed16013adc 100644 --- a/op-service/sources/receipts_basic_test.go +++ b/op-service/sources/receipts_basic_test.go @@ -9,6 +9,8 @@ import ( "testing" "time" + "github.com/ethereum-optimism/optimism/op-service/retry" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" @@ -104,32 +106,48 @@ func TestBasicRPCReceiptsFetcher_Concurrency(t *testing.T) { for _, rec := range receipts { recMap[rec.TxHash] = rec } - mrpc := new(mockRPC) - rp := NewBasicRPCReceiptsFetcher(mrpc, batchSize) - // prepare mock - var numCalls atomic.Int32 - mrpc.On("BatchCallContext", mock.Anything, mock.AnythingOfType("[]rpc.BatchElem")). - Run(func(args mock.Arguments) { - numCalls.Add(1) - els := args.Get(1).([]rpc.BatchElem) - for _, el := range els { - if el.Method == "eth_getTransactionReceipt" { - txHash := el.Args[0].(common.Hash) - // The IterativeBatchCall expects that the values are written - // to the fields of the allocated *types.Receipt. - **(el.Result.(**types.Receipt)) = *recMap[txHash] + boff := &retry.ExponentialStrategy{ + Min: 0, + Max: time.Second, + MaxJitter: 100 * time.Millisecond, + } + err := retry.Do0(context.Background(), 10, boff, func() error { + mrpc := new(mockRPC) + rp := NewBasicRPCReceiptsFetcher(mrpc, batchSize) + + // prepare mock + var numCalls atomic.Int32 + mrpc.On("BatchCallContext", mock.Anything, mock.AnythingOfType("[]rpc.BatchElem")). + Run(func(args mock.Arguments) { + numCalls.Add(1) + els := args.Get(1).([]rpc.BatchElem) + for _, el := range els { + if el.Method == "eth_getTransactionReceipt" { + txHash := el.Args[0].(common.Hash) + // The IterativeBatchCall expects that the values are written + // to the fields of the allocated *types.Receipt. + **(el.Result.(**types.Receipt)) = *recMap[txHash] + } } - } - }). - Return([]error{nil}) + }). + Return([]error{nil}) - runConcurrentFetchingTest(t, rp, numFetchers, receipts, block) + runConcurrentFetchingTest(t, rp, numFetchers, receipts, block) - mrpc.AssertExpectations(t) - finalNumCalls := int(numCalls.Load()) - require.NotZero(finalNumCalls, "BatchCallContext should have been called.") - require.Less(finalNumCalls, numFetchers*numBatchCalls, "Some IterativeBatchCalls should have been shared.") + mrpc.AssertExpectations(t) + finalNumCalls := int(numCalls.Load()) + + if finalNumCalls == 0 { + return errors.New("batchCallContext should have been called") + } + + if finalNumCalls >= numFetchers*numBatchCalls { + return errors.New("some IterativeBatchCalls should have been shared") + } + return nil + }) + require.NoError(err) } func runConcurrentFetchingTest(t *testing.T, rp ReceiptsProvider, numFetchers int, receipts types.Receipts, block *RPCBlock) { diff --git a/op-service/sources/supervisor_client.go b/op-service/sources/supervisor_client.go index 48063e351e54a..d6191b9cfb208 100644 --- a/op-service/sources/supervisor_client.go +++ b/op-service/sources/supervisor_client.go @@ -4,11 +4,10 @@ import ( "context" "fmt" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" + "github.com/ethereum/go-ethereum/common" ) type SupervisorClient struct { @@ -21,9 +20,7 @@ func NewSupervisorClient(client client.RPC) *SupervisorClient { } } -func (cl *SupervisorClient) Stop( - ctx context.Context, -) error { +func (cl *SupervisorClient) Stop(ctx context.Context) error { var result error err := cl.client.CallContext( ctx, @@ -35,9 +32,7 @@ func (cl *SupervisorClient) Stop( return result } -func (cl *SupervisorClient) Start( - ctx context.Context, -) error { +func (cl *SupervisorClient) Start(ctx context.Context) error { var result error err := cl.client.CallContext( ctx, @@ -49,10 +44,7 @@ func (cl *SupervisorClient) Start( return result } -func (cl *SupervisorClient) AddL2RPC( - ctx context.Context, - rpc string, -) error { +func (cl *SupervisorClient) AddL2RPC(ctx context.Context, rpc string) error { var result error err := cl.client.CallContext( ctx, @@ -65,6 +57,25 @@ func (cl *SupervisorClient) AddL2RPC( return result } +func (cl *SupervisorClient) CheckMessage(ctx context.Context, identifier types.Identifier, logHash common.Hash) (types.SafetyLevel, error) { + var result types.SafetyLevel + err := cl.client.CallContext( + ctx, + &result, + "supervisor_checkMessage", + identifier, + logHash) + if err != nil { + return types.Invalid, fmt.Errorf("failed to check message (chain %s), (block %v), (index %v), (logHash %s): %w", + identifier.ChainID, + identifier.BlockNumber, + identifier.LogIndex, + logHash, + err) + } + return result, nil +} + func (cl *SupervisorClient) UnsafeView(ctx context.Context, chainID types.ChainID, unsafe types.ReferenceView) (types.ReferenceView, error) { var result types.ReferenceView err := cl.client.CallContext( @@ -95,26 +106,51 @@ func (cl *SupervisorClient) SafeView(ctx context.Context, chainID types.ChainID, func (cl *SupervisorClient) Finalized(ctx context.Context, chainID types.ChainID) (eth.BlockID, error) { var result eth.BlockID - err := cl.client.CallContext(ctx, &result, "supervisor_finalized", chainID) + err := cl.client.CallContext( + ctx, + &result, + "supervisor_finalized", + chainID) return result, err } -func (cl *SupervisorClient) DerivedFrom(ctx context.Context, chainID types.ChainID, blockHash common.Hash, blockNumber uint64) (eth.L1BlockRef, error) { - var result eth.L1BlockRef - err := cl.client.CallContext(ctx, &result, "supervisor_derivedFrom", chainID, blockHash, blockNumber) +func (cl *SupervisorClient) CrossDerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (eth.BlockRef, error) { + var result eth.BlockRef + err := cl.client.CallContext( + ctx, + &result, + "supervisor_crossDerivedFrom", + chainID, + derived) return result, err } -func (cl *SupervisorClient) UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.L2BlockRef) error { - return cl.client.CallContext(ctx, nil, "supervisor_updateLocalUnsafe", chainID, head) +func (cl *SupervisorClient) UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.BlockRef) error { + return cl.client.CallContext( + ctx, + nil, + "supervisor_updateLocalUnsafe", + chainID, + head) } -func (cl *SupervisorClient) UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.L2BlockRef) error { - return cl.client.CallContext(ctx, nil, "supervisor_updateLocalSafe", chainID, derivedFrom, lastDerived) +func (cl *SupervisorClient) UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.BlockRef) error { + return cl.client.CallContext( + ctx, + nil, + "supervisor_updateLocalSafe", + chainID, + derivedFrom, + lastDerived) } func (cl *SupervisorClient) UpdateFinalizedL1(ctx context.Context, chainID types.ChainID, finalizedL1 eth.L1BlockRef) error { - return cl.client.CallContext(ctx, nil, "supervisor_updateFinalizedL1", chainID, finalizedL1) + return cl.client.CallContext( + ctx, + nil, + "supervisor_updateFinalizedL1", + chainID, + finalizedL1) } func (cl *SupervisorClient) Close() { diff --git a/op-service/testutils/fake_interop_backend.go b/op-service/testutils/fake_interop_backend.go index 7c6287031229c..4c8624d535525 100644 --- a/op-service/testutils/fake_interop_backend.go +++ b/op-service/testutils/fake_interop_backend.go @@ -3,8 +3,6 @@ package testutils import ( "context" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -13,9 +11,9 @@ type FakeInteropBackend struct { UnsafeViewFn func(ctx context.Context, chainID types.ChainID, unsafe types.ReferenceView) (types.ReferenceView, error) SafeViewFn func(ctx context.Context, chainID types.ChainID, safe types.ReferenceView) (types.ReferenceView, error) FinalizedFn func(ctx context.Context, chainID types.ChainID) (eth.BlockID, error) - DerivedFromFn func(ctx context.Context, chainID types.ChainID, blockHash common.Hash, blockNumber uint64) (eth.L1BlockRef, error) - UpdateLocalUnsafeFn func(ctx context.Context, chainID types.ChainID, head eth.L2BlockRef) error - UpdateLocalSafeFn func(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.L2BlockRef) error + DerivedFromFn func(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (eth.L1BlockRef, error) + UpdateLocalUnsafeFn func(ctx context.Context, chainID types.ChainID, head eth.BlockRef) error + UpdateLocalSafeFn func(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.BlockRef) error UpdateFinalizedL1Fn func(ctx context.Context, chainID types.ChainID, finalized eth.L1BlockRef) error } @@ -31,15 +29,15 @@ func (m *FakeInteropBackend) Finalized(ctx context.Context, chainID types.ChainI return m.FinalizedFn(ctx, chainID) } -func (m *FakeInteropBackend) DerivedFrom(ctx context.Context, chainID types.ChainID, blockHash common.Hash, blockNumber uint64) (eth.L1BlockRef, error) { - return m.DerivedFromFn(ctx, chainID, blockHash, blockNumber) +func (m *FakeInteropBackend) CrossDerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (eth.L1BlockRef, error) { + return m.DerivedFromFn(ctx, chainID, derived) } -func (m *FakeInteropBackend) UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.L2BlockRef) error { +func (m *FakeInteropBackend) UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.BlockRef) error { return m.UpdateLocalUnsafeFn(ctx, chainID, head) } -func (m *FakeInteropBackend) UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.L2BlockRef) error { +func (m *FakeInteropBackend) UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.BlockRef) error { return m.UpdateLocalSafeFn(ctx, chainID, derivedFrom, lastDerived) } diff --git a/op-service/testutils/mock_eth_client.go b/op-service/testutils/mock_eth_client.go index fcb0a60c24b08..2d82966724b33 100644 --- a/op-service/testutils/mock_eth_client.go +++ b/op-service/testutils/mock_eth_client.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum-optimism/optimism/op-service/eth" ) @@ -16,6 +17,11 @@ type MockEthClient struct { mock.Mock } +func (m *MockEthClient) Client() *rpc.Client { + out := m.Mock.Called() + return out.Get(0).(*rpc.Client) +} + func (m *MockEthClient) InfoByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, error) { out := m.Mock.Called(hash) return *out.Get(0).(*eth.BlockInfo), out.Error(1) diff --git a/op-service/testutils/mock_interop_backend.go b/op-service/testutils/mock_interop_backend.go index 4bb300a95ff2f..af6762c204cd6 100644 --- a/op-service/testutils/mock_interop_backend.go +++ b/op-service/testutils/mock_interop_backend.go @@ -5,8 +5,6 @@ import ( "github.com/stretchr/testify/mock" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -60,21 +58,21 @@ func (m *MockInteropBackend) ExpectFinalized(chainID types.ChainID, result eth.B m.Mock.On("Finalized", chainID).Once().Return(result, &err) } -func (m *MockInteropBackend) DerivedFrom(ctx context.Context, chainID types.ChainID, blockHash common.Hash, blockNumber uint64) (eth.L1BlockRef, error) { - result := m.Mock.MethodCalled("DerivedFrom", chainID, blockHash, blockNumber) +func (m *MockInteropBackend) CrossDerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (eth.L1BlockRef, error) { + result := m.Mock.MethodCalled("CrossDerivedFrom", chainID, derived) return result.Get(0).(eth.L1BlockRef), *result.Get(1).(*error) } -func (m *MockInteropBackend) ExpectDerivedFrom(chainID types.ChainID, blockHash common.Hash, blockNumber uint64, result eth.L1BlockRef, err error) { - m.Mock.On("DerivedFrom", chainID, blockHash, blockNumber).Once().Return(result, &err) +func (m *MockInteropBackend) ExpectDerivedFrom(chainID types.ChainID, derived eth.BlockID, result eth.L1BlockRef, err error) { + m.Mock.On("CrossDerivedFrom", chainID, derived).Once().Return(result, &err) } -func (m *MockInteropBackend) UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.L2BlockRef) error { +func (m *MockInteropBackend) UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.BlockRef) error { result := m.Mock.MethodCalled("UpdateLocalUnsafe", chainID, head) return *result.Get(0).(*error) } -func (m *MockInteropBackend) ExpectUpdateLocalUnsafe(chainID types.ChainID, head eth.L2BlockRef, err error) { +func (m *MockInteropBackend) ExpectUpdateLocalUnsafe(chainID types.ChainID, head eth.BlockRef, err error) { m.Mock.On("UpdateLocalUnsafe", chainID, head).Once().Return(&err) } @@ -82,12 +80,12 @@ func (m *MockInteropBackend) ExpectAnyUpdateLocalUnsafe(chainID types.ChainID, e m.Mock.On("UpdateLocalUnsafe", chainID, mock.Anything).Once().Return(&err) } -func (m *MockInteropBackend) UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.L2BlockRef) error { +func (m *MockInteropBackend) UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.BlockRef) error { result := m.Mock.MethodCalled("UpdateLocalSafe", chainID, derivedFrom, lastDerived) return *result.Get(0).(*error) } -func (m *MockInteropBackend) ExpectUpdateLocalSafe(chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.L2BlockRef, err error) { +func (m *MockInteropBackend) ExpectUpdateLocalSafe(chainID types.ChainID, derivedFrom eth.L1BlockRef, lastDerived eth.BlockRef, err error) { m.Mock.On("UpdateLocalSafe", chainID, derivedFrom, lastDerived).Once().Return(&err) } diff --git a/op-service/tls/cli.go b/op-service/tls/cli.go index b00b084cd339b..e2e086e922c3c 100644 --- a/op-service/tls/cli.go +++ b/op-service/tls/cli.go @@ -12,9 +12,10 @@ import ( ) const ( - TLSCaCertFlagName = "tls.ca" - TLSCertFlagName = "tls.cert" - TLSKeyFlagName = "tls.key" + TLSCaCertFlagName = "tls.ca" + TLSCertFlagName = "tls.cert" + TLSKeyFlagName = "tls.key" + TLSEnabledFlagName = "tls.enabled" ) // CLIFlags returns flags with env var envPrefix @@ -24,9 +25,10 @@ func CLIFlags(envPrefix string) []cli.Flag { } var ( - defaultTLSCaCert = "tls/ca.crt" - defaultTLSCert = "tls/tls.crt" - defaultTLSKey = "tls/tls.key" + defaultTLSCaCert = "tls/ca.crt" + defaultTLSCert = "tls/tls.crt" + defaultTLSKey = "tls/tls.key" + defaultTLSEnabled = true ) // CLIFlagsWithFlagPrefix returns flags with env var and cli flag prefixes @@ -39,6 +41,12 @@ func CLIFlagsWithFlagPrefix(envPrefix string, flagPrefix string) []cli.Flag { return opservice.PrefixEnvVar(envPrefix, name) } return []cli.Flag{ + &cli.BoolFlag{ + Name: prefixFunc(TLSEnabledFlagName), + Usage: "Enable or disable TLS client authentication for the signer", + Value: defaultTLSEnabled, + EnvVars: prefixEnvVars("TLS_ENABLED"), + }, &cli.StringFlag{ Name: prefixFunc(TLSCaCertFlagName), Usage: "tls ca cert path", @@ -72,7 +80,7 @@ func NewCLIConfig() CLIConfig { TLSCaCert: defaultTLSCaCert, TLSCert: defaultTLSCert, TLSKey: defaultTLSKey, - Enabled: false, + Enabled: true, } } @@ -95,7 +103,7 @@ func ReadCLIConfig(ctx *cli.Context) CLIConfig { TLSCaCert: ctx.String(TLSCaCertFlagName), TLSCert: ctx.String(TLSCertFlagName), TLSKey: ctx.String(TLSKeyFlagName), - Enabled: ctx.IsSet(TLSCaCertFlagName) || ctx.IsSet(TLSCertFlagName) || ctx.IsSet(TLSKeyFlagName), + Enabled: ctx.Bool(TLSEnabledFlagName), } } @@ -109,6 +117,6 @@ func ReadCLIConfigWithPrefix(ctx *cli.Context, flagPrefix string) CLIConfig { TLSCaCert: ctx.String(prefixFunc(TLSCaCertFlagName)), TLSCert: ctx.String(prefixFunc(TLSCertFlagName)), TLSKey: ctx.String(prefixFunc(TLSKeyFlagName)), - Enabled: ctx.IsSet(TLSCaCertFlagName) || ctx.IsSet(TLSCertFlagName) || ctx.IsSet(TLSKeyFlagName), + Enabled: ctx.Bool(prefixFunc(TLSEnabledFlagName)), } } diff --git a/op-service/tls/cli_test.go b/op-service/tls/cli_test.go index f926a19fabdd5..bd4ea4bf17c99 100644 --- a/op-service/tls/cli_test.go +++ b/op-service/tls/cli_test.go @@ -1,6 +1,7 @@ package tls import ( + "fmt" "testing" "github.com/stretchr/testify/require" @@ -41,6 +42,12 @@ func TestInvalidConfig(t *testing.T) { err := cfg.Check() require.ErrorContains(t, err, "all tls flags must be set if at least one is set") }) + t.Run(fmt.Sprintf("%sAllowedWhenDisabled", test.name), func(t *testing.T) { + cfg := NewCLIConfig() + cfg.Enabled = false + test.configChange(&cfg) + require.NoError(t, cfg.Check()) + }) } } diff --git a/op-supervisor/config/config_test.go b/op-supervisor/config/config_test.go index fd57c7b95d97e..0d354ca134a56 100644 --- a/op-supervisor/config/config_test.go +++ b/op-supervisor/config/config_test.go @@ -56,13 +56,15 @@ func TestValidateRPCConfig(t *testing.T) { } func validConfig() *Config { - depSet := &depset.StaticConfigDependencySet{ - Dependencies: map[types.ChainID]*depset.StaticConfigDependency{ - types.ChainIDFromUInt64(900): &depset.StaticConfigDependency{ - ActivationTime: 0, - HistoryMinTime: 0, - }, + depSet, err := depset.NewStaticConfigDependencySet(map[types.ChainID]*depset.StaticConfigDependency{ + types.ChainIDFromUInt64(900): &depset.StaticConfigDependency{ + ChainIndex: 900, + ActivationTime: 0, + HistoryMinTime: 0, }, + }) + if err != nil { + panic(err) } // Should be valid using only the required arguments passed in via the constructor. return NewConfig([]string{"http://localhost:8545"}, depSet, "./supervisor_testdir") diff --git a/op-supervisor/supervisor/backend/backend.go b/op-supervisor/supervisor/backend/backend.go index 7a1eb2eaf78a1..7d368cb40f159 100644 --- a/op-supervisor/supervisor/backend/backend.go +++ b/op-supervisor/supervisor/backend/backend.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "sync" "sync/atomic" "time" @@ -14,10 +13,11 @@ import ( "github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/dial" "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/locks" "github.com/ethereum-optimism/optimism/op-service/sources" "github.com/ethereum-optimism/optimism/op-supervisor/config" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/cross" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/entrydb" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/processors" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/frontend" @@ -30,11 +30,6 @@ type SupervisorBackend struct { m Metrics dataDir string - // RW lock to avoid concurrent map mutations. - // Read = any chain may be used and mutated. - // Write = set of chains is changing. - mu sync.RWMutex - // depSet is the dependency set that the backend uses to know about the chains it is indexing depSet depset.DependencySet @@ -42,15 +37,21 @@ type SupervisorBackend struct { chainDBs *db.ChainsDB // chainProcessors are notified of new unsafe blocks, and add the unsafe log events data into the events DB - chainProcessors map[types.ChainID]*processors.ChainProcessor + chainProcessors locks.RWMap[types.ChainID, *processors.ChainProcessor] - // synchronousProcessors disables background-workers, - // requiring manual triggers for the backend to process anything. - synchronousProcessors bool + // crossSafeProcessors take local-safe data and promote it to cross-safe when verified + crossSafeProcessors locks.RWMap[types.ChainID, *cross.Worker] + + // crossUnsafeProcessors take local-unsafe data and promote it to cross-unsafe when verified + crossUnsafeProcessors locks.RWMap[types.ChainID, *cross.Worker] // chainMetrics are used to track metrics for each chain // they are reused for processors and databases of the same chain - chainMetrics map[types.ChainID]*chainMetrics + chainMetrics locks.RWMap[types.ChainID, *chainMetrics] + + // synchronousProcessors disables background-workers, + // requiring manual triggers for the backend to process anything. + synchronousProcessors bool } var _ frontend.Backend = (*SupervisorBackend)(nil) @@ -68,22 +69,17 @@ func NewSupervisorBackend(ctx context.Context, logger log.Logger, m Metrics, cfg if err != nil { return nil, fmt.Errorf("failed to load dependency set: %w", err) } - chains := depSet.Chains() // create initial per-chain resources - chainsDBs := db.NewChainsDB(logger) - chainProcessors := make(map[types.ChainID]*processors.ChainProcessor, len(chains)) - chainMetrics := make(map[types.ChainID]*chainMetrics, len(chains)) + chainsDBs := db.NewChainsDB(logger, depSet) // create the supervisor backend super := &SupervisorBackend{ - logger: logger, - m: m, - dataDir: cfg.Datadir, - depSet: depSet, - chainDBs: chainsDBs, - chainProcessors: chainProcessors, - chainMetrics: chainMetrics, + logger: logger, + m: m, + dataDir: cfg.Datadir, + depSet: depSet, + chainDBs: chainsDBs, // For testing we can avoid running the processors. synchronousProcessors: cfg.SynchronousProcessors, } @@ -111,11 +107,22 @@ func (su *SupervisorBackend) initResources(ctx context.Context, cfg *config.Conf } } - // for each chain initialize a chain processor service + // initialize all cross-unsafe processors + for _, chainID := range chains { + worker := cross.NewCrossUnsafeWorker(su.logger, chainID, su.chainDBs) + su.crossUnsafeProcessors.Set(chainID, worker) + } + // initialize all cross-safe processors + for _, chainID := range chains { + worker := cross.NewCrossSafeWorker(su.logger, chainID, su.chainDBs) + su.crossSafeProcessors.Set(chainID, worker) + } + // For each chain initialize a chain processor service, + // after cross-unsafe workers are ready to receive updates for _, chainID := range chains { logProcessor := processors.NewLogProcessor(chainID, su.chainDBs) - chainProcessor := processors.NewChainProcessor(su.logger, chainID, logProcessor, su.chainDBs) - su.chainProcessors[chainID] = chainProcessor + chainProcessor := processors.NewChainProcessor(su.logger, chainID, logProcessor, su.chainDBs, su.onIndexedLocalUnsafeData) + su.chainProcessors.Set(chainID, chainProcessor) } // the config has some RPC connections to attach to the chain-processors @@ -128,12 +135,38 @@ func (su *SupervisorBackend) initResources(ctx context.Context, cfg *config.Conf return nil } +// onIndexedLocalUnsafeData is called by the event indexing workers. +// This signals to cross-unsafe workers that there's data to index. +func (su *SupervisorBackend) onIndexedLocalUnsafeData() { + // We signal all workers, since dependencies on a chain may be unblocked + // by new data on other chains. + // Busy workers don't block processing. + // The signal is picked up only if the worker is running in the background. + su.crossUnsafeProcessors.Range(func(_ types.ChainID, w *cross.Worker) bool { + w.OnNewData() + return true + }) +} + +// onNewLocalSafeData is called by the safety-indexing. +// This signals to cross-safe workers that there's data to index. +func (su *SupervisorBackend) onNewLocalSafeData() { + // We signal all workers, since dependencies on a chain may be unblocked + // by new data on other chains. + // Busy workers don't block processing. + // The signal is picked up only if the worker is running in the background. + su.crossSafeProcessors.Range(func(_ types.ChainID, w *cross.Worker) bool { + w.OnNewData() + return true + }) +} + // openChainDBs initializes all the DB resources of a specific chain. // It is a sub-task of initResources. func (su *SupervisorBackend) openChainDBs(chainID types.ChainID) error { cm := newChainMetrics(chainID, su.m) // create metrics and a logdb for the chain - su.chainMetrics[chainID] = cm + su.chainMetrics.Set(chainID, cm) logDB, err := db.OpenLogDB(su.logger, chainID, su.dataDir, cm) if err != nil { @@ -167,9 +200,9 @@ func (su *SupervisorBackend) attachRPC(ctx context.Context, rpc string) error { return err } if !su.depSet.HasChain(chainID) { - return fmt.Errorf("chain %s is not part of the interop dependency set: %w", chainID, db.ErrUnknownChain) + return fmt.Errorf("chain %s is not part of the interop dependency set: %w", chainID, types.ErrUnknownChain) } - cm, ok := su.chainMetrics[chainID] + cm, ok := su.chainMetrics.Get(chainID) if !ok { return fmt.Errorf("failed to find metrics for chain %v", chainID) } @@ -189,10 +222,7 @@ func (su *SupervisorBackend) attachRPC(ctx context.Context, rpc string) error { } func (su *SupervisorBackend) AttachProcessorSource(chainID types.ChainID, src processors.Source) error { - su.mu.RLock() - defer su.mu.RUnlock() - - proc, ok := su.chainProcessors[chainID] + proc, ok := su.chainProcessors.Get(chainID) if !ok { return fmt.Errorf("unknown chain %s, cannot attach RPC to processor", chainID) } @@ -213,9 +243,6 @@ func clientForL2(ctx context.Context, logger log.Logger, rpc string) (client.RPC } func (su *SupervisorBackend) Start(ctx context.Context) error { - su.mu.Lock() - defer su.mu.Unlock() - // ensure we only start once if !su.started.CompareAndSwap(false, true) { return errors.New("already started") @@ -229,74 +256,107 @@ func (su *SupervisorBackend) Start(ctx context.Context) error { if !su.synchronousProcessors { // Make all the chain-processors run automatic background processing - for _, processor := range su.chainProcessors { + su.chainProcessors.Range(func(_ types.ChainID, processor *processors.ChainProcessor) bool { processor.StartBackground() - } + return true + }) + su.crossUnsafeProcessors.Range(func(_ types.ChainID, worker *cross.Worker) bool { + worker.StartBackground() + return true + }) + su.crossSafeProcessors.Range(func(_ types.ChainID, worker *cross.Worker) bool { + worker.StartBackground() + return true + }) } return nil } func (su *SupervisorBackend) Stop(ctx context.Context) error { - su.mu.Lock() - defer su.mu.Unlock() - if !su.started.CompareAndSwap(true, false) { return errAlreadyStopped } + su.logger.Info("Closing supervisor backend") // close all processors - for id, processor := range su.chainProcessors { + su.chainProcessors.Range(func(id types.ChainID, processor *processors.ChainProcessor) bool { su.logger.Info("stopping chain processor", "chainID", id) processor.Close() - } - clear(su.chainProcessors) + return true + }) + su.chainProcessors.Clear() + + su.crossUnsafeProcessors.Range(func(id types.ChainID, worker *cross.Worker) bool { + su.logger.Info("stopping cross-unsafe processor", "chainID", id) + worker.Close() + return true + }) + su.crossUnsafeProcessors.Clear() + + su.crossSafeProcessors.Range(func(id types.ChainID, worker *cross.Worker) bool { + su.logger.Info("stopping cross-safe processor", "chainID", id) + worker.Close() + return true + }) + su.crossSafeProcessors.Clear() + // close the databases return su.chainDBs.Close() } // AddL2RPC attaches an RPC as the RPC for the given chain, overriding the previous RPC source, if any. func (su *SupervisorBackend) AddL2RPC(ctx context.Context, rpc string) error { - su.mu.RLock() // read-lock: we only modify an existing chain, we don't add/remove chains - defer su.mu.RUnlock() - return su.attachRPC(ctx, rpc) } +// Internal methods, for processors +// ---------------------------- + +func (su *SupervisorBackend) DependencySet() depset.DependencySet { + return su.depSet +} + // Query methods // ---------------------------- func (su *SupervisorBackend) CheckMessage(identifier types.Identifier, payloadHash common.Hash) (types.SafetyLevel, error) { - su.mu.RLock() - defer su.mu.RUnlock() - + logHash := types.PayloadHashToLogHash(payloadHash, identifier.Origin) chainID := identifier.ChainID blockNum := identifier.BlockNumber logIdx := identifier.LogIndex - _, err := su.chainDBs.Check(chainID, blockNum, uint32(logIdx), payloadHash) - if errors.Is(err, entrydb.ErrFuture) { + _, err := su.chainDBs.Check(chainID, blockNum, logIdx, logHash) + if errors.Is(err, types.ErrFuture) { + su.logger.Debug("Future message", "identifier", identifier, "payloadHash", payloadHash, "err", err) return types.LocalUnsafe, nil } - if errors.Is(err, entrydb.ErrConflict) { + if errors.Is(err, types.ErrConflict) { + su.logger.Debug("Conflicting message", "identifier", identifier, "payloadHash", payloadHash, "err", err) return types.Invalid, nil } if err != nil { return types.Invalid, fmt.Errorf("failed to check log: %w", err) } - return su.chainDBs.Safest(chainID, blockNum, uint32(logIdx)) + return su.chainDBs.Safest(chainID, blockNum, logIdx) } func (su *SupervisorBackend) CheckMessages( messages []types.Message, minSafety types.SafetyLevel) error { - su.mu.RLock() - defer su.mu.RUnlock() + su.logger.Debug("Checking messages", "count", len(messages), "minSafety", minSafety) for _, msg := range messages { + su.logger.Debug("Checking message", + "identifier", msg.Identifier, "payloadHash", msg.PayloadHash.String()) safety, err := su.CheckMessage(msg.Identifier, msg.PayloadHash) if err != nil { + su.logger.Error("Check message failed", "err", err, + "identifier", msg.Identifier, "payloadHash", msg.PayloadHash.String()) return fmt.Errorf("failed to check message: %w", err) } if !safety.AtLeastAsSafe(minSafety) { + su.logger.Error("Message is not sufficiently safe", + "safety", safety, "minSafety", minSafety, + "identifier", msg.Identifier, "payloadHash", msg.PayloadHash.String()) return fmt.Errorf("message %v (safety level: %v) does not meet the minimum safety %v", msg.Identifier, safety, @@ -307,9 +367,6 @@ func (su *SupervisorBackend) CheckMessages( } func (su *SupervisorBackend) UnsafeView(ctx context.Context, chainID types.ChainID, unsafe types.ReferenceView) (types.ReferenceView, error) { - su.mu.RLock() - defer su.mu.RUnlock() - head, err := su.chainDBs.LocalUnsafe(chainID) if err != nil { return types.ReferenceView{}, fmt.Errorf("failed to get local-unsafe head: %w", err) @@ -328,9 +385,6 @@ func (su *SupervisorBackend) UnsafeView(ctx context.Context, chainID types.Chain } func (su *SupervisorBackend) SafeView(ctx context.Context, chainID types.ChainID, safe types.ReferenceView) (types.ReferenceView, error) { - su.mu.RLock() - defer su.mu.RUnlock() - _, localSafe, err := su.chainDBs.LocalSafe(chainID) if err != nil { return types.ReferenceView{}, fmt.Errorf("failed to get local-safe head: %w", err) @@ -349,9 +403,6 @@ func (su *SupervisorBackend) SafeView(ctx context.Context, chainID types.ChainID } func (su *SupervisorBackend) Finalized(ctx context.Context, chainID types.ChainID) (eth.BlockID, error) { - su.mu.RLock() - defer su.mu.RUnlock() - v, err := su.chainDBs.Finalized(chainID) if err != nil { return eth.BlockID{}, err @@ -359,40 +410,62 @@ func (su *SupervisorBackend) Finalized(ctx context.Context, chainID types.ChainI return v.ID(), nil } -func (su *SupervisorBackend) DerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (derivedFrom eth.BlockID, err error) { - su.mu.RLock() - defer su.mu.RUnlock() - - v, err := su.chainDBs.DerivedFrom(chainID, derived) +func (su *SupervisorBackend) CrossDerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (derivedFrom eth.BlockRef, err error) { + v, err := su.chainDBs.CrossDerivedFromBlockRef(chainID, derived) if err != nil { - return eth.BlockID{}, err + return eth.BlockRef{}, err } - return v.ID(), nil + return v, nil } // Update methods // ---------------------------- -func (su *SupervisorBackend) UpdateLocalUnsafe(chainID types.ChainID, head eth.BlockRef) error { - su.mu.RLock() - defer su.mu.RUnlock() - ch, ok := su.chainProcessors[chainID] +func (su *SupervisorBackend) UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.BlockRef) error { + ch, ok := su.chainProcessors.Get(chainID) if !ok { - return db.ErrUnknownChain + return types.ErrUnknownChain } return ch.OnNewHead(head) } -func (su *SupervisorBackend) UpdateLocalSafe(chainID types.ChainID, derivedFrom eth.BlockRef, lastDerived eth.BlockRef) error { - su.mu.RLock() - defer su.mu.RUnlock() +func (su *SupervisorBackend) UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.BlockRef, lastDerived eth.BlockRef) error { + err := su.chainDBs.UpdateLocalSafe(chainID, derivedFrom, lastDerived) + if err != nil { + return err + } + su.onNewLocalSafeData() + return nil +} - return su.chainDBs.UpdateLocalSafe(chainID, derivedFrom, lastDerived) +func (su *SupervisorBackend) UpdateFinalizedL1(ctx context.Context, chainID types.ChainID, finalized eth.BlockRef) error { + return su.chainDBs.UpdateFinalizedL1(finalized) } -func (su *SupervisorBackend) UpdateFinalizedL1(chainID types.ChainID, finalized eth.BlockRef) error { - su.mu.RLock() - defer su.mu.RUnlock() +// Access to synchronous processing for tests +// ---------------------------- - return su.chainDBs.UpdateFinalizedL1(finalized) +func (su *SupervisorBackend) SyncEvents(chainID types.ChainID) error { + ch, ok := su.chainProcessors.Get(chainID) + if !ok { + return types.ErrUnknownChain + } + ch.ProcessToHead() + return nil +} + +func (su *SupervisorBackend) SyncCrossUnsafe(chainID types.ChainID) error { + ch, ok := su.crossUnsafeProcessors.Get(chainID) + if !ok { + return types.ErrUnknownChain + } + return ch.ProcessWork() +} + +func (su *SupervisorBackend) SyncCrossSafe(chainID types.ChainID) error { + ch, ok := su.crossSafeProcessors.Get(chainID) + if !ok { + return types.ErrUnknownChain + } + return ch.ProcessWork() } diff --git a/op-supervisor/supervisor/backend/backend_test.go b/op-supervisor/supervisor/backend/backend_test.go index 5bdb49caaaf96..c104bf0bae5dc 100644 --- a/op-supervisor/supervisor/backend/backend_test.go +++ b/op-supervisor/supervisor/backend/backend_test.go @@ -21,7 +21,6 @@ import ( "github.com/ethereum-optimism/optimism/op-service/testutils" "github.com/ethereum-optimism/optimism/op-supervisor/config" "github.com/ethereum-optimism/optimism/op-supervisor/metrics" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/entrydb" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -32,24 +31,27 @@ func TestBackendLifetime(t *testing.T) { dataDir := t.TempDir() chainA := types.ChainIDFromUInt64(900) chainB := types.ChainIDFromUInt64(901) - cfg := &config.Config{ - Version: "test", - LogConfig: oplog.CLIConfig{}, - MetricsConfig: opmetrics.CLIConfig{}, - PprofConfig: oppprof.CLIConfig{}, - RPC: oprpc.CLIConfig{}, - DependencySetSource: &depset.StaticConfigDependencySet{ - Dependencies: map[types.ChainID]*depset.StaticConfigDependency{ - chainA: { - ActivationTime: 42, - HistoryMinTime: 100, - }, - chainB: { - ActivationTime: 30, - HistoryMinTime: 20, - }, + depSet, err := depset.NewStaticConfigDependencySet( + map[types.ChainID]*depset.StaticConfigDependency{ + chainA: { + ChainIndex: 900, + ActivationTime: 42, + HistoryMinTime: 100, + }, + chainB: { + ChainIndex: 901, + ActivationTime: 30, + HistoryMinTime: 20, }, - }, + }) + require.NoError(t, err) + cfg := &config.Config{ + Version: "test", + LogConfig: oplog.CLIConfig{}, + MetricsConfig: opmetrics.CLIConfig{}, + PprofConfig: oppprof.CLIConfig{}, + RPC: oprpc.CLIConfig{}, + DependencySetSource: depSet, SynchronousProcessors: true, MockRun: false, L2RPCs: nil, @@ -89,7 +91,7 @@ func TestBackendLifetime(t *testing.T) { t.Log("started!") _, err = b.UnsafeView(context.Background(), chainA, types.ReferenceView{}) - require.ErrorIs(t, err, entrydb.ErrFuture, "no data yet, need local-unsafe") + require.ErrorIs(t, err, types.ErrFuture, "no data yet, need local-unsafe") src.ExpectL1BlockRefByNumber(0, blockX, nil) src.ExpectFetchReceipts(blockX.Hash, &testutils.MockBlockInfo{ @@ -111,14 +113,15 @@ func TestBackendLifetime(t *testing.T) { src.ExpectL1BlockRefByNumber(2, eth.L1BlockRef{}, ethereum.NotFound) - err = b.UpdateLocalUnsafe(chainA, blockY) + err = b.UpdateLocalUnsafe(context.Background(), chainA, blockY) require.NoError(t, err) // Make the processing happen, so we can rely on the new chain information, // and not run into errors for future data that isn't mocked at this time. - b.chainProcessors[chainA].ProcessToHead() + proc, _ := b.chainProcessors.Get(chainA) + proc.ProcessToHead() _, err = b.UnsafeView(context.Background(), chainA, types.ReferenceView{}) - require.ErrorIs(t, err, entrydb.ErrFuture, "still no data yet, need cross-unsafe") + require.ErrorIs(t, err, types.ErrFuture, "still no data yet, need cross-unsafe") err = b.chainDBs.UpdateCrossUnsafe(chainA, types.BlockSeal{ Hash: blockX.Hash, diff --git a/op-supervisor/supervisor/backend/cross/cycle.go b/op-supervisor/supervisor/backend/cross/cycle.go new file mode 100644 index 0000000000000..9884856a34a50 --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/cycle.go @@ -0,0 +1,308 @@ +package cross + +import ( + "errors" + "fmt" + "strings" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" +) + +var ( + ErrCycle = errors.New("cycle detected") + ErrExecMsgHasInvalidIndex = errors.New("executing message has invalid log index") + ErrExecMsgUnknownChain = errors.New("executing message references unknown chain") +) + +// CycleCheckDeps is an interface for checking cyclical dependencies between logs. +type CycleCheckDeps interface { + // OpenBlock returns log data for the requested block, to be used for cycle checking. + OpenBlock(chainID types.ChainID, blockNum uint64) (block eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) +} + +// node represents a log entry in the dependency graph. +// It could be an initiating message, executing message, both, or neither. +// It is uniquely identified by chain index and the log index within its parent block. +type node struct { + chainIndex types.ChainIndex + logIndex uint32 +} + +// graph is a directed graph of message dependencies. +// It is represented as an adjacency list with in-degree counts to be friendly to cycle checking. +type graph struct { + inDegree0 map[node]struct{} + inDegreeNon0 map[node]uint32 + outgoingEdges map[node][]node +} + +// addEdge adds a directed edge from -> to in the graph. +func (g *graph) addEdge(from, to node) { + // Remove the target from inDegree0 if it's there + delete(g.inDegree0, to) + + // Add or increment the target's in-degree count + g.inDegreeNon0[to] += 1 + + // Add the outgoing edge + g.outgoingEdges[from] = append(g.outgoingEdges[from], to) +} + +// HazardCycleChecks checks for cyclical dependencies between logs at the given timestamp. +// Here the timestamp invariant alone does not ensure ordering of messages. +// +// We perform this check in 3 steps: +// - Gather all logs across all hazard blocks at the given timestamp. +// - Build the logs into a directed graph of dependencies between logs. +// - Check the graph for cycles. +// +// The edges of the graph are determined by: +// - For all logs except the first in a block, there is an edge from the previous log. +// - For all executing messages, there is an edge from the initiating message. +// +// The edges between sequential logs ensure the graph is well-connected and free of any +// disjoint subgraphs that would make cycle checking more difficult. +// +// The cycle check is performed by executing Kahn's topological sort algorithm which +// succeeds if and only if a graph is acyclic. +// +// Returns nil if no cycles are found or ErrCycle if a cycle is detected. +func HazardCycleChecks(d CycleCheckDeps, inTimestamp uint64, hazards map[types.ChainIndex]types.BlockSeal) error { + g, err := buildGraph(d, inTimestamp, hazards) + if err != nil { + return err + } + + return checkGraph(g) +} + +// gatherLogs collects all log counts and executing messages across all hazard blocks. +// Returns: +// - map of chain index to its log count +// - map of chain index to map of log index to executing message (nil if doesn't exist or ignored) +func gatherLogs(d CycleCheckDeps, inTimestamp uint64, hazards map[types.ChainIndex]types.BlockSeal) ( + map[types.ChainIndex]uint32, + map[types.ChainIndex]map[uint32]*types.ExecutingMessage, + error, +) { + logCounts := make(map[types.ChainIndex]uint32) + execMsgs := make(map[types.ChainIndex]map[uint32]*types.ExecutingMessage) + + for hazardChainIndex, hazardBlock := range hazards { + // TODO(#11105): translate chain index to chain ID + hazardChainID := types.ChainIDFromUInt64(uint64(hazardChainIndex)) + bl, logCount, msgs, err := d.OpenBlock(hazardChainID, hazardBlock.Number) + if err != nil { + return nil, nil, fmt.Errorf("failed to open block: %w", err) + } + + if !blockSealMatchesRef(hazardBlock, bl) { + return nil, nil, fmt.Errorf("tried to open block %s of chain %s, but got different block %s than expected, use a reorg lock for consistency", hazardBlock, hazardChainID, bl) + } + + // Validate executing message indices + for logIdx := range msgs { + if logIdx >= logCount { + return nil, nil, fmt.Errorf("%w: log index %d >= log count %d", ErrExecMsgHasInvalidIndex, logIdx, logCount) + } + } + + // Store log count and in-timestamp executing messages + logCounts[hazardChainIndex] = logCount + + if len(msgs) > 0 { + if _, exists := execMsgs[hazardChainIndex]; !exists { + execMsgs[hazardChainIndex] = make(map[uint32]*types.ExecutingMessage) + } + } + for logIdx, msg := range msgs { + if msg.Timestamp == inTimestamp { + execMsgs[hazardChainIndex][logIdx] = msg + } + } + } + + return logCounts, execMsgs, nil +} + +// buildGraph constructs a dependency graph from the hazard blocks. +func buildGraph(d CycleCheckDeps, inTimestamp uint64, hazards map[types.ChainIndex]types.BlockSeal) (*graph, error) { + g := &graph{ + inDegree0: make(map[node]struct{}), + inDegreeNon0: make(map[node]uint32), + outgoingEdges: make(map[node][]node), + } + + logCounts, execMsgs, err := gatherLogs(d, inTimestamp, hazards) + if err != nil { + return nil, err + } + + // Add nodes for each log in the block, and add edges between sequential logs + for hazardChainIndex, logCount := range logCounts { + for i := uint32(0); i < logCount; i++ { + k := node{ + chainIndex: hazardChainIndex, + logIndex: i, + } + + if i == 0 { + // First log in block has no dependencies + g.inDegree0[k] = struct{}{} + } else { + // Add edge: prev log <> current log + prevKey := node{ + chainIndex: hazardChainIndex, + logIndex: i - 1, + } + g.addEdge(prevKey, k) + } + } + } + + // Add edges for executing messages to their initiating messages + for hazardChainIndex, msgs := range execMsgs { + for execLogIdx, m := range msgs { + // Error if the chain is unknown + if _, ok := hazards[m.Chain]; !ok { + return nil, ErrExecMsgUnknownChain + } + + // Check if we care about the init message + initChainMsgs, ok := execMsgs[m.Chain] + if !ok { + continue + } + if _, ok := initChainMsgs[m.LogIdx]; !ok { + continue + } + + // Check if the init message exists + if logCount, ok := logCounts[m.Chain]; !ok || m.LogIdx >= logCount { + return nil, fmt.Errorf("%w: initiating message log index out of bounds", types.ErrConflict) + } + + initKey := node{ + chainIndex: m.Chain, + logIndex: m.LogIdx, + } + execKey := node{ + chainIndex: hazardChainIndex, + logIndex: execLogIdx, + } + + // Disallow self-referencing messages + // This should not be possible since the executing message contains the hash of the initiating message. + if initKey == execKey { + return nil, fmt.Errorf("%w: self referencial message", types.ErrConflict) + } + + // Add the edge + g.addEdge(initKey, execKey) + } + } + + return g, nil +} + +// checkGraph uses Kahn's topological sort algorithm to check for cycles in the graph. +// +// Returns: +// - nil for acyclic graphs. +// - ErrCycle for cyclic graphs. +// +// Algorithm: +// 1. for each node with in-degree 0 (i.e. no dependencies), add it to the result, remove it from the work. +// 2. along with removing, remove the outgoing edges +// 3. if there is no node left with in-degree 0, then there is a cycle +func checkGraph(g *graph) error { + for { + // Process all nodes that have no incoming edges + for k := range g.inDegree0 { + // Remove all outgoing edges from this node + for _, out := range g.outgoingEdges[k] { + g.inDegreeNon0[out] -= 1 + if g.inDegreeNon0[out] == 0 { + delete(g.inDegreeNon0, out) + g.inDegree0[out] = struct{}{} + } + } + delete(g.outgoingEdges, k) + delete(g.inDegree0, k) + } + + // If there are new nodes with in-degree 0 then process them + if len(g.inDegree0) > 0 { + continue + } + + // We're done processing so check for remaining nodes + if len(g.inDegreeNon0) == 0 { + // Done, without cycles! + return nil + } + + // Some nodes left; there must be a cycle. + return ErrCycle + } +} + +func blockSealMatchesRef(seal types.BlockSeal, ref eth.BlockRef) bool { + return seal.Number == ref.Number && seal.Hash == ref.Hash +} + +// GenerateMermaidDiagram creates a Mermaid flowchart diagram from the graph data for debugging. +func GenerateMermaidDiagram(g *graph) string { + var sb strings.Builder + + sb.WriteString("flowchart TD\n") + + // Helper function to get a unique ID for each node + getNodeID := func(k node) string { + return fmt.Sprintf("N%d_%d", k.chainIndex, k.logIndex) + } + + // Helper function to get a label for each node + getNodeLabel := func(k node) string { + return fmt.Sprintf("C%d:L%d", k.chainIndex, k.logIndex) + } + + // Function to add a node to the diagram + addNode := func(k node, inDegree uint32) { + nodeID := getNodeID(k) + nodeLabel := getNodeLabel(k) + var shape string + if inDegree == 0 { + shape = "((%s))" + } else { + shape = "[%s]" + } + sb.WriteString(fmt.Sprintf(" %s"+shape+"\n", nodeID, nodeLabel)) + } + + // Add all nodes + for k := range g.inDegree0 { + addNode(k, 0) + } + for k, inDegree := range g.inDegreeNon0 { + addNode(k, inDegree) + } + + // Add all edges + for from, tos := range g.outgoingEdges { + fromID := getNodeID(from) + for _, to := range tos { + toID := getNodeID(to) + sb.WriteString(fmt.Sprintf(" %s --> %s\n", fromID, toID)) + } + } + + // Add a legend + sb.WriteString(" subgraph Legend\n") + sb.WriteString(" L1((In-Degree 0))\n") + sb.WriteString(" L2[In-Degree > 0]\n") + sb.WriteString(" end\n") + + return sb.String() +} diff --git a/op-supervisor/supervisor/backend/cross/cycle_test.go b/op-supervisor/supervisor/backend/cross/cycle_test.go new file mode 100644 index 0000000000000..e160023caf818 --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/cycle_test.go @@ -0,0 +1,557 @@ +package cross + +import ( + "errors" + "fmt" + "strconv" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" +) + +type mockCycleCheckDeps struct { + openBlockFn func(chainID types.ChainID, blockNum uint64) (eth.BlockRef, uint32, map[uint32]*types.ExecutingMessage, error) +} + +func (m *mockCycleCheckDeps) OpenBlock(chainID types.ChainID, blockNum uint64) (eth.BlockRef, uint32, map[uint32]*types.ExecutingMessage, error) { + return m.openBlockFn(chainID, blockNum) +} + +type chainBlockDef struct { + logCount uint32 + messages map[uint32]*types.ExecutingMessage + error error +} + +type hazardCycleChecksTestCase struct { + name string + chainBlocks map[string]chainBlockDef + expectErr error + msg string + + // Optional overrides + hazards map[types.ChainIndex]types.BlockSeal + openBlockFn func(chainID types.ChainID, blockNum uint64) (eth.BlockRef, uint32, map[uint32]*types.ExecutingMessage, error) +} + +func runHazardCycleChecksTestCaseGroup(t *testing.T, group string, tests []hazardCycleChecksTestCase) { + for _, tc := range tests { + t.Run(group+"/"+tc.name, func(t *testing.T) { + runHazardCycleChecksTestCase(t, tc) + }) + } +} + +func runHazardCycleChecksTestCase(t *testing.T, tc hazardCycleChecksTestCase) { + // Create mocked dependencies + deps := &mockCycleCheckDeps{ + openBlockFn: func(chainID types.ChainID, blockNum uint64) (eth.BlockRef, uint32, map[uint32]*types.ExecutingMessage, error) { + // Use override if provided + if tc.openBlockFn != nil { + return tc.openBlockFn(chainID, blockNum) + } + + // Default behavior + chainStr := chainID.String() + def, ok := tc.chainBlocks[chainStr] + if !ok { + return eth.BlockRef{}, 0, nil, errors.New("unexpected chain") + } + if def.error != nil { + return eth.BlockRef{}, 0, nil, def.error + } + return eth.BlockRef{Number: blockNum}, def.logCount, def.messages, nil + }, + } + + // Generate hazards map automatically if not explicitly provided + var hazards map[types.ChainIndex]types.BlockSeal + if tc.hazards != nil { + hazards = tc.hazards + } else { + hazards = make(map[types.ChainIndex]types.BlockSeal) + for chainStr := range tc.chainBlocks { + hazards[chainIndex(chainStr)] = types.BlockSeal{Number: 1} + } + } + + // Run the test + err := HazardCycleChecks(deps, 100, hazards) + + // No error expected + if tc.expectErr == nil { + require.NoError(t, err, tc.msg) + return + } + + // Error expected, make sure it's the right one + require.Error(t, err, tc.msg) + if errors.Is(err, tc.expectErr) { + require.ErrorIs(t, err, tc.expectErr, tc.msg) + } else { + require.Contains(t, err.Error(), tc.expectErr.Error(), tc.msg) + } +} + +func chainIndex(s string) types.ChainIndex { + id, err := strconv.ParseUint(s, 10, 32) + if err != nil { + panic(fmt.Sprintf("invalid chain index in test: %v", err)) + } + return types.ChainIndex(id) +} + +func execMsg(chain string, logIdx uint32) *types.ExecutingMessage { + return execMsgWithTimestamp(chain, logIdx, 100) +} + +func execMsgWithTimestamp(chain string, logIdx uint32, timestamp uint64) *types.ExecutingMessage { + return &types.ExecutingMessage{ + Chain: chainIndex(chain), + LogIdx: logIdx, + Timestamp: timestamp, + } +} + +var emptyChainBlocks = map[string]chainBlockDef{ + "1": { + logCount: 0, + messages: map[uint32]*types.ExecutingMessage{}, + }, +} + +func TestHazardCycleChecksFailures(t *testing.T) { + testOpenBlockErr := errors.New("test OpenBlock error") + tests := []hazardCycleChecksTestCase{ + { + name: "empty hazards", + chainBlocks: emptyChainBlocks, + hazards: make(map[types.ChainIndex]types.BlockSeal), + expectErr: nil, + msg: "expected no error when there are no hazards", + }, + { + name: "nil hazards", + chainBlocks: emptyChainBlocks, + hazards: nil, + expectErr: nil, + msg: "expected no error when there are nil hazards", + }, + { + name: "nil blocks", + chainBlocks: nil, + hazards: nil, + expectErr: nil, + msg: "expected no error when there are nil blocks and hazards", + }, + { + name: "failed to open block error", + chainBlocks: emptyChainBlocks, + openBlockFn: func(chainID types.ChainID, blockNum uint64) (eth.BlockRef, uint32, map[uint32]*types.ExecutingMessage, error) { + return eth.BlockRef{}, 0, nil, testOpenBlockErr + }, + expectErr: errors.New("failed to open block"), + msg: "expected error when OpenBlock fails", + }, + { + name: "block mismatch error", + chainBlocks: emptyChainBlocks, + // openBlockFn returns a block number that doesn't match the expected block number. + openBlockFn: func(chainID types.ChainID, blockNum uint64) (eth.BlockRef, uint32, map[uint32]*types.ExecutingMessage, error) { + return eth.BlockRef{Number: blockNum + 1}, 0, make(map[uint32]*types.ExecutingMessage), nil + }, + expectErr: errors.New("tried to open block"), + msg: "expected error due to block mismatch", + }, + { + name: "invalid log index error", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 3, + messages: map[uint32]*types.ExecutingMessage{ + 5: execMsg("1", 0), // Invalid index >= logCount. + }, + }, + }, + expectErr: ErrExecMsgHasInvalidIndex, + msg: "expected invalid log index error", + }, + { + name: "self reference detected error", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 1, + messages: map[uint32]*types.ExecutingMessage{ + 0: execMsg("1", 0), // Points at itself. + }, + }, + }, + expectErr: types.ErrConflict, + msg: "expected self reference detection error", + }, + { + name: "unknown chain", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{ + 1: execMsg("2", 0), // References chain 2 which isn't in hazards. + }, + }, + }, + hazards: map[types.ChainIndex]types.BlockSeal{ + 1: {Number: 1}, // Only include chain 1. + }, + expectErr: ErrExecMsgUnknownChain, + msg: "expected unknown chain error", + }, + } + runHazardCycleChecksTestCaseGroup(t, "Failure", tests) +} + +func TestHazardCycleChecksNoCycle(t *testing.T) { + tests := []hazardCycleChecksTestCase{ + { + name: "no logs", + chainBlocks: emptyChainBlocks, + expectErr: nil, + msg: "expected no cycle found for block with no logs", + }, + { + name: "one basic log", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 1, + messages: map[uint32]*types.ExecutingMessage{}, + }, + }, + msg: "expected no cycle found for single basic log", + }, + { + name: "one exec log", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{ + 1: execMsg("1", 0), + }, + }, + }, + msg: "expected no cycle found for single exec log", + }, + { + name: "two basic logs", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{}, + }, + }, + msg: "expected no cycle found for two basic logs", + }, + { + name: "two exec logs to same target", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 3, + messages: map[uint32]*types.ExecutingMessage{ + 1: execMsg("1", 0), + 2: execMsg("1", 0), + }, + }, + }, + msg: "expected no cycle found for two exec logs pointing at the same log", + }, + { + name: "two exec logs to different targets", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 3, + messages: map[uint32]*types.ExecutingMessage{ + 1: execMsg("1", 0), + 2: execMsg("1", 1), + }, + }, + }, + msg: "expected no cycle found for two exec logs pointing at the different logs", + }, + { + name: "one basic log one exec log", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{ + 1: execMsg("1", 0), + }, + }, + }, + msg: "expected no cycle found for one basic and one exec log", + }, + { + name: "first log is exec", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 1, + messages: map[uint32]*types.ExecutingMessage{ + 0: execMsg("2", 0), + }, + }, + "2": { + logCount: 1, + messages: nil, + }, + }, + msg: "expected no cycle found first log is exec", + }, + { + name: "cycle through older timestamp", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{ + 0: execMsg("2", 0), + 1: execMsgWithTimestamp("2", 1, 101), + }, + }, + "2": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{ + 0: execMsg("1", 1), + }, + }, + }, + msg: "expected no cycle detection error for cycle through messages with different timestamps", + }, + // This should be caught by earlier validations, but included for completeness. + { + name: "cycle through younger timestamp", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{ + 0: execMsg("2", 0), + 1: execMsgWithTimestamp("2", 1, 99), + }, + }, + "2": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{ + 0: execMsg("1", 1), + }, + }, + }, + msg: "expected no cycle detection error for cycle through messages with different timestamps", + }, + } + runHazardCycleChecksTestCaseGroup(t, "NoCycle", tests) +} + +func TestHazardCycleChecksCycle(t *testing.T) { + tests := []hazardCycleChecksTestCase{ + { + name: "2-cycle in single chain with first log", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 3, + messages: map[uint32]*types.ExecutingMessage{ + 0: execMsg("1", 2), + 2: execMsg("1", 0), + }, + }, + }, + expectErr: ErrCycle, + msg: "expected cycle detection error", + }, + { + name: "2-cycle in single chain with first log, adjacent", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{ + 0: execMsg("1", 1), + 1: execMsg("1", 0), + }, + }, + }, + expectErr: ErrCycle, + msg: "expected cycle detection error", + }, + { + name: "2-cycle in single chain, not first, adjacent", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 3, + messages: map[uint32]*types.ExecutingMessage{ + 1: execMsg("1", 2), + 2: execMsg("1", 1), + }, + }, + }, + expectErr: ErrCycle, + msg: "expected cycle detection error", + }, + { + name: "2-cycle in single chain, not first, not adjacent", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 4, + messages: map[uint32]*types.ExecutingMessage{ + 1: execMsg("1", 3), + 3: execMsg("1", 1), + }, + }, + }, + expectErr: ErrCycle, + msg: "expected cycle detection error", + }, + { + name: "2-cycle across chains", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{ + 1: execMsg("2", 0), + }, + }, + "2": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{ + 0: execMsg("1", 1), + }, + }, + }, + expectErr: ErrCycle, + msg: "expected cycle detection error for cycle through executing messages", + }, + { + name: "3-cycle in single chain", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 4, + messages: map[uint32]*types.ExecutingMessage{ + 1: execMsg("1", 2), // Points to log 2 + 2: execMsg("1", 3), // Points to log 3 + 3: execMsg("1", 1), // Points back to log 1 + }, + }, + }, + expectErr: ErrCycle, + msg: "expected cycle detection error for 3-node cycle", + }, + { + name: "cycle through adjacency dependency", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 10, + messages: map[uint32]*types.ExecutingMessage{ + 1: execMsg("1", 5), // Points to log 5 + 5: execMsg("1", 2), // Points back to log 2 which is adjacent to log 1 + }, + }, + }, + expectErr: ErrCycle, + msg: "expected cycle detection error for when cycle goes through adjacency dependency", + }, + { + name: "2-cycle across chains with 3 hazard chains", + chainBlocks: map[string]chainBlockDef{ + "1": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{ + 1: execMsg("2", 1), + }, + }, + "2": { + logCount: 2, + messages: map[uint32]*types.ExecutingMessage{ + 1: execMsg("1", 1), + }, + }, + "3": {}, + }, + expectErr: ErrCycle, + hazards: map[types.ChainIndex]types.BlockSeal{ + 1: {Number: 1}, + 2: {Number: 1}, + 3: {Number: 1}, + }, + msg: "expected cycle detection error for cycle through executing messages", + }, + } + runHazardCycleChecksTestCaseGroup(t, "Cycle", tests) +} + +const ( + largeGraphChains = 10 + largeGraphLogsPerChain = 10000 +) + +func TestHazardCycleChecksLargeGraphNoCycle(t *testing.T) { + // Create a large but acyclic graph + chainBlocks := make(map[string]chainBlockDef) + for i := 1; i <= largeGraphChains; i++ { + msgs := make(map[uint32]*types.ExecutingMessage) + // Create a chain of dependencies across chains + if i > 1 { + for j := uint32(0); j < largeGraphLogsPerChain; j++ { + // Point to previous chain, same log index + msgs[j] = execMsg(strconv.Itoa(i-1), j) + } + } + chainBlocks[strconv.Itoa(i)] = chainBlockDef{ + logCount: largeGraphLogsPerChain, + messages: msgs, + } + } + + tc := hazardCycleChecksTestCase{ + name: "Large graph without cycles", + chainBlocks: chainBlocks, + expectErr: nil, + msg: "expected no cycle in large acyclic graph", + } + runHazardCycleChecksTestCase(t, tc) +} + +func TestHazardCycleChecksLargeGraphCycle(t *testing.T) { + // Create a large graph with a cycle hidden in it + const cycleChain = 3 + const cycleLogIndex = 5678 + + chainBlocks := make(map[string]chainBlockDef) + for i := 1; i <= largeGraphChains; i++ { + msgs := make(map[uint32]*types.ExecutingMessage) + + // Create a chain of dependencies across chains + if i > 1 { + for j := uint32(0); j < largeGraphLogsPerChain; j++ { + if i == cycleChain && j == cycleLogIndex { + // Create a cycle by pointing back to chain 1 + msgs[j] = execMsg("1", cycleLogIndex+1) + } else { + // Normal case: point to previous chain, same log index + msgs[j] = execMsg(strconv.Itoa(i-1), j) + } + } + } else { + // In chain 1, create the other side of the cycle + msgs[cycleLogIndex+1] = execMsg(strconv.Itoa(cycleChain), cycleLogIndex) + } + + chainBlocks[strconv.Itoa(i)] = chainBlockDef{ + logCount: largeGraphLogsPerChain, + messages: msgs, + } + } + + tc := hazardCycleChecksTestCase{ + name: "Large graph with cycle", + chainBlocks: chainBlocks, + expectErr: ErrCycle, + msg: "expected to detect cycle in large cyclic graph", + } + runHazardCycleChecksTestCase(t, tc) +} diff --git a/op-supervisor/supervisor/backend/cross/safe_frontier.go b/op-supervisor/supervisor/backend/cross/safe_frontier.go new file mode 100644 index 0000000000000..31b48843fd9a6 --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/safe_frontier.go @@ -0,0 +1,59 @@ +package cross + +import ( + "errors" + "fmt" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" +) + +type SafeFrontierCheckDeps interface { + CandidateCrossSafe(chain types.ChainID) (derivedFromScope, crossSafe eth.BlockRef, err error) + + CrossDerivedFrom(chainID types.ChainID, derived eth.BlockID) (derivedFrom types.BlockSeal, err error) + + DependencySet() depset.DependencySet +} + +// HazardSafeFrontierChecks verifies all the hazard blocks are either: +// - already cross-safe. +// - the first (if not first: local blocks to verify before proceeding) +// local-safe block, after the cross-safe block. +func HazardSafeFrontierChecks(d SafeFrontierCheckDeps, inL1DerivedFrom eth.BlockID, hazards map[types.ChainIndex]types.BlockSeal) error { + depSet := d.DependencySet() + for hazardChainIndex, hazardBlock := range hazards { + hazardChainID, err := depSet.ChainIDFromIndex(hazardChainIndex) + if err != nil { + if errors.Is(err, types.ErrUnknownChain) { + err = fmt.Errorf("cannot cross-safe verify block %s of unknown chain index %s: %w", hazardBlock, hazardChainIndex, types.ErrConflict) + } + return err + } + initDerivedFrom, err := d.CrossDerivedFrom(hazardChainID, hazardBlock.ID()) + if err != nil { + if errors.Is(err, types.ErrFuture) { + // If not in cross-safe scope, then check if it's the candidate cross-safe block. + initDerivedFrom, initSelf, err := d.CandidateCrossSafe(hazardChainID) + if err != nil { + return fmt.Errorf("failed to determine cross-safe candidate block of hazard dependency %s (chain %s): %w", hazardBlock, hazardChainID, err) + } + if initSelf.Number == hazardBlock.Number && initSelf.ID() != hazardBlock.ID() { + return fmt.Errorf("expected block %s (chain %d) does not match candidate local-safe block %s: %w", + hazardBlock, hazardChainID, initSelf, types.ErrConflict) + } + if initDerivedFrom.Number > inL1DerivedFrom.Number { + return fmt.Errorf("local-safe hazard block %s derived from L1 block %s is after scope %s: %w", + hazardBlock.ID(), initDerivedFrom, inL1DerivedFrom, types.ErrOutOfScope) + } + } else { + return fmt.Errorf("failed to determine cross-derived of hazard block %s (chain %s): %w", hazardBlock, hazardChainID, err) + } + } else if initDerivedFrom.Number > inL1DerivedFrom.Number { + return fmt.Errorf("cross-safe hazard block %s derived from L1 block %s is after scope %s: %w", + hazardBlock.ID(), initDerivedFrom, inL1DerivedFrom, types.ErrOutOfScope) + } + } + return nil +} diff --git a/op-supervisor/supervisor/backend/cross/safe_frontier_test.go b/op-supervisor/supervisor/backend/cross/safe_frontier_test.go new file mode 100644 index 0000000000000..6848acf841cd8 --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/safe_frontier_test.go @@ -0,0 +1,201 @@ +package cross + +import ( + "errors" + "testing" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestHazardSafeFrontierChecks(t *testing.T) { + t.Run("empty hazards", func(t *testing.T) { + sfcd := &mockSafeFrontierCheckDeps{} + l1DerivedFrom := eth.BlockID{} + hazards := map[types.ChainIndex]types.BlockSeal{} + // when there are no hazards, + // no work is done, and no error is returned + err := HazardSafeFrontierChecks(sfcd, l1DerivedFrom, hazards) + require.NoError(t, err) + }) + t.Run("unknown chain", func(t *testing.T) { + sfcd := &mockSafeFrontierCheckDeps{ + deps: mockDependencySet{ + chainIDFromIndexfn: func() (types.ChainID, error) { + return types.ChainID{}, types.ErrUnknownChain + }, + }, + } + l1DerivedFrom := eth.BlockID{} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {}} + // when there is one hazard, and ChainIDFromIndex returns ErrUnknownChain, + // an error is returned as a ErrConflict + err := HazardSafeFrontierChecks(sfcd, l1DerivedFrom, hazards) + require.ErrorIs(t, err, types.ErrConflict) + }) + t.Run("initDerivedFrom in scope", func(t *testing.T) { + sfcd := &mockSafeFrontierCheckDeps{} + sfcd.crossDerivedFromFn = func() (types.BlockSeal, error) { + return types.BlockSeal{Number: 1}, nil + } + l1DerivedFrom := eth.BlockID{Number: 2} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {}} + // when there is one hazard, and CrossDerivedFrom returns a BlockSeal within scope + // (ie the hazard's block number is less than or equal to the derivedFrom block number), + // no error is returned + err := HazardSafeFrontierChecks(sfcd, l1DerivedFrom, hazards) + require.NoError(t, err) + }) + t.Run("initDerivedFrom out of scope", func(t *testing.T) { + sfcd := &mockSafeFrontierCheckDeps{} + sfcd.crossDerivedFromFn = func() (types.BlockSeal, error) { + return types.BlockSeal{Number: 3}, nil + } + l1DerivedFrom := eth.BlockID{Number: 2} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {}} + // when there is one hazard, and CrossDerivedFrom returns a BlockSeal out of scope + // (ie the hazard's block number is greater than the derivedFrom block number), + // an error is returned as a ErrOutOfScope + err := HazardSafeFrontierChecks(sfcd, l1DerivedFrom, hazards) + require.ErrorIs(t, err, types.ErrOutOfScope) + }) + t.Run("errFuture: candidate cross safe failure", func(t *testing.T) { + sfcd := &mockSafeFrontierCheckDeps{} + sfcd.crossDerivedFromFn = func() (types.BlockSeal, error) { + return types.BlockSeal{Number: 3}, types.ErrFuture + } + sfcd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return eth.BlockRef{}, + eth.BlockRef{Number: 3, Hash: common.BytesToHash([]byte{0x01})}, + errors.New("some error") + } + l1DerivedFrom := eth.BlockID{} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {}} + // when there is one hazard, and CrossDerivedFrom returns an ErrFuture, + // and CandidateCrossSafe returns an error, + // the error from CandidateCrossSafe is returned + err := HazardSafeFrontierChecks(sfcd, l1DerivedFrom, hazards) + require.ErrorContains(t, err, "some error") + }) + t.Run("errFuture: expected block does not match candidate", func(t *testing.T) { + sfcd := &mockSafeFrontierCheckDeps{} + sfcd.crossDerivedFromFn = func() (types.BlockSeal, error) { + return types.BlockSeal{}, types.ErrFuture + } + sfcd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return eth.BlockRef{}, + eth.BlockRef{Number: 3, Hash: common.BytesToHash([]byte{0x01})}, + nil + } + l1DerivedFrom := eth.BlockID{} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {Number: 3, Hash: common.BytesToHash([]byte{0x02})}} + // when there is one hazard, and CrossDerivedFrom returns an ErrFuture, + // and CandidateCrossSafe returns a candidate that does not match the hazard, + // (ie the candidate's block number is the same as the hazard's block number, but the hashes are different), + // an error is returned as a ErrConflict + err := HazardSafeFrontierChecks(sfcd, l1DerivedFrom, hazards) + require.ErrorIs(t, err, types.ErrConflict) + }) + t.Run("errFuture: local-safe hazard out of scope", func(t *testing.T) { + sfcd := &mockSafeFrontierCheckDeps{} + sfcd.crossDerivedFromFn = func() (types.BlockSeal, error) { + return types.BlockSeal{}, types.ErrFuture + } + sfcd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return eth.BlockRef{Number: 9}, + eth.BlockRef{}, + nil + } + l1DerivedFrom := eth.BlockID{Number: 8} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {Number: 3, Hash: common.BytesToHash([]byte{0x02})}} + // when there is one hazard, and CrossDerivedFrom returns an ErrFuture, + // and the initDerivedFrom is out of scope, + // an error is returned as a ErrOutOfScope + err := HazardSafeFrontierChecks(sfcd, l1DerivedFrom, hazards) + require.ErrorIs(t, err, types.ErrOutOfScope) + }) + t.Run("CrossDerivedFrom Error", func(t *testing.T) { + sfcd := &mockSafeFrontierCheckDeps{} + sfcd.crossDerivedFromFn = func() (types.BlockSeal, error) { + return types.BlockSeal{}, errors.New("some error") + } + sfcd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return eth.BlockRef{Number: 9}, + eth.BlockRef{}, + nil + } + l1DerivedFrom := eth.BlockID{Number: 8} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {Number: 3, Hash: common.BytesToHash([]byte{0x02})}} + // when there is one hazard, and CrossDerivedFrom returns an ErrFuture, + // and the initDerivedFrom is out of scope, + // an error is returned as a ErrOutOfScope + err := HazardSafeFrontierChecks(sfcd, l1DerivedFrom, hazards) + require.ErrorContains(t, err, "some error") + }) +} + +type mockSafeFrontierCheckDeps struct { + deps mockDependencySet + candidateCrossSafeFn func() (derivedFromScope, crossSafe eth.BlockRef, err error) + crossDerivedFromFn func() (derivedFrom types.BlockSeal, err error) +} + +func (m *mockSafeFrontierCheckDeps) CandidateCrossSafe(chain types.ChainID) (derivedFromScope, crossSafe eth.BlockRef, err error) { + if m.candidateCrossSafeFn != nil { + return m.candidateCrossSafeFn() + } + return eth.BlockRef{}, eth.BlockRef{}, nil +} + +func (m *mockSafeFrontierCheckDeps) CrossDerivedFrom(chainID types.ChainID, derived eth.BlockID) (derivedFrom types.BlockSeal, err error) { + if m.crossDerivedFromFn != nil { + return m.crossDerivedFromFn() + } + return types.BlockSeal{}, nil +} + +func (m *mockSafeFrontierCheckDeps) DependencySet() depset.DependencySet { + return m.deps +} + +type mockDependencySet struct { + chainIDFromIndexfn func() (types.ChainID, error) + canExecuteAtfn func() (bool, error) + canInitiateAtfn func() (bool, error) +} + +func (m mockDependencySet) CanExecuteAt(chain types.ChainID, timestamp uint64) (bool, error) { + if m.canExecuteAtfn != nil { + return m.canExecuteAtfn() + } + return true, nil +} + +func (m mockDependencySet) CanInitiateAt(chain types.ChainID, timestamp uint64) (bool, error) { + if m.canInitiateAtfn != nil { + return m.canInitiateAtfn() + } + return true, nil +} + +func (m mockDependencySet) ChainIDFromIndex(index types.ChainIndex) (types.ChainID, error) { + if m.chainIDFromIndexfn != nil { + return m.chainIDFromIndexfn() + } + return types.ChainID{}, nil +} + +func (m mockDependencySet) ChainIndexFromID(chain types.ChainID) (types.ChainIndex, error) { + return types.ChainIndex(0), nil +} + +func (m mockDependencySet) Chains() []types.ChainID { + return nil +} + +func (m mockDependencySet) HasChain(chain types.ChainID) bool { + return true +} diff --git a/op-supervisor/supervisor/backend/cross/safe_start.go b/op-supervisor/supervisor/backend/cross/safe_start.go new file mode 100644 index 0000000000000..acd97304ed148 --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/safe_start.go @@ -0,0 +1,104 @@ +package cross + +import ( + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/common" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" +) + +type SafeStartDeps interface { + Check(chain types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (includedIn types.BlockSeal, err error) + + CrossDerivedFrom(chainID types.ChainID, derived eth.BlockID) (derivedFrom types.BlockSeal, err error) + + DependencySet() depset.DependencySet +} + +// CrossSafeHazards checks if the given messages all exist and pass invariants. +// It returns a hazard-set: if any intra-block messaging happened, +// these hazard blocks have to be verified. +func CrossSafeHazards(d SafeStartDeps, chainID types.ChainID, inL1DerivedFrom eth.BlockID, + candidate types.BlockSeal, execMsgs []*types.ExecutingMessage) (hazards map[types.ChainIndex]types.BlockSeal, err error) { + + hazards = make(map[types.ChainIndex]types.BlockSeal) + + // Warning for future: If we have sub-second distinct blocks (different block number), + // we need to increase precision on the above timestamp invariant. + // Otherwise a local block can depend on a future local block of the same chain, + // simply by pulling in a block of another chain, + // which then depends on a block of the original chain, + // all with the same timestamp, without message cycles. + + depSet := d.DependencySet() + + if len(execMsgs) > 0 { + if ok, err := depSet.CanExecuteAt(chainID, candidate.Timestamp); err != nil { + return nil, fmt.Errorf("cannot check message execution of block %s (chain %s): %w", candidate, chainID, err) + } else if !ok { + return nil, fmt.Errorf("cannot execute messages in block %s (chain %s): %w", candidate, chainID, types.ErrConflict) + } + } + + // check all executing messages + for _, msg := range execMsgs { + initChainID, err := depSet.ChainIDFromIndex(msg.Chain) + if err != nil { + if errors.Is(err, types.ErrUnknownChain) { + err = fmt.Errorf("msg %s may not execute from unknown chain %s: %w", msg, msg.Chain, types.ErrConflict) + } + return nil, err + } + if ok, err := depSet.CanInitiateAt(initChainID, msg.Timestamp); err != nil { + return nil, fmt.Errorf("cannot check message initiation of msg %s (chain %s): %w", msg, chainID, err) + } else if !ok { + return nil, fmt.Errorf("cannot allow initiating message %s (chain %s): %w", msg, chainID, types.ErrConflict) + } + if msg.Timestamp < candidate.Timestamp { + // If timestamp is older: invariant ensures non-cyclic ordering relative to other messages. + // Check that the block that they are included in is cross-safe already. + includedIn, err := d.Check(initChainID, msg.BlockNum, msg.LogIdx, msg.Hash) + if err != nil { + return nil, fmt.Errorf("executing msg %s failed check: %w", msg, err) + } + initDerivedFrom, err := d.CrossDerivedFrom(initChainID, includedIn.ID()) + if err != nil { + return nil, fmt.Errorf("msg %s included in non-cross-safe block %s: %w", msg, includedIn, err) + } + if initDerivedFrom.Number > inL1DerivedFrom.Number { + return nil, fmt.Errorf("msg %s was included in block %s derived from %s which is not in cross-safe scope %s: %w", + msg, includedIn, initDerivedFrom, inL1DerivedFrom, types.ErrOutOfScope) + } + } else if msg.Timestamp == candidate.Timestamp { + // If timestamp is equal: we have to inspect ordering of individual + // log events to ensure non-cyclic cross-chain message ordering. + // And since we may have back-and-forth messaging, we cannot wait till the initiating side is cross-safe. + // Thus check that it was included in a local-safe block, + // and then proceed with transitive block checks, + // to ensure the local block we depend on is becoming cross-safe also. + includedIn, err := d.Check(initChainID, msg.BlockNum, msg.LogIdx, msg.Hash) + if err != nil { + return nil, fmt.Errorf("executing msg %s failed check: %w", msg, err) + } + // As a hazard block, it will be checked to be included in a cross-safe block, + // or right after a cross-safe block in a local-safe block, in HazardSafeFrontierChecks. + if existing, ok := hazards[msg.Chain]; ok { + if existing != includedIn { + return nil, fmt.Errorf("found dependency on %s (chain %d), but already depend on %s", includedIn, initChainID, chainID) + } + } else { + // Mark it as hazard block + hazards[msg.Chain] = includedIn + } + } else { + // Timestamp invariant is broken: executing message tries to execute future block. + // The predeploy inbox contract should not have allowed this executing message through. + return nil, fmt.Errorf("executing message %s in %s breaks timestamp invariant", msg, candidate) + } + } + return hazards, nil +} diff --git a/op-supervisor/supervisor/backend/cross/safe_start_test.go b/op-supervisor/supervisor/backend/cross/safe_start_test.go new file mode 100644 index 0000000000000..1a5924e06963f --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/safe_start_test.go @@ -0,0 +1,341 @@ +package cross + +import ( + "errors" + "testing" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestCrossSafeHazards(t *testing.T) { + t.Run("empty execMsgs", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{} + // when there are no execMsgs, + // no work is done, and no error is returned + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.NoError(t, err) + require.Empty(t, hazards) + }) + t.Run("CanExecuteAt returns false", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + ssd.deps = mockDependencySet{ + canExecuteAtfn: func() (bool, error) { + return false, nil + }, + } + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{{}} + // when there is one execMsg, and CanExecuteAt returns false, + // no work is done and an error is returned + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.ErrorIs(t, err, types.ErrConflict) + require.Empty(t, hazards) + }) + t.Run("CanExecuteAt returns error", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + ssd.deps = mockDependencySet{ + canExecuteAtfn: func() (bool, error) { + return false, errors.New("some error") + }, + } + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{{}} + // when there is one execMsg, and CanExecuteAt returns false, + // no work is done and an error is returned + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.ErrorContains(t, err, "some error") + require.Empty(t, hazards) + }) + t.Run("unknown chain", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + ssd.deps = mockDependencySet{ + chainIDFromIndexfn: func() (types.ChainID, error) { + return types.ChainID{}, types.ErrUnknownChain + }, + } + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{{}} + // when there is one execMsg, and ChainIDFromIndex returns ErrUnknownChain, + // an error is returned as a ErrConflict + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.ErrorIs(t, err, types.ErrConflict) + require.Empty(t, hazards) + }) + t.Run("ChainIDFromUInt64 returns error", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + ssd.deps = mockDependencySet{ + chainIDFromIndexfn: func() (types.ChainID, error) { + return types.ChainID{}, errors.New("some error") + }, + } + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{{}} + // when there is one execMsg, and ChainIDFromIndex returns some other error, + // the error is returned + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.ErrorContains(t, err, "some error") + require.Empty(t, hazards) + }) + t.Run("CanInitiateAt returns false", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + ssd.deps = mockDependencySet{ + canInitiateAtfn: func() (bool, error) { + return false, nil + }, + } + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{{}} + // when there is one execMsg, and CanInitiateAt returns false, + // the error is returned as a ErrConflict + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.ErrorIs(t, err, types.ErrConflict) + require.Empty(t, hazards) + }) + t.Run("CanInitiateAt returns error", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + ssd.deps = mockDependencySet{ + canInitiateAtfn: func() (bool, error) { + return false, errors.New("some error") + }, + } + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{{}} + // when there is one execMsg, and CanInitiateAt returns an error, + // the error is returned + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.ErrorContains(t, err, "some error") + require.Empty(t, hazards) + }) + t.Run("timestamp is greater than candidate", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + ssd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 10} + execMsgs := []*types.ExecutingMessage{em1} + // when there is one execMsg, and the timestamp is greater than the candidate, + // an error is returned + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.ErrorContains(t, err, "breaks timestamp invariant") + require.Empty(t, hazards) + }) + t.Run("timestamp is equal, Check returns error", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + ssd.checkFn = func() (includedIn types.BlockSeal, err error) { + return types.BlockSeal{}, errors.New("some error") + } + ssd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 2} + execMsgs := []*types.ExecutingMessage{em1} + // when there is one execMsg, and the timetamp is equal to the candidate, + // and check returns an error, + // that error is returned + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.ErrorContains(t, err, "some error") + require.Empty(t, hazards) + }) + t.Run("timestamp is equal, same hazard twice", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + sampleBlockSeal := types.BlockSeal{Number: 3, Hash: common.BytesToHash([]byte{0x02})} + ssd.checkFn = func() (includedIn types.BlockSeal, err error) { + return sampleBlockSeal, nil + } + ssd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 2} + em2 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 2} + execMsgs := []*types.ExecutingMessage{em1, em2} + // when there are two execMsgs, and both are equal time to the candidate, + // and check returns the same includedIn for both + // they load the hazards once, and return no error + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.NoError(t, err) + require.Equal(t, hazards, map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): sampleBlockSeal}) + }) + t.Run("timestamp is equal, different hazards", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + // set the check function to return a different BlockSeal for the second call + sampleBlockSeal := types.BlockSeal{Number: 3, Hash: common.BytesToHash([]byte{0x02})} + sampleBlockSeal2 := types.BlockSeal{Number: 333, Hash: common.BytesToHash([]byte{0x22})} + calls := 0 + ssd.checkFn = func() (includedIn types.BlockSeal, err error) { + defer func() { calls++ }() + if calls == 0 { + return sampleBlockSeal, nil + } + return sampleBlockSeal2, nil + } + ssd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 2} + em2 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 2} + execMsgs := []*types.ExecutingMessage{em1, em2} + // when there are two execMsgs, and both are equal time to the candidate, + // and check returns different includedIn for the two, + // an error is returned + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.ErrorContains(t, err, "but already depend on") + require.Empty(t, hazards) + }) + t.Run("timestamp is less, check returns error", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + ssd.checkFn = func() (includedIn types.BlockSeal, err error) { + return types.BlockSeal{}, errors.New("some error") + } + ssd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 1} + execMsgs := []*types.ExecutingMessage{em1} + // when there is one execMsg, and the timestamp is less than the candidate, + // and check returns an error, + // that error is returned + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.ErrorContains(t, err, "some error") + require.Empty(t, hazards) + }) + t.Run("timestamp is less, CrossDerivedFrom returns error", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + sampleBlockSeal := types.BlockSeal{Number: 3, Hash: common.BytesToHash([]byte{0x02})} + ssd.checkFn = func() (includedIn types.BlockSeal, err error) { + return sampleBlockSeal, nil + } + ssd.derivedFromFn = func() (derivedFrom types.BlockSeal, err error) { + return types.BlockSeal{}, errors.New("some error") + } + ssd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 1} + execMsgs := []*types.ExecutingMessage{em1} + // when there is one execMsg, and the timestamp is less than the candidate, + // and CrossDerivedFrom returns aan error, + // that error is returned + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.ErrorContains(t, err, "some error") + require.Empty(t, hazards) + }) + t.Run("timestamp is less, CrossDerivedFrom Number is greater", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + sampleBlockSeal := types.BlockSeal{Number: 3, Hash: common.BytesToHash([]byte{0x02})} + ssd.checkFn = func() (includedIn types.BlockSeal, err error) { + return sampleBlockSeal, nil + } + sampleDerivedFrom := types.BlockSeal{Number: 4, Hash: common.BytesToHash([]byte{0x03})} + ssd.derivedFromFn = func() (derivedFrom types.BlockSeal, err error) { + return sampleDerivedFrom, nil + } + ssd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{} + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 1} + execMsgs := []*types.ExecutingMessage{em1} + // when there is one execMsg, and the timestamp is less than the candidate, + // and CrossDerivedFrom returns a BlockSeal with a greater Number than the inL1DerivedFrom, + // an error is returned as a ErrOutOfScope + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.ErrorIs(t, err, types.ErrOutOfScope) + require.Empty(t, hazards) + }) + t.Run("timestamp is less, CrossDerivedFrom Number less", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + sampleBlockSeal := types.BlockSeal{Number: 3, Hash: common.BytesToHash([]byte{0x02})} + ssd.checkFn = func() (includedIn types.BlockSeal, err error) { + return sampleBlockSeal, nil + } + sampleDerivedFrom := types.BlockSeal{Number: 1, Hash: common.BytesToHash([]byte{0x03})} + ssd.derivedFromFn = func() (derivedFrom types.BlockSeal, err error) { + return sampleDerivedFrom, nil + } + ssd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{Number: 10} + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 1} + execMsgs := []*types.ExecutingMessage{em1} + // when there is one execMsg, and the timestamp is less than the candidate, + // and CrossDerivedFrom returns a BlockSeal with a smaller Number than the inL1DerivedFrom, + // no error is returned + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.NoError(t, err) + require.Empty(t, hazards) + }) + t.Run("timestamp is less, CrossDerivedFrom Number equal", func(t *testing.T) { + ssd := &mockSafeStartDeps{} + sampleBlockSeal := types.BlockSeal{Number: 3, Hash: common.BytesToHash([]byte{0x02})} + ssd.checkFn = func() (includedIn types.BlockSeal, err error) { + return sampleBlockSeal, nil + } + sampleDerivedFrom := types.BlockSeal{Number: 1, Hash: common.BytesToHash([]byte{0x03})} + ssd.derivedFromFn = func() (derivedFrom types.BlockSeal, err error) { + return sampleDerivedFrom, nil + } + ssd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + inL1DerivedFrom := eth.BlockID{Number: 1} + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 1} + execMsgs := []*types.ExecutingMessage{em1} + // when there is one execMsg, and the timestamp is less than the candidate, + // and CrossDerivedFrom returns a BlockSeal with a equal to the Number of inL1DerivedFrom, + // no error is returned + hazards, err := CrossSafeHazards(ssd, chainID, inL1DerivedFrom, candidate, execMsgs) + require.NoError(t, err) + require.Empty(t, hazards) + }) +} + +type mockSafeStartDeps struct { + deps mockDependencySet + checkFn func() (includedIn types.BlockSeal, err error) + derivedFromFn func() (derivedFrom types.BlockSeal, err error) +} + +func (m *mockSafeStartDeps) Check(chain types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (includedIn types.BlockSeal, err error) { + if m.checkFn != nil { + return m.checkFn() + } + return types.BlockSeal{}, nil +} + +func (m *mockSafeStartDeps) CrossDerivedFrom(chainID types.ChainID, derived eth.BlockID) (derivedFrom types.BlockSeal, err error) { + if m.derivedFromFn != nil { + return m.derivedFromFn() + } + return types.BlockSeal{}, nil +} + +func (m *mockSafeStartDeps) DependencySet() depset.DependencySet { + return m.deps +} diff --git a/op-supervisor/supervisor/backend/cross/safe_update.go b/op-supervisor/supervisor/backend/cross/safe_update.go new file mode 100644 index 0000000000000..bcda7c9f782bc --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/safe_update.go @@ -0,0 +1,116 @@ +package cross + +import ( + "context" + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/log" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" +) + +type CrossSafeDeps interface { + CrossSafe(chainID types.ChainID) (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) + + SafeFrontierCheckDeps + SafeStartDeps + + CandidateCrossSafe(chain types.ChainID) (derivedFromScope, crossSafe eth.BlockRef, err error) + NextDerivedFrom(chain types.ChainID, derivedFrom eth.BlockID) (after eth.BlockRef, err error) + PreviousDerived(chain types.ChainID, derived eth.BlockID) (prevDerived types.BlockSeal, err error) + + OpenBlock(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) + + UpdateCrossSafe(chain types.ChainID, l1View eth.BlockRef, lastCrossDerived eth.BlockRef) error +} + +func CrossSafeUpdate(ctx context.Context, logger log.Logger, chainID types.ChainID, d CrossSafeDeps) error { + logger.Debug("Cross-safe update call") + // TODO(#11693): establish L1 reorg-lock of scopeDerivedFrom + // defer unlock once we are done checking the chain + candidateScope, err := scopedCrossSafeUpdate(logger, chainID, d) + if err == nil { + // if we made progress, and no errors, then there is no need to bump the L1 scope yet. + return nil + } + if !errors.Is(err, types.ErrOutOfScope) { + return err + } + // candidateScope is expected to be set if ErrOutOfScope is returned. + if candidateScope == (eth.BlockRef{}) { + return fmt.Errorf("expected L1 scope to be defined with ErrOutOfScope: %w", err) + } + logger.Debug("Cross-safe updating ran out of L1 scope", "scope", candidateScope, "err", err) + // bump the L1 scope up, and repeat the prev L2 block, not the candidate + newScope, err := d.NextDerivedFrom(chainID, candidateScope.ID()) + if err != nil { + return fmt.Errorf("failed to identify new L1 scope to expand to after %s: %w", candidateScope, err) + } + _, currentCrossSafe, err := d.CrossSafe(chainID) + if err != nil { + // TODO: if genesis isn't cross-safe by default, then we can't register something as cross-safe here + return fmt.Errorf("failed to identify cross-safe scope to repeat: %w", err) + } + parent, err := d.PreviousDerived(chainID, currentCrossSafe.ID()) + if err != nil { + return fmt.Errorf("cannot find parent-block of cross-safe: %w", err) + } + crossSafeRef := currentCrossSafe.MustWithParent(parent.ID()) + logger.Debug("Bumping cross-safe scope", "scope", newScope, "crossSafe", crossSafeRef) + if err := d.UpdateCrossSafe(chainID, newScope, crossSafeRef); err != nil { + return fmt.Errorf("failed to update cross-safe head with L1 scope increment to %s and repeat of L2 block %s: %w", candidateScope, crossSafeRef, err) + } + return nil +} + +// scopedCrossSafeUpdate runs through the cross-safe update checks. +// If no L2 cross-safe progress can be made without additional L1 input data, +// then a types.ErrOutOfScope error is returned, +// with the current scope that will need to be expanded for further progress. +func scopedCrossSafeUpdate(logger log.Logger, chainID types.ChainID, d CrossSafeDeps) (scope eth.BlockRef, err error) { + candidateScope, candidate, err := d.CandidateCrossSafe(chainID) + if err != nil { + return candidateScope, fmt.Errorf("failed to determine candidate block for cross-safe: %w", err) + } + logger.Debug("Candidate cross-safe", "scope", candidateScope, "candidate", candidate) + opened, _, execMsgs, err := d.OpenBlock(chainID, candidate.Number) + if err != nil { + return candidateScope, fmt.Errorf("failed to open block %s: %w", candidate, err) + } + if opened.ID() != candidate.ID() { + return candidateScope, fmt.Errorf("unsafe L2 DB has %s, but candidate cross-safe was %s: %w", opened, candidate, types.ErrConflict) + } + hazards, err := CrossSafeHazards(d, chainID, candidateScope.ID(), types.BlockSealFromRef(opened), sliceOfExecMsgs(execMsgs)) + if err != nil { + return candidateScope, fmt.Errorf("failed to determine dependencies of cross-safe candidate %s: %w", candidate, err) + } + if err := HazardSafeFrontierChecks(d, candidateScope.ID(), hazards); err != nil { + return candidateScope, fmt.Errorf("failed to verify block %s in cross-safe frontier: %w", candidate, err) + } + if err := HazardCycleChecks(d, candidate.Time, hazards); err != nil { + return candidateScope, fmt.Errorf("failed to verify block %s in cross-safe check for cycle hazards: %w", candidate, err) + } + + // promote the candidate block to cross-safe + if err := d.UpdateCrossSafe(chainID, candidateScope, candidate); err != nil { + return candidateScope, fmt.Errorf("failed to update cross-safe head to %s, derived from scope %s: %w", candidate, candidateScope, err) + } + return candidateScope, nil +} + +func NewCrossSafeWorker(logger log.Logger, chainID types.ChainID, d CrossSafeDeps) *Worker { + logger = logger.New("chain", chainID) + return NewWorker(logger, func(ctx context.Context) error { + return CrossSafeUpdate(ctx, logger, chainID, d) + }) +} + +func sliceOfExecMsgs(execMsgs map[uint32]*types.ExecutingMessage) []*types.ExecutingMessage { + msgs := make([]*types.ExecutingMessage, 0, len(execMsgs)) + for _, msg := range execMsgs { + msgs = append(msgs, msg) + } + return msgs +} diff --git a/op-supervisor/supervisor/backend/cross/safe_update_test.go b/op-supervisor/supervisor/backend/cross/safe_update_test.go new file mode 100644 index 0000000000000..3fc0ebba13884 --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/safe_update_test.go @@ -0,0 +1,442 @@ +package cross + +import ( + "context" + "errors" + "testing" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" +) + +func TestCrossSafeUpdate(t *testing.T) { + t.Run("scopedCrossSafeUpdate passes", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + candidate := eth.BlockRef{Number: 1} + candidateScope := eth.BlockRef{Number: 2} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return candidateScope, candidate, nil + } + opened := eth.BlockRef{Number: 1} + execs := map[uint32]*types.ExecutingMessage{1: {}} + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return opened, 10, execs, nil + } + csd.checkFn = func(chainID types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (types.BlockSeal, error) { + return types.BlockSeal{Number: 1, Timestamp: 1}, nil + } + csd.deps = mockDependencySet{} + // when scopedCrossSafeUpdate returns no error, + // no error is returned + err := CrossSafeUpdate(ctx, logger, chainID, csd) + require.NoError(t, err) + }) + t.Run("scopedCrossSafeUpdate reuturns error", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + candidate := eth.BlockRef{Number: 1} + candidateScope := eth.BlockRef{Number: 2} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return candidateScope, candidate, nil + } + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return eth.BlockRef{}, 0, nil, errors.New("some error") + } + csd.deps = mockDependencySet{} + // when scopedCrossSafeUpdate returns an error, + // (by way of OpenBlock returning an error), + // the error is returned + err := CrossSafeUpdate(ctx, logger, chainID, csd) + require.ErrorContains(t, err, "some error") + }) + t.Run("scopedCrossSafeUpdate reuturns ErrOutOfScope", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + candidate := eth.BlockRef{Number: 1} + candidateScope := eth.BlockRef{Number: 2} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return candidateScope, candidate, nil + } + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return eth.BlockRef{}, 0, nil, types.ErrOutOfScope + } + newScope := eth.BlockRef{Number: 3} + csd.nextDerivedFromFn = func(chain types.ChainID, derivedFrom eth.BlockID) (after eth.BlockRef, err error) { + return newScope, nil + } + currentCrossSafe := types.BlockSeal{Number: 5} + csd.crossSafeFn = func(chainID types.ChainID) (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) { + return types.BlockSeal{}, currentCrossSafe, nil + } + parent := types.BlockSeal{Number: 4} + csd.previousDerivedFn = func(chain types.ChainID, derived eth.BlockID) (prevDerived types.BlockSeal, err error) { + return parent, nil + } + csd.deps = mockDependencySet{} + var updatingChain types.ChainID + var updatingCandidateScope eth.BlockRef + var updatingCandidate eth.BlockRef + csd.updateCrossSafeFn = func(chain types.ChainID, l1View eth.BlockRef, lastCrossDerived eth.BlockRef) error { + updatingChain = chain + updatingCandidateScope = l1View + updatingCandidate = lastCrossDerived + return nil + } + // when scopedCrossSafeUpdate returns Out of Scope error, + // CrossSafeUpdate proceeds anyway and calls UpdateCrossSafe + // the update uses the new scope returned by NextDerivedFrom + // and a crossSafeRef made from the current crossSafe and its parent + err := CrossSafeUpdate(ctx, logger, chainID, csd) + require.NoError(t, err) + require.Equal(t, chainID, updatingChain) + require.Equal(t, newScope, updatingCandidateScope) + crossSafeRef := currentCrossSafe.MustWithParent(parent.ID()) + require.Equal(t, crossSafeRef, updatingCandidate) + }) + t.Run("NextDerivedFrom returns error", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + candidate := eth.BlockRef{Number: 1} + candidateScope := eth.BlockRef{Number: 2} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return candidateScope, candidate, nil + } + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return eth.BlockRef{}, 0, nil, types.ErrOutOfScope + } + csd.nextDerivedFromFn = func(chain types.ChainID, derivedFrom eth.BlockID) (after eth.BlockRef, err error) { + return eth.BlockRef{}, errors.New("some error") + } + csd.deps = mockDependencySet{} + // when scopedCrossSafeUpdate returns Out of Scope error, + // and NextDerivedFrom returns an error, + // the error is returned + err := CrossSafeUpdate(ctx, logger, chainID, csd) + require.ErrorContains(t, err, "some error") + }) + t.Run("PreviousDerived returns error", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + candidate := eth.BlockRef{Number: 1} + candidateScope := eth.BlockRef{Number: 2} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return candidateScope, candidate, nil + } + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return eth.BlockRef{}, 0, nil, types.ErrOutOfScope + } + csd.previousDerivedFn = func(chain types.ChainID, derived eth.BlockID) (prevDerived types.BlockSeal, err error) { + return types.BlockSeal{}, errors.New("some error") + } + csd.deps = mockDependencySet{} + // when scopedCrossSafeUpdate returns Out of Scope error, + // and PreviousDerived returns an error, + // the error is returned + err := CrossSafeUpdate(ctx, logger, chainID, csd) + require.ErrorContains(t, err, "some error") + }) + t.Run("UpdateCrossSafe returns error", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + candidate := eth.BlockRef{Number: 1} + candidateScope := eth.BlockRef{Number: 2} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return candidateScope, candidate, nil + } + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return eth.BlockRef{}, 0, nil, types.ErrOutOfScope + } + csd.updateCrossSafeFn = func(chain types.ChainID, l1View eth.BlockRef, lastCrossDerived eth.BlockRef) error { + return errors.New("some error") + } + csd.deps = mockDependencySet{} + // when scopedCrossSafeUpdate returns Out of Scope error, + // and UpdateCrossSafe returns an error, + // the error is returned + err := CrossSafeUpdate(ctx, logger, chainID, csd) + require.ErrorContains(t, err, "some error") + }) +} + +func TestScopedCrossSafeUpdate(t *testing.T) { + t.Run("CandidateCrossSafe returns error", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return eth.BlockRef{}, eth.BlockRef{}, errors.New("some error") + } + // when CandidateCrossSafe returns an error, + // the error is returned + blockRef, err := scopedCrossSafeUpdate(logger, chainID, csd) + require.ErrorContains(t, err, "some error") + require.Equal(t, eth.BlockRef{}, blockRef) + }) + t.Run("CandidateCrossSafe returns error", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return eth.BlockRef{}, 0, nil, errors.New("some error") + } + // when OpenBlock returns an error, + // the error is returned + blockRef, err := scopedCrossSafeUpdate(logger, chainID, csd) + require.ErrorContains(t, err, "some error") + require.Equal(t, eth.BlockRef{}, blockRef) + }) + t.Run("candidate does not match opened block", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + candidate := eth.BlockRef{Number: 1} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return eth.BlockRef{}, candidate, nil + } + opened := eth.BlockRef{Number: 2} + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return opened, 0, nil, nil + } + // when OpenBlock and CandidateCrossSafe return different blocks, + // an ErrConflict is returned + blockRef, err := scopedCrossSafeUpdate(logger, chainID, csd) + require.ErrorIs(t, err, types.ErrConflict) + require.Equal(t, eth.BlockRef{}, blockRef) + }) + t.Run("CrossSafeHazards returns error", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + candidate := eth.BlockRef{Number: 1} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return eth.BlockRef{}, candidate, nil + } + opened := eth.BlockRef{Number: 1} + execs := map[uint32]*types.ExecutingMessage{1: {}} + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return opened, 10, execs, nil + } + // cause CrossSafeHazards to return an error by making ChainIDFromIndex return an error + csd.deps = mockDependencySet{} + csd.deps.chainIDFromIndexfn = func() (types.ChainID, error) { + return types.ChainID{}, errors.New("some error") + } + // when CrossSafeHazards returns an error, + // the error is returned + blockRef, err := scopedCrossSafeUpdate(logger, chainID, csd) + require.ErrorContains(t, err, "some error") + require.ErrorContains(t, err, "dependencies of cross-safe candidate") + require.Equal(t, eth.BlockRef{}, blockRef) + }) + t.Run("HazardSafeFrontierChecks returns error", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + candidate := eth.BlockRef{Number: 1} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return eth.BlockRef{}, candidate, nil + } + opened := eth.BlockRef{Number: 1} + execs := map[uint32]*types.ExecutingMessage{1: {}} + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return opened, 10, execs, nil + } + csd.checkFn = func(chainID types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (types.BlockSeal, error) { + return types.BlockSeal{Number: 1, Timestamp: 1}, nil + } + count := 0 + csd.deps = mockDependencySet{} + // cause CrossSafeHazards to return an error by making ChainIDFromIndex return an error + // but only on the second call (which will be used by HazardSafeFrontierChecks) + csd.deps.chainIDFromIndexfn = func() (types.ChainID, error) { + defer func() { count++ }() + if count == 0 { + return types.ChainID{}, nil + } + return types.ChainID{}, errors.New("some error") + } + // when CrossSafeHazards returns an error, + // the error is returned + blockRef, err := scopedCrossSafeUpdate(logger, chainID, csd) + require.ErrorContains(t, err, "some error") + require.ErrorContains(t, err, "frontier") + require.Equal(t, eth.BlockRef{}, blockRef) + }) + t.Run("HazardCycleChecks returns error", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + candidate := eth.BlockRef{Number: 1, Time: 1} + candidateScope := eth.BlockRef{Number: 2} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return candidateScope, candidate, nil + } + opened := eth.BlockRef{Number: 1, Time: 1} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 1, LogIdx: 2} + em2 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 1, LogIdx: 1} + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return opened, 3, map[uint32]*types.ExecutingMessage{1: em1, 2: em2}, nil + } + csd.checkFn = func(chainID types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (types.BlockSeal, error) { + return types.BlockSeal{Number: 1, Timestamp: 1}, nil + } + csd.deps = mockDependencySet{} + + // HazardCycleChecks returns an error with appropriate wrapping + blockRef, err := scopedCrossSafeUpdate(logger, chainID, csd) + require.ErrorContains(t, err, "cycle detected") + require.ErrorContains(t, err, "failed to verify block") + require.Equal(t, eth.BlockRef{Number: 2}, blockRef) + }) + t.Run("UpdateCrossSafe returns error", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + candidate := eth.BlockRef{Number: 1} + candidateScope := eth.BlockRef{Number: 2} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return candidateScope, candidate, nil + } + opened := eth.BlockRef{Number: 1} + execs := map[uint32]*types.ExecutingMessage{1: {}} + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return opened, 10, execs, nil + } + csd.checkFn = func(chainID types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (types.BlockSeal, error) { + return types.BlockSeal{Number: 1, Timestamp: 1}, nil + } + csd.deps = mockDependencySet{} + csd.updateCrossSafeFn = func(chain types.ChainID, l1View eth.BlockRef, lastCrossDerived eth.BlockRef) error { + return errors.New("some error") + } + // when UpdateCrossSafe returns an error, + // the error is returned + blockRef, err := scopedCrossSafeUpdate(logger, chainID, csd) + require.ErrorContains(t, err, "some error") + require.ErrorContains(t, err, "failed to update") + require.Equal(t, eth.BlockRef{Number: 2}, blockRef) + }) + t.Run("successful update", func(t *testing.T) { + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + csd := &mockCrossSafeDeps{} + candidate := eth.BlockRef{Number: 1} + candidateScope := eth.BlockRef{Number: 2} + csd.candidateCrossSafeFn = func() (derivedFromScope, crossSafe eth.BlockRef, err error) { + return candidateScope, candidate, nil + } + opened := eth.BlockRef{Number: 1} + execs := map[uint32]*types.ExecutingMessage{1: {}} + csd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return opened, 10, execs, nil + } + csd.deps = mockDependencySet{} + var updatingChain types.ChainID + var updatingCandidateScope eth.BlockRef + var updatingCandidate eth.BlockRef + csd.updateCrossSafeFn = func(chain types.ChainID, l1View eth.BlockRef, lastCrossDerived eth.BlockRef) error { + updatingChain = chain + updatingCandidateScope = l1View + updatingCandidate = lastCrossDerived + return nil + } + // when no errors occur, the update is carried out + // the used candidate and scope are from CandidateCrossSafe + // the candidateScope is returned + csd.checkFn = func(chainID types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (types.BlockSeal, error) { + return types.BlockSeal{Number: 1, Timestamp: 1}, nil + } + blockRef, err := scopedCrossSafeUpdate(logger, chainID, csd) + require.Equal(t, chainID, updatingChain) + require.Equal(t, candidateScope, updatingCandidateScope) + require.Equal(t, candidate, updatingCandidate) + require.Equal(t, candidateScope, blockRef) + require.NoError(t, err) + }) +} + +type mockCrossSafeDeps struct { + deps mockDependencySet + crossSafeFn func(chainID types.ChainID) (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) + candidateCrossSafeFn func() (derivedFromScope, crossSafe eth.BlockRef, err error) + openBlockFn func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) + updateCrossSafeFn func(chain types.ChainID, l1View eth.BlockRef, lastCrossDerived eth.BlockRef) error + nextDerivedFromFn func(chain types.ChainID, derivedFrom eth.BlockID) (after eth.BlockRef, err error) + previousDerivedFn func(chain types.ChainID, derived eth.BlockID) (prevDerived types.BlockSeal, err error) + checkFn func(chainID types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (types.BlockSeal, error) +} + +func (m *mockCrossSafeDeps) CrossSafe(chainID types.ChainID) (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) { + if m.crossSafeFn != nil { + return m.crossSafeFn(chainID) + } + return types.BlockSeal{}, types.BlockSeal{}, nil +} + +func (m *mockCrossSafeDeps) CandidateCrossSafe(chain types.ChainID) (derivedFromScope, crossSafe eth.BlockRef, err error) { + if m.candidateCrossSafeFn != nil { + return m.candidateCrossSafeFn() + } + return eth.BlockRef{}, eth.BlockRef{}, nil +} + +func (m *mockCrossSafeDeps) DependencySet() depset.DependencySet { + return m.deps +} + +func (m *mockCrossSafeDeps) CrossDerivedFrom(chainID types.ChainID, derived eth.BlockID) (derivedFrom types.BlockSeal, err error) { + return types.BlockSeal{}, nil +} + +func (m *mockCrossSafeDeps) Check(chainID types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (types.BlockSeal, error) { + if m.checkFn != nil { + return m.checkFn(chainID, blockNum, logIdx, logHash) + } + return types.BlockSeal{}, nil +} + +func (m *mockCrossSafeDeps) NextDerivedFrom(chain types.ChainID, derivedFrom eth.BlockID) (after eth.BlockRef, err error) { + if m.nextDerivedFromFn != nil { + return m.nextDerivedFromFn(chain, derivedFrom) + } + return eth.BlockRef{}, nil +} + +func (m *mockCrossSafeDeps) PreviousDerived(chain types.ChainID, derived eth.BlockID) (prevDerived types.BlockSeal, err error) { + if m.previousDerivedFn != nil { + return m.previousDerivedFn(chain, derived) + } + return types.BlockSeal{}, nil +} + +func (m *mockCrossSafeDeps) OpenBlock(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + if m.openBlockFn != nil { + return m.openBlockFn(chainID, blockNum) + } + return eth.BlockRef{}, 0, nil, nil +} + +func (m *mockCrossSafeDeps) UpdateCrossSafe(chain types.ChainID, l1View eth.BlockRef, lastCrossDerived eth.BlockRef) error { + if m.updateCrossSafeFn != nil { + return m.updateCrossSafeFn(chain, l1View, lastCrossDerived) + } + return nil +} diff --git a/op-supervisor/supervisor/backend/cross/unsafe_frontier.go b/op-supervisor/supervisor/backend/cross/unsafe_frontier.go new file mode 100644 index 0000000000000..5e30da999eb13 --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/unsafe_frontier.go @@ -0,0 +1,63 @@ +package cross + +import ( + "errors" + "fmt" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" +) + +type UnsafeFrontierCheckDeps interface { + ParentBlock(chainID types.ChainID, parentOf eth.BlockID) (parent eth.BlockID, err error) + + IsCrossUnsafe(chainID types.ChainID, block eth.BlockID) error + IsLocalUnsafe(chainID types.ChainID, block eth.BlockID) error + + DependencySet() depset.DependencySet +} + +// HazardUnsafeFrontierChecks verifies all the hazard blocks are either: +// - already cross-unsafe. +// - the first (if not first: local blocks to verify before proceeding) +// local-unsafe block, after the cross-unsafe block. +func HazardUnsafeFrontierChecks(d UnsafeFrontierCheckDeps, hazards map[types.ChainIndex]types.BlockSeal) error { + depSet := d.DependencySet() + for hazardChainIndex, hazardBlock := range hazards { + hazardChainID, err := depSet.ChainIDFromIndex(hazardChainIndex) + if err != nil { + if errors.Is(err, types.ErrUnknownChain) { + err = fmt.Errorf("cannot cross-unsafe verify block %s of unknown chain index %s: %w", hazardBlock, hazardChainIndex, types.ErrConflict) + } + return err + } + // Anything we depend on in this timestamp must be cross-unsafe already, or the first block after. + err = d.IsCrossUnsafe(hazardChainID, hazardBlock.ID()) + if err != nil { + if errors.Is(err, types.ErrFuture) { + // Not already cross-unsafe, so we check if the block is local-unsafe + // (a sanity check if part of the canonical chain). + err = d.IsLocalUnsafe(hazardChainID, hazardBlock.ID()) + if err != nil { + // can be ErrFuture (missing data) or ErrConflict (non-canonical) + return fmt.Errorf("hazard block %s (chain %d) is not local-unsafe: %w", hazardBlock, hazardChainID, err) + } + // If it doesn't have a parent block, then there is no prior block required to be cross-safe + if hazardBlock.Number > 0 { + // Check that parent of hazardBlockID is cross-safe within view + parent, err := d.ParentBlock(hazardChainID, hazardBlock.ID()) + if err != nil { + return fmt.Errorf("failed to retrieve parent-block of hazard block %s (chain %s): %w", hazardBlock, hazardChainID, err) + } + if err := d.IsCrossUnsafe(hazardChainID, parent); err != nil { + return fmt.Errorf("cannot rely on hazard-block %s (chain %s), parent block %s is not cross-unsafe: %w", hazardBlock, hazardChainID, parent, err) + } + } + } else { + return fmt.Errorf("failed to determine cross-derived of hazard block %s (chain %s): %w", hazardBlock, hazardChainID, err) + } + } + } + return nil +} diff --git a/op-supervisor/supervisor/backend/cross/unsafe_frontier_test.go b/op-supervisor/supervisor/backend/cross/unsafe_frontier_test.go new file mode 100644 index 0000000000000..09086e0e87385 --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/unsafe_frontier_test.go @@ -0,0 +1,130 @@ +package cross + +import ( + "errors" + "testing" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestHazardUnsafeFrontierChecks(t *testing.T) { + t.Run("empty hazards", func(t *testing.T) { + ufcd := &mockUnsafeFrontierCheckDeps{} + hazards := map[types.ChainIndex]types.BlockSeal{} + // when there are no hazards, + // no work is done, and no error is returned + err := HazardUnsafeFrontierChecks(ufcd, hazards) + require.NoError(t, err) + }) + t.Run("unknown chain", func(t *testing.T) { + ufcd := &mockUnsafeFrontierCheckDeps{ + deps: mockDependencySet{ + chainIDFromIndexfn: func() (types.ChainID, error) { + return types.ChainID{}, types.ErrUnknownChain + }, + }, + } + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {}} + // when there is one hazard, and ChainIDFromIndex returns ErrUnknownChain, + // an error is returned as a ErrConflict + err := HazardUnsafeFrontierChecks(ufcd, hazards) + require.ErrorIs(t, err, types.ErrConflict) + }) + t.Run("is cross unsafe", func(t *testing.T) { + ufcd := &mockUnsafeFrontierCheckDeps{} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {}} + ufcd.isCrossUnsafe = nil + // when there is one hazard, and IsCrossUnsafe returns nil (no error) + // no error is returned + err := HazardUnsafeFrontierChecks(ufcd, hazards) + require.NoError(t, err) + }) + t.Run("errFuture: is not local unsafe", func(t *testing.T) { + ufcd := &mockUnsafeFrontierCheckDeps{} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {}} + ufcd.isCrossUnsafe = types.ErrFuture + ufcd.isLocalUnsafe = errors.New("some error") + // when there is one hazard, and IsCrossUnsafe returns an ErrFuture, + // and IsLocalUnsafe returns an error, + // the error from IsLocalUnsafe is (wrapped and) returned + err := HazardUnsafeFrontierChecks(ufcd, hazards) + require.ErrorContains(t, err, "some error") + }) + t.Run("errFuture: genesis block", func(t *testing.T) { + ufcd := &mockUnsafeFrontierCheckDeps{} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {}} + ufcd.isCrossUnsafe = types.ErrFuture + // when there is one hazard, and IsCrossUnsafe returns an ErrFuture, + // BUT the hazard's block number is 0, + // no error is returned + err := HazardUnsafeFrontierChecks(ufcd, hazards) + require.NoError(t, err) + }) + t.Run("errFuture: error getting parent block", func(t *testing.T) { + ufcd := &mockUnsafeFrontierCheckDeps{} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {Number: 3}} + ufcd.isCrossUnsafe = types.ErrFuture + ufcd.parentBlockFn = func() (parent eth.BlockID, err error) { + return eth.BlockID{}, errors.New("some error") + } + // when there is one hazard, and IsCrossUnsafe returns an ErrFuture, + // and there is an error getting the parent block, + // the error from ParentBlock is (wrapped and) returned + err := HazardUnsafeFrontierChecks(ufcd, hazards) + require.ErrorContains(t, err, "some error") + }) + t.Run("errFuture: parent block is not cross unsafe", func(t *testing.T) { + ufcd := &mockUnsafeFrontierCheckDeps{} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {Number: 3}} + ufcd.isCrossUnsafe = types.ErrFuture + ufcd.parentBlockFn = func() (parent eth.BlockID, err error) { + // when getting the parent block, prep isCrossSafe to be err + ufcd.isCrossUnsafe = errors.New("not cross unsafe!") + return eth.BlockID{}, nil + } + // when there is one hazard, and IsCrossUnsafe returns an ErrFuture, + // and the parent block is not cross unsafe, + // the error from IsCrossUnsafe is (wrapped and) returned + err := HazardUnsafeFrontierChecks(ufcd, hazards) + require.ErrorContains(t, err, "not cross unsafe!") + }) + t.Run("IsCrossUnsafe Error", func(t *testing.T) { + ufcd := &mockUnsafeFrontierCheckDeps{} + hazards := map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): {Number: 3, Hash: common.BytesToHash([]byte{0x02})}} + ufcd.isCrossUnsafe = errors.New("some error") + // when there is one hazard, and IsCrossUnsafe returns an error, + // the error from IsCrossUnsafe is (wrapped and) returned + err := HazardUnsafeFrontierChecks(ufcd, hazards) + require.ErrorContains(t, err, "some error") + }) +} + +type mockUnsafeFrontierCheckDeps struct { + deps mockDependencySet + parentBlockFn func() (parent eth.BlockID, err error) + isCrossUnsafe error + isLocalUnsafe error +} + +func (m *mockUnsafeFrontierCheckDeps) DependencySet() depset.DependencySet { + return m.deps +} + +func (m *mockUnsafeFrontierCheckDeps) ParentBlock(chainID types.ChainID, block eth.BlockID) (parent eth.BlockID, err error) { + if m.parentBlockFn != nil { + return m.parentBlockFn() + } + return eth.BlockID{}, nil +} + +func (m *mockUnsafeFrontierCheckDeps) IsCrossUnsafe(chainID types.ChainID, block eth.BlockID) error { + return m.isCrossUnsafe +} + +func (m *mockUnsafeFrontierCheckDeps) IsLocalUnsafe(chainID types.ChainID, block eth.BlockID) error { + return m.isLocalUnsafe +} diff --git a/op-supervisor/supervisor/backend/cross/unsafe_start.go b/op-supervisor/supervisor/backend/cross/unsafe_start.go new file mode 100644 index 0000000000000..9b4568a7b6225 --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/unsafe_start.go @@ -0,0 +1,100 @@ +package cross + +import ( + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/common" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" +) + +type UnsafeStartDeps interface { + Check(chain types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (includedIn types.BlockSeal, err error) + + IsCrossUnsafe(chainID types.ChainID, block eth.BlockID) error + + DependencySet() depset.DependencySet +} + +// CrossUnsafeHazards checks if the given messages all exist and pass invariants. +// It returns a hazard-set: if any intra-block messaging happened, +// these hazard blocks have to be verified. +func CrossUnsafeHazards(d UnsafeStartDeps, chainID types.ChainID, + candidate types.BlockSeal, execMsgs []*types.ExecutingMessage) (hazards map[types.ChainIndex]types.BlockSeal, err error) { + + hazards = make(map[types.ChainIndex]types.BlockSeal) + + // Warning for future: If we have sub-second distinct blocks (different block number), + // we need to increase precision on the above timestamp invariant. + // Otherwise a local block can depend on a future local block of the same chain, + // simply by pulling in a block of another chain, + // which then depends on a block of the original chain, + // all with the same timestamp, without message cycles. + + depSet := d.DependencySet() + + if len(execMsgs) > 0 { + if ok, err := depSet.CanExecuteAt(chainID, candidate.Timestamp); err != nil { + return nil, fmt.Errorf("cannot check message execution of block %s (chain %s): %w", candidate, chainID, err) + } else if !ok { + return nil, fmt.Errorf("cannot execute messages in block %s (chain %s): %w", candidate, chainID, types.ErrConflict) + } + } + + // check all executing messages + for _, msg := range execMsgs { + initChainID, err := depSet.ChainIDFromIndex(msg.Chain) + if err != nil { + if errors.Is(err, types.ErrUnknownChain) { + err = fmt.Errorf("msg %s may not execute from unknown chain %s: %w", msg, msg.Chain, types.ErrConflict) + } + return nil, err + } + if ok, err := depSet.CanInitiateAt(initChainID, msg.Timestamp); err != nil { + return nil, fmt.Errorf("cannot check message initiation of msg %s (chain %s): %w", msg, chainID, err) + } else if !ok { + return nil, fmt.Errorf("cannot allow initiating message %s (chain %s): %w", msg, chainID, types.ErrConflict) + } + if msg.Timestamp < candidate.Timestamp { + // If timestamp is older: invariant ensures non-cyclic ordering relative to other messages. + // Check that the block that they are included in is cross-safe already. + includedIn, err := d.Check(initChainID, msg.BlockNum, msg.LogIdx, msg.Hash) + if err != nil { + return nil, fmt.Errorf("executing msg %s failed check: %w", msg, err) + } + if err := d.IsCrossUnsafe(initChainID, includedIn.ID()); err != nil { + return nil, fmt.Errorf("msg %s included in non-cross-unsafe block %s: %w", msg, includedIn, err) + } + } else if msg.Timestamp == candidate.Timestamp { + // If timestamp is equal: we have to inspect ordering of individual + // log events to ensure non-cyclic cross-chain message ordering. + // And since we may have back-and-forth messaging, we cannot wait till the initiating side is cross-unsafe. + // Thus check that it was included in a local-unsafe block, + // and then proceed with transitive block checks, + // to ensure the local block we depend on is becoming cross-unsafe also. + includedIn, err := d.Check(initChainID, msg.BlockNum, msg.LogIdx, msg.Hash) + if err != nil { + return nil, fmt.Errorf("executing msg %s failed check: %w", msg, err) + } + + // As a hazard block, it will be checked to be included in a cross-unsafe block, + // or right after a cross-unsafe block, in HazardUnsafeFrontierChecks. + if existing, ok := hazards[msg.Chain]; ok { + if existing != includedIn { + return nil, fmt.Errorf("found dependency on %s (chain %d), but already depend on %s", includedIn, initChainID, chainID) + } + } else { + // Mark it as hazard block + hazards[msg.Chain] = includedIn + } + } else { + // Timestamp invariant is broken: executing message tries to execute future block. + // The predeploy inbox contract should not have allowed this executing message through. + return nil, fmt.Errorf("executing message %s in %s breaks timestamp invariant", msg, candidate) + } + } + return hazards, nil +} diff --git a/op-supervisor/supervisor/backend/cross/unsafe_start_test.go b/op-supervisor/supervisor/backend/cross/unsafe_start_test.go new file mode 100644 index 0000000000000..123fc70abe17d --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/unsafe_start_test.go @@ -0,0 +1,280 @@ +package cross + +import ( + "errors" + "testing" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestCrossUnsafeHazards(t *testing.T) { + t.Run("empty execMsgs", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{} + // when there are no execMsgs, + // no work is done, and no error is returned + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.NoError(t, err) + require.Empty(t, hazards) + }) + t.Run("CanExecuteAt returns false", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + usd.deps = mockDependencySet{ + canExecuteAtfn: func() (bool, error) { + return false, nil + }, + } + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{{}} + // when there is one execMsg, and CanExecuteAt returns false, + // no work is done and an error is returned + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.ErrorIs(t, err, types.ErrConflict) + require.Empty(t, hazards) + }) + t.Run("CanExecuteAt returns error", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + usd.deps = mockDependencySet{ + canExecuteAtfn: func() (bool, error) { + return false, errors.New("some error") + }, + } + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{{}} + // when there is one execMsg, and CanExecuteAt returns false, + // no work is done and an error is returned + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.ErrorContains(t, err, "some error") + require.Empty(t, hazards) + }) + t.Run("unknown chain", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + usd.deps = mockDependencySet{ + chainIDFromIndexfn: func() (types.ChainID, error) { + return types.ChainID{}, types.ErrUnknownChain + }, + } + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{{}} + // when there is one execMsg, and ChainIDFromIndex returns ErrUnknownChain, + // an error is returned as a ErrConflict + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.ErrorIs(t, err, types.ErrConflict) + require.Empty(t, hazards) + }) + t.Run("ChainIDFromUInt64 returns error", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + usd.deps = mockDependencySet{ + chainIDFromIndexfn: func() (types.ChainID, error) { + return types.ChainID{}, errors.New("some error") + }, + } + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{{}} + // when there is one execMsg, and ChainIDFromIndex returns some other error, + // the error is returned + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.ErrorContains(t, err, "some error") + require.Empty(t, hazards) + }) + t.Run("CanInitiateAt returns false", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + usd.deps = mockDependencySet{ + canInitiateAtfn: func() (bool, error) { + return false, nil + }, + } + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{{}} + // when there is one execMsg, and CanInitiateAt returns false, + // the error is returned as a ErrConflict + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.ErrorIs(t, err, types.ErrConflict) + require.Empty(t, hazards) + }) + t.Run("CanInitiateAt returns error", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + usd.deps = mockDependencySet{ + canInitiateAtfn: func() (bool, error) { + return false, errors.New("some error") + }, + } + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{} + execMsgs := []*types.ExecutingMessage{{}} + // when there is one execMsg, and CanInitiateAt returns an error, + // the error is returned + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.ErrorContains(t, err, "some error") + require.Empty(t, hazards) + }) + t.Run("timestamp is greater than candidate", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + usd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 10} + execMsgs := []*types.ExecutingMessage{em1} + // when there is one execMsg, and the timestamp is greater than the candidate, + // an error is returned + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.ErrorContains(t, err, "breaks timestamp invariant") + require.Empty(t, hazards) + }) + t.Run("timestamp is equal, Check returns error", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + usd.checkFn = func() (includedIn types.BlockSeal, err error) { + return types.BlockSeal{}, errors.New("some error") + } + usd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 2} + execMsgs := []*types.ExecutingMessage{em1} + // when there is one execMsg, and the timetamp is equal to the candidate, + // and check returns an error, + // that error is returned + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.ErrorContains(t, err, "some error") + require.Empty(t, hazards) + }) + t.Run("timestamp is equal, same hazard twice", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + sampleBlockSeal := types.BlockSeal{Number: 3, Hash: common.BytesToHash([]byte{0x02})} + usd.checkFn = func() (includedIn types.BlockSeal, err error) { + return sampleBlockSeal, nil + } + usd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 2} + em2 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 2} + execMsgs := []*types.ExecutingMessage{em1, em2} + // when there are two execMsgs, and both are equal time to the candidate, + // and check returns the same includedIn for both + // they load the hazards once, and return no error + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.NoError(t, err) + require.Equal(t, hazards, map[types.ChainIndex]types.BlockSeal{types.ChainIndex(0): sampleBlockSeal}) + }) + t.Run("timestamp is equal, different hazards", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + // set the check function to return a different BlockSeal for the second call + sampleBlockSeal := types.BlockSeal{Number: 3, Hash: common.BytesToHash([]byte{0x02})} + sampleBlockSeal2 := types.BlockSeal{Number: 333, Hash: common.BytesToHash([]byte{0x22})} + calls := 0 + usd.checkFn = func() (includedIn types.BlockSeal, err error) { + defer func() { calls++ }() + if calls == 0 { + return sampleBlockSeal, nil + } + return sampleBlockSeal2, nil + } + usd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 2} + em2 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 2} + execMsgs := []*types.ExecutingMessage{em1, em2} + // when there are two execMsgs, and both are equal time to the candidate, + // and check returns different includedIn for the two, + // an error is returned + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.ErrorContains(t, err, "but already depend on") + require.Empty(t, hazards) + }) + t.Run("timestamp is less, check returns error", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + usd.checkFn = func() (includedIn types.BlockSeal, err error) { + return types.BlockSeal{}, errors.New("some error") + } + usd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 1} + execMsgs := []*types.ExecutingMessage{em1} + // when there is one execMsg, and the timestamp is less than the candidate, + // and check returns an error, + // that error is returned + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.ErrorContains(t, err, "some error") + require.Empty(t, hazards) + }) + t.Run("timestamp is less, IsCrossUnsafe returns error", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + sampleBlockSeal := types.BlockSeal{Number: 3, Hash: common.BytesToHash([]byte{0x02})} + usd.checkFn = func() (includedIn types.BlockSeal, err error) { + return sampleBlockSeal, nil + } + usd.isCrossUnsafeFn = func() error { + return errors.New("some error") + } + usd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 1} + execMsgs := []*types.ExecutingMessage{em1} + // when there is one execMsg, and the timestamp is less than the candidate, + // and IsCrossUnsafe returns an error, + // that error is returned + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.ErrorContains(t, err, "some error") + require.Empty(t, hazards) + }) + t.Run("timestamp is less, IsCrossUnsafe", func(t *testing.T) { + usd := &mockUnsafeStartDeps{} + sampleBlockSeal := types.BlockSeal{Number: 3, Hash: common.BytesToHash([]byte{0x02})} + usd.checkFn = func() (includedIn types.BlockSeal, err error) { + return sampleBlockSeal, nil + } + usd.isCrossUnsafeFn = func() error { + return nil + } + usd.deps = mockDependencySet{} + chainID := types.ChainIDFromUInt64(0) + candidate := types.BlockSeal{Timestamp: 2} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 1} + execMsgs := []*types.ExecutingMessage{em1} + // when there is one execMsg, and the timestamp is less than the candidate, + // and IsCrossUnsafe returns no error, + // no error is returned + hazards, err := CrossUnsafeHazards(usd, chainID, candidate, execMsgs) + require.NoError(t, err) + require.Empty(t, hazards) + }) +} + +type mockUnsafeStartDeps struct { + deps mockDependencySet + checkFn func() (includedIn types.BlockSeal, err error) + isCrossUnsafeFn func() error +} + +func (m *mockUnsafeStartDeps) Check(chain types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (includedIn types.BlockSeal, err error) { + if m.checkFn != nil { + return m.checkFn() + } + return types.BlockSeal{}, nil +} + +func (m *mockUnsafeStartDeps) IsCrossUnsafe(chainID types.ChainID, derived eth.BlockID) error { + if m.isCrossUnsafeFn != nil { + return m.isCrossUnsafeFn() + } + return nil +} + +func (m *mockUnsafeStartDeps) DependencySet() depset.DependencySet { + return m.deps +} diff --git a/op-supervisor/supervisor/backend/cross/unsafe_update.go b/op-supervisor/supervisor/backend/cross/unsafe_update.go new file mode 100644 index 0000000000000..56d3961271585 --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/unsafe_update.go @@ -0,0 +1,79 @@ +package cross + +import ( + "context" + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/log" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" +) + +type CrossUnsafeDeps interface { + CrossUnsafe(chainID types.ChainID) (types.BlockSeal, error) + + UnsafeStartDeps + UnsafeFrontierCheckDeps + + OpenBlock(chainID types.ChainID, blockNum uint64) (block eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) + + UpdateCrossUnsafe(chain types.ChainID, crossUnsafe types.BlockSeal) error +} + +func CrossUnsafeUpdate(ctx context.Context, logger log.Logger, chainID types.ChainID, d CrossUnsafeDeps) error { + var candidate types.BlockSeal + var execMsgs []*types.ExecutingMessage + + // fetch cross-head to determine next cross-unsafe candidate + if crossUnsafe, err := d.CrossUnsafe(chainID); err != nil { + if errors.Is(err, types.ErrFuture) { + // If genesis / no cross-safe block yet, then defer update + logger.Debug("No cross-unsafe starting point yet") + return nil + } else { + return err + } + } else { + // Open block N+1: this is a local-unsafe block, + // just after cross-safe, that can be promoted if it passes the dependency checks. + bl, _, msgs, err := d.OpenBlock(chainID, crossUnsafe.Number+1) + if err != nil { + return fmt.Errorf("failed to open block %d: %w", crossUnsafe.Number+1, err) + } + if bl.ParentHash != crossUnsafe.Hash { + return fmt.Errorf("cannot use block %s, it does not build on cross-unsafe block %s: %w", bl, crossUnsafe, types.ErrConflict) + } + candidate = types.BlockSealFromRef(bl) + execMsgs = sliceOfExecMsgs(msgs) + } + + hazards, err := CrossUnsafeHazards(d, chainID, candidate, execMsgs) + if err != nil { + // TODO(#11693): reorgs can be detected by checking if the error is ErrConflict, + // missing data is identified by ErrFuture, + // and other errors (e.g. DB issues) are identifier by remaining error kinds. + return fmt.Errorf("failed to check for cross-chain hazards: %w", err) + } + + if err := HazardUnsafeFrontierChecks(d, hazards); err != nil { + return fmt.Errorf("failed to verify block %s in cross-unsafe frontier: %w", candidate, err) + } + if err := HazardCycleChecks(d, candidate.Timestamp, hazards); err != nil { + return fmt.Errorf("failed to verify block %s in cross-unsafe check for cycle hazards: %w", candidate, err) + } + + // promote the candidate block to cross-unsafe + if err := d.UpdateCrossUnsafe(chainID, candidate); err != nil { + return fmt.Errorf("failed to update cross-unsafe head to %s: %w", candidate, err) + } + return nil +} + +func NewCrossUnsafeWorker(logger log.Logger, chainID types.ChainID, d CrossUnsafeDeps) *Worker { + logger = logger.New("chain", chainID) + return NewWorker(logger, func(ctx context.Context) error { + return CrossUnsafeUpdate(ctx, logger, chainID, d) + }) +} diff --git a/op-supervisor/supervisor/backend/cross/unsafe_update_test.go b/op-supervisor/supervisor/backend/cross/unsafe_update_test.go new file mode 100644 index 0000000000000..ada7d0756cf46 --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/unsafe_update_test.go @@ -0,0 +1,241 @@ +package cross + +import ( + "context" + "errors" + "testing" + + "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" +) + +func TestCrossUnsafeUpdate(t *testing.T) { + t.Run("CrossUnsafe returns error", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + usd := &mockCrossUnsafeDeps{} + usd.crossUnsafeFn = func(chainID types.ChainID) (types.BlockSeal, error) { + return types.BlockSeal{}, errors.New("some error") + } + usd.deps = mockDependencySet{} + // when an error is returned by CrossUnsafe, + // the error is returned + err := CrossUnsafeUpdate(ctx, logger, chainID, usd) + require.ErrorContains(t, err, "some error") + }) + t.Run("CrossUnsafe returns ErrFuture", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + usd := &mockCrossUnsafeDeps{} + usd.crossUnsafeFn = func(chainID types.ChainID) (types.BlockSeal, error) { + return types.BlockSeal{}, types.ErrFuture + } + usd.deps = mockDependencySet{} + // when a ErrFuture is returned by CrossUnsafe, + // no error is returned + err := CrossUnsafeUpdate(ctx, logger, chainID, usd) + require.NoError(t, err) + }) + t.Run("OpenBlock returns error", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + usd := &mockCrossUnsafeDeps{} + usd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return eth.BlockRef{}, 0, nil, errors.New("some error") + } + usd.deps = mockDependencySet{} + // when an error is returned by OpenBlock, + // the error is returned + err := CrossUnsafeUpdate(ctx, logger, chainID, usd) + require.ErrorContains(t, err, "some error") + }) + t.Run("opened block parent hash does not match", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + usd := &mockCrossUnsafeDeps{} + crossUnsafe := types.BlockSeal{Hash: common.Hash{0x11}} + usd.crossUnsafeFn = func(chainID types.ChainID) (types.BlockSeal, error) { + return crossUnsafe, nil + } + bl := eth.BlockRef{ParentHash: common.Hash{0x01}} + usd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return bl, 0, nil, nil + } + usd.deps = mockDependencySet{} + // when the parent hash of the opened block does not match the cross-unsafe block, + // an ErrConflict is returned + err := CrossUnsafeUpdate(ctx, logger, chainID, usd) + require.ErrorIs(t, err, types.ErrConflict) + }) + t.Run("CrossSafeHazards returns error", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + usd := &mockCrossUnsafeDeps{} + crossUnsafe := types.BlockSeal{Hash: common.Hash{0x01}} + usd.crossUnsafeFn = func(chainID types.ChainID) (types.BlockSeal, error) { + return crossUnsafe, nil + } + bl := eth.BlockRef{ParentHash: common.Hash{0x01}} + usd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + // include one executing message to trigger the CanExecuteAt check + return bl, 0, map[uint32]*types.ExecutingMessage{1: {}}, nil + } + usd.deps = mockDependencySet{} + // make CrossSafeHazards return an error by setting CanExecuteAtfn to return an error + usd.deps.canExecuteAtfn = func() (bool, error) { + return false, errors.New("some error") + } + // when CrossSafeHazards returns an error, + // the error is returned + err := CrossUnsafeUpdate(ctx, logger, chainID, usd) + require.ErrorContains(t, err, "some error") + }) + t.Run("HazardUnsafeFrontierChecks returns error", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + usd := &mockCrossUnsafeDeps{} + crossUnsafe := types.BlockSeal{Hash: common.Hash{0x01}} + usd.crossUnsafeFn = func(chainID types.ChainID) (types.BlockSeal, error) { + return crossUnsafe, nil + } + bl := eth.BlockRef{ParentHash: common.Hash{0x01}, Time: 1} + em1 := &types.ExecutingMessage{Timestamp: 1} + usd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + // include one executing message to ensure one hazard is returned + return bl, 0, map[uint32]*types.ExecutingMessage{1: em1}, nil + } + usd.deps = mockDependencySet{} + count := 0 + // make HazardUnsafeFrontierChecks return an error by failing the second ChainIDFromIndex call + // (the first one is in CrossSafeHazards) + usd.deps.chainIDFromIndexfn = func() (types.ChainID, error) { + defer func() { count++ }() + if count == 1 { + return types.ChainID{}, errors.New("some error") + } + return types.ChainID{}, nil + } + // when HazardUnsafeFrontierChecks returns an error, + // the error is returned + err := CrossUnsafeUpdate(ctx, logger, chainID, usd) + require.ErrorContains(t, err, "some error") + }) + t.Run("HazardCycleChecks returns error", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + usd := &mockCrossUnsafeDeps{} + crossUnsafe := types.BlockSeal{Hash: common.Hash{0x01}} + usd.crossUnsafeFn = func(chainID types.ChainID) (types.BlockSeal, error) { + return crossUnsafe, nil + } + bl := eth.BlockRef{ParentHash: common.Hash{0x01}, Number: 1, Time: 1} + em1 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 1, LogIdx: 2} + em2 := &types.ExecutingMessage{Chain: types.ChainIndex(0), Timestamp: 1, LogIdx: 1} + usd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + return bl, 3, map[uint32]*types.ExecutingMessage{1: em1, 2: em2}, nil + } + usd.checkFn = func(chainID types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (types.BlockSeal, error) { + return types.BlockSeal{Number: 1, Timestamp: 1}, nil + } + usd.deps = mockDependencySet{} + + // HazardCycleChecks returns an error with appropriate wrapping + err := CrossUnsafeUpdate(ctx, logger, chainID, usd) + require.ErrorContains(t, err, "cycle detected") + require.ErrorContains(t, err, "failed to verify block") + }) + t.Run("successful update", func(t *testing.T) { + ctx := context.Background() + logger := testlog.Logger(t, log.LevelDebug) + chainID := types.ChainIDFromUInt64(0) + usd := &mockCrossUnsafeDeps{} + crossUnsafe := types.BlockSeal{Hash: common.Hash{0x01}} + usd.crossUnsafeFn = func(chainID types.ChainID) (types.BlockSeal, error) { + return crossUnsafe, nil + } + bl := eth.BlockRef{ParentHash: common.Hash{0x01}, Time: 1} + em1 := &types.ExecutingMessage{Timestamp: 1} + usd.openBlockFn = func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + // include one executing message to ensure one hazard is returned + return bl, 2, map[uint32]*types.ExecutingMessage{1: em1}, nil + } + usd.deps = mockDependencySet{} + var updatingChainID types.ChainID + var updatingBlock types.BlockSeal + usd.updateCrossUnsafeFn = func(chain types.ChainID, crossUnsafe types.BlockSeal) error { + updatingChainID = chain + updatingBlock = crossUnsafe + return nil + } + // when there are no errors, the cross-unsafe block is updated + // the updated block is the block opened in OpenBlock + err := CrossUnsafeUpdate(ctx, logger, chainID, usd) + require.NoError(t, err) + require.Equal(t, chainID, updatingChainID) + require.Equal(t, types.BlockSealFromRef(bl), updatingBlock) + }) +} + +type mockCrossUnsafeDeps struct { + deps mockDependencySet + crossUnsafeFn func(chainID types.ChainID) (types.BlockSeal, error) + openBlockFn func(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) + updateCrossUnsafeFn func(chain types.ChainID, crossUnsafe types.BlockSeal) error + checkFn func(chainID types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (types.BlockSeal, error) +} + +func (m *mockCrossUnsafeDeps) CrossUnsafe(chainID types.ChainID) (derived types.BlockSeal, err error) { + if m.crossUnsafeFn != nil { + return m.crossUnsafeFn(chainID) + } + return types.BlockSeal{}, nil +} + +func (m *mockCrossUnsafeDeps) DependencySet() depset.DependencySet { + return m.deps +} + +func (m *mockCrossUnsafeDeps) Check(chainID types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (types.BlockSeal, error) { + if m.checkFn != nil { + return m.checkFn(chainID, blockNum, logIdx, logHash) + } + return types.BlockSeal{}, nil +} + +func (m *mockCrossUnsafeDeps) OpenBlock(chainID types.ChainID, blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + if m.openBlockFn != nil { + return m.openBlockFn(chainID, blockNum) + } + return eth.BlockRef{}, 0, nil, nil +} + +func (m *mockCrossUnsafeDeps) UpdateCrossUnsafe(chain types.ChainID, block types.BlockSeal) error { + if m.updateCrossUnsafeFn != nil { + return m.updateCrossUnsafeFn(chain, block) + } + return nil +} + +func (m *mockCrossUnsafeDeps) IsCrossUnsafe(chainID types.ChainID, blockNum eth.BlockID) error { + return nil +} + +func (m *mockCrossUnsafeDeps) IsLocalUnsafe(chainID types.ChainID, blockNum eth.BlockID) error { + return nil +} + +func (m *mockCrossUnsafeDeps) ParentBlock(chainID types.ChainID, blockNum eth.BlockID) (eth.BlockID, error) { + return eth.BlockID{}, nil +} diff --git a/op-supervisor/supervisor/backend/cross/worker.go b/op-supervisor/supervisor/backend/cross/worker.go new file mode 100644 index 0000000000000..689b89829e4b9 --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/worker.go @@ -0,0 +1,107 @@ +package cross + +import ( + "context" + "errors" + "sync" + "time" + + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" + "github.com/ethereum/go-ethereum/log" +) + +// Worker iterates work +type Worker struct { + log log.Logger + + // workFn is the function to call to process the scope + workFn workFn + + // channel with capacity of 1, full if there is work to do + poke chan struct{} + pollDuration time.Duration + + // lifetime management of the chain processor + ctx context.Context + cancel context.CancelFunc + wg sync.WaitGroup +} + +// workFn is a function used by the worker +// it is opaque to the worker, and is set by the constructor +type workFn func(ctx context.Context) error + +// NewWorker creates a new worker to process updates +func NewWorker(log log.Logger, workFn workFn) *Worker { + ctx, cancel := context.WithCancel(context.Background()) + out := &Worker{ + log: log, + poke: make(chan struct{}, 1), + // The data may have changed, and we may have missed a poke, so re-attempt regularly. + pollDuration: 250 * time.Millisecond, + ctx: ctx, + cancel: cancel, + } + out.workFn = workFn + return out +} + +func (s *Worker) StartBackground() { + s.wg.Add(1) + go s.worker() +} + +func (s *Worker) ProcessWork() error { + return s.workFn(s.ctx) +} + +func (s *Worker) worker() { + defer s.wg.Done() + + delay := time.NewTicker(s.pollDuration) + for { + if s.ctx.Err() != nil { // check if we are closing down + return + } + + // do the work + err := s.workFn(s.ctx) + if err != nil { + if errors.Is(err, s.ctx.Err()) { + return + } + if errors.Is(err, types.ErrFuture) { + s.log.Debug("Worker awaits additional blocks", "err", err) + } else { + s.log.Warn("Failed to process work", "err", err) + } + } + + // await next time we process, or detect shutdown + select { + case <-s.ctx.Done(): + delay.Stop() + return + case <-s.poke: + s.log.Debug("Continuing cross-safe verification after hint of new data") + continue + case <-delay.C: + s.log.Debug("Checking for cross-safe updates") + continue + } + } +} + +func (s *Worker) OnNewData() { + // signal that we have something to process + select { + case s.poke <- struct{}{}: + default: + // already requested an update + } +} + +func (s *Worker) Close() { + s.cancel() + s.wg.Wait() +} diff --git a/op-supervisor/supervisor/backend/cross/worker_test.go b/op-supervisor/supervisor/backend/cross/worker_test.go new file mode 100644 index 0000000000000..6f9d543fde1aa --- /dev/null +++ b/op-supervisor/supervisor/backend/cross/worker_test.go @@ -0,0 +1,107 @@ +package cross + +import ( + "context" + "sync/atomic" + "testing" + "time" + + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" +) + +func TestWorker(t *testing.T) { + logger := testlog.Logger(t, log.LevelDebug) + t.Run("do work", func(t *testing.T) { + var count int32 + w := NewWorker(logger, func(ctx context.Context) error { + atomic.AddInt32(&count, 1) + return nil + }) + t.Cleanup(w.Close) + // when ProcessWork is called, the workFn is called once + require.NoError(t, w.ProcessWork()) + require.EqualValues(t, 1, atomic.LoadInt32(&count)) + }) + t.Run("background worker", func(t *testing.T) { + var count int32 + w := NewWorker(logger, func(ctx context.Context) error { + atomic.AddInt32(&count, 1) + return nil + }) + t.Cleanup(w.Close) + // set a long poll duration so the worker does not auto-run + w.pollDuration = 100 * time.Second + // when StartBackground is called, the worker runs in the background + // the count should increment once + w.StartBackground() + require.Eventually(t, func() bool { + return atomic.LoadInt32(&count) == 1 + }, 2*time.Second, 100*time.Millisecond) + }) + t.Run("background worker OnNewData", func(t *testing.T) { + var count int32 + w := NewWorker(logger, func(ctx context.Context) error { + atomic.AddInt32(&count, 1) + return nil + }) + t.Cleanup(w.Close) + // set a long poll duration so the worker does not auto-run + w.pollDuration = 100 * time.Second + // when StartBackground is called, the worker runs in the background + // the count should increment once + w.StartBackground() + require.Eventually(t, func() bool { + return atomic.LoadInt32(&count) == 1 + }, 2*time.Second, 100*time.Millisecond) + // when OnNewData is called, the worker runs again + w.OnNewData() + require.Eventually(t, func() bool { + return atomic.LoadInt32(&count) == 2 + }, 2*time.Second, 100*time.Millisecond) + // and due to the long poll duration, the worker does not run again + require.Never(t, func() bool { + return atomic.LoadInt32(&count) > 2 + }, time.Second, 100*time.Millisecond) + }) + t.Run("background fast poll", func(t *testing.T) { + var count int32 + w := NewWorker(logger, func(ctx context.Context) error { + atomic.AddInt32(&count, 1) + return nil + }) + t.Cleanup(w.Close) + // set a long poll duration so the worker does not auto-run + w.pollDuration = 100 * time.Millisecond + // when StartBackground is called, the worker runs in the background + // the count should increment rapidly and reach at least 10 in 1 second + w.StartBackground() + require.Eventually(t, func() bool { + return atomic.LoadInt32(&count) >= 10 + }, 2*time.Second, 100*time.Millisecond) + }) + t.Run("close", func(t *testing.T) { + var count int32 + w := NewWorker(logger, func(ctx context.Context) error { + atomic.AddInt32(&count, 1) + return nil + }) + t.Cleanup(w.Close) // close on cleanup in case of early error + // set a long poll duration so the worker does not auto-run + w.pollDuration = 100 * time.Millisecond + // when StartBackground is called, the worker runs in the background + // the count should increment rapidly and reach at least 10 in 1 second + w.StartBackground() + require.Eventually(t, func() bool { + return atomic.LoadInt32(&count) >= 10 + }, 10*time.Second, time.Second) + // once the worker is closed, it stops running + // and the count does not increment + w.Close() + stopCount := atomic.LoadInt32(&count) + require.Never(t, func() bool { + return atomic.LoadInt32(&count) != stopCount + }, time.Second, 100*time.Millisecond) + }) +} diff --git a/op-supervisor/supervisor/backend/db/db.go b/op-supervisor/supervisor/backend/db/db.go index ab8a9a652e5ba..b667718759b79 100644 --- a/op-supervisor/supervisor/backend/db/db.go +++ b/op-supervisor/supervisor/backend/db/db.go @@ -4,21 +4,18 @@ import ( "errors" "fmt" "io" - "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/log" "github.com/ethereum-optimism/optimism/op-service/eth" + "github.com/ethereum-optimism/optimism/op-service/locks" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/fromda" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/logs" + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/depset" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) -var ( - ErrUnknownChain = errors.New("unknown chain") -) - type LogStorage interface { io.Closer @@ -46,13 +43,22 @@ type LogStorage interface { // The block-seal of the blockNum block, that the log was included in, is returned. // This seal may be fully zeroed, without error, if the block isn't fully known yet. Contains(blockNum uint64, logIdx uint32, logHash common.Hash) (includedIn types.BlockSeal, err error) + + // OpenBlock accumulates the ExecutingMessage events for a block and returns them + OpenBlock(blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) } type LocalDerivedFromStorage interface { + First() (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) Latest() (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) AddDerived(derivedFrom eth.BlockRef, derived eth.BlockRef) error LastDerivedAt(derivedFrom eth.BlockID) (derived types.BlockSeal, err error) DerivedFrom(derived eth.BlockID) (derivedFrom types.BlockSeal, err error) + FirstAfter(derivedFrom, derived eth.BlockID) (nextDerivedFrom, nextDerived types.BlockSeal, err error) + NextDerivedFrom(derivedFrom eth.BlockID) (nextDerivedFrom types.BlockSeal, err error) + NextDerived(derived eth.BlockID) (derivedFrom types.BlockSeal, nextDerived types.BlockSeal, err error) + PreviousDerivedFrom(derivedFrom eth.BlockID) (prevDerivedFrom types.BlockSeal, err error) + PreviousDerived(derived eth.BlockID) (prevDerived types.BlockSeal, err error) } var _ LocalDerivedFromStorage = (*fromda.DB)(nil) @@ -65,118 +71,104 @@ type CrossDerivedFromStorage interface { var _ LogStorage = (*logs.DB)(nil) // ChainsDB is a database that stores logs and derived-from data for multiple chains. -// it implements the ChainsStorage interface. +// it implements the LogStorage interface, as well as several DB interfaces needed by the cross package. type ChainsDB struct { - // RW mutex: - // Read = chains can be read / mutated. - // Write = set of chains is changing. - mu sync.RWMutex - // unsafe info: the sequence of block seals and events - logDBs map[types.ChainID]LogStorage + logDBs locks.RWMap[types.ChainID, LogStorage] // cross-unsafe: how far we have processed the unsafe data. // If present but set to a zeroed value the cross-unsafe will fallback to cross-safe. - crossUnsafe map[types.ChainID]types.BlockSeal + crossUnsafe locks.RWMap[types.ChainID, *locks.RWValue[types.BlockSeal]] // local-safe: index of what we optimistically know about L2 blocks being derived from L1 - localDBs map[types.ChainID]LocalDerivedFromStorage + localDBs locks.RWMap[types.ChainID, LocalDerivedFromStorage] // cross-safe: index of L2 blocks we know to only have cross-L2 valid dependencies - crossDBs map[types.ChainID]CrossDerivedFromStorage + crossDBs locks.RWMap[types.ChainID, CrossDerivedFromStorage] // finalized: the L1 finality progress. This can be translated into what may be considered as finalized in L2. // It is initially zeroed, and the L2 finality query will return // an error until it has this L1 finality to work with. - finalizedL1 eth.L1BlockRef + finalizedL1 locks.RWValue[eth.L1BlockRef] + + // depSet is the dependency set, used to determine what may be tracked, + // what is missing, and to provide it to DB users. + depSet depset.DependencySet logger log.Logger } -func NewChainsDB(l log.Logger) *ChainsDB { +func NewChainsDB(l log.Logger, depSet depset.DependencySet) *ChainsDB { return &ChainsDB{ - logDBs: make(map[types.ChainID]LogStorage), - logger: l, - localDBs: make(map[types.ChainID]LocalDerivedFromStorage), - crossDBs: make(map[types.ChainID]CrossDerivedFromStorage), - crossUnsafe: make(map[types.ChainID]types.BlockSeal), + logger: l, + depSet: depSet, } } func (db *ChainsDB) AddLogDB(chainID types.ChainID, logDB LogStorage) { - db.mu.Lock() - defer db.mu.Unlock() - - if _, ok := db.logDBs[chainID]; ok { + if db.logDBs.Has(chainID) { db.logger.Warn("overwriting existing log DB for chain", "chain", chainID) } - db.logDBs[chainID] = logDB + db.logDBs.Set(chainID, logDB) } func (db *ChainsDB) AddLocalDerivedFromDB(chainID types.ChainID, dfDB LocalDerivedFromStorage) { - db.mu.Lock() - defer db.mu.Unlock() - - if _, ok := db.localDBs[chainID]; ok { + if db.localDBs.Has(chainID) { db.logger.Warn("overwriting existing local derived-from DB for chain", "chain", chainID) } - db.localDBs[chainID] = dfDB + db.localDBs.Set(chainID, dfDB) } func (db *ChainsDB) AddCrossDerivedFromDB(chainID types.ChainID, dfDB CrossDerivedFromStorage) { - db.mu.Lock() - defer db.mu.Unlock() - - if _, ok := db.crossDBs[chainID]; ok { + if db.crossDBs.Has(chainID) { db.logger.Warn("overwriting existing cross derived-from DB for chain", "chain", chainID) } - db.crossDBs[chainID] = dfDB + db.crossDBs.Set(chainID, dfDB) } func (db *ChainsDB) AddCrossUnsafeTracker(chainID types.ChainID) { - db.mu.Lock() - defer db.mu.Unlock() - - if _, ok := db.crossUnsafe[chainID]; ok { + if db.crossUnsafe.Has(chainID) { db.logger.Warn("overwriting existing cross-unsafe tracker for chain", "chain", chainID) } - db.crossUnsafe[chainID] = types.BlockSeal{} + db.crossUnsafe.Set(chainID, &locks.RWValue[types.BlockSeal]{}) } // ResumeFromLastSealedBlock prepares the chains db to resume recording events after a restart. // It rewinds the database to the last block that is guaranteed to have been fully recorded to the database, // to ensure it can resume recording from the first log of the next block. func (db *ChainsDB) ResumeFromLastSealedBlock() error { - db.mu.RLock() - defer db.mu.RUnlock() - - for chain, logStore := range db.logDBs { + var result error + db.logDBs.Range(func(chain types.ChainID, logStore LogStorage) bool { headNum, ok := logStore.LatestSealedBlockNum() if !ok { // db must be empty, nothing to rewind to db.logger.Info("Resuming, but found no DB contents", "chain", chain) - continue + return true } db.logger.Info("Resuming, starting from last sealed block", "head", headNum) if err := logStore.Rewind(headNum); err != nil { - return fmt.Errorf("failed to rewind chain %s to sealed block %d", chain, headNum) + result = fmt.Errorf("failed to rewind chain %s to sealed block %d", chain, headNum) + return false } - } - return nil + return true + }) + return result } -func (db *ChainsDB) Close() error { - db.mu.Lock() - defer db.mu.Unlock() +func (db *ChainsDB) DependencySet() depset.DependencySet { + return db.depSet +} +func (db *ChainsDB) Close() error { var combined error - for id, logDB := range db.logDBs { + db.logDBs.Range(func(id types.ChainID, logDB LogStorage) bool { if err := logDB.Close(); err != nil { combined = errors.Join(combined, fmt.Errorf("failed to close log db for chain %v: %w", id, err)) } - } + return true + }) return combined } diff --git a/op-supervisor/supervisor/backend/db/fromda/db.go b/op-supervisor/supervisor/backend/db/fromda/db.go index 7016fc6b25cb2..48d8564ced202 100644 --- a/op-supervisor/supervisor/backend/db/fromda/db.go +++ b/op-supervisor/supervisor/backend/db/fromda/db.go @@ -3,6 +3,7 @@ package fromda import ( "cmp" "fmt" + "io" "sort" "sync" @@ -64,12 +65,48 @@ func (db *DB) Rewind(derivedFrom uint64) error { return nil } +// First returns the first known values, alike to Latest. +func (db *DB) First() (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) { + db.rwLock.RLock() + defer db.rwLock.RUnlock() + lastIndex := db.store.LastEntryIdx() + if lastIndex < 0 { + return types.BlockSeal{}, types.BlockSeal{}, types.ErrFuture + } + last, err := db.readAt(0) + if err != nil { + return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("failed to read first derivation data: %w", err) + } + return last.derivedFrom, last.derived, nil +} + +func (db *DB) PreviousDerived(derived eth.BlockID) (prevDerived types.BlockSeal, err error) { + db.rwLock.RLock() + defer db.rwLock.RUnlock() + // get the last time this L2 block was seen. + selfIndex, self, err := db.firstDerivedFrom(derived.Number) + if err != nil { + return types.BlockSeal{}, fmt.Errorf("failed to find derived %d: %w", derived.Number, err) + } + if self.derived.ID() != derived { + return types.BlockSeal{}, fmt.Errorf("found %s, but expected %s: %w", self.derived, derived, types.ErrConflict) + } + if selfIndex == 0 { // genesis block has a zeroed block as parent block + return types.BlockSeal{}, nil + } + prev, err := db.readAt(selfIndex - 1) + if err != nil { + return types.BlockSeal{}, fmt.Errorf("cannot find previous derived before %s: %w", derived, err) + } + return prev.derived, nil +} + // Latest returns the last known values: // derivedFrom: the L1 block that the L2 block is safe for (not necessarily the first, multiple L2 blocks may be derived from the same L1 block). // derived: the L2 block that was derived (not necessarily the first, the L1 block may have been empty and repeated the last safe L2 block). func (db *DB) Latest() (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) { - db.rwLock.Lock() - defer db.rwLock.Unlock() + db.rwLock.RLock() + defer db.rwLock.RUnlock() return db.latest() } @@ -77,7 +114,7 @@ func (db *DB) Latest() (derivedFrom types.BlockSeal, derived types.BlockSeal, er func (db *DB) latest() (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) { lastIndex := db.store.LastEntryIdx() if lastIndex < 0 { - return types.BlockSeal{}, types.BlockSeal{}, entrydb.ErrFuture + return types.BlockSeal{}, types.BlockSeal{}, types.ErrFuture } last, err := db.readAt(lastIndex) if err != nil { @@ -96,11 +133,30 @@ func (db *DB) LastDerivedAt(derivedFrom eth.BlockID) (derived types.BlockSeal, e } if link.derivedFrom.ID() != derivedFrom { return types.BlockSeal{}, fmt.Errorf("searched for last derived-from %s but found %s: %w", - derivedFrom, link.derivedFrom, entrydb.ErrConflict) + derivedFrom, link.derivedFrom, types.ErrConflict) } return link.derived, nil } +// NextDerived finds the next L2 block after derived, and what it was derived from +func (db *DB) NextDerived(derived eth.BlockID) (derivedFrom types.BlockSeal, nextDerived types.BlockSeal, err error) { + db.rwLock.RLock() + defer db.rwLock.RUnlock() + // get the last time this L2 block was seen. + selfIndex, self, err := db.lastDerivedFrom(derived.Number) + if err != nil { + return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("failed to find derived %d: %w", derived.Number, err) + } + if self.derived.ID() != derived { + return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("found %s, but expected %s: %w", self.derived, derived, types.ErrConflict) + } + next, err := db.readAt(selfIndex + 1) + if err != nil { + return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("cannot find next derived after %s: %w", derived, err) + } + return next.derivedFrom, next.derived, nil +} + // DerivedFrom determines where a L2 block was first derived from. // (a L2 block may repeat if the following L1 blocks are empty and don't produce additional L2 blocks) func (db *DB) DerivedFrom(derived eth.BlockID) (derivedFrom types.BlockSeal, err error) { @@ -112,17 +168,100 @@ func (db *DB) DerivedFrom(derived eth.BlockID) (derivedFrom types.BlockSeal, err } if link.derived.ID() != derived { return types.BlockSeal{}, fmt.Errorf("searched for first derived %s but found %s: %w", - derived, link.derived, entrydb.ErrConflict) + derived, link.derived, types.ErrConflict) } return link.derivedFrom, nil } +func (db *DB) PreviousDerivedFrom(derivedFrom eth.BlockID) (prevDerivedFrom types.BlockSeal, err error) { + db.rwLock.RLock() + defer db.rwLock.RUnlock() + // get the last time this L1 block was seen. + selfIndex, self, err := db.firstDerivedAt(derivedFrom.Number) + if err != nil { + return types.BlockSeal{}, fmt.Errorf("failed to find derived %d: %w", derivedFrom.Number, err) + } + if self.derivedFrom.ID() != derivedFrom { + return types.BlockSeal{}, fmt.Errorf("found %s, but expected %s: %w", self.derivedFrom, derivedFrom, types.ErrConflict) + } + if selfIndex == 0 { + // genesis block has a zeroed block as parent block + if self.derivedFrom.Number == 0 { + return types.BlockSeal{}, nil + } else { + return types.BlockSeal{}, + fmt.Errorf("cannot find previous derived before start of database: %s (%w)", derivedFrom, types.ErrPreviousToFirst) + } + } + prev, err := db.readAt(selfIndex - 1) + if err != nil { + return types.BlockSeal{}, fmt.Errorf("cannot find previous derived before %s: %w", derivedFrom, err) + } + return prev.derivedFrom, nil +} + +// NextDerivedFrom finds the next L1 block after derivedFrom +func (db *DB) NextDerivedFrom(derivedFrom eth.BlockID) (nextDerivedFrom types.BlockSeal, err error) { + db.rwLock.RLock() + defer db.rwLock.RUnlock() + selfIndex, self, err := db.lastDerivedAt(derivedFrom.Number) + if err != nil { + return types.BlockSeal{}, fmt.Errorf("failed to find derived-from %d: %w", derivedFrom.Number, err) + } + if self.derivedFrom.ID() != derivedFrom { + return types.BlockSeal{}, fmt.Errorf("found %s, but expected %s: %w", self.derivedFrom, derivedFrom, types.ErrConflict) + } + next, err := db.readAt(selfIndex + 1) + if err != nil { + return types.BlockSeal{}, fmt.Errorf("cannot find next derived-from after %s: %w", derivedFrom, err) + } + return next.derivedFrom, nil +} + +// FirstAfter determines the next entry after the given pair of derivedFrom, derived. +// Either one or both of the two entries will be an increment by 1 +func (db *DB) FirstAfter(derivedFrom, derived eth.BlockID) (nextDerivedFrom, nextDerived types.BlockSeal, err error) { + db.rwLock.RLock() + defer db.rwLock.RUnlock() + selfIndex, selfLink, err := db.lookup(derivedFrom.Number, derived.Number) + if err != nil { + return types.BlockSeal{}, types.BlockSeal{}, err + } + if selfLink.derivedFrom.ID() != derivedFrom { + return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("DB has derived-from %s but expected %s: %w", selfLink.derivedFrom, derivedFrom, types.ErrConflict) + } + if selfLink.derived.ID() != derived { + return types.BlockSeal{}, types.BlockSeal{}, fmt.Errorf("DB has derived %s but expected %s: %w", selfLink.derived, derived, types.ErrConflict) + } + next, err := db.readAt(selfIndex + 1) + if err != nil { + return types.BlockSeal{}, types.BlockSeal{}, err + } + return next.derivedFrom, next.derived, nil +} + +func (db *DB) lastDerivedFrom(derived uint64) (entrydb.EntryIdx, LinkEntry, error) { + return db.find(true, func(link LinkEntry) int { + return cmp.Compare(derived, link.derived.Number) + }) +} + func (db *DB) firstDerivedFrom(derived uint64) (entrydb.EntryIdx, LinkEntry, error) { return db.find(false, func(link LinkEntry) int { return cmp.Compare(link.derived.Number, derived) }) } +func (db *DB) lookup(derivedFrom, derived uint64) (entrydb.EntryIdx, LinkEntry, error) { + return db.find(false, func(link LinkEntry) int { + res := cmp.Compare(link.derived.Number, derived) + if res == 0 { + return cmp.Compare(link.derivedFrom.Number, derivedFrom) + } + return res + }) +} + func (db *DB) lastDerivedAt(derivedFrom uint64) (entrydb.EntryIdx, LinkEntry, error) { // Reverse: prioritize the last entry. return db.find(true, func(link LinkEntry) int { @@ -130,13 +269,19 @@ func (db *DB) lastDerivedAt(derivedFrom uint64) (entrydb.EntryIdx, LinkEntry, er }) } +func (db *DB) firstDerivedAt(derivedFrom uint64) (entrydb.EntryIdx, LinkEntry, error) { + return db.find(false, func(link LinkEntry) int { + return cmp.Compare(link.derivedFrom.Number, derivedFrom) + }) +} + // find finds the first entry for which cmpFn(link) returns 0. // The cmpFn entries to the left should return -1, entries to the right 1. // If reverse, the cmpFn should be flipped too, and the last entry for which cmpFn(link) is 0 will be found. func (db *DB) find(reverse bool, cmpFn func(link LinkEntry) int) (entrydb.EntryIdx, LinkEntry, error) { n := db.store.Size() if n == 0 { - return -1, LinkEntry{}, entrydb.ErrFuture + return -1, LinkEntry{}, types.ErrFuture } var searchErr error // binary-search for the smallest index i for which cmp(i) >= 0 @@ -157,9 +302,9 @@ func (db *DB) find(reverse bool, cmpFn func(link LinkEntry) int) (entrydb.EntryI } if result == int(n) { if reverse { - return -1, LinkEntry{}, fmt.Errorf("no entry found: %w", entrydb.ErrSkipped) + return -1, LinkEntry{}, fmt.Errorf("no entry found: %w", types.ErrSkipped) } else { - return -1, LinkEntry{}, fmt.Errorf("no entry found: %w", entrydb.ErrFuture) + return -1, LinkEntry{}, fmt.Errorf("no entry found: %w", types.ErrFuture) } } if reverse { @@ -171,9 +316,9 @@ func (db *DB) find(reverse bool, cmpFn func(link LinkEntry) int) (entrydb.EntryI } if cmpFn(link) != 0 { if reverse { - return -1, LinkEntry{}, fmt.Errorf("lowest entry %s is too high: %w", link, entrydb.ErrFuture) + return -1, LinkEntry{}, fmt.Errorf("lowest entry %s is too high: %w", link, types.ErrFuture) } else { - return -1, LinkEntry{}, fmt.Errorf("lowest entry %s is too high: %w", link, entrydb.ErrSkipped) + return -1, LinkEntry{}, fmt.Errorf("lowest entry %s is too high: %w", link, types.ErrSkipped) } } if cmpFn(link) != 0 { @@ -187,6 +332,9 @@ func (db *DB) find(reverse bool, cmpFn func(link LinkEntry) int) (entrydb.EntryI func (db *DB) readAt(i entrydb.EntryIdx) (LinkEntry, error) { entry, err := db.store.Read(i) if err != nil { + if err == io.EOF { + return LinkEntry{}, types.ErrFuture + } return LinkEntry{}, err } var out LinkEntry diff --git a/op-supervisor/supervisor/backend/db/fromda/db_test.go b/op-supervisor/supervisor/backend/db/fromda/db_test.go index bfc44ec00aaa0..8d6a273e1f986 100644 --- a/op-supervisor/supervisor/backend/db/fromda/db_test.go +++ b/op-supervisor/supervisor/backend/db/fromda/db_test.go @@ -15,7 +15,6 @@ import ( "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/testlog" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/entrydb" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -74,16 +73,31 @@ func TestEmptyDB(t *testing.T) { func(t *testing.T, db *DB, m *stubMetrics) {}, func(t *testing.T, db *DB, m *stubMetrics) { _, _, err := db.Latest() - require.ErrorIs(t, err, entrydb.ErrFuture) + require.ErrorIs(t, err, types.ErrFuture) - _, _, err = db.Latest() - require.ErrorIs(t, err, entrydb.ErrFuture) + _, _, err = db.First() + require.ErrorIs(t, err, types.ErrFuture) _, err = db.LastDerivedAt(eth.BlockID{}) - require.ErrorIs(t, err, entrydb.ErrFuture) + require.ErrorIs(t, err, types.ErrFuture) _, err = db.DerivedFrom(eth.BlockID{}) - require.ErrorIs(t, err, entrydb.ErrFuture) + require.ErrorIs(t, err, types.ErrFuture) + + _, err = db.PreviousDerived(eth.BlockID{}) + require.ErrorIs(t, err, types.ErrFuture) + + _, _, err = db.NextDerived(eth.BlockID{}) + require.ErrorIs(t, err, types.ErrFuture) + + _, err = db.PreviousDerivedFrom(eth.BlockID{}) + require.ErrorIs(t, err, types.ErrFuture) + + _, err = db.NextDerivedFrom(eth.BlockID{}) + require.ErrorIs(t, err, types.ErrFuture) + + _, _, err = db.FirstAfter(eth.BlockID{}, eth.BlockID{}) + require.ErrorIs(t, err, types.ErrFuture) }) } @@ -117,35 +131,96 @@ func toRef(seal types.BlockSeal, parentHash common.Hash) eth.BlockRef { } func TestSingleEntryDB(t *testing.T) { - expectedDerivedFrom := mockL1(1) + expectedDerivedFrom := mockL1(0) expectedDerived := mockL2(2) runDBTest(t, func(t *testing.T, db *DB, m *stubMetrics) { require.NoError(t, db.AddDerived(toRef(expectedDerivedFrom, mockL1(0).Hash), toRef(expectedDerived, mockL2(0).Hash))) }, func(t *testing.T, db *DB, m *stubMetrics) { - derivedFrom, derived, err := db.Latest() + // First + derivedFrom, derived, err := db.First() require.NoError(t, err) require.Equal(t, expectedDerivedFrom, derivedFrom) require.Equal(t, expectedDerived, derived) + // Latest + derivedFrom, derived, err = db.Latest() + require.NoError(t, err) + require.Equal(t, expectedDerivedFrom, derivedFrom) + require.Equal(t, expectedDerived, derived) + + // FirstAfter Latest + _, _, err = db.FirstAfter(derivedFrom.ID(), derived.ID()) + require.ErrorIs(t, err, types.ErrFuture) + + // LastDerivedAt derived, err = db.LastDerivedAt(expectedDerivedFrom.ID()) require.NoError(t, err) require.Equal(t, expectedDerived, derived) + // LastDerivedAt with a non-existent block _, err = db.LastDerivedAt(eth.BlockID{Hash: common.Hash{0xaa}, Number: expectedDerivedFrom.Number}) - require.ErrorIs(t, err, entrydb.ErrConflict) + require.ErrorIs(t, err, types.ErrConflict) + + // FirstAfter with a non-existent block (derived and derivedFrom) + _, _, err = db.FirstAfter(eth.BlockID{Hash: common.Hash{0xaa}, Number: expectedDerivedFrom.Number}, expectedDerived.ID()) + require.ErrorIs(t, err, types.ErrConflict) + _, _, err = db.FirstAfter(expectedDerivedFrom.ID(), eth.BlockID{Hash: common.Hash{0xaa}, Number: expectedDerived.Number}) + require.ErrorIs(t, err, types.ErrConflict) + // DerivedFrom derivedFrom, err = db.DerivedFrom(expectedDerived.ID()) require.NoError(t, err) require.Equal(t, expectedDerivedFrom, derivedFrom) + // DerivedFrom with a non-existent block _, err = db.DerivedFrom(eth.BlockID{Hash: common.Hash{0xbb}, Number: expectedDerived.Number}) - require.ErrorIs(t, err, entrydb.ErrConflict) + require.ErrorIs(t, err, types.ErrConflict) + + // PreviousDerived + prev, err := db.PreviousDerived(expectedDerived.ID()) + require.NoError(t, err) + require.Equal(t, types.BlockSeal{}, prev, "zeroed seal before first entry") + + // PreviousDerivedFrom + prev, err = db.PreviousDerivedFrom(expectedDerivedFrom.ID()) + require.NoError(t, err) + require.Equal(t, types.BlockSeal{}, prev, "zeroed seal before first entry") + + // NextDerived + _, _, err = db.NextDerived(expectedDerived.ID()) + require.ErrorIs(t, err, types.ErrFuture) + + // NextDerivedFrom + _, err = db.NextDerivedFrom(expectedDerivedFrom.ID()) + require.ErrorIs(t, err, types.ErrFuture) + + // FirstAfter + _, _, err = db.FirstAfter(expectedDerivedFrom.ID(), expectedDerived.ID()) + require.ErrorIs(t, err, types.ErrFuture) + }) +} + +func TestGap(t *testing.T) { + // mockL1 starts at block 1 to produce a gap + expectedDerivedFrom := mockL1(1) + // mockL2 starts at block 2 to produce a gap + expectedDerived := mockL2(2) + runDBTest(t, + func(t *testing.T, db *DB, m *stubMetrics) { + require.NoError(t, db.AddDerived(toRef(expectedDerivedFrom, mockL1(0).Hash), toRef(expectedDerived, mockL2(0).Hash))) + }, + func(t *testing.T, db *DB, m *stubMetrics) { + _, _, err := db.NextDerived(mockL2(0).ID()) + require.ErrorIs(t, err, types.ErrSkipped) + + _, err = db.NextDerivedFrom(mockL1(0).ID()) + require.ErrorIs(t, err, types.ErrSkipped) }) } -func TestTwoEntryDB(t *testing.T) { +func TestThreeEntryDB(t *testing.T) { l1Block0 := mockL1(0) l1Block1 := mockL1(1) l1Block2 := mockL1(2) @@ -165,19 +240,24 @@ func TestTwoEntryDB(t *testing.T) { require.Equal(t, l1Block2, derivedFrom) require.Equal(t, l2Block2, derived) + derivedFrom, derived, err = db.First() + require.NoError(t, err) + require.Equal(t, l1Block0, derivedFrom) + require.Equal(t, l2Block0, derived) + derived, err = db.LastDerivedAt(l1Block2.ID()) require.NoError(t, err) require.Equal(t, l2Block2, derived) _, err = db.LastDerivedAt(eth.BlockID{Hash: common.Hash{0xaa}, Number: l1Block2.Number}) - require.ErrorIs(t, err, entrydb.ErrConflict) + require.ErrorIs(t, err, types.ErrConflict) derivedFrom, err = db.DerivedFrom(l2Block2.ID()) require.NoError(t, err) require.Equal(t, l1Block2, derivedFrom) _, err = db.DerivedFrom(eth.BlockID{Hash: common.Hash{0xbb}, Number: l2Block2.Number}) - require.ErrorIs(t, err, entrydb.ErrConflict) + require.ErrorIs(t, err, types.ErrConflict) derived, err = db.LastDerivedAt(l1Block1.ID()) require.NoError(t, err) @@ -194,6 +274,67 @@ func TestTwoEntryDB(t *testing.T) { derivedFrom, err = db.DerivedFrom(l2Block0.ID()) require.NoError(t, err) require.Equal(t, l1Block0, derivedFrom) + + derived, err = db.PreviousDerived(l2Block0.ID()) + require.NoError(t, err) + require.Equal(t, types.BlockSeal{}, derived) + + derived, err = db.PreviousDerived(l2Block1.ID()) + require.NoError(t, err) + require.Equal(t, l2Block0, derived) + + derived, err = db.PreviousDerived(l2Block2.ID()) + require.NoError(t, err) + require.Equal(t, l2Block1, derived) + + derivedFrom, derived, err = db.NextDerived(l2Block0.ID()) + require.NoError(t, err) + require.Equal(t, l2Block1, derived) + require.Equal(t, l1Block1, derivedFrom) + + derivedFrom, derived, err = db.NextDerived(l2Block1.ID()) + require.NoError(t, err) + require.Equal(t, l2Block2, derived) + require.Equal(t, l1Block2, derivedFrom) + + _, _, err = db.NextDerived(l2Block2.ID()) + require.ErrorIs(t, err, types.ErrFuture) + + derivedFrom, err = db.PreviousDerivedFrom(l1Block0.ID()) + require.NoError(t, err) + require.Equal(t, types.BlockSeal{}, derivedFrom) + + derivedFrom, err = db.PreviousDerivedFrom(l1Block1.ID()) + require.NoError(t, err) + require.Equal(t, l1Block0, derivedFrom) + + derivedFrom, err = db.PreviousDerivedFrom(l1Block2.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) + + derivedFrom, err = db.NextDerivedFrom(l1Block0.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) + + derivedFrom, err = db.NextDerivedFrom(l1Block1.ID()) + require.NoError(t, err) + require.Equal(t, l1Block2, derivedFrom) + + _, err = db.NextDerivedFrom(l1Block2.ID()) + require.ErrorIs(t, err, types.ErrFuture) + + _, _, err = db.FirstAfter(l1Block2.ID(), l2Block2.ID()) + require.ErrorIs(t, err, types.ErrFuture) + + derivedFrom, derived, err = db.FirstAfter(l1Block0.ID(), l2Block0.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) + require.Equal(t, l2Block1, derived) + + derivedFrom, derived, err = db.FirstAfter(l1Block1.ID(), l2Block1.ID()) + require.NoError(t, err) + require.Equal(t, l1Block2, derivedFrom) + require.Equal(t, l2Block2, derived) }) } @@ -249,6 +390,65 @@ func TestFastL2Batcher(t *testing.T) { require.NoError(t, err) require.Equal(t, l2Block4, derived) + derived, err = db.PreviousDerived(l2Block5.ID()) + require.NoError(t, err) + require.Equal(t, l2Block4, derived) + derived, err = db.PreviousDerived(l2Block4.ID()) + require.NoError(t, err) + require.Equal(t, l2Block3, derived) + derived, err = db.PreviousDerived(l2Block3.ID()) + require.NoError(t, err) + require.Equal(t, l2Block2, derived) + derived, err = db.PreviousDerived(l2Block2.ID()) + require.NoError(t, err) + require.Equal(t, l2Block1, derived) + derived, err = db.PreviousDerived(l2Block1.ID()) + require.NoError(t, err) + require.Equal(t, l2Block0, derived) + + derivedFrom, derived, err = db.NextDerived(l2Block0.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) + require.Equal(t, l2Block1, derived) + derivedFrom, derived, err = db.NextDerived(l2Block1.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) + require.Equal(t, l2Block2, derived) + derivedFrom, derived, err = db.NextDerived(l2Block2.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) + require.Equal(t, l2Block3, derived) + derivedFrom, derived, err = db.NextDerived(l2Block3.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) + require.Equal(t, l2Block4, derived) + derivedFrom, derived, err = db.NextDerived(l2Block4.ID()) + require.NoError(t, err) + require.Equal(t, l1Block2, derivedFrom) // derived from later L1 block + require.Equal(t, l2Block5, derived) + _, _, err = db.NextDerived(l2Block5.ID()) + require.ErrorIs(t, err, types.ErrFuture) + + derivedFrom, err = db.PreviousDerivedFrom(l1Block2.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) + derivedFrom, err = db.PreviousDerivedFrom(l1Block1.ID()) + require.NoError(t, err) + require.Equal(t, l1Block0, derivedFrom) + + derivedFrom, err = db.NextDerivedFrom(l1Block0.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) + derivedFrom, err = db.NextDerivedFrom(l1Block1.ID()) + require.NoError(t, err) + require.Equal(t, l1Block2, derivedFrom) + _, err = db.NextDerivedFrom(l1Block2.ID()) + require.ErrorIs(t, err, types.ErrFuture) + + derivedFrom, derived, err = db.FirstAfter(l1Block1.ID(), l2Block2.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) // no increment in L1 yet, the next after is L2 block 3 + require.Equal(t, l2Block3, derived) }) } @@ -299,6 +499,60 @@ func TestSlowL2Batcher(t *testing.T) { derivedFrom, err = db.DerivedFrom(l2Block1.ID()) require.NoError(t, err) require.Equal(t, l1Block1, derivedFrom) + + derived, err = db.PreviousDerived(l2Block2.ID()) + require.NoError(t, err) + require.Equal(t, l2Block1, derived) + derived, err = db.PreviousDerived(l2Block1.ID()) + require.NoError(t, err) + require.Equal(t, l2Block0, derived) + + derivedFrom, derived, err = db.NextDerived(l2Block0.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) + require.Equal(t, l2Block1, derived) + derivedFrom, derived, err = db.NextDerived(l2Block1.ID()) + require.NoError(t, err) + require.Equal(t, l1Block5, derivedFrom) + require.Equal(t, l2Block2, derived) + _, _, err = db.NextDerived(l2Block2.ID()) + require.ErrorIs(t, err, types.ErrFuture) + + derivedFrom, err = db.PreviousDerivedFrom(l1Block5.ID()) + require.NoError(t, err) + require.Equal(t, l1Block4, derivedFrom) + derivedFrom, err = db.PreviousDerivedFrom(l1Block4.ID()) + require.NoError(t, err) + require.Equal(t, l1Block3, derivedFrom) + derivedFrom, err = db.PreviousDerivedFrom(l1Block3.ID()) + require.NoError(t, err) + require.Equal(t, l1Block2, derivedFrom) + derivedFrom, err = db.PreviousDerivedFrom(l1Block2.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) + derivedFrom, err = db.PreviousDerivedFrom(l1Block1.ID()) + require.NoError(t, err) + require.Equal(t, l1Block0, derivedFrom) + + derivedFrom, err = db.NextDerivedFrom(l1Block0.ID()) + require.NoError(t, err) + require.Equal(t, l1Block1, derivedFrom) + derivedFrom, err = db.NextDerivedFrom(l1Block1.ID()) + require.NoError(t, err) + require.Equal(t, l1Block2, derivedFrom) + derivedFrom, err = db.NextDerivedFrom(l1Block2.ID()) + require.NoError(t, err) + require.Equal(t, l1Block3, derivedFrom) + derivedFrom, err = db.NextDerivedFrom(l1Block4.ID()) + require.NoError(t, err) + require.Equal(t, l1Block5, derivedFrom) + _, err = db.NextDerivedFrom(l1Block5.ID()) + require.ErrorIs(t, err, types.ErrFuture) + + derivedFrom, derived, err = db.FirstAfter(l1Block2.ID(), l2Block1.ID()) + require.NoError(t, err) + require.Equal(t, l1Block3, derivedFrom) + require.Equal(t, l2Block1, derived) // no increment in L2 yet, the next after is L1 block 3 }) } @@ -378,17 +632,17 @@ func testManyEntryDB(t *testing.T, offsetL1 uint64, offsetL2 uint64) { // if not started at genesis, try to read older data, assert it's unavailable. if offsetL1 > 0 { _, err := db.LastDerivedAt(mockL1(0).ID()) - require.ErrorIs(t, err, entrydb.ErrSkipped) + require.ErrorIs(t, err, types.ErrSkipped) _, err = db.LastDerivedAt(mockL1(offsetL1 - 1).ID()) - require.ErrorIs(t, err, entrydb.ErrSkipped) + require.ErrorIs(t, err, types.ErrSkipped) } if offsetL2 > 0 { _, err := db.DerivedFrom(mockL2(0).ID()) - require.ErrorIs(t, err, entrydb.ErrSkipped) + require.ErrorIs(t, err, types.ErrSkipped) _, err = db.DerivedFrom(mockL2(offsetL2 - 1).ID()) - require.ErrorIs(t, err, entrydb.ErrSkipped) + require.ErrorIs(t, err, types.ErrSkipped) } }) } @@ -425,7 +679,7 @@ func TestRewind(t *testing.T) { require.Equal(t, l2Block2, derived) // Rewind to the future - require.ErrorIs(t, db.Rewind(6), entrydb.ErrFuture) + require.ErrorIs(t, db.Rewind(6), types.ErrFuture) // Rewind to the exact block we're at require.NoError(t, db.Rewind(l1Block5.Number)) diff --git a/op-supervisor/supervisor/backend/db/fromda/entry.go b/op-supervisor/supervisor/backend/db/fromda/entry.go index 651643b4eb433..4e4f9876d3e8e 100644 --- a/op-supervisor/supervisor/backend/db/fromda/entry.go +++ b/op-supervisor/supervisor/backend/db/fromda/entry.go @@ -5,7 +5,6 @@ import ( "fmt" "io" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/entrydb" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -57,10 +56,10 @@ func (d LinkEntry) String() string { func (d *LinkEntry) decode(e Entry) error { if e.Type() != DerivedFromV0 { - return fmt.Errorf("%w: unexpected entry type: %s", entrydb.ErrDataCorruption, e.Type()) + return fmt.Errorf("%w: unexpected entry type: %s", types.ErrDataCorruption, e.Type()) } if [3]byte(e[1:4]) != ([3]byte{}) { - return fmt.Errorf("%w: expected empty data, to pad entry size to round number: %x", entrydb.ErrDataCorruption, e[1:4]) + return fmt.Errorf("%w: expected empty data, to pad entry size to round number: %x", types.ErrDataCorruption, e[1:4]) } offset := 4 d.derivedFrom.Number = binary.BigEndian.Uint64(e[offset : offset+8]) diff --git a/op-supervisor/supervisor/backend/db/fromda/update.go b/op-supervisor/supervisor/backend/db/fromda/update.go index 07174cb8495a8..146e558cf2661 100644 --- a/op-supervisor/supervisor/backend/db/fromda/update.go +++ b/op-supervisor/supervisor/backend/db/fromda/update.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/entrydb" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -60,19 +59,19 @@ func (db *DB) AddDerived(derivedFrom eth.BlockRef, derived eth.BlockRef) error { // I.e. we encountered an empty L1 block, and the same L2 block continues to be the last block that was derived from it. if lastDerived.Hash != derived.Hash { return fmt.Errorf("derived block %s conflicts with known derived block %s at same height: %w", - derived, lastDerived, entrydb.ErrConflict) + derived, lastDerived, types.ErrConflict) } } else if lastDerived.Number+1 == derived.Number { if lastDerived.Hash != derived.ParentHash { return fmt.Errorf("derived block %s (parent %s) does not build on %s: %w", - derived, derived.ParentHash, lastDerived, entrydb.ErrConflict) + derived, derived.ParentHash, lastDerived, types.ErrConflict) } } else if lastDerived.Number+1 < derived.Number { return fmt.Errorf("derived block %s (parent: %s) is too new, expected to build on top of %s: %w", - derived, derived.ParentHash, lastDerived, entrydb.ErrOutOfOrder) + derived, derived.ParentHash, lastDerived, types.ErrOutOfOrder) } else { return fmt.Errorf("derived block %s is older than current derived block %s: %w", - derived, lastDerived, entrydb.ErrOutOfOrder) + derived, lastDerived, types.ErrOutOfOrder) } // Check derived-from relation: multiple L2 blocks may be derived from the same L1 block. But everything in sequence. @@ -80,22 +79,22 @@ func (db *DB) AddDerived(derivedFrom eth.BlockRef, derived eth.BlockRef) error { // Same block height? Then it must be the same block. if lastDerivedFrom.Hash != derivedFrom.Hash { return fmt.Errorf("cannot add block %s as derived from %s, expected to be derived from %s at this block height: %w", - derived, derivedFrom, lastDerivedFrom, entrydb.ErrConflict) + derived, derivedFrom, lastDerivedFrom, types.ErrConflict) } } else if lastDerivedFrom.Number+1 == derivedFrom.Number { // parent hash check if lastDerivedFrom.Hash != derivedFrom.ParentHash { return fmt.Errorf("cannot add block %s as derived from %s (parent %s) derived on top of %s: %w", - derived, derivedFrom, derivedFrom.ParentHash, lastDerivedFrom, entrydb.ErrConflict) + derived, derivedFrom, derivedFrom.ParentHash, lastDerivedFrom, types.ErrConflict) } } else if lastDerivedFrom.Number+1 < derivedFrom.Number { // adding block that is derived from something too far into the future return fmt.Errorf("cannot add block %s as derived from %s, still deriving from %s: %w", - derived, derivedFrom, lastDerivedFrom, entrydb.ErrOutOfOrder) + derived, derivedFrom, lastDerivedFrom, types.ErrOutOfOrder) } else { // adding block that is derived from something too old return fmt.Errorf("cannot add block %s as derived from %s, deriving already at %s: %w", - derived, derivedFrom, lastDerivedFrom, entrydb.ErrOutOfOrder) + derived, derivedFrom, lastDerivedFrom, types.ErrOutOfOrder) } link := LinkEntry{ diff --git a/op-supervisor/supervisor/backend/db/fromda/update_test.go b/op-supervisor/supervisor/backend/db/fromda/update_test.go index 72141947110ec..10b6b3bdd0533 100644 --- a/op-supervisor/supervisor/backend/db/fromda/update_test.go +++ b/op-supervisor/supervisor/backend/db/fromda/update_test.go @@ -7,7 +7,6 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/entrydb" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -42,14 +41,14 @@ func TestBadUpdates(t *testing.T) { { name: "add on old derivedFrom", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { - require.ErrorIs(t, db.AddDerived(toRef(bDerivedFrom, aDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)), entrydb.ErrOutOfOrder) + require.ErrorIs(t, db.AddDerived(toRef(bDerivedFrom, aDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)), types.ErrOutOfOrder) }, assertFn: noChange, }, { name: "repeat parent derivedFrom", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { - require.ErrorIs(t, db.AddDerived(toRef(cDerivedFrom, bDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)), entrydb.ErrOutOfOrder) + require.ErrorIs(t, db.AddDerived(toRef(cDerivedFrom, bDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)), types.ErrOutOfOrder) }, assertFn: noChange, }, @@ -60,14 +59,14 @@ func TestBadUpdates(t *testing.T) { Hash: common.Hash{0xba, 0xd}, Number: dDerivedFrom.Number, Timestamp: dDerivedFrom.Timestamp, - }, cDerivedFrom.Hash), toRef(eDerived, dDerived.Hash)), entrydb.ErrConflict) + }, cDerivedFrom.Hash), toRef(eDerived, dDerived.Hash)), types.ErrConflict) }, assertFn: noChange, }, { - name: "DerivedFrom with conflicting parent root, same L1 height, new L2: accepted, L1 parent-hash is used only on L1 increments.", + name: "CrossDerivedFrom with conflicting parent root, same L1 height, new L2: accepted, L1 parent-hash is used only on L1 increments.", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { - require.NoError(t, db.AddDerived(toRef(dDerivedFrom, common.Hash{0x42}), toRef(eDerived, dDerived.Hash)), entrydb.ErrConflict) + require.NoError(t, db.AddDerived(toRef(dDerivedFrom, common.Hash{0x42}), toRef(eDerived, dDerived.Hash)), types.ErrConflict) }, assertFn: func(t *testing.T, db *DB, m *stubMetrics) { derivedFrom, derived, err := db.Latest() @@ -79,28 +78,28 @@ func TestBadUpdates(t *testing.T) { { name: "Conflicting derivedFrom parent root, new L1 height, same L2", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { - require.ErrorIs(t, db.AddDerived(toRef(eDerivedFrom, common.Hash{0x42}), toRef(dDerived, cDerived.Hash)), entrydb.ErrConflict) + require.ErrorIs(t, db.AddDerived(toRef(eDerivedFrom, common.Hash{0x42}), toRef(dDerived, cDerived.Hash)), types.ErrConflict) }, assertFn: noChange, }, { name: "add on too new derivedFrom (even if parent-hash looks correct)", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { - require.ErrorIs(t, db.AddDerived(toRef(fDerivedFrom, dDerivedFrom.Hash), toRef(eDerived, dDerived.Hash)), entrydb.ErrOutOfOrder) + require.ErrorIs(t, db.AddDerived(toRef(fDerivedFrom, dDerivedFrom.Hash), toRef(eDerived, dDerived.Hash)), types.ErrOutOfOrder) }, assertFn: noChange, }, { name: "add on old derivedFrom (even if parent-hash looks correct)", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { - require.ErrorIs(t, db.AddDerived(toRef(cDerivedFrom, bDerivedFrom.Hash), toRef(cDerived, dDerived.Hash)), entrydb.ErrOutOfOrder) + require.ErrorIs(t, db.AddDerived(toRef(cDerivedFrom, bDerivedFrom.Hash), toRef(cDerived, dDerived.Hash)), types.ErrOutOfOrder) }, assertFn: noChange, }, { name: "add on even older derivedFrom", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { - require.ErrorIs(t, db.AddDerived(toRef(bDerivedFrom, aDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)), entrydb.ErrOutOfOrder) + require.ErrorIs(t, db.AddDerived(toRef(bDerivedFrom, aDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)), types.ErrOutOfOrder) }, assertFn: noChange, }, @@ -111,14 +110,14 @@ func TestBadUpdates(t *testing.T) { Hash: common.Hash{0x42}, Number: dDerived.Number, Timestamp: dDerived.Timestamp, - }, cDerived.Hash)), entrydb.ErrConflict) + }, cDerived.Hash)), types.ErrConflict) }, assertFn: noChange, }, { name: "add derived with conflicting parent hash, new L1 height, same L2 height: accepted, L2 parent-hash is only checked on L2 increments.", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { - require.NoError(t, db.AddDerived(toRef(eDerivedFrom, dDerivedFrom.Hash), toRef(dDerived, common.Hash{0x42})), entrydb.ErrConflict) + require.NoError(t, db.AddDerived(toRef(eDerivedFrom, dDerivedFrom.Hash), toRef(dDerived, common.Hash{0x42})), types.ErrConflict) }, assertFn: func(t *testing.T, db *DB, m *stubMetrics) { derivedFrom, derived, err := db.Latest() @@ -130,28 +129,28 @@ func TestBadUpdates(t *testing.T) { { name: "add derived with conflicting parent hash, same L1 height, new L2 height", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { - require.ErrorIs(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(eDerived, common.Hash{0x42})), entrydb.ErrConflict) + require.ErrorIs(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(eDerived, common.Hash{0x42})), types.ErrConflict) }, assertFn: noChange, }, { name: "add on too new derived (even if parent-hash looks correct)", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { - require.ErrorIs(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(fDerived, dDerived.Hash)), entrydb.ErrOutOfOrder) + require.ErrorIs(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(fDerived, dDerived.Hash)), types.ErrOutOfOrder) }, assertFn: noChange, }, { name: "add on old derived (even if parent-hash looks correct)", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { - require.ErrorIs(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(cDerived, bDerived.Hash)), entrydb.ErrOutOfOrder) + require.ErrorIs(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(cDerived, bDerived.Hash)), types.ErrOutOfOrder) }, assertFn: noChange, }, { name: "add on even older derived", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { - require.ErrorIs(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(bDerived, aDerived.Hash)), entrydb.ErrOutOfOrder) + require.ErrorIs(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(bDerived, aDerived.Hash)), types.ErrOutOfOrder) }, assertFn: noChange, }, @@ -159,7 +158,7 @@ func TestBadUpdates(t *testing.T) { name: "repeat self, silent no-op", setupFn: func(t *testing.T, db *DB, m *stubMetrics) { pre := m.DBDerivedEntryCount - require.NoError(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)), entrydb.ErrOutOfOrder) + require.NoError(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)), types.ErrOutOfOrder) require.Equal(t, pre, m.DBDerivedEntryCount) }, assertFn: noChange, diff --git a/op-supervisor/supervisor/backend/db/logs/db.go b/op-supervisor/supervisor/backend/db/logs/db.go index 0094997550595..64e61c6bebf76 100644 --- a/op-supervisor/supervisor/backend/db/logs/db.go +++ b/op-supervisor/supervisor/backend/db/logs/db.go @@ -139,8 +139,8 @@ func (db *DB) FindSealedBlock(number uint64) (seal types.BlockSeal, err error) { db.rwLock.RLock() defer db.rwLock.RUnlock() iter, err := db.newIteratorAt(number, 0) - if errors.Is(err, entrydb.ErrFuture) { - return types.BlockSeal{}, fmt.Errorf("block %d is not known yet: %w", number, entrydb.ErrFuture) + if errors.Is(err, types.ErrFuture) { + return types.BlockSeal{}, fmt.Errorf("block %d is not known yet: %w", number, types.ErrFuture) } else if err != nil { return types.BlockSeal{}, fmt.Errorf("failed to find sealed block %d: %w", number, err) } @@ -162,6 +162,89 @@ func (db *DB) FindSealedBlock(number uint64) (seal types.BlockSeal, err error) { }, nil } +// StartingBlock returns the first block seal in the DB, if any. +func (db *DB) StartingBlock() (seal types.BlockSeal, err error) { + db.rwLock.RLock() + defer db.rwLock.RUnlock() + iter := db.newIterator(0) + if err := iter.NextBlock(); err != nil { + return types.BlockSeal{}, err + } + h, n, _ := iter.SealedBlock() + t, _ := iter.SealedTimestamp() + return types.BlockSeal{ + Hash: h, + Number: n, + Timestamp: t, + }, err +} + +// OpenBlock returns the Executing Messages for the block at the given number. +// it returns identification of the block, the parent block, and the executing messages. +func (db *DB) OpenBlock(blockNum uint64) (ref eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, retErr error) { + db.rwLock.RLock() + defer db.rwLock.RUnlock() + + if blockNum == 0 { + seal, err := db.StartingBlock() + if err != nil { + retErr = err + return + } + ref = eth.BlockRef{ + Hash: seal.Hash, + Number: seal.Number, + ParentHash: common.Hash{}, + Time: seal.Timestamp, + } + logCount = 0 + execMsgs = nil + return + } + + // start at the first log (if any) after the block-seal of the parent block + blockIter, err := db.newIteratorAt(blockNum-1, 0) + if err != nil { + retErr = err + return + } + // register the parent block + parentHash, _, ok := blockIter.SealedBlock() + if ok { + ref.ParentHash = parentHash + } + // walk to the end of the block, and remember what we see in the block. + logCount = 0 + execMsgs = make(map[uint32]*types.ExecutingMessage, 0) + retErr = blockIter.TraverseConditional(func(state IteratorState) error { + _, logIndex, ok := state.InitMessage() + if ok { + logCount = logIndex + 1 + } + if m := state.ExecMessage(); m != nil { + execMsgs[logIndex] = m + } + h, n, ok := state.SealedBlock() + if !ok { + return nil + } + if n == blockNum { + ref.Number = n + ref.Hash = h + ref.Time, _ = state.SealedTimestamp() + return types.ErrStop + } + if n > blockNum { + return fmt.Errorf("expected to run into block %d, but did not find it, found %d: %w", blockNum, n, types.ErrDataCorruption) + } + return nil + }) + if errors.Is(retErr, types.ErrStop) { + retErr = nil + } + return +} + // LatestSealedBlockNum returns the block number of the block that was last sealed, // or ok=false if there is no sealed block (i.e. empty DB) func (db *DB) LatestSealedBlockNum() (n uint64, ok bool) { @@ -197,6 +280,11 @@ func (db *DB) Contains(blockNum uint64, logIdx uint32, logHash common.Hash) (typ defer db.rwLock.RUnlock() db.log.Trace("Checking for log", "blockNum", blockNum, "logIdx", logIdx, "hash", logHash) + // Hot-path: check if we have the block + if db.lastEntryContext.hasCompleteBlock() && db.lastEntryContext.blockNum < blockNum { + return types.BlockSeal{}, types.ErrFuture + } + evtHash, iter, err := db.findLogInfo(blockNum, logIdx) if err != nil { return types.BlockSeal{}, err // may be ErrConflict if the block does not have as many logs @@ -204,7 +292,7 @@ func (db *DB) Contains(blockNum uint64, logIdx uint32, logHash common.Hash) (typ db.log.Trace("Found initiatingEvent", "blockNum", blockNum, "logIdx", logIdx, "hash", evtHash) // Found the requested block and log index, check if the hash matches if evtHash != logHash { - return types.BlockSeal{}, fmt.Errorf("payload hash mismatch: expected %s, got %s", logHash, evtHash) + return types.BlockSeal{}, fmt.Errorf("payload hash mismatch: expected %s, got %s %w", logHash, evtHash, types.ErrConflict) } // Now find the block seal after the log, to identify where the log was included in. err = iter.TraverseConditional(func(state IteratorState) error { @@ -213,21 +301,17 @@ func (db *DB) Contains(blockNum uint64, logIdx uint32, logHash common.Hash) (typ return nil } if n == blockNum { - return entrydb.ErrStop + return types.ErrStop } if n > blockNum { - return entrydb.ErrDataCorruption + return types.ErrDataCorruption } return nil }) if err == nil { panic("expected iterator to stop with error") } - if errors.Is(err, entrydb.ErrFuture) { - // Log is known, but as part of an unsealed block. - return types.BlockSeal{}, nil - } - if errors.Is(err, entrydb.ErrStop) { + if errors.Is(err, types.ErrStop) { h, n, _ := iter.SealedBlock() timestamp, _ := iter.SealedTimestamp() return types.BlockSeal{ @@ -241,12 +325,12 @@ func (db *DB) Contains(blockNum uint64, logIdx uint32, logHash common.Hash) (typ func (db *DB) findLogInfo(blockNum uint64, logIdx uint32) (common.Hash, Iterator, error) { if blockNum == 0 { - return common.Hash{}, nil, entrydb.ErrConflict // no logs in block 0 + return common.Hash{}, nil, types.ErrConflict // no logs in block 0 } // blockNum-1, such that we find a log that came after the parent num-1 was sealed. // logIdx, such that all entries before logIdx can be skipped, but logIdx itself is still readable. iter, err := db.newIteratorAt(blockNum-1, logIdx) - if errors.Is(err, entrydb.ErrFuture) { + if errors.Is(err, types.ErrFuture) { db.log.Trace("Could not find log yet", "blockNum", blockNum, "logIdx", logIdx) return common.Hash{}, nil, err } else if err != nil { @@ -261,7 +345,7 @@ func (db *DB) findLogInfo(blockNum uint64, logIdx uint32) (common.Hash, Iterator } else if x < blockNum-1 { panic(fmt.Errorf("bug in newIteratorAt, expected to have found parent block %d but got %d", blockNum-1, x)) } else if x > blockNum-1 { - return common.Hash{}, nil, fmt.Errorf("log does not exist, found next block already: %w", entrydb.ErrConflict) + return common.Hash{}, nil, fmt.Errorf("log does not exist, found next block already: %w", types.ErrConflict) } logHash, x, ok := iter.InitMessage() if !ok { @@ -282,7 +366,7 @@ func (db *DB) newIteratorAt(blockNum uint64, logIndex uint32) (*iterator, error) searchCheckpointIndex, err := db.searchCheckpoint(blockNum, logIndex) if errors.Is(err, io.EOF) { // Did not find a checkpoint to start reading from so the log cannot be present. - return nil, entrydb.ErrFuture + return nil, types.ErrFuture } else if err != nil { return nil, err } @@ -298,9 +382,9 @@ func (db *DB) newIteratorAt(blockNum uint64, logIndex uint32) (*iterator, error) if _, n, ok := iter.SealedBlock(); ok && n == blockNum { // we may already have it exactly break } - if err := iter.NextBlock(); errors.Is(err, entrydb.ErrFuture) { + if err := iter.NextBlock(); errors.Is(err, types.ErrFuture) { db.log.Trace("ran out of data, could not find block", "nextIndex", iter.NextIndex(), "target", blockNum) - return nil, entrydb.ErrFuture + return nil, types.ErrFuture } else if err != nil { db.log.Error("failed to read next block", "nextIndex", iter.NextIndex(), "target", blockNum, "err", err) return nil, err @@ -314,7 +398,7 @@ func (db *DB) newIteratorAt(blockNum uint64, logIndex uint32) (*iterator, error) continue } if num != blockNum { // block does not contain - return nil, fmt.Errorf("looking for %d, but already at %d: %w", blockNum, num, entrydb.ErrConflict) + return nil, fmt.Errorf("looking for %d, but already at %d: %w", blockNum, num, types.ErrConflict) } break } @@ -323,7 +407,7 @@ func (db *DB) newIteratorAt(blockNum uint64, logIndex uint32) (*iterator, error) // so two logs before quiting (and not 3 to then quit after). for iter.current.logsSince < logIndex { if err := iter.NextInitMsg(); err == io.EOF { - return nil, entrydb.ErrFuture + return nil, types.ErrFuture } else if err != nil { return nil, err } @@ -333,7 +417,7 @@ func (db *DB) newIteratorAt(blockNum uint64, logIndex uint32) (*iterator, error) } if num > blockNum { // we overshot, the block did not contain as many seen log events as requested - return nil, entrydb.ErrConflict + return nil, types.ErrConflict } _, idx, ok := iter.InitMessage() if !ok { @@ -367,7 +451,7 @@ func (db *DB) newIterator(index entrydb.EntryIdx) *iterator { // Returns the index of the searchCheckpoint to begin reading from or an error. func (db *DB) searchCheckpoint(sealedBlockNum uint64, logsSince uint32) (entrydb.EntryIdx, error) { if db.lastEntryContext.nextEntryIndex == 0 { - return 0, entrydb.ErrFuture // empty DB, everything is in the future + return 0, types.ErrFuture // empty DB, everything is in the future } n := (db.lastEntryIdx() / searchCheckpointFrequency) + 1 // Define: x is the array of known checkpoints @@ -404,7 +488,7 @@ func (db *DB) searchCheckpoint(sealedBlockNum uint64, logsSince uint32) (entrydb if checkpoint.blockNum > sealedBlockNum || (checkpoint.blockNum == sealedBlockNum && checkpoint.logsSince > logsSince) { return 0, fmt.Errorf("missing data, earliest search checkpoint is %d with %d logs, cannot find something before or at %d with %d logs: %w", - checkpoint.blockNum, checkpoint.logsSince, sealedBlockNum, logsSince, entrydb.ErrSkipped) + checkpoint.blockNum, checkpoint.logsSince, sealedBlockNum, logsSince, types.ErrSkipped) } return result, nil } diff --git a/op-supervisor/supervisor/backend/db/logs/db_test.go b/op-supervisor/supervisor/backend/db/logs/db_test.go index 718bc68a04f4b..5e7c22c899398 100644 --- a/op-supervisor/supervisor/backend/db/logs/db_test.go +++ b/op-supervisor/supervisor/backend/db/logs/db_test.go @@ -89,8 +89,8 @@ func TestLatestSealedBlockNum(t *testing.T) { require.False(t, ok, "empty db expected") require.Zero(t, n) idx, err := db.searchCheckpoint(0, 0) - require.ErrorIs(t, err, entrydb.ErrFuture, "no checkpoint in empty db") - require.ErrorIs(t, err, entrydb.ErrFuture, "no checkpoint in empty db") + require.ErrorIs(t, err, types.ErrFuture, "no checkpoint in empty db") + require.ErrorIs(t, err, types.ErrFuture, "no checkpoint in empty db") require.Zero(t, idx) }) }) @@ -107,6 +107,14 @@ func TestLatestSealedBlockNum(t *testing.T) { idx, err := db.searchCheckpoint(0, 0) require.NoError(t, err) require.Zero(t, idx, "genesis block as checkpoint 0") + + // Test if we can open the genesis block + ref, logCount, execMsgs, err := db.OpenBlock(0) + require.NoError(t, err) + require.Empty(t, execMsgs) + require.Zero(t, logCount) + require.Equal(t, genesis, ref.ID()) + require.Equal(t, uint64(5000), ref.Time) }) }) t.Run("Later genesis case", func(t *testing.T) { @@ -123,8 +131,16 @@ func TestLatestSealedBlockNum(t *testing.T) { require.NoError(t, err) require.Zero(t, idx, "anchor block as checkpoint 0") _, err = db.searchCheckpoint(0, 0) - require.ErrorIs(t, err, entrydb.ErrSkipped, "no checkpoint before genesis") - require.ErrorIs(t, err, entrydb.ErrSkipped, "no checkpoint before genesis") + require.ErrorIs(t, err, types.ErrSkipped, "no checkpoint before genesis") + require.ErrorIs(t, err, types.ErrSkipped, "no checkpoint before genesis") + + // Test if we can open the starting block + _, _, _, err = db.OpenBlock(genesis.Number) + // no data to find the parent-hash. + // OpenBlock cannot start from the first entry, when not 0. + // To start at a non-zero block, index the seal of the parent-block block before it, + // and then that parent-hash will be available. + require.ErrorIs(t, err, types.ErrSkipped) }) }) t.Run("Block 1 case", func(t *testing.T) { @@ -142,6 +158,22 @@ func TestLatestSealedBlockNum(t *testing.T) { idx, err := db.searchCheckpoint(block1.Number, 0) require.NoError(t, err) require.Equal(t, entrydb.EntryIdx(0), idx, "checkpoint 0 still for block 1") + + // Test if we can open the starting block + ref, logCount, execMsgs, err := db.OpenBlock(genesis.Number) + require.NoError(t, err) + require.Empty(t, execMsgs) + require.Zero(t, logCount) + require.Equal(t, genesis, ref.ID()) + require.Equal(t, uint64(5000), ref.Time) + + // Test if we can open the first block after genesis + ref, logCount, execMsgs, err = db.OpenBlock(block1.Number) + require.NoError(t, err) + require.Empty(t, execMsgs) + require.Zero(t, logCount) + require.Equal(t, block1, ref.ID()) + require.Equal(t, uint64(5001), ref.Time) }) }) t.Run("Using checkpoint case", func(t *testing.T) { @@ -151,7 +183,7 @@ func TestLatestSealedBlockNum(t *testing.T) { require.NoError(t, db.SealBlock(common.Hash{}, genesis, 5000), "seal genesis") for i := 1; i <= 260; i++ { id := eth.BlockID{Hash: createHash(i), Number: uint64(i)} - require.NoError(t, db.SealBlock(createHash(i-1), id, 5001), "seal block %d", i) + require.NoError(t, db.SealBlock(createHash(i-1), id, 5000+uint64(i)), "seal block %d", i) } }, func(t *testing.T, db *DB, m *stubMetrics) { @@ -164,6 +196,14 @@ func TestLatestSealedBlockNum(t *testing.T) { // It costs 2 entries per block, so if we add more than 1 checkpoint worth of blocks, // then we get to checkpoint 2 require.Equal(t, entrydb.EntryIdx(searchCheckpointFrequency*2), idx, "checkpoint 1 reached") + + // Test if we can open the block + ref, logCount, execMsgs, err := db.OpenBlock(n) + require.NoError(t, err) + require.Empty(t, execMsgs) + require.Zero(t, logCount) + require.Equal(t, createHash(int(n)), ref.Hash) + require.Equal(t, uint64(5000)+n, ref.Time) }) }) } @@ -176,8 +216,8 @@ func TestAddLog(t *testing.T) { func(t *testing.T, db *DB, m *stubMetrics) { genesis := eth.BlockID{Hash: createHash(15), Number: 0} err := db.AddLog(createHash(1), genesis, 0, nil) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) }) }) @@ -192,6 +232,12 @@ func TestAddLog(t *testing.T) { }, func(t *testing.T, db *DB, m *stubMetrics) { requireContains(t, db, 16, 0, createHash(1)) + + ref, logCount, execMsgs, err := db.OpenBlock(16) + require.NoError(t, err) + require.Empty(t, execMsgs) + require.Equal(t, uint32(1), logCount) + require.Equal(t, eth.BlockRef{Hash: createHash(16), Number: 16, ParentHash: createHash(15), Time: 5001}, ref) }) }) @@ -221,6 +267,18 @@ func TestAddLog(t *testing.T) { requireContains(t, db, 16, 0, createHash(1)) requireContains(t, db, 16, 1, createHash(2)) requireContains(t, db, 16, 2, createHash(3)) + + ref, logCount, execMsgs, err := db.OpenBlock(13) + require.NoError(t, err) + require.Empty(t, execMsgs) + require.Equal(t, uint32(0), logCount) + require.Equal(t, eth.BlockRef{Hash: createHash(13), Number: 13, ParentHash: createHash(12), Time: 5013}, ref) + + ref, logCount, execMsgs, err = db.OpenBlock(16) + require.NoError(t, err) + require.Empty(t, execMsgs) + require.Equal(t, uint32(3), logCount) + require.Equal(t, eth.BlockRef{Hash: createHash(16), Number: 16, ParentHash: createHash(15), Time: 5016}, ref) }) }) @@ -267,8 +325,8 @@ func TestAddLog(t *testing.T) { func(t *testing.T, db *DB, m *stubMetrics) { bl14 := eth.BlockID{Hash: createHash(14), Number: 14} err := db.SealBlock(createHash(13), bl14, 5000) - require.ErrorIs(t, err, entrydb.ErrConflict) - require.ErrorIs(t, err, entrydb.ErrConflict) + require.ErrorIs(t, err, types.ErrConflict) + require.ErrorIs(t, err, types.ErrConflict) }) }) @@ -285,8 +343,8 @@ func TestAddLog(t *testing.T) { func(t *testing.T, db *DB, m *stubMetrics) { onto := eth.BlockID{Hash: createHash(14), Number: 14} err := db.AddLog(createHash(1), onto, 0, nil) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder, "cannot build logs on 14 when 15 is already sealed") - require.ErrorIs(t, err, entrydb.ErrOutOfOrder, "cannot build logs on 14 when 15 is already sealed") + require.ErrorIs(t, err, types.ErrOutOfOrder, "cannot build logs on 14 when 15 is already sealed") + require.ErrorIs(t, err, types.ErrOutOfOrder, "cannot build logs on 14 when 15 is already sealed") }) }) @@ -302,8 +360,8 @@ func TestAddLog(t *testing.T) { func(t *testing.T, db *DB, m *stubMetrics) { bl15 := eth.BlockID{Hash: createHash(15), Number: 15} err := db.AddLog(createHash(1), bl15, 0, nil) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder, "already at log index 2") - require.ErrorIs(t, err, entrydb.ErrOutOfOrder, "already at log index 2") + require.ErrorIs(t, err, types.ErrOutOfOrder, "already at log index 2") + require.ErrorIs(t, err, types.ErrOutOfOrder, "already at log index 2") }) }) @@ -318,8 +376,8 @@ func TestAddLog(t *testing.T) { }, func(t *testing.T, db *DB, m *stubMetrics) { err := db.AddLog(createHash(1), eth.BlockID{Hash: createHash(16), Number: 16}, 0, nil) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) }) }) @@ -335,8 +393,8 @@ func TestAddLog(t *testing.T) { func(t *testing.T, db *DB, m *stubMetrics) { bl15 := eth.BlockID{Hash: createHash(15), Number: 15} err := db.AddLog(createHash(1), bl15, 1, nil) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder, "already at log index 2") - require.ErrorIs(t, err, entrydb.ErrOutOfOrder, "already at log index 2") + require.ErrorIs(t, err, types.ErrOutOfOrder, "already at log index 2") + require.ErrorIs(t, err, types.ErrOutOfOrder, "already at log index 2") }) }) @@ -352,8 +410,8 @@ func TestAddLog(t *testing.T) { func(t *testing.T, db *DB, m *stubMetrics) { bl15 := eth.BlockID{Hash: createHash(16), Number: 16} err := db.AddLog(createHash(1), bl15, 2, nil) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) }) }) @@ -368,8 +426,8 @@ func TestAddLog(t *testing.T) { func(t *testing.T, db *DB, m *stubMetrics) { bl15 := eth.BlockID{Hash: createHash(15), Number: 15} err := db.AddLog(createHash(1), bl15, 2, nil) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) }) }) @@ -382,8 +440,8 @@ func TestAddLog(t *testing.T) { func(t *testing.T, db *DB, m *stubMetrics) { bl15 := eth.BlockID{Hash: createHash(15), Number: 15} err := db.AddLog(createHash(1), bl15, 5, nil) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) }) }) @@ -404,8 +462,8 @@ func TestAddLog(t *testing.T) { err = db.SealBlock(bl15.Hash, bl16, 5001) require.NoError(t, err) err = db.AddLog(createHash(1), bl16, 1, nil) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) }) }) @@ -524,6 +582,8 @@ func TestAddDependentLog(t *testing.T) { require.NoError(t, db.lastEntryContext.forceBlock(bl15, 5000)) err := db.AddLog(createHash(1), bl15, 0, &execMsg) require.NoError(t, err) + bl16 := eth.BlockID{Hash: createHash(16), Number: 16} + require.NoError(t, db.SealBlock(bl15.Hash, bl16, 5002)) }, func(t *testing.T, db *DB, m *stubMetrics) { requireContains(t, db, 16, 0, createHash(1), execMsg) @@ -544,6 +604,8 @@ func TestAddDependentLog(t *testing.T) { require.Equal(t, m.entryCount, int64(searchCheckpointFrequency+2)) err := db.AddLog(createHash(1), bl16, 0, &execMsg) require.NoError(t, err) + bl17 := eth.BlockID{Hash: createHash(17), Number: 17} + require.NoError(t, db.SealBlock(bl16.Hash, bl17, 5002)) }, func(t *testing.T, db *DB, m *stubMetrics) { requireContains(t, db, 16, 0, createHash(9)) @@ -574,6 +636,8 @@ func TestAddDependentLog(t *testing.T) { // 260 = executing message check require.Equal(t, int64(261), m.entryCount) db.debugTip() + bl16 := eth.BlockID{Hash: createHash(16), Number: 16} + require.NoError(t, db.SealBlock(bl15.Hash, bl16, 5001)) }, func(t *testing.T, db *DB, m *stubMetrics) { requireContains(t, db, 16, 251, createHash(9)) @@ -603,6 +667,8 @@ func TestAddDependentLog(t *testing.T) { // 260 = executing message check db.debugTip() require.Equal(t, int64(261), m.entryCount) + bl16 := eth.BlockID{Hash: createHash(16), Number: 16} + require.NoError(t, db.SealBlock(bl15.Hash, bl16, 5001)) }, func(t *testing.T, db *DB, m *stubMetrics) { requireContains(t, db, 16, 252, createHash(9)) @@ -631,8 +697,8 @@ func TestContains(t *testing.T) { requireContains(t, db, 51, 0, createHash(1)) requireContains(t, db, 51, 1, createHash(3)) requireContains(t, db, 51, 2, createHash(2)) - requireContains(t, db, 53, 0, createHash(1)) - requireContains(t, db, 53, 1, createHash(3)) + requireFuture(t, db, 53, 0, createHash(1)) + requireFuture(t, db, 53, 1, createHash(3)) // 52 was sealed as empty requireConflicts(t, db, 52, 0, createHash(1)) @@ -701,6 +767,14 @@ func TestExecutes(t *testing.T) { // 51 only contained 3 logs, not 4 requireConflicts(t, db, 51, 3, createHash(2)) + + // 51 contains an executing message, and 2 other non-executing logs + ref, logCount, execMsgs, err := db.OpenBlock(51) + require.NoError(t, err) + require.Len(t, execMsgs, 1) + require.Equal(t, &execMsg1, execMsgs[1]) + require.Equal(t, uint32(3), logCount) + require.Equal(t, eth.BlockRef{Hash: createHash(51), Number: 51, ParentHash: createHash(50), Time: 5001}, ref) }) } @@ -710,9 +784,9 @@ func TestGetBlockInfo(t *testing.T) { func(t *testing.T, db *DB, m *stubMetrics) {}, func(t *testing.T, db *DB, m *stubMetrics) { _, err := db.FindSealedBlock(10) - require.ErrorIs(t, err, entrydb.ErrFuture) + require.ErrorIs(t, err, types.ErrFuture) _, err = db.FindSealedBlock(10) - require.ErrorIs(t, err, entrydb.ErrFuture) + require.ErrorIs(t, err, types.ErrFuture) }) }) @@ -727,9 +801,9 @@ func TestGetBlockInfo(t *testing.T) { func(t *testing.T, db *DB, m *stubMetrics) { // if the DB starts at 11, then shouldn't find 10 _, err := db.FindSealedBlock(10) - require.ErrorIs(t, err, entrydb.ErrSkipped) + require.ErrorIs(t, err, types.ErrSkipped) _, err = db.FindSealedBlock(10) - require.ErrorIs(t, err, entrydb.ErrSkipped) + require.ErrorIs(t, err, types.ErrSkipped) }) }) @@ -772,8 +846,8 @@ func requireConflicts(t *testing.T, db *DB, blockNum uint64, logIdx uint32, logH m, ok := db.m.(*stubMetrics) require.True(t, ok, "Did not get the expected metrics type") _, err := db.Contains(blockNum, logIdx, logHash) - require.ErrorIs(t, err, entrydb.ErrConflict, "canonical chain must not include this log") - require.ErrorIs(t, err, entrydb.ErrConflict, "canonical chain must not include this log") + require.ErrorIs(t, err, types.ErrConflict, "canonical chain must not include this log") + require.ErrorIs(t, err, types.ErrConflict, "canonical chain must not include this log") require.LessOrEqual(t, m.entriesReadForSearch, int64(searchCheckpointFrequency*2), "Should not need to read more than between two checkpoints") } @@ -781,8 +855,8 @@ func requireFuture(t *testing.T, db *DB, blockNum uint64, logIdx uint32, logHash m, ok := db.m.(*stubMetrics) require.True(t, ok, "Did not get the expected metrics type") _, err := db.Contains(blockNum, logIdx, logHash) - require.ErrorIs(t, err, entrydb.ErrFuture, "canonical chain does not yet include this log") - require.ErrorIs(t, err, entrydb.ErrFuture, "canonical chain does not yet include this log") + require.ErrorIs(t, err, types.ErrFuture, "canonical chain does not yet include this log") + require.ErrorIs(t, err, types.ErrFuture, "canonical chain does not yet include this log") require.LessOrEqual(t, m.entriesReadForSearch, int64(searchCheckpointFrequency*2), "Should not need to read more than between two checkpoints") } @@ -943,11 +1017,11 @@ func TestRewind(t *testing.T) { t.Run("WhenEmpty", func(t *testing.T) { runDBTest(t, func(t *testing.T, db *DB, m *stubMetrics) {}, func(t *testing.T, db *DB, m *stubMetrics) { - require.ErrorIs(t, db.Rewind(100), entrydb.ErrFuture) - require.ErrorIs(t, db.Rewind(100), entrydb.ErrFuture) + require.ErrorIs(t, db.Rewind(100), types.ErrFuture) + require.ErrorIs(t, db.Rewind(100), types.ErrFuture) // Genesis is a block to, not present in an empty DB - require.ErrorIs(t, db.Rewind(0), entrydb.ErrFuture) - require.ErrorIs(t, db.Rewind(0), entrydb.ErrFuture) + require.ErrorIs(t, db.Rewind(0), types.ErrFuture) + require.ErrorIs(t, db.Rewind(0), types.ErrFuture) }) }) @@ -965,15 +1039,15 @@ func TestRewind(t *testing.T) { require.NoError(t, db.SealBlock(bl51.Hash, bl52, 504)) require.NoError(t, db.AddLog(createHash(4), bl52, 0, nil)) // cannot rewind to a block that is not sealed yet - require.ErrorIs(t, db.Rewind(53), entrydb.ErrFuture) - require.ErrorIs(t, db.Rewind(53), entrydb.ErrFuture) + require.ErrorIs(t, db.Rewind(53), types.ErrFuture) + require.ErrorIs(t, db.Rewind(53), types.ErrFuture) }, func(t *testing.T, db *DB, m *stubMetrics) { requireContains(t, db, 51, 0, createHash(1)) requireContains(t, db, 51, 1, createHash(2)) requireContains(t, db, 52, 0, createHash(3)) // Still have the pending log of unsealed block if the rewind to unknown sealed block fails - requireContains(t, db, 53, 0, createHash(4)) + requireFuture(t, db, 53, 0, createHash(4)) }) }) @@ -985,12 +1059,13 @@ func TestRewind(t *testing.T) { require.NoError(t, db.AddLog(createHash(1), bl50, 0, nil)) require.NoError(t, db.AddLog(createHash(2), bl50, 1, nil)) // cannot go back to an unknown block - require.ErrorIs(t, db.Rewind(25), entrydb.ErrSkipped) - require.ErrorIs(t, db.Rewind(25), entrydb.ErrSkipped) + require.ErrorIs(t, db.Rewind(25), types.ErrSkipped) + require.ErrorIs(t, db.Rewind(25), types.ErrSkipped) }, func(t *testing.T, db *DB, m *stubMetrics) { - requireContains(t, db, 51, 0, createHash(1)) - requireContains(t, db, 51, 0, createHash(1)) + // block 51 is not sealed yet + requireFuture(t, db, 51, 0, createHash(1)) + requireFuture(t, db, 51, 0, createHash(1)) }) }) @@ -1111,19 +1186,20 @@ func TestRewind(t *testing.T) { bl29 := eth.BlockID{Hash: createHash(29), Number: 29} // 29 was deleted err := db.AddLog(createHash(2), bl29, 1, nil) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder, "Cannot add log on removed block") - require.ErrorIs(t, err, entrydb.ErrOutOfOrder, "Cannot add log on removed block") + require.ErrorIs(t, err, types.ErrOutOfOrder, "Cannot add log on removed block") + require.ErrorIs(t, err, types.ErrOutOfOrder, "Cannot add log on removed block") // 15 is older, we have up to 16 bl15 := eth.BlockID{Hash: createHash(15), Number: 15} // try to add a third log to 15 err = db.AddLog(createHash(10), bl15, 2, nil) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) - require.ErrorIs(t, err, entrydb.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) + require.ErrorIs(t, err, types.ErrOutOfOrder) bl16 := eth.BlockID{Hash: createHash(16), Number: 16} // try to add a log to 17, on top of 16 err = db.AddLog(createHash(42), bl16, 0, nil) require.NoError(t, err) - requireContains(t, db, 17, 0, createHash(42)) + // not sealed yet + requireFuture(t, db, 17, 0, createHash(42)) }) }) } diff --git a/op-supervisor/supervisor/backend/db/logs/entries.go b/op-supervisor/supervisor/backend/db/logs/entries.go index acb0d2b556262..5c5472c522b74 100644 --- a/op-supervisor/supervisor/backend/db/logs/entries.go +++ b/op-supervisor/supervisor/backend/db/logs/entries.go @@ -6,7 +6,6 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/entrydb" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -29,7 +28,7 @@ func newSearchCheckpoint(blockNum uint64, logsSince uint32, timestamp uint64) se func newSearchCheckpointFromEntry(data Entry) (searchCheckpoint, error) { if data.Type() != TypeSearchCheckpoint { - return searchCheckpoint{}, fmt.Errorf("%w: attempting to decode search checkpoint but was type %s", entrydb.ErrDataCorruption, data.Type()) + return searchCheckpoint{}, fmt.Errorf("%w: attempting to decode search checkpoint but was type %s", types.ErrDataCorruption, data.Type()) } return searchCheckpoint{ blockNum: binary.LittleEndian.Uint64(data[1:9]), @@ -59,7 +58,7 @@ func newCanonicalHash(hash common.Hash) canonicalHash { func newCanonicalHashFromEntry(data Entry) (canonicalHash, error) { if data.Type() != TypeCanonicalHash { - return canonicalHash{}, fmt.Errorf("%w: attempting to decode canonical hash but was type %s", entrydb.ErrDataCorruption, data.Type()) + return canonicalHash{}, fmt.Errorf("%w: attempting to decode canonical hash but was type %s", types.ErrDataCorruption, data.Type()) } return newCanonicalHash(common.Hash(data[1:33])), nil } @@ -78,7 +77,7 @@ type initiatingEvent struct { func newInitiatingEventFromEntry(data Entry) (initiatingEvent, error) { if data.Type() != TypeInitiatingEvent { - return initiatingEvent{}, fmt.Errorf("%w: attempting to decode initiating event but was type %s", entrydb.ErrDataCorruption, data.Type()) + return initiatingEvent{}, fmt.Errorf("%w: attempting to decode initiating event but was type %s", types.ErrDataCorruption, data.Type()) } flags := data[1] return initiatingEvent{ @@ -109,7 +108,7 @@ func (i initiatingEvent) encode() Entry { } type executingLink struct { - chain uint32 + chain uint32 // chain index, not a chain ID blockNum uint64 logIdx uint32 timestamp uint64 @@ -120,7 +119,7 @@ func newExecutingLink(msg types.ExecutingMessage) (executingLink, error) { return executingLink{}, fmt.Errorf("log idx is too large (%v)", msg.LogIdx) } return executingLink{ - chain: msg.Chain, + chain: uint32(msg.Chain), blockNum: msg.BlockNum, logIdx: msg.LogIdx, timestamp: msg.Timestamp, @@ -129,7 +128,7 @@ func newExecutingLink(msg types.ExecutingMessage) (executingLink, error) { func newExecutingLinkFromEntry(data Entry) (executingLink, error) { if data.Type() != TypeExecutingLink { - return executingLink{}, fmt.Errorf("%w: attempting to decode executing link but was type %s", entrydb.ErrDataCorruption, data.Type()) + return executingLink{}, fmt.Errorf("%w: attempting to decode executing link but was type %s", types.ErrDataCorruption, data.Type()) } timestamp := binary.LittleEndian.Uint64(data[16:24]) return executingLink{ @@ -166,7 +165,7 @@ func newExecutingCheck(hash common.Hash) executingCheck { func newExecutingCheckFromEntry(data Entry) (executingCheck, error) { if data.Type() != TypeExecutingCheck { - return executingCheck{}, fmt.Errorf("%w: attempting to decode executing check but was type %s", entrydb.ErrDataCorruption, data.Type()) + return executingCheck{}, fmt.Errorf("%w: attempting to decode executing check but was type %s", types.ErrDataCorruption, data.Type()) } return newExecutingCheck(common.Hash(data[1:33])), nil } diff --git a/op-supervisor/supervisor/backend/db/logs/iterator.go b/op-supervisor/supervisor/backend/db/logs/iterator.go index 5a7015ca4fda2..c107a2a9fb862 100644 --- a/op-supervisor/supervisor/backend/db/logs/iterator.go +++ b/op-supervisor/supervisor/backend/db/logs/iterator.go @@ -41,7 +41,7 @@ type traverseConditionalFn func(state IteratorState) error func (i *iterator) End() error { for { _, err := i.next() - if errors.Is(err, entrydb.ErrFuture) { + if errors.Is(err, types.ErrFuture) { return nil } else if err != nil { return err @@ -49,7 +49,7 @@ func (i *iterator) End() error { } } -// NextInitMsg returns the next initiating message in the iterator. +// NextInitMsg advances the iterator until it reads the next Initiating Message into the current state. // It scans forward until it finds and fully reads an initiating event, skipping any blocks. func (i *iterator) NextInitMsg() error { seenLog := false @@ -73,9 +73,8 @@ func (i *iterator) NextInitMsg() error { } } -// NextExecMsg returns the next executing message in the iterator. +// NextExecMsg advances the iterator until it reads the next Executing Message into the current state. // It scans forward until it finds and fully reads an initiating event, skipping any blocks. -// This does not stay at the executing message of the current initiating message, if there is any. func (i *iterator) NextExecMsg() error { for { err := i.NextInitMsg() @@ -88,7 +87,7 @@ func (i *iterator) NextExecMsg() error { } } -// NextBlock returns the next block in the iterator. +// NextBlock advances the iterator until it reads the next block into the current state. // It scans forward until it finds and fully reads a block, skipping any events. func (i *iterator) NextBlock() error { seenBlock := false @@ -134,7 +133,7 @@ func (i *iterator) next() (EntryType, error) { entry, err := i.db.store.Read(index) if err != nil { if errors.Is(err, io.EOF) { - return 0, entrydb.ErrFuture + return 0, types.ErrFuture } return 0, fmt.Errorf("failed to read entry %d: %w", index, err) } diff --git a/op-supervisor/supervisor/backend/db/logs/state.go b/op-supervisor/supervisor/backend/db/logs/state.go index 2e51295c93df1..3c90102b1ad0a 100644 --- a/op-supervisor/supervisor/backend/db/logs/state.go +++ b/op-supervisor/supervisor/backend/db/logs/state.go @@ -200,7 +200,7 @@ func (l *logContext) processEntry(entry Entry) error { return err } l.execMsg = &types.ExecutingMessage{ - Chain: link.chain, + Chain: types.ChainIndex(link.chain), // TODO(#11105): translate chain ID to chain index BlockNum: link.blockNum, LogIdx: link.logIdx, Timestamp: link.timestamp, @@ -352,13 +352,13 @@ func (l *logContext) SealBlock(parent common.Hash, upd eth.BlockID, timestamp ui return err } if l.blockHash != parent { - return fmt.Errorf("%w: cannot apply block %s (parent %s) on top of %s", entrydb.ErrConflict, upd, parent, l.blockHash) + return fmt.Errorf("%w: cannot apply block %s (parent %s) on top of %s", types.ErrConflict, upd, parent, l.blockHash) } if l.blockHash != (common.Hash{}) && l.blockNum+1 != upd.Number { - return fmt.Errorf("%w: cannot apply block %d on top of %d", entrydb.ErrConflict, upd.Number, l.blockNum) + return fmt.Errorf("%w: cannot apply block %d on top of %d", types.ErrConflict, upd.Number, l.blockNum) } if l.timestamp > timestamp { - return fmt.Errorf("%w: block timestamp %d must be equal or larger than current timestamp %d", entrydb.ErrConflict, timestamp, l.timestamp) + return fmt.Errorf("%w: block timestamp %d must be equal or larger than current timestamp %d", types.ErrConflict, timestamp, l.timestamp) } } l.blockHash = upd.Hash @@ -375,28 +375,28 @@ func (l *logContext) SealBlock(parent common.Hash, upd eth.BlockID, timestamp ui // The parent-block that the log comes after must be applied with ApplyBlock first. func (l *logContext) ApplyLog(parentBlock eth.BlockID, logIdx uint32, logHash common.Hash, execMsg *types.ExecutingMessage) error { if parentBlock == (eth.BlockID{}) { - return fmt.Errorf("genesis does not have logs: %w", entrydb.ErrOutOfOrder) + return fmt.Errorf("genesis does not have logs: %w", types.ErrOutOfOrder) } if err := l.inferFull(); err != nil { // ensure we can start applying return err } if !l.hasCompleteBlock() { if l.blockNum == 0 { - return fmt.Errorf("%w: should not have logs in block 0", entrydb.ErrOutOfOrder) + return fmt.Errorf("%w: should not have logs in block 0", types.ErrOutOfOrder) } else { return errors.New("cannot append log before last known block is sealed") } } // check parent block if l.blockHash != parentBlock.Hash { - return fmt.Errorf("%w: log builds on top of block %s, but have block %s", entrydb.ErrOutOfOrder, parentBlock, l.blockHash) + return fmt.Errorf("%w: log builds on top of block %s, but have block %s", types.ErrOutOfOrder, parentBlock, l.blockHash) } if l.blockNum != parentBlock.Number { - return fmt.Errorf("%w: log builds on top of block %d, but have block %d", entrydb.ErrOutOfOrder, parentBlock.Number, l.blockNum) + return fmt.Errorf("%w: log builds on top of block %d, but have block %d", types.ErrOutOfOrder, parentBlock.Number, l.blockNum) } // check if log fits on top. The length so far == the index of the next log. if logIdx != l.logsSince { - return fmt.Errorf("%w: expected event index %d, cannot append %d", entrydb.ErrOutOfOrder, l.logsSince, logIdx) + return fmt.Errorf("%w: expected event index %d, cannot append %d", types.ErrOutOfOrder, l.logsSince, logIdx) } l.logHash = logHash l.execMsg = execMsg diff --git a/op-supervisor/supervisor/backend/db/query.go b/op-supervisor/supervisor/backend/db/query.go index c331379f9a289..bbee01d71b4d0 100644 --- a/op-supervisor/supervisor/backend/db/query.go +++ b/op-supervisor/supervisor/backend/db/query.go @@ -7,18 +7,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/entrydb" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/db/logs" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) func (db *ChainsDB) FindSealedBlock(chain types.ChainID, number uint64) (seal types.BlockSeal, err error) { - db.mu.RLock() - defer db.mu.RUnlock() - - logDB, ok := db.logDBs[chain] + logDB, ok := db.logDBs.Get(chain) if !ok { - return types.BlockSeal{}, fmt.Errorf("%w: %v", ErrUnknownChain, chain) + return types.BlockSeal{}, fmt.Errorf("%w: %v", types.ErrUnknownChain, chain) } return logDB.FindSealedBlock(number) } @@ -27,77 +23,107 @@ func (db *ChainsDB) FindSealedBlock(chain types.ChainID, number uint64) (seal ty // for the given chain. It does not contain safety guarantees. // The block number might not be available (empty database, or non-existent chain). func (db *ChainsDB) LatestBlockNum(chain types.ChainID) (num uint64, ok bool) { - db.mu.RLock() - defer db.mu.RUnlock() - - logDB, knownChain := db.logDBs[chain] + logDB, knownChain := db.logDBs.Get(chain) if !knownChain { return 0, false } return logDB.LatestSealedBlockNum() } -func (db *ChainsDB) LocalUnsafe(chainID types.ChainID) (types.BlockSeal, error) { - db.mu.RLock() - defer db.mu.RUnlock() +func (db *ChainsDB) IsCrossUnsafe(chainID types.ChainID, block eth.BlockID) error { + v, ok := db.crossUnsafe.Get(chainID) + if !ok { + return types.ErrUnknownChain + } + crossUnsafe := v.Get() + if crossUnsafe == (types.BlockSeal{}) { + return types.ErrFuture + } + if block.Number > crossUnsafe.Number { + return types.ErrFuture + } + // TODO(#11693): make cross-unsafe reorg safe + return nil +} + +func (db *ChainsDB) ParentBlock(chainID types.ChainID, parentOf eth.BlockID) (parent eth.BlockID, err error) { + logDB, ok := db.logDBs.Get(chainID) + if !ok { + return eth.BlockID{}, types.ErrUnknownChain + } + if parentOf.Number == 0 { + return eth.BlockID{}, nil + } + // TODO(#11693): make parent-lookup reorg safe + got, err := logDB.FindSealedBlock(parentOf.Number - 1) + if err != nil { + return eth.BlockID{}, err + } + return got.ID(), nil +} + +func (db *ChainsDB) IsLocalUnsafe(chainID types.ChainID, block eth.BlockID) error { + logDB, ok := db.logDBs.Get(chainID) + if !ok { + return types.ErrUnknownChain + } + got, err := logDB.FindSealedBlock(block.Number) + if err != nil { + return err + } + if got.ID() != block { + return fmt.Errorf("found %s but was looking for unsafe block %s: %w", got, block, types.ErrConflict) + } + return nil +} - eventsDB, ok := db.logDBs[chainID] +func (db *ChainsDB) LocalUnsafe(chainID types.ChainID) (types.BlockSeal, error) { + eventsDB, ok := db.logDBs.Get(chainID) if !ok { - return types.BlockSeal{}, ErrUnknownChain + return types.BlockSeal{}, types.ErrUnknownChain } n, ok := eventsDB.LatestSealedBlockNum() if !ok { - return types.BlockSeal{}, entrydb.ErrFuture + return types.BlockSeal{}, types.ErrFuture } return eventsDB.FindSealedBlock(n) } func (db *ChainsDB) CrossUnsafe(chainID types.ChainID) (types.BlockSeal, error) { - db.mu.RLock() - defer db.mu.RUnlock() - - result, ok := db.crossUnsafe[chainID] + result, ok := db.crossUnsafe.Get(chainID) if !ok { - return types.BlockSeal{}, ErrUnknownChain + return types.BlockSeal{}, types.ErrUnknownChain } + crossUnsafe := result.Get() // Fall back to cross-safe if cross-unsafe is not known yet - if result == (types.BlockSeal{}) { + if crossUnsafe == (types.BlockSeal{}) { _, crossSafe, err := db.CrossSafe(chainID) if err != nil { return types.BlockSeal{}, fmt.Errorf("no cross-unsafe known for chain %s, and failed to fall back to cross-safe value: %w", chainID, err) } return crossSafe, nil } - return result, nil + return crossUnsafe, nil } func (db *ChainsDB) LocalSafe(chainID types.ChainID) (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) { - db.mu.RLock() - defer db.mu.RUnlock() - - localDB, ok := db.localDBs[chainID] + localDB, ok := db.localDBs.Get(chainID) if !ok { - return types.BlockSeal{}, types.BlockSeal{}, ErrUnknownChain + return types.BlockSeal{}, types.BlockSeal{}, types.ErrUnknownChain } return localDB.Latest() } func (db *ChainsDB) CrossSafe(chainID types.ChainID) (derivedFrom types.BlockSeal, derived types.BlockSeal, err error) { - db.mu.RLock() - defer db.mu.RUnlock() - - crossDB, ok := db.crossDBs[chainID] + crossDB, ok := db.crossDBs.Get(chainID) if !ok { - return types.BlockSeal{}, types.BlockSeal{}, ErrUnknownChain + return types.BlockSeal{}, types.BlockSeal{}, types.ErrUnknownChain } return crossDB.Latest() } func (db *ChainsDB) Finalized(chainID types.ChainID) (types.BlockSeal, error) { - db.mu.RLock() - defer db.mu.RUnlock() - - finalizedL1 := db.finalizedL1 + finalizedL1 := db.finalizedL1.Get() if finalizedL1 == (eth.L1BlockRef{}) { return types.BlockSeal{}, errors.New("no finalized L1 signal, cannot determine L2 finality yet") } @@ -109,44 +135,205 @@ func (db *ChainsDB) Finalized(chainID types.ChainID) (types.BlockSeal, error) { } func (db *ChainsDB) LastDerivedFrom(chainID types.ChainID, derivedFrom eth.BlockID) (derived types.BlockSeal, err error) { - crossDB, ok := db.crossDBs[chainID] + crossDB, ok := db.crossDBs.Get(chainID) if !ok { - return types.BlockSeal{}, ErrUnknownChain + return types.BlockSeal{}, types.ErrUnknownChain } return crossDB.LastDerivedAt(derivedFrom) } -func (db *ChainsDB) DerivedFrom(chainID types.ChainID, derived eth.BlockID) (derivedFrom types.BlockSeal, err error) { - db.mu.RLock() - defer db.mu.RUnlock() - - localDB, ok := db.localDBs[chainID] +// CrossDerivedFromBlockRef returns the block that the given block was derived from, if it exists in the cross derived-from storage. +// This includes the parent-block lookup. Use CrossDerivedFrom if no parent-block info is needed. +func (db *ChainsDB) CrossDerivedFromBlockRef(chainID types.ChainID, derived eth.BlockID) (derivedFrom eth.BlockRef, err error) { + xdb, ok := db.crossDBs.Get(chainID) if !ok { - return types.BlockSeal{}, ErrUnknownChain + return eth.BlockRef{}, types.ErrUnknownChain + } + res, err := xdb.DerivedFrom(derived) + if err != nil { + return eth.BlockRef{}, err } - return localDB.DerivedFrom(derived) + parent, err := xdb.PreviousDerivedFrom(res.ID()) + // if we are working with the first item in the database, PreviousDerivedFrom will return ErrPreviousToFirst + // in which case we can attach a zero parent to the cross-derived-from block, as the parent block is unknown + if errors.Is(err, types.ErrPreviousToFirst) { + return res.ForceWithParent(eth.BlockID{}), nil + } else if err != nil { + return eth.BlockRef{}, err + } + return res.MustWithParent(parent.ID()), nil } // Check calls the underlying logDB to determine if the given log entry exists at the given location. // If the block-seal of the block that includes the log is known, it is returned. It is fully zeroed otherwise, if the block is in-progress. func (db *ChainsDB) Check(chain types.ChainID, blockNum uint64, logIdx uint32, logHash common.Hash) (includedIn types.BlockSeal, err error) { - db.mu.RLock() - defer db.mu.RUnlock() - - logDB, ok := db.logDBs[chain] + logDB, ok := db.logDBs.Get(chain) if !ok { - return types.BlockSeal{}, fmt.Errorf("%w: %v", ErrUnknownChain, chain) + return types.BlockSeal{}, fmt.Errorf("%w: %v", types.ErrUnknownChain, chain) } return logDB.Contains(blockNum, logIdx, logHash) } +// OpenBlock returns the Executing Messages for the block at the given number on the given chain. +// it routes the request to the appropriate logDB. +func (db *ChainsDB) OpenBlock(chainID types.ChainID, blockNum uint64) (seal eth.BlockRef, logCount uint32, execMsgs map[uint32]*types.ExecutingMessage, err error) { + logDB, ok := db.logDBs.Get(chainID) + if !ok { + return eth.BlockRef{}, 0, nil, types.ErrUnknownChain + } + return logDB.OpenBlock(blockNum) +} + +// LocalDerivedFrom returns the block that the given block was derived from, if it exists in the local derived-from storage. +// it routes the request to the appropriate localDB. +func (db *ChainsDB) LocalDerivedFrom(chain types.ChainID, derived eth.BlockID) (derivedFrom types.BlockSeal, err error) { + lDB, ok := db.localDBs.Get(chain) + if !ok { + return types.BlockSeal{}, types.ErrUnknownChain + } + return lDB.DerivedFrom(derived) +} + +// CrossDerivedFrom returns the block that the given block was derived from, if it exists in the cross derived-from storage. +// it routes the request to the appropriate crossDB. +func (db *ChainsDB) CrossDerivedFrom(chain types.ChainID, derived eth.BlockID) (derivedFrom types.BlockSeal, err error) { + xDB, ok := db.crossDBs.Get(chain) + if !ok { + return types.BlockSeal{}, types.ErrUnknownChain + } + return xDB.DerivedFrom(derived) +} + +// CandidateCrossSafe returns the candidate local-safe block that may become cross-safe. +// +// This returns ErrFuture if no block is known yet. +// +// Or ErrConflict if there is an inconsistency between the local-safe and cross-safe DB. +// +// Or ErrOutOfScope, with non-zero derivedFromScope, +// if additional L1 data is needed to cross-verify the candidate L2 block. +func (db *ChainsDB) CandidateCrossSafe(chain types.ChainID) (derivedFromScope, crossSafe eth.BlockRef, err error) { + xDB, ok := db.crossDBs.Get(chain) + if !ok { + return eth.BlockRef{}, eth.BlockRef{}, types.ErrUnknownChain + } + + lDB, ok := db.localDBs.Get(chain) + if !ok { + return eth.BlockRef{}, eth.BlockRef{}, types.ErrUnknownChain + } + + // Example: + // A B C D <- L1 + // 1 2 <- L2 + // return: + // (A, 0) -> initial scope, no L2 block yet. Genesis found to be cross-safe + // (A, 1) -> 1 is determined cross-safe, won't be a candidate anymore after. 2 is the new candidate + // (B, 2) -> 2 is out of scope, go to B + // (C, 2) -> 2 is out of scope, go to C + // (D, 2) -> 2 is in scope, stay on D, promote candidate to cross-safe + // (D, 3) -> look at 3 next, see if we have to bump L1 yet, try with same L1 scope first + + crossDerivedFrom, crossDerived, err := xDB.Latest() + if err != nil { + if errors.Is(err, types.ErrFuture) { + // If we do not have any cross-safe block yet, then return the first local-safe block. + derivedFrom, derived, err := lDB.First() + if err != nil { + return eth.BlockRef{}, eth.BlockRef{}, fmt.Errorf("failed to find first local-safe block: %w", err) + } + // the first derivedFrom (L1 block) is unlikely to be the genesis block, + derivedFromRef, err := derivedFrom.WithParent(eth.BlockID{}) + if err != nil { + // if the first derivedFrom isn't the genesis block, just warn and continue anyway + db.logger.Warn("First DerivedFrom is not genesis block") + derivedFromRef = derivedFrom.ForceWithParent(eth.BlockID{}) + } + // the first derived must be the genesis block, panic otherwise + derivedRef := derived.MustWithParent(eth.BlockID{}) + return derivedFromRef, derivedRef, nil + } + return eth.BlockRef{}, eth.BlockRef{}, err + } + // Find the local-safe block that comes right after the last seen cross-safe block. + // Just L2 block by block traversal, conditional on being local-safe. + // This will be the candidate L2 block to promote. + + // While the local-safe block isn't cross-safe given limited L1 scope, we'll keep bumping the L1 scope, + // And update cross-safe accordingly. + // This method will keep returning the latest known scope that has been verified to be cross-safe. + candidateFrom, candidate, err := lDB.NextDerived(crossDerived.ID()) + if err != nil { + return eth.BlockRef{}, eth.BlockRef{}, err + } + + candidateRef := candidate.MustWithParent(crossDerived.ID()) + + parentDerivedFrom, err := lDB.PreviousDerivedFrom(candidateFrom.ID()) + // if we are working with the first item in the database, PreviousDerivedFrom will return ErrPreviousToFirst + // in which case we can attach a zero parent to the cross-derived-from block, as the parent block is unknown + if errors.Is(err, types.ErrPreviousToFirst) { + parentDerivedFrom = types.BlockSeal{} + } else if err != nil { + return eth.BlockRef{}, eth.BlockRef{}, fmt.Errorf("failed to find parent-block of derived-from %s: %w", candidateFrom, err) + } + candidateFromRef := candidateFrom.MustWithParent(parentDerivedFrom.ID()) + + // Allow increment of DA by 1, if we know the floor (due to local safety) is 1 ahead of the current cross-safe L1 scope. + if candidateFrom.Number > crossDerivedFrom.Number+1 { + // If we are not ready to process the candidate block, + // then we need to stick to the current scope, so the caller can bump up from there. + var crossDerivedFromRef eth.BlockRef + parent, err := lDB.PreviousDerivedFrom(crossDerivedFrom.ID()) + // if we are working with the first item in the database, PreviousDerivedFrom will return ErrPreviousToFirst + // in which case we can attach a zero parent to the cross-derived-from block, as the parent block is unknown + if errors.Is(err, types.ErrPreviousToFirst) { + crossDerivedFromRef = crossDerivedFrom.ForceWithParent(eth.BlockID{}) + } else if err != nil { + return eth.BlockRef{}, eth.BlockRef{}, + fmt.Errorf("failed to find parent-block of cross-derived-from %s: %w", crossDerivedFrom, err) + } else { + crossDerivedFromRef = crossDerivedFrom.MustWithParent(parent.ID()) + } + return crossDerivedFromRef, eth.BlockRef{}, + fmt.Errorf("candidate is from %s, while current scope is %s: %w", + candidateFrom, crossDerivedFrom, types.ErrOutOfScope) + } + return candidateFromRef, candidateRef, nil +} + +func (db *ChainsDB) PreviousDerived(chain types.ChainID, derived eth.BlockID) (prevDerived types.BlockSeal, err error) { + lDB, ok := db.localDBs.Get(chain) + if !ok { + return types.BlockSeal{}, types.ErrUnknownChain + } + return lDB.PreviousDerived(derived) +} + +func (db *ChainsDB) PreviousDerivedFrom(chain types.ChainID, derivedFrom eth.BlockID) (prevDerivedFrom types.BlockSeal, err error) { + lDB, ok := db.localDBs.Get(chain) + if !ok { + return types.BlockSeal{}, types.ErrUnknownChain + } + return lDB.PreviousDerivedFrom(derivedFrom) +} + +func (db *ChainsDB) NextDerivedFrom(chain types.ChainID, derivedFrom eth.BlockID) (after eth.BlockRef, err error) { + lDB, ok := db.localDBs.Get(chain) + if !ok { + return eth.BlockRef{}, types.ErrUnknownChain + } + v, err := lDB.NextDerivedFrom(derivedFrom) + if err != nil { + return eth.BlockRef{}, err + } + return v.MustWithParent(derivedFrom), nil +} + // Safest returns the strongest safety level that can be guaranteed for the given log entry. // it assumes the log entry has already been checked and is valid, this function only checks safety levels. -// Cross-safety levels are all considered to be more safe than any form of local-safety. +// Safety levels are assumed to graduate from LocalUnsafe to LocalSafe to CrossUnsafe to CrossSafe, with Finalized as the strongest. func (db *ChainsDB) Safest(chainID types.ChainID, blockNum uint64, index uint32) (safest types.SafetyLevel, err error) { - db.mu.RLock() - defer db.mu.RUnlock() - if finalized, err := db.Finalized(chainID); err == nil { if finalized.Number >= blockNum { return types.Finalized, nil @@ -179,9 +366,9 @@ func (db *ChainsDB) Safest(chainID types.ChainID, blockNum uint64, index uint32) } func (db *ChainsDB) IteratorStartingAt(chain types.ChainID, sealedNum uint64, logIndex uint32) (logs.Iterator, error) { - logDB, ok := db.logDBs[chain] + logDB, ok := db.logDBs.Get(chain) if !ok { - return nil, fmt.Errorf("%w: %v", ErrUnknownChain, chain) + return nil, fmt.Errorf("%w: %v", types.ErrUnknownChain, chain) } return logDB.IteratorStartingAt(sealedNum, logIndex) } diff --git a/op-supervisor/supervisor/backend/db/update.go b/op-supervisor/supervisor/backend/db/update.go index 9825b76fdafc9..7ae7fde58a8bd 100644 --- a/op-supervisor/supervisor/backend/db/update.go +++ b/op-supervisor/supervisor/backend/db/update.go @@ -15,82 +15,74 @@ func (db *ChainsDB) AddLog( parentBlock eth.BlockID, logIdx uint32, execMsg *types.ExecutingMessage) error { - db.mu.RLock() - defer db.mu.RUnlock() - - logDB, ok := db.logDBs[chain] + logDB, ok := db.logDBs.Get(chain) if !ok { - return fmt.Errorf("cannot AddLog: %w: %v", ErrUnknownChain, chain) + return fmt.Errorf("cannot AddLog: %w: %v", types.ErrUnknownChain, chain) } return logDB.AddLog(logHash, parentBlock, logIdx, execMsg) } func (db *ChainsDB) SealBlock(chain types.ChainID, block eth.BlockRef) error { - db.mu.RLock() - defer db.mu.RUnlock() - - logDB, ok := db.logDBs[chain] + logDB, ok := db.logDBs.Get(chain) if !ok { - return fmt.Errorf("cannot SealBlock: %w: %v", ErrUnknownChain, chain) + return fmt.Errorf("cannot SealBlock: %w: %v", types.ErrUnknownChain, chain) } err := logDB.SealBlock(block.ParentHash, block.ID(), block.Time) if err != nil { return fmt.Errorf("failed to seal block %v: %w", block, err) } + db.logger.Info("Updated local unsafe", "chain", chain, "block", block) return nil } func (db *ChainsDB) Rewind(chain types.ChainID, headBlockNum uint64) error { - db.mu.RLock() - defer db.mu.RUnlock() - - logDB, ok := db.logDBs[chain] + logDB, ok := db.logDBs.Get(chain) if !ok { - return fmt.Errorf("cannot Rewind: %w: %s", ErrUnknownChain, chain) + return fmt.Errorf("cannot Rewind: %w: %s", types.ErrUnknownChain, chain) } return logDB.Rewind(headBlockNum) } func (db *ChainsDB) UpdateLocalSafe(chain types.ChainID, derivedFrom eth.BlockRef, lastDerived eth.BlockRef) error { - db.mu.RLock() - defer db.mu.RUnlock() - - localDB, ok := db.localDBs[chain] + localDB, ok := db.localDBs.Get(chain) if !ok { - return fmt.Errorf("cannot UpdateLocalSafe: %w: %v", ErrUnknownChain, chain) + return fmt.Errorf("cannot UpdateLocalSafe: %w: %v", types.ErrUnknownChain, chain) } + db.logger.Debug("Updating local safe", "chain", chain, "derivedFrom", derivedFrom, "lastDerived", lastDerived) return localDB.AddDerived(derivedFrom, lastDerived) } func (db *ChainsDB) UpdateCrossUnsafe(chain types.ChainID, crossUnsafe types.BlockSeal) error { - db.mu.RLock() - defer db.mu.RUnlock() - - if _, ok := db.crossUnsafe[chain]; !ok { - return fmt.Errorf("cannot UpdateCrossUnsafe: %w: %s", ErrUnknownChain, chain) + v, ok := db.crossUnsafe.Get(chain) + if !ok { + return fmt.Errorf("cannot UpdateCrossUnsafe: %w: %s", types.ErrUnknownChain, chain) } - db.crossUnsafe[chain] = crossUnsafe + v.Set(crossUnsafe) + db.logger.Info("Updated cross-unsafe", "chain", chain, "crossUnsafe", crossUnsafe) return nil } func (db *ChainsDB) UpdateCrossSafe(chain types.ChainID, l1View eth.BlockRef, lastCrossDerived eth.BlockRef) error { - db.mu.RLock() - defer db.mu.RUnlock() - - crossDB, ok := db.crossDBs[chain] + crossDB, ok := db.crossDBs.Get(chain) if !ok { - return fmt.Errorf("cannot UpdateCrossSafe: %w: %s", ErrUnknownChain, chain) + return fmt.Errorf("cannot UpdateCrossSafe: %w: %s", types.ErrUnknownChain, chain) } - return crossDB.AddDerived(l1View, lastCrossDerived) + if err := crossDB.AddDerived(l1View, lastCrossDerived); err != nil { + return err + } + db.logger.Info("Updated cross-safe", "chain", chain, "l1View", l1View, "lastCrossDerived", lastCrossDerived) + return nil } func (db *ChainsDB) UpdateFinalizedL1(finalized eth.BlockRef) error { - db.mu.RLock() - defer db.mu.RUnlock() + // Lock, so we avoid race-conditions in-between getting (for comparison) and setting. + db.finalizedL1.Lock() + defer db.finalizedL1.Unlock() - if db.finalizedL1.Number > finalized.Number { - return fmt.Errorf("cannot rewind finalized L1 head from %s to %s", db.finalizedL1, finalized) + if v := db.finalizedL1.Value; v.Number > finalized.Number { + return fmt.Errorf("cannot rewind finalized L1 head from %s to %s", v, finalized) } - db.finalizedL1 = finalized + db.finalizedL1.Value = finalized + db.logger.Info("Updated finalized L1", "finalizedL1", finalized) return nil } diff --git a/op-supervisor/supervisor/backend/depset/depset.go b/op-supervisor/supervisor/backend/depset/depset.go index 06127726f0007..da32b77190087 100644 --- a/op-supervisor/supervisor/backend/depset/depset.go +++ b/op-supervisor/supervisor/backend/depset/depset.go @@ -32,4 +32,10 @@ type DependencySet interface { // HasChain determines if a chain is being tracked for interop purposes. // See CanExecuteAt and CanInitiateAt to check if a chain may message at a given time. HasChain(chainID types.ChainID) bool + + // ChainIndexFromID converts a ChainID to a ChainIndex. + ChainIndexFromID(id types.ChainID) (types.ChainIndex, error) + + // ChainIDFromIndex converts a ChainIndex to a ChainID. + ChainIDFromIndex(index types.ChainIndex) (types.ChainID, error) } diff --git a/op-supervisor/supervisor/backend/depset/depset_test.go b/op-supervisor/supervisor/backend/depset/depset_test.go index 42dbb284d6e29..8b71b38ef46ed 100644 --- a/op-supervisor/supervisor/backend/depset/depset_test.go +++ b/op-supervisor/supervisor/backend/depset/depset_test.go @@ -15,18 +15,20 @@ import ( func TestDependencySet(t *testing.T) { d := path.Join(t.TempDir(), "tmp_dep_set.json") - depSet := &StaticConfigDependencySet{ - Dependencies: map[types.ChainID]*StaticConfigDependency{ + depSet, err := NewStaticConfigDependencySet( + map[types.ChainID]*StaticConfigDependency{ types.ChainIDFromUInt64(900): { + ChainIndex: 900, ActivationTime: 42, HistoryMinTime: 100, }, types.ChainIDFromUInt64(901): { + ChainIndex: 901, ActivationTime: 30, HistoryMinTime: 20, }, - }, - } + }) + require.NoError(t, err) data, err := json.Marshal(depSet) require.NoError(t, err) diff --git a/op-supervisor/supervisor/backend/depset/static.go b/op-supervisor/supervisor/backend/depset/static.go index 0ef2874bb527f..f7cf1c166de53 100644 --- a/op-supervisor/supervisor/backend/depset/static.go +++ b/op-supervisor/supervisor/backend/depset/static.go @@ -2,14 +2,18 @@ package depset import ( "context" + "encoding/json" + "fmt" + "slices" "sort" - "golang.org/x/exp/maps" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) type StaticConfigDependency struct { + // ChainIndex is the unique short identifier of this chain. + ChainIndex types.ChainIndex `json:"chainIndex"` + // ActivationTime is when the chain becomes part of the dependency set. // This is the minimum timestamp of the inclusion of an executing message. ActivationTime uint64 `json:"activationTime"` @@ -23,9 +27,62 @@ type StaticConfigDependency struct { // StaticConfigDependencySet statically declares a DependencySet. // It can be used as a DependencySetSource itself, by simply returning the itself when loading the set. type StaticConfigDependencySet struct { + // dependency info per chain + dependencies map[types.ChainID]*StaticConfigDependency + // cached mapping of chain index to chain ID + indexToID map[types.ChainIndex]types.ChainID + // cached list of chain IDs, sorted by ID value + chainIDs []types.ChainID +} + +func NewStaticConfigDependencySet(dependencies map[types.ChainID]*StaticConfigDependency) (*StaticConfigDependencySet, error) { + out := &StaticConfigDependencySet{dependencies: dependencies} + if err := out.hydrate(); err != nil { + return nil, err + } + return out, nil +} + +// jsonStaticConfigDependencySet is a util for JSON encoding/decoding, +// to encode/decode just the attributes that matter, +// while wrapping the decoding functionality with additional hydration step. +type jsonStaticConfigDependencySet struct { Dependencies map[types.ChainID]*StaticConfigDependency `json:"dependencies"` } +func (ds *StaticConfigDependencySet) MarshalJSON() ([]byte, error) { + out := &jsonStaticConfigDependencySet{ + Dependencies: ds.dependencies, + } + return json.Marshal(out) +} + +func (ds *StaticConfigDependencySet) UnmarshalJSON(data []byte) error { + var v jsonStaticConfigDependencySet + if err := json.Unmarshal(data, &v); err != nil { + return err + } + ds.dependencies = v.Dependencies + return ds.hydrate() +} + +// hydrate sets all the cached values, based on the dependencies attribute +func (ds *StaticConfigDependencySet) hydrate() error { + ds.indexToID = make(map[types.ChainIndex]types.ChainID) + ds.chainIDs = make([]types.ChainID, 0, len(ds.dependencies)) + for id, dep := range ds.dependencies { + if existing, ok := ds.indexToID[dep.ChainIndex]; ok { + return fmt.Errorf("chain %s cannot have the same index (%d) as chain %s", id, dep.ChainIndex, existing) + } + ds.indexToID[dep.ChainIndex] = id + ds.chainIDs = append(ds.chainIDs, id) + } + sort.Slice(ds.chainIDs, func(i, j int) bool { + return ds.chainIDs[i].Cmp(ds.chainIDs[j]) < 0 + }) + return nil +} + var _ DependencySetSource = (*StaticConfigDependencySet)(nil) var _ DependencySet = (*StaticConfigDependencySet)(nil) @@ -35,7 +92,7 @@ func (ds *StaticConfigDependencySet) LoadDependencySet(ctx context.Context) (Dep } func (ds *StaticConfigDependencySet) CanExecuteAt(chainID types.ChainID, execTimestamp uint64) (bool, error) { - dep, ok := ds.Dependencies[chainID] + dep, ok := ds.dependencies[chainID] if !ok { return false, nil } @@ -43,7 +100,7 @@ func (ds *StaticConfigDependencySet) CanExecuteAt(chainID types.ChainID, execTim } func (ds *StaticConfigDependencySet) CanInitiateAt(chainID types.ChainID, initTimestamp uint64) (bool, error) { - dep, ok := ds.Dependencies[chainID] + dep, ok := ds.dependencies[chainID] if !ok { return false, nil } @@ -51,14 +108,26 @@ func (ds *StaticConfigDependencySet) CanInitiateAt(chainID types.ChainID, initTi } func (ds *StaticConfigDependencySet) Chains() []types.ChainID { - out := maps.Keys(ds.Dependencies) - sort.Slice(out, func(i, j int) bool { - return out[i].Cmp(out[j]) < 0 - }) - return out + return slices.Clone(ds.chainIDs) } func (ds *StaticConfigDependencySet) HasChain(chainID types.ChainID) bool { - _, ok := ds.Dependencies[chainID] + _, ok := ds.dependencies[chainID] return ok } + +func (ds *StaticConfigDependencySet) ChainIndexFromID(id types.ChainID) (types.ChainIndex, error) { + dep, ok := ds.dependencies[id] + if !ok { + return 0, types.ErrUnknownChain + } + return dep.ChainIndex, nil +} + +func (ds *StaticConfigDependencySet) ChainIDFromIndex(index types.ChainIndex) (types.ChainID, error) { + id, ok := ds.indexToID[index] + if !ok { + return types.ChainID{}, types.ErrUnknownChain + } + return id, nil +} diff --git a/op-supervisor/supervisor/backend/mock.go b/op-supervisor/supervisor/backend/mock.go index 0cee49463197d..b40c5209d5ef2 100644 --- a/op-supervisor/supervisor/backend/mock.go +++ b/op-supervisor/supervisor/backend/mock.go @@ -62,19 +62,19 @@ func (m *MockBackend) Finalized(ctx context.Context, chainID types.ChainID) (eth return eth.BlockID{}, nil } -func (m *MockBackend) DerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (derivedFrom eth.BlockID, err error) { - return eth.BlockID{}, nil +func (m *MockBackend) CrossDerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (derivedFrom eth.BlockRef, err error) { + return eth.BlockRef{}, nil } -func (m *MockBackend) UpdateLocalUnsafe(chainID types.ChainID, head eth.BlockRef) error { +func (m *MockBackend) UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.BlockRef) error { return nil } -func (m *MockBackend) UpdateLocalSafe(chainID types.ChainID, derivedFrom eth.BlockRef, lastDerived eth.BlockRef) error { +func (m *MockBackend) UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.BlockRef, lastDerived eth.BlockRef) error { return nil } -func (m *MockBackend) UpdateFinalizedL1(chainID types.ChainID, finalized eth.BlockRef) error { +func (m *MockBackend) UpdateFinalizedL1(ctx context.Context, chainID types.ChainID, finalized eth.BlockRef) error { return nil } diff --git a/op-supervisor/supervisor/backend/processors/chain_processor.go b/op-supervisor/supervisor/backend/processors/chain_processor.go index d27c26fe2bbc2..688f68ac61197 100644 --- a/op-supervisor/supervisor/backend/processors/chain_processor.go +++ b/op-supervisor/supervisor/backend/processors/chain_processor.go @@ -17,8 +17,6 @@ import ( "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) -var ErrNoRPCSource = errors.New("no RPC client configured") - type Source interface { L1BlockRefByNumber(ctx context.Context, number uint64) (eth.L1BlockRef, error) FetchReceipts(ctx context.Context, blockHash common.Hash) (eth.BlockInfo, gethtypes.Receipts, error) @@ -57,8 +55,8 @@ type ChainProcessor struct { // channel with capacity of 1, full if there is work to do newHead chan struct{} - // channel with capacity of 1, to signal work complete if running in synchroneous mode - out chan struct{} + // to signal to the other services that new indexed data is available + onIndexed func() // lifetime management of the chain processor ctx context.Context @@ -66,7 +64,7 @@ type ChainProcessor struct { wg sync.WaitGroup } -func NewChainProcessor(log log.Logger, chain types.ChainID, processor LogProcessor, rewinder DatabaseRewinder) *ChainProcessor { +func NewChainProcessor(log log.Logger, chain types.ChainID, processor LogProcessor, rewinder DatabaseRewinder, onIndexed func()) *ChainProcessor { ctx, cancel := context.WithCancel(context.Background()) out := &ChainProcessor{ log: log.New("chain", chain), @@ -75,7 +73,7 @@ func NewChainProcessor(log log.Logger, chain types.ChainID, processor LogProcess processor: processor, rewinder: rewinder, newHead: make(chan struct{}, 1), - out: make(chan struct{}, 1), + onIndexed: onIndexed, ctx: ctx, cancel: cancel, } @@ -136,8 +134,8 @@ func (s *ChainProcessor) work() { target := s.nextNum() if err := s.update(target); err != nil { if errors.Is(err, ethereum.NotFound) { - s.log.Info("Cannot find next block yet", "target", target) - } else if errors.Is(err, ErrNoRPCSource) { + s.log.Debug("Event-indexer cannot find next block yet", "target", target, "err", err) + } else if errors.Is(err, types.ErrNoRPCSource) { s.log.Warn("No RPC source configured, cannot process new blocks") } else { s.log.Error("Failed to process new block", "err", err) @@ -158,7 +156,7 @@ func (s *ChainProcessor) update(nextNum uint64) error { defer s.clientLock.Unlock() if s.client == nil { - return ErrNoRPCSource + return types.ErrNoRPCSource } ctx, cancel := context.WithTimeout(s.ctx, time.Second*10) @@ -194,7 +192,10 @@ func (s *ChainProcessor) update(nextNum uint64) error { // If no logs were written successfully then the rewind wouldn't have done anything anyway. s.log.Error("Failed to rewind after error processing block", "block", next, "err", err) } + return err } + s.log.Info("Indexed block events", "block", next, "txs", len(receipts)) + s.onIndexed() return nil } diff --git a/op-supervisor/supervisor/backend/processors/contracts/l2inbox.go b/op-supervisor/supervisor/backend/processors/contracts/l2inbox.go deleted file mode 100644 index 213b6ce1bad96..0000000000000 --- a/op-supervisor/supervisor/backend/processors/contracts/l2inbox.go +++ /dev/null @@ -1,133 +0,0 @@ -package contracts - -import ( - "bytes" - "errors" - "fmt" - "io" - "math/big" - - "github.com/ethereum-optimism/optimism/op-service/predeploys" - "github.com/ethereum-optimism/optimism/op-service/solabi" - "github.com/ethereum-optimism/optimism/op-service/sources/batching" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" - "github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots" - "github.com/ethereum/go-ethereum/common" - ethTypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" -) - -const ( - eventExecutingMessage = "ExecutingMessage" -) - -var ( - ErrEventNotFound = errors.New("event not found") -) - -type contractIdentifier struct { - // Origin represents the address that initiated the message - // it is used in combination with the MsgHash to uniquely identify a message - // and is hashed into the log hash, not stored directly. - Origin common.Address - LogIndex *big.Int - BlockNumber *big.Int - ChainId *big.Int - Timestamp *big.Int -} - -type CrossL2Inbox struct { - contract *batching.BoundContract -} - -func NewCrossL2Inbox() *CrossL2Inbox { - abi := snapshots.LoadCrossL2InboxABI() - return &CrossL2Inbox{ - contract: batching.NewBoundContract(abi, predeploys.CrossL2InboxAddr), - } -} - -func (i *CrossL2Inbox) DecodeExecutingMessageLog(l *ethTypes.Log) (types.ExecutingMessage, error) { - if l.Address != i.contract.Addr() { - return types.ExecutingMessage{}, fmt.Errorf("%w: log not from CrossL2Inbox", ErrEventNotFound) - } - // use DecodeEvent to check the name of the event - // but the actual decoding is done manually to extract the contract identifier - name, _, err := i.contract.DecodeEvent(l) - if errors.Is(err, batching.ErrUnknownEvent) { - return types.ExecutingMessage{}, fmt.Errorf("%w: %v", ErrEventNotFound, err.Error()) - } else if err != nil { - return types.ExecutingMessage{}, fmt.Errorf("failed to decode event: %w", err) - } - if name != eventExecutingMessage { - return types.ExecutingMessage{}, fmt.Errorf("%w: event %v not an ExecutingMessage event", ErrEventNotFound, name) - } - // the second topic is the hash of the payload (the first is the event ID) - msgHash := l.Topics[1] - // the first 32 bytes of the data are the msgHash, so we skip them - identifierBytes := bytes.NewReader(l.Data[32:]) - identifier, err := identifierFromBytes(identifierBytes) - if err != nil { - return types.ExecutingMessage{}, fmt.Errorf("failed to read contract identifier: %w", err) - } - chainID, err := types.ChainIDFromBig(identifier.ChainId).ToUInt32() - if err != nil { - return types.ExecutingMessage{}, fmt.Errorf("failed to convert chain ID %v to uint32: %w", identifier.ChainId, err) - } - hash := payloadHashToLogHash(msgHash, identifier.Origin) - return types.ExecutingMessage{ - Chain: chainID, - Hash: hash, - BlockNum: identifier.BlockNumber.Uint64(), - LogIdx: uint32(identifier.LogIndex.Uint64()), - Timestamp: identifier.Timestamp.Uint64(), - }, nil -} - -// identifierFromBytes reads a contract identifier from a byte stream. -// it follows the spec and matches the CrossL2Inbox.json definition, -// rather than relying on reflection, as that can be error-prone regarding struct ordering -func identifierFromBytes(identifierBytes io.Reader) (contractIdentifier, error) { - origin, err := solabi.ReadAddress(identifierBytes) - if err != nil { - return contractIdentifier{}, fmt.Errorf("failed to read origin address: %w", err) - } - originAddr := common.BytesToAddress(origin[:]) - blockNumber, err := solabi.ReadUint256(identifierBytes) - if err != nil { - return contractIdentifier{}, fmt.Errorf("failed to read block number: %w", err) - } - logIndex, err := solabi.ReadUint256(identifierBytes) - if err != nil { - return contractIdentifier{}, fmt.Errorf("failed to read log index: %w", err) - } - timestamp, err := solabi.ReadUint256(identifierBytes) - if err != nil { - return contractIdentifier{}, fmt.Errorf("failed to read timestamp: %w", err) - } - chainID, err := solabi.ReadUint256(identifierBytes) - if err != nil { - return contractIdentifier{}, fmt.Errorf("failed to read chain ID: %w", err) - } - return contractIdentifier{ - Origin: originAddr, - BlockNumber: blockNumber, - LogIndex: logIndex, - Timestamp: timestamp, - ChainId: chainID, - }, nil -} - -// payloadHashToLogHash converts the payload hash to the log hash -// it is the concatenation of the log's address and the hash of the log's payload, -// which is then hashed again. This is the hash that is stored in the log storage. -// The logHash can then be used to traverse from the executing message -// to the log the referenced initiating message. -// TODO(#12424): this function is duplicated between contracts and backend/source/log_processor.go -// to avoid a circular dependency. It should be reorganized to avoid this duplication. -func payloadHashToLogHash(payloadHash common.Hash, addr common.Address) common.Hash { - msg := make([]byte, 0, 2*common.HashLength) - msg = append(msg, addr.Bytes()...) - msg = append(msg, payloadHash.Bytes()...) - return crypto.Keccak256Hash(msg) -} diff --git a/op-supervisor/supervisor/backend/processors/contracts/l2inbox_test.go b/op-supervisor/supervisor/backend/processors/contracts/l2inbox_test.go deleted file mode 100644 index 302b188e5cdf7..0000000000000 --- a/op-supervisor/supervisor/backend/processors/contracts/l2inbox_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package contracts - -import ( - "bytes" - "math/big" - "testing" - - "github.com/ethereum-optimism/optimism/op-service/predeploys" - "github.com/ethereum-optimism/optimism/op-service/sources/batching" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" - "github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots" - "github.com/ethereum/go-ethereum/common" - ethTypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/stretchr/testify/require" -) - -func TestDecodeExecutingMessageEvent(t *testing.T) { - inbox := NewCrossL2Inbox() - payload := bytes.Repeat([]byte{0xaa, 0xbb}, 50) - payloadHash := crypto.Keccak256Hash(payload) - expected := types.ExecutingMessage{ - Chain: 42424, - BlockNum: 12345, - LogIdx: 98, - Timestamp: 9578295, - } - contractIdent := contractIdentifier{ - Origin: common.Address{0xbb, 0xcc}, - ChainId: new(big.Int).SetUint64(uint64(expected.Chain)), - BlockNumber: new(big.Int).SetUint64(expected.BlockNum), - Timestamp: new(big.Int).SetUint64(expected.Timestamp), - LogIndex: new(big.Int).SetUint64(uint64(expected.LogIdx)), - } - expected.Hash = payloadHashToLogHash(payloadHash, contractIdent.Origin) - abi := snapshots.LoadCrossL2InboxABI() - validData, err := abi.Events[eventExecutingMessage].Inputs.Pack(payloadHash, contractIdent) - require.NoError(t, err) - createValidLog := func() *ethTypes.Log { - //protoHack := bytes.Repeat([]byte{0x00}, 32*5) - return ðTypes.Log{ - Address: predeploys.CrossL2InboxAddr, - Topics: []common.Hash{abi.Events[eventExecutingMessage].ID, payloadHash}, - Data: validData, - } - } - - t.Run("ParseValid", func(t *testing.T) { - l := createValidLog() - result, err := inbox.DecodeExecutingMessageLog(l) - require.NoError(t, err) - require.Equal(t, expected, result) - }) - - t.Run("IgnoreIncorrectContract", func(t *testing.T) { - l := createValidLog() - l.Address = common.Address{0xff} - _, err := inbox.DecodeExecutingMessageLog(l) - require.ErrorIs(t, err, ErrEventNotFound) - }) - - t.Run("IgnoreWrongEvent", func(t *testing.T) { - l := createValidLog() - l.Topics[0] = common.Hash{0xbb} - _, err := inbox.DecodeExecutingMessageLog(l) - require.ErrorIs(t, err, ErrEventNotFound) - }) - - t.Run("ErrorOnInvalidEvent", func(t *testing.T) { - l := createValidLog() - l.Data = []byte{0xbb, 0xcc} - _, err := inbox.DecodeExecutingMessageLog(l) - require.ErrorIs(t, err, batching.ErrInvalidEvent) - }) -} diff --git a/op-supervisor/supervisor/backend/processors/executing_message.go b/op-supervisor/supervisor/backend/processors/executing_message.go new file mode 100644 index 0000000000000..eedd8ce4b1e34 --- /dev/null +++ b/op-supervisor/supervisor/backend/processors/executing_message.go @@ -0,0 +1,38 @@ +package processors + +import ( + "fmt" + + ethTypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/types/interoptypes" + "github.com/ethereum/go-ethereum/params" + + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" +) + +type EventDecoderFn func(*ethTypes.Log) (*types.ExecutingMessage, error) + +func DecodeExecutingMessageLog(l *ethTypes.Log) (*types.ExecutingMessage, error) { + if l.Address != params.InteropCrossL2InboxAddress { + return nil, nil + } + if len(l.Topics) != 2 { // topics: event-id and payload-hash + return nil, nil + } + if l.Topics[0] != interoptypes.ExecutingMessageEventTopic { + return nil, nil + } + var msg interoptypes.Message + if err := msg.DecodeEvent(l.Topics, l.Data); err != nil { + return nil, fmt.Errorf("invalid executing message: %w", err) + } + logHash := types.PayloadHashToLogHash(msg.PayloadHash, msg.Identifier.Origin) + return &types.ExecutingMessage{ + // TODO(#11105): translate chain index to chain ID + Chain: types.ChainIndex(msg.Identifier.ChainID.Uint64()), + BlockNum: msg.Identifier.BlockNumber, + LogIdx: msg.Identifier.LogIndex, + Timestamp: msg.Identifier.Timestamp, + Hash: logHash, + }, nil +} diff --git a/op-supervisor/supervisor/backend/processors/executing_message_test.go b/op-supervisor/supervisor/backend/processors/executing_message_test.go new file mode 100644 index 0000000000000..6badeb2016726 --- /dev/null +++ b/op-supervisor/supervisor/backend/processors/executing_message_test.go @@ -0,0 +1,58 @@ +package processors + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/common" + ethTypes "github.com/ethereum/go-ethereum/core/types" + + "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" +) + +func TestDecodeExecutingMessageLog(t *testing.T) { + data := ` +{ + "address": "0x4200000000000000000000000000000000000022", + "topics": [ + "0x5c37832d2e8d10e346e55ad62071a6a2f9fa5130614ef2ec6617555c6f467ba7", + "0xc3f57e1f0dd62a4f77787d834029bfeaab8894022c47edbe13b044fb658c9190" + ], + "data": "0x0000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa3000000000000000000000000000000000000000000000000000000000000119d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006724d56300000000000000000000000000000000000000000000000000000000000dbc68", + "blockHash": "0x355b82e9db9105fe3e7b7ed1897878ecbba8be7f30f94aca9dc55b6296a624cf", + "blockNumber": "0x13a8", + "transactionHash": "0x6eb22bb67562ac6a8fdbf60d6227c0b1f3f9d1d15ead1b0de055358f4fb9fa69", + "transactionIndex": "0x2", + "logIndex": "0x0", + "removed": false +} +` + var logEvent ethTypes.Log + require.NoError(t, json.Unmarshal([]byte(data), &logEvent)) + + msg, err := DecodeExecutingMessageLog(&logEvent) + require.NoError(t, err) + require.NotNil(t, msg) + + // struct Identifier { + // address origin; + // uint256 blockNumber; + // uint256 logIndex; + // uint256 timestamp; + // uint256 chainId; + // } + // function executeMessage(Identifier calldata _id, + // address _target, bytes calldata _message) external payable; + + originAddr := common.HexToAddress("0x5fbdb2315678afecb367f032d93f642f64180aa3") + payloadHash := common.HexToHash("0xc3f57e1f0dd62a4f77787d834029bfeaab8894022c47edbe13b044fb658c9190") + logHash := types.PayloadHashToLogHash(payloadHash, originAddr) + + require.Equal(t, logHash, msg.Hash) + require.Equal(t, uint64(4509), msg.BlockNum) + require.Equal(t, uint32(0), msg.LogIdx) + require.Equal(t, uint64(1730467171), msg.Timestamp) + require.Equal(t, types.ChainIndex(900200), msg.Chain) +} diff --git a/op-supervisor/supervisor/backend/processors/log_processor.go b/op-supervisor/supervisor/backend/processors/log_processor.go index 01846f32795c5..2ca79c4d2f2f0 100644 --- a/op-supervisor/supervisor/backend/processors/log_processor.go +++ b/op-supervisor/supervisor/backend/processors/log_processor.go @@ -2,7 +2,6 @@ package processors import ( "context" - "errors" "fmt" "github.com/ethereum/go-ethereum/common" @@ -10,7 +9,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum-optimism/optimism/op-service/eth" - "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/backend/processors/contracts" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" ) @@ -24,21 +22,17 @@ type ChainsDBClientForLogProcessor interface { AddLog(chain types.ChainID, logHash common.Hash, parentBlock eth.BlockID, logIdx uint32, execMsg *types.ExecutingMessage) error } -type EventDecoder interface { - DecodeExecutingMessageLog(log *ethTypes.Log) (types.ExecutingMessage, error) -} - type logProcessor struct { chain types.ChainID logStore LogStorage - eventDecoder EventDecoder + eventDecoder EventDecoderFn } func NewLogProcessor(chain types.ChainID, logStore LogStorage) LogProcessor { return &logProcessor{ chain: chain, logStore: logStore, - eventDecoder: contracts.NewCrossL2Inbox(), + eventDecoder: DecodeExecutingMessageLog, } } @@ -49,19 +43,15 @@ func (p *logProcessor) ProcessLogs(_ context.Context, block eth.BlockRef, rcpts for _, l := range rcpt.Logs { // log hash represents the hash of *this* log as a potentially initiating message logHash := logToLogHash(l) - var execMsg *types.ExecutingMessage - msg, err := p.eventDecoder.DecodeExecutingMessageLog(l) - if err != nil && !errors.Is(err, contracts.ErrEventNotFound) { - return fmt.Errorf("failed to decode executing message log: %w", err) - } else if err == nil { - // if the log is an executing message, store the message - execMsg = &msg + // The log may be an executing message emitted by the CrossL2Inbox + execMsg, err := p.eventDecoder(l) + if err != nil { + return fmt.Errorf("invalid log %d from block %s: %w", l.Index, block.ID(), err) } // executing messages have multiple entries in the database // they should start with the initiating message and then include the execution - err = p.logStore.AddLog(p.chain, logHash, block.ParentID(), uint32(l.Index), execMsg) - if err != nil { - return fmt.Errorf("failed to add log %d from block %v: %w", l.Index, block.ID(), err) + if err := p.logStore.AddLog(p.chain, logHash, block.ParentID(), uint32(l.Index), execMsg); err != nil { + return fmt.Errorf("failed to add log %d from block %s: %w", l.Index, block.ID(), err) } } } @@ -77,30 +67,6 @@ func (p *logProcessor) ProcessLogs(_ context.Context, block eth.BlockRef, rcpts // The address is hashed into the payload hash to save space in the log storage, // and because they represent paired data. func logToLogHash(l *ethTypes.Log) common.Hash { - payloadHash := crypto.Keccak256(logToMessagePayload(l)) - return payloadHashToLogHash(common.Hash(payloadHash), l.Address) -} - -// logToMessagePayload is the data that is hashed to get the logHash -// it is the concatenation of the log's topics and data -// the implementation is based on the interop messaging spec -func logToMessagePayload(l *ethTypes.Log) []byte { - msg := make([]byte, 0) - for _, topic := range l.Topics { - msg = append(msg, topic.Bytes()...) - } - msg = append(msg, l.Data...) - return msg -} - -// payloadHashToLogHash converts the payload hash to the log hash -// it is the concatenation of the log's address and the hash of the log's payload, -// which is then hashed. This is the hash that is stored in the log storage. -// The logHash can then be used to traverse from the executing message -// to the log the referenced initiating message. -func payloadHashToLogHash(payloadHash common.Hash, addr common.Address) common.Hash { - msg := make([]byte, 0, 2*common.HashLength) - msg = append(msg, addr.Bytes()...) - msg = append(msg, payloadHash.Bytes()...) - return crypto.Keccak256Hash(msg) + payloadHash := crypto.Keccak256Hash(types.LogToMessagePayload(l)) + return types.PayloadHashToLogHash(payloadHash, l.Address) } diff --git a/op-supervisor/supervisor/backend/processors/log_processor_test.go b/op-supervisor/supervisor/backend/processors/log_processor_test.go index de28b1f6f5082..f919d4f801ed8 100644 --- a/op-supervisor/supervisor/backend/processors/log_processor_test.go +++ b/op-supervisor/supervisor/backend/processors/log_processor_test.go @@ -107,8 +107,8 @@ func TestLogProcessor(t *testing.T) { }, }, } - execMsg := types.ExecutingMessage{ - Chain: 4, + execMsg := &types.ExecutingMessage{ + Chain: 4, // TODO(#11105): translate chain ID to chain index BlockNum: 6, LogIdx: 8, Timestamp: 10, @@ -116,10 +116,10 @@ func TestLogProcessor(t *testing.T) { } store := &stubLogStorage{} processor := NewLogProcessor(types.ChainID{4}, store).(*logProcessor) - processor.eventDecoder = EventDecoderFn(func(l *ethTypes.Log) (types.ExecutingMessage, error) { + processor.eventDecoder = func(l *ethTypes.Log) (*types.ExecutingMessage, error) { require.Equal(t, rcpts[0].Logs[0], l) return execMsg, nil - }) + } err := processor.ProcessLogs(ctx, block1, rcpts) require.NoError(t, err) @@ -128,7 +128,7 @@ func TestLogProcessor(t *testing.T) { parent: block1.ParentID(), logIdx: 0, logHash: logToLogHash(rcpts[0].Logs[0]), - execMsg: &execMsg, + execMsg: execMsg, }, } require.Equal(t, expected, store.logs) @@ -242,9 +242,3 @@ type storedLog struct { logHash common.Hash execMsg *types.ExecutingMessage } - -type EventDecoderFn func(*ethTypes.Log) (types.ExecutingMessage, error) - -func (f EventDecoderFn) DecodeExecutingMessageLog(log *ethTypes.Log) (types.ExecutingMessage, error) { - return f(log) -} diff --git a/op-supervisor/supervisor/frontend/frontend.go b/op-supervisor/supervisor/frontend/frontend.go index 6b87b219e075a..0a5b70a4799a7 100644 --- a/op-supervisor/supervisor/frontend/frontend.go +++ b/op-supervisor/supervisor/frontend/frontend.go @@ -17,16 +17,16 @@ type AdminBackend interface { type QueryBackend interface { CheckMessage(identifier types.Identifier, payloadHash common.Hash) (types.SafetyLevel, error) CheckMessages(messages []types.Message, minSafety types.SafetyLevel) error - DerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (derivedFrom eth.BlockID, err error) + CrossDerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (derivedFrom eth.BlockRef, err error) UnsafeView(ctx context.Context, chainID types.ChainID, unsafe types.ReferenceView) (types.ReferenceView, error) SafeView(ctx context.Context, chainID types.ChainID, safe types.ReferenceView) (types.ReferenceView, error) Finalized(ctx context.Context, chainID types.ChainID) (eth.BlockID, error) } type UpdatesBackend interface { - UpdateLocalUnsafe(chainID types.ChainID, head eth.BlockRef) error - UpdateLocalSafe(chainID types.ChainID, derivedFrom eth.BlockRef, lastDerived eth.BlockRef) error - UpdateFinalizedL1(chainID types.ChainID, finalized eth.BlockRef) error + UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.BlockRef) error + UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.BlockRef, lastDerived eth.BlockRef) error + UpdateFinalizedL1(ctx context.Context, chainID types.ChainID, finalized eth.BlockRef) error } type Backend interface { @@ -39,6 +39,8 @@ type QueryFrontend struct { Supervisor QueryBackend } +var _ QueryBackend = (*QueryFrontend)(nil) + // CheckMessage checks the safety-level of an individual message. // The payloadHash references the hash of the message-payload of the message. func (q *QueryFrontend) CheckMessage(identifier types.Identifier, payloadHash common.Hash) (types.SafetyLevel, error) { @@ -65,14 +67,16 @@ func (q *QueryFrontend) Finalized(ctx context.Context, chainID types.ChainID) (e return q.Supervisor.Finalized(ctx, chainID) } -func (q *QueryFrontend) DerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (derivedFrom eth.BlockID, err error) { - return q.Supervisor.DerivedFrom(ctx, chainID, derived) +func (q *QueryFrontend) CrossDerivedFrom(ctx context.Context, chainID types.ChainID, derived eth.BlockID) (derivedFrom eth.BlockRef, err error) { + return q.Supervisor.CrossDerivedFrom(ctx, chainID, derived) } type AdminFrontend struct { Supervisor Backend } +var _ AdminBackend = (*AdminFrontend)(nil) + // Start starts the service, if it was previously stopped. func (a *AdminFrontend) Start(ctx context.Context) error { return a.Supervisor.Start(ctx) @@ -92,14 +96,16 @@ type UpdatesFrontend struct { Supervisor UpdatesBackend } -func (u *UpdatesFrontend) UpdateLocalUnsafe(chainID types.ChainID, head eth.BlockRef) error { - return u.Supervisor.UpdateLocalUnsafe(chainID, head) +var _ UpdatesBackend = (*UpdatesFrontend)(nil) + +func (u *UpdatesFrontend) UpdateLocalUnsafe(ctx context.Context, chainID types.ChainID, head eth.BlockRef) error { + return u.Supervisor.UpdateLocalUnsafe(ctx, chainID, head) } -func (u *UpdatesFrontend) UpdateLocalSafe(chainID types.ChainID, derivedFrom eth.BlockRef, lastDerived eth.BlockRef) error { - return u.Supervisor.UpdateLocalSafe(chainID, derivedFrom, lastDerived) +func (u *UpdatesFrontend) UpdateLocalSafe(ctx context.Context, chainID types.ChainID, derivedFrom eth.BlockRef, lastDerived eth.BlockRef) error { + return u.Supervisor.UpdateLocalSafe(ctx, chainID, derivedFrom, lastDerived) } -func (u *UpdatesFrontend) UpdateFinalizedL1(chainID types.ChainID, finalized eth.BlockRef) error { - return u.Supervisor.UpdateFinalizedL1(chainID, finalized) +func (u *UpdatesFrontend) UpdateFinalizedL1(ctx context.Context, chainID types.ChainID, finalized eth.BlockRef) error { + return u.Supervisor.UpdateFinalizedL1(ctx, chainID, finalized) } diff --git a/op-supervisor/supervisor/service.go b/op-supervisor/supervisor/service.go index 469a80439e349..7054c7e0ff555 100644 --- a/op-supervisor/supervisor/service.go +++ b/op-supervisor/supervisor/service.go @@ -72,6 +72,17 @@ func (su *SupervisorService) initBackend(ctx context.Context, cfg *config.Config su.backend = backend.NewMockBackend() return nil } + // the flag is a string slice, which has the potential to have empty strings + filterBlank := func(in []string) []string { + out := make([]string, 0, len(in)) + for _, s := range in { + if s != "" { + out = append(out, s) + } + } + return out + } + cfg.L2RPCs = filterBlank(cfg.L2RPCs) be, err := backend.NewSupervisorBackend(ctx, su.log, su.metrics, cfg) if err != nil { return fmt.Errorf("failed to create supervisor backend: %w", err) @@ -173,6 +184,7 @@ func (su *SupervisorService) Start(ctx context.Context) error { func (su *SupervisorService) Stop(ctx context.Context) error { if !su.closing.CompareAndSwap(false, true) { + su.log.Warn("Supervisor is already closing") return nil // already closing } su.log.Info("Stopping JSON-RPC server") diff --git a/op-supervisor/supervisor/service_test.go b/op-supervisor/supervisor/service_test.go index fad118e96a828..9fce3ec48b4c8 100644 --- a/op-supervisor/supervisor/service_test.go +++ b/op-supervisor/supervisor/service_test.go @@ -22,6 +22,9 @@ import ( ) func TestSupervisorService(t *testing.T) { + depSet, err := depset.NewStaticConfigDependencySet(make(map[types.ChainID]*depset.StaticConfigDependency)) + require.NoError(t, err) + cfg := &config.Config{ Version: "", LogConfig: oplog.CLIConfig{ @@ -47,10 +50,8 @@ func TestSupervisorService(t *testing.T) { ListenPort: 0, // pick a port automatically EnableAdmin: true, }, - DependencySetSource: &depset.StaticConfigDependencySet{ - Dependencies: make(map[types.ChainID]*depset.StaticConfigDependency), - }, - MockRun: true, + DependencySetSource: depSet, + MockRun: true, } logger := testlog.Logger(t, log.LevelError) supervisor, err := SupervisorFromConfig(context.Background(), cfg, logger) diff --git a/op-supervisor/supervisor/backend/db/entrydb/error.go b/op-supervisor/supervisor/types/error.go similarity index 54% rename from op-supervisor/supervisor/backend/db/entrydb/error.go rename to op-supervisor/supervisor/types/error.go index 42ae26dcf1125..fc493fb87f913 100644 --- a/op-supervisor/supervisor/backend/db/entrydb/error.go +++ b/op-supervisor/supervisor/types/error.go @@ -1,4 +1,4 @@ -package entrydb +package types import "errors" @@ -17,4 +17,14 @@ var ( ErrConflict = errors.New("conflicting data") // ErrStop can be used in iterators to indicate iteration has to stop ErrStop = errors.New("iter stop") + // ErrOutOfScope is when data is accessed, but access is not allowed, because of a limited scope. + // E.g. when limiting scope to L2 blocks derived from a specific subset of the L1 chain. + ErrOutOfScope = errors.New("out of scope") + // ErrPreviousToFirst is when you try to get the previous block of the first block + // E.g. when calling PreviousDerivedFrom on the first L1 block in the DB. + ErrPreviousToFirst = errors.New("cannot get parent of first block in the database") + // ErrUnknownChain is when a chain is unknown, not in the dependency set. + ErrUnknownChain = errors.New("unknown chain") + // ErrNoRPCSource happens when a sub-service needs an RPC data source, but is not configured with one. + ErrNoRPCSource = errors.New("no RPC client configured") ) diff --git a/op-supervisor/supervisor/types/types.go b/op-supervisor/supervisor/types/types.go index 05a9b16331264..8f2b32bb227ac 100644 --- a/op-supervisor/supervisor/types/types.go +++ b/op-supervisor/supervisor/types/types.go @@ -6,17 +6,41 @@ import ( "fmt" "math" "math/big" + "strconv" + + ethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/holiman/uint256" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum-optimism/optimism/op-service/eth" ) +// ChainIndex represents the lifetime of a chain in a dependency set. +type ChainIndex uint32 + +func (ci ChainIndex) String() string { + return strconv.FormatUint(uint64(ci), 10) +} + +func (ci ChainIndex) MarshalText() ([]byte, error) { + return []byte(ci.String()), nil +} + +func (ci *ChainIndex) UnmarshalText(data []byte) error { + v, err := strconv.ParseUint(string(data), 10, 32) + if err != nil { + return err + } + *ci = ChainIndex(v) + return nil +} + type ExecutingMessage struct { - Chain uint32 // same as ChainID for now, but will be indirect, i.e. translated to full ID, later + Chain ChainIndex // same as ChainID for now, but will be indirect, i.e. translated to full ID, later BlockNum uint64 LogIdx uint32 Timestamp uint64 @@ -24,7 +48,7 @@ type ExecutingMessage struct { } func (s *ExecutingMessage) String() string { - return fmt.Sprintf("ExecMsg(chain: %d, block: %d, log: %d, time: %d, logHash: %s)", + return fmt.Sprintf("ExecMsg(chainIndex: %s, block: %d, log: %d, time: %d, logHash: %s)", s.Chain, s.BlockNum, s.LogIdx, s.Timestamp, s.Hash) } @@ -36,7 +60,7 @@ type Message struct { type Identifier struct { Origin common.Address BlockNumber uint64 - LogIndex uint64 + LogIndex uint32 Timestamp uint64 ChainID ChainID // flat, not a pointer, to make Identifier safe as map key } @@ -66,7 +90,10 @@ func (id *Identifier) UnmarshalJSON(input []byte) error { } id.Origin = dec.Origin id.BlockNumber = uint64(dec.BlockNumber) - id.LogIndex = uint64(dec.LogIndex) + if dec.LogIndex > math.MaxUint32 { + return fmt.Errorf("log index too large: %d", dec.LogIndex) + } + id.LogIndex = uint32(dec.LogIndex) id.Timestamp = uint64(dec.Timestamp) id.ChainID = (ChainID)(dec.ChainID) return nil @@ -104,19 +131,27 @@ func (lvl *SafetyLevel) UnmarshalText(text []byte) error { } // AtLeastAsSafe returns true if the receiver is at least as safe as the other SafetyLevel. +// Safety levels are assumed to graduate from LocalUnsafe to LocalSafe to CrossUnsafe to CrossSafe, with Finalized as the strongest. func (lvl *SafetyLevel) AtLeastAsSafe(min SafetyLevel) bool { - switch min { - case Invalid: - return true - case CrossUnsafe: - return *lvl != Invalid - case CrossSafe: - return *lvl == CrossSafe || *lvl == Finalized - case Finalized: - return *lvl == Finalized - default: + relativeSafety := map[SafetyLevel]int{ + Invalid: 0, + LocalUnsafe: 1, + LocalSafe: 2, + CrossUnsafe: 3, + CrossSafe: 4, + Finalized: 5, + } + // if either level is not recognized, return false + _, ok := relativeSafety[*lvl] + if !ok { + return false + } + _, ok = relativeSafety[min] + if !ok { return false } + // compare the relative safety levels to determine if the receiver is at least as safe as the other + return relativeSafety[*lvl] >= relativeSafety[min] } const ( @@ -168,6 +203,10 @@ func (id ChainID) ToUInt32() (uint32, error) { return uint32(v64), nil } +func (id *ChainID) ToBig() *big.Int { + return (*uint256.Int)(id).ToBig() +} + func (id ChainID) MarshalText() ([]byte, error) { return []byte(id.String()), nil } @@ -208,3 +247,66 @@ func (s BlockSeal) String() string { func (s BlockSeal) ID() eth.BlockID { return eth.BlockID{Hash: s.Hash, Number: s.Number} } + +func (s BlockSeal) MustWithParent(parent eth.BlockID) eth.BlockRef { + ref, err := s.WithParent(parent) + if err != nil { + panic(err) + } + return ref +} + +func (s BlockSeal) WithParent(parent eth.BlockID) (eth.BlockRef, error) { + // prevent parent attachment if the parent is not the previous block, + // and the block is not the genesis block + if s.Number != parent.Number+1 && s.Number != 0 { + return eth.BlockRef{}, fmt.Errorf("invalid parent block %s to combine with %s", parent, s) + } + return eth.BlockRef{ + Hash: s.Hash, + Number: s.Number, + ParentHash: parent.Hash, + Time: s.Timestamp, + }, nil +} + +func (s BlockSeal) ForceWithParent(parent eth.BlockID) eth.BlockRef { + return eth.BlockRef{ + Hash: s.Hash, + Number: s.Number, + ParentHash: parent.Hash, + Time: s.Timestamp, + } +} + +func BlockSealFromRef(ref eth.BlockRef) BlockSeal { + return BlockSeal{ + Hash: ref.Hash, + Number: ref.Number, + Timestamp: ref.Time, + } +} + +// PayloadHashToLogHash converts the payload hash to the log hash +// it is the concatenation of the log's address and the hash of the log's payload, +// which is then hashed again. This is the hash that is stored in the log storage. +// The logHash can then be used to traverse from the executing message +// to the log the referenced initiating message. +func PayloadHashToLogHash(payloadHash common.Hash, addr common.Address) common.Hash { + msg := make([]byte, 0, 2*common.HashLength) + msg = append(msg, addr.Bytes()...) + msg = append(msg, payloadHash.Bytes()...) + return crypto.Keccak256Hash(msg) +} + +// LogToMessagePayload is the data that is hashed to get the payloadHash +// it is the concatenation of the log's topics and data +// the implementation is based on the interop messaging spec +func LogToMessagePayload(l *ethTypes.Log) []byte { + msg := make([]byte, 0) + for _, topic := range l.Topics { + msg = append(msg, topic.Bytes()...) + } + msg = append(msg, l.Data...) + return msg +} diff --git a/op-supervisor/supervisor/types/types_test.go b/op-supervisor/supervisor/types/types_test.go index 50c856bdc7945..7e3e0d4843a91 100644 --- a/op-supervisor/supervisor/types/types_test.go +++ b/op-supervisor/supervisor/types/types_test.go @@ -13,7 +13,7 @@ import ( ) func FuzzRoundtripIdentifierJSONMarshal(f *testing.F) { - f.Fuzz(func(t *testing.T, origin []byte, blockNumber uint64, logIndex uint64, timestamp uint64, chainID []byte) { + f.Fuzz(func(t *testing.T, origin []byte, blockNumber uint64, logIndex uint32, timestamp uint64, chainID []byte) { if len(chainID) > 32 { chainID = chainID[:32] } @@ -55,7 +55,19 @@ func TestChainID_String(t *testing.T) { for _, test := range tests { test := test t.Run(test.expected, func(t *testing.T) { - require.Equal(t, test.expected, test.input.String()) + t.Run("String", func(t *testing.T) { + require.Equal(t, test.expected, test.input.String()) + }) + t.Run("MarshalText", func(t *testing.T) { + data, err := test.input.MarshalText() + require.NoError(t, err) + require.Equal(t, test.expected, string(data)) + }) + t.Run("UnmarshalText", func(t *testing.T) { + var id ChainID + require.NoError(t, id.UnmarshalText([]byte(test.expected))) + require.Equal(t, test.input, id) + }) }) } } diff --git a/ops-bedrock/l2-op-geth-entrypoint.sh b/ops-bedrock/l2-op-geth-entrypoint.sh index f760a87f18750..eee8684e97b03 100644 --- a/ops-bedrock/l2-op-geth-entrypoint.sh +++ b/ops-bedrock/l2-op-geth-entrypoint.sh @@ -31,12 +31,12 @@ exec geth \ --http.vhosts="*" \ --http.addr=0.0.0.0 \ --http.port="$RPC_PORT" \ - --http.api=web3,debug,eth,txpool,net,engine \ + --http.api=web3,debug,eth,txpool,net,engine,miner \ --ws \ --ws.addr=0.0.0.0 \ --ws.port="$WS_PORT" \ --ws.origins="*" \ - --ws.api=debug,eth,txpool,net,engine \ + --ws.api=debug,eth,txpool,net,engine,miner \ --syncmode=full \ --nodiscover \ --maxpeers=0 \ diff --git a/ops-bedrock/l2-op-geth-interop.Dockerfile b/ops-bedrock/l2-op-geth-interop.Dockerfile new file mode 100644 index 0000000000000..41a667c0fc296 --- /dev/null +++ b/ops-bedrock/l2-op-geth-interop.Dockerfile @@ -0,0 +1,10 @@ +FROM us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:v1.101411.1-rc.3 +# Note: depend on dev-release for sequencer interop message checks + +RUN apk add --no-cache jq + +COPY l2-op-geth-entrypoint.sh /entrypoint.sh + +VOLUME ["/db"] + +ENTRYPOINT ["/bin/sh", "/entrypoint.sh"] diff --git a/ops/docker/op-stack-go/Dockerfile.dockerignore b/ops/docker/op-stack-go/Dockerfile.dockerignore index 1c0841df1f334..bd700e291e494 100644 --- a/ops/docker/op-stack-go/Dockerfile.dockerignore +++ b/ops/docker/op-stack-go/Dockerfile.dockerignore @@ -4,8 +4,8 @@ !/cannon !/op-batcher -!/op-bootnode !/op-chain-ops +!/op-deployer !/op-challenger !/packages/contracts-bedrock/snapshots !/op-dispute-mon diff --git a/packages/contracts-bedrock/scripts/checks/check-foundry-install.sh b/ops/scripts/check-foundry.sh similarity index 84% rename from packages/contracts-bedrock/scripts/checks/check-foundry-install.sh rename to ops/scripts/check-foundry.sh index a2093e936f3ff..530046bd85ea8 100755 --- a/packages/contracts-bedrock/scripts/checks/check-foundry-install.sh +++ b/ops/scripts/check-foundry.sh @@ -1,9 +1,6 @@ #!/usr/bin/env bash -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -CONTRACTS_BASE=$(dirname "$(dirname "$SCRIPT_DIR")") -MONOREPO_BASE=$(dirname "$(dirname "$CONTRACTS_BASE")") -VERSIONS_FILE="${MONOREPO_BASE}/versions.json" +VERSIONS_FILE="versions.json" if ! command -v jq &> /dev/null then diff --git a/ops/scripts/ci-docker-tag-op-stack-release.sh b/ops/scripts/ci-docker-tag-op-stack-release.sh index 45dd920949946..1de86b749d329 100755 --- a/ops/scripts/ci-docker-tag-op-stack-release.sh +++ b/ops/scripts/ci-docker-tag-op-stack-release.sh @@ -6,7 +6,7 @@ DOCKER_REPO=$1 GIT_TAG=$2 GIT_SHA=$3 -IMAGE_NAME=$(echo "$GIT_TAG" | grep -Eow '^(ci-builder(-rust)?|da-server|proofs-tools|cannon|ufm-[a-z0-9\-]*|op-[a-z0-9\-]*)' || true) +IMAGE_NAME=$(echo "$GIT_TAG" | grep -Eow '^(ci-builder(-rust)?|da-server|proofs-tools|holocene-deployer|cannon|ufm-[a-z0-9\-]*|op-[a-z0-9\-]*)' || true) if [ -z "$IMAGE_NAME" ]; then echo "image name could not be parsed from git tag '$GIT_TAG'" exit 1 diff --git a/packages/contracts-bedrock/.gitignore b/packages/contracts-bedrock/.gitignore index 6ca35454b2915..ae6569a94ebea 100644 --- a/packages/contracts-bedrock/.gitignore +++ b/packages/contracts-bedrock/.gitignore @@ -16,6 +16,7 @@ kontrol_prove_report.xml # Scripts scripts/go-ffi/go-ffi +scripts/go-ffi/go-ffi-cannon64 # Environment Variables .envrc diff --git a/packages/contracts-bedrock/CHANGELOG.md b/packages/contracts-bedrock/CHANGELOG.md deleted file mode 100644 index e4d02f372ade0..0000000000000 --- a/packages/contracts-bedrock/CHANGELOG.md +++ /dev/null @@ -1,491 +0,0 @@ -# @eth-optimism/contracts-bedrock - -## 0.17.3 - -### Patch Changes - -- [#10621](https://github.com/ethereum-optimism/optimism/pull/10621) [`eb454ac72b26211eb8037e7e777315c8f30d994d`](https://github.com/ethereum-optimism/optimism/commit/eb454ac72b26211eb8037e7e777315c8f30d994d) Thanks [@tarunkhasnavis](https://github.com/tarunkhasnavis)! - Add data field to faucet contract drip parameters - -## 0.17.2 - -### Patch Changes - -- [#9964](https://github.com/ethereum-optimism/optimism/pull/9964) [`8241220898128e1f61064f22dcb6fdd0a5f043c3`](https://github.com/ethereum-optimism/optimism/commit/8241220898128e1f61064f22dcb6fdd0a5f043c3) Thanks [@roninjin10](https://github.com/roninjin10)! - Removed only-allow command from package.json - -## 0.17.1 - -### Patch Changes - -- [#9415](https://github.com/ethereum-optimism/optimism/pull/9415) [`79effc52e8b82d15b5eda43acf540ac6c5f8d5d7`](https://github.com/ethereum-optimism/optimism/commit/79effc52e8b82d15b5eda43acf540ac6c5f8d5d7) Thanks [@nitaliano](https://github.com/nitaliano)! - Bumps version so fpac contracts exist for SDK to consume - -## 0.16.2 - -### Patch Changes - -- [#7450](https://github.com/ethereum-optimism/optimism/pull/7450) [`ac90e16a7`](https://github.com/ethereum-optimism/optimism/commit/ac90e16a7f85c4f73661ae6023135c3d00421c1e) Thanks [@roninjin10](https://github.com/roninjin10)! - Updated dev dependencies related to testing that is causing audit tooling to report failures - -## 0.16.1 - -### Patch Changes - -- [#7244](https://github.com/ethereum-optimism/optimism/pull/7244) [`2440f5e7a`](https://github.com/ethereum-optimism/optimism/commit/2440f5e7ab6577f2d2e9c8b0c78c014290dde8e7) Thanks [@nitaliano](https://github.com/nitaliano)! - bumps sdk version to have access to sepolia deployments - -## 0.16.0 - -### Minor Changes - -- [#6206](https://github.com/ethereum-optimism/optimism/pull/6206) [`72d184854`](https://github.com/ethereum-optimism/optimism/commit/72d184854ebad8b2025641f126ed76573b1f0ac3) Thanks [@tynes](https://github.com/tynes)! - Migrate contracts periphery into bedrock - -### Patch Changes - -- [#6164](https://github.com/ethereum-optimism/optimism/pull/6164) [`c11039060`](https://github.com/ethereum-optimism/optimism/commit/c11039060bc037a88916c2cba602687b6d69ad1a) Thanks [@pengin7384](https://github.com/pengin7384)! - fix typo - -- [#6198](https://github.com/ethereum-optimism/optimism/pull/6198) [`77da6edc6`](https://github.com/ethereum-optimism/optimism/commit/77da6edc643e0b5e39f7b6bb41c3c7ead418a876) Thanks [@tremarkley](https://github.com/tremarkley)! - Delete dead typescript https://github.com/ethereum-optimism/optimism/pull/6148. - -## 0.15.0 - -### Minor Changes - -- af292562f: Fix issue with deposits running out of gas - -### Patch Changes - -- Updated dependencies [8d7dcc70c] -- Updated dependencies [d6388be4a] - - @eth-optimism/core-utils@0.12.1 - -## 0.14.0 - -### Minor Changes - -- 197884eae: Bump XDM semver after #5444 -- 6eb05430d: Increase precision in `SafeCall.hasMinGas` -- 5063a69fb: Update sdk contract addresses for bedrock - -### Patch Changes - -- f1e867177: contracts-bedrock was exporting hardhat when it didn't need to be - -## 0.13.2 - -### Patch Changes - -- b16067a9f: Reduce the time that the system dictator deploy scripts wait before checking the chain state. -- 9a02079eb: Makes the Proxy contract inheritable by making functions (public virtual). -- 98fbe9d22: Added a contsructor to the System Dictator - -## 0.13.1 - -### Patch Changes - -- 22c3885f5: Optionally print cast commands during migration -- f52c07529: Print tenderly simulation links during deployment - -## 0.13.0 - -### Minor Changes - -- cb19e2f9c: Moves `FINALIZATION_PERIOD_SECONDS` from the `OptimismPortal` to the `L2OutputOracle` & ensures the `CHALLENGER` key cannot delete finalized outputs. - -## 0.12.1 - -### Patch Changes - -- 80f2271f5: Update foundry - -## 0.12.0 - -### Minor Changes - -- efc98d261: Change the `relayMessage` reentrancy guard in the XDMs to be per-message. - -### Patch Changes - -- 7c0a2cc37: add is IERC165 to IOptimismMintableERC20 -- 2865dd9b4: Minor comment updates and cleanup to the SystemConfig contract. -- 388f2c25a: Trigger a release including CrossDomainOwnable3 - -## 0.11.4 - -### Patch Changes - -- 3c22333b8: Loosens the requirements for re-proving a withdrawal transaction in the `OptimismPortal` - -## 0.11.3 - -### Patch Changes - -- 4964be480: Added a test for large deposit gaps - -## 0.11.2 - -### Patch Changes - -- 8784bc0bc: Add invariant test for the L1 XDM's `relayMessage` minimum gas limits. - -## 0.11.1 - -### Patch Changes - -- fe80a9488: Add echidna tests for portal -- 827fc7b04: Adds a go package to generate fuzz inputs for the Bedrock contract tests. -- a2166dcad: Add echidna tests for metering -- ff09ec22d: Add echidna tests for hashing -- 85dfa9fe2: Add echidna tests for encoding -- 0f8fc58ad: Add echidna tests for Burn -- 89f70c591: Add tests for the `Bytes` library -- 03940c3cb: Make lint check and fix scripts match - -## 0.11.0 - -### Minor Changes - -- 4d13f0afe: Refactors the MerkleTrie get function to throw explicitly instead of returning an existence boolean - -### Patch Changes - -- 43f33f39f: Add echidna test commands -- 237a351f1: Add tests to the SystemConfig contract -- 1d3c749a2: Bumps the version of ts-node used -- 1594678e0: Add echidna test for AliasHelper -- 1d3c749a2: Updates the version of TypeScript -- 136ea1785: Refactors the L2OutputOracle to key the l2Outputs mapping by index instead of by L2 block number. -- 7300a7ca7: Document test function naming convention and create a script for checking. -- Updated dependencies [c975c9620] -- Updated dependencies [136ea1785] - - @eth-optimism/core-utils@0.12.0 - -## 0.10.0 - -### Minor Changes - -- 59adcaa09: Deleted Unused Variables fundAccount , impersonatedTx -- 1bfe79f20: Adds an implementation of the Two Step Withdrawals V2 proposal - -### Patch Changes - -- c025a1153: Fixes a severe vulnerability found in ToB's November 2022 audit of the Bedrock contracts -- f8697a607: Removes historicalTotalBlocks from the L2OutputOracle -- c71500a7e: Updates L2OutputOracle to easily delete multiple outputs at once -- f49b71d50: Updated forge-std version -- ccaf5bc83: Allows owner and proposer addresses to be the same in L2OutputOracle - -## 0.9.1 - -### Patch Changes - -- 52079cc12: Has ProxyAdmin use Ownable instead of Owned -- 13bfafb21: Tweaks variable ordering in OptimismPortal -- eeae96941: Removes the unused DeployConfig contract -- 427831d86: Add comments to SystemConfig.sol - -## 0.9.0 - -### Minor Changes - -- 87702c741: Use SCREAMING_SNAKE_CASE for immutables - -### Patch Changes - -- c02831144: Introduces layout lock and more storage layout verification -- d58b0a397: Cleans up remaining lint warnings -- ff860ecf3: Introduces the MigrationSystemDictator for the Bedrock migration -- cc5adbc61: Updates function ordering in ProxyAdmin to match original contract -- 31c91ea74: Adds another assertion in the CrossDomainMessenger to explicitly identify an invariant which was previously implicit. -- Updated dependencies [1e76cdb86] - - @eth-optimism/core-utils@0.11.0 - -## 0.8.3 - -### Patch Changes - -- db84317b: Various RLP updates -- 9b90c732: Added codecov badge to readme - -## 0.8.2 - -### Patch Changes - -- 7d7d9ba8: Moves initializers underneath constructors always - -## 0.8.1 - -### Patch Changes - -- 35a7bb5e: Use uint64 for arithmetic in XDM's baseGas -- a5e715c3: Rename the event emitted in the L2ToL1MessagePasser -- d18b8aa3: Removes an unnecessary initializer parameter in the L200 - -## 0.8.0 - -### Minor Changes - -- 3d4e8529: No refunds! - -### Patch Changes - -- 6ed68fa3: Fixes a small bug in the constructor of the L2OutputOracle contract -- caf5dd3e: Updates README to include versioning rules. -- a6cbfee2: Fuzz L2ToL1MessagePasser -- 394a26ec: Modifies the StandardBridge to move a value check deeper down the call stack to be more defensive. - -## 0.7.0 - -### Minor Changes - -- e2faaa8b: Moves the L2ToL1MessagePasser to a new address and puts a LegacyMessagePasser at the old address. - -### Patch Changes - -- cb5fed67: Clarify intent with mintable token interfaces -- c427f0c0: Fixes to natspec docs -- d28ad592: Tweaks storage spacers to standardize names and use original types -- 76c8ee2d: Fix event names orderings for `OptimismMintableERC20Created` - -## 0.6.3 - -### Patch Changes - -- 88dde7c8: Uses assert rather than a require statements to check for conditions we believe are unreachable.This is more semantically explicit, and should enable us to more effectively use some advanced analysis methods in our testing. -- 7215f4ce: Bump ethers to 5.7.0 globally -- 249a8ed6: Fixed a backwards compatibility issue in which incorrect events were emitted during a failed deposit finalization on the L2 bridge. -- 7d7c4fdf: Makes spacers private and updates names to reflect slot, offset, and length. -- e164e22e: Makes finalizeWithdrawalTransaction not payable because it doesn't need to be and it was causing confusion throughout the codebase. -- 0bc1be45: Make the use of storage gaps consistent across contracts -- af3e56b1: Fix to Ensure the Oracle's owner and proposer accounts are unique -- 206f6033: Fix outdated references to 'withdrawal contract' -- 88dde7c8: Use assert statements for unreachable conditions. -- 8790156c: Simplifies the initialization function of the CrossDomainMessenger in Bedrock -- 515685f4: Update comments on GovernanceToken to match Seaport style. -- Updated dependencies [7215f4ce] -- Updated dependencies [206f6033] - - @eth-optimism/core-utils@0.10.1 - -## 0.6.2 - -### Patch Changes - -- 651a2883: Make spacer variables private in the Bridge and Messenger contracts so that they cannot be accessed in child contracts. - -## 0.6.1 - -### Patch Changes - -- 85232179: Add CrossDomainOwnable contracts -- 593f1cfb: Removes the blockedSystemMessages mapping in favor of a simpler approach to preventing messages from being sent to internal system addresses. -- f78eb056: Prevents v0 (legacy) messages from being relayed in the bedrock XDM. - -## 0.6.0 - -### Minor Changes - -- 7fdc490c: Removes initializer from StandardBridge in favor of immutables -- 3d228a0e: Updates the storage layout for the CrossDomainMessenger base contract to reduce diff with the existing system. - -### Patch Changes - -- 63ef1949: Delete hardhat genesis tasks -- Updated dependencies [dbfea116] - - @eth-optimism/core-utils@0.10.0 - -## 0.5.4 - -### Patch Changes - -- a095d544: Include latest devnet deployment artifacts -- cdf2163e: Bump oz packages to latest release -- 791f30bc: Migrate deploy config to json from ts -- 193befed: Fix nonce issue for parallel deployments -- 02420db0: Add missing predeploy to Predeploys.sol -- 94a8f287: Moves forge-std and ds-test to devDependencies to avoid breaking npm -- 7d03c5c0: Update the L2 genesis hardhat task to use the ProxyAdmin's deployed address as the admin of each predeploy -- fec22bfe: Fix legibility in the L2CrossDomainMessengerInitializer -- 9272253e: Make a library call internal -- c025f418: Add additional deployments of address manager and proxy admin -- 329d21b6: Use safecall that doesn't copy calldata -- 35eafed0: Deletes the L2 genesis creation hardhat task as its now replaced by go code -- 3cde9205: Update @foundry-rs/hardhat-forge to 0.1.17 - -## 0.5.3 - -### Patch Changes - -- 056cb982: Fix slither script -- a32e68ac: Update genesis-l2 task to set immutables in the bytecode -- c648d55c: Fix build for smaller package -- d544f804: Use the same initializable across codebase -- ccbfe545: Update @foundry-rs/hardhat-forge@0.1.16 -- c97ad241: Fix build on latest foundry -- 45541553: Emit an extra event when withdrawals are initiated to make chainops easier -- 3dd296e8: Fix portal deployment to have L2OutputOracle proxy address -- fe94b864: Add watch task -- 28649d64: Add harhdat forge contract verification support -- 898c7ac5: Update hardhat-forge dep, remove dead deps -- 51a1595b: bedrock-goerli-96f44f79 deployment -- 8ae39154: Update deposit transaction type -- af96563a: Fix typechain exports -- dac4a9f0: Updates the SDK to be compatible with Bedrock (via the "bedrock: true" constructor param). Updates the build pipeline for contracts-bedrock to export a properly formatted dist folder that matches our other packages. -- Updated dependencies [0df744f6] -- Updated dependencies [8ae39154] -- Updated dependencies [dac4a9f0] - - @eth-optimism/core-utils@0.9.3 - -## 0.5.2 - -### Patch Changes - -- 1a22e822: Standardizes revert strings globally -- 5e113137: Fixes a bug in the L2 Bedrock genesis script -- 177a9ea8: Cleans linting errors in MerkleTrie.sol -- 7d68f82f: Adds a new event SentMessageExtension1 to the CrossDomainMessenger contract. Includes additional data that's being attached to messages sent after the Bedrock upgrade. -- 90630336: Properly generates and exports ABI and artifact files that can be imported by client libraries -- 8bd7abde: Moves various legacy contracts into the legacy folder -- 7e6eb9b2: The output oracle's getL2Output function now reverts when no output is returned -- f243dacf: Bump to use solidity 0.8.15 -- 8d26459b: Remove subversion byte from deposit tx -- fa9823f3: Naming improvements for functions and variables in the L2OutputOracle -- 0bf3b9b4: Update forge-std -- e764cbb7: Shortens library names -- 3a0271f8: Introduces Types.sol -- 5de373ea: Semver contract updated to include a getter for the full version string -- Updated dependencies [0bf3b9b4] -- Updated dependencies [8d26459b] -- Updated dependencies [4477fe9f] - - @eth-optimism/core-utils@0.9.2 - -## 0.5.1 - -### Patch Changes - -- e4693481: Clean up BytesUtils -- b7b77d6c: Updates CrossDomainMessenger.baseGas to more accurately reflect gas costs -- 9d435aec: Cleans up natspec in MerkleTrie and SecureMerkleTrie contracts -- 87f745b5: Cleans up various compiler warnings -- 8a3074ab: Minor cleanups to initialization and semver for L1 contracts -- e1501bc0: Clears most contract linting warnings - -## 0.5.0 - -### Minor Changes - -- 42a4cc30: Remove Lib* and OVM* prefixes from all contracts - -### Patch Changes - -- 0cb3929e: Move encoding and hashing into Encoding and Hashing libraries -- 28bd76ae: Cleans up hashing and encoding library natspec and function names -- 4279647f: Port RLPWriter tests -- ce6cb121: Use external version of ExcessivelySafeCall -- 8986f165: Fix solc warnings in ProxyAdmin -- 69ee689f: Remove unnecessary DefaultValues library -- 2e89f634: Fixes a bug that caused L2 timestamps to be computed incorrectly -- 49d33b08: Standardizes comments, errors, and events for contracts in the /universal package -- 821907e2: Bump typechain to 8.1.0 -- 91b31168: Clean up comments and errors for legacy contracts -- 3c5726d4: Cleaned up enums, should be CapitalCase enums and UPPER_CASE values -- eb11a5bb: Add comments to RLP libraries -- 092b0901: Update to new L2 tx hash style for deposits -- 4ea33e13: Standardizes initialization logic for L1 contracts -- 297af083: Move contracts written by external parties into a vendor folder -- 71800503: Reduce the number of compiler warnings -- 611d93a1: Remove storage slot buffer in xdomain messengers -- 75089d0a: Cleans up initialization logic everywhere -- b9a90f32: Rename OptimismMintableTokenFactory to OptimismMintableERC20Factory -- 50e20ea1: Fix initialization logic -- 6f74ca9f: Clean up the PredeployAddresses library -- c031ec95: Tests for RLPReader -- 9c8b1f00: Bump forge-std to 62caef29b0f87a2c6aaaf634b2ca4c09b6867c92 -- 89d01f2e: Add semver to L2 contracts -- 7d9820b6: Resolve compiler warnings in Proxy.sol -- f9fee446: Move the `DepositTx` type to `core-utils`. This way it can be more easily used across projects -- 5050e0fb: Remove "not implemented" errors in virtual functions -- 78d7c2ec: Update typechain pipeline -- 89d01f2e: Update dev deps -- Updated dependencies [f9fee446] - - @eth-optimism/core-utils@0.9.1 - -## 0.4.1 - -### Patch Changes - -- 5c3b4bfa: Enable hardhat style buildinfo -- ef29d8a5: Make the Portal upgradeable -- 5bb6f2c7: Add `OptimismPortal.isOutputFinalized` -- 79f31007: correct l33t sp34k in toCodeAddrr -- 5a12c635: Add deployer docker image -- 8460865f: Optimize buildinfo support, only build through hardhat interface - -## 0.4.0 - -### Minor Changes - -- a828da9f: Add separate sequencer role to Oracle - -### Patch Changes - -- a828da9f: Separate the owner and sequencer roles in the OutputOracle -- 347fd37c: Fix bug in bedrock deploy scripts -- 700dcbb0: Add genesis script -- 931e517b: Fix order of args to L2OO constructor -- 93e2f750: Fix for incorrect constructor args in deploy config -- ddf515cb: Make the output oracle upgradeable. -- Updated dependencies [700dcbb0] - - @eth-optimism/core-utils@0.9.0 - -## 0.3.0 - -### Minor Changes - -- 35757456: Replaces L2 timestamps with block numbers as the key in mapping(uint => OutputProposal). - -### Patch Changes - -- f23bae0b: bedrock: ProxyAdmin rename OpenZeppelin proxy to ERC1967 -- fadb1a93: OZ Audit fixes with a Low or informational severity: - - - Hardcode constant values - - Require that msg.value == \_amount on ETH withdrawals - - use \_from in place of msg.sender when applicable in internal functions - -- f23bae0b: bedrock: Simplify ProxyAdmin static calls -- 650ca6d4: Fixes to medium severity OZ findings - - - Disallow reentrant withdrawals - - remove donateEth - - Correct ordering of \_from and \_to arguments on refunds of failed deposits - -- 9aa8049c: Have contracts-bedrock properly include contract sources in npm package - -## 0.2.0 - -### Minor Changes - -- 04884132: Corrects the ordering of token addresses when a finalizeBridgeERC20 call fails - -### Patch Changes - -- 0a5ca8bf: Deployment for bedrock contracts on goerli -- 2f3fae0e: Fix hh artifact schema -- a96cbe7c: Fix style for L2 contracts to match L1 contracts -- 29ff7462: Revert es target back to 2017 -- 14dd80f3: Add proxy contract -- Updated dependencies [29ff7462] - - @eth-optimism/core-utils@0.8.7 - -## 0.1.3 - -### Patch Changes - -- c258acd4: Update comments and style for L1 contracts - -## 0.1.2 - -### Patch Changes - -- 07a84aed: Move core-utils to deps instead of devdeps - -## 0.1.1 - -### Patch Changes - -- 1aca58c4: Initial release diff --git a/packages/contracts-bedrock/README.md b/packages/contracts-bedrock/README.md index f3c70baf0914d..a9f1dbeeaa5ff 100644 --- a/packages/contracts-bedrock/README.md +++ b/packages/contracts-bedrock/README.md @@ -66,22 +66,22 @@ See the [Optimism Developer Docs](https://docs.optimism.io/chain/addresses) for ### Contributing Guide Contributions to the OP Stack are always welcome. -Please refer to the [CONTRIBUTING.md](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/CONTRIBUTING.md) for more information about how to contribute to the OP Stack smart contracts. +Please refer to the [CONTRIBUTING.md](./meta/CONTRIBUTING.md) for more information about how to contribute to the OP Stack smart contracts. ### Style Guide -OP Stack smart contracts should be written according to the [STYLE_GUIDE.md](./STYLE_GUIDE.md) found within this repository. +OP Stack smart contracts should be written according to the [STYLE_GUIDE.md](./meta/STYLE_GUIDE.md) found within this repository. Maintaining a consistent code style makes code easier to review and maintain, ultimately making the development process safer. ### Contract Interfaces OP Stack smart contracts use contract interfaces in a relatively unique way. Please refer to -[INTERFACES.md](./INTERFACES.md) to read more about how the OP Stack uses contract interfaces. +[INTERFACES.md](./meta/INTERFACES.md) to read more about how the OP Stack uses contract interfaces. ### Solidity Versioning OP Stack smart contracts are designed to utilize a single, consistent Solidity version. Please -refer to [SOLIDITY_UPGRADES.md](./SOLIDITY_UPGRADES.md) to understand the process for updating to +refer to [SOLIDITY_UPGRADES.md](./meta/SOLIDITY_UPGRADES.md) to understand the process for updating to newer Solidity versions. ## Deployment diff --git a/packages/contracts-bedrock/deploy-config/sepolia-devnet-0.json b/packages/contracts-bedrock/deploy-config/sepolia-devnet-0.json index ff87fc4f8cbb4..4239d10c3d071 100644 --- a/packages/contracts-bedrock/deploy-config/sepolia-devnet-0.json +++ b/packages/contracts-bedrock/deploy-config/sepolia-devnet-0.json @@ -65,7 +65,7 @@ "eip1559Denominator": 250, "eip1559DenominatorCanyon": 250, "systemConfigStartBlock": 4071248, - "faultGameAbsolutePrestate": "0x0385c3f8ee78491001d92b90b07d0cf387b7b52ab9b83b4d87c994e92cf823ba", + "faultGameAbsolutePrestate": "0x03925193e3e89f87835bbdf3a813f60b2aa818a36bbe71cd5d8fd7e79f5e8afe", "faultGameMaxDepth": 73, "faultGameClockExtension": 3600, "faultGameMaxClockDuration": 14400, diff --git a/packages/contracts-bedrock/foundry.toml b/packages/contracts-bedrock/foundry.toml index b173f71abc33a..6bd441ca3cdb7 100644 --- a/packages/contracts-bedrock/foundry.toml +++ b/packages/contracts-bedrock/foundry.toml @@ -48,7 +48,6 @@ fs_permissions = [ { access='read', path='./deploy-config-periphery/' }, { access='read', path='./broadcast/' }, { access='read', path = './forge-artifacts/' }, - { access='write', path='./semver-lock.json' }, { access='read-write', path='./.testdata/' }, { access='read', path='./kout-deployment' }, { access='read', path='./test/fixtures' }, @@ -76,7 +75,9 @@ runs = 256 depth = 32 [profile.ciheavy] -fuzz = { runs = 10000 } +# fuzz = { runs = 20000 } +# temporary reduce fuzz runs to unblock CI +fuzz = { runs = 200 } [profile.ciheavy.invariant] runs = 128 diff --git a/packages/contracts-bedrock/justfile b/packages/contracts-bedrock/justfile index 897114cdc11a7..fe6f4c0834c9c 100644 --- a/packages/contracts-bedrock/justfile +++ b/packages/contracts-bedrock/justfile @@ -16,20 +16,34 @@ dep-status: ######################################################## # Checks that the correct version of Foundry is installed. -prebuild: - ./scripts/checks/check-foundry-install.sh +check-foundry: + cd ../../ && ./ops/scripts/check-foundry.sh + +# Checks that semgrep is installed. +check-semgrep: + cd ../../ && just check-semgrep + +# Checks that the correct versions of Foundry and semgrep are installed. +check-dependencies: + just check-foundry && just check-semgrep # Core forge build command forge-build: forge build # Builds the contracts. -build: prebuild lint-fix-no-fail forge-build interfaces-check-no-build +build: check-dependencies lint-fix-no-fail forge-build interfaces-check-no-build # Builds the go-ffi tool for contract tests. -build-go-ffi: +build-go-ffi-default: cd ./scripts/go-ffi && go build +# Builds the go-ffi tool for MIPS64 contract tests. +build-go-ffi-cannon64: + cd ./scripts/go-ffi && go build -tags=cannon64 -o ./go-ffi-cannon64 + +build-go-ffi: build-go-ffi-default build-go-ffi-cannon64 + # Cleans build artifacts and deployments. clean: rm -rf ./artifacts ./forge-artifacts ./cache ./scripts/go-ffi/go-ffi ./deployments/hardhat/* @@ -82,7 +96,7 @@ deploy: # Generates a gas snapshot without building. gas-snapshot-no-build: - forge snapshot --match-contract GasBenchMark + forge snapshot --match-contract GasBenchMark --snap snapshots/.gas-snapshot # Generates a gas snapshot. gas-snapshot: build-go-ffi gas-snapshot-no-build @@ -102,9 +116,9 @@ kontrol-summary-full: kontrol-summary kontrol-summary-fp snapshots-abi-storage: go run ./scripts/autogen/generate-snapshots . -# Updates the semver-lock.json file. +# Updates the snapshots/semver-lock.json file. semver-lock: - forge script scripts/autogen/SemverLock.s.sol + go run scripts/autogen/generate-semver-lock/main.go # Generates core snapshots without building contracts. Currently just an alias for # snapshots-abi-storage because we no longer run Kontrol snapshots here. Run @@ -121,7 +135,7 @@ snapshots: build snapshots-no-build # Checks that the gas snapshot is up to date without building. gas-snapshot-check-no-build: - forge snapshot --match-contract GasBenchMark --check + forge snapshot --match-contract GasBenchMark --snap snapshots/.gas-snapshot --check # Checks that the gas snapshot is up to date. gas-snapshot-check: build-go-ffi gas-snapshot-check-no-build @@ -155,21 +169,16 @@ semver-diff-check-no-build: # Checks that any contracts with a modified semver lock also have a modified semver version. semver-diff-check: build semver-diff-check-no-build -# Checks that semver natspec is equal to the actual semver version. -# Does not build contracts. -semver-natspec-check-no-build: - go run ./scripts/checks/semver-natspec - -# Checks that semver natspec is equal to the actual semver version. -semver-natspec-check: build semver-natspec-check-no-build - # Checks that the semgrep tests are valid. semgrep-test-validity-check: - forge fmt ../../semgrep/sol-rules.t.sol --check + forge fmt ../../.semgrep/tests/sol-rules.t.sol --check + +# Checks that forge test names are correctly formatted. Does not build contracts. +lint-forge-tests-check-no-build: + go run ./scripts/checks/test-names # Checks that forge test names are correctly formatted. -lint-forge-tests-check: - go run ./scripts/checks/names +lint-forge-tests-check: build lint-forge-tests-check-no-build # Checks that contracts are properly linted. lint-check: @@ -193,9 +202,19 @@ validate-spacers-no-build: # Checks that spacer variables are correctly inserted. validate-spacers: build validate-spacers-no-build +# Checks that the Kontrol summary dummy files have not been modified. +# If you have changed the summary files deliberately, update the hashes in the script. +# Use `openssl dgst -sha256` to generate the hash for a file. +check-kontrol-summaries-unchanged: + ./scripts/checks/check-kontrol-summaries-unchanged.sh + # Runs semgrep on the contracts. semgrep: - cd ../../ && semgrep scan --config=semgrep ./packages/contracts-bedrock + cd ../../ && semgrep scan --config .semgrep/rules/ ./packages/contracts-bedrock + +# Runs semgrep tests. +semgrep-test: + cd ../../ && semgrep scan --test --config .semgrep/rules/ .semgrep/tests/ # TODO: Also run lint-forge-tests-check but we need to fix the test names first. # Runs all checks. @@ -206,10 +225,10 @@ check: snapshots-check-no-build \ lint-check \ semver-diff-check-no-build \ - semver-natspec-check-no-build \ validate-deploy-configs \ validate-spacers-no-build \ - interfaces-check-no-build + interfaces-check-no-build \ + lint-forge-tests-check-no-build ######################################################## # DEV TOOLS # diff --git a/packages/contracts-bedrock/CONTRIBUTING.md b/packages/contracts-bedrock/meta/CONTRIBUTING.md similarity index 100% rename from packages/contracts-bedrock/CONTRIBUTING.md rename to packages/contracts-bedrock/meta/CONTRIBUTING.md diff --git a/packages/contracts-bedrock/INTERFACES.md b/packages/contracts-bedrock/meta/INTERFACES.md similarity index 100% rename from packages/contracts-bedrock/INTERFACES.md rename to packages/contracts-bedrock/meta/INTERFACES.md diff --git a/packages/contracts-bedrock/LICENSE b/packages/contracts-bedrock/meta/LICENSE similarity index 100% rename from packages/contracts-bedrock/LICENSE rename to packages/contracts-bedrock/meta/LICENSE diff --git a/packages/contracts-bedrock/meta/POLICY.md b/packages/contracts-bedrock/meta/POLICY.md new file mode 100644 index 0000000000000..e2759f4eff129 --- /dev/null +++ b/packages/contracts-bedrock/meta/POLICY.md @@ -0,0 +1,36 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Policy](#policy) + - [Contributing](#contributing) + - [Versioning Policy](#versioning-policy) + - [Upgrade Policy](#upgrade-policy) + - [Style Guide](#style-guide) + - [Revert Data](#revert-data) + + + +# Policy + +This document outlines upgrade policies regarding the OP Stack codebase. + +## Contributing + +For any policies on contributing, please see [CONTRIBUTING](./CONTRIBUTING.md) + +## Versioning Policy + +For our versioning policy, please see our policy on [VERSIONING](./VERSIONING.md) + +## Upgrade Policy + +For the solidity upgrade policy, please see our doc on [SOLIDITY UPGRADES](./SOLIDITY_UPGRADES.md) + +## Style Guide + +For an indepth review of the code style used in the OP Stack contracts, please see our [STYLE GUIDE](./STYLE_GUIDE.md) + +## Revert Data + +Revert data may be changed in the future, and is not a reliable interface for external consumers. Contracts should not depend on specific revert data returned by OP Stack contracts, which can be changed during any future OP Stack contract upgrades. Revert data includes both custom errors returned by contracts, as a well as revert strings. diff --git a/packages/contracts-bedrock/SOLIDITY_UPGRADES.md b/packages/contracts-bedrock/meta/SOLIDITY_UPGRADES.md similarity index 100% rename from packages/contracts-bedrock/SOLIDITY_UPGRADES.md rename to packages/contracts-bedrock/meta/SOLIDITY_UPGRADES.md diff --git a/packages/contracts-bedrock/STYLE_GUIDE.md b/packages/contracts-bedrock/meta/STYLE_GUIDE.md similarity index 98% rename from packages/contracts-bedrock/STYLE_GUIDE.md rename to packages/contracts-bedrock/meta/STYLE_GUIDE.md index 1d8b84818b9bf..00af13d5a5b49 100644 --- a/packages/contracts-bedrock/STYLE_GUIDE.md +++ b/packages/contracts-bedrock/meta/STYLE_GUIDE.md @@ -96,8 +96,8 @@ Spacers MUST be `private`. All contracts should be assumed to live behind proxies (except in certain special circumstances). This means that new contracts MUST be built under the assumption of upgradeability. -We use a minimal [`Proxy`](./src/universal/Proxy.sol) contract designed to be owned by a -corresponding [`ProxyAdmin`](./src/universal/ProxyAdmin.sol) which follow the interfaces +We use a minimal [`Proxy`](../src/universal/Proxy.sol) contract designed to be owned by a +corresponding [`ProxyAdmin`](../src/universal/ProxyAdmin.sol) which follow the interfaces of OpenZeppelin's `Proxy` and `ProxyAdmin` contracts, respectively. Unless explicitly discussed otherwise, you MUST include the following basic upgradeability diff --git a/packages/contracts-bedrock/VERSIONING.md b/packages/contracts-bedrock/meta/VERSIONING.md similarity index 91% rename from packages/contracts-bedrock/VERSIONING.md rename to packages/contracts-bedrock/meta/VERSIONING.md index fefc2211b3e58..cb2b6b6921248 100644 --- a/packages/contracts-bedrock/VERSIONING.md +++ b/packages/contracts-bedrock/meta/VERSIONING.md @@ -11,7 +11,6 @@ There are five parts to the versioning and release process: - [Release Process](#release-process): The process for deploying contracts, creating a governance proposal, and the required associated releases. - [Additional Release Candidates](#additional-release-candidates): How to handle additional release candidates after an initial `op-contracts/vX.Y.Z-rc.1` release. - [Merging Back to Develop After Governance Approval](#merging-back-to-develop-after-governance-approval): Explains how to choose the resulting contract versions when merging back into `develop`. -- [Changelog](#changelog): A CHANGELOG for contract releases is maintained. > [!NOTE] > The rules described in this document must be enforced manually. @@ -119,14 +118,3 @@ Now there are two scenarios for the PR that merges the release branch back into - In practice, this one unlikely to occur when using inheritance for feature development, as specified in [Smart Contract Feature Development](https://github.com/ethereum-optimism/design-docs/blob/main/smart-contract-feature-development.md) architecture. It's more likely that (1) is the case, and we merge the version change into the base contract. This flow also provides a dedicated branch for each release, making it easy to deploy a patch or bug fix, regardless of other changes that may have occurred on develop since the release. - -## Changelog - -Lastly, a CHANGELOG for contract releases must be maintained: - -- Each upcoming release will have a tracking issue that documents the new versions of each contract that will be included in the release, along with links to the PRs that made the changes. -- Every contracts PR must have an accompanying changelog entry in a tracking issue once it is merged. -- Tracking issue titles should be named based on the expected Upgrade number they will go to governance with, e.g. "op-contracts changelog: Upgrade 9". - - See [ethereum-optimism/optimism#10592](https://github.com/ethereum-optimism/optimism/issues/10592) for an example of what this tracking issue should look like. - - We do not include a version number in the issue because it may be hard to predict the final version number of a release until all PRs are merged. - - Using upgrade numbers also acts as a forcing function to ensure upgrade sequencing and the governance process is accounted for early in the development process. diff --git a/packages/contracts-bedrock/safe.json b/packages/contracts-bedrock/safe.json deleted file mode 100644 index 1168ce3d51500..0000000000000 --- a/packages/contracts-bedrock/safe.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "version": "1.0", - "chainId": "11155111", - "createdAt": 1718216278, - "meta": { - "name": "Transactions Batch", - "description": "", - "txBuilderVersion": "1.16.5", - "createdFromSafeAddress": "0x422c32c10b16c442426Eb7E93b07f7B521294565", - "createdFromOwnerAddress": "", - "checksum": "0xc2d69412777b9d9ba16c95d12f3aca13820b37a8db5f9d436f63058c48994cde" - }, - "transactions": [ - { - "to": "0xa0ff2a54adc3fb33c44a141e67d194cf249258cb", - "value": "0", - "data": "0x9bc94d010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000176f7065726174696f6e735f73657175656e6365725f7632000000000000000000", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0x2a6c106ae13b558bb9e2ec64bd2f1f7beff3a5e0", - "value": "0", - "data": "0xee8ca3b568c76a8fa53bf566fc0934edddf25deba2199a53772b6c3a05ce20f5b8d220f8", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0xa0ff2a54adc3fb33c44a141e67d194cf249258cb", - "value": "0", - "data": "0x9bc94d010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000166f7065726174696f6e735f70726f706f7365725f763200000000000000000000", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0x2a6c106ae13b558bb9e2ec64bd2f1f7beff3a5e0", - "value": "0", - "data": "0xee8ca3b5c790be67575b95a6b0c9f618fbdce9b72b6e7202233f0afe087bb641e3d1f0e8", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0xa0ff2a54adc3fb33c44a141e67d194cf249258cb", - "value": "0", - "data": "0x9bc94d010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000146f7065726174696f6e735f67656c61746f5f7632000000000000000000000000", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0x2a6c106ae13b558bb9e2ec64bd2f1f7beff3a5e0", - "value": "0", - "data": "0xee8ca3b5f666fe8af1ff0032744dcf71fbbeada5e47079f37425a8a0069350bbb508c3db", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0xa0ff2a54adc3fb33c44a141e67d194cf249258cb", - "value": "0", - "data": "0x9bc94d010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000186f7065726174696f6e735f6368616c6c656e6765725f76310000000000000000", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0x2a6c106ae13b558bb9e2ec64bd2f1f7beff3a5e0", - "value": "0", - "data": "0xee8ca3b53fa0ce0493ae4a3e182ec7ed727076c63bf2d7761a43e328e118b2afdf86afc3", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0xa0ff2a54adc3fb33c44a141e67d194cf249258cb", - "value": "0", - "data": "0xe551cdaa0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000176f7065726174696f6e735f73657175656e6365725f763400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e10000000000000000000000000af8c77cfeb57620c4d9dcc81df75a1f0da7064af00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000400000000000000000000000008f23bb38f531600e5d8fddaaec41f13fab46e98c00000000000000000000000000000000000000000000003635c9adc5dea00000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000008f23bb38f531600e5d8fddaaec41f13fab46e98c00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0x2a6c106ae13b558bb9e2ec64bd2f1f7beff3a5e0", - "value": "0", - "data": "0x3323b467000000000000000000000000a0ff2a54adc3fb33c44a141e67d194cf249258cb000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006467148cd2000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000176f7065726174696f6e735f73657175656e6365725f763400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000176f7065726174696f6e735f73657175656e6365725f763400000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057e40", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0xa0ff2a54adc3fb33c44a141e67d194cf249258cb", - "value": "0", - "data": "0x9bc94d010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000176f7065726174696f6e735f73657175656e6365725f7634000000000000000000", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0xa0ff2a54adc3fb33c44a141e67d194cf249258cb", - "value": "0", - "data": "0xe551cdaa0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000166f7065726174696f6e735f70726f706f7365725f76330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015180000000000000000000000000af8c77cfeb57620c4d9dcc81df75a1f0da7064af00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000004000000000000000000000000049277ee36a024120ee218127354c4a3591dc90a90000000000000000000000000000000000000000000000056bc75e2d631000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000049277ee36a024120ee218127354c4a3591dc90a90000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000001158e460913d00000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0x2a6c106ae13b558bb9e2ec64bd2f1f7beff3a5e0", - "value": "0", - "data": "0x3323b467000000000000000000000000a0ff2a54adc3fb33c44a141e67d194cf249258cb000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006467148cd2000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000166f7065726174696f6e735f70726f706f7365725f76330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000166f7065726174696f6e735f70726f706f7365725f76330000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083d600", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0xa0ff2a54adc3fb33c44a141e67d194cf249258cb", - "value": "0", - "data": "0x9bc94d010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000166f7065726174696f6e735f70726f706f7365725f763300000000000000000000", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0xa0ff2a54adc3fb33c44a141e67d194cf249258cb", - "value": "0", - "data": "0xe551cdaa0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000186f7065726174696f6e735f6368616c6c656e6765725f7632000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e10000000000000000000000000af8c77cfeb57620c4d9dcc81df75a1f0da7064af00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000ffb026f67da0869eb3abb090cb7f015ce0925cdf00000000000000000000000000000000000000000000003635c9adc5dea000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000049277ee36a024120ee218127354c4a3591dc90a900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000056bc75e2d63100000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0x2a6c106ae13b558bb9e2ec64bd2f1f7beff3a5e0", - "value": "0", - "data": "0x3323b467000000000000000000000000a0ff2a54adc3fb33c44a141e67d194cf249258cb000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006467148cd2000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000186f7065726174696f6e735f6368616c6c656e6765725f7632000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000186f7065726174696f6e735f6368616c6c656e6765725f7632000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057e40", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0xa0ff2a54adc3fb33c44a141e67d194cf249258cb", - "value": "0", - "data": "0x9bc94d010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000186f7065726174696f6e735f6368616c6c656e6765725f76320000000000000000", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0xa0ff2a54adc3fb33c44a141e67d194cf249258cb", - "value": "0", - "data": "0xe551cdaa0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000146f7065726174696f6e735f67656c61746f5f7633000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000ff11afac4146a0babf7f9f042a22c8053a5467400000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000600000000000000000000000007506c12a824d73d9b08564d5afc22c949434755e0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000cd438409d5cac9d2e076ac7bd0bf2377e99bb6e4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000007506c12a824d73d9b08564d5afc22c949434755e00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002100000000000000000000000000cd438409d5cac9d2e076ac7bd0bf2377e99bb6e400000000000000000000000000000000000000000000000000000000000000", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0x2a6c106ae13b558bb9e2ec64bd2f1f7beff3a5e0", - "value": "0", - "data": "0x3323b467000000000000000000000000a0ff2a54adc3fb33c44a141e67d194cf249258cb000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006467148cd2000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000146f7065726174696f6e735f67656c61746f5f763300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000146f7065726174696f6e735f67656c61746f5f763300000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083d600", - "contractMethod": null, - "contractInputsValues": null - }, - { - "to": "0xa0ff2a54adc3fb33c44a141e67d194cf249258cb", - "value": "0", - "data": "0x9bc94d010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000146f7065726174696f6e735f67656c61746f5f7633000000000000000000000000", - "contractMethod": null, - "contractInputsValues": null - } - ] -} \ No newline at end of file diff --git a/packages/contracts-bedrock/scripts/Artifacts.s.sol b/packages/contracts-bedrock/scripts/Artifacts.s.sol index 3ed021ea9dbbb..87a87f61fb909 100644 --- a/packages/contracts-bedrock/scripts/Artifacts.s.sol +++ b/packages/contracts-bedrock/scripts/Artifacts.s.sol @@ -67,11 +67,7 @@ abstract contract Artifacts { /// as well as the JSON files that contain addresses in the `superchain-registry` /// repo. The JSON key is the name of the contract and the value is an address. function _loadAddresses(string memory _path) internal { - string[] memory commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = string.concat("jq -cr < ", _path); - string memory json = string(Process.run(commands)); + string memory json = Process.bash(string.concat("jq -cr < ", _path)); string[] memory keys = vm.parseJsonKeys(json, ""); for (uint256 i; i < keys.length; i++) { string memory key = keys[i]; diff --git a/packages/contracts-bedrock/scripts/L2Genesis.s.sol b/packages/contracts-bedrock/scripts/L2Genesis.s.sol index 5beb8d71346c4..bf13cc1eb8e04 100644 --- a/packages/contracts-bedrock/scripts/L2Genesis.s.sol +++ b/packages/contracts-bedrock/scripts/L2Genesis.s.sol @@ -34,10 +34,6 @@ import { IL1Block } from "src/L2/interfaces/IL1Block.sol"; import { SoulGasToken } from "src/L2/SoulGasToken.sol"; -interface IInitializable { - function initialize(address _addr) external; -} - struct L1Dependencies { address payable l1CrossDomainMessengerProxy; address payable l1StandardBridgeProxy; @@ -687,11 +683,7 @@ contract L2Genesis is Deployer { /// @notice Sorts the allocs by address function sortJsonByKeys(string memory _path) internal { - string[] memory commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = string.concat("cat <<< $(jq -S '.' ", _path, ") > ", _path); - Process.run(commands); + Process.bash(string.concat("cat <<< $(jq -S '.' ", _path, ") > ", _path)); } /// @notice Funds the default dev accounts with ether diff --git a/packages/contracts-bedrock/scripts/autogen/SemverLock.s.sol b/packages/contracts-bedrock/scripts/autogen/SemverLock.s.sol deleted file mode 100644 index 1d5aeb963e3db..0000000000000 --- a/packages/contracts-bedrock/scripts/autogen/SemverLock.s.sol +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import { Script } from "forge-std/Script.sol"; -import { stdJson } from "forge-std/StdJson.sol"; -import { console2 as console } from "forge-std/console2.sol"; -import { Process } from "scripts/libraries/Process.sol"; - -contract SemverLock is Script { - function run() public { - // First, find all contracts with a Semver inheritance. - string[] memory commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = "grep -rl '@custom:semver' src | jq -Rs 'split(\"\\n\") | map(select(length > 0))'"; - string memory rawFiles = string(Process.run(commands)); - - string[] memory files = vm.parseJsonStringArray(rawFiles, ""); - writeSemverLock(files); - } - - /// @dev Writes a Semver lockfile - function writeSemverLock(string[] memory _files) internal { - string memory out; - for (uint256 i; i < _files.length; i++) { - // Use FFI to read the file to remove the need for FS permissions in the foundry.toml. - string[] memory commands = new string[](2); - commands[0] = "cat"; - commands[1] = _files[i]; - string memory fileContents = string(Process.run(commands)); - - // Grab the contract name - commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = string.concat("echo \"", _files[i], "\"| sed -E \'s|src/.*/(.+)\\.sol|\\1|\'"); - string memory contractName = string(Process.run(commands)); - - commands[2] = "forge config --json | jq -r .out"; - string memory artifactsDir = string(Process.run(commands)); - - // Handle the case where there are multiple artifacts for a contract. This happens - // when the same contract is compiled with multiple compiler versions. - string memory contractArtifactDir = string.concat(artifactsDir, "/", contractName, ".sol"); - commands[2] = string.concat( - "ls -1 --color=never ", contractArtifactDir, " | jq -R -s -c 'split(\"\n\") | map(select(length > 0))'" - ); - string memory artifactFiles = string(Process.run(commands)); - - string[] memory files = stdJson.readStringArray(artifactFiles, ""); - require(files.length > 0, string.concat("SemverLock: no artifacts found for ", contractName)); - string memory fileName = files[0]; - - // Parse the artifact to get the contract's initcode hash. - bytes memory initCode = vm.getCode(string.concat(artifactsDir, "/", contractName, ".sol/", fileName)); - - // Serialize the initcode hash + sourcecode hash in JSON. - vm.serializeBytes32(_files[i], "initCodeHash", keccak256(initCode)); - string memory obj = vm.serializeBytes32(_files[i], "sourceCodeHash", keccak256(bytes(fileContents))); - - // Serialize the map from the file name -> initcode hash + sourcecode hash in JSON. - out = vm.serializeString("", _files[i], obj); - } - - // Write the semver lockfile. - vm.writeJson(out, "semver-lock.json"); - console.logString("Wrote semver lock file to \"semver-lock.json\"."); - } -} diff --git a/packages/contracts-bedrock/scripts/autogen/generate-semver-lock/main.go b/packages/contracts-bedrock/scripts/autogen/generate-semver-lock/main.go new file mode 100644 index 0000000000000..162f81c840dd2 --- /dev/null +++ b/packages/contracts-bedrock/scripts/autogen/generate-semver-lock/main.go @@ -0,0 +1,128 @@ +package main + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" + + "github.com/ethereum/go-ethereum/crypto" +) + +const semverLockFile = "snapshots/semver-lock.json" + +func main() { + if err := run(); err != nil { + panic(err) + } +} + +func run() error { + // Find semver files + // Execute grep command to find files with @custom:semver + var cmd = exec.Command("bash", "-c", "grep -rl '@custom:semver' src | jq -Rs 'split(\"\n\") | map(select(length > 0))'") + cmdOutput, err := cmd.Output() + if err != nil { + return err + } + + // Parse the JSON array of files + var files []string + if err := json.Unmarshal(cmdOutput, &files); err != nil { + return fmt.Errorf("failed to parse JSON output: %w", err) + } + + // Hash and write to JSON file + // Map to store our JSON output + output := make(map[string]map[string]string) + + // regex to extract contract name from file path + re := regexp.MustCompile(`src/.*/(.+)\.sol`) + + // Get artifacts directory + cmd = exec.Command("forge", "config", "--json") + out, err := cmd.Output() + if err != nil { + return fmt.Errorf("failed to get forge config: %w", err) + } + var config struct { + Out string `json:"out"` + } + if err := json.Unmarshal(out, &config); err != nil { + return fmt.Errorf("failed to parse forge config: %w", err) + } + + for _, file := range files { + // Read file contents + fileContents, err := os.ReadFile(file) + if err != nil { + return fmt.Errorf("failed to read file %s: %w", file, err) + } + + // Extract contract name from file path using regex + matches := re.FindStringSubmatch(file) + if len(matches) < 2 { + return fmt.Errorf("invalid file path format: %s", file) + } + contractName := matches[1] + + // Get artifact files + artifactDir := filepath.Join(config.Out, contractName+".sol") + files, err := os.ReadDir(artifactDir) + if err != nil { + return fmt.Errorf("failed to read artifact directory: %w", err) + } + if len(files) == 0 { + return fmt.Errorf("no artifacts found for %s", contractName) + } + + // Read initcode from artifact + artifactPath := filepath.Join(artifactDir, files[0].Name()) + artifact, err := os.ReadFile(artifactPath) + if err != nil { + return fmt.Errorf("failed to read initcode: %w", err) + } + artifactJson := json.RawMessage(artifact) + var artifactObj struct { + Bytecode struct { + Object string `json:"object"` + } `json:"bytecode"` + } + if err := json.Unmarshal(artifactJson, &artifactObj); err != nil { + return fmt.Errorf("failed to parse artifact: %w", err) + } + + // convert the hex bytecode to a uint8 array / bytes + initCodeBytes, err := hex.DecodeString(strings.TrimPrefix(artifactObj.Bytecode.Object, "0x")) + if err != nil { + return fmt.Errorf("failed to decode hex: %w", err) + } + + // Calculate hashes using Keccak256 + var sourceCode = []byte(strings.TrimSuffix(string(fileContents), "\n")) + initCodeHash := fmt.Sprintf("0x%x", crypto.Keccak256Hash(initCodeBytes)) + sourceCodeHash := fmt.Sprintf("0x%x", crypto.Keccak256Hash(sourceCode)) + + // Store in output map + output[file] = map[string]string{ + "initCodeHash": initCodeHash, + "sourceCodeHash": sourceCodeHash, + } + } + + // Write to JSON file + jsonData, err := json.MarshalIndent(output, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal JSON: %w", err) + } + if err := os.WriteFile(semverLockFile, jsonData, 0644); err != nil { + return fmt.Errorf("failed to write semver lock file: %w", err) + } + + fmt.Printf("Wrote semver lock file to \"%s\".\n", semverLockFile) + return nil +} diff --git a/packages/contracts-bedrock/scripts/checks/check-file-unchanged.sh b/packages/contracts-bedrock/scripts/checks/check-file-unchanged.sh new file mode 100755 index 0000000000000..0949503efe32c --- /dev/null +++ b/packages/contracts-bedrock/scripts/checks/check-file-unchanged.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Check if both arguments are provided +if [ $# -ne 2 ]; then + echo "Usage: $0 " + exit 1 +fi + +file_path="$1" +expected_hash="$2" + +# Check if the file exists +if [ ! -f "$file_path" ]; then + echo "Error: File '$file_path' does not exist." + exit 1 +fi + +# Calculate the actual hash of the file +actual_hash=$(openssl dgst -sha256 -r "$file_path" | awk '{print $1}') + +# Compare the hashes +if [ "$actual_hash" = "$expected_hash" ]; then + exit 0 +else + echo "File '$file_path' has changed when it shouldn't have" + echo "Expected hash: $expected_hash" + echo "Actual hash: $actual_hash" + exit 1 +fi diff --git a/packages/contracts-bedrock/scripts/checks/check-interfaces.sh b/packages/contracts-bedrock/scripts/checks/check-interfaces.sh deleted file mode 100755 index a2cda470d2a83..0000000000000 --- a/packages/contracts-bedrock/scripts/checks/check-interfaces.sh +++ /dev/null @@ -1,286 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Warn users of Mac OSX who have not ever upgraded bash from the default that they may experience -# performance issues. -if [ "${BASH_VERSINFO[0]}" -lt 5 ]; then - echo "WARNING: your bash installation is very old, and may cause this script to run extremely slowly. Please upgrade bash to at least version 5 if you have performance issues." -fi - -# This script checks for ABI consistency between interfaces and their corresponding contracts. -# It compares the ABIs of interfaces (files starting with 'I') with their implementation contracts, -# excluding certain predefined files. Constructors are expected to be represented in interfaces by a -# pseudo-constructor function `__constructor__(...)` with arguments the same as the contract's constructor. -# The script reports any differences found and exits with an error if inconsistencies are detected. -# NOTE: Script is fast enough but could be parallelized if necessary. - -# Parse flags -no_diff=false -if [[ "${1:-}" == "--no-diff" ]]; then - no_diff=true -fi - -# Grab the directory of the contracts-bedrock package -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -CONTRACTS_BASE=$(dirname "$(dirname "$SCRIPT_DIR")") - -# Define contracts that should be excluded from the check -EXCLUDE_CONTRACTS=( - # External dependencies - "IERC20" - "IERC721" - "IERC721Enumerable" - "IERC721Upgradeable" - "IERC721Metadata" - "IERC165" - "IERC165Upgradeable" - "ERC721TokenReceiver" - "ERC1155TokenReceiver" - "ERC777TokensRecipient" - "Guard" - "IProxy" - "Vm" - "VmSafe" - "IMulticall3" - "IERC721TokenReceiver" - "IProxyCreationCallback" - "IBeacon" - - # EAS - "IEAS" - "ISchemaResolver" - "ISchemaRegistry" - - # TODO: Interfaces that need to be fixed are below this line - # ---------------------------------------------------------- - - # Inlined interface, needs to be replaced. - "IInitializable" - - # Missing various functions. - "IPreimageOracle" - "ILegacyMintableERC20" - "IOptimismMintableERC20" - "IOptimismMintableERC721" - - # Doesn't start with "I" - "KontrolCheatsBase" - - # Currently inherit from interface, needs to be fixed. - "IWETH" - "IDelayedWETH" - "ISuperchainWETH" - "IL2ToL2CrossDomainMessenger" - "ICrossL2Inbox" - "ISystemConfigInterop" - - # Enums need to be normalized - "ISequencerFeeVault" - "IBaseFeeVault" - "IL1FeeVault" - "IFeeVault" - - # Solidity complains about receive but contract doens't have it. - "IResolvedDelegateProxy" -) - -# Find all JSON files in the forge-artifacts folder -JSON_FILES=$(find "$CONTRACTS_BASE/forge-artifacts" -type f -name "*.json") - -# Initialize a flag to track if any issues are detected -issues_detected=false - -# Create a temporary file to store files that have already been reported -REPORTED_INTERFACES_FILE=$(mktemp) - -# Clean up the temporary file on exit -cleanup() { - rm -f "$REPORTED_INTERFACES_FILE" -} - -# Trap exit and error signals and call cleanup function -trap cleanup EXIT ERR - -# Check if a contract is excluded -is_excluded() { - for exclude in "${EXCLUDE_CONTRACTS[@]}"; do - if [[ "$exclude" == "$1" ]]; then - return 0 - fi - done - return 1 -} - -# Iterate over all JSON files -for interface_file in $JSON_FILES; do - # Grab the contract name from the file name - contract_name=$(basename "$interface_file" .json | cut -d '.' -f 1) - - # Extract all contract definitions in a single pass - contract_definitions=$(jq -r '.ast.nodes[] | select(.nodeType == "ContractDefinition") | "\(.contractKind),\(.name)"' "$interface_file") - - # Continue if no contract definitions are found - # Can happen in Solidity files that don't declare any contracts/interfaces - if [ -z "$contract_definitions" ]; then - continue - fi - - # Iterate over the found contract definitions and figure out which one - # matches the file name. We do this so that we can figure out if this is an - # interface or a contract based on the contract kind. - found=false - contract_temp="" - contract_kind="" - for definition in $contract_definitions; do - IFS=',' read -r contract_kind contract_temp <<< "$definition" - if [[ "$contract_name" == "$contract_temp" ]]; then - found=true - break - fi - done - - # Continue if no matching contract name is found. Can happen in Solidity - # files where no contracts/interfaces are defined with the same name as the - # file. Still OK because a separate artifact *will* be generated for the - # specific contract/interface. - if [ "$found" = false ]; then - continue - fi - - # If contract kind is not "interface", skip the file - if [ "$contract_kind" != "interface" ]; then - continue - fi - - # If contract name does not start with an "I", throw an error - if [[ "$contract_name" != I* ]]; then - if ! grep -q "^$contract_name$" "$REPORTED_INTERFACES_FILE"; then - echo "$contract_name" >> "$REPORTED_INTERFACES_FILE" - if ! is_excluded "$contract_name"; then - echo "Issue found in ABI for interface $contract_name from file $interface_file." - echo "Interface $contract_name does not start with 'I'." - issues_detected=true - fi - fi - continue - fi - - # Extract contract semver - contract_semver=$(jq -r '.ast.nodes[] | select(.nodeType == "PragmaDirective") | .literals | join("")' "$interface_file") - - # If semver is not exactly "solidity^0.8.0", throw an error - if [ "$contract_semver" != "solidity^0.8.0" ]; then - if ! grep -q "^$contract_name$" "$REPORTED_INTERFACES_FILE"; then - echo "$contract_name" >> "$REPORTED_INTERFACES_FILE" - if ! is_excluded "$contract_name"; then - echo "Issue found in ABI for interface $contract_name from file $interface_file." - echo "Interface $contract_name does not have correct compiler version (MUST be exactly solidity ^0.8.0)." - issues_detected=true - fi - fi - continue - fi - - # Construct the corresponding contract name by removing the leading "I" - contract_basename=${contract_name:1} - corresponding_contract_file="$CONTRACTS_BASE/forge-artifacts/$contract_basename.sol/$contract_basename.json" - - # Skip the file if the corresponding contract file does not exist - if [ ! -f "$corresponding_contract_file" ]; then - continue - fi - - # Extract and compare ABIs excluding constructors - interface_abi=$(jq '[.abi[]]' < "$interface_file") - contract_abi=$(jq '[.abi[]]' < "$corresponding_contract_file") - - # Function to normalize ABI by replacing interface name with contract name. - # Base contracts aren't allowed to inherit from their interfaces in order - # to guarantee a 1:1 match between interfaces and contracts. This means - # that the interface will redefine types in the base contract. We normalize - # the ABI as if the interface and contract are the same name. - normalize_abi() { - # Here we just remove the leading "I" from any contract, enum, or - # struct type. It's not beautiful but it's good enough for now. It - # would miss certain edge cases like if an interface really is using - # the contract type instead of the interface type but that's unlikely - # to happen in practice and should be an easy fix if it does. - local abi="$1" - - # Remove the leading "I" from types. - abi="${abi//\"internalType\": \"contract I/\"internalType\": \"contract }" - abi="${abi//\"internalType\": \"enum I/\"internalType\": \"enum }" - abi="${abi//\"internalType\": \"struct I/\"internalType\": \"struct }" - - # Handle translating pseudo-constructors. - abi=$(echo "$abi" | jq 'map(if .type == "function" and .name == "__constructor__" then .type = "constructor" | del(.name) | del(.outputs) else . end)') - - echo "$abi" - } - - # Normalize the ABIs - normalized_interface_abi=$(normalize_abi "$interface_abi") - normalized_contract_abi=$(normalize_abi "$contract_abi") - - # Check if the contract ABI has no constructor but the interface is missing __constructor__ - contract_has_constructor=$(echo "$normalized_contract_abi" | jq 'any(.[]; .type == "constructor")') - interface_has_default_pseudo_constructor=$(echo "$normalized_interface_abi" | jq 'any(.[]; .type == "constructor" and .inputs == [])') - - # If any contract has no constructor and its corresponding interface also does not have one, flag it as a detected issue - if [ "$contract_has_constructor" = false ] && [ "$interface_has_default_pseudo_constructor" = false ]; then - if ! grep -q "^$contract_name$" "$REPORTED_INTERFACES_FILE"; then - echo "$contract_name" >> "$REPORTED_INTERFACES_FILE" - if ! is_excluded "$contract_name"; then - echo "Issue found in ABI for interface $contract_name from file $interface_file." - echo "Interface $contract_name must have a function named '__constructor__' as the corresponding contract has no constructor in its ABI." - issues_detected=true - fi - fi - continue - fi - - # removes the pseudo constructor json entry from the interface files where the corresponding contract file has no constructor - # this is to ensure it is not flagged as a diff in the next step below - if [ "$contract_has_constructor" = false ] && [ "$interface_has_default_pseudo_constructor" ]; then - normalized_interface_abi=$(echo "$normalized_interface_abi" | jq 'map(select(.type != "constructor"))') - fi - - # Use jq to compare the ABIs - if ! diff_result=$(diff -u <(echo "$normalized_interface_abi" | jq 'sort') <(echo "$normalized_contract_abi" | jq 'sort')); then - if ! grep -q "^$contract_name$" "$REPORTED_INTERFACES_FILE"; then - echo "$contract_name" >> "$REPORTED_INTERFACES_FILE" - if ! is_excluded "$contract_name"; then - echo "Issue found in ABI for interface $contract_name from file $interface_file." - echo "Differences found in ABI between interface $contract_name and actual contract $contract_basename." - if [ "$no_diff" = false ]; then - echo "$diff_result" - fi - issues_detected=true - fi - fi - continue - fi -done - -# Check for unnecessary exclusions -for exclude_item in "${EXCLUDE_CONTRACTS[@]}"; do - if ! grep -q "^$exclude_item$" "$REPORTED_INTERFACES_FILE"; then - echo "Warning: $exclude_item is in the exclude list but WAS NOT reported as an issue. It" - echo "may be unnecessary in the EXCLUDE_CONTRACTS list, but you MUST verify this before" - echo "removing it by performing a clean and full build before re-running this script." - fi -done - -# Fail the script if any issues were detected -if [ "$issues_detected" = true ]; then - echo "Issues were detected while validating interface files." - echo "If the interface is an external dependency or should otherwise be excluded from this" - echo "check, add the interface name to the EXCLUDE_CONTRACTS list in the script. This will prevent" - echo "the script from comparing it against a corresponding contract." - echo "IMPORTANT: Interface files are NOT yet generated automatically. You must fix any" - echo "listed discrepancies manually by updating the specified interface file. Automated" - echo "interface generation is dependent on a few Forge bug fixes." - exit 1 -else - exit 0 -fi diff --git a/packages/contracts-bedrock/scripts/checks/check-kontrol-summaries-unchanged.sh b/packages/contracts-bedrock/scripts/checks/check-kontrol-summaries-unchanged.sh new file mode 100755 index 0000000000000..32c764c188a8e --- /dev/null +++ b/packages/contracts-bedrock/scripts/checks/check-kontrol-summaries-unchanged.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Runs the file unchanged script for each of the Kontrol summary files. +# Update these hashes if you have changed the summary files deliberately. +# Use `openssl dgst -sha256` to generate the hash for a file. +./scripts/checks/check-file-unchanged.sh ./test/kontrol/proofs/utils/DeploymentSummary.sol 73e1ed1f3c8bd9e46bb348b774443458206b2399e4eac303e2a92ac987eeefc6 +./scripts/checks/check-file-unchanged.sh ./test/kontrol/proofs/utils/DeploymentSummaryCode.sol ffe7298024464a6a282ceb549db401cce4b36fe3342113250a6c674a3b4203ba +./scripts/checks/check-file-unchanged.sh ./test/kontrol/proofs/utils/DeploymentSummaryFaultProofs.sol 5ec8b19a00b47f15a2a8c8d632ab83933e19b0c2bbb04c905a2cda926e56038f +./scripts/checks/check-file-unchanged.sh ./test/kontrol/proofs/utils/DeploymentSummaryFaultProofsCode.sol 1215a561a2bffb5af62b532a2608c4048a22368e505f7ae1d237c16b4ef6a45e diff --git a/packages/contracts-bedrock/scripts/checks/check-semver-diff.sh b/packages/contracts-bedrock/scripts/checks/check-semver-diff.sh index 81e7c6476d3a1..70304f6416908 100755 --- a/packages/contracts-bedrock/scripts/checks/check-semver-diff.sh +++ b/packages/contracts-bedrock/scripts/checks/check-semver-diff.sh @@ -9,7 +9,7 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source "$SCRIPT_DIR/utils/semver-utils.sh" # Path to semver-lock.json. -SEMVER_LOCK="semver-lock.json" +SEMVER_LOCK="snapshots/semver-lock.json" # Create a temporary directory. temp_dir=$(mktemp -d) @@ -22,7 +22,10 @@ if ! { git diff origin/develop...HEAD --name-only; git diff --name-only; git dif fi # Get the upstream semver-lock.json. -git show origin/develop:packages/contracts-bedrock/semver-lock.json > "$temp_dir/upstream_semver_lock.json" +if ! git show origin/develop:packages/contracts-bedrock/snapshots/semver-lock.json > "$temp_dir/upstream_semver_lock.json" 2>/dev/null; then + echo "❌ Error: Could not find semver-lock.json in the snapshots/ directory of develop branch" + exit 1 +fi # Copy the local semver-lock.json. cp "$SEMVER_LOCK" "$temp_dir/local_semver_lock.json" diff --git a/packages/contracts-bedrock/scripts/checks/check-snapshots.sh b/packages/contracts-bedrock/scripts/checks/check-snapshots.sh index 66a04dc331d41..18557eba52a52 100755 --- a/packages/contracts-bedrock/scripts/checks/check-snapshots.sh +++ b/packages/contracts-bedrock/scripts/checks/check-snapshots.sh @@ -3,7 +3,7 @@ set -euo pipefail # Check for the --no-build flag # Generate snapshots -if [ "$1" == "--no-build" ]; then +if [ "${1:-}" == "--no-build" ]; then just snapshots-no-build else just snapshots diff --git a/packages/contracts-bedrock/scripts/checks/interfaces/main.go b/packages/contracts-bedrock/scripts/checks/interfaces/main.go index 6a141f7ccde5d..fbaeaac8c13b1 100644 --- a/packages/contracts-bedrock/scripts/checks/interfaces/main.go +++ b/packages/contracts-bedrock/scripts/checks/interfaces/main.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "log" "os" "path/filepath" "runtime" @@ -26,9 +27,9 @@ var excludeContracts = []string{ "IEAS", "ISchemaResolver", "ISchemaRegistry", // TODO: Interfaces that need to be fixed - "IInitializable", "ILegacyMintableERC20", "IOptimismMintableERC20", - "IOptimismMintableERC721", "KontrolCheatsBase", "IWETH", "IDelayedWETH", "ISuperchainWETH", - "IL2ToL2CrossDomainMessenger", "ICrossL2Inbox", "ISystemConfigInterop", "IResolvedDelegateProxy", + + "IInitializable", "IOptimismMintableERC20", "ILegacyMintableERC20", + "KontrolCheatsBase", "ISystemConfigInterop", "IResolvedDelegateProxy", "IERC20Upgradeable", } @@ -303,6 +304,7 @@ func compareABIs(abi1, abi2 json.RawMessage) (bool, error) { // Compare using go-cmp diff := cmp.Diff(data1, data2) if diff != "" { + log.Printf("ABI diff: %s", diff) return false, nil } return true, nil diff --git a/packages/contracts-bedrock/scripts/checks/semver-natspec/main.go b/packages/contracts-bedrock/scripts/checks/semver-natspec/main.go deleted file mode 100644 index 1be082dda7635..0000000000000 --- a/packages/contracts-bedrock/scripts/checks/semver-natspec/main.go +++ /dev/null @@ -1,220 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "encoding/json" - "fmt" - "io" - "os" - "path/filepath" - "regexp" - "runtime" - "strings" - "sync" - "sync/atomic" -) - -type ArtifactsWrapper struct { - RawMetadata string `json:"rawMetadata"` -} - -type Artifacts struct { - Output struct { - Devdoc struct { - StateVariables struct { - Version struct { - Semver string `json:"custom:semver"` - } `json:"version"` - } `json:"stateVariables,omitempty"` - Methods struct { - Version struct { - Semver string `json:"custom:semver"` - } `json:"version()"` - } `json:"methods,omitempty"` - } `json:"devdoc"` - } `json:"output"` -} - -var ConstantVersionPattern = regexp.MustCompile(`string.*constant.*version\s+=\s+"([^"]+)";`) - -var FunctionVersionPattern = regexp.MustCompile(`^\s+return\s+"((?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)";$`) - -var InteropVersionPattern = regexp.MustCompile(`^\s+return\s+string\.concat\(super\.version\(\), "((.*)\+interop(.*)?)"\);`) - -func main() { - if err := run(); err != nil { - writeStderr("an error occurred: %v", err) - os.Exit(1) - } -} - -func writeStderr(msg string, args ...any) { - _, _ = fmt.Fprintf(os.Stderr, msg+"\n", args...) -} - -func run() error { - cwd, err := os.Getwd() - if err != nil { - return fmt.Errorf("failed to get current working directory: %w", err) - } - - writeStderr("working directory: %s", cwd) - - artifactsDir := filepath.Join(cwd, "forge-artifacts") - srcDir := filepath.Join(cwd, "src") - - artifactFiles, err := glob(artifactsDir, ".json") - if err != nil { - return fmt.Errorf("failed to get artifact files: %w", err) - } - contractFiles, err := glob(srcDir, ".sol") - if err != nil { - return fmt.Errorf("failed to get contract files: %w", err) - } - - var hasErr int32 - var outMtx sync.Mutex - fail := func(msg string, args ...any) { - outMtx.Lock() - writeStderr("❌ "+msg, args...) - outMtx.Unlock() - atomic.StoreInt32(&hasErr, 1) - } - - sem := make(chan struct{}, runtime.NumCPU()) - for contractName, artifactPath := range artifactFiles { - contractName := contractName - artifactPath := artifactPath - - sem <- struct{}{} - - go func() { - defer func() { - <-sem - }() - - af, err := os.Open(artifactPath) - if err != nil { - fail("%s: failed to open contract artifact: %v", contractName, err) - return - } - defer af.Close() - - var wrapper ArtifactsWrapper - if err := json.NewDecoder(af).Decode(&wrapper); err != nil { - fail("%s: failed to parse artifact file: %v", contractName, err) - return - } - - if wrapper.RawMetadata == "" { - return - } - - var artifactData Artifacts - if err := json.Unmarshal([]byte(wrapper.RawMetadata), &artifactData); err != nil { - fail("%s: failed to unwrap artifact metadata: %v", contractName, err) - return - } - - artifactVersion := artifactData.Output.Devdoc.StateVariables.Version.Semver - - isConstant := true - if artifactData.Output.Devdoc.StateVariables.Version.Semver == "" { - artifactVersion = artifactData.Output.Devdoc.Methods.Version.Semver - isConstant = false - } - - if artifactVersion == "" { - return - } - - // Skip mock contracts - if strings.HasPrefix(contractName, "Mock") { - return - } - - contractPath := contractFiles[contractName] - if contractPath == "" { - fail("%s: Source file not found (For test mock contracts, prefix the name with 'Mock' to ignore this warning)", contractName) - return - } - - cf, err := os.Open(contractPath) - if err != nil { - fail("%s: failed to open contract source: %v", contractName, err) - return - } - defer cf.Close() - - sourceData, err := io.ReadAll(cf) - if err != nil { - fail("%s: failed to read contract source: %v", contractName, err) - return - } - - var sourceVersion string - - if isConstant { - sourceVersion = findLine(sourceData, ConstantVersionPattern) - } else { - sourceVersion = findLine(sourceData, FunctionVersionPattern) - } - - // Need to define a special case for interop contracts since they technically - // use an invalid semver format. Checking for sourceVersion == "" allows the - // team to update the format to a valid semver format in the future without - // needing to change this program. - if sourceVersion == "" && strings.HasSuffix(contractName, "Interop") { - sourceVersion = findLine(sourceData, InteropVersionPattern) - } - - if sourceVersion == "" { - fail("%s: version not found in source", contractName) - return - } - - if sourceVersion != artifactVersion { - fail("%s: version mismatch: source=%s, artifact=%s", contractName, sourceVersion, artifactVersion) - return - } - - _, _ = fmt.Fprintf(os.Stderr, "✅ %s: code: %s, artifact: %s\n", contractName, sourceVersion, artifactVersion) - }() - } - - for i := 0; i < cap(sem); i++ { - sem <- struct{}{} - } - - if atomic.LoadInt32(&hasErr) == 1 { - return fmt.Errorf("semver check failed, see logs above") - } - - return nil -} - -func glob(dir string, ext string) (map[string]string, error) { - out := make(map[string]string) - err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { - if !info.IsDir() && filepath.Ext(path) == ext { - out[strings.TrimSuffix(filepath.Base(path), ext)] = path - } - return nil - }) - if err != nil { - return nil, fmt.Errorf("failed to walk directory: %w", err) - } - return out, nil -} - -func findLine(in []byte, pattern *regexp.Regexp) string { - scanner := bufio.NewScanner(bytes.NewReader(in)) - for scanner.Scan() { - match := pattern.FindStringSubmatch(scanner.Text()) - if len(match) > 0 { - return match[1] - } - } - return "" -} diff --git a/packages/contracts-bedrock/scripts/checks/semver-natspec/main_test.go b/packages/contracts-bedrock/scripts/checks/semver-natspec/main_test.go deleted file mode 100644 index 7a8872d76d780..0000000000000 --- a/packages/contracts-bedrock/scripts/checks/semver-natspec/main_test.go +++ /dev/null @@ -1,124 +0,0 @@ -package main - -import ( - "regexp" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestRegexes(t *testing.T) { - t.Run("ConstantVersionPattern", func(t *testing.T) { - testRegex(t, ConstantVersionPattern, []regexTest{ - { - name: "constant version", - input: `string constant version = "1.2.3";`, - capture: "1.2.3", - }, - { - name: "constant version with weird spaces", - input: ` string constant version = "1.2.3";`, - capture: "1.2.3", - }, - { - name: "constant version with visibility", - input: `string public constant version = "1.2.3";`, - capture: "1.2.3", - }, - { - name: "different variable name", - input: `string constant VERSION = "1.2.3";`, - capture: "", - }, - { - name: "different type", - input: `uint constant version = 1;`, - capture: "", - }, - { - name: "not constant", - input: `string version = "1.2.3";`, - capture: "", - }, - { - name: "unterminated", - input: `string constant version = "1.2.3"`, - capture: "", - }, - }) - }) - - t.Run("FunctionVersionPattern", func(t *testing.T) { - testRegex(t, FunctionVersionPattern, []regexTest{ - { - name: "function version", - input: ` return "1.2.3";`, - capture: "1.2.3", - }, - { - name: "function version with weird spaces", - input: ` return "1.2.3";`, - capture: "1.2.3", - }, - { - name: "function version with prerelease", - input: ` return "1.2.3-alpha.1";`, - capture: "1.2.3-alpha.1", - }, - { - name: "invalid semver", - input: ` return "1.2.cabdab";`, - capture: "", - }, - { - name: "not a return statement", - input: `function foo()`, - capture: "", - }, - }) - }) - - t.Run("InteropVersionPattern", func(t *testing.T) { - testRegex(t, InteropVersionPattern, []regexTest{ - { - name: "interop version", - input: ` return string.concat(super.version(), "+interop");`, - capture: "+interop", - }, - { - name: "interop version but as a valid semver", - input: ` return string.concat(super.version(), "0.0.0+interop");`, - capture: "0.0.0+interop", - }, - { - name: "not an interop version", - input: ` return string.concat(super.version(), "hello!");`, - capture: "", - }, - { - name: "invalid syntax", - input: ` return string.concat(super.version(), "0.0.0+interop`, - capture: "", - }, - { - name: "something else is concatted", - input: ` return string.concat("superduper", "mart");`, - capture: "", - }, - }) - }) -} - -type regexTest struct { - name string - input string - capture string -} - -func testRegex(t *testing.T, re *regexp.Regexp, tests []regexTest) { - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - require.Equal(t, test.capture, findLine([]byte(test.input), re)) - }) - } -} diff --git a/packages/contracts-bedrock/scripts/checks/names/main.go b/packages/contracts-bedrock/scripts/checks/test-names/main.go similarity index 96% rename from packages/contracts-bedrock/scripts/checks/names/main.go rename to packages/contracts-bedrock/scripts/checks/test-names/main.go index 1a0be03f33f29..86550f211cbae 100644 --- a/packages/contracts-bedrock/scripts/checks/names/main.go +++ b/packages/contracts-bedrock/scripts/checks/test-names/main.go @@ -18,6 +18,8 @@ type CheckInfo struct { error string } +var excludes = map[string]bool{} + var checks = []CheckInfo{ { error: "test name parts should be in camelCase", @@ -97,6 +99,10 @@ func main() { return nil } + if excludes[strings.TrimSuffix(filepath.Base(path), filepath.Ext(path))] { + return nil + } + data, err := os.ReadFile(path) if err != nil { return err diff --git a/packages/contracts-bedrock/scripts/utils/BaseDeployIO.sol b/packages/contracts-bedrock/scripts/deploy/BaseDeployIO.sol similarity index 100% rename from packages/contracts-bedrock/scripts/utils/BaseDeployIO.sol rename to packages/contracts-bedrock/scripts/deploy/BaseDeployIO.sol diff --git a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol index e68938392ee3e..26ef385c2f90b 100644 --- a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol @@ -12,17 +12,17 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; import { Deployer } from "scripts/deploy/Deployer.sol"; import { Chains } from "scripts/libraries/Chains.sol"; import { Config } from "scripts/libraries/Config.sol"; -import { LibStateDiff } from "scripts/libraries/LibStateDiff.sol"; +import { StateDiff } from "scripts/libraries/StateDiff.sol"; import { Process } from "scripts/libraries/Process.sol"; import { ChainAssertions } from "scripts/deploy/ChainAssertions.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; -import { DeploySuperchainInput, DeploySuperchain, DeploySuperchainOutput } from "scripts/DeploySuperchain.s.sol"; +import { DeploySuperchainInput, DeploySuperchain, DeploySuperchainOutput } from "scripts/deploy/DeploySuperchain.s.sol"; import { DeployImplementationsInput, DeployImplementations, DeployImplementationsInterop, DeployImplementationsOutput -} from "scripts/DeployImplementations.s.sol"; +} from "scripts/deploy/DeployImplementations.s.sol"; // Contracts import { StorageSetter } from "src/universal/StorageSetter.sol"; @@ -33,7 +33,7 @@ import { Constants } from "src/libraries/Constants.sol"; import { Types } from "scripts/libraries/Types.sol"; import { Duration } from "src/dispute/lib/LibUDT.sol"; import { StorageSlot, ForgeArtifacts } from "scripts/libraries/ForgeArtifacts.sol"; -import "src/dispute/lib/Types.sol"; +import { GameType, Claim, GameTypes, OutputRoot, Hash } from "src/dispute/lib/Types.sol"; // Interfaces import { IProxy } from "src/universal/interfaces/IProxy.sol"; @@ -128,7 +128,7 @@ contract Deploy is Deployer { accesses.length, vm.toString(block.chainid) ); - string memory json = LibStateDiff.encodeAccountAccesses(accesses); + string memory json = StateDiff.encodeAccountAccesses(accesses); string memory statediffPath = string.concat(vm.projectRoot(), "/snapshots/state-diff/", vm.toString(block.chainid), ".json"); vm.writeJson({ json: json, path: statediffPath }); @@ -162,7 +162,7 @@ contract Deploy is Deployer { L1ERC721Bridge: getAddress("L1ERC721BridgeProxy"), ProtocolVersions: getAddress("ProtocolVersionsProxy"), SuperchainConfig: getAddress("SuperchainConfigProxy"), - OPContractsManager: getAddress("OPContractsManagerProxy") + OPContractsManager: getAddress("OPContractsManager") }); } @@ -378,13 +378,12 @@ contract Deploy is Deployer { dii.set(dii.disputeGameFinalityDelaySeconds.selector, cfg.disputeGameFinalityDelaySeconds()); dii.set(dii.mipsVersion.selector, Config.useMultithreadedCannon() ? 2 : 1); string memory release = "dev"; - dii.set(dii.release.selector, release); + dii.set(dii.l1ContractsRelease.selector, release); dii.set( dii.standardVersionsToml.selector, string.concat(vm.projectRoot(), "/test/fixtures/standard-versions.toml") ); dii.set(dii.superchainConfigProxy.selector, mustGetAddress("SuperchainConfigProxy")); dii.set(dii.protocolVersionsProxy.selector, mustGetAddress("ProtocolVersionsProxy")); - dii.set(dii.opcmProxyOwner.selector, cfg.finalSystemOwner()); if (_isInterop) { di = DeployImplementations(new DeployImplementationsInterop()); @@ -409,8 +408,7 @@ contract Deploy is Deployer { save("DelayedWETH", address(dio.delayedWETHImpl())); save("PreimageOracle", address(dio.preimageOracleSingleton())); save("Mips", address(dio.mipsSingleton())); - save("OPContractsManagerProxy", address(dio.opcmProxy())); - save("OPContractsManager", address(dio.opcmImpl())); + save("OPContractsManager", address(dio.opcm())); Types.ContractSet memory contracts = _impls(); ChainAssertions.checkL1CrossDomainMessenger({ _contracts: contracts, _vm: vm, _isProxy: false }); @@ -446,7 +444,7 @@ contract Deploy is Deployer { // Ensure that the requisite contracts are deployed address superchainConfigProxy = mustGetAddress("SuperchainConfigProxy"); - OPContractsManager opcm = OPContractsManager(mustGetAddress("OPContractsManagerProxy")); + OPContractsManager opcm = OPContractsManager(mustGetAddress("OPContractsManager")); OPContractsManager.DeployInput memory deployInput = getDeployInput(); OPContractsManager.DeployOutput memory deployOutput = opcm.deploy(deployInput); @@ -697,12 +695,12 @@ contract Deploy is Deployer { addr_ = address(oracle); } - /// @notice Deploy Mips VM. Deploys either MIPS or MIPS2 depending on the environment + /// @notice Deploy Mips VM. Deploys either MIPS or MIPS64 depending on the environment function deployMips() public broadcast returns (address addr_) { addr_ = DeployUtils.create2AndSave({ _save: this, _salt: _implSalt(), - _name: Config.useMultithreadedCannon() ? "MIPS2" : "MIPS", + _name: Config.useMultithreadedCannon() ? "MIPS64" : "MIPS", _args: DeployUtils.encodeConstructor( abi.encodeCall(IMIPS2.__constructor__, (IPreimageOracle(mustGetAddress("PreimageOracle")))) ) @@ -995,17 +993,13 @@ contract Deploy is Deployer { function _loadDevnetStMipsAbsolutePrestate() internal returns (Claim mipsAbsolutePrestate_) { // Fetch the absolute prestate dump string memory filePath = string.concat(vm.projectRoot(), "/../../op-program/bin/prestate-proof.json"); - string[] memory commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = string.concat("[[ -f ", filePath, " ]] && echo \"present\""); - if (Process.run(commands).length == 0) { + if (bytes(Process.bash(string.concat("[[ -f ", filePath, " ]] && echo \"present\""))).length == 0) { revert( "Deploy: cannon prestate dump not found, generate it with `make cannon-prestate` in the monorepo root" ); } - commands[2] = string.concat("cat ", filePath, " | jq -r .pre"); - mipsAbsolutePrestate_ = Claim.wrap(abi.decode(Process.run(commands), (bytes32))); + mipsAbsolutePrestate_ = + Claim.wrap(abi.decode(bytes(Process.bash(string.concat("cat ", filePath, " | jq -r .pre"))), (bytes32))); console.log( "[Cannon Dispute Game] Using devnet MIPS Absolute prestate: %s", vm.toString(Claim.unwrap(mipsAbsolutePrestate_)) @@ -1017,19 +1011,15 @@ contract Deploy is Deployer { function _loadDevnetMtMipsAbsolutePrestate() internal returns (Claim mipsAbsolutePrestate_) { // Fetch the absolute prestate dump string memory filePath = string.concat(vm.projectRoot(), "/../../op-program/bin/prestate-proof-mt.json"); - string[] memory commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = string.concat("[[ -f ", filePath, " ]] && echo \"present\""); - if (Process.run(commands).length == 0) { + if (bytes(Process.bash(string.concat("[[ -f ", filePath, " ]] && echo \"present\""))).length == 0) { revert( "Deploy: MT-Cannon prestate dump not found, generate it with `make cannon-prestate-mt` in the monorepo root" ); } - commands[2] = string.concat("cat ", filePath, " | jq -r .pre"); - mipsAbsolutePrestate_ = Claim.wrap(abi.decode(Process.run(commands), (bytes32))); + mipsAbsolutePrestate_ = + Claim.wrap(abi.decode(bytes(Process.bash(string.concat("cat ", filePath, " | jq -r .pre"))), (bytes32))); console.log( - "[MT-Cannon Dispute Game] Using devnet MIPS2 Absolute prestate: %s", + "[MT-Cannon Dispute Game] Using devnet MIPS64 Absolute prestate: %s", vm.toString(Claim.unwrap(mipsAbsolutePrestate_)) ); } diff --git a/packages/contracts-bedrock/scripts/deploy/DeployAltDA.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployAltDA.s.sol new file mode 100644 index 0000000000000..a5071474926bd --- /dev/null +++ b/packages/contracts-bedrock/scripts/deploy/DeployAltDA.s.sol @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; +import { IDataAvailabilityChallenge } from "src/L1/interfaces/IDataAvailabilityChallenge.sol"; +import { IProxy } from "src/universal/interfaces/IProxy.sol"; +import { Script } from "forge-std/Script.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; +import { IProxyAdmin } from "src/universal/interfaces/IProxyAdmin.sol"; +import { Solarray } from "scripts/libraries/Solarray.sol"; + +contract DeployAltDAInput is BaseDeployIO { + bytes32 internal _salt; + IProxyAdmin internal _proxyAdmin; + address internal _challengeContractOwner; + uint256 internal _challengeWindow; + uint256 internal _resolveWindow; + uint256 internal _bondSize; + uint256 internal _resolverRefundPercentage; + + function set(bytes4 _sel, bytes32 _val) public { + if (_sel == this.salt.selector) _salt = _val; + else revert("DeployAltDAInput: unknown selector"); + } + + function set(bytes4 _sel, address _addr) public { + require(_addr != address(0), "DeployAltDAInput: cannot set zero address"); + if (_sel == this.proxyAdmin.selector) _proxyAdmin = IProxyAdmin(_addr); + else if (_sel == this.challengeContractOwner.selector) _challengeContractOwner = _addr; + else revert("DeployAltDAInput: unknown selector"); + } + + function set(bytes4 _sel, uint256 _val) public { + if (_sel == this.challengeWindow.selector) _challengeWindow = _val; + else if (_sel == this.resolveWindow.selector) _resolveWindow = _val; + else if (_sel == this.bondSize.selector) _bondSize = _val; + else if (_sel == this.resolverRefundPercentage.selector) _resolverRefundPercentage = _val; + else revert("DeployAltDAInput: unknown selector"); + } + + function salt() public view returns (bytes32) { + require(_salt != 0, "DeployAltDAInput: salt not set"); + return _salt; + } + + function proxyAdmin() public view returns (IProxyAdmin) { + require(address(_proxyAdmin) != address(0), "DeployAltDAInput: proxyAdmin not set"); + return _proxyAdmin; + } + + function challengeContractOwner() public view returns (address) { + require(_challengeContractOwner != address(0), "DeployAltDAInput: challengeContractOwner not set"); + return _challengeContractOwner; + } + + function challengeWindow() public view returns (uint256) { + require(_challengeWindow != 0, "DeployAltDAInput: challengeWindow not set"); + return _challengeWindow; + } + + function resolveWindow() public view returns (uint256) { + require(_resolveWindow != 0, "DeployAltDAInput: resolveWindow not set"); + return _resolveWindow; + } + + function bondSize() public view returns (uint256) { + require(_bondSize != 0, "DeployAltDAInput: bondSize not set"); + return _bondSize; + } + + function resolverRefundPercentage() public view returns (uint256) { + require(_resolverRefundPercentage != 0, "DeployAltDAInput: resolverRefundPercentage not set"); + return _resolverRefundPercentage; + } +} + +contract DeployAltDAOutput is BaseDeployIO { + IDataAvailabilityChallenge internal _dataAvailabilityChallengeProxy; + IDataAvailabilityChallenge internal _dataAvailabilityChallengeImpl; + + function set(bytes4 _sel, address _addr) public { + require(_addr != address(0), "DeployAltDAOutput: cannot set zero address"); + if (_sel == this.dataAvailabilityChallengeProxy.selector) { + _dataAvailabilityChallengeProxy = IDataAvailabilityChallenge(payable(_addr)); + } else if (_sel == this.dataAvailabilityChallengeImpl.selector) { + _dataAvailabilityChallengeImpl = IDataAvailabilityChallenge(payable(_addr)); + } else { + revert("DeployAltDAOutput: unknown selector"); + } + } + + function dataAvailabilityChallengeProxy() public view returns (IDataAvailabilityChallenge) { + DeployUtils.assertValidContractAddress(address(_dataAvailabilityChallengeProxy)); + return _dataAvailabilityChallengeProxy; + } + + function dataAvailabilityChallengeImpl() public view returns (IDataAvailabilityChallenge) { + DeployUtils.assertValidContractAddress(address(_dataAvailabilityChallengeImpl)); + return _dataAvailabilityChallengeImpl; + } +} + +contract DeployAltDA is Script { + function run(DeployAltDAInput _dai, DeployAltDAOutput _dao) public { + deployDataAvailabilityChallengeProxy(_dai, _dao); + deployDataAvailabilityChallengeImpl(_dai, _dao); + initializeDataAvailabilityChallengeProxy(_dai, _dao); + + checkOutput(_dai, _dao); + } + + function deployDataAvailabilityChallengeProxy(DeployAltDAInput _dai, DeployAltDAOutput _dao) public { + bytes32 salt = _dai.salt(); + vm.broadcast(msg.sender); + IProxy proxy = IProxy( + DeployUtils.create2({ + _name: "Proxy", + _salt: salt, + _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (msg.sender))) + }) + ); + vm.label(address(proxy), "DataAvailabilityChallengeProxy"); + _dao.set(_dao.dataAvailabilityChallengeProxy.selector, address(proxy)); + } + + function deployDataAvailabilityChallengeImpl(DeployAltDAInput _dai, DeployAltDAOutput _dao) public { + bytes32 salt = _dai.salt(); + vm.broadcast(msg.sender); + IDataAvailabilityChallenge impl = IDataAvailabilityChallenge( + DeployUtils.create2({ + _name: "DataAvailabilityChallenge", + _salt: salt, + _args: DeployUtils.encodeConstructor(abi.encodeCall(IDataAvailabilityChallenge.__constructor__, ())) + }) + ); + vm.label(address(impl), "DataAvailabilityChallengeImpl"); + _dao.set(_dao.dataAvailabilityChallengeImpl.selector, address(impl)); + } + + function initializeDataAvailabilityChallengeProxy(DeployAltDAInput _dai, DeployAltDAOutput _dao) public { + IProxy proxy = IProxy(payable(address(_dao.dataAvailabilityChallengeProxy()))); + IDataAvailabilityChallenge impl = _dao.dataAvailabilityChallengeImpl(); + IProxyAdmin proxyAdmin = IProxyAdmin(payable(address(_dai.proxyAdmin()))); + + address contractOwner = _dai.challengeContractOwner(); + uint256 challengeWindow = _dai.challengeWindow(); + uint256 resolveWindow = _dai.resolveWindow(); + uint256 bondSize = _dai.bondSize(); + uint256 resolverRefundPercentage = _dai.resolverRefundPercentage(); + + vm.startBroadcast(msg.sender); + proxy.upgradeToAndCall( + address(impl), + abi.encodeCall( + IDataAvailabilityChallenge.initialize, + (contractOwner, challengeWindow, resolveWindow, bondSize, resolverRefundPercentage) + ) + ); + proxy.changeAdmin(address(proxyAdmin)); + vm.stopBroadcast(); + } + + function checkOutput(DeployAltDAInput _dai, DeployAltDAOutput _dao) public { + address[] memory addresses = Solarray.addresses( + address(_dao.dataAvailabilityChallengeProxy()), address(_dao.dataAvailabilityChallengeImpl()) + ); + DeployUtils.assertValidContractAddresses(addresses); + + assertValidDataAvailabilityChallengeProxy(_dai, _dao); + assertValidDataAvailabilityChallengeImpl(_dao); + } + + function assertValidDataAvailabilityChallengeProxy(DeployAltDAInput _dai, DeployAltDAOutput _dao) public { + DeployUtils.assertERC1967ImplementationSet(address(_dao.dataAvailabilityChallengeProxy())); + + IProxy proxy = IProxy(payable(address(_dao.dataAvailabilityChallengeProxy()))); + vm.prank(address(0)); + address admin = proxy.admin(); + require(admin == address(_dai.proxyAdmin()), "DACP-10"); + + DeployUtils.assertInitialized({ _contractAddress: address(proxy), _slot: 0, _offset: 0 }); + + vm.prank(address(0)); + address impl = proxy.implementation(); + require(impl == address(_dao.dataAvailabilityChallengeImpl()), "DACP-20"); + + IDataAvailabilityChallenge dac = _dao.dataAvailabilityChallengeProxy(); + require(dac.owner() == _dai.challengeContractOwner(), "DACP-30"); + require(dac.challengeWindow() == _dai.challengeWindow(), "DACP-40"); + require(dac.resolveWindow() == _dai.resolveWindow(), "DACP-50"); + require(dac.bondSize() == _dai.bondSize(), "DACP-60"); + require(dac.resolverRefundPercentage() == _dai.resolverRefundPercentage(), "DACP-70"); + } + + function assertValidDataAvailabilityChallengeImpl(DeployAltDAOutput _dao) public view { + IDataAvailabilityChallenge dac = _dao.dataAvailabilityChallengeImpl(); + DeployUtils.assertInitialized({ _contractAddress: address(dac), _slot: 0, _offset: 0 }); + } +} diff --git a/packages/contracts-bedrock/scripts/DeployAuthSystem.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployAuthSystem.s.sol similarity index 100% rename from packages/contracts-bedrock/scripts/DeployAuthSystem.s.sol rename to packages/contracts-bedrock/scripts/deploy/DeployAuthSystem.s.sol diff --git a/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol index bfedb269ec944..968334ab501d0 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.15; import { Script } from "forge-std/Script.sol"; import { console2 as console } from "forge-std/console2.sol"; import { stdJson } from "forge-std/StdJson.sol"; -import { Executables } from "scripts/libraries/Executables.sol"; import { Process } from "scripts/libraries/Process.sol"; import { Config, Fork, ForkUtils } from "scripts/libraries/Config.sol"; @@ -215,12 +214,9 @@ contract DeployConfig is Script { function l2OutputOracleStartingTimestamp() public returns (uint256) { if (_l2OutputOracleStartingTimestamp < 0) { bytes32 tag = l1StartingBlockTag(); - string[] memory cmd = new string[](3); - cmd[0] = Executables.bash; - cmd[1] = "-c"; - cmd[2] = string.concat("cast block ", vm.toString(tag), " --json | ", Executables.jq, " .timestamp"); - bytes memory res = Process.run(cmd); - return stdJson.readUint(string(res), ""); + string memory cmd = string.concat("cast block ", vm.toString(tag), " --json | jq .timestamp"); + string memory res = Process.bash(cmd); + return stdJson.readUint(res, ""); } return uint256(_l2OutputOracleStartingTimestamp); } @@ -267,11 +263,8 @@ contract DeployConfig is Script { } function _getBlockByTag(string memory _tag) internal returns (bytes32) { - string[] memory cmd = new string[](3); - cmd[0] = Executables.bash; - cmd[1] = "-c"; - cmd[2] = string.concat("cast block ", _tag, " --json | ", Executables.jq, " -r .hash"); - bytes memory res = Process.run(cmd); + string memory cmd = string.concat("cast block ", _tag, " --json | jq -r .hash"); + bytes memory res = bytes(Process.bash(cmd)); return abi.decode(res, (bytes32)); } diff --git a/packages/contracts-bedrock/scripts/deploy/DeployDelayedWETH.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployDelayedWETH.s.sol new file mode 100644 index 0000000000000..979869cb3ad0d --- /dev/null +++ b/packages/contracts-bedrock/scripts/deploy/DeployDelayedWETH.s.sol @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +// Forge +import { Script } from "forge-std/Script.sol"; + +// Scripts +import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; + +// Libraries +import { LibString } from "@solady/utils/LibString.sol"; + +// Interfaces +import { IProxy } from "src/universal/interfaces/IProxy.sol"; +import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol"; +import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; + +/// @title DeployDelayedWETH +contract DeployDelayedWETHInput is BaseDeployIO { + /// Required inputs. + string internal _release; + string internal _standardVersionsToml; + address public _proxyAdmin; + ISuperchainConfig public _superchainConfigProxy; + address public _delayedWethOwner; + uint256 public _delayedWethDelay; + + function set(bytes4 _sel, uint256 _value) public { + if (_sel == this.delayedWethDelay.selector) { + require(_value != 0, "DeployDelayedWETH: delayedWethDelay cannot be zero"); + _delayedWethDelay = _value; + } else { + revert("DeployDelayedWETH: unknown selector"); + } + } + + function set(bytes4 _sel, address _value) public { + if (_sel == this.proxyAdmin.selector) { + require(_value != address(0), "DeployDelayedWETH: proxyAdmin cannot be zero address"); + _proxyAdmin = _value; + } else if (_sel == this.superchainConfigProxy.selector) { + require(_value != address(0), "DeployDelayedWETH: superchainConfigProxy cannot be zero address"); + _superchainConfigProxy = ISuperchainConfig(_value); + } else if (_sel == this.delayedWethOwner.selector) { + require(_value != address(0), "DeployDelayedWETH: delayedWethOwner cannot be zero address"); + _delayedWethOwner = _value; + } else { + revert("DeployDelayedWETH: unknown selector"); + } + } + + function set(bytes4 _sel, string memory _value) public { + if (_sel == this.release.selector) { + require(!LibString.eq(_value, ""), "DeployDelayedWETH: release cannot be empty"); + _release = _value; + } else if (_sel == this.standardVersionsToml.selector) { + require(!LibString.eq(_value, ""), "DeployDelayedWETH: standardVersionsToml cannot be empty"); + _standardVersionsToml = _value; + } else { + revert("DeployDelayedWETH: unknown selector"); + } + } + + function release() public view returns (string memory) { + require(!LibString.eq(_release, ""), "DeployDelayedWETH: release not set"); + return _release; + } + + function standardVersionsToml() public view returns (string memory) { + require(!LibString.eq(_standardVersionsToml, ""), "DeployDelayedWETH: standardVersionsToml not set"); + return _standardVersionsToml; + } + + function proxyAdmin() public view returns (address) { + require(_proxyAdmin != address(0), "DeployDelayedWETH: proxyAdmin not set"); + return _proxyAdmin; + } + + function superchainConfigProxy() public view returns (ISuperchainConfig) { + require(address(_superchainConfigProxy) != address(0), "DeployDisputeGame: superchainConfigProxy not set"); + return _superchainConfigProxy; + } + + function delayedWethOwner() public view returns (address) { + require(_delayedWethOwner != address(0), "DeployDelayedWETH: delayedWethOwner not set"); + return _delayedWethOwner; + } + + function delayedWethDelay() public view returns (uint256) { + require(_delayedWethDelay != 0, "DeployDelayedWETH: delayedWethDelay not set"); + return _delayedWethDelay; + } +} + +/// @title DeployDelayedWETHOutput +contract DeployDelayedWETHOutput is BaseDeployIO { + IDelayedWETH internal _delayedWethImpl; + IDelayedWETH internal _delayedWethProxy; + + function set(bytes4 _sel, address _value) public { + if (_sel == this.delayedWethImpl.selector) { + require(_value != address(0), "DeployDelayedWETHOutput: delayedWethImpl cannot be zero address"); + _delayedWethImpl = IDelayedWETH(payable(_value)); + } else if (_sel == this.delayedWethProxy.selector) { + require(_value != address(0), "DeployDelayedWETHOutput: delayedWethProxy cannot be zero address"); + _delayedWethProxy = IDelayedWETH(payable(_value)); + } else { + revert("DeployDelayedWETHOutput: unknown selector"); + } + } + + function checkOutput(DeployDelayedWETHInput _dwi) public { + DeployUtils.assertValidContractAddress(address(_delayedWethImpl)); + DeployUtils.assertValidContractAddress(address(_delayedWethProxy)); + assertValidDeploy(_dwi); + } + + function delayedWethImpl() public view returns (IDelayedWETH) { + DeployUtils.assertValidContractAddress(address(_delayedWethImpl)); + return _delayedWethImpl; + } + + function delayedWethProxy() public view returns (IDelayedWETH) { + DeployUtils.assertValidContractAddress(address(_delayedWethProxy)); + return _delayedWethProxy; + } + + function assertValidDeploy(DeployDelayedWETHInput _dwi) public { + assertValidDelayedWethImpl(_dwi); + assertValidDelayedWethProxy(_dwi); + } + + function assertValidDelayedWethImpl(DeployDelayedWETHInput _dwi) internal { + IProxy proxy = IProxy(payable(address(delayedWethProxy()))); + vm.prank(address(0)); + address impl = proxy.implementation(); + require(impl == address(delayedWethImpl()), "DWI-10"); + DeployUtils.assertInitialized({ _contractAddress: address(delayedWethImpl()), _slot: 0, _offset: 0 }); + require(delayedWethImpl().owner() == address(0), "DWI-20"); + require(delayedWethImpl().delay() == _dwi.delayedWethDelay(), "DWI-30"); + require(address(delayedWethImpl().config()) == address(0), "DWI-30"); + } + + function assertValidDelayedWethProxy(DeployDelayedWETHInput _dwi) internal { + // Check as proxy. + IProxy proxy = IProxy(payable(address(delayedWethProxy()))); + vm.prank(address(0)); + address admin = proxy.admin(); + require(admin == _dwi.proxyAdmin(), "DWP-10"); + + // Check as implementation. + DeployUtils.assertInitialized({ _contractAddress: address(delayedWethProxy()), _slot: 0, _offset: 0 }); + require(delayedWethProxy().owner() == _dwi.delayedWethOwner(), "DWP-20"); + require(delayedWethProxy().delay() == _dwi.delayedWethDelay(), "DWP-30"); + require(delayedWethProxy().config() == _dwi.superchainConfigProxy(), "DWP-40"); + } +} + +/// @title DeployDelayedWETH +contract DeployDelayedWETH is Script { + function run(DeployDelayedWETHInput _dwi, DeployDelayedWETHOutput _dwo) public { + deployDelayedWethProxy(_dwi, _dwo); + _dwo.checkOutput(_dwi); + } + + function deployDelayedWethImpl(DeployDelayedWETHInput _dwi, DeployDelayedWETHOutput _dwo) internal { + string memory release = _dwi.release(); + string memory stdVerToml = _dwi.standardVersionsToml(); + string memory contractName = "delayed_weth"; + IDelayedWETH impl; + + address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); + if (existingImplementation != address(0)) { + impl = IDelayedWETH(payable(existingImplementation)); + } else if (isDevelopRelease(release)) { + vm.broadcast(msg.sender); + impl = IDelayedWETH( + DeployUtils.create1({ + _name: "DelayedWETH", + _args: DeployUtils.encodeConstructor( + abi.encodeCall(IDelayedWETH.__constructor__, (_dwi.delayedWethDelay())) + ) + }) + ); + } else { + revert(string.concat("DeployDelayedWETH: failed to deploy release ", release)); + } + + vm.label(address(impl), "DelayedWETHImpl"); + _dwo.set(_dwo.delayedWethImpl.selector, address(impl)); + } + + function deployDelayedWethProxy(DeployDelayedWETHInput _dwi, DeployDelayedWETHOutput _dwo) internal { + vm.broadcast(msg.sender); + IProxy proxy = IProxy( + DeployUtils.create1({ + _name: "Proxy", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (msg.sender))) + }) + ); + + deployDelayedWethImpl(_dwi, _dwo); + IDelayedWETH impl = _dwo.delayedWethImpl(); + + vm.startBroadcast(msg.sender); + proxy.upgradeToAndCall( + address(impl), abi.encodeCall(impl.initialize, (_dwi.delayedWethOwner(), _dwi.superchainConfigProxy())) + ); + proxy.changeAdmin(_dwi.proxyAdmin()); + vm.stopBroadcast(); + + vm.label(address(proxy), "DelayedWETHProxy"); + _dwo.set(_dwo.delayedWethProxy.selector, address(proxy)); + } + + // Zero address is returned if the address is not found in '_standardVersionsToml'. + function getReleaseAddress( + string memory _version, + string memory _contractName, + string memory _standardVersionsToml + ) + internal + pure + returns (address addr_) + { + string memory baseKey = string.concat('.releases["', _version, '"].', _contractName); + string memory implAddressKey = string.concat(baseKey, ".implementation_address"); + string memory addressKey = string.concat(baseKey, ".address"); + try vm.parseTomlAddress(_standardVersionsToml, implAddressKey) returns (address parsedAddr_) { + addr_ = parsedAddr_; + } catch { + try vm.parseTomlAddress(_standardVersionsToml, addressKey) returns (address parsedAddr_) { + addr_ = parsedAddr_; + } catch { + addr_ = address(0); + } + } + } + + // A release is considered a 'develop' release if it does not start with 'op-contracts'. + function isDevelopRelease(string memory _release) internal pure returns (bool) { + return !LibString.startsWith(_release, "op-contracts"); + } +} diff --git a/packages/contracts-bedrock/scripts/deploy/DeployDisputeGame.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployDisputeGame.s.sol new file mode 100644 index 0000000000000..c128260a21da5 --- /dev/null +++ b/packages/contracts-bedrock/scripts/deploy/DeployDisputeGame.s.sol @@ -0,0 +1,495 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +// Forge +import { Script } from "forge-std/Script.sol"; + +// Scripts +import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; + +// Libraries +import { GameType, Claim, Duration } from "src/dispute/lib/Types.sol"; +import { LibString } from "@solady/utils/LibString.sol"; + +// Interfaces +import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol"; +import { IPermissionedDisputeGame } from "src/dispute/interfaces/IPermissionedDisputeGame.sol"; +import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol"; +import { IBigStepper } from "src/dispute/interfaces/IBigStepper.sol"; +import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol"; +import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol"; +import { IMIPS } from "src/cannon/interfaces/IMIPS.sol"; + +/// @title DeployDisputeGameInput +contract DeployDisputeGameInput is BaseDeployIO { + // Common inputs. + string internal _release; + string internal _standardVersionsToml; + + // Specify which MIPS version to use. + uint256 internal _mipsVersion; + + // All inputs required to deploy PreimageOracle. + uint256 internal _minProposalSizeBytes; + uint256 internal _challengePeriodSeconds; + + // Specify which game kind is being deployed here. + string internal _gameKind; + + // All inputs required to deploy FaultDisputeGame. + uint256 internal _gameType; + bytes32 internal _absolutePrestate; + uint256 internal _maxGameDepth; + uint256 internal _splitDepth; + uint256 internal _clockExtension; + uint256 internal _maxClockDuration; + IDelayedWETH internal _delayedWethProxy; + IAnchorStateRegistry internal _anchorStateRegistryProxy; + uint256 internal _l2ChainId; + + // Additional inputs required to deploy PermissionedDisputeGame. + address internal _proposer; + address internal _challenger; + + function set(bytes4 _sel, uint256 _value) public { + if (_sel == this.mipsVersion.selector) { + require(_value == 1 || _value == 2, "DeployDisputeGame: unknown mips version"); + _mipsVersion = _value; + } else if (_sel == this.minProposalSizeBytes.selector) { + require(_value != 0, "DeployDisputeGame: minProposalSizeBytes cannot be zero"); + _minProposalSizeBytes = _value; + } else if (_sel == this.challengePeriodSeconds.selector) { + require(_value != 0, "DeployDisputeGame: challengePeriodSeconds cannot be zero"); + _challengePeriodSeconds = _value; + } else if (_sel == this.gameType.selector) { + require(_value <= type(uint32).max, "DeployDisputeGame: gameType must fit inside uint32"); + _gameType = _value; + } else if (_sel == this.maxGameDepth.selector) { + require(_value != 0, "DeployDisputeGame: maxGameDepth cannot be zero"); + _maxGameDepth = _value; + } else if (_sel == this.splitDepth.selector) { + require(_value != 0, "DeployDisputeGame: splitDepth cannot be zero"); + _splitDepth = _value; + } else if (_sel == this.clockExtension.selector) { + require(_value <= type(uint64).max, "DeployDisputeGame: clockExtension must fit inside uint64"); + require(_value != 0, "DeployDisputeGame: clockExtension cannot be zero"); + _clockExtension = _value; + } else if (_sel == this.maxClockDuration.selector) { + require(_value <= type(uint64).max, "DeployDisputeGame: maxClockDuration must fit inside uint64"); + require(_value != 0, "DeployDisputeGame: maxClockDuration cannot be zero"); + _maxClockDuration = _value; + } else if (_sel == this.l2ChainId.selector) { + require(_value != 0, "DeployDisputeGame: l2ChainId cannot be zero"); + _l2ChainId = _value; + } else { + revert("DeployDisputeGame: unknown selector"); + } + } + + function set(bytes4 _sel, address _value) public { + if (_sel == this.delayedWethProxy.selector) { + require(_value != address(0), "DeployDisputeGame: delayedWethProxy cannot be zero address"); + _delayedWethProxy = IDelayedWETH(payable(_value)); + } else if (_sel == this.anchorStateRegistryProxy.selector) { + require(_value != address(0), "DeployDisputeGame: anchorStateRegistryProxy cannot be zero address"); + _anchorStateRegistryProxy = IAnchorStateRegistry(payable(_value)); + } else if (_sel == this.proposer.selector) { + require(_value != address(0), "DeployDisputeGame: proposer cannot be zero address"); + _proposer = _value; + } else if (_sel == this.challenger.selector) { + require(_value != address(0), "DeployDisputeGame: challenger cannot be zero address"); + _challenger = _value; + } else { + revert("DeployDisputeGame: unknown selector"); + } + } + + function set(bytes4 _sel, string memory _value) public { + if (_sel == this.gameKind.selector) { + require( + LibString.eq(_value, "FaultDisputeGame") || LibString.eq(_value, "PermissionedDisputeGame"), + "DeployDisputeGame: unknown game kind" + ); + _gameKind = _value; + } else if (_sel == this.release.selector) { + require(!LibString.eq(_value, ""), "DeployDisputeGame: release cannot be empty"); + _release = _value; + } else if (_sel == this.standardVersionsToml.selector) { + require(!LibString.eq(_value, ""), "DeployDisputeGame: standardVersionsToml cannot be empty"); + _standardVersionsToml = _value; + } else { + revert("DeployDisputeGame: unknown selector"); + } + } + + function release() public view returns (string memory) { + require(!LibString.eq(_release, ""), "DeployDisputeGame: release not set"); + return _release; + } + + function standardVersionsToml() public view returns (string memory) { + require(!LibString.eq(_standardVersionsToml, ""), "DeployDisputeGame: standardVersionsToml not set"); + return _standardVersionsToml; + } + + function mipsVersion() public view returns (uint256) { + require(_mipsVersion != 0, "DeployDisputeGame: mipsVersion not set"); + require(_mipsVersion == 1 || _mipsVersion == 2, "DeployDisputeGame: unknown mips version"); + return _mipsVersion; + } + + function minProposalSizeBytes() public view returns (uint256) { + require(_minProposalSizeBytes != 0, "DeployDisputeGame: minProposalSizeBytes not set"); + return _minProposalSizeBytes; + } + + function challengePeriodSeconds() public view returns (uint256) { + require(_challengePeriodSeconds != 0, "DeployDisputeGame: challengePeriodSeconds not set"); + return _challengePeriodSeconds; + } + + function gameKind() public view returns (string memory) { + require( + LibString.eq(_gameKind, "FaultDisputeGame") || LibString.eq(_gameKind, "PermissionedDisputeGame"), + "DeployDisputeGame: unknown game kind" + ); + return _gameKind; + } + + function gameType() public view returns (uint256) { + require(_gameType <= type(uint32).max, "DeployDisputeGame: gameType must fit inside uint32"); + return _gameType; + } + + function absolutePrestate() public view returns (bytes32) { + require(_absolutePrestate != bytes32(0), "DeployDisputeGame: absolutePrestate not set"); + return _absolutePrestate; + } + + function maxGameDepth() public view returns (uint256) { + require(_maxGameDepth != 0, "DeployDisputeGame: maxGameDepth not set"); + return _maxGameDepth; + } + + function splitDepth() public view returns (uint256) { + require(_splitDepth != 0, "DeployDisputeGame: splitDepth not set"); + return _splitDepth; + } + + function clockExtension() public view returns (uint256) { + require(_clockExtension <= type(uint64).max, "DeployDisputeGame: clockExtension must fit inside uint64"); + require(_clockExtension != 0, "DeployDisputeGame: clockExtension not set"); + return _clockExtension; + } + + function maxClockDuration() public view returns (uint256) { + require(_maxClockDuration <= type(uint64).max, "DeployDisputeGame: maxClockDuration must fit inside uint64"); + require(_maxClockDuration != 0, "DeployDisputeGame: maxClockDuration not set"); + return _maxClockDuration; + } + + function delayedWethProxy() public view returns (IDelayedWETH) { + require(address(_delayedWethProxy) != address(0), "DeployDisputeGame: delayedWethProxy not set"); + return _delayedWethProxy; + } + + function anchorStateRegistryProxy() public view returns (IAnchorStateRegistry) { + require(address(_anchorStateRegistryProxy) != address(0), "DeployDisputeGame: anchorStateRegistryProxy not set"); + return _anchorStateRegistryProxy; + } + + function l2ChainId() public view returns (uint256) { + require(_l2ChainId != 0, "DeployDisputeGame: l2ChainId not set"); + return _l2ChainId; + } + + function proposer() public view returns (address) { + if (LibString.eq(_gameKind, "FaultDisputeGame")) { + require(_proposer == address(0), "DeployDisputeGame: proposer must be empty"); + } else { + require(_proposer != address(0), "DeployDisputeGame: proposer not set"); + } + return _proposer; + } + + function challenger() public view returns (address) { + if (LibString.eq(_gameKind, "FaultDisputeGame")) { + require(_challenger == address(0), "DeployDisputeGame: challenger must be empty"); + } else { + require(_challenger != address(0), "DeployDisputeGame: challenger not set"); + } + return _challenger; + } +} + +/// @title DeployDisputeGameOutput +contract DeployDisputeGameOutput is BaseDeployIO { + // PermissionedDisputeGame is used as the type here because it has all of the same functions as + // FaultDisputeGame but with the added proposer and challenger fields. + IPermissionedDisputeGame internal _disputeGameImpl; + IMIPS internal _mipsSingleton; + IPreimageOracle internal _preimageOracleSingleton; + + function set(bytes4 _sel, address _value) public { + if (_sel == this.disputeGameImpl.selector) { + require(_value != address(0), "DeployDisputeGame: disputeGameImpl cannot be zero address"); + _disputeGameImpl = IPermissionedDisputeGame(_value); + } else if (_sel == this.mipsSingleton.selector) { + require(_value != address(0), "DeployDisputeGame: mipsSingleton cannot be zero address"); + _mipsSingleton = IMIPS(_value); + } else if (_sel == this.preimageOracleSingleton.selector) { + require(_value != address(0), "DeployDisputeGame: preimageOracleSingleton cannot be zero address"); + _preimageOracleSingleton = IPreimageOracle(_value); + } else { + revert("DeployDisputeGame: unknown selector"); + } + } + + function checkOutput(DeployDisputeGameInput _dgi) public view { + DeployUtils.assertValidContractAddress(address(_preimageOracleSingleton)); + DeployUtils.assertValidContractAddress(address(_mipsSingleton)); + DeployUtils.assertValidContractAddress(address(_disputeGameImpl)); + assertValidDeploy(_dgi); + } + + function preimageOracleSingleton() public view returns (IPreimageOracle) { + DeployUtils.assertValidContractAddress(address(_preimageOracleSingleton)); + return _preimageOracleSingleton; + } + + function mipsSingleton() public view returns (IMIPS) { + DeployUtils.assertValidContractAddress(address(_mipsSingleton)); + return _mipsSingleton; + } + + function disputeGameImpl() public view returns (IPermissionedDisputeGame) { + DeployUtils.assertValidContractAddress(address(_disputeGameImpl)); + return _disputeGameImpl; + } + + function assertValidDeploy(DeployDisputeGameInput _dgi) public view { + assertValidPreimageOracleSingleton(_dgi); + assertValidMipsSingleton(_dgi); + assertValidDisputeGameImpl(_dgi); + } + + function assertValidPreimageOracleSingleton(DeployDisputeGameInput _dgi) internal view { + IPreimageOracle oracle = preimageOracleSingleton(); + + require(oracle.minProposalSize() == _dgi.minProposalSizeBytes(), "PO-10"); + require(oracle.challengePeriod() == _dgi.challengePeriodSeconds(), "PO-20"); + } + + function assertValidMipsSingleton(DeployDisputeGameInput) internal view { + IMIPS mips = mipsSingleton(); + + require(address(mips.oracle()) == address(preimageOracleSingleton()), "MIPS-10"); + } + + function assertValidDisputeGameImpl(DeployDisputeGameInput _dgi) internal view { + IPermissionedDisputeGame game = disputeGameImpl(); + + require(game.gameType().raw() == uint32(_dgi.gameType()), "DG-10"); + require(game.maxGameDepth() == _dgi.maxGameDepth(), "DG-20"); + require(game.splitDepth() == _dgi.splitDepth(), "DG-30"); + require(game.clockExtension().raw() == uint64(_dgi.clockExtension()), "DG-40"); + require(game.maxClockDuration().raw() == uint64(_dgi.maxClockDuration()), "DG-50"); + require(game.vm() == IBigStepper(address(mipsSingleton())), "DG-60"); + require(game.weth() == _dgi.delayedWethProxy(), "DG-70"); + require(game.anchorStateRegistry() == _dgi.anchorStateRegistryProxy(), "DG-80"); + require(game.l2ChainId() == _dgi.l2ChainId(), "DG-90"); + + if (LibString.eq(_dgi.gameKind(), "PermissionedDisputeGame")) { + require(game.proposer() == _dgi.proposer(), "DG-100"); + require(game.challenger() == _dgi.challenger(), "DG-110"); + } + } +} + +/// @title DeployDisputeGame +contract DeployDisputeGame is Script { + /// We need a struct for constructor args to avoid stack-too-deep errors. + struct DisputeGameConstructorArgs { + GameType gameType; + Claim absolutePrestate; + uint256 maxGameDepth; + uint256 splitDepth; + Duration clockExtension; + Duration maxClockDuration; + IBigStepper gameVm; + IDelayedWETH delayedWethProxy; + IAnchorStateRegistry anchorStateRegistryProxy; + uint256 l2ChainId; + address proposer; + address challenger; + } + + function run(DeployDisputeGameInput _dgi, DeployDisputeGameOutput _dgo) public { + deployPreimageOracleSingleton(_dgi, _dgo); + deployMipsSingleton(_dgi, _dgo); + deployDisputeGameImpl(_dgi, _dgo); + _dgo.checkOutput(_dgi); + } + + function deployPreimageOracleSingleton(DeployDisputeGameInput _dgi, DeployDisputeGameOutput _dgo) internal { + string memory release = _dgi.release(); + string memory stdVerToml = _dgi.standardVersionsToml(); + string memory contractName = "preimage_oracle"; + IPreimageOracle singleton; + + address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); + if (existingImplementation != address(0)) { + singleton = IPreimageOracle(payable(existingImplementation)); + } else if (isDevelopRelease(release)) { + uint256 minProposalSizeBytes = _dgi.minProposalSizeBytes(); + uint256 challengePeriodSeconds = _dgi.challengePeriodSeconds(); + vm.broadcast(msg.sender); + singleton = IPreimageOracle( + DeployUtils.create1({ + _name: "PreimageOracle", + _args: DeployUtils.encodeConstructor( + abi.encodeCall(IPreimageOracle.__constructor__, (minProposalSizeBytes, challengePeriodSeconds)) + ) + }) + ); + } else { + revert(string.concat("DeployImplementations: failed to deploy release ", release)); + } + + vm.label(address(singleton), "PreimageOracleSingleton"); + _dgo.set(_dgo.preimageOracleSingleton.selector, address(singleton)); + } + + function deployMipsSingleton(DeployDisputeGameInput _dgi, DeployDisputeGameOutput _dgo) internal { + string memory release = _dgi.release(); + string memory stdVerToml = _dgi.standardVersionsToml(); + string memory contractName = "mips"; + IMIPS singleton; + + address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); + if (existingImplementation != address(0)) { + singleton = IMIPS(payable(existingImplementation)); + } else if (isDevelopRelease(release)) { + uint256 mipsVersion = _dgi.mipsVersion(); + IPreimageOracle preimageOracle = IPreimageOracle(address(_dgo.preimageOracleSingleton())); + vm.broadcast(msg.sender); + singleton = IMIPS( + DeployUtils.create1({ + _name: mipsVersion == 1 ? "MIPS" : "MIPS64", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (preimageOracle))) + }) + ); + } else { + revert(string.concat("DeployImplementations: failed to deploy release ", release)); + } + + vm.label(address(singleton), "MIPSSingleton"); + _dgo.set(_dgo.mipsSingleton.selector, address(singleton)); + } + + function deployDisputeGameImpl(DeployDisputeGameInput _dgi, DeployDisputeGameOutput _dgo) internal { + // Shove the arguments into a struct to avoid stack-too-deep errors. + DisputeGameConstructorArgs memory args = DisputeGameConstructorArgs({ + gameType: GameType.wrap(uint32(_dgi.gameType())), + absolutePrestate: Claim.wrap(_dgi.absolutePrestate()), + maxGameDepth: _dgi.maxGameDepth(), + splitDepth: _dgi.splitDepth(), + clockExtension: Duration.wrap(uint64(_dgi.clockExtension())), + maxClockDuration: Duration.wrap(uint64(_dgi.maxClockDuration())), + gameVm: IBigStepper(address(_dgo.mipsSingleton())), + delayedWethProxy: _dgi.delayedWethProxy(), + anchorStateRegistryProxy: _dgi.anchorStateRegistryProxy(), + l2ChainId: _dgi.l2ChainId(), + proposer: _dgi.proposer(), + challenger: _dgi.challenger() + }); + + // PermissionedDisputeGame is used as the type here because it is a superset of + // FaultDisputeGame. If the user requests to deploy a FaultDisputeGame, the user will get a + // FaultDisputeGame (and not a PermissionedDisputeGame). + vm.broadcast(msg.sender); + IPermissionedDisputeGame impl; + if (LibString.eq(_dgi.gameKind(), "FaultDisputeGame")) { + impl = IPermissionedDisputeGame( + DeployUtils.create1({ + _name: "FaultDisputeGame", + _args: DeployUtils.encodeConstructor( + abi.encodeCall( + IFaultDisputeGame.__constructor__, + ( + args.gameType, + args.absolutePrestate, + args.maxGameDepth, + args.splitDepth, + args.clockExtension, + args.maxClockDuration, + args.gameVm, + args.delayedWethProxy, + args.anchorStateRegistryProxy, + args.l2ChainId + ) + ) + ) + }) + ); + } else { + impl = IPermissionedDisputeGame( + DeployUtils.create1({ + _name: "PermissionedDisputeGame", + _args: DeployUtils.encodeConstructor( + abi.encodeCall( + IPermissionedDisputeGame.__constructor__, + ( + args.gameType, + args.absolutePrestate, + args.maxGameDepth, + args.splitDepth, + args.clockExtension, + args.maxClockDuration, + args.gameVm, + args.delayedWethProxy, + args.anchorStateRegistryProxy, + args.l2ChainId, + args.proposer, + args.challenger + ) + ) + ) + }) + ); + } + + vm.label(address(impl), string.concat(_dgi.gameKind(), "Impl")); + _dgo.set(_dgo.disputeGameImpl.selector, address(impl)); + } + + // Zero address is returned if the address is not found in '_standardVersionsToml'. + function getReleaseAddress( + string memory _version, + string memory _contractName, + string memory _standardVersionsToml + ) + internal + pure + returns (address addr_) + { + string memory baseKey = string.concat('.releases["', _version, '"].', _contractName); + string memory implAddressKey = string.concat(baseKey, ".implementation_address"); + string memory addressKey = string.concat(baseKey, ".address"); + try vm.parseTomlAddress(_standardVersionsToml, implAddressKey) returns (address parsedAddr_) { + addr_ = parsedAddr_; + } catch { + try vm.parseTomlAddress(_standardVersionsToml, addressKey) returns (address parsedAddr_) { + addr_ = parsedAddr_; + } catch { + addr_ = address(0); + } + } + } + + // A release is considered a 'develop' release if it does not start with 'op-contracts'. + function isDevelopRelease(string memory _release) internal pure returns (bool) { + return !LibString.startsWith(_release, "op-contracts"); + } +} diff --git a/packages/contracts-bedrock/scripts/DeployImplementations.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol similarity index 73% rename from packages/contracts-bedrock/scripts/DeployImplementations.s.sol rename to packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol index 3179ea3d6426e..71ba435df4c31 100644 --- a/packages/contracts-bedrock/scripts/DeployImplementations.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol @@ -8,16 +8,11 @@ import { LibString } from "@solady/utils/LibString.sol"; import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; import { IProtocolVersions } from "src/L1/interfaces/IProtocolVersions.sol"; -import { ISystemConfigV160 } from "src/L1/interfaces/ISystemConfigV160.sol"; -import { IL1CrossDomainMessengerV160 } from "src/L1/interfaces/IL1CrossDomainMessengerV160.sol"; -import { IL1StandardBridgeV160 } from "src/L1/interfaces/IL1StandardBridgeV160.sol"; import { Constants } from "src/libraries/Constants.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { Bytes } from "src/libraries/Bytes.sol"; -import { IProxy } from "src/universal/interfaces/IProxy.sol"; - import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol"; import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol"; import { IMIPS } from "src/cannon/interfaces/IMIPS.sol"; @@ -39,7 +34,7 @@ import { Blueprint } from "src/libraries/Blueprint.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { Solarray } from "scripts/libraries/Solarray.sol"; -import { BaseDeployIO } from "scripts/utils/BaseDeployIO.sol"; +import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; // See DeploySuperchain.s.sol for detailed comments on the script architecture used here. contract DeployImplementationsInput is BaseDeployIO { @@ -51,8 +46,9 @@ contract DeployImplementationsInput is BaseDeployIO { uint256 internal _disputeGameFinalityDelaySeconds; uint256 internal _mipsVersion; - // The release version to set OPCM implementations for, of the format `op-contracts/vX.Y.Z`. - string internal _release; + // This is used in opcm to signal which version of the L1 smart contracts is deployed. + // It takes the format of `op-contracts/v*.*.*`. + string internal _l1ContractsRelease; // Outputs from DeploySuperchain.s.sol. ISuperchainConfig internal _superchainConfigProxy; @@ -60,8 +56,6 @@ contract DeployImplementationsInput is BaseDeployIO { string internal _standardVersionsToml; - address internal _opcmProxyOwner; - function set(bytes4 _sel, uint256 _value) public { require(_value != 0, "DeployImplementationsInput: cannot set zero value"); @@ -85,7 +79,7 @@ contract DeployImplementationsInput is BaseDeployIO { function set(bytes4 _sel, string memory _value) public { require(!LibString.eq(_value, ""), "DeployImplementationsInput: cannot set empty string"); - if (_sel == this.release.selector) _release = _value; + if (_sel == this.l1ContractsRelease.selector) _l1ContractsRelease = _value; else if (_sel == this.standardVersionsToml.selector) _standardVersionsToml = _value; else revert("DeployImplementationsInput: unknown selector"); } @@ -94,7 +88,6 @@ contract DeployImplementationsInput is BaseDeployIO { require(_addr != address(0), "DeployImplementationsInput: cannot set zero address"); if (_sel == this.superchainConfigProxy.selector) _superchainConfigProxy = ISuperchainConfig(_addr); else if (_sel == this.protocolVersionsProxy.selector) _protocolVersionsProxy = IProtocolVersions(_addr); - else if (_sel == this.opcmProxyOwner.selector) _opcmProxyOwner = _addr; else revert("DeployImplementationsInput: unknown selector"); } @@ -141,9 +134,9 @@ contract DeployImplementationsInput is BaseDeployIO { return _mipsVersion; } - function release() public view returns (string memory) { - require(!LibString.eq(_release, ""), "DeployImplementationsInput: not set"); - return _release; + function l1ContractsRelease() public view returns (string memory) { + require(!LibString.eq(_l1ContractsRelease, ""), "DeployImplementationsInput: not set"); + return _l1ContractsRelease; } function standardVersionsToml() public view returns (string memory) { @@ -160,16 +153,10 @@ contract DeployImplementationsInput is BaseDeployIO { require(address(_protocolVersionsProxy) != address(0), "DeployImplementationsInput: not set"); return _protocolVersionsProxy; } - - function opcmProxyOwner() public view returns (address) { - require(address(_opcmProxyOwner) != address(0), "DeployImplementationsInput: not set"); - return _opcmProxyOwner; - } } contract DeployImplementationsOutput is BaseDeployIO { - OPContractsManager internal _opcmProxy; - OPContractsManager internal _opcmImpl; + OPContractsManager internal _opcm; IDelayedWETH internal _delayedWETHImpl; IOptimismPortal2 internal _optimismPortalImpl; IPreimageOracle internal _preimageOracleSingleton; @@ -185,8 +172,7 @@ contract DeployImplementationsOutput is BaseDeployIO { require(_addr != address(0), "DeployImplementationsOutput: cannot set zero address"); // forgefmt: disable-start - if (_sel == this.opcmProxy.selector) _opcmProxy = OPContractsManager(payable(_addr)); - else if (_sel == this.opcmImpl.selector) _opcmImpl = OPContractsManager(payable(_addr)); + if (_sel == this.opcm.selector) _opcm = OPContractsManager(_addr); else if (_sel == this.optimismPortalImpl.selector) _optimismPortalImpl = IOptimismPortal2(payable(_addr)); else if (_sel == this.delayedWETHImpl.selector) _delayedWETHImpl = IDelayedWETH(payable(_addr)); else if (_sel == this.preimageOracleSingleton.selector) _preimageOracleSingleton = IPreimageOracle(_addr); @@ -201,12 +187,11 @@ contract DeployImplementationsOutput is BaseDeployIO { // forgefmt: disable-end } - function checkOutput(DeployImplementationsInput _dii) public { + function checkOutput(DeployImplementationsInput _dii) public view { // 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. address[] memory addrs1 = Solarray.addresses( - address(this.opcmProxy()), - address(this.opcmImpl()), + address(this.opcm()), address(this.optimismPortalImpl()), address(this.delayedWETHImpl()), address(this.preimageOracleSingleton()), @@ -227,15 +212,9 @@ contract DeployImplementationsOutput is BaseDeployIO { assertValidDeploy(_dii); } - function opcmProxy() public returns (OPContractsManager) { - DeployUtils.assertValidContractAddress(address(_opcmProxy)); - DeployUtils.assertERC1967ImplementationSet(address(_opcmProxy)); - return _opcmProxy; - } - - function opcmImpl() public view returns (OPContractsManager) { - DeployUtils.assertValidContractAddress(address(_opcmImpl)); - return _opcmImpl; + function opcm() public view returns (OPContractsManager) { + DeployUtils.assertValidContractAddress(address(_opcm)); + return _opcm; } function optimismPortalImpl() public view returns (IOptimismPortal2) { @@ -289,40 +268,22 @@ contract DeployImplementationsOutput is BaseDeployIO { } // -------- Deployment Assertions -------- - function assertValidDeploy(DeployImplementationsInput _dii) public { + function assertValidDeploy(DeployImplementationsInput _dii) public view { assertValidDelayedWETHImpl(_dii); assertValidDisputeGameFactoryImpl(_dii); assertValidL1CrossDomainMessengerImpl(_dii); assertValidL1ERC721BridgeImpl(_dii); assertValidL1StandardBridgeImpl(_dii); assertValidMipsSingleton(_dii); - assertValidOpcmProxy(_dii); - assertValidOpcmImpl(_dii); + assertValidOpcm(_dii); assertValidOptimismMintableERC20FactoryImpl(_dii); assertValidOptimismPortalImpl(_dii); assertValidPreimageOracleSingleton(_dii); assertValidSystemConfigImpl(_dii); } - function assertValidOpcmProxy(DeployImplementationsInput _dii) internal { - // First we check the proxy as itself. - IProxy proxy = IProxy(payable(address(opcmProxy()))); - vm.prank(address(0)); - address admin = proxy.admin(); - require(admin == address(_dii.opcmProxyOwner()), "OPCMP-10"); - - // Then we check the proxy as OPCM. - DeployUtils.assertInitialized({ _contractAddress: address(opcmProxy()), _slot: 0, _offset: 0 }); - require(address(opcmProxy().superchainConfig()) == address(_dii.superchainConfigProxy()), "OPCMP-20"); - require(address(opcmProxy().protocolVersions()) == address(_dii.protocolVersionsProxy()), "OPCMP-30"); - require(LibString.eq(opcmProxy().latestRelease(), _dii.release()), "OPCMP-50"); // Initial release is latest. - } - - function assertValidOpcmImpl(DeployImplementationsInput _dii) internal { - IProxy proxy = IProxy(payable(address(opcmProxy()))); - vm.prank(address(0)); - OPContractsManager impl = OPContractsManager(proxy.implementation()); - DeployUtils.assertInitialized({ _contractAddress: address(impl), _slot: 0, _offset: 0 }); + function assertValidOpcm(DeployImplementationsInput _dii) internal view { + OPContractsManager impl = OPContractsManager(address(opcm())); require(address(impl.superchainConfig()) == address(_dii.superchainConfigProxy()), "OPCMI-10"); require(address(impl.protocolVersions()) == address(_dii.protocolVersionsProxy()), "OPCMI-20"); } @@ -361,7 +322,6 @@ contract DeployImplementationsOutput is BaseDeployIO { function assertValidMipsSingleton(DeployImplementationsInput) internal view { IMIPS mips = mipsSingleton(); - require(address(mips.oracle()) == address(preimageOracleSingleton()), "MIPS-10"); } @@ -480,104 +440,38 @@ contract DeployImplementations is Script { // --- OP Contracts Manager --- - function opcmSystemConfigSetter( - DeployImplementationsInput _dii, - DeployImplementationsOutput _dio - ) - internal - view - virtual - returns (OPContractsManager.ImplementationSetter memory) - { - // When configuring OPCM during Solidity tests, we are using the latest SystemConfig.sol - // version in this repo, which contains Custom Gas Token (CGT) features. This CGT version - // has a different `initialize` signature than the SystemConfig version that was released - // as part of `op-contracts/v1.6.0`, which is no longer in the repo. When running this - // script's bytecode for a production deploy of OPCM at `op-contracts/v1.6.0`, we need to - // use the ISystemConfigV160 interface instead of ISystemConfig. Therefore the selector used - // is a function of the `release` passed in by the caller. - bytes4 selector = LibString.eq(_dii.release(), "op-contracts/v1.6.0") - ? ISystemConfigV160.initialize.selector - : ISystemConfig.initialize.selector; - return OPContractsManager.ImplementationSetter({ - name: "SystemConfig", - info: OPContractsManager.Implementation(address(_dio.systemConfigImpl()), selector) - }); - } - - function l1CrossDomainMessengerConfigSetter( - DeployImplementationsInput _dii, - DeployImplementationsOutput _dio - ) - internal - view - virtual - returns (OPContractsManager.ImplementationSetter memory) - { - bytes4 selector = LibString.eq(_dii.release(), "op-contracts/v1.6.0") - ? IL1CrossDomainMessengerV160.initialize.selector - : IL1CrossDomainMessenger.initialize.selector; - return OPContractsManager.ImplementationSetter({ - name: "L1CrossDomainMessenger", - info: OPContractsManager.Implementation(address(_dio.l1CrossDomainMessengerImpl()), selector) - }); - } - - function l1StandardBridgeConfigSetter( - DeployImplementationsInput _dii, - DeployImplementationsOutput _dio - ) - internal - view - virtual - returns (OPContractsManager.ImplementationSetter memory) - { - bytes4 selector = LibString.eq(_dii.release(), "op-contracts/v1.6.0") - ? IL1StandardBridgeV160.initialize.selector - : IL1StandardBridge.initialize.selector; - return OPContractsManager.ImplementationSetter({ - name: "L1StandardBridge", - info: OPContractsManager.Implementation(address(_dio.l1StandardBridgeImpl()), selector) - }); - } - - // Deploy and initialize a proxied OPContractsManager. function createOPCMContract( DeployImplementationsInput _dii, DeployImplementationsOutput _dio, OPContractsManager.Blueprints memory _blueprints, - string memory _release, - OPContractsManager.ImplementationSetter[] memory _setters + string memory _l1ContractsRelease ) internal virtual - returns (OPContractsManager opcmProxy_) + returns (OPContractsManager opcm_) { - address opcmProxyOwner = _dii.opcmProxyOwner(); - - vm.broadcast(msg.sender); - IProxy proxy = IProxy( - DeployUtils.create1({ - _name: "Proxy", - _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (msg.sender))) - }) - ); - - deployOPContractsManagerImpl(_dii, _dio); - OPContractsManager opcmImpl = _dio.opcmImpl(); + ISuperchainConfig superchainConfigProxy = _dii.superchainConfigProxy(); + IProtocolVersions protocolVersionsProxy = _dii.protocolVersionsProxy(); - OPContractsManager.InitializerInputs memory initializerInputs = - OPContractsManager.InitializerInputs(_blueprints, _setters, _release, true); + OPContractsManager.Implementations memory implementations = OPContractsManager.Implementations({ + l1ERC721BridgeImpl: address(_dio.l1ERC721BridgeImpl()), + optimismPortalImpl: address(_dio.optimismPortalImpl()), + systemConfigImpl: address(_dio.systemConfigImpl()), + optimismMintableERC20FactoryImpl: address(_dio.optimismMintableERC20FactoryImpl()), + l1CrossDomainMessengerImpl: address(_dio.l1CrossDomainMessengerImpl()), + l1StandardBridgeImpl: address(_dio.l1StandardBridgeImpl()), + disputeGameFactoryImpl: address(_dio.disputeGameFactoryImpl()), + delayedWETHImpl: address(_dio.delayedWETHImpl()), + mipsImpl: address(_dio.mipsSingleton()) + }); - vm.startBroadcast(msg.sender); - proxy.upgradeToAndCall( - address(opcmImpl), abi.encodeWithSelector(opcmImpl.initialize.selector, initializerInputs) + vm.broadcast(msg.sender); + opcm_ = new OPContractsManager( + superchainConfigProxy, protocolVersionsProxy, _l1ContractsRelease, _blueprints, implementations ); - proxy.changeAdmin(address(opcmProxyOwner)); // transfer ownership of Proxy contract to the ProxyAdmin contract - vm.stopBroadcast(); - - opcmProxy_ = OPContractsManager(address(proxy)); + vm.label(address(opcm_), "OPContractsManager"); + _dio.set(_dio.opcm.selector, address(opcm_)); } function deployOPContractsManager( @@ -587,72 +481,42 @@ contract DeployImplementations is Script { public virtual { - string memory release = _dii.release(); - - // First we deploy the blueprints for the singletons deployed by OPCM. - // forgefmt: disable-start - bytes32 salt = _dii.salt(); - OPContractsManager.Blueprints memory blueprints; - - vm.startBroadcast(msg.sender); - blueprints.addressManager = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("AddressManager")), salt); - blueprints.proxy = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("Proxy")), salt); - blueprints.proxyAdmin = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("ProxyAdmin")), salt); - blueprints.l1ChugSplashProxy = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("L1ChugSplashProxy")), salt); - blueprints.resolvedDelegateProxy = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("ResolvedDelegateProxy")), salt); - blueprints.anchorStateRegistry = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("AnchorStateRegistry")), salt); - (blueprints.permissionedDisputeGame1, blueprints.permissionedDisputeGame2) = deployBigBytecode(vm.getCode("PermissionedDisputeGame"), salt); - vm.stopBroadcast(); - // forgefmt: disable-end - - OPContractsManager.ImplementationSetter[] memory setters = new OPContractsManager.ImplementationSetter[](9); - setters[0] = OPContractsManager.ImplementationSetter({ - name: "L1ERC721Bridge", - info: OPContractsManager.Implementation(address(_dio.l1ERC721BridgeImpl()), IL1ERC721Bridge.initialize.selector) - }); - setters[1] = OPContractsManager.ImplementationSetter({ - name: "OptimismPortal", - info: OPContractsManager.Implementation( - address(_dio.optimismPortalImpl()), IOptimismPortal2.initialize.selector - ) - }); - setters[2] = opcmSystemConfigSetter(_dii, _dio); - setters[3] = OPContractsManager.ImplementationSetter({ - name: "OptimismMintableERC20Factory", - info: OPContractsManager.Implementation( - address(_dio.optimismMintableERC20FactoryImpl()), IOptimismMintableERC20Factory.initialize.selector - ) - }); - setters[4] = l1CrossDomainMessengerConfigSetter(_dii, _dio); - setters[5] = l1StandardBridgeConfigSetter(_dii, _dio); - setters[6] = OPContractsManager.ImplementationSetter({ - name: "DisputeGameFactory", - info: OPContractsManager.Implementation( - address(_dio.disputeGameFactoryImpl()), IDisputeGameFactory.initialize.selector - ) - }); - setters[7] = OPContractsManager.ImplementationSetter({ - name: "DelayedWETH", - info: OPContractsManager.Implementation(address(_dio.delayedWETHImpl()), IDelayedWETH.initialize.selector) - }); - setters[8] = OPContractsManager.ImplementationSetter({ - name: "MIPS", - // MIPS is a singleton for all chains, so it doesn't need to be initialized, so the - // selector is just `bytes4(0)`. - info: OPContractsManager.Implementation(address(_dio.mipsSingleton()), bytes4(0)) - }); + string memory l1ContractsRelease = _dii.l1ContractsRelease(); + string memory stdVerToml = _dii.standardVersionsToml(); + string memory contractName = "op_contracts_manager"; + OPContractsManager opcm; - // This call contains a broadcast to deploy OPCM which is proxied. - OPContractsManager opcmProxy = createOPCMContract(_dii, _dio, blueprints, release, setters); + address existingImplementation = getReleaseAddress(l1ContractsRelease, contractName, stdVerToml); + if (existingImplementation != address(0)) { + opcm = OPContractsManager(existingImplementation); + } else { + // First we deploy the blueprints for the singletons deployed by OPCM. + // forgefmt: disable-start + bytes32 salt = _dii.salt(); + OPContractsManager.Blueprints memory blueprints; + + vm.startBroadcast(msg.sender); + blueprints.addressManager = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("AddressManager")), salt); + blueprints.proxy = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("Proxy")), salt); + blueprints.proxyAdmin = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("ProxyAdmin")), salt); + blueprints.l1ChugSplashProxy = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("L1ChugSplashProxy")), salt); + blueprints.resolvedDelegateProxy = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("ResolvedDelegateProxy")), salt); + blueprints.anchorStateRegistry = deployBytecode(Blueprint.blueprintDeployerBytecode(vm.getCode("AnchorStateRegistry")), salt); + (blueprints.permissionedDisputeGame1, blueprints.permissionedDisputeGame2) = deployBigBytecode(vm.getCode("PermissionedDisputeGame"), salt); + vm.stopBroadcast(); + // forgefmt: disable-end + + opcm = createOPCMContract(_dii, _dio, blueprints, l1ContractsRelease); + } - vm.label(address(opcmProxy), "OPContractsManager"); - _dio.set(_dio.opcmProxy.selector, address(opcmProxy)); + vm.label(address(opcm), "OPContractsManager"); + _dio.set(_dio.opcm.selector, address(opcm)); } // --- Core Contracts --- function deploySystemConfigImpl(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual { - string memory release = _dii.release(); + string memory release = _dii.l1ContractsRelease(); string memory stdVerToml = _dii.standardVersionsToml(); // Using snake case for contract name to match the TOML file in superchain-registry. string memory contractName = "system_config"; @@ -661,7 +525,7 @@ contract DeployImplementations is Script { address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); if (existingImplementation != address(0)) { impl = ISystemConfig(existingImplementation); - } else if (isDevelopRelease(release)) { + } else { // Deploy a new implementation for development builds. vm.broadcast(msg.sender); impl = ISystemConfig( @@ -670,8 +534,6 @@ contract DeployImplementations is Script { _args: DeployUtils.encodeConstructor(abi.encodeCall(ISystemConfig.__constructor__, ())) }) ); - } else { - revert(string.concat("DeployImplementations: failed to deploy release ", release)); } vm.label(address(impl), "SystemConfigImpl"); @@ -685,7 +547,7 @@ contract DeployImplementations is Script { public virtual { - string memory release = _dii.release(); + string memory release = _dii.l1ContractsRelease(); string memory stdVerToml = _dii.standardVersionsToml(); string memory contractName = "l1_cross_domain_messenger"; IL1CrossDomainMessenger impl; @@ -693,7 +555,7 @@ contract DeployImplementations is Script { address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); if (existingImplementation != address(0)) { impl = IL1CrossDomainMessenger(existingImplementation); - } else if (isDevelopRelease(release)) { + } else { vm.broadcast(msg.sender); impl = IL1CrossDomainMessenger( DeployUtils.create1({ @@ -701,8 +563,6 @@ contract DeployImplementations is Script { _args: DeployUtils.encodeConstructor(abi.encodeCall(IL1CrossDomainMessenger.__constructor__, ())) }) ); - } else { - revert(string.concat("DeployImplementations: failed to deploy release ", release)); } vm.label(address(impl), "L1CrossDomainMessengerImpl"); @@ -716,7 +576,7 @@ contract DeployImplementations is Script { public virtual { - string memory release = _dii.release(); + string memory release = _dii.l1ContractsRelease(); string memory stdVerToml = _dii.standardVersionsToml(); string memory contractName = "l1_erc721_bridge"; IL1ERC721Bridge impl; @@ -724,7 +584,7 @@ contract DeployImplementations is Script { address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); if (existingImplementation != address(0)) { impl = IL1ERC721Bridge(existingImplementation); - } else if (isDevelopRelease(release)) { + } else { vm.broadcast(msg.sender); impl = IL1ERC721Bridge( DeployUtils.create1({ @@ -732,8 +592,6 @@ contract DeployImplementations is Script { _args: DeployUtils.encodeConstructor(abi.encodeCall(IL1ERC721Bridge.__constructor__, ())) }) ); - } else { - revert(string.concat("DeployImplementations: failed to deploy release ", release)); } vm.label(address(impl), "L1ERC721BridgeImpl"); @@ -747,7 +605,7 @@ contract DeployImplementations is Script { public virtual { - string memory release = _dii.release(); + string memory release = _dii.l1ContractsRelease(); string memory stdVerToml = _dii.standardVersionsToml(); string memory contractName = "l1_standard_bridge"; IL1StandardBridge impl; @@ -755,7 +613,7 @@ contract DeployImplementations is Script { address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); if (existingImplementation != address(0)) { impl = IL1StandardBridge(payable(existingImplementation)); - } else if (isDevelopRelease(release)) { + } else { vm.broadcast(msg.sender); impl = IL1StandardBridge( DeployUtils.create1({ @@ -763,8 +621,6 @@ contract DeployImplementations is Script { _args: DeployUtils.encodeConstructor(abi.encodeCall(IL1StandardBridge.__constructor__, ())) }) ); - } else { - revert(string.concat("DeployImplementations: failed to deploy release ", release)); } vm.label(address(impl), "L1StandardBridgeImpl"); @@ -778,7 +634,7 @@ contract DeployImplementations is Script { public virtual { - string memory release = _dii.release(); + string memory release = _dii.l1ContractsRelease(); string memory stdVerToml = _dii.standardVersionsToml(); string memory contractName = "optimism_mintable_erc20_factory"; IOptimismMintableERC20Factory impl; @@ -786,7 +642,7 @@ contract DeployImplementations is Script { address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); if (existingImplementation != address(0)) { impl = IOptimismMintableERC20Factory(existingImplementation); - } else if (isDevelopRelease(release)) { + } else { vm.broadcast(msg.sender); impl = IOptimismMintableERC20Factory( DeployUtils.create1({ @@ -794,32 +650,12 @@ contract DeployImplementations is Script { _args: DeployUtils.encodeConstructor(abi.encodeCall(IOptimismMintableERC20Factory.__constructor__, ())) }) ); - } else { - revert(string.concat("DeployImplementations: failed to deploy release ", release)); } vm.label(address(impl), "OptimismMintableERC20FactoryImpl"); _dio.set(_dio.optimismMintableERC20FactoryImpl.selector, address(impl)); } - function deployOPContractsManagerImpl( - DeployImplementationsInput _dii, - DeployImplementationsOutput _dio - ) - public - virtual - { - ISuperchainConfig superchainConfigProxy = _dii.superchainConfigProxy(); - IProtocolVersions protocolVersionsProxy = _dii.protocolVersionsProxy(); - - vm.broadcast(msg.sender); - // TODO: Eventually we will want to select the correct implementation based on the release. - OPContractsManager impl = new OPContractsManager(superchainConfigProxy, protocolVersionsProxy); - - vm.label(address(impl), "OPContractsManagerImpl"); - _dio.set(_dio.opcmImpl.selector, address(impl)); - } - // --- Fault Proofs Contracts --- // The fault proofs contracts are configured as follows: @@ -864,7 +700,7 @@ contract DeployImplementations is Script { public virtual { - string memory release = _dii.release(); + string memory release = _dii.l1ContractsRelease(); string memory stdVerToml = _dii.standardVersionsToml(); string memory contractName = "optimism_portal"; IOptimismPortal2 impl; @@ -872,7 +708,7 @@ contract DeployImplementations is Script { address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); if (existingImplementation != address(0)) { impl = IOptimismPortal2(payable(existingImplementation)); - } else if (isDevelopRelease(release)) { + } else { uint256 proofMaturityDelaySeconds = _dii.proofMaturityDelaySeconds(); uint256 disputeGameFinalityDelaySeconds = _dii.disputeGameFinalityDelaySeconds(); vm.broadcast(msg.sender); @@ -886,8 +722,6 @@ contract DeployImplementations is Script { ) }) ); - } else { - revert(string.concat("DeployImplementations: failed to deploy release ", release)); } vm.label(address(impl), "OptimismPortalImpl"); @@ -895,7 +729,7 @@ contract DeployImplementations is Script { } function deployDelayedWETHImpl(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual { - string memory release = _dii.release(); + string memory release = _dii.l1ContractsRelease(); string memory stdVerToml = _dii.standardVersionsToml(); string memory contractName = "delayed_weth"; IDelayedWETH impl; @@ -903,7 +737,7 @@ contract DeployImplementations is Script { address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); if (existingImplementation != address(0)) { impl = IDelayedWETH(payable(existingImplementation)); - } else if (isDevelopRelease(release)) { + } else { uint256 withdrawalDelaySeconds = _dii.withdrawalDelaySeconds(); vm.broadcast(msg.sender); impl = IDelayedWETH( @@ -914,8 +748,6 @@ contract DeployImplementations is Script { ) }) ); - } else { - revert(string.concat("DeployImplementations: failed to deploy release ", release)); } vm.label(address(impl), "DelayedWETHImpl"); @@ -929,7 +761,7 @@ contract DeployImplementations is Script { public virtual { - string memory release = _dii.release(); + string memory release = _dii.l1ContractsRelease(); string memory stdVerToml = _dii.standardVersionsToml(); string memory contractName = "preimage_oracle"; IPreimageOracle singleton; @@ -937,7 +769,7 @@ contract DeployImplementations is Script { address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); if (existingImplementation != address(0)) { singleton = IPreimageOracle(payable(existingImplementation)); - } else if (isDevelopRelease(release)) { + } else { uint256 minProposalSizeBytes = _dii.minProposalSizeBytes(); uint256 challengePeriodSeconds = _dii.challengePeriodSeconds(); vm.broadcast(msg.sender); @@ -949,8 +781,6 @@ contract DeployImplementations is Script { ) }) ); - } else { - revert(string.concat("DeployImplementations: failed to deploy release ", release)); } vm.label(address(singleton), "PreimageOracleSingleton"); @@ -958,7 +788,7 @@ contract DeployImplementations is Script { } function deployMipsSingleton(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual { - string memory release = _dii.release(); + string memory release = _dii.l1ContractsRelease(); string memory stdVerToml = _dii.standardVersionsToml(); string memory contractName = "mips"; IMIPS singleton; @@ -966,18 +796,16 @@ contract DeployImplementations is Script { address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); if (existingImplementation != address(0)) { singleton = IMIPS(payable(existingImplementation)); - } else if (isDevelopRelease(release)) { + } else { uint256 mipsVersion = _dii.mipsVersion(); IPreimageOracle preimageOracle = IPreimageOracle(address(_dio.preimageOracleSingleton())); vm.broadcast(msg.sender); singleton = IMIPS( DeployUtils.create1({ - _name: mipsVersion == 1 ? "MIPS" : "MIPS2", + _name: mipsVersion == 1 ? "MIPS" : "MIPS64", _args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (preimageOracle))) }) ); - } else { - revert(string.concat("DeployImplementations: failed to deploy release ", release)); } vm.label(address(singleton), "MIPSSingleton"); @@ -991,7 +819,7 @@ contract DeployImplementations is Script { public virtual { - string memory release = _dii.release(); + string memory release = _dii.l1ContractsRelease(); string memory stdVerToml = _dii.standardVersionsToml(); string memory contractName = "dispute_game_factory"; IDisputeGameFactory impl; @@ -999,7 +827,7 @@ contract DeployImplementations is Script { address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); if (existingImplementation != address(0)) { impl = IDisputeGameFactory(payable(existingImplementation)); - } else if (isDevelopRelease(release)) { + } else { vm.broadcast(msg.sender); impl = IDisputeGameFactory( DeployUtils.create1({ @@ -1007,8 +835,6 @@ contract DeployImplementations is Script { _args: DeployUtils.encodeConstructor(abi.encodeCall(IDisputeGameFactory.__constructor__, ())) }) ); - } else { - revert(string.concat("DeployImplementations: failed to deploy release ", release)); } vm.label(address(impl), "DisputeGameFactoryImpl"); @@ -1078,11 +904,6 @@ contract DeployImplementations is Script { } } } - - // A release is considered a 'develop' release if it does not start with 'op-contracts'. - function isDevelopRelease(string memory _release) internal pure returns (bool) { - return !LibString.startsWith(_release, "op-contracts"); - } } // Similar to how DeploySuperchain.s.sol contains a lot of comments to thoroughly document the script @@ -1122,38 +943,35 @@ contract DeployImplementationsInterop is DeployImplementations { DeployImplementationsInput _dii, DeployImplementationsOutput _dio, OPContractsManager.Blueprints memory _blueprints, - string memory _release, - OPContractsManager.ImplementationSetter[] memory _setters + string memory _l1ContractsRelease ) internal + virtual override - returns (OPContractsManager opcmProxy_) + returns (OPContractsManager opcm_) { - address opcmProxyOwner = _dii.opcmProxyOwner(); - - vm.broadcast(msg.sender); - IProxy proxy = IProxy( - DeployUtils.create1({ - _name: "Proxy", - _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (msg.sender))) - }) - ); - - deployOPContractsManagerImpl(_dii, _dio); // overriding function - OPContractsManager opcmImpl = _dio.opcmImpl(); + ISuperchainConfig superchainConfigProxy = _dii.superchainConfigProxy(); + IProtocolVersions protocolVersionsProxy = _dii.protocolVersionsProxy(); - OPContractsManager.InitializerInputs memory initializerInputs = - OPContractsManager.InitializerInputs(_blueprints, _setters, _release, true); + OPContractsManager.Implementations memory implementations = OPContractsManager.Implementations({ + l1ERC721BridgeImpl: address(_dio.l1ERC721BridgeImpl()), + optimismPortalImpl: address(_dio.optimismPortalImpl()), + systemConfigImpl: address(_dio.systemConfigImpl()), + optimismMintableERC20FactoryImpl: address(_dio.optimismMintableERC20FactoryImpl()), + l1CrossDomainMessengerImpl: address(_dio.l1CrossDomainMessengerImpl()), + l1StandardBridgeImpl: address(_dio.l1StandardBridgeImpl()), + disputeGameFactoryImpl: address(_dio.disputeGameFactoryImpl()), + delayedWETHImpl: address(_dio.delayedWETHImpl()), + mipsImpl: address(_dio.mipsSingleton()) + }); - vm.startBroadcast(msg.sender); - proxy.upgradeToAndCall( - address(opcmImpl), abi.encodeWithSelector(opcmImpl.initialize.selector, initializerInputs) + vm.broadcast(msg.sender); + opcm_ = new OPContractsManagerInterop( + superchainConfigProxy, protocolVersionsProxy, _l1ContractsRelease, _blueprints, implementations ); - proxy.changeAdmin(opcmProxyOwner); // transfer ownership of Proxy contract to the ProxyAdmin contract - vm.stopBroadcast(); - - opcmProxy_ = OPContractsManagerInterop(address(proxy)); + vm.label(address(opcm_), "OPContractsManager"); + _dio.set(_dio.opcm.selector, address(opcm_)); } function deployOptimismPortalImpl( @@ -1163,7 +981,7 @@ contract DeployImplementationsInterop is DeployImplementations { public override { - string memory release = _dii.release(); + string memory release = _dii.l1ContractsRelease(); string memory stdVerToml = _dii.standardVersionsToml(); string memory contractName = "optimism_portal"; IOptimismPortalInterop impl; @@ -1171,7 +989,7 @@ contract DeployImplementationsInterop is DeployImplementations { address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); if (existingImplementation != address(0)) { impl = IOptimismPortalInterop(payable(existingImplementation)); - } else if (isDevelopRelease(release)) { + } else { uint256 proofMaturityDelaySeconds = _dii.proofMaturityDelaySeconds(); uint256 disputeGameFinalityDelaySeconds = _dii.disputeGameFinalityDelaySeconds(); vm.broadcast(msg.sender); @@ -1186,8 +1004,6 @@ contract DeployImplementationsInterop is DeployImplementations { ) }) ); - } else { - revert(string.concat("DeployImplementations: failed to deploy release ", release)); } vm.label(address(impl), "OptimismPortalImpl"); @@ -1201,7 +1017,7 @@ contract DeployImplementationsInterop is DeployImplementations { public override { - string memory release = _dii.release(); + string memory release = _dii.l1ContractsRelease(); string memory stdVerToml = _dii.standardVersionsToml(); string memory contractName = "system_config"; @@ -1210,7 +1026,7 @@ contract DeployImplementationsInterop is DeployImplementations { address existingImplementation = getReleaseAddress(release, contractName, stdVerToml); if (existingImplementation != address(0)) { impl = ISystemConfigInterop(existingImplementation); - } else if (isDevelopRelease(release)) { + } else { vm.broadcast(msg.sender); impl = ISystemConfigInterop( DeployUtils.create1({ @@ -1218,46 +1034,9 @@ contract DeployImplementationsInterop is DeployImplementations { _args: DeployUtils.encodeConstructor(abi.encodeCall(ISystemConfigInterop.__constructor__, ())) }) ); - } else { - revert(string.concat("DeployImplementations: failed to deploy release ", release)); } vm.label(address(impl), "SystemConfigImpl"); _dio.set(_dio.systemConfigImpl.selector, address(impl)); } - - function deployOPContractsManagerImpl( - DeployImplementationsInput _dii, - DeployImplementationsOutput _dio - ) - public - override - { - ISuperchainConfig superchainConfigProxy = _dii.superchainConfigProxy(); - IProtocolVersions protocolVersionsProxy = _dii.protocolVersionsProxy(); - - vm.broadcast(msg.sender); - // TODO: Eventually we will want to select the correct implementation based on the release. - OPContractsManager impl = new OPContractsManagerInterop(superchainConfigProxy, protocolVersionsProxy); - - vm.label(address(impl), "OPContractsManagerImpl"); - _dio.set(_dio.opcmImpl.selector, address(impl)); - } - - function opcmSystemConfigSetter( - DeployImplementationsInput, - DeployImplementationsOutput _dio - ) - internal - view - override - returns (OPContractsManager.ImplementationSetter memory) - { - return OPContractsManager.ImplementationSetter({ - name: "SystemConfig", - info: OPContractsManager.Implementation( - address(_dio.systemConfigImpl()), ISystemConfigInterop.initialize.selector - ) - }); - } } diff --git a/packages/contracts-bedrock/scripts/deploy/DeployMIPS.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployMIPS.s.sol new file mode 100644 index 0000000000000..09ef6d059cd0f --- /dev/null +++ b/packages/contracts-bedrock/scripts/deploy/DeployMIPS.s.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +// Forge +import { Script } from "forge-std/Script.sol"; + +// Scripts +import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; + +// Interfaces +import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol"; +import { IMIPS } from "src/cannon/interfaces/IMIPS.sol"; + +/// @title DeployMIPSInput +contract DeployMIPSInput is BaseDeployIO { + // Specify the PreimageOracle to use + address internal _preimageOracle; + + // Specify which MIPS version to use. + uint256 internal _mipsVersion; + + function set(bytes4 _sel, uint256 _value) public { + if (_sel == this.mipsVersion.selector) { + require(_value == 1 || _value == 2, "DeployMIPS: unknown mips version"); + _mipsVersion = _value; + } else { + revert("DeployMIPS: unknown selector"); + } + } + + function set(bytes4 _sel, address _value) public { + if (_sel == this.preimageOracle.selector) { + require(_value != address(0), "DeployMIPS: preimageOracle cannot be empty"); + _preimageOracle = _value; + } else { + revert("DeployMIPS: unknown selector"); + } + } + + function mipsVersion() public view returns (uint256) { + require(_mipsVersion != 0, "DeployMIPS: mipsVersion not set"); + require(_mipsVersion == 1 || _mipsVersion == 2, "DeployMIPS: unknown mips version"); + return _mipsVersion; + } + + function preimageOracle() public view returns (address) { + require(_preimageOracle != address(0), "DeployMIPS: preimageOracle not set"); + return _preimageOracle; + } +} + +/// @title DeployMIPSOutput +contract DeployMIPSOutput is BaseDeployIO { + IMIPS internal _mipsSingleton; + + function set(bytes4 _sel, address _value) public { + if (_sel == this.mipsSingleton.selector) { + require(_value != address(0), "DeployMIPS: mipsSingleton cannot be zero address"); + _mipsSingleton = IMIPS(_value); + } else { + revert("DeployMIPS: unknown selector"); + } + } + + function checkOutput(DeployMIPSInput _mi) public view { + DeployUtils.assertValidContractAddress(address(_mipsSingleton)); + assertValidDeploy(_mi); + } + + function mipsSingleton() public view returns (IMIPS) { + DeployUtils.assertValidContractAddress(address(_mipsSingleton)); + return _mipsSingleton; + } + + function assertValidDeploy(DeployMIPSInput _mi) public view { + assertValidMipsSingleton(_mi); + } + + function assertValidMipsSingleton(DeployMIPSInput _mi) internal view { + IMIPS mips = mipsSingleton(); + + require(address(mips.oracle()) == address(_mi.preimageOracle()), "MIPS-10"); + } +} + +/// @title DeployMIPS +contract DeployMIPS is Script { + function run(DeployMIPSInput _mi, DeployMIPSOutput _mo) public { + deployMipsSingleton(_mi, _mo); + _mo.checkOutput(_mi); + } + + function deployMipsSingleton(DeployMIPSInput _mi, DeployMIPSOutput _mo) internal { + IMIPS singleton; + uint256 mipsVersion = _mi.mipsVersion(); + IPreimageOracle preimageOracle = IPreimageOracle(_mi.preimageOracle()); + vm.broadcast(msg.sender); + singleton = IMIPS( + DeployUtils.create1({ + _name: mipsVersion == 1 ? "MIPS" : "MIPS64", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (preimageOracle))) + }) + ); + + vm.label(address(singleton), "MIPSSingleton"); + _mo.set(_mo.mipsSingleton.selector, address(singleton)); + } +} diff --git a/packages/contracts-bedrock/scripts/DeployOPChain.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol similarity index 96% rename from packages/contracts-bedrock/scripts/DeployOPChain.s.sol rename to packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol index a48d46348f7ea..a83dfb110625a 100644 --- a/packages/contracts-bedrock/scripts/DeployOPChain.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol @@ -7,7 +7,7 @@ import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { Solarray } from "scripts/libraries/Solarray.sol"; -import { BaseDeployIO } from "scripts/utils/BaseDeployIO.sol"; +import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; @@ -47,7 +47,7 @@ contract DeployOPChainInput is BaseDeployIO { uint32 internal _basefeeScalar; uint32 internal _blobBaseFeeScalar; uint256 internal _l2ChainId; - OPContractsManager internal _opcmProxy; + OPContractsManager internal _opcm; string internal _saltMixer; uint64 internal _gasLimit; @@ -58,6 +58,7 @@ contract DeployOPChainInput is BaseDeployIO { uint256 internal _disputeSplitDepth; Duration internal _disputeClockExtension; Duration internal _disputeMaxClockDuration; + bool internal _allowCustomDisputeParameters; function set(bytes4 _sel, address _addr) public { require(_addr != address(0), "DeployOPChainInput: cannot set zero address"); @@ -67,7 +68,7 @@ contract DeployOPChainInput is BaseDeployIO { else if (_sel == this.unsafeBlockSigner.selector) _unsafeBlockSigner = _addr; else if (_sel == this.proposer.selector) _proposer = _addr; else if (_sel == this.challenger.selector) _challenger = _addr; - else if (_sel == this.opcmProxy.selector) _opcmProxy = OPContractsManager(_addr); + else if (_sel == this.opcm.selector) _opcm = OPContractsManager(_addr); else revert("DeployOPChainInput: unknown selector"); } @@ -107,6 +108,11 @@ contract DeployOPChainInput is BaseDeployIO { else revert("DeployImplementationsInput: unknown selector"); } + function set(bytes4 _sel, bool _value) public { + if (_sel == this.allowCustomDisputeParameters.selector) _allowCustomDisputeParameters = _value; + else revert("DeployOPChainInput: unknown selector"); + } + function opChainProxyAdminOwner() public view returns (address) { require(_opChainProxyAdminOwner != address(0), "DeployOPChainInput: not set"); return _opChainProxyAdminOwner; @@ -168,11 +174,10 @@ contract DeployOPChainInput is BaseDeployIO { return abi.encode(ScriptConstants.DEFAULT_STARTING_ANCHOR_ROOTS()); } - function opcmProxy() public returns (OPContractsManager) { - require(address(_opcmProxy) != address(0), "DeployOPChainInput: not set"); - DeployUtils.assertValidContractAddress(address(_opcmProxy)); - DeployUtils.assertERC1967ImplementationSet(address(_opcmProxy)); - return _opcmProxy; + function opcm() public view returns (OPContractsManager) { + require(address(_opcm) != address(0), "DeployOPChainInput: not set"); + DeployUtils.assertValidContractAddress(address(_opcm)); + return _opcm; } function saltMixer() public view returns (string memory) { @@ -206,6 +211,10 @@ contract DeployOPChainInput is BaseDeployIO { function disputeMaxClockDuration() public view returns (Duration) { return _disputeMaxClockDuration; } + + function allowCustomDisputeParameters() public view returns (bool) { + return _allowCustomDisputeParameters; + } } contract DeployOPChainOutput is BaseDeployIO { @@ -225,7 +234,7 @@ contract DeployOPChainOutput is BaseDeployIO { IDelayedWETH internal _delayedWETHPermissionedGameProxy; IDelayedWETH internal _delayedWETHPermissionlessGameProxy; - function set(bytes4 _sel, address _addr) public { + function set(bytes4 _sel, address _addr) public virtual { require(_addr != address(0), "DeployOPChainOutput: cannot set zero address"); // forgefmt: disable-start if (_sel == this.opChainProxyAdmin.selector) _opChainProxyAdmin = IProxyAdmin(_addr) ; @@ -337,7 +346,7 @@ contract DeployOPChain is Script { // -------- Core Deployment Methods -------- function run(DeployOPChainInput _doi, DeployOPChainOutput _doo) public { - OPContractsManager opcmProxy = _doi.opcmProxy(); + OPContractsManager opcm = _doi.opcm(); OPContractsManager.Roles memory roles = OPContractsManager.Roles({ opChainProxyAdminOwner: _doi.opChainProxyAdminOwner(), @@ -364,7 +373,7 @@ contract DeployOPChain is Script { }); vm.broadcast(msg.sender); - OPContractsManager.DeployOutput memory deployOutput = opcmProxy.deploy(deployInput); + OPContractsManager.DeployOutput memory deployOutput = opcm.deploy(deployInput); vm.label(address(deployOutput.opChainProxyAdmin), "opChainProxyAdmin"); vm.label(address(deployOutput.addressManager), "addressManager"); @@ -457,6 +466,11 @@ contract DeployOPChain is Script { IPermissionedDisputeGame game = _doo.permissionedDisputeGame(); require(GameType.unwrap(game.gameType()) == GameType.unwrap(GameTypes.PERMISSIONED_CANNON), "DPG-10"); + + if (_doi.allowCustomDisputeParameters()) { + return; + } + // This hex string is the absolutePrestate of the latest op-program release, see where the // `EXPECTED_PRESTATE_HASH` is defined in `config.yml`. require( @@ -465,9 +479,9 @@ contract DeployOPChain is Script { "DPG-20" ); - OPContractsManager opcm = _doi.opcmProxy(); - (address mips,) = opcm.implementations(opcm.latestRelease(), "MIPS"); - require(game.vm() == IBigStepper(mips), "DPG-30"); + OPContractsManager opcm = _doi.opcm(); + address mipsImpl = opcm.implementations().mipsImpl; + require(game.vm() == IBigStepper(mipsImpl), "DPG-30"); require(address(game.weth()) == address(_doo.delayedWETHPermissionedGameProxy()), "DPG-40"); require(address(game.anchorStateRegistry()) == address(_doo.anchorStateRegistryProxy()), "DPG-50"); @@ -537,9 +551,7 @@ contract DeployOPChain is Script { require(outputConfig.maximumBaseFee == rConfig.maximumBaseFee, "SYSCON-130"); require(systemConfig.startBlock() == block.number, "SYSCON-140"); - require( - systemConfig.batchInbox() == _doi.opcmProxy().chainIdToBatchInboxAddress(_doi.l2ChainId()), "SYSCON-150" - ); + require(systemConfig.batchInbox() == _doi.opcm().chainIdToBatchInboxAddress(_doi.l2ChainId()), "SYSCON-150"); require(systemConfig.l1CrossDomainMessenger() == address(_doo.l1CrossDomainMessengerProxy()), "SYSCON-160"); require(systemConfig.l1ERC721Bridge() == address(_doo.l1ERC721BridgeProxy()), "SYSCON-170"); @@ -564,7 +576,7 @@ contract DeployOPChain is Script { require(address(messenger.PORTAL()) == address(_doo.optimismPortalProxy()), "L1xDM-30"); require(address(messenger.portal()) == address(_doo.optimismPortalProxy()), "L1xDM-40"); - require(address(messenger.superchainConfig()) == address(_doi.opcmProxy().superchainConfig()), "L1xDM-50"); + require(address(messenger.superchainConfig()) == address(_doi.opcm().superchainConfig()), "L1xDM-50"); bytes32 xdmSenderSlot = vm.load(address(messenger), bytes32(uint256(204))); require(address(uint160(uint256(xdmSenderSlot))) == Constants.DEFAULT_L2_SENDER, "L1xDM-60"); @@ -580,7 +592,7 @@ contract DeployOPChain is Script { require(address(bridge.messenger()) == address(messenger), "L1SB-20"); require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_STANDARD_BRIDGE, "L1SB-30"); require(address(bridge.otherBridge()) == Predeploys.L2_STANDARD_BRIDGE, "L1SB-40"); - require(address(bridge.superchainConfig()) == address(_doi.opcmProxy().superchainConfig()), "L1SB-50"); + require(address(bridge.superchainConfig()) == address(_doi.opcm().superchainConfig()), "L1SB-50"); } function assertValidOptimismMintableERC20Factory(DeployOPChainInput, DeployOPChainOutput _doo) internal { @@ -602,12 +614,12 @@ contract DeployOPChain is Script { require(address(bridge.MESSENGER()) == address(_doo.l1CrossDomainMessengerProxy()), "L721B-30"); require(address(bridge.messenger()) == address(_doo.l1CrossDomainMessengerProxy()), "L721B-40"); - require(address(bridge.superchainConfig()) == address(_doi.opcmProxy().superchainConfig()), "L721B-50"); + require(address(bridge.superchainConfig()) == address(_doi.opcm().superchainConfig()), "L721B-50"); } function assertValidOptimismPortal(DeployOPChainInput _doi, DeployOPChainOutput _doo) internal { IOptimismPortal2 portal = _doo.optimismPortalProxy(); - ISuperchainConfig superchainConfig = ISuperchainConfig(address(_doi.opcmProxy().superchainConfig())); + ISuperchainConfig superchainConfig = ISuperchainConfig(address(_doi.opcm().superchainConfig())); require(address(portal.disputeGameFactory()) == address(_doo.disputeGameFactoryProxy()), "PORTAL-10"); require(address(portal.systemConfig()) == address(_doo.systemConfigProxy()), "PORTAL-20"); diff --git a/packages/contracts-bedrock/scripts/DeploySuperchain.s.sol b/packages/contracts-bedrock/scripts/deploy/DeploySuperchain.s.sol similarity index 99% rename from packages/contracts-bedrock/scripts/DeploySuperchain.s.sol rename to packages/contracts-bedrock/scripts/deploy/DeploySuperchain.s.sol index 38c87f6234434..5e35e8848c8a7 100644 --- a/packages/contracts-bedrock/scripts/DeploySuperchain.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeploySuperchain.s.sol @@ -11,7 +11,7 @@ import { IProxy } from "src/universal/interfaces/IProxy.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { Solarray } from "scripts/libraries/Solarray.sol"; -import { BaseDeployIO } from "scripts/utils/BaseDeployIO.sol"; +import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; // This comment block defines the requirements and rationale for the architecture used in this forge // script, along with other scripts that are being written as new Superchain-first deploy scripts to @@ -60,9 +60,9 @@ import { BaseDeployIO } from "scripts/utils/BaseDeployIO.sol"; // we use variable names that are shorthand for the full contract names, for example: // - `dsi` for DeploySuperchainInput // - `dso` for DeploySuperchainOutput -// - `dio` for DeployImplementationsInput +// - `dii` for DeployImplementationsInput // - `dio` for DeployImplementationsOutput -// - `doo` for DeployOPChainInput +// - `doi` for DeployOPChainInput // - `doo` for DeployOPChainOutput // - etc. diff --git a/packages/contracts-bedrock/scripts/deploy/Deployer.sol b/packages/contracts-bedrock/scripts/deploy/Deployer.sol index 36de8dd440fc1..fa7454f5ee1dc 100644 --- a/packages/contracts-bedrock/scripts/deploy/Deployer.sol +++ b/packages/contracts-bedrock/scripts/deploy/Deployer.sol @@ -5,8 +5,8 @@ import { Script } from "forge-std/Script.sol"; import { Artifacts } from "scripts/Artifacts.s.sol"; import { Config } from "scripts/libraries/Config.sol"; import { DeployConfig } from "scripts/deploy/DeployConfig.s.sol"; -import { Executables } from "scripts/libraries/Executables.sol"; import { console } from "forge-std/console.sol"; +import { Process } from "scripts/libraries/Process.sol"; /// @title Deployer /// @author tynes @@ -19,11 +19,20 @@ abstract contract Deployer is Script, Artifacts { function setUp() public virtual override { Artifacts.setUp(); - console.log("Commit hash: %s", Executables.gitCommitHash()); + console.log("Commit hash: %s", gitCommitHash()); vm.etch(address(cfg), vm.getDeployedCode("DeployConfig.s.sol:DeployConfig")); vm.label(address(cfg), "DeployConfig"); vm.allowCheatcodes(address(cfg)); cfg.read(Config.deployConfigPath()); } + + /// @notice Returns the commit hash of HEAD. If no git repository is + /// found, it will return the contents of the .gitcommit file. Otherwise, + /// it will return an error. The .gitcommit file is used to store the + /// git commit of the contracts when they are packaged into docker images + /// in order to avoid the need to have a git repository in the image. + function gitCommitHash() internal returns (string memory) { + return Process.bash("cast abi-encode 'f(string)' $(git rev-parse HEAD || cat .gitcommit)"); + } } diff --git a/packages/contracts-bedrock/scripts/deploy/ReadImplementationAddresses.s.sol b/packages/contracts-bedrock/scripts/deploy/ReadImplementationAddresses.s.sol new file mode 100644 index 0000000000000..35aefbed16d58 --- /dev/null +++ b/packages/contracts-bedrock/scripts/deploy/ReadImplementationAddresses.s.sol @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; +import { IProxy } from "src/universal/interfaces/IProxy.sol"; +import { Script } from "forge-std/Script.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; +import { DeployOPChainOutput } from "scripts/deploy/DeployOPChain.s.sol"; +import { IMIPS } from "src/cannon/interfaces/IMIPS.sol"; +import { OPContractsManager } from "src/L1/OPContractsManager.sol"; +import { IAddressManager } from "src/legacy/interfaces/IAddressManager.sol"; +import { IStaticL1ChugSplashProxy } from "src/legacy/interfaces/IL1ChugSplashProxy.sol"; + +contract ReadImplementationAddressesInput is DeployOPChainOutput { + OPContractsManager internal _opcm; + + function set(bytes4 _sel, address _addr) public override { + require(_addr != address(0), "ReadImplementationAddressesInput: cannot set zero address"); + if (_sel == this.opcm.selector) _opcm = OPContractsManager(_addr); + else if (_sel == this.addressManager.selector) _addressManager = IAddressManager(_addr); + else super.set(_sel, _addr); + } + + function opcm() public view returns (OPContractsManager) { + DeployUtils.assertValidContractAddress(address(_opcm)); + return _opcm; + } +} + +contract ReadImplementationAddressesOutput is BaseDeployIO { + address internal _delayedWETH; + address internal _optimismPortal; + address internal _systemConfig; + address internal _l1CrossDomainMessenger; + address internal _l1ERC721Bridge; + address internal _l1StandardBridge; + address internal _optimismMintableERC20Factory; + address internal _disputeGameFactory; + address internal _mipsSingleton; + address internal _preimageOracleSingleton; + + function set(bytes4 _sel, address _addr) public { + require(_addr != address(0), "ReadImplementationAddressesOutput: cannot set zero address"); + if (_sel == this.delayedWETH.selector) _delayedWETH = _addr; + else if (_sel == this.optimismPortal.selector) _optimismPortal = _addr; + else if (_sel == this.systemConfig.selector) _systemConfig = _addr; + else if (_sel == this.l1CrossDomainMessenger.selector) _l1CrossDomainMessenger = _addr; + else if (_sel == this.l1ERC721Bridge.selector) _l1ERC721Bridge = _addr; + else if (_sel == this.l1StandardBridge.selector) _l1StandardBridge = _addr; + else if (_sel == this.optimismMintableERC20Factory.selector) _optimismMintableERC20Factory = _addr; + else if (_sel == this.disputeGameFactory.selector) _disputeGameFactory = _addr; + else if (_sel == this.mipsSingleton.selector) _mipsSingleton = _addr; + else if (_sel == this.preimageOracleSingleton.selector) _preimageOracleSingleton = _addr; + else revert("ReadImplementationAddressesOutput: unknown selector"); + } + + function delayedWETH() public view returns (address) { + require(_delayedWETH != address(0), "ReadImplementationAddressesOutput: delayedWETH not set"); + return _delayedWETH; + } + + function optimismPortal() public view returns (address) { + require(_optimismPortal != address(0), "ReadImplementationAddressesOutput: optimismPortal not set"); + return _optimismPortal; + } + + function systemConfig() public view returns (address) { + require(_systemConfig != address(0), "ReadImplementationAddressesOutput: systemConfig not set"); + return _systemConfig; + } + + function l1CrossDomainMessenger() public view returns (address) { + require( + _l1CrossDomainMessenger != address(0), "ReadImplementationAddressesOutput: l1CrossDomainMessenger not set" + ); + return _l1CrossDomainMessenger; + } + + function l1ERC721Bridge() public view returns (address) { + require(_l1ERC721Bridge != address(0), "ReadImplementationAddressesOutput: l1ERC721Bridge not set"); + return _l1ERC721Bridge; + } + + function l1StandardBridge() public view returns (address) { + require(_l1StandardBridge != address(0), "ReadImplementationAddressesOutput: l1StandardBridge not set"); + return _l1StandardBridge; + } + + function optimismMintableERC20Factory() public view returns (address) { + require( + _optimismMintableERC20Factory != address(0), + "ReadImplementationAddressesOutput: optimismMintableERC20Factory not set" + ); + return _optimismMintableERC20Factory; + } + + function disputeGameFactory() public view returns (address) { + require(_disputeGameFactory != address(0), "ReadImplementationAddressesOutput: disputeGameFactory not set"); + return _disputeGameFactory; + } + + function mipsSingleton() public view returns (address) { + require(_mipsSingleton != address(0), "ReadImplementationAddressesOutput: mipsSingleton not set"); + return _mipsSingleton; + } + + function preimageOracleSingleton() public view returns (address) { + require( + _preimageOracleSingleton != address(0), "ReadImplementationAddressesOutput: preimageOracleSingleton not set" + ); + return _preimageOracleSingleton; + } +} + +contract ReadImplementationAddresses is Script { + function run(ReadImplementationAddressesInput _rii, ReadImplementationAddressesOutput _rio) public { + address[6] memory eip1967Proxies = [ + address(_rii.delayedWETHPermissionedGameProxy()), + address(_rii.optimismPortalProxy()), + address(_rii.systemConfigProxy()), + address(_rii.l1ERC721BridgeProxy()), + address(_rii.optimismMintableERC20FactoryProxy()), + address(_rii.disputeGameFactoryProxy()) + ]; + + bytes4[6] memory sels = [ + _rio.delayedWETH.selector, + _rio.optimismPortal.selector, + _rio.systemConfig.selector, + _rio.l1ERC721Bridge.selector, + _rio.optimismMintableERC20Factory.selector, + _rio.disputeGameFactory.selector + ]; + + for (uint256 i = 0; i < eip1967Proxies.length; i++) { + IProxy proxy = IProxy(payable(eip1967Proxies[i])); + vm.prank(address(0)); + _rio.set(sels[i], proxy.implementation()); + } + + vm.prank(address(0)); + address l1SBImpl = IStaticL1ChugSplashProxy(address(_rii.l1StandardBridgeProxy())).getImplementation(); + vm.prank(address(0)); + _rio.set(_rio.l1StandardBridge.selector, l1SBImpl); + + address mipsLogic = _rii.opcm().implementations().mipsImpl; + _rio.set(_rio.mipsSingleton.selector, mipsLogic); + + address delayedWETH = _rii.opcm().implementations().delayedWETHImpl; + _rio.set(_rio.delayedWETH.selector, delayedWETH); + + IAddressManager am = _rii.addressManager(); + _rio.set(_rio.l1CrossDomainMessenger.selector, am.getAddress("OVM_L1CrossDomainMessenger")); + + address preimageOracle = address(IMIPS(mipsLogic).oracle()); + _rio.set(_rio.preimageOracleSingleton.selector, preimageOracle); + } +} diff --git a/packages/contracts-bedrock/scripts/go-ffi/differential-testing.go b/packages/contracts-bedrock/scripts/go-ffi/differential-testing.go index 5eef7f1389778..e35d2a82c3036 100644 --- a/packages/contracts-bedrock/scripts/go-ffi/differential-testing.go +++ b/packages/contracts-bedrock/scripts/go-ffi/differential-testing.go @@ -17,6 +17,7 @@ import ( "github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb/hashdb" + "github.com/ethereum-optimism/optimism/cannon/mipsevm/arch" "github.com/ethereum-optimism/optimism/cannon/mipsevm/memory" "github.com/ethereum-optimism/optimism/op-chain-ops/crossdomain" "github.com/ethereum-optimism/optimism/op-service/eth" @@ -359,70 +360,73 @@ func DiffTestUtils() { // Print the output fmt.Print(hexutil.Encode(packed[32:])) case "cannonMemoryProof": - // - // Generates a memory proof of `memAddr` for a trie containing memValue and memValue2 + // + // Generates memory proofs of `memAddr0` for a trie containing memValue0 and `memAddr1` for a trie containing memValue1 and memValue2 + // For the cannon stf, this is equivalent to the prestate proofs of the program counter and memory access for instruction execution mem := memory.NewMemory() if len(args) != 3 && len(args) != 5 && len(args) != 7 { panic("Error: cannonMemoryProofWithProof requires 2, 4, or 6 arguments") } - pc, err := strconv.ParseUint(args[1], 10, 32) + memAddr0, err := strconv.ParseUint(args[1], 10, arch.WordSize) checkErr(err, "Error decoding addr") - insn, err := strconv.ParseUint(args[2], 10, 32) - checkErr(err, "Error decoding insn") - mem.SetUint32(uint32(pc), uint32(insn)) + memValue0, err := strconv.ParseUint(args[2], 10, arch.WordSize) + checkErr(err, "Error decoding memValue0") + mem.SetWord(arch.Word(memAddr0), arch.Word(memValue0)) - var insnProof, memProof [896]byte + var proof1 []byte if len(args) >= 5 { - memAddr, err := strconv.ParseUint(args[3], 10, 32) + memAddr, err := strconv.ParseUint(args[3], 10, arch.WordSize) checkErr(err, "Error decoding memAddr") - memValue, err := strconv.ParseUint(args[4], 10, 32) + memValue, err := strconv.ParseUint(args[4], 10, arch.WordSize) checkErr(err, "Error decoding memValue") - mem.SetUint32(uint32(memAddr), uint32(memValue)) - memProof = mem.MerkleProof(uint32(memAddr)) + mem.SetWord(arch.Word(memAddr), arch.Word(memValue)) + proof := mem.MerkleProof(arch.Word(memAddr)) + proof1 = proof[:] } if len(args) == 7 { - memAddr, err := strconv.ParseUint(args[5], 10, 32) + memAddr, err := strconv.ParseUint(args[5], 10, arch.WordSize) checkErr(err, "Error decoding memAddr") - memValue, err := strconv.ParseUint(args[6], 10, 32) + memValue, err := strconv.ParseUint(args[6], 10, arch.WordSize) checkErr(err, "Error decoding memValue") - mem.SetUint32(uint32(memAddr), uint32(memValue)) - memProof = mem.MerkleProof(uint32(memAddr)) + mem.SetWord(arch.Word(memAddr), arch.Word(memValue)) + proof := mem.MerkleProof(arch.Word(memAddr)) + proof1 = proof[:] } - insnProof = mem.MerkleProof(uint32(pc)) + proof0 := mem.MerkleProof(arch.Word(memAddr0)) output := struct { MemRoot common.Hash Proof []byte }{ MemRoot: mem.MerkleRoot(), - Proof: append(insnProof[:], memProof[:]...), + Proof: append(proof0[:], proof1...), } packed, err := cannonMemoryProofArgs.Pack(&output) checkErr(err, "Error encoding output") fmt.Print(hexutil.Encode(packed[32:])) case "cannonMemoryProof2": - // - // Generates a memory proof of memAddr2 for a trie containing memValue + // + // Generates memory proof of `memAddr2` for a trie containing `memValue0` and `memValue1` mem := memory.NewMemory() if len(args) != 6 { panic("Error: cannonMemoryProofWithProof2 requires 5 arguments") } - pc, err := strconv.ParseUint(args[1], 10, 32) + memAddr0, err := strconv.ParseUint(args[1], 10, arch.WordSize) checkErr(err, "Error decoding addr") - insn, err := strconv.ParseUint(args[2], 10, 32) - checkErr(err, "Error decoding insn") - mem.SetUint32(uint32(pc), uint32(insn)) + memValue0, err := strconv.ParseUint(args[2], 10, arch.WordSize) + checkErr(err, "Error decoding memValue0") + mem.SetWord(arch.Word(memAddr0), arch.Word(memValue0)) - var memProof [896]byte - memAddr, err := strconv.ParseUint(args[3], 10, 32) + var memProof [memory.MemProofSize]byte + memAddr, err := strconv.ParseUint(args[3], 10, arch.WordSize) checkErr(err, "Error decoding memAddr") - memValue, err := strconv.ParseUint(args[4], 10, 32) - checkErr(err, "Error decoding memValue") - mem.SetUint32(uint32(memAddr), uint32(memValue)) + memValue1, err := strconv.ParseUint(args[4], 10, arch.WordSize) + checkErr(err, "Error decoding memValue1") + mem.SetWord(arch.Word(memAddr), arch.Word(memValue1)) - memAddr2, err := strconv.ParseUint(args[5], 10, 32) + memAddr2, err := strconv.ParseUint(args[5], 10, arch.WordSize) checkErr(err, "Error decoding memAddr") - memProof = mem.MerkleProof(uint32(memAddr2)) + memProof = mem.MerkleProof(arch.Word(memAddr2)) output := struct { MemRoot common.Hash @@ -435,27 +439,27 @@ func DiffTestUtils() { checkErr(err, "Error encoding output") fmt.Print(hexutil.Encode(packed[32:])) case "cannonMemoryProofWrongLeaf": - // + // mem := memory.NewMemory() if len(args) != 5 { panic("Error: cannonMemoryProofWrongLeaf requires 4 arguments") } - pc, err := strconv.ParseUint(args[1], 10, 32) - checkErr(err, "Error decoding addr") - insn, err := strconv.ParseUint(args[2], 10, 32) - checkErr(err, "Error decoding insn") - mem.SetUint32(uint32(pc), uint32(insn)) - - var insnProof, memProof [896]byte - memAddr, err := strconv.ParseUint(args[3], 10, 32) - checkErr(err, "Error decoding memAddr") - memValue, err := strconv.ParseUint(args[4], 10, 32) - checkErr(err, "Error decoding memValue") - mem.SetUint32(uint32(memAddr), uint32(memValue)) + memAddr0, err := strconv.ParseUint(args[1], 10, arch.WordSize) + checkErr(err, "Error decoding memAddr0") + memValue0, err := strconv.ParseUint(args[2], 10, arch.WordSize) + checkErr(err, "Error decoding memValue0") + mem.SetWord(arch.Word(memAddr0), arch.Word(memValue0)) + + var insnProof, memProof [memory.MemProofSize]byte + memAddr1, err := strconv.ParseUint(args[3], 10, arch.WordSize) + checkErr(err, "Error decoding memAddr1") + memValue1, err := strconv.ParseUint(args[4], 10, arch.WordSize) + checkErr(err, "Error decoding memValue1") + mem.SetWord(arch.Word(memAddr1), arch.Word(memValue1)) // Compute a valid proof for the root, but for the wrong leaves. - memProof = mem.MerkleProof(uint32(memAddr + 32)) - insnProof = mem.MerkleProof(uint32(pc + 32)) + memProof = mem.MerkleProof(arch.Word(memAddr1 + arch.WordSize)) + insnProof = mem.MerkleProof(arch.Word(memAddr0 + arch.WordSize)) output := struct { MemRoot common.Hash diff --git a/packages/contracts-bedrock/scripts/libraries/DeployUtils.sol b/packages/contracts-bedrock/scripts/libraries/DeployUtils.sol index c58c00b5a1800..da9aea12a0ace 100644 --- a/packages/contracts-bedrock/scripts/libraries/DeployUtils.sol +++ b/packages/contracts-bedrock/scripts/libraries/DeployUtils.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity ^0.8.0; // Scripts import { Vm } from "forge-std/Vm.sol"; @@ -263,7 +263,7 @@ library DeployUtils { /// @notice Builds an ERC1967 Proxy with a dummy implementation. /// @param _proxyImplName Name of the implementation contract. - function buildERC1967ProxyWithImpl(string memory _proxyImplName) public returns (IProxy genericProxy_) { + function buildERC1967ProxyWithImpl(string memory _proxyImplName) internal returns (IProxy genericProxy_) { genericProxy_ = IProxy( create1({ _name: "Proxy", @@ -279,7 +279,10 @@ library DeployUtils { /// @notice Builds an L1ChugSplashProxy with a dummy implementation. /// @param _proxyImplName Name of the implementation contract. - function buildL1ChugSplashProxyWithImpl(string memory _proxyImplName) public returns (IL1ChugSplashProxy proxy_) { + function buildL1ChugSplashProxyWithImpl(string memory _proxyImplName) + internal + returns (IL1ChugSplashProxy proxy_) + { proxy_ = IL1ChugSplashProxy( create1({ _name: "L1ChugSplashProxy", @@ -299,7 +302,7 @@ library DeployUtils { IAddressManager _addressManager, string memory _proxyImplName ) - public + internal returns (IResolvedDelegateProxy proxy_) { proxy_ = IResolvedDelegateProxy( @@ -316,7 +319,7 @@ library DeployUtils { } /// @notice Builds an AddressManager contract. - function buildAddressManager() public returns (IAddressManager addressManager_) { + function buildAddressManager() internal returns (IAddressManager addressManager_) { addressManager_ = IAddressManager( create1({ _name: "AddressManager", diff --git a/packages/contracts-bedrock/scripts/libraries/Executables.sol b/packages/contracts-bedrock/scripts/libraries/Executables.sol deleted file mode 100644 index 0dc91e32072db..0000000000000 --- a/packages/contracts-bedrock/scripts/libraries/Executables.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import { Vm } from "forge-std/Vm.sol"; -import { Process } from "scripts/libraries/Process.sol"; - -/// @notice The executables used in ffi commands. These are set here -/// to have a single source of truth in case absolute paths -/// need to be used. -library Executables { - /// @notice Foundry cheatcode VM. - Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); - string internal constant bash = "bash"; - string internal constant jq = "jq"; - string internal constant forge = "forge"; - string internal constant echo = "echo"; - string internal constant sed = "sed"; - string internal constant find = "find"; - string internal constant ls = "ls"; - string internal constant git = "git"; - - /// @notice Returns the commit hash of HEAD. If no git repository is - /// found, it will return the contents of the .gitcommit file. Otherwise, - /// it will return an error. The .gitcommit file is used to store the - /// git commit of the contracts when they are packaged into docker images - /// in order to avoid the need to have a git repository in the image. - function gitCommitHash() internal returns (string memory) { - string[] memory commands = new string[](3); - commands[0] = bash; - commands[1] = "-c"; - commands[2] = "cast abi-encode 'f(string)' $(git rev-parse HEAD || cat .gitcommit)"; - return abi.decode(Process.run(commands), (string)); - } -} diff --git a/packages/contracts-bedrock/scripts/libraries/ForgeArtifacts.sol b/packages/contracts-bedrock/scripts/libraries/ForgeArtifacts.sol index 944206694d78c..dba01345d05e9 100644 --- a/packages/contracts-bedrock/scripts/libraries/ForgeArtifacts.sol +++ b/packages/contracts-bedrock/scripts/libraries/ForgeArtifacts.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.0; import { Vm } from "forge-std/Vm.sol"; import { stdJson } from "forge-std/StdJson.sol"; import { LibString } from "@solady/utils/LibString.sol"; -import { Executables } from "scripts/libraries/Executables.sol"; import { Process } from "scripts/libraries/Process.sol"; /// @notice Contains information about a storage slot. Mirrors the layout of the storage @@ -37,14 +36,7 @@ library ForgeArtifacts { /// @notice Removes the semantic versioning from a contract name. The semver will exist if the contract is compiled /// more than once with different versions of the compiler. function _stripSemver(string memory _name) internal returns (string memory out_) { - string[] memory cmd = new string[](3); - cmd[0] = Executables.bash; - cmd[1] = "-c"; - cmd[2] = string.concat( - Executables.echo, " ", _name, " | ", Executables.sed, " -E 's/[.][0-9]+\\.[0-9]+\\.[0-9]+//g'" - ); - bytes memory res = Process.run(cmd); - out_ = string(res); + out_ = Process.bash(string.concat("echo ", _name, " | sed -E 's/[.][0-9]+\\.[0-9]+\\.[0-9]+//g'")); } /// @notice Builds the fully qualified name of a contract. Assumes that the @@ -56,48 +48,33 @@ library ForgeArtifacts { /// @notice Returns the storage layout for a deployed contract. function getStorageLayout(string memory _name) internal returns (string memory layout_) { - string[] memory cmd = new string[](3); - cmd[0] = Executables.bash; - cmd[1] = "-c"; - cmd[2] = string.concat(Executables.jq, " -r '.storageLayout' < ", _getForgeArtifactPath(_name)); - bytes memory res = Process.run(cmd); - layout_ = string(res); + layout_ = Process.bash(string.concat("jq -r '.storageLayout' < ", _getForgeArtifactPath(_name))); } /// @notice Returns the abi from a the forge artifact function getAbi(string memory _name) internal returns (string memory abi_) { - string[] memory cmd = new string[](3); - cmd[0] = Executables.bash; - cmd[1] = "-c"; - cmd[2] = string.concat(Executables.jq, " -r '.abi' < ", _getForgeArtifactPath(_name)); - bytes memory res = Process.run(cmd); - abi_ = string(res); + abi_ = Process.bash(string.concat("jq -r '.abi' < ", _getForgeArtifactPath(_name))); } /// @notice Returns the methodIdentifiers from the forge artifact function getMethodIdentifiers(string memory _name) internal returns (string[] memory ids_) { - string[] memory cmd = new string[](3); - cmd[0] = Executables.bash; - cmd[1] = "-c"; - cmd[2] = string.concat(Executables.jq, " '.methodIdentifiers // {} | keys ' < ", _getForgeArtifactPath(_name)); - bytes memory res = Process.run(cmd, true); - ids_ = stdJson.readStringArray(string(res), ""); + string memory res = Process.bash({ + _command: string.concat("jq '.methodIdentifiers // {} | keys ' < ", _getForgeArtifactPath(_name)), + _allowEmpty: true + }); + ids_ = stdJson.readStringArray(res, ""); } /// @notice Returns the kind of contract (i.e. library, contract, or interface). /// @param _name The name of the contract to get the kind of. /// @return kind_ The kind of contract ("library", "contract", or "interface"). function getContractKind(string memory _name) internal returns (string memory kind_) { - string[] memory cmd = new string[](3); - cmd[0] = Executables.bash; - cmd[1] = "-c"; - cmd[2] = string.concat( - Executables.jq, - " -r '.ast.nodes[] | select(.nodeType == \"ContractDefinition\") | .contractKind' < ", - _getForgeArtifactPath(_name) + kind_ = Process.bash( + string.concat( + "jq -r '.ast.nodes[] | select(.nodeType == \"ContractDefinition\") | .contractKind' < ", + _getForgeArtifactPath(_name) + ) ); - bytes memory res = Process.run(cmd); - kind_ = string(res); } /// @notice Returns whether or not a contract is proxied. @@ -109,19 +86,14 @@ library ForgeArtifacts { // contract. We should consider determining whether a contract is proxied based on the // deployment script since it's the source of truth for that. Current deployment script // does not make this easy but an updated script should likely make this possible. - string[] memory cmd = new string[](3); - cmd[0] = Executables.bash; - cmd[1] = "-c"; - cmd[2] = string.concat( - Executables.jq, - " -r '.rawMetadata' ", - _getForgeArtifactPath(_name), - " | ", - Executables.jq, - " -r '.output.devdoc' | jq -r 'has(\"custom:proxied\")'" + string memory res = Process.bash( + string.concat( + "jq -r '.rawMetadata' ", + _getForgeArtifactPath(_name), + " | jq -r '.output.devdoc' | jq -r 'has(\"custom:proxied\")'" + ) ); - bytes memory res = Process.run(cmd); - out_ = stdJson.readBool(string(res), ""); + out_ = stdJson.readBool(res, ""); } /// @notice Returns whether or not a contract is predeployed. @@ -130,27 +102,18 @@ library ForgeArtifacts { function isPredeployedContract(string memory _name) internal returns (bool out_) { // TODO: Similar to the above, using the `@custom:predeployed` tag is not reliable but // functional for now. Deployment script should make this easier to determine. - string[] memory cmd = new string[](3); - cmd[0] = Executables.bash; - cmd[1] = "-c"; - cmd[2] = string.concat( - Executables.jq, - " -r '.rawMetadata' ", - _getForgeArtifactPath(_name), - " | ", - Executables.jq, - " -r '.output.devdoc' | jq -r 'has(\"custom:predeploy\")'" + string memory res = Process.bash( + string.concat( + "jq -r '.rawMetadata' ", + _getForgeArtifactPath(_name), + " | jq -r '.output.devdoc' | jq -r 'has(\"custom:predeploy\")'" + ) ); - bytes memory res = Process.run(cmd); - out_ = stdJson.readBool(string(res), ""); + out_ = stdJson.readBool(res, ""); } function _getForgeArtifactDirectory(string memory _name) internal returns (string memory dir_) { - string[] memory cmd = new string[](3); - cmd[0] = Executables.bash; - cmd[1] = "-c"; - cmd[2] = string.concat(Executables.forge, " config --json | ", Executables.jq, " -r .out"); - bytes memory res = Process.run(cmd); + string memory res = Process.bash("forge config --json | jq -r .out"); string memory contractName = _stripSemver(_name); dir_ = string.concat(vm.projectRoot(), "/", string(res), "/", contractName, ".sol"); } @@ -164,19 +127,10 @@ library ForgeArtifacts { return path; } - string[] memory cmd = new string[](3); - cmd[0] = Executables.bash; - cmd[1] = "-c"; - cmd[2] = string.concat( - Executables.ls, - " -1 --color=never ", - directory, - " | ", - Executables.jq, - " -R -s -c 'split(\"\n\") | map(select(length > 0))'" + string memory res = Process.bash( + string.concat("ls -1 --color=never ", directory, " | jq -R -s -c 'split(\"\n\") | map(select(length > 0))'") ); - bytes memory res = Process.run(cmd); - string[] memory files = stdJson.readStringArray(string(res), ""); + string[] memory files = stdJson.readStringArray(res, ""); out_ = string.concat(directory, "/", files[0]); } @@ -198,23 +152,19 @@ library ForgeArtifacts { slotType = "t_bool"; } - string[] memory command = new string[](3); - command[0] = Executables.bash; - command[1] = "-c"; - command[2] = string.concat( - Executables.echo, - " '", - storageLayout, - "'", - " | ", - Executables.jq, - " '.storage[] | select(.label == \"", - slotName, - "\" and .type == \"", - slotType, - "\")'" + bytes memory rawSlot = vm.parseJson( + Process.bash( + string.concat( + "echo '", + storageLayout, + "' | jq '.storage[] | select(.label == \"", + slotName, + "\" and .type == \"", + slotType, + "\")'" + ) + ) ); - bytes memory rawSlot = vm.parseJson(string(Process.run(command))); slot_ = abi.decode(rawSlot, (StorageSlot)); } @@ -245,25 +195,19 @@ library ForgeArtifacts { } } - string[] memory command = new string[](3); - command[0] = Executables.bash; - command[1] = "-c"; - command[2] = string.concat( - Executables.find, - " ", - _path, - bytes(pathExcludesPat).length > 0 ? string.concat(" ! \\( ", pathExcludesPat, " \\)") : "", - " -type f ", - "-exec basename {} \\;", - " | ", - Executables.sed, - " 's/\\.[^.]*$//'", - " | ", - Executables.jq, - " -R -s 'split(\"\n\")[:-1]'" + contractNames_ = abi.decode( + vm.parseJson( + Process.bash( + string.concat( + "find ", + _path, + bytes(pathExcludesPat).length > 0 ? string.concat(" ! \\( ", pathExcludesPat, " \\)") : "", + " -type f -exec basename {} \\; | sed 's/\\.[^.]*$//' | jq -R -s 'split(\"\n\")[:-1]'" + ) + ) + ), + (string[]) ); - - contractNames_ = abi.decode(vm.parseJson(string(Process.run(command))), (string[])); } /// @notice Returns the function ABIs of all L1 contracts. diff --git a/packages/contracts-bedrock/scripts/libraries/Process.sol b/packages/contracts-bedrock/scripts/libraries/Process.sol index d2cf5c3af4aa0..7a8c939f11f83 100644 --- a/packages/contracts-bedrock/scripts/libraries/Process.sol +++ b/packages/contracts-bedrock/scripts/libraries/Process.sol @@ -10,6 +10,25 @@ library Process { /// @notice Foundry cheatcode VM. Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + /// @notice Executes a bash command in a subprocess and returns its output as a string. Will revert if the command + /// returns no output. + /// @param _command The bash command to execute + function bash(string memory _command) internal returns (string memory stdout_) { + stdout_ = bash({ _command: _command, _allowEmpty: false }); + } + + /// @notice Executes a bash command in a subprocess and returns its output as a string. Will 'optionally' revert if + /// the command returns no output. + /// @param _command The bash command to execute + /// @param _allowEmpty Allow empty output. + function bash(string memory _command, bool _allowEmpty) internal returns (string memory stdout_) { + string[] memory command = new string[](3); + command[0] = "bash"; + command[1] = "-c"; + command[2] = _command; + stdout_ = string(run({ _command: command, _allowEmpty: _allowEmpty })); + } + /// @notice Run a command in a subprocess. Fails if no output is returned. /// @param _command Command to run. function run(string[] memory _command) internal returns (bytes memory stdout_) { diff --git a/packages/contracts-bedrock/scripts/libraries/LibStateDiff.sol b/packages/contracts-bedrock/scripts/libraries/StateDiff.sol similarity index 99% rename from packages/contracts-bedrock/scripts/libraries/LibStateDiff.sol rename to packages/contracts-bedrock/scripts/libraries/StateDiff.sol index 2b6f38a9afa77..4b4cacab42f24 100644 --- a/packages/contracts-bedrock/scripts/libraries/LibStateDiff.sol +++ b/packages/contracts-bedrock/scripts/libraries/StateDiff.sol @@ -4,10 +4,10 @@ pragma solidity 0.8.15; import { stdJson } from "forge-std/StdJson.sol"; import { VmSafe } from "forge-std/Vm.sol"; -/// @title LibStateDiff +/// @title StateDiff /// @author refcell /// @notice Library to write StateDiff output to json. -library LibStateDiff { +library StateDiff { /// @notice Accepts an array of AccountAccess structs from the Vm and encodes them as a json string. /// @param _accountAccesses Array of AccountAccess structs. /// @return serialized_ string diff --git a/packages/contracts-bedrock/scripts/ops/FeeVaultWithdrawal.s.sol b/packages/contracts-bedrock/scripts/ops/FeeVaultWithdrawal.s.sol deleted file mode 100644 index 9e5bb96cfe319..0000000000000 --- a/packages/contracts-bedrock/scripts/ops/FeeVaultWithdrawal.s.sol +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import { console } from "forge-std/console.sol"; -import { Script } from "forge-std/Script.sol"; -import { IMulticall3 } from "forge-std/interfaces/IMulticall3.sol"; -import { Predeploys } from "src/libraries/Predeploys.sol"; -import { IFeeVault } from "src/L2/interfaces/IFeeVault.sol"; - -/// @title FeeVaultWithdrawal -/// @notice A script to make it very simple to withdraw from the fee vaults. -/// The usage is as follows: -/// $ forge script scripts/FeeVaultWithdrawal.s.sol \ -/// --rpc-url $ETH_RPC_URL --broadcast \ -/// --private-key $PRIVATE_KEY -contract FeeVaultWithdrawal is Script { - IMulticall3 private constant multicall = IMulticall3(MULTICALL3_ADDRESS); - IMulticall3.Call3[] internal calls; - - /// @notice The entrypoint function. Determines which FeeVaults can be withdrawn from and then - /// will send the transaction via Multicall3 to withdraw all FeeVaults. - function run() external { - require(address(multicall).code.length > 0); - - address[] memory vaults = new address[](3); - vaults[0] = Predeploys.SEQUENCER_FEE_WALLET; - vaults[1] = Predeploys.BASE_FEE_VAULT; - vaults[2] = Predeploys.L1_FEE_VAULT; - - for (uint256 i; i < vaults.length; i++) { - address vault = vaults[i]; - bool shouldCall = canWithdrawal(vault); - if (shouldCall) { - calls.push( - IMulticall3.Call3({ - target: vault, - allowFailure: false, - callData: abi.encodeWithSelector(IFeeVault.withdraw.selector) - }) - ); - - address recipient = IFeeVault(payable(vault)).RECIPIENT(); - uint256 balance = vault.balance; - log(balance, recipient, vault); - } else { - string memory logline = - string.concat(vm.toString(vault), " does not have a large enough balance to withdraw."); - console.log(logline); - } - } - - if (calls.length > 0) { - vm.broadcast(); - multicall.aggregate3(calls); - console.log("Success."); - } - } - - /// @notice Checks whether or not a FeeVault can be withdrawn. The balance of the account must - /// be larger than the `MIN_WITHDRAWAL_AMOUNT`. - function canWithdrawal(address _vault) internal view returns (bool) { - uint256 minWithdrawalAmount = IFeeVault(payable(_vault)).MIN_WITHDRAWAL_AMOUNT(); - uint256 balance = _vault.balance; - return balance >= minWithdrawalAmount; - } - - /// @notice Logs the information relevant to the user. - function log(uint256 _balance, address _recipient, address _vault) internal pure { - string memory logline = string.concat( - "Withdrawing ", vm.toString(_balance), " to ", vm.toString(_recipient), " from ", vm.toString(_vault) - ); - console.log(logline); - } -} diff --git a/packages/contracts-bedrock/scripts/ops/calculate-checksum.sh b/packages/contracts-bedrock/scripts/ops/calculate-checksum.sh old mode 100644 new mode 100755 index 86fb4394c091a..f00fa6b17641b --- a/packages/contracts-bedrock/scripts/ops/calculate-checksum.sh +++ b/packages/contracts-bedrock/scripts/ops/calculate-checksum.sh @@ -14,7 +14,7 @@ cd "$CONTRACTS_DIR" echoerr "> Calculating contracts checksum..." find . -type f -name '*.sol' -exec sha256sum {} + > manifest.txt -sha256sum semver-lock.json >> manifest.txt +sha256sum snapshots/semver-lock.json >> manifest.txt sha256sum foundry.toml >> manifest.txt # need to specify the locale to ensure consistent sorting across platforms LC_ALL=C sort -o manifest.txt manifest.txt diff --git a/packages/contracts-bedrock/scripts/ops/publish-artifacts.sh b/packages/contracts-bedrock/scripts/ops/publish-artifacts.sh index 720e71ad9720a..9e04ea8d0fdc2 100644 --- a/packages/contracts-bedrock/scripts/ops/publish-artifacts.sh +++ b/packages/contracts-bedrock/scripts/ops/publish-artifacts.sh @@ -44,7 +44,11 @@ else tar="tar" fi -"$tar" -czf "$archive_name" artifacts forge-artifacts cache +rm -f COMMIT +commit=$(git rev-parse HEAD) +echo "$commit" > COMMIT + +"$tar" -czf "$archive_name" artifacts forge-artifacts cache COMMIT du -sh "$archive_name" | awk '{$1=$1};1' # trim leading whitespace echoerr "> Done." @@ -52,4 +56,5 @@ echoerr "> Uploading artifacts to GCS..." gcloud storage cp "$archive_name" "gs://$DEPLOY_BUCKET/$archive_name" echoerr "> Done." -rm "$archive_name" \ No newline at end of file +rm "$archive_name" +rm COMMIT \ No newline at end of file diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/.env.example b/packages/contracts-bedrock/scripts/upgrades/holocene/.env.example new file mode 100644 index 0000000000000..02d67a4bad06f --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/.env.example @@ -0,0 +1,93 @@ +############################################## +# ↓ Required ↓ # +############################################## + +# The network to deploy the contracts to. +# Must be one of 'mainnet', 'sepolia' +NETWORK= + +# Etherscan API key used to verify contract bytecode +ETHERSCAN_API_KEY= + +# RPC URL for the L1 network that matches $NETWORK +ETH_RPC_URL= + +# Private key used to deploy the new contracts for this upgrade +PRIVATE_KEY= + +# Path to the deploy config JSON file +DEPLOY_CONFIG_PATH= + +# Path to the folder where output artifacts will be stored +OUTPUT_FOLDER_PATH= + +# Address of deployed `PreimageOracle` contract. +PREIMAGE_ORACLE_ADDR= + +# Address of deployed `AnchorStateRegistry` proxy contract. +ANCHOR_STATE_REGISTRY_PROXY_ADDR= + +# Address of the `SuperchainConfig` proxy contract. +SUPERCHAIN_CONFIG_PROXY_ADDR= + +# Address of deployed `ProxyAdmin` contract. +PROXY_ADMIN_ADDR= + +# Address of deployed `SystemConfig` proxy contract. +SYSTEM_CONFIG_PROXY_ADDR= + +# Address of deployed `DisputeGameFactory` proxy contract. +DISPUTE_GAME_FACTORY_PROXY_ADDR= + +# Whether or not to deploy and include any fault proof contracts in the upgrade. +# +# If 'true', the `PermissionedDisputeGame` contract will be deployed and included in the upgrade. +# If 'false', the `PermissionedDisputeGame` contract will not be deployed or included in the upgrade. +# +# Must be one of 'true', 'false' +# Cannot be 'false' if `USE_PERMISSIONLESS_FAULT_PROOFS` is 'true' +USE_FAULT_PROOFS=true + +# Whether or not to deploy and include the `FaultDisputeGame` contract in the upgrade. +# +# If 'true', the `FaultDisputeGame` contract will be deployed and included in the upgrade. +# If 'false', the `FaultDisputeGame` contract will not be deployed or included in the upgrade. +# +# Must be one of 'true', 'false' +# Cannot be 'true' if `USE_FAULT_PROOFS` is 'false' +USE_PERMISSIONLESS_FAULT_PROOFS=true + +################################################### +# ↓ Optional ↓ # +# Do not set if you don't know what you're doing. # +################################################### + +# Address of the deployed `SystemConfig` implementation for Holocene. +# +# This implementation is reused across L2 deployments based on the L1 @ `ETH_RPC_URL`. +# If you are not the first to deploy Holocene on this L1, this field should be set to +# the existing deployment address. +# +# If this field is not set, the `superchain-registry` will be consulted for the implementation address. +# If this field is set to the zero address, a new `SystemConfig` implementation will be deployed. +SYSTEM_CONFIG_IMPL_ADDR= + +# Address of the deployed `MIPS` implementation for Holocene. +# +# This implementation is reused across L2 deployments based on the L1 @ `ETH_RPC_URL`. +# If you are not the first to deploy Holocene on this L1, this field should be set to +# the existing deployment address. +# +# If this field is not set, the `superchain-registry` will be consulted for the implementation address. +# If this field is set to the zero address, a new `MIPS` implementation will be deployed. +MIPS_IMPL_ADDR= + +# Address of deployed `DelayedWETH` implementation contract. +# +# This implementation is reused across L2 deployments based on the L1 @ `ETH_RPC_URL`. +# If you are not the first to deploy permissionless fault proofs on L1, this field should be +# set to the existing deployment address. +# +# If this field is not set, the `superchain-registry` will be consulted for the implementation address. +# If this field is set to the zero address, a new `DelayedWETH` implementation will be deployed. +DELAYED_WETH_IMPL_ADDR= diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/.gitignore b/packages/contracts-bedrock/scripts/upgrades/holocene/.gitignore new file mode 100644 index 0000000000000..442ed87d93042 --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/.gitignore @@ -0,0 +1,2 @@ +# Environment +.env diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/DeployUpgrade.s.sol b/packages/contracts-bedrock/scripts/upgrades/holocene/DeployUpgrade.s.sol new file mode 100644 index 0000000000000..8203e42b060c6 --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/DeployUpgrade.s.sol @@ -0,0 +1,337 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.15; + +// Forge +import { console2 as console } from "forge-std/console2.sol"; + +// Scripts +import { Deployer } from "scripts/deploy/Deployer.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; + +// Utils +import { Claim, GameTypes, Duration } from "src/dispute/lib/Types.sol"; + +// Interfaces +import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; +import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; +import { IProxy } from "src/universal/interfaces/IProxy.sol"; +import { + IFaultDisputeGame, + IBigStepper, + IAnchorStateRegistry, + IDelayedWETH +} from "src/dispute/interfaces/IFaultDisputeGame.sol"; +import { IPermissionedDisputeGame } from "src/dispute/interfaces/IPermissionedDisputeGame.sol"; +import { IMIPS, IPreimageOracle } from "src/cannon/interfaces/IMIPS.sol"; + +/// @title DeployUpgrade +/// @notice A deployment script for smart contract upgrades surrounding the Holocene hardfork. +contract DeployUpgrade is Deployer { + /// @dev The entrypoint to the deployment script. + function deploy( + address _proxyAdmin, + address _superchainConfig, + address _systemConfigImpl, + address _mipsImpl, + address _delayedWETH, + address _preimageOracle, + address _anchorStateRegistry, + bool _useFaultProofs, + bool _usePermissionlessFaultProofs + ) + public + { + // Shim the existing contracts that this upgrade is dependent on. + shim({ + _proxyAdmin: _proxyAdmin, + _superchainConfig: _superchainConfig, + _systemConfigImpl: _systemConfigImpl, + _mipsImpl: _mipsImpl, + _delayedWETH: _delayedWETH, + _preimageOracle: _preimageOracle, + _anchorStateRegistry: _anchorStateRegistry + }); + + // Deploy conditional implementations. + if (_systemConfigImpl == address(0)) deploySystemConfigImplementation(); + + if (_useFaultProofs) { + if (_mipsImpl == address(0)) deployMIPSImplementation(); + if (_delayedWETH == address(0)) deployDelayedWETH(); + + // Deploy: + // 1. New `DelayedWETH` proxy contracts for the `FaultDisputeGame` and `PermissionedDisputeGame`. + // 2. New `FaultDisputeGame` and `PermissionedDisputeGame` implementation contracts. + deployDelayedWETHProxy("PDG"); + deployPermissionedDisputeGameImplementation(); + if (_usePermissionlessFaultProofs) { + deployDelayedWETHProxy("FDG"); + deployFaultDisputeGameImplementation(); + } + + // Run deployment checks. + checkMIPS(); + checkPermissionedDisputeGame(); + checkDelayedWETH("PDG"); + if (_usePermissionlessFaultProofs) { + checkFaultDisputeGame(); + checkDelayedWETH("FDG"); + } + } + + // Print the deployment summary. + printSummary(); + } + + /// @dev Shims the existing contracts that this upgrade is dependent on. + function shim( + address _proxyAdmin, + address _superchainConfig, + address _systemConfigImpl, + address _mipsImpl, + address _delayedWETH, + address _preimageOracle, + address _anchorStateRegistry + ) + public + { + prankDeployment("ProxyAdmin", _proxyAdmin); + prankDeployment("SuperchainConfig", _superchainConfig); + if (_systemConfigImpl != address(0)) prankDeployment("SystemConfig", _systemConfigImpl); + if (_mipsImpl != address(0)) prankDeployment("MIPS", _mipsImpl); + if (_delayedWETH != address(0)) prankDeployment("DelayedWETH", _delayedWETH); + prankDeployment("PreimageOracle", _preimageOracle); + prankDeployment("AnchorStateRegistry", _anchorStateRegistry); + } + + /// @dev Deploys the Holocene `SystemConfig` implementation contract. + function deploySystemConfigImplementation() public { + vm.broadcast(msg.sender); + address systemConfig = DeployUtils.create1( + "SystemConfig", DeployUtils.encodeConstructor(abi.encodeCall(ISystemConfig.__constructor__, ())) + ); + save("SystemConfig", systemConfig); + } + + /// @dev Deploys the new `MIPS` implementation contract. + function deployMIPSImplementation() public { + vm.broadcast(msg.sender); + address mips = DeployUtils.create1({ + _name: "MIPS", + _args: DeployUtils.encodeConstructor( + abi.encodeCall(IMIPS.__constructor__, (IPreimageOracle(mustGetAddress("PreimageOracle")))) + ) + }); + save("MIPS", mips); + } + + /// @dev Checks if the `MIPS` contract is correctly configured. + function checkMIPS() public view { + IMIPS mips = IMIPS(mustGetAddress("MIPS")); + require( + address(mips.oracle()) == mustGetAddress("PreimageOracle"), "DeployHoloceneUpgrade: invalid MIPS oracle" + ); + } + + /// @dev Deploys the Holocene `FaultDisputeGame` implementation contract. + function deployFaultDisputeGameImplementation() public { + bytes memory constructorInput = abi.encodeCall( + IFaultDisputeGame.__constructor__, + ( + GameTypes.CANNON, + Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate())), + cfg.faultGameMaxDepth(), + cfg.faultGameSplitDepth(), + Duration.wrap(uint64(cfg.faultGameClockExtension())), + Duration.wrap(uint64(cfg.faultGameMaxClockDuration())), + IBigStepper(mustGetAddress("MIPS")), + IDelayedWETH(payable(mustGetAddress("DelayedWETHProxyFDG"))), + IAnchorStateRegistry(mustGetAddress("AnchorStateRegistry")), + cfg.l2ChainID() + ) + ); + + vm.broadcast(msg.sender); + address fdg = DeployUtils.create1("FaultDisputeGame", DeployUtils.encodeConstructor(constructorInput)); + save("FaultDisputeGame", fdg); + } + + /// @dev Checks if the `FaultDisputeGame` contract is correctly configured. + function checkFaultDisputeGame() public view { + IFaultDisputeGame fdg = IFaultDisputeGame(mustGetAddress("FaultDisputeGame")); + require( + fdg.gameType().raw() == GameTypes.CANNON.raw(), "DeployHoloceneUpgrade: invalid FaultDisputeGame gameType" + ); + require( + fdg.absolutePrestate().raw() == bytes32(cfg.faultGameAbsolutePrestate()), + "DeployHoloceneUpgrade: invalid FaultDisputeGame absolutePrestate" + ); + require( + fdg.maxGameDepth() == cfg.faultGameMaxDepth(), "DeployHoloceneUpgrade: invalid FaultDisputeGame maxDepth" + ); + require( + fdg.splitDepth() == cfg.faultGameSplitDepth(), "DeployHoloceneUpgrade: invalid FaultDisputeGame splitDepth" + ); + require( + fdg.clockExtension().raw() == cfg.faultGameClockExtension(), + "DeployHoloceneUpgrade: invalid FaultDisputeGame clockExtension" + ); + require( + fdg.maxClockDuration().raw() == cfg.faultGameMaxClockDuration(), + "DeployHoloceneUpgrade: invalid FaultDisputeGame maxClockDuration" + ); + require(address(fdg.vm()) == mustGetAddress("MIPS"), "DeployHoloceneUpgrade: invalid FaultDisputeGame MIPS"); + require( + address(fdg.weth()) == mustGetAddress("DelayedWETHProxyFDG"), + "DeployHoloceneUpgrade: invalid FaultDisputeGame DelayedWETH" + ); + require( + address(fdg.anchorStateRegistry()) == mustGetAddress("AnchorStateRegistry"), + "DeployHoloceneUpgrade: invalid FaultDisputeGame AnchorStateRegistry" + ); + require(fdg.l2ChainId() == cfg.l2ChainID(), "DeployHoloceneUpgrade: invalid FaultDisputeGame l2ChainID"); + } + + /// @dev Deploys the Holocene `PermissionedDisputeGame` implementation contract. + function deployPermissionedDisputeGameImplementation() public { + bytes memory constructorInput = abi.encodeCall( + IPermissionedDisputeGame.__constructor__, + ( + GameTypes.PERMISSIONED_CANNON, + Claim.wrap(bytes32(cfg.faultGameAbsolutePrestate())), + cfg.faultGameMaxDepth(), + cfg.faultGameSplitDepth(), + Duration.wrap(uint64(cfg.faultGameClockExtension())), + Duration.wrap(uint64(cfg.faultGameMaxClockDuration())), + IBigStepper(mustGetAddress("MIPS")), + IDelayedWETH(payable(mustGetAddress("DelayedWETHProxyPDG"))), + IAnchorStateRegistry(mustGetAddress("AnchorStateRegistry")), + cfg.l2ChainID(), + cfg.l2OutputOracleProposer(), + cfg.l2OutputOracleChallenger() + ) + ); + + vm.broadcast(msg.sender); + address fdg = DeployUtils.create1("PermissionedDisputeGame", DeployUtils.encodeConstructor(constructorInput)); + save("PermissionedDisputeGame", fdg); + } + + /// @dev Checks if the `PermissionedDisputeGame` contract is correctly configured. + function checkPermissionedDisputeGame() public view { + IPermissionedDisputeGame pdg = IPermissionedDisputeGame(mustGetAddress("PermissionedDisputeGame")); + require( + pdg.gameType().raw() == GameTypes.PERMISSIONED_CANNON.raw(), + "DeployHoloceneUpgrade: invalid PermissionedDisputeGame gameType" + ); + require( + pdg.absolutePrestate().raw() == bytes32(cfg.faultGameAbsolutePrestate()), + "DeployHoloceneUpgrade: invalid PermissionedDisputeGame absolutePrestate" + ); + require( + pdg.maxGameDepth() == cfg.faultGameMaxDepth(), + "DeployHoloceneUpgrade: invalid PermissionedDisputeGame maxDepth" + ); + require( + pdg.splitDepth() == cfg.faultGameSplitDepth(), + "DeployHoloceneUpgrade: invalid PermissionedDisputeGame splitDepth" + ); + require( + pdg.clockExtension().raw() == cfg.faultGameClockExtension(), + "DeployHoloceneUpgrade: invalid PermissionedDisputeGame clockExtension" + ); + require( + pdg.maxClockDuration().raw() == cfg.faultGameMaxClockDuration(), + "DeployHoloceneUpgrade: invalid PermissionedDisputeGame maxClockDuration" + ); + require( + address(pdg.vm()) == mustGetAddress("MIPS"), "DeployHoloceneUpgrade: invalid PermissionedDisputeGame MIPS" + ); + require( + address(pdg.weth()) == mustGetAddress("DelayedWETHProxyPDG"), + "DeployHoloceneUpgrade: invalid PermissionedDisputeGame DelayedWETH" + ); + require( + address(pdg.anchorStateRegistry()) == mustGetAddress("AnchorStateRegistry"), + "DeployHoloceneUpgrade: invalid PermissionedDisputeGame AnchorStateRegistry" + ); + require(pdg.l2ChainId() == cfg.l2ChainID(), "DeployHoloceneUpgrade: invalid PermissionedDisputeGame l2ChainID"); + require( + pdg.proposer() == cfg.l2OutputOracleProposer(), + "DeployHoloceneUpgrade: invalid PermissionedDisputeGame proposer" + ); + require( + pdg.challenger() == cfg.l2OutputOracleChallenger(), + "DeployHoloceneUpgrade: invalid PermissionedDisputeGame challenger" + ); + } + + /// @dev Deploys a new implementation of the `DelayedWETH` contract. + function deployDelayedWETH() public { + uint256 delay = cfg.faultGameWithdrawalDelay(); + + vm.broadcast(msg.sender); + address impl = DeployUtils.create1({ + _name: "DelayedWETH", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IDelayedWETH.__constructor__, (delay))) + }); + + // Save the new implementation address. + save("DelayedWETH", impl); + } + + /// @dev Deploys a new proxy contract with a new `DelayedWETH` implementation. + function deployDelayedWETHProxy(string memory _variant) public { + address delayedWethOwner = cfg.finalSystemOwner(); + address proxyAdmin = mustGetAddress("ProxyAdmin"); + address impl = mustGetAddress("DelayedWETH"); + ISuperchainConfig superchainConfig = ISuperchainConfig(mustGetAddress("SuperchainConfig")); + string memory finalName = string.concat("DelayedWETHProxy", _variant); + + // Deploy the implementation and proxy contracts. + vm.broadcast(msg.sender); + IProxy proxy = IProxy( + DeployUtils.create1({ + _name: "Proxy", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (msg.sender))) + }) + ); + + // Upgrade the proxy to the implementation and initialize it. + vm.broadcast(msg.sender); + proxy.upgradeToAndCall(impl, abi.encodeCall(IDelayedWETH.initialize, (delayedWethOwner, superchainConfig))); + + // Transfer the admin role of the proxy to the ProxyAdmin, now that we've upgraded + // and initialized the proxy. + vm.broadcast(msg.sender); + proxy.changeAdmin(proxyAdmin); + + // Save the proxy address. + save(finalName, address(proxy)); + } + + /// @dev Checks if the `DelayedWETH` contract is correctly configured. + function checkDelayedWETH(string memory _variant) internal { + string memory finalName = string.concat("DelayedWETHProxy", _variant); + IDelayedWETH delayedWeth = IDelayedWETH(mustGetAddress(finalName)); + require( + delayedWeth.delay() == cfg.faultGameWithdrawalDelay(), "DeployHoloceneUpgrade: invalid DelayedWETH delay" + ); + require( + delayedWeth.config() == ISuperchainConfig(mustGetAddress("SuperchainConfig")), + "DeployHoloceneUpgrade: invalid DelayedWETH config" + ); + + vm.prank(mustGetAddress("ProxyAdmin")); + address admin = IProxy(payable(address(delayedWeth))).admin(); + require(admin == mustGetAddress("ProxyAdmin"), "DeployHoloceneUpgrade: invalid DelayedWETH admin"); + } + + /// @dev Prints a summary of the deployment. + function printSummary() internal view { + console.log("1. SystemConfig: %s", mustGetAddress("SystemConfig")); + console.log("2. MIPS: %s", getAddress("MIPS")); + console.log("3. FaultDisputeGame: %s", getAddress("FaultDisputeGame")); + console.log("4. PermissionedDisputeGame: %s", getAddress("PermissionedDisputeGame")); + } +} diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/README.md b/packages/contracts-bedrock/scripts/upgrades/holocene/README.md new file mode 100644 index 0000000000000..f16127ffebbd0 --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/README.md @@ -0,0 +1,41 @@ +# Holocene Upgrade + +This directory contains a repeatable task for: +* upgrading an `op-contracts/v1.6.0` deployment to `op-contracts/v1.8.0`. +* upgrading an `op-contracts/v1.3.0` deployment to `op-contracts/v1.8.0`, while retaining the `L2OutputOracle`. + +## Dependencies + +- [`docker`](https://docs.docker.com/engine/install/) +- [`just`](https://github.com/casey/just) +- [`foundry`](https://getfoundry.sh/) + +## Usage + +This script has several different modes of operation. Namely: +1. Deploy and upgrade `op-contracts/1.6.0` -> `op-contracts/v1.8.0` + - Always upgrade the `SystemConfig` + - FP options: + - With permissionless fault proofs enabled (incl. `FaultDisputeGame`) + - With permissioned fault proofs enabled (excl. `FaultDisputeGame`) +1. Deploy and upgrade `op-contracts/v1.3.0` -> `op-contracts/v1.8.0`, with the `L2OutputOracle` still active. + - Only upgrade the `SystemConfig` + +```sh +# 1. Clone the monorepo and navigate to this directory. +git clone git@github.com:ethereum-optimism/monorepo.git && \ + cd monorepo/packages/contracts-bedrock/scripts/upgrades/holocene + +# 2. Set up the `.env` file +# +# Read the documentation carefully, and when in doubt, reach out to the OP Labs team. +cp .env.example .env && vim .env + +# 3. Run the upgrade task. +# +# This task will: +# - Deploy the new smart contract implementations. +# - Optionally, generate a safe upgrade bundle. +# - Optionally, generate a `superchain-ops` upgrade task. +just run +``` diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/justfile b/packages/contracts-bedrock/scripts/upgrades/holocene/justfile new file mode 100644 index 0000000000000..08cdc771ac92c --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/justfile @@ -0,0 +1,26 @@ +# Default recipe to list help menu. +default: + @just --list + +# Run the deployment / upgrade generation image. If the image is not present locally, +# it will be built. +run *args='': + #!/bin/bash + if [ ! "$(docker images -q op-holocene-upgrade:local 2> /dev/null)" ]; then + just build-image + fi + + # Run the deployment. + docker run \ + --rm \ + -v $OUTPUT_FOLDER_PATH/:/output \ + --env-file=.env \ + op-holocene-upgrade:local {{args}} + +# Build the image locally. +build-image: + docker build \ + -t op-holocene-upgrade:local \ + -f upgrade.dockerfile \ + --build-arg REV=op-contracts/v1.8.0-rc.1 \ + . diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/common.sh b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/common.sh new file mode 100755 index 0000000000000..0f4e80b29c408 --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/common.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Associative array to store cached TOML content for different URLs +# Used by fetch_standard_address and fetch_superchain_config_address +declare -A CACHED_TOML_CONTENT + +# error_handler +# +# Basic error handler +error_handler() { + echo "Error occurred in ${BASH_SOURCE[1]} at line: ${BASH_LINENO[0]}" + echo "Error message: $BASH_COMMAND" + exit 1 +} + +# Register the error handler +trap error_handler ERR + +# reqenv +# +# Checks if a specified environment variable is set. +# +# Arguments: +# $1 - The name of the environment variable to check +# +# Exits with status 1 if: +# - The specified environment variable is not set +reqenv() { + if [ -z "$1" ]; then + echo "Error: $1 is not set" + exit 1 + fi +} + +# prompt +# +# Prompts the user for a yes/no response. +# +# Arguments: +# $1 - The prompt message +# +# Exits with status 1 if: +# - The user does not respond with 'y' +# - The process is interrupted +prompt() { + read -p "$1 [Y/n] " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + [[ "$0" = "${BASH_SOURCE[0]}" ]] && exit 1 || return 1 + exit 1 + fi +} + +# fetch_standard_address +# +# Fetches the implementation address for a given contract from a TOML file. +# The TOML file is downloaded from a URL specified in ADDRESSES_TOML_URL +# environment variable. Results are cached to avoid repeated downloads. +# +# Arguments: +# $1 - Network name +# $2 - The release version +# $3 - The name of the contract to look up +# +# Returns: +# The implementation address of the specified contract +# +# Exits with status 1 if: +# - Failed to fetch the TOML file +# - The release version is not found in the TOML file +# - The implementation address for the specified contract is not found +fetch_standard_address() { + local network_name="$1" + local release_version="$2" + local contract_name="$3" + + # Determine the correct toml url + local toml_url="https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/refs/heads/main/validation/standard/standard-versions" + if [ "$network_name" = "mainnet" ]; then + toml_url="$toml_url-mainnet.toml" + elif [ "$network_name" = "sepolia" ]; then + toml_url="$toml_url-sepolia.toml" + else + echo "Error: NETWORK must be set to 'mainnet' or 'sepolia'" + exit 1 + fi + + # Fetch the TOML file content from the URL if not already cached for this URL + if [ -z "${CACHED_TOML_CONTENT[$toml_url]:-}" ]; then + CACHED_TOML_CONTENT[$toml_url]=$(curl -s "$toml_url") + # shellcheck disable=SC2181 + if [ $? -ne 0 ]; then + echo "Error: Failed to fetch TOML file from $toml_url" + exit 1 + fi + fi + + # Use the cached content for the current URL + local toml_content="${CACHED_TOML_CONTENT[$toml_url]}" + + # Find the section for v1.6.0 release + # shellcheck disable=SC2155 + local section_content=$(echo "$toml_content" | awk -v version="$release_version" ' + $0 ~ "^\\[releases.\"op-contracts/v" version "\"\\]" { + flag=1; + next + } + flag && /^\[/ { + exit + } + flag { + print + } + ') + if [ -z "$section_content" ]; then + echo "Error: v$release_version release section not found in addresses TOML" + exit 1 + fi + + # Extract the implementation address for the specified contract + local regex="(address|implementation_address) = \"(0x[a-fA-F0-9]{40})\"" + # shellcheck disable=SC2155 + local data=$(echo "$section_content" | grep "${contract_name}") + if [[ $data =~ $regex ]]; then + echo "${BASH_REMATCH[2]}" + else + echo "Error: Implementation address for $contract_name not found in v$release_version release" + exit 1 + fi +} diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/deploy.sh b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/deploy.sh new file mode 100755 index 0000000000000..d1e15aa63e7f5 --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/deploy.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Grab the script directory +SCRIPT_DIR=$(dirname "$0") + +# Load common.sh +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/common.sh" + +# Check required environment variables +reqenv "ETH_RPC_URL" +reqenv "PRIVATE_KEY" +reqenv "ETHERSCAN_API_KEY" +reqenv "DEPLOY_CONFIG_PATH" +reqenv "IMPL_SALT" + +# Check required address environment variables +reqenv "PROXY_ADMIN_ADDR" +reqenv "SUPERCHAIN_CONFIG_PROXY_ADDR" +reqenv "PREIMAGE_ORACLE_ADDR" +reqenv "ANCHOR_STATE_REGISTRY_PROXY_ADDR" +reqenv "DELAYED_WETH_IMPL_ADDR" +reqenv "SYSTEM_CONFIG_IMPL_ADDR" +reqenv "MIPS_IMPL_ADDR" +reqenv "USE_FAULT_PROOFS" +reqenv "USE_PERMISSIONLESS_FAULT_PROOFS" + +# Run the upgrade script +forge script DeployUpgrade.s.sol \ + --rpc-url "$ETH_RPC_URL" \ + --private-key "$PRIVATE_KEY" \ + --etherscan-api-key "$ETHERSCAN_API_KEY" \ + --sig "deploy(address,address,address,address,address,address,address,bool,bool)" \ + "$PROXY_ADMIN_ADDR" \ + "$SUPERCHAIN_CONFIG_PROXY_ADDR" \ + "$SYSTEM_CONFIG_IMPL_ADDR" \ + "$MIPS_IMPL_ADDR" \ + "$DELAYED_WETH_IMPL_ADDR" \ + "$PREIMAGE_ORACLE_ADDR" \ + "$ANCHOR_STATE_REGISTRY_PROXY_ADDR" \ + "$USE_FAULT_PROOFS" \ + "$USE_PERMISSIONLESS_FAULT_PROOFS" \ + --broadcast \ + --verify \ + --slow diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/main.sh b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/main.sh new file mode 100755 index 0000000000000..95fe1a43c231b --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/main.sh @@ -0,0 +1,152 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Grab the script directory +SCRIPT_DIR=$(dirname "$0") + +# Load common.sh +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/common.sh" + +echo " +⠄⢀⠀⠀⡐⠠⠀⢂⣠⡤⣤⣖⣤⣤⣄⢢⣤⣤⣤⡀⠄⠰⠀⠆⠀⠀⠠⠀⠆⠠⢀⠢⠐⠆⡀ +⠔⢀⠀⠄⡀⠔⢠⣾⣿⣿⣷⣿⣿⣿⣿⣷⣟⣛⣻⣿⣤⡠⢀⠆⢄⠂⠠⢠⠀⠄⠀⢠⠰⢄⠄ +⣈⠀⠐⡀⠀⠈⣾⣿⣿⣿⣿⡿⡿⣿⣿⣿⣿⡿⢿⣿⣿⣿⣦⠀⠂⠀⢈⠀⠁⠂⡀⢀⠠⠈⡀ +⠆⠈⠀⠄⣃⣼⣿⣿⣿⠿⡿⣿⣿⣷⣾⣷⣾⡾⣿⣿⣿⢿⡟⡇⠠⠁⠨⠐⠀⠃⠱⠊⠀⠀⠄ +⠐⣠⣶⣿⣿⣿⣿⣿⣿⣿⣾⣮⣛⢿⣿⡿⠘⣇⢯⣹⣶⣷⣿⣿⡄⠆⢐⠀⢄⠢⡒⠐⠠⢀⠂ +⢴⣿⣿⣿⣿⣿⣿⡿⠿⢿⣿⣿⣟⢿⣶⣾⣿⣧⢻⣿⢿⣿⣿⣿⠂⠈⢀⠈⡀⡁⢀⠉⢀⠀⠀ +⡜⣿⣿⣿⣿⣿⣿⣦⡻⠀⢨⣽⣿⣿⣿⣿⣿⣿⣦⡛⣾⣭⣃⣀⣦⠀⠨⠐⠀⠄⠃⠈⠀⠀⠁ +⣳⡘⣿⣿⣿⣿⣿⣿⣿⣿⣿⢛⣭⣿⣿⣿⣿⣿⣿⣿⢢⣿⣿⣿⣿⡇⢀⠲⠂⠄⢀⡐⠠⠐⠂ +⢣⠵⢹⣿⣿⣿⣿⣿⣿⣿⣿⣧⣛⣻⣿⣭⣿⣿⠻⢥⣿⣿⣿⣿⣿⣿⡄⠀⠁⡀⢀⢈⠀⢀⠁ +⡼⣹⡘⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⣟⣻⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⠁⠉⠐⠀⠂⠈ +⡷⣡⠧⢹⣿⣿⣿⣿⣿⣿⣗⣶⣾⣿⣿⣿⣿⣿⠮⢿⣿⣿⡿⠿⣿⣿⢀⣀⠂⡁⠐⢌⠐⡠⠁ +⢷⠡⠏⢧⢌⢻⣿⣿⣿⣟⣿⣿⣻⣿⡿⠿⣛⣵⢟⣭⡭⠥⠮⠕⣒⣒⣚⣮⣰⢤⣤⣄⣀⡠⠄ +⠁⠠⠀⠄⣏⢦⡙⣿⣿⣽⣟⣿⡟⣬⣾⣿⣿⣿⣾⣆⠭⠽⠶⢶⢶⣖⣶⣹⣖⡿⣿⣿⣿⣿⡆ +⠀⡁⠂⡟⡜⣦⢫⣌⠻⣷⣿⢏⣾⣿⣿⣿⢿⣿⢿⣿⣿⣿⣿⣿⠿⣛⣛⣛⠛⣭⣿⣿⢻⣽⡇ +⣏⠖⣮⢱⣋⢖⣣⢎⡳⢤⡅⣾⣿⢯⣷⡏⡖⣰⣝⣚⣙⣫⢍⡶⠷⣽⢭⣛⡇⠀⢰⣶⣾⣿⠀ +⡮⡝⢦⣓⢎⡳⡜⠎⠡⠁⢸⣿⣿⣿⣿⣁⢠⣿⡿⣿⡟⣎⣯⣽⣋⡷⣾⣹⡃⠀⢸⣿⣿⢿⠀ +⣳⠁⠀⡝⢮⣱⢹⠀⠂⠈⣿⣿⣿⣿⡻⣈⣸⣿⣙⢾⢿⣹⡶⣿⣼⣗⣻⡞⣡⠁⣼⣿⣿⣿⡀ +⡔⢦⢥⡛⣜⠦⣏⡄⡈⣸⢿⣿⡿⣽⢃⠇⣿⣧⡝⣟⡳⢾⣹⣟⡻⣾⣹⢣⠞⣄⣯⣿⣷⣿⡆ + -*~ [ Grug Deployer mk2 ] ~*- + ~*- [ Holocene ] -*~ +" + +# Set variables from environment or error. +export RELEASE="1.8.0" +export NETWORK="${NETWORK:?NETWORK must be set}" +export ETHERSCAN_API_KEY=${ETHERSCAN_API_KEY:?ETHERSCAN_API_KEY must be set} +export ETH_RPC_URL=${ETH_RPC_URL:?ETH_RPC_URL must be set} +export PRIVATE_KEY=${PRIVATE_KEY:?PRIVATE_KEY must be set} +export BASE_DEPLOY_CONFIG_PATH=${DEPLOY_CONFIG_PATH:?DEPLOY_CONFIG_PATH must be set} +export OUTPUT_FOLDER_PATH=${OUTPUT_FOLDER_PATH:?OUTPUT_FOLDER_PATH must be set} +export SYSTEM_CONFIG_IMPL_ADDR=${SYSTEM_CONFIG_IMPL_ADDR:-$(fetch_standard_address "$NETWORK" "$RELEASE" "system_config")} +export MIPS_IMPL_ADDR=${MIPS_IMPL_ADDR:-$(fetch_standard_address "$NETWORK" "$RELEASE" "mips")} +export PREIMAGE_ORACLE_ADDR=${PREIMAGE_ORACLE_ADDR:?PREIMAGE_ORACLE_ADDR must be set} +export ANCHOR_STATE_REGISTRY_PROXY_ADDR=${ANCHOR_STATE_REGISTRY_PROXY_ADDR:?ANCHOR_STATE_REGISTRY_PROXY_ADDR must be set} +export DELAYED_WETH_IMPL_ADDR=${DELAYED_WETH_IMPL_ADDR:-$(fetch_standard_address "$NETWORK" "$RELEASE" "delayed_weth")} +export PROXY_ADMIN_ADDR=${PROXY_ADMIN_ADDR:?PROXY_ADMIN_ADDR must be set} +export SUPERCHAIN_CONFIG_PROXY_ADDR=${SUPERCHAIN_CONFIG_PROXY_ADDR:?SUPERCHAIN_CONFIG_ADDR must be set} +export SYSTEM_CONFIG_PROXY_ADDR=${SYSTEM_CONFIG_PROXY_ADDR:?SYSTEM_CONFIG_PROXY_ADDR must be set} +export DISPUTE_GAME_FACTORY_PROXY_ADDR=${DISPUTE_GAME_FACTORY_PROXY_ADDR:?DISPUTE_GAME_FACTORY_PROXY_ADDR must be set} +export USE_FAULT_PROOFS=${USE_FAULT_PROOFS:?USE_FAULT_PROOFS must be set} +export USE_PERMISSIONLESS_FAULT_PROOFS=${USE_PERMISSIONLESS_FAULT_PROOFS:?USE_PERMISSIONLESS_FAULT_PROOFS must be set} + +# Sanity check FP configuration. +if [[ $USE_PERMISSIONLESS_FAULT_PROOFS == true && $USE_FAULT_PROOFS == false ]]; then + echo "Error: USE_PERMISSIONLESS_FAULT_PROOFS cannot be true if USE_FAULT_PROOFS is false" + exit 1 +fi + +# Make the output folder, if it doesn't exist +mkdir -p "$OUTPUT_FOLDER_PATH" + +# Find the contracts-bedrock directory +CONTRACTS_BEDROCK_DIR=$(pwd) +while [[ "$CONTRACTS_BEDROCK_DIR" != "/" && "${CONTRACTS_BEDROCK_DIR##*/}" != "contracts-bedrock" ]]; do + CONTRACTS_BEDROCK_DIR=$(dirname "$CONTRACTS_BEDROCK_DIR") +done + +# Error out if we couldn't find it for some reason +if [[ "$CONTRACTS_BEDROCK_DIR" == "/" ]]; then + echo "Error: 'contracts-bedrock' directory not found" + exit 1 +fi + +# Set file paths from command-line arguments +export DEPLOY_CONFIG_PATH="$CONTRACTS_BEDROCK_DIR/deploy-config/deploy-config.json" + +# Copy the files into the paths so that the script can actually access it +cp "$BASE_DEPLOY_CONFIG_PATH" "$DEPLOY_CONFIG_PATH" + +# Run deploy.sh +DEPLOY_LOG_PATH="$OUTPUT_FOLDER_PATH/deploy.log" +if ! "$SCRIPT_DIR/deploy.sh" | tee "$DEPLOY_LOG_PATH"; then + echo "Error: deploy.sh failed" + exit 1 +fi + +# Extract the addresses from the deployment logs +# shellcheck disable=2155 +export SYSTEM_CONFIG_IMPL=$(grep "1. SystemConfig:" "$DEPLOY_LOG_PATH" | awk '{print $3}') +# shellcheck disable=2155 +export MIPS_IMPL=$(grep "2. MIPS:" "$DEPLOY_LOG_PATH" | awk '{print $3}') +# shellcheck disable=2155 +export FDG_IMPL=$(grep "3. FaultDisputeGame:" "$DEPLOY_LOG_PATH" | awk '{print $3}') +# shellcheck disable=2155 +export PDG_IMPL=$(grep "4. PermissionedDisputeGame:" "$DEPLOY_LOG_PATH" | awk '{print $3}') + +# Ensure that the addresses were extracted properly +reqenv "SYSTEM_CONFIG_IMPL" +reqenv "MIPS_IMPL" +reqenv "FDG_IMPL" +reqenv "PDG_IMPL" + +# Generate deployments.json with extracted addresses +DEPLOYMENTS_JSON_PATH="$OUTPUT_FOLDER_PATH/deployments.json" +cat << EOF > "$DEPLOYMENTS_JSON_PATH" +{ + "SystemConfig": "$SYSTEM_CONFIG_IMPL", + "MIPS": "$MIPS_IMPL", + "FaultDisputeGame": "$FDG_IMPL", + "PermissionedDisputeGame": "$PDG_IMPL" +} +EOF + +echo "✨ Deployed contracts and saved addresses to \"$DEPLOYMENTS_JSON_PATH\"" + +# Print a message when the script exits +trap 'echo "✨ Done. Artifacts are available in \"$OUTPUT_FOLDER_PATH\""' EXIT + +prompt "Generate safe upgrade bundle for SystemConfig?" + +# Generate the system config upgrade bundle +if ! "$SCRIPT_DIR/sys-cfg-bundle.sh"; then + echo "Error: sys-cfg-bundle.sh failed" + exit 1 +fi + +prompt "Generate superchain-ops upgrade task for SystemConfig upgrade bundle?" + +# Generate the superchain-ops upgrade task +if ! "$SCRIPT_DIR/sc-ops-sys-cfg.sh"; then + echo "Error: sc-ops-sys-cfg.sh failed" + exit 1 +fi + +if [[ $USE_FAULT_PROOFS == true ]]; then + prompt "Generate safe upgrade bundle for proofs contracts?" + + # Generate the proofs contracts' upgrade bundle + if ! "$SCRIPT_DIR/proofs-bundle.sh"; then + echo "Error: proofs-bundle.sh failed" + exit 1 + fi + + prompt "Generate superchain-ops upgrade task for proofs contracts upgrade bundle?" + + # Generate the superchain-ops upgrade task + if ! "$SCRIPT_DIR/sc-ops-proofs.sh"; then + echo "Error: sc-ops-proofs.sh failed" + exit 1 + fi +fi diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/proofs-bundle.sh b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/proofs-bundle.sh new file mode 100755 index 0000000000000..85295d3040f1f --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/proofs-bundle.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Grab the script directory +SCRIPT_DIR=$(dirname "$0") + +# Load common.sh +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/common.sh" + +# Check the env +reqenv "ETH_RPC_URL" +reqenv "OUTPUT_FOLDER_PATH" +reqenv "MIPS_IMPL" +reqenv "FDG_IMPL" +reqenv "PDG_IMPL" +reqenv "DISPUTE_GAME_FACTORY_PROXY_ADDR" +reqenv "USE_PERMISSIONLESS_FAULT_PROOFS" + +# Local environment +BUNDLE_PATH="$OUTPUT_FOLDER_PATH/proofs_bundle.json" +L1_CHAIN_ID=$(cast chain-id) + +# Copy the bundle template +cp ./templates/proof_upgrade_bundle_template.json "$BUNDLE_PATH" + +# Tx 1: Upgrade PermissionedDisputeGame implementation +TX_1_PAYLOAD=$(cast calldata "setImplementation(uint32,address)" 1 "$PDG_IMPL") + +# Tx 2: Upgrade FaultDisputeGame implementation +TX_2_PAYLOAD=$(cast calldata "setImplementation(uint32,address)" 0 "$FDG_IMPL") + +# Replace variables +sed -i '' "s/\$L1_CHAIN_ID/$L1_CHAIN_ID/g" "$BUNDLE_PATH" +sed -i '' "s/\$PDG_IMPL/$PDG_IMPL/g" "$BUNDLE_PATH" +sed -i '' "s/\$TX_1_PAYLOAD/$TX_1_PAYLOAD/g" "$BUNDLE_PATH" +sed -i '' "s/\$TX_2_PAYLOAD/$TX_2_PAYLOAD/g" "$BUNDLE_PATH" + +# Conditionally, if the FDG is being deployed, append the bundle extension +if [ "$USE_PERMISSIONLESS_FAULT_PROOFS" == true ]; then + echo "✨ USE_PERMISSIONLESS_FAULT_PROOFS=true | Adding FDG deployment to upgrade bundle." + jq --argjson fdg_extension "$(cat ./templates/fdg_bundle_extension.json)" \ + '.transactions += [$fdg_extension]' \ + "$BUNDLE_PATH" > "$BUNDLE_PATH.tmp" + mv "$BUNDLE_PATH.tmp" "$BUNDLE_PATH" + + # Replace variables + sed -i '' "s/\$FDG_IMPL/$FDG_IMPL/g" "$BUNDLE_PATH" + sed -i '' "s/\$TX_2_PAYLOAD/$TX_2_PAYLOAD/g" "$BUNDLE_PATH" +fi + +sed -i '' "s/\$DISPUTE_GAME_FACTORY_PROXY_ADDR/$DISPUTE_GAME_FACTORY_PROXY_ADDR/g" "$BUNDLE_PATH" + +echo "✨ Generated proof contracts upgrade bundle at \"$BUNDLE_PATH\"" diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/sc-ops-proofs.sh b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/sc-ops-proofs.sh new file mode 100755 index 0000000000000..d4ff18db5738e --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/sc-ops-proofs.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Grab the script directory +SCRIPT_DIR=$(dirname "$0") + +# Load common.sh +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/common.sh" + +# Check required environment variables +reqenv "OUTPUT_FOLDER_PATH" +reqenv "MIPS_IMPL" +reqenv "FDG_IMPL" +reqenv "PDG_IMPL" +reqenv "DISPUTE_GAME_FACTORY_PROXY_ADDR" + +# Create directory for the task +TASK_DIR="$OUTPUT_FOLDER_PATH/proofs-sc-ops-task" +mkdir -p "$TASK_DIR" + +# Copy the bundle and task template +cp "$OUTPUT_FOLDER_PATH/proofs_bundle.json" "$TASK_DIR/input.json" +cp -R "$SCRIPT_DIR/../templates/proofs-sc-ops-task/." "$TASK_DIR/" + +# Generate the task overview +msup render -i "$TASK_DIR/input.json" -o "$TASK_DIR/OVERVIEW.md" + +# Generate the README +sed -i '' "s/\$MIPS_IMPL/$MIPS_IMPL/g" "$TASK_DIR/README.md" +sed -i '' "s/\$FDG_IMPL/$FDG_IMPL/g" "$TASK_DIR/README.md" +sed -i '' "s/\$PDG_IMPL/$PDG_IMPL/g" "$TASK_DIR/README.md" + +# Generate the validation doc +OLD_FDG=$(cast call "$DISPUTE_GAME_FACTORY_PROXY_ADDR" "gameImpls(uint32)" 0) +OLD_PDG=$(cast call "$DISPUTE_GAME_FACTORY_PROXY_ADDR" "gameImpls(uint32)" 1) + +PADDED_OLD_FDG=$(cast 2u "$OLD_FDG") +PADDED_OLD_PDG=$(cast 2u "$OLD_PDG") +PADDED_FDG_IMPL=$(cast 2u "$FDG_IMPL") +PADDED_PDG_IMPL=$(cast 2u "$PDG_IMPL") + +sed -i '' "s/\$DISPUTE_GAME_FACTORY_PROXY_ADDR/$DISPUTE_GAME_FACTORY_PROXY_ADDR/g" "$TASK_DIR/VALIDATION.md" +sed -i '' "s/\$OLD_FDG/$PADDED_OLD_FDG/g" "$TASK_DIR/VALIDATION.md" +sed -i '' "s/\$FDG_IMPL/$PADDED_FDG_IMPL/g" "$TASK_DIR/VALIDATION.md" +sed -i '' "s/\$PDG_IMPL/$PADDED_PDG_IMPL/g" "$TASK_DIR/VALIDATION.md" +sed -i '' "s/\$OLD_PDG/$PADDED_OLD_PDG/g" "$TASK_DIR/VALIDATION.md" diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/sc-ops-sys-cfg.sh b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/sc-ops-sys-cfg.sh new file mode 100755 index 0000000000000..b0e4a57b32b70 --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/sc-ops-sys-cfg.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Grab the script directory +SCRIPT_DIR=$(dirname "$0") + +# Load common.sh +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/common.sh" + +# Check required environment variables +reqenv "OUTPUT_FOLDER_PATH" +reqenv "SYSTEM_CONFIG_IMPL" +reqenv "SYSTEM_CONFIG_PROXY_ADDR" + +# Create directory for the task +TASK_DIR="$OUTPUT_FOLDER_PATH/sys-cfg-sc-ops-task" +mkdir -p "$TASK_DIR" + +# Copy the bundle and task template +cp "$OUTPUT_FOLDER_PATH/sys_cfg_bundle.json" "$TASK_DIR/input.json" +cp -R "$SCRIPT_DIR/../templates/sys-cfg-sc-ops-task/." "$TASK_DIR/" + +# Generate the task overview +msup render -i "$TASK_DIR/input.json" -o "$TASK_DIR/OVERVIEW.md" + +# Generate the README +sed -i '' "s/\$SYSTEM_CONFIG_IMPL/$SYSTEM_CONFIG_IMPL/g" "$TASK_DIR/README.md" + +# Generate the validation doc +OLD_SYS_CFG=$(cast impl "$SYSTEM_CONFIG_PROXY_ADDR") + +PADDED_OLD_SYS_CFG=$(cast 2u "$OLD_SYS_CFG") +PADDED_SYS_CFG=$(cast 2u "$SYSTEM_CONFIG_IMPL") + +sed -i '' "s/\$SYSTEM_CONFIG_PROXY_ADDR/$SYSTEM_CONFIG_PROXY_ADDR/g" "$TASK_DIR/VALIDATION.md" +sed -i '' "s/\$OLD_SYS_CFG/$PADDED_OLD_SYS_CFG/g" "$TASK_DIR/VALIDATION.md" +sed -i '' "s/\$SYSTEM_CONFIG_IMPL/$PADDED_SYS_CFG/g" "$TASK_DIR/VALIDATION.md" diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/sys-cfg-bundle.sh b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/sys-cfg-bundle.sh new file mode 100755 index 0000000000000..64c34088ebf53 --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/scripts/sys-cfg-bundle.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Grab the script directory +SCRIPT_DIR=$(dirname "$0") + +# Load common.sh +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/common.sh" + +# Check the env +reqenv "ETH_RPC_URL" +reqenv "OUTPUT_FOLDER_PATH" +reqenv "PROXY_ADMIN_ADDR" +reqenv "SYSTEM_CONFIG_PROXY_ADDR" +reqenv "SYSTEM_CONFIG_IMPL" + +# Local environment +BUNDLE_PATH="$OUTPUT_FOLDER_PATH/sys_cfg_bundle.json" +L1_CHAIN_ID=$(cast chain-id) + +# Copy the bundle template +cp ./templates/sys_cfg_upgrade_bundle_template.json "$BUNDLE_PATH" + +# Tx 1: Upgrade SystemConfigProxy implementation +TX_1_PAYLOAD=$(cast calldata "upgrade(address,address)" "$SYSTEM_CONFIG_PROXY_ADDR" "$SYSTEM_CONFIG_IMPL") + +# Replace variables +sed -i '' "s/\$L1_CHAIN_ID/$L1_CHAIN_ID/g" "$BUNDLE_PATH" +sed -i '' "s/\$PROXY_ADMIN_ADDR/$PROXY_ADMIN_ADDR/g" "$BUNDLE_PATH" +sed -i '' "s/\$SYSTEM_CONFIG_PROXY_ADDR/$SYSTEM_CONFIG_PROXY_ADDR/g" "$BUNDLE_PATH" +sed -i '' "s/\$SYSTEM_CONFIG_IMPL/$SYSTEM_CONFIG_IMPL/g" "$BUNDLE_PATH" +sed -i '' "s/\$TX_1_PAYLOAD/$TX_1_PAYLOAD/g" "$BUNDLE_PATH" + +echo "✨ Generated SystemConfig upgrade bundle at \"$BUNDLE_PATH\"" diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/templates/fdg_bundle_extension.json b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/fdg_bundle_extension.json new file mode 100644 index 0000000000000..fa6680496bdb8 --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/fdg_bundle_extension.json @@ -0,0 +1,29 @@ +{ + "metadata": { + "name": "Upgrade `CANNON` game type in `DisputeGameFactory`", + "description": "Upgrades the `CANNON` game type to the new Holocene deployment, with an updated version of `op-program` as the absolute prestate hash." + }, + "to": "$DISPUTE_GAME_FACTORY_PROXY_ADDR", + "value": "0x0", + "data": "$TX_2_PAYLOAD", + "contractMethod": { + "type": "function", + "name": "setImplementation", + "inputs": [ + { + "name": "_gameType", + "type": "uint32" + }, + { + "name": "_impl", + "type": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + "contractInputsValues": { + "_gameType": "0", + "_impl": "$FDG_IMPL" + } +} diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/templates/proof_upgrade_bundle_template.json b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/proof_upgrade_bundle_template.json new file mode 100644 index 0000000000000..e74360f02a97c --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/proof_upgrade_bundle_template.json @@ -0,0 +1,38 @@ +{ + "chainId": $L1_CHAIN_ID, + "metadata": { + "name": "Holocene Hardfork - Proof Contract Upgrades", + "description": "Upgrades the `MIPS.sol`, `FaultDisputeGame.sol`, and `PermissionedDisputeGame.sol` contracts for Holocene." + }, + "transactions": [ + { + "metadata": { + "name": "Upgrade `PERMISSIONED_CANNON` game type in `DisputeGameFactory`", + "description": "Upgrades the `PERMISSIONED_CANNON` game type to the new Holocene deployment, with an updated version of `op-program` as the absolute prestate hash." + }, + "to": "$DISPUTE_GAME_FACTORY_PROXY_ADDR", + "value": "0x0", + "data": "$TX_1_PAYLOAD", + "contractMethod": { + "type": "function", + "name": "setImplementation", + "inputs": [ + { + "name": "_gameType", + "type": "uint32" + }, + { + "name": "_impl", + "type": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + "contractInputsValues": { + "_gameType": "1", + "_impl": "$PDG_IMPL" + } + } + ] +} diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/templates/proofs-sc-ops-task/.env.example b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/proofs-sc-ops-task/.env.example new file mode 100644 index 0000000000000..ba2beff7f4291 --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/proofs-sc-ops-task/.env.example @@ -0,0 +1,6 @@ +ETH_RPC_URL= +SUPERCHAIN_CONFIG_ADDR= +COUNCIL_SAFE= +FOUNDATION_SAFE= +OWNER_SAFE= +SAFE_NONCE= diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/templates/proofs-sc-ops-task/README.md b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/proofs-sc-ops-task/README.md new file mode 100644 index 0000000000000..e2077747dba12 --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/proofs-sc-ops-task/README.md @@ -0,0 +1,46 @@ +# Holocene Hardfork Upgrade + +Status: DRAFT, NOT READY TO SIGN + +## Objective + +Upgrades the Fault Proof contracts for the Holocene hardfork. + +The proposal was: + +- [ ] Posted on the governance forum. +- [ ] Approved by Token House voting. +- [ ] Not vetoed by the Citizens' house. +- [ ] Executed on OP Mainnet. + +The governance proposal should be treated as the source of truth and used to verify the correctness of the onchain operations. + +Governance post of the upgrade can be found at . + +This upgrades the Fault Proof contracts in the +[op-contracts/v1.8.0](https://github.com/ethereum-optimism/optimism/tree/op-contracts/v1.8.0-rc.1) release. + +## Pre-deployments + +- `MIPS` - `$MIPS_IMPL` +- `FaultDisputeGame` - `$FDG_IMPL` +- `PermissionedDisputeGame` - `$PDG_IMPL` + +## Simulation + +Please see the "Simulating and Verifying the Transaction" instructions in [NESTED.md](../../../NESTED.md). +When simulating, ensure the logs say `Using script /your/path/to/superchain-ops/tasks//NestedSignFromJson.s.sol`. +This ensures all safety checks are run. If the default `NestedSignFromJson.s.sol` script is shown (without the full path), something is wrong and the safety checks will not run. + +## State Validation + +Please see the instructions for [validation](./VALIDATION.md). + +## Execution + +This upgrade +* Changes dispute game implementation of the `CANNON` and `PERMISSIONED_CANNON` game types to contain a `op-program` release for the Holocene hardfork, which contains + the Holocene fork implementation as well as a `ChainConfig` and `RollupConfig` for the L2 chain being upgraded. +* Upgrades `MIPS.sol` to support the `F_GETFD` syscall, required by the golang 1.22+ runtime. + +See the [overview](./OVERVIEW.md) and `input.json` bundle for more details. diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/templates/proofs-sc-ops-task/VALIDATION.md b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/proofs-sc-ops-task/VALIDATION.md new file mode 100644 index 0000000000000..50ba3ca106b46 --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/proofs-sc-ops-task/VALIDATION.md @@ -0,0 +1,24 @@ +# Validation + +This document can be used to validate the state diff resulting from the execution of the upgrade +transaction. + +For each contract listed in the state diff, please verify that no contracts or state changes shown in the Tenderly diff are missing from this document. Additionally, please verify that for each contract: + +- The following state changes (and none others) are made to that contract. This validates that no unexpected state changes occur. +- All addresses (in section headers and storage values) match the provided name, using the Etherscan and Superchain Registry links provided. This validates the bytecode deployed at the addresses contains the correct logic. +- All key values match the semantic meaning provided, which can be validated using the storage layout links provided. + +## State Changes + +### `$DISPUTE_GAME_FACTORY_PROXY_ADDR` (`DisputeGameFactoryProxy`) + +- **Key**: `0xffdfc1249c027f9191656349feb0761381bb32c9f557e01f419fd08754bf5a1b`
+ **Before**: `$OLD_FDG`
+ **After**: `$FDG_IMPL`
+ **Meaning**: Updates the CANNON game type implementation. Verify that the new implementation is set using `cast call $DISPUTE_GAME_FACTORY_PROXY_ADDR "gameImpls(uint32)(address)" 0`. Where `0` is the [`CANNON` game type](https://github.com/ethereum-optimism/optimism/blob/op-contracts/v1.4.0/packages/contracts-bedrock/src/dispute/lib/Types.sol#L28). + +- **Key**: `0x4d5a9bd2e41301728d41c8e705190becb4e74abe869f75bdb405b63716a35f9e`
+ **Before**: `$OLD_PDG`
+ **After**: `$PDG_IMPL`
+ **Meaning**: Updates the PERMISSIONED_CANNON game type implementation. Verify that the new implementation is set using `cast call $DISPUTE_GAME_FACTORY_PROXY_ADDR "gameImpls(uint32)(address)" 1`. Where `1` is the [`PERMISSIONED_CANNON` game type](https://github.com/ethereum-optimism/optimism/blob/op-contracts/v1.4.0/packages/contracts-bedrock/src/dispute/lib/Types.sol#L31). diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/templates/sys-cfg-sc-ops-task/.env.example b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/sys-cfg-sc-ops-task/.env.example new file mode 100644 index 0000000000000..ba2beff7f4291 --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/sys-cfg-sc-ops-task/.env.example @@ -0,0 +1,6 @@ +ETH_RPC_URL= +SUPERCHAIN_CONFIG_ADDR= +COUNCIL_SAFE= +FOUNDATION_SAFE= +OWNER_SAFE= +SAFE_NONCE= diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/templates/sys-cfg-sc-ops-task/README.md b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/sys-cfg-sc-ops-task/README.md new file mode 100644 index 0000000000000..740219586b80f --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/sys-cfg-sc-ops-task/README.md @@ -0,0 +1,42 @@ +# Holocene Hardfork Upgrade - `SystemConfig` + +Status: DRAFT, NOT READY TO SIGN + +## Objective + +Upgrades the `SystemConfig` for the Holocene hardfork. + +The proposal was: + +- [ ] Posted on the governance forum. +- [ ] Approved by Token House voting. +- [ ] Not vetoed by the Citizens' house. +- [ ] Executed on OP Mainnet. + +The governance proposal should be treated as the source of truth and used to verify the correctness of the onchain operations. + +Governance post of the upgrade can be found at . + +This upgrades the `SystemConfig` in the +[op-contracts/v1.8.0](https://github.com/ethereum-optimism/optimism/tree/op-contracts/v1.8.0-rc.1) release. + +## Pre-deployments + +- `SystemConfig` - `$SYSTEM_CONFIG_IMPL` + +## Simulation + +Please see the "Simulating and Verifying the Transaction" instructions in [NESTED.md](../../../NESTED.md). +When simulating, ensure the logs say `Using script /your/path/to/superchain-ops/tasks//NestedSignFromJson.s.sol`. +This ensures all safety checks are run. If the default `NestedSignFromJson.s.sol` script is shown (without the full path), something is wrong and the safety checks will not run. + +## State Validation + +Please see the instructions for [validation](./VALIDATION.md). + +## Execution + +This upgrade +* Changes the implementation of the `SystemConfig` to hold EIP-1559 parameters for the + +See the [overview](./OVERVIEW.md) and `input.json` bundle for more details. diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/templates/sys-cfg-sc-ops-task/VALIDATION.md b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/sys-cfg-sc-ops-task/VALIDATION.md new file mode 100644 index 0000000000000..3a5e7b67595aa --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/sys-cfg-sc-ops-task/VALIDATION.md @@ -0,0 +1,19 @@ +# Validation + +This document can be used to validate the state diff resulting from the execution of the upgrade +transaction. + +For each contract listed in the state diff, please verify that no contracts or state changes shown in the Tenderly diff are missing from this document. Additionally, please verify that for each contract: + +- The following state changes (and none others) are made to that contract. This validates that no unexpected state changes occur. +- All addresses (in section headers and storage values) match the provided name, using the Etherscan and Superchain Registry links provided. This validates the bytecode deployed at the addresses contains the correct logic. +- All key values match the semantic meaning provided, which can be validated using the storage layout links provided. + +## State Changes + +### `$SYSTEM_CONFIG_PROXY_ADDR` (`SystemConfigProxy`) + +- **Key**: `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc` + **Before**: `$OLD_SYS_CFG` + **After**: `$SYSTEM_CONFIG_IMPL` + **Meaning**: Updates the `SystemConfig` proxy implementation. diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/templates/sys_cfg_upgrade_bundle_template.json b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/sys_cfg_upgrade_bundle_template.json new file mode 100644 index 0000000000000..62746a51982fe --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/templates/sys_cfg_upgrade_bundle_template.json @@ -0,0 +1,38 @@ +{ + "chainId": $L1_CHAIN_ID, + "metadata": { + "name": "Holocene Hardfork - SystemConfig Upgrade", + "description": "Upgrades the `SystemConfig.sol` contract for Holocene." + }, + "transactions": [ + { + "metadata": { + "name": "Upgrade `SystemConfig` proxy", + "description": "Upgrades the `SystemConfig` proxy to the new implementation, featuring configurable EIP-1559 parameters." + }, + "to": "$PROXY_ADMIN_ADDR", + "value": "0x0", + "data": "$TX_1_PAYLOAD", + "contractMethod": { + "type": "function", + "name": "upgrade", + "inputs": [ + { + "name": "_proxy", + "type": "address" + }, + { + "name": "_implementation", + "type": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + "contractInputsValues": { + "_proxy": "$SYSTEM_CONFIG_PROXY_ADDR", + "_implementation": "$SYSTEM_CONFIG_IMPL" + } + } + ] +} diff --git a/packages/contracts-bedrock/scripts/upgrades/holocene/upgrade.dockerfile b/packages/contracts-bedrock/scripts/upgrades/holocene/upgrade.dockerfile new file mode 100644 index 0000000000000..f91ff8dadd83e --- /dev/null +++ b/packages/contracts-bedrock/scripts/upgrades/holocene/upgrade.dockerfile @@ -0,0 +1,62 @@ +# Use a base image with necessary tools +FROM ubuntu:20.04 + +ARG REV + +# Install required packages +RUN apt-get update && apt-get install -y \ + git \ + bash \ + curl \ + build-essential \ + jq \ + && rm -rf /var/lib/apt/lists/* + +# Install Rust +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" + +# Install just +RUN curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin + +# Install msup +RUN git clone https://github.com/clabby/msup.git && \ + cd msup && \ + cargo install --path . + +# Install foundryup +RUN curl -L https://foundry.paradigm.xyz | bash +ENV PATH="/root/.foundry/bin:${PATH}" + +# Set the working directory +WORKDIR /app + +# Clone the repository +RUN git clone https://github.com/ethereum-optimism/optimism.git . + +# Check out the target branch +RUN git checkout $REV + +# Set the working directory to the root of the monorepo +WORKDIR /app + +# Install correct foundry version +RUN just update-foundry + +# Set the working directory to the root of the contracts package +WORKDIR /app/packages/contracts-bedrock + +# Install dependencies +RUN just install + +# Build the contracts package +RUN forge build + +# Deliberately run the upgrade script with invalid args to trigger a build +RUN forge script ./scripts/upgrades/holocene/DeployUpgrade.s.sol || true + +# Set the working directory to where upgrade.sh is located +WORKDIR /app/packages/contracts-bedrock/scripts/upgrades/holocene + +# Set the entrypoint to the main.sh script +ENTRYPOINT ["./scripts/main.sh"] diff --git a/packages/contracts-bedrock/.gas-snapshot b/packages/contracts-bedrock/snapshots/.gas-snapshot similarity index 97% rename from packages/contracts-bedrock/.gas-snapshot rename to packages/contracts-bedrock/snapshots/.gas-snapshot index 1b1a01905ba5f..2ab3157a714ee 100644 --- a/packages/contracts-bedrock/.gas-snapshot +++ b/packages/contracts-bedrock/snapshots/.gas-snapshot @@ -5,7 +5,7 @@ GasBenchMark_L1BlockInterop_SetValuesInterop_Warm:test_setL1BlockValuesInterop_b GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() (gas: 158531) GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7597) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 369280) -GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2967420) +GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2967465) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 564398) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4076613) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 467098) @@ -14,4 +14,4 @@ GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (g GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 92973) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 68422) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 68986) -GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 155610) \ No newline at end of file +GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 155565) \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/CrossL2Inbox.json b/packages/contracts-bedrock/snapshots/abi/CrossL2Inbox.json index 6f8c10e82eedf..47eeab3f07f14 100644 --- a/packages/contracts-bedrock/snapshots/abi/CrossL2Inbox.json +++ b/packages/contracts-bedrock/snapshots/abi/CrossL2Inbox.json @@ -55,7 +55,7 @@ "type": "uint256" } ], - "internalType": "struct ICrossL2Inbox.Identifier", + "internalType": "struct Identifier", "name": "_id", "type": "tuple" }, @@ -164,7 +164,7 @@ "type": "uint256" } ], - "internalType": "struct ICrossL2Inbox.Identifier", + "internalType": "struct Identifier", "name": "_id", "type": "tuple" }, @@ -230,7 +230,7 @@ } ], "indexed": false, - "internalType": "struct ICrossL2Inbox.Identifier", + "internalType": "struct Identifier", "name": "id", "type": "tuple" } diff --git a/packages/contracts-bedrock/snapshots/abi/DelayedVetoable.json b/packages/contracts-bedrock/snapshots/abi/DelayedVetoable.json deleted file mode 100644 index d76d1c8b108b9..0000000000000 --- a/packages/contracts-bedrock/snapshots/abi/DelayedVetoable.json +++ /dev/null @@ -1,207 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "address", - "name": "_vetoer", - "type": "address" - }, - { - "internalType": "address", - "name": "_initiator", - "type": "address" - }, - { - "internalType": "address", - "name": "_target", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_operatingDelay", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "stateMutability": "nonpayable", - "type": "fallback" - }, - { - "inputs": [], - "name": "delay", - "outputs": [ - { - "internalType": "uint256", - "name": "delay_", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "initiator", - "outputs": [ - { - "internalType": "address", - "name": "initiator_", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "_callHash", - "type": "bytes32" - } - ], - "name": "queuedAt", - "outputs": [ - { - "internalType": "uint256", - "name": "queuedAt_", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "target", - "outputs": [ - { - "internalType": "address", - "name": "target_", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "vetoer", - "outputs": [ - { - "internalType": "address", - "name": "vetoer_", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint256", - "name": "delay", - "type": "uint256" - } - ], - "name": "DelayActivated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "callHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "Forwarded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "callHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "Initiated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "callHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "Vetoed", - "type": "event" - }, - { - "inputs": [], - "name": "ForwardingEarly", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "expected", - "type": "address" - }, - { - "internalType": "address", - "name": "actual", - "type": "address" - } - ], - "name": "Unauthorized", - "type": "error" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/DelayedWETH.json b/packages/contracts-bedrock/snapshots/abi/DelayedWETH.json index a84394e6b0036..a6f0dd660468f 100644 --- a/packages/contracts-bedrock/snapshots/abi/DelayedWETH.json +++ b/packages/contracts-bedrock/snapshots/abi/DelayedWETH.json @@ -22,12 +22,12 @@ "inputs": [ { "internalType": "address", - "name": "", + "name": "owner", "type": "address" }, { "internalType": "address", - "name": "", + "name": "spender", "type": "address" } ], @@ -70,7 +70,7 @@ "inputs": [ { "internalType": "address", - "name": "", + "name": "src", "type": "address" } ], diff --git a/packages/contracts-bedrock/snapshots/abi/L2ToL2CrossDomainMessenger.json b/packages/contracts-bedrock/snapshots/abi/L2ToL2CrossDomainMessenger.json index daefa3a74386e..6434233930dbc 100644 --- a/packages/contracts-bedrock/snapshots/abi/L2ToL2CrossDomainMessenger.json +++ b/packages/contracts-bedrock/snapshots/abi/L2ToL2CrossDomainMessenger.json @@ -99,7 +99,7 @@ "type": "uint256" } ], - "internalType": "struct ICrossL2Inbox.Identifier", + "internalType": "struct Identifier", "name": "_id", "type": "tuple" }, diff --git a/packages/contracts-bedrock/snapshots/abi/MIPS2.json b/packages/contracts-bedrock/snapshots/abi/MIPS2.json index 2294e23e754e5..348868bfba0ad 100644 --- a/packages/contracts-bedrock/snapshots/abi/MIPS2.json +++ b/packages/contracts-bedrock/snapshots/abi/MIPS2.json @@ -45,7 +45,7 @@ "outputs": [ { "internalType": "bytes32", - "name": "", + "name": "postState_", "type": "bytes32" } ], diff --git a/packages/contracts-bedrock/snapshots/abi/MIPS64.json b/packages/contracts-bedrock/snapshots/abi/MIPS64.json new file mode 100644 index 0000000000000..a12c96c7a70db --- /dev/null +++ b/packages/contracts-bedrock/snapshots/abi/MIPS64.json @@ -0,0 +1,93 @@ +[ + { + "inputs": [ + { + "internalType": "contract IPreimageOracle", + "name": "_oracle", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "oracle", + "outputs": [ + { + "internalType": "contract IPreimageOracle", + "name": "oracle_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_stateData", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "_proof", + "type": "bytes" + }, + { + "internalType": "bytes32", + "name": "_localContext", + "type": "bytes32" + } + ], + "name": "step", + "outputs": [ + { + "internalType": "bytes32", + "name": "postState_", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "InvalidExitedValue", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidMemoryProof", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidPC", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidRMWInstruction", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidSecondMemoryProof", + "type": "error" + } +] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json index 7c478feb235d4..b5758eca610f7 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json @@ -10,6 +10,110 @@ "internalType": "contract IProtocolVersions", "name": "_protocolVersions", "type": "address" + }, + { + "internalType": "string", + "name": "_l1ContractsRelease", + "type": "string" + }, + { + "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": "address", + "name": "anchorStateRegistry", + "type": "address" + }, + { + "internalType": "address", + "name": "permissionedDisputeGame1", + "type": "address" + }, + { + "internalType": "address", + "name": "permissionedDisputeGame2", + "type": "address" + } + ], + "internalType": "struct OPContractsManager.Blueprints", + "name": "_blueprints", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "l1ERC721BridgeImpl", + "type": "address" + }, + { + "internalType": "address", + "name": "optimismPortalImpl", + "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": "delayedWETHImpl", + "type": "address" + }, + { + "internalType": "address", + "name": "mipsImpl", + "type": "address" + } + ], + "internalType": "struct OPContractsManager.Implementations", + "name": "_implementations", + "type": "tuple" } ], "stateMutability": "nonpayable", @@ -298,138 +402,68 @@ "type": "function" }, { - "inputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - }, - { - "internalType": "string", - "name": "", - "type": "string" - } - ], + "inputs": [], "name": "implementations", "outputs": [ - { - "internalType": "address", - "name": "logic", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "initializer", - "type": "bytes4" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ { "components": [ { - "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": "address", - "name": "anchorStateRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "permissionedDisputeGame1", - "type": "address" - }, - { - "internalType": "address", - "name": "permissionedDisputeGame2", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Blueprints", - "name": "blueprints", - "type": "tuple" + "internalType": "address", + "name": "l1ERC721BridgeImpl", + "type": "address" }, { - "components": [ - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "components": [ - { - "internalType": "address", - "name": "logic", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "initializer", - "type": "bytes4" - } - ], - "internalType": "struct OPContractsManager.Implementation", - "name": "info", - "type": "tuple" - } - ], - "internalType": "struct OPContractsManager.ImplementationSetter[]", - "name": "setters", - "type": "tuple[]" + "internalType": "address", + "name": "optimismPortalImpl", + "type": "address" }, { - "internalType": "string", - "name": "release", - "type": "string" + "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": "bool", - "name": "isLatest", - "type": "bool" + "internalType": "address", + "name": "disputeGameFactoryImpl", + "type": "address" + }, + { + "internalType": "address", + "name": "delayedWETHImpl", + "type": "address" + }, + { + "internalType": "address", + "name": "mipsImpl", + "type": "address" } ], - "internalType": "struct OPContractsManager.InitializerInputs", - "name": "_initializerInputs", + "internalType": "struct OPContractsManager.Implementations", + "name": "", "type": "tuple" } ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "latestRelease", + "name": "l1ContractsRelease", "outputs": [ { "internalType": "string", @@ -529,19 +563,6 @@ "name": "Deployed", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, { "inputs": [ { diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInterop.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInterop.json index 7c478feb235d4..b5758eca610f7 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInterop.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInterop.json @@ -10,6 +10,110 @@ "internalType": "contract IProtocolVersions", "name": "_protocolVersions", "type": "address" + }, + { + "internalType": "string", + "name": "_l1ContractsRelease", + "type": "string" + }, + { + "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": "address", + "name": "anchorStateRegistry", + "type": "address" + }, + { + "internalType": "address", + "name": "permissionedDisputeGame1", + "type": "address" + }, + { + "internalType": "address", + "name": "permissionedDisputeGame2", + "type": "address" + } + ], + "internalType": "struct OPContractsManager.Blueprints", + "name": "_blueprints", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "l1ERC721BridgeImpl", + "type": "address" + }, + { + "internalType": "address", + "name": "optimismPortalImpl", + "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": "delayedWETHImpl", + "type": "address" + }, + { + "internalType": "address", + "name": "mipsImpl", + "type": "address" + } + ], + "internalType": "struct OPContractsManager.Implementations", + "name": "_implementations", + "type": "tuple" } ], "stateMutability": "nonpayable", @@ -298,138 +402,68 @@ "type": "function" }, { - "inputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - }, - { - "internalType": "string", - "name": "", - "type": "string" - } - ], + "inputs": [], "name": "implementations", "outputs": [ - { - "internalType": "address", - "name": "logic", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "initializer", - "type": "bytes4" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ { "components": [ { - "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": "address", - "name": "anchorStateRegistry", - "type": "address" - }, - { - "internalType": "address", - "name": "permissionedDisputeGame1", - "type": "address" - }, - { - "internalType": "address", - "name": "permissionedDisputeGame2", - "type": "address" - } - ], - "internalType": "struct OPContractsManager.Blueprints", - "name": "blueprints", - "type": "tuple" + "internalType": "address", + "name": "l1ERC721BridgeImpl", + "type": "address" }, { - "components": [ - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "components": [ - { - "internalType": "address", - "name": "logic", - "type": "address" - }, - { - "internalType": "bytes4", - "name": "initializer", - "type": "bytes4" - } - ], - "internalType": "struct OPContractsManager.Implementation", - "name": "info", - "type": "tuple" - } - ], - "internalType": "struct OPContractsManager.ImplementationSetter[]", - "name": "setters", - "type": "tuple[]" + "internalType": "address", + "name": "optimismPortalImpl", + "type": "address" }, { - "internalType": "string", - "name": "release", - "type": "string" + "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": "bool", - "name": "isLatest", - "type": "bool" + "internalType": "address", + "name": "disputeGameFactoryImpl", + "type": "address" + }, + { + "internalType": "address", + "name": "delayedWETHImpl", + "type": "address" + }, + { + "internalType": "address", + "name": "mipsImpl", + "type": "address" } ], - "internalType": "struct OPContractsManager.InitializerInputs", - "name": "_initializerInputs", + "internalType": "struct OPContractsManager.Implementations", + "name": "", "type": "tuple" } ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { "inputs": [], - "name": "latestRelease", + "name": "l1ContractsRelease", "outputs": [ { "internalType": "string", @@ -529,19 +563,6 @@ "name": "Deployed", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, { "inputs": [ { diff --git a/packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json b/packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json index d6ad63fad9c34..24ac8a88fab40 100644 --- a/packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json +++ b/packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json @@ -456,7 +456,7 @@ "type": "uint256" } ], - "name": "CrosschainBurnt", + "name": "CrosschainBurn", "type": "event" }, { @@ -475,7 +475,7 @@ "type": "uint256" } ], - "name": "CrosschainMinted", + "name": "CrosschainMint", "type": "event" }, { diff --git a/packages/contracts-bedrock/snapshots/abi/SuperchainTokenBridge.json b/packages/contracts-bedrock/snapshots/abi/SuperchainTokenBridge.json index 36358db1b307a..a75bb2ba7234b 100644 --- a/packages/contracts-bedrock/snapshots/abi/SuperchainTokenBridge.json +++ b/packages/contracts-bedrock/snapshots/abi/SuperchainTokenBridge.json @@ -153,6 +153,11 @@ "name": "InvalidCrossDomainSender", "type": "error" }, + { + "inputs": [], + "name": "InvalidERC7802", + "type": "error" + }, { "inputs": [], "name": "Unauthorized", diff --git a/packages/contracts-bedrock/snapshots/abi/SuperchainWETH.json b/packages/contracts-bedrock/snapshots/abi/SuperchainWETH.json index 59e959f9f2313..32d84df7d889e 100644 --- a/packages/contracts-bedrock/snapshots/abi/SuperchainWETH.json +++ b/packages/contracts-bedrock/snapshots/abi/SuperchainWETH.json @@ -11,12 +11,12 @@ "inputs": [ { "internalType": "address", - "name": "", + "name": "owner", "type": "address" }, { "internalType": "address", - "name": "", + "name": "spender", "type": "address" } ], @@ -59,7 +59,7 @@ "inputs": [ { "internalType": "address", - "name": "", + "name": "src", "type": "address" } ], @@ -143,6 +143,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "_interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "symbol", @@ -289,7 +308,7 @@ "type": "uint256" } ], - "name": "CrosschainBurnt", + "name": "CrosschainBurn", "type": "event" }, { @@ -308,7 +327,7 @@ "type": "uint256" } ], - "name": "CrosschainMinted", + "name": "CrosschainMint", "type": "event" }, { diff --git a/packages/contracts-bedrock/snapshots/abi/WETH.json b/packages/contracts-bedrock/snapshots/abi/WETH.json index 9430e99a4c857..03cf2880ccce0 100644 --- a/packages/contracts-bedrock/snapshots/abi/WETH.json +++ b/packages/contracts-bedrock/snapshots/abi/WETH.json @@ -11,12 +11,12 @@ "inputs": [ { "internalType": "address", - "name": "", + "name": "owner", "type": "address" }, { "internalType": "address", - "name": "", + "name": "spender", "type": "address" } ], @@ -59,7 +59,7 @@ "inputs": [ { "internalType": "address", - "name": "", + "name": "src", "type": "address" } ], diff --git a/packages/contracts-bedrock/snapshots/abi/WETH98.json b/packages/contracts-bedrock/snapshots/abi/WETH98.json index 364d6b0591dc0..019b5c37a1af9 100644 --- a/packages/contracts-bedrock/snapshots/abi/WETH98.json +++ b/packages/contracts-bedrock/snapshots/abi/WETH98.json @@ -11,12 +11,12 @@ "inputs": [ { "internalType": "address", - "name": "", + "name": "owner", "type": "address" }, { "internalType": "address", - "name": "", + "name": "spender", "type": "address" } ], @@ -59,7 +59,7 @@ "inputs": [ { "internalType": "address", - "name": "", + "name": "src", "type": "address" } ], diff --git a/packages/contracts-bedrock/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json similarity index 64% rename from packages/contracts-bedrock/semver-lock.json rename to packages/contracts-bedrock/snapshots/semver-lock.json index e73dd3b4527eb..5ba3a4b6a165d 100644 --- a/packages/contracts-bedrock/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -1,31 +1,27 @@ { "src/L1/DataAvailabilityChallenge.sol": { - "initCodeHash": "0xbd00d6568abab3e7fc211c40d682862242f25493010a4a097bd1f3b45c8c87c3", - "sourceCodeHash": "0x58b587034a67b4bb718abbaded8ac23b082c0971105874bcc42c23f051c67f6e" - }, - "src/L1/DelayedVetoable.sol": { - "initCodeHash": "0x9fe8ade6f6332262ff1f3539ac0bf57660edbad3cf4c4cb230c2ddac18aa0a3f", - "sourceCodeHash": "0x30e83a535ef27b2e900c831c4e1a4ec2750195350011c4fdacda1da9db2d167b" + "initCodeHash": "0x240a9b695e1ab73692672b907c2ae147ee9224e95a03c02d99333afe186c3d2f", + "sourceCodeHash": "0xc6ab0e64cfbdcfa6de0a480426263712b3ddbabe56a88ec7c02556cb432e6b02" }, "src/L1/L1CrossDomainMessenger.sol": { "initCodeHash": "0x2e9cb3ceb5e55341b311f0666ef7655df4fafae75afdfbcd701cd9c9b2b017d5", "sourceCodeHash": "0x848ec3774be17bcc8ba65a23d08e35e979b3f39f9d2ac8a810188f945c69c9ea" }, "src/L1/L1ERC721Bridge.sol": { - "initCodeHash": "0x63dc4da75200f4b968f57e27e81834e6eb3f6625826410882526ab1eec7847ff", - "sourceCodeHash": "0xfec29cfbb7aa05473e32a6c2484deebfc1ff50c0e08c42e8ee70696ad701ceaa" + "initCodeHash": "0xb3bf093ea83a24574a6093bebf5b2aea707355ed8d6702b2b5eb292e75b6ae42", + "sourceCodeHash": "0x289de9f40898b6305deecc6b60cdf566aa6c6a1444f713c3a0af23ea7878207e" }, "src/L1/L1StandardBridge.sol": { - "initCodeHash": "0x2868b09ecbe9f2bbc885605c2886b4c79f1c8e4171626c63776603b1b84698a8", - "sourceCodeHash": "0xc03da137b3ea72e0109fb284229283b21a0303104afbe37d2fe86ad806392a7f" + "initCodeHash": "0x802f72745bb9a82dc049377bb9cf6b58f35aec388aeb957b28a5e14f28d91bc1", + "sourceCodeHash": "0x24b784645b065a5393a2115a078d67f91eb09afd5e70baf81daf975381f16155" }, "src/L1/L2OutputOracle.sol": { "initCodeHash": "0x1182bfb87c4ab399b912ca7fe18cdbf4b24c414e078fb0a55bd3c44d442d3ed1", "sourceCodeHash": "0x4132ff37d267cb12224b75ea806c0aa7d25407b0d66ce526d7fcda8f7d223882" }, "src/L1/OPContractsManager.sol": { - "initCodeHash": "0xd58cb3978affc5c1457cdd498ff8420c90aef804d4c3b62cf42ab2691986d6d2", - "sourceCodeHash": "0x7bfa6eff76176649fe600303cd60009a0f6e282cbaec55836b5ea1f8875cbeb5" + "initCodeHash": "0xd038cc35325d023499151264232d75fa4ecc81f04a8c8353e6b50c43af224d6e", + "sourceCodeHash": "0xa13f3ab2b8744015290dbabe5f20fdd44774607e6a7ad3e5e016303fc4aa8c12" }, "src/L1/OptimismPortal.sol": { "initCodeHash": "0x152167cfa18635ae4918a6eb3371a599cfa084418c0a652799cdb48bfc0ee0cc", @@ -48,20 +44,20 @@ "sourceCodeHash": "0x39489a85bc3a5c8560f82d41b31bf7fe22f5b648f4ed538f61695a73092ea9eb" }, "src/L1/SystemConfig.sol": { - "initCodeHash": "0x429058f75d97fa7a7d0166b59830909bc722324feefc40f2b41419d6335d3f37", - "sourceCodeHash": "0x5ca776041a4ddc0d28ec55db7012d669481cd4601b0e71dbd3493a67b8a7e5a5" + "initCodeHash": "0x0eda38e2fb2687a324289f04ec8ad0d2afe51f45219d074740fb4a0e24ea6569", + "sourceCodeHash": "0x6dbbe8716ca8cd2fba3da8dcae0ca0c4b1f3e9dd04220fb24a15666b23300927" }, "src/L1/SystemConfigInterop.sol": { - "initCodeHash": "0x277a61dcabed81a15739a8e9ed50615252bcc687cebea852e00191d0a1fbe11f", - "sourceCodeHash": "0x38361a4f70a19e1b7819e933932a0c9fd2bcebaaebcbc7942f5c00dfaa2c28df" + "initCodeHash": "0x443fd84f8dbc38f03e59a56b99099b5e4b28de3e860a5d16c1a21101745622a4", + "sourceCodeHash": "0x5c2e00cd8939a538eb38580d76e70d27dd1e8e6cd9328e1978468981017736e6" }, "src/L2/BaseFeeVault.sol": { "initCodeHash": "0xbf49824cf37e201181484a8a423fcad8f504dc925921a2b28e83398197858dec", "sourceCodeHash": "0x983e8e248c61e362ba6a01dd2e217a535c9bb828dc0b4421f5f27e0577f2e14c" }, "src/L2/CrossL2Inbox.sol": { - "initCodeHash": "0x66b052adce7e9194d054952d67d08b53964120067600358243ec86c85b90877b", - "sourceCodeHash": "0x38e6127ec6be99eb8c38c2c9d6e82761b33dde446bba250dc2c1b84983449e4e" + "initCodeHash": "0x31ecaebf368ab3333e80c6dc004b3c9f9a31f813c3138ab388bb3eead9f1b4ee", + "sourceCodeHash": "0xa1779d84a14332dcdd167293171d0fe2629d759a23d7cc34ffe2bde7e1605dbc" }, "src/L2/ETHLiquidity.sol": { "initCodeHash": "0x713c18f95a6a746d0703f475f3ae10c106c9b9ecb64d881a2e61b8969b581371", @@ -88,28 +84,28 @@ "sourceCodeHash": "0x56edf0f36366326a92722ae3c7502bce3d80b2ee5e354181dc09ba801437a488" }, "src/L2/L2ERC721Bridge.sol": { - "initCodeHash": "0x558fff5939a26b9d5d86e6b907d9dd9c7c917eaef7657a8b5acfeb58de1442f0", - "sourceCodeHash": "0xca9acd19fd5f42e6a7a5b1de6359f2d841814fb54d377664c2fe9c3f9c6be34a" + "initCodeHash": "0xaed0528e8b81817a0c3b41513c02e7fd678f58e34b98f02ea33d5a770a064c2f", + "sourceCodeHash": "0xf8569c75b801f38f8a5a41e94e90f159ddc5f5412804b26e3e564755a50631b8" }, "src/L2/L2StandardBridge.sol": { - "initCodeHash": "0x651eed10044d0b19b7e4eba864345df15e252be1401f39a552ec0d2f9c4df064", - "sourceCodeHash": "0xb55e58b5d4912edf05026878a5f5ac8019372212ed2a77843775d595fbf51b84" + "initCodeHash": "0xcb4aa19f0cd43a35cb5c65f26c3cfd7c41f1d1e5bcc15aef6096d385df7272c9", + "sourceCodeHash": "0x89771b53b7f6e64d943afb2a4bf15395efcf20d5302b76a18e52fa7cce8cdc56" }, "src/L2/L2StandardBridgeInterop.sol": { - "initCodeHash": "0xd43d07c2ba5a73af56181c0221c28f3b495851b03cf8e35f9b009857bb9538a6", - "sourceCodeHash": "0x36087332a4365ee172eed8fa35aa48e804b08279e97332058a588c2d4ae30c6b" + "initCodeHash": "0xc4eaece28d2cfca3c51247c3cce320a167a83c7fd13aea5736549d2b25e0b139", + "sourceCodeHash": "0x9e80044adf5f83c30b520ee153b75be5a152081c9e1271e7e618ecfccd1fb4ac" }, "src/L2/L2ToL1MessagePasser.sol": { "initCodeHash": "0x13fe3729beb9ed966c97bef09acb9fe5043fe651d453145073d05f2567fa988d", "sourceCodeHash": "0xd08a2e6514dbd44e16aa312a1b27b2841a9eab5622cbd05a39c30f543fad673c" }, "src/L2/L2ToL2CrossDomainMessenger.sol": { - "initCodeHash": "0x6eb3718548d97b69c201a75c27a3a5a77400ebd5e0a9bdcc06e2cc28f9b4a689", - "sourceCodeHash": "0x4bb08a8a9d5de37d1fb2dd8a9bcc483305510c32508f0be2d54757e6e257aedb" + "initCodeHash": "0x2a1a1ee4f47175ce661ee8e4e50cfa879b082dcb5278b1d66ddda00ed77bb744", + "sourceCodeHash": "0xa76133db7f449ae742f9ba988ad86ccb5672475f61298b9fefe411b63b63e9f6" }, "src/L2/OptimismSuperchainERC20.sol": { - "initCodeHash": "0x4e25579079d73c93f1d494e1976334b77fc4ec181c67f376d8e2613c7b207f52", - "sourceCodeHash": "0xe41cf3b005f1ea007fc1b5f69f630be5f6ef12d6e5e94a50e3160b0ebe0a1613" + "initCodeHash": "0x5bc5824030ecdb531e1f615d207cb73cdaa702e198769445d0ddbe717271eba9", + "sourceCodeHash": "0x0819c9411a155dca592d19b60c4176954202e4fe5d632a4ffbf88d465461252c" }, "src/L2/OptimismSuperchainERC20Beacon.sol": { "initCodeHash": "0x23dba3ceb9e58646695c306996c9e15251ac79acc6339c1a93d10a4c79da6dab", @@ -125,27 +121,31 @@ }, "src/L2/SuperchainERC20.sol": { "initCodeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "sourceCodeHash": "0x6a384ccfb6f2f7316c1b33873a1630b5179e52475951d31771656e06d2b11519" + "sourceCodeHash": "0xcf39c16893cace1e7d61350bfff05a27f3ce8da8eb0ac02cb5ac7bf603f163fa" }, "src/L2/SuperchainTokenBridge.sol": { - "initCodeHash": "0xef7590c30630a75f105384e339e52758569c25a5aa0a5934c521e004b8f86220", - "sourceCodeHash": "0x4f539e9d9096d31e861982b8f751fa2d7de0849590523375cf92e175294d1036" + "initCodeHash": "0x1cd2afdae6dd1b6ebc17f1d529e7d74c9b8b21b02db8589b8e389e2d5523d775", + "sourceCodeHash": "0x617aa994f659c5d8ebd54128d994f86f5b175ceca095b024b8524a7898e8ae62" }, "src/L2/SuperchainWETH.sol": { - "initCodeHash": "0x09c7efed7d6c8ae5981f6e7a75c7b8c675f73d679265d15a010844ad9b41fa9b", - "sourceCodeHash": "0x8d7612a71deaadfb324c4136673df96019211292ff54494fa4b7724e2e5dd22a" + "initCodeHash": "0x5aef986a7c9c102b1e9b3068e2a2b66adce0a71dd5f39e03694622bf494f8d97", + "sourceCodeHash": "0xa62101a23b860e97f393027c898082a1c73d50679eceb6c6793844af29702359" }, "src/L2/WETH.sol": { - "initCodeHash": "0xfb253765520690623f177941c2cd9eba23e4c6d15063bccdd5e98081329d8956", - "sourceCodeHash": "0x2ab6be69795109a1ee04c5693a34d6ce0ff90b62e404cdeb18178bab18d06784" + "initCodeHash": "0x17ea1b1c5d5a622d51c2961fde886a5498de63584e654ed1d69ee80dddbe0b17", + "sourceCodeHash": "0x0fa0633a769e73f5937514c0003ba7947a1c275bbe5b85d78879c42f0ed8895b" }, "src/cannon/MIPS.sol": { - "initCodeHash": "0x8fb590d45fa06fdc7ae55860827d6b1abf070c9dc5e18cd28176e844fa1da6c9", - "sourceCodeHash": "0x01d3d59020ec29ce78f68f977da5b7754455743121bda65626509864ab6c9da9" + "initCodeHash": "0xa3cbf121bad13c00227ea4fef128853d9a86b7ec9158de894f99b58d38d7630a", + "sourceCodeHash": "0xd8467700c80b3e62fa37193dc6513bac35282094b686b50e162e157f704dde00" }, "src/cannon/MIPS2.sol": { - "initCodeHash": "0x88acf3297642c2c9e0c1e92b48f59f7015915f25fb816cac44ee0073a1c93ccb", - "sourceCodeHash": "0x3dd89839f268569cbf2659beb42e3ac3c53887472cfc94a6e339d2b3a963b941" + "initCodeHash": "0xc38c76ab3aad78c81ca01b3235b402614972d6604b22fda1e870f1bf47be1194", + "sourceCodeHash": "0x3d38b1924669d1bde756f1306601c764a6d31f428ac72667a3dd194b3388210d" + }, + "src/cannon/MIPS64.sol": { + "initCodeHash": "0x93aa8d7f9fd3c22276c0d303a3fefdf8f73cc55807b35e483bba64c92d02aaef", + "sourceCodeHash": "0x171d66c651fdad2ac9c287da92689815a5b09589945ada092179508ad2326306" }, "src/cannon/PreimageOracle.sol": { "initCodeHash": "0x5d7e8ae64f802bd9d760e3d52c0a620bd02405dc2c8795818db9183792ffe81c", @@ -156,16 +156,16 @@ "sourceCodeHash": "0x1d918a536d9f6c900efdf069e96c2a27bb49340d6d1ebaa92dd6b481835a9a82" }, "src/dispute/DelayedWETH.sol": { - "initCodeHash": "0x835b322de7d5c84b415e99f2cb1000411df18995b5476f2116ac6f897f2d0910", - "sourceCodeHash": "0xdbd64724b73f8f9d6f1cc72bb662a99b9955ab72950a8f6ffeb1d2454997f60b" + "initCodeHash": "0xb31e0ff80fd69bc3f3b7d53f3fa42da4cdae393e41b8816719ce5ebe3d248688", + "sourceCodeHash": "0x1dfc68560c0805faa78360e3d4ef2d768e2f3d6c0c7183d2077a2c4277c778db" }, "src/dispute/DisputeGameFactory.sol": { "initCodeHash": "0xd72eced7cb5400d93188038a707fe6c1b04077f059cd8e2f5253e871de2cee3b", "sourceCodeHash": "0x9cb0851b6e471461f2bb369bd72eef4cffe8a0d1345546608a2aa6795540211d" }, "src/dispute/FaultDisputeGame.sol": { - "initCodeHash": "0xf97d35adc72c7bcbb5415ff1b183af0a4e3c951696d1dde213df61df50c848b9", - "sourceCodeHash": "0x27b4ab6f75004d01ff177b2b26e500a8ad06e906fcd36b920daa067f27f97da6" + "initCodeHash": "0xa352179f5055232764aac6b66a3ff5a6b3bfae2101d20c077f714b0ed7e40eef", + "sourceCodeHash": "0x730eff9147294c115a0a53e7e75771bcc4a517beb48457140ab929a8d1510893" }, "src/legacy/DeployerWhitelist.sol": { "initCodeHash": "0x0b8177ed75b69eddbb9ce6537683f69a9935efed86a1d6faa8feaafbd151c1bd", @@ -196,8 +196,8 @@ "sourceCodeHash": "0x3a0a294932d6deba043f6a2b46b4e8477ee96e7fb054d7e7229a43ce4352c68d" }, "src/safe/DeputyGuardianModule.sol": { - "initCodeHash": "0x308212d163aad169a5e42ce703a1ce36f5425ad96037850c0747177041f6596e", - "sourceCodeHash": "0xde1a289c1cb0bf92138daf8f3db7457be2f84bedaa111b536f646dd6e121718c" + "initCodeHash": "0xd95e562f395d4eb6e332f4474dffab660ada9e9da7c79f58fb6052278e0904df", + "sourceCodeHash": "0x45daabe094de0287e244e6fea4f1887b9adc09b07c47dc77361b1678645a1470" }, "src/safe/LivenessGuard.sol": { "initCodeHash": "0x9ac0b039b1591f7c00cf11cb758d118c9b42e6e08250b619d6b6fd605a43d5ee", @@ -208,20 +208,20 @@ "sourceCodeHash": "0xd1479c60087f352385b6d5379ef3cc07839f671d617626b4c94ece91da781ef2" }, "src/universal/OptimismMintableERC20.sol": { - "initCodeHash": "0x28c88484e1932253d6d12954492ac8a70744dc15c84429089af9944e5b158fd9", - "sourceCodeHash": "0x740b4043436d1b314ee3ba145acfcde60b6abd8416ea594f2b8e890b5d0bce6b" + "initCodeHash": "0x9cd677275b175812f1d5f90a127dbf7b3592714fd842a7a0de3988d716ca3eac", + "sourceCodeHash": "0x5611d8082f68af566554d7f09640b4b1f0e3efee4da1372b68fc7fc538a35ac7" }, "src/universal/OptimismMintableERC20Factory.sol": { - "initCodeHash": "0x9cd4102d3ca811d5dc67ae99ce7de95812264575a789f96a6057600e55dcab64", - "sourceCodeHash": "0xc70c8c11d6e754eabe746bbee47a5e1051f71f7a83913f62ebcce8db989a1357" + "initCodeHash": "0x03ad07bd7f89a29f1850fa8b5d377daf0e1d5aef6cb458a127df520549e8e8e6", + "sourceCodeHash": "0xdb6ec93782a4a217475195507740794a4f5553b9032e7ba31dc48b81f579a940" }, "src/universal/OptimismMintableERC721.sol": { - "initCodeHash": "0xec037be7fc28e072944b0a9e55d4278b92d6c68ccb41049ab52eafca59c6e023", - "sourceCodeHash": "0x5ea7c1b0cef5609f25c4193f5795fc9ce8f3ae08dbbf2945afe38e5af58f32c3" + "initCodeHash": "0x8aa309f2676d5267b6c9e411f88dc6e4badce414b8d66b330df3f60e9836380e", + "sourceCodeHash": "0x03bf7ad4d2b751bdead9930fc8f89b8e55d40dd4b2f5670fd339e87ae81f8b49" }, "src/universal/OptimismMintableERC721Factory.sol": { - "initCodeHash": "0x63d2ceafd3f3b3b54e31749574563e8022fef9c6da7bb8c7a113b3dbf571cfa2", - "sourceCodeHash": "0x705e270925fcad14e805b5ec1bbbb9e78b5b44e3b128f284b0113a4d68c82ef6" + "initCodeHash": "0x5ea977ba35558c3b75bebe28900548c763d205e40d6cf7660292b8e96bf3aea8", + "sourceCodeHash": "0x063ca3a0a2e3c592173af6157e383b5aaeff752000f98648a5c71260bb26590a" }, "src/universal/StorageSetter.sol": { "initCodeHash": "0x21b3059e9b13b330f76d02b61f61dcfa3abf3517a0b56afa0895c4b8291740bf", diff --git a/packages/contracts-bedrock/snapshots/storageLayout/DelayedVetoable.json b/packages/contracts-bedrock/snapshots/storageLayout/DelayedVetoable.json deleted file mode 100644 index 7da3cbbe5bd66..0000000000000 --- a/packages/contracts-bedrock/snapshots/storageLayout/DelayedVetoable.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "bytes": "32", - "label": "_delay", - "offset": 0, - "slot": "0", - "type": "uint256" - }, - { - "bytes": "32", - "label": "_queuedAt", - "offset": 0, - "slot": "1", - "type": "mapping(bytes32 => uint256)" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/DelayedWETH.json b/packages/contracts-bedrock/snapshots/storageLayout/DelayedWETH.json index 4e8b771cd9bb3..6fdbd4718b690 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/DelayedWETH.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/DelayedWETH.json @@ -36,14 +36,14 @@ }, { "bytes": "32", - "label": "balanceOf", + "label": "_balanceOf", "offset": 0, "slot": "101", "type": "mapping(address => uint256)" }, { "bytes": "32", - "label": "allowance", + "label": "_allowance", "offset": 0, "slot": "102", "type": "mapping(address => mapping(address => uint256))" diff --git a/packages/contracts-bedrock/snapshots/storageLayout/MIPS64.json b/packages/contracts-bedrock/snapshots/storageLayout/MIPS64.json new file mode 100644 index 0000000000000..0637a088a01e8 --- /dev/null +++ b/packages/contracts-bedrock/snapshots/storageLayout/MIPS64.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManager.json b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManager.json index aeef539c5c208..aa8148b34cba2 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManager.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManager.json @@ -1,51 +1,30 @@ [ - { - "bytes": "1", - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "uint8" - }, - { - "bytes": "1", - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "bool" - }, { "bytes": "32", - "label": "latestRelease", + "label": "l1ContractsRelease", "offset": 0, - "slot": "1", + "slot": "0", "type": "string" }, - { - "bytes": "32", - "label": "implementations", - "offset": 0, - "slot": "2", - "type": "mapping(string => mapping(string => struct OPContractsManager.Implementation))" - }, { "bytes": "32", "label": "systemConfigs", "offset": 0, - "slot": "3", + "slot": "1", "type": "mapping(uint256 => contract ISystemConfig)" }, { "bytes": "256", "label": "blueprint", "offset": 0, - "slot": "4", + "slot": "2", "type": "struct OPContractsManager.Blueprints" }, { - "bytes": "1600", - "label": "__gap", + "bytes": "288", + "label": "implementation", "offset": 0, - "slot": "12", - "type": "uint256[50]" + "slot": "10", + "type": "struct OPContractsManager.Implementations" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerInterop.json b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerInterop.json index aeef539c5c208..aa8148b34cba2 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerInterop.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/OPContractsManagerInterop.json @@ -1,51 +1,30 @@ [ - { - "bytes": "1", - "label": "_initialized", - "offset": 0, - "slot": "0", - "type": "uint8" - }, - { - "bytes": "1", - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "bool" - }, { "bytes": "32", - "label": "latestRelease", + "label": "l1ContractsRelease", "offset": 0, - "slot": "1", + "slot": "0", "type": "string" }, - { - "bytes": "32", - "label": "implementations", - "offset": 0, - "slot": "2", - "type": "mapping(string => mapping(string => struct OPContractsManager.Implementation))" - }, { "bytes": "32", "label": "systemConfigs", "offset": 0, - "slot": "3", + "slot": "1", "type": "mapping(uint256 => contract ISystemConfig)" }, { "bytes": "256", "label": "blueprint", "offset": 0, - "slot": "4", + "slot": "2", "type": "struct OPContractsManager.Blueprints" }, { - "bytes": "1600", - "label": "__gap", + "bytes": "288", + "label": "implementation", "offset": 0, - "slot": "12", - "type": "uint256[50]" + "slot": "10", + "type": "struct OPContractsManager.Implementations" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/SuperchainWETH.json b/packages/contracts-bedrock/snapshots/storageLayout/SuperchainWETH.json index ac5f38a75a045..93eac8f284290 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/SuperchainWETH.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/SuperchainWETH.json @@ -1,14 +1,14 @@ [ { "bytes": "32", - "label": "balanceOf", + "label": "_balanceOf", "offset": 0, "slot": "0", "type": "mapping(address => uint256)" }, { "bytes": "32", - "label": "allowance", + "label": "_allowance", "offset": 0, "slot": "1", "type": "mapping(address => mapping(address => uint256))" diff --git a/packages/contracts-bedrock/snapshots/storageLayout/WETH.json b/packages/contracts-bedrock/snapshots/storageLayout/WETH.json index ac5f38a75a045..93eac8f284290 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/WETH.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/WETH.json @@ -1,14 +1,14 @@ [ { "bytes": "32", - "label": "balanceOf", + "label": "_balanceOf", "offset": 0, "slot": "0", "type": "mapping(address => uint256)" }, { "bytes": "32", - "label": "allowance", + "label": "_allowance", "offset": 0, "slot": "1", "type": "mapping(address => mapping(address => uint256))" diff --git a/packages/contracts-bedrock/snapshots/storageLayout/WETH98.json b/packages/contracts-bedrock/snapshots/storageLayout/WETH98.json index ac5f38a75a045..93eac8f284290 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/WETH98.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/WETH98.json @@ -1,14 +1,14 @@ [ { "bytes": "32", - "label": "balanceOf", + "label": "_balanceOf", "offset": 0, "slot": "0", "type": "mapping(address => uint256)" }, { "bytes": "32", - "label": "allowance", + "label": "_allowance", "offset": 0, "slot": "1", "type": "mapping(address => mapping(address => uint256))" diff --git a/packages/contracts-bedrock/src/L1/DataAvailabilityChallenge.sol b/packages/contracts-bedrock/src/L1/DataAvailabilityChallenge.sol index 2a725fc4f2002..666e4306b4829 100644 --- a/packages/contracts-bedrock/src/L1/DataAvailabilityChallenge.sol +++ b/packages/contracts-bedrock/src/L1/DataAvailabilityChallenge.sol @@ -24,9 +24,10 @@ enum CommitmentType { } /// @dev A struct representing a single DA challenge. -/// @custom:field status The status of the challenge. /// @custom:field challenger The address that initiated the challenge. +/// @custom:field lockedBond The amount of ETH bond that was locked by the challenger. /// @custom:field startBlock The block number at which the challenge was initiated. +/// @custom:field resolvedBlock The block number at which the challenge was resolved. struct Challenge { address challenger; uint256 lockedBond; @@ -94,8 +95,8 @@ contract DataAvailabilityChallenge is OwnableUpgradeable, ISemver { event BalanceChanged(address account, uint256 balance); /// @notice Semantic version. - /// @custom:semver 1.0.1-beta.2 - string public constant version = "1.0.1-beta.2"; + /// @custom:semver 1.0.1-beta.3 + string public constant version = "1.0.1-beta.3"; /// @notice The fixed cost of resolving a challenge. /// @dev The value is estimated by measuring the cost of resolving with `bytes(0)` diff --git a/packages/contracts-bedrock/src/L1/DelayedVetoable.sol b/packages/contracts-bedrock/src/L1/DelayedVetoable.sol deleted file mode 100644 index d968af2149753..0000000000000 --- a/packages/contracts-bedrock/src/L1/DelayedVetoable.sol +++ /dev/null @@ -1,193 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -// Interfaces -import { ISemver } from "src/universal/interfaces/ISemver.sol"; - -/// @title DelayedVetoable -/// @notice This contract enables a delay before a call is forwarded to a target contract, and during the delay period -/// the call can be vetoed by the authorized vetoer. -/// This contract does not support value transfers, only data is forwarded. -/// Additionally, this contract cannot be used to forward calls with data beginning with the function selector -/// of the queuedAt(bytes32) function. This is because of input validation checks which solidity performs at -/// runtime on functions which take an argument. -contract DelayedVetoable is ISemver { - /// @notice Error for when attempting to forward too early. - error ForwardingEarly(); - - /// @notice Error for unauthorized calls. - error Unauthorized(address expected, address actual); - - /// @notice An event that is emitted when the delay is activated. - /// @param delay The delay that was activated. - event DelayActivated(uint256 delay); - - /// @notice An event that is emitted when a call is initiated. - /// @param callHash The hash of the call data. - /// @param data The data of the initiated call. - event Initiated(bytes32 indexed callHash, bytes data); - - /// @notice An event that is emitted each time a call is forwarded. - /// @param callHash The hash of the call data. - /// @param data The data forwarded to the target. - event Forwarded(bytes32 indexed callHash, bytes data); - - /// @notice An event that is emitted each time a call is vetoed. - /// @param callHash The hash of the call data. - /// @param data The data forwarded to the target. - event Vetoed(bytes32 indexed callHash, bytes data); - - /// @notice The address that all calls are forwarded to after the delay. - address internal immutable TARGET; - - /// @notice The address that can veto a call. - address internal immutable VETOER; - - /// @notice The address that can initiate a call. - address internal immutable INITIATOR; - - /// @notice The delay which will be set after the initial system deployment is completed. - uint256 internal immutable OPERATING_DELAY; - - /// @notice The current amount of time to wait before forwarding a call. - uint256 internal _delay; - - /// @notice The time that a call was initiated. - mapping(bytes32 => uint256) internal _queuedAt; - - /// @notice A modifier that reverts if not called by the vetoer or by address(0) to allow - /// eth_call to interact with this proxy without needing to use low-level storage - /// inspection. We assume that nobody is able to trigger calls from address(0) during - /// normal EVM execution. - modifier readOrHandle() { - if (msg.sender == address(0)) { - _; - } else { - // This WILL halt the call frame on completion. - _handleCall(); - } - } - - /// @notice Semantic version. - /// @custom:semver 1.0.1-beta.2 - string public constant version = "1.0.1-beta.2"; - - /// @notice Sets the target admin during contract deployment. - /// @param _vetoer Address of the vetoer. - /// @param _initiator Address of the initiator. - /// @param _target Address of the target. - /// @param _operatingDelay Time to delay when the system is operational. - constructor(address _vetoer, address _initiator, address _target, uint256 _operatingDelay) { - // Note that the _delay value is not set here. Having an initial delay of 0 is helpful - // during the deployment of a new system. - VETOER = _vetoer; - INITIATOR = _initiator; - TARGET = _target; - OPERATING_DELAY = _operatingDelay; - } - - /// @notice Gets the initiator - /// @return initiator_ Initiator address. - function initiator() external virtual readOrHandle returns (address initiator_) { - initiator_ = INITIATOR; - } - - //// @notice Queries the vetoer address. - /// @return vetoer_ Vetoer address. - function vetoer() external virtual readOrHandle returns (address vetoer_) { - vetoer_ = VETOER; - } - - //// @notice Queries the target address. - /// @return target_ Target address. - function target() external readOrHandle returns (address target_) { - target_ = TARGET; - } - - /// @notice Gets the delay - /// @return delay_ Delay address. - function delay() external readOrHandle returns (uint256 delay_) { - delay_ = _delay; - } - - /// @notice Gets entries in the _queuedAt mapping. - /// @param _callHash The hash of the call data. - /// @return queuedAt_ The time the callHash was recorded. - function queuedAt(bytes32 _callHash) external readOrHandle returns (uint256 queuedAt_) { - queuedAt_ = _queuedAt[_callHash]; - } - - /// @notice Used for all calls that pass data to the contract. - fallback() external { - _handleCall(); - } - - /// @notice Receives all calls other than those made by the vetoer. - /// This enables transparent initiation and forwarding of calls to the target and avoids - /// the need for additional layers of abi encoding. - function _handleCall() internal { - // The initiator and vetoer activate the delay by passing in null data. - if (msg.data.length == 0 && _delay == 0) { - if (msg.sender != INITIATOR && msg.sender != VETOER) { - revert Unauthorized(INITIATOR, msg.sender); - } - _delay = OPERATING_DELAY; - emit DelayActivated(_delay); - return; - } - - bytes32 callHash = keccak256(msg.data); - - // Case 1: The initiator is calling the contract to initiate a call. - if (msg.sender == INITIATOR && _queuedAt[callHash] == 0) { - if (_delay == 0) { - // This forward function will halt the call frame on completion. - _forwardAndHalt(callHash); - } - _queuedAt[callHash] = block.timestamp; - emit Initiated(callHash, msg.data); - return; - } - - // Case 2: The vetoer is calling the contract to veto a call. - // Note: The vetoer retains the ability to veto even after the delay has passed. This makes censoring the vetoer - // more costly, as there is no time limit after which their transaction can be included. - if (msg.sender == VETOER && _queuedAt[callHash] != 0) { - delete _queuedAt[callHash]; - emit Vetoed(callHash, msg.data); - return; - } - - // Case 3: The call is from an unpermissioned actor. We'll forward the call if the delay has - // passed. - if (_queuedAt[callHash] == 0) { - // The call has not been initiated, so we'll treat this is an unauthorized initiation attempt. - revert Unauthorized(INITIATOR, msg.sender); - } - - if (_queuedAt[callHash] + _delay > block.timestamp) { - // Not enough time has passed, so we'll revert. - revert ForwardingEarly(); - } - - // Delete the call to prevent replays - delete _queuedAt[callHash]; - _forwardAndHalt(callHash); - } - - /// @notice Forwards the call to the target and halts the call frame. - function _forwardAndHalt(bytes32 _callHash) internal { - // Forward the call - emit Forwarded(_callHash, msg.data); - (bool success, bytes memory returndata) = TARGET.call(msg.data); - if (success == true) { - assembly { - return(add(returndata, 0x20), mload(returndata)) - } - } else { - assembly { - revert(add(returndata, 0x20), mload(returndata)) - } - } - } -} diff --git a/packages/contracts-bedrock/src/L1/L1ERC721Bridge.sol b/packages/contracts-bedrock/src/L1/L1ERC721Bridge.sol index dd01ff5cd2d31..bd9b31c1e5893 100644 --- a/packages/contracts-bedrock/src/L1/L1ERC721Bridge.sol +++ b/packages/contracts-bedrock/src/L1/L1ERC721Bridge.sol @@ -28,8 +28,8 @@ contract L1ERC721Bridge is ERC721Bridge, ISemver { ISuperchainConfig public superchainConfig; /// @notice Semantic version. - /// @custom:semver 2.1.1-beta.4 - string public constant version = "2.1.1-beta.4"; + /// @custom:semver 2.2.0-beta.1 + string public constant version = "2.2.0-beta.1"; /// @notice Constructs the L1ERC721Bridge contract. constructor() ERC721Bridge() { @@ -107,8 +107,8 @@ contract L1ERC721Bridge is ERC721Bridge, ISemver { require(_remoteToken != address(0), "L1ERC721Bridge: remote token cannot be address(0)"); // Construct calldata for _l2Token.finalizeBridgeERC721(_to, _tokenId) - bytes memory message = abi.encodeWithSelector( - IL2ERC721Bridge.finalizeBridgeERC721.selector, _remoteToken, _localToken, _from, _to, _tokenId, _extraData + bytes memory message = abi.encodeCall( + IL2ERC721Bridge.finalizeBridgeERC721, (_remoteToken, _localToken, _from, _to, _tokenId, _extraData) ); // Lock token into bridge diff --git a/packages/contracts-bedrock/src/L1/L1StandardBridge.sol b/packages/contracts-bedrock/src/L1/L1StandardBridge.sol index 6dd648f0d5410..54cc833fe6730 100644 --- a/packages/contracts-bedrock/src/L1/L1StandardBridge.sol +++ b/packages/contracts-bedrock/src/L1/L1StandardBridge.sol @@ -75,8 +75,8 @@ contract L1StandardBridge is StandardBridge, ISemver { ); /// @notice Semantic version. - /// @custom:semver 2.2.1-beta.1 - string public constant version = "2.2.1-beta.1"; + /// @custom:semver 2.2.1-beta.2 + string public constant version = "2.2.1-beta.2"; /// @notice Address of the SuperchainConfig contract. ISuperchainConfig public superchainConfig; diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index 4bf52ff228a19..a2a5a5f215b04 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -4,15 +4,12 @@ pragma solidity 0.8.15; import { Blueprint } from "src/libraries/Blueprint.sol"; import { Constants } from "src/libraries/Constants.sol"; -import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; - import { ISemver } from "src/universal/interfaces/ISemver.sol"; import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; import { IBigStepper } from "src/dispute/interfaces/IBigStepper.sol"; import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol"; import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol"; import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol"; -import { ISystemConfigV160 } from "src/L1/interfaces/ISystemConfigV160.sol"; import { IAddressManager } from "src/legacy/interfaces/IAddressManager.sol"; import { IProxyAdmin } from "src/universal/interfaces/IProxyAdmin.sol"; @@ -28,14 +25,12 @@ import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; import { IProtocolVersions } from "src/L1/interfaces/IProtocolVersions.sol"; import { IOptimismPortal2 } from "src/L1/interfaces/IOptimismPortal2.sol"; import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; -import { ISystemConfigV160 } from "src/L1/interfaces/ISystemConfigV160.sol"; import { IL1CrossDomainMessenger } from "src/L1/interfaces/IL1CrossDomainMessenger.sol"; import { IL1ERC721Bridge } from "src/L1/interfaces/IL1ERC721Bridge.sol"; import { IL1StandardBridge } from "src/L1/interfaces/IL1StandardBridge.sol"; import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimismMintableERC20Factory.sol"; -/// @custom:proxied true -contract OPContractsManager is ISemver, Initializable { +contract OPContractsManager is ISemver { // -------- Structs -------- /// @notice Represents the roles that can be set when deploying a standard OP Stack chain. @@ -89,19 +84,6 @@ contract OPContractsManager is ISemver, Initializable { IDelayedWETH delayedWETHPermissionlessGameProxy; } - /// @notice The logic address and initializer selector for an implementation contract. - struct Implementation { - address logic; // Address containing the deployed logic contract. - bytes4 initializer; // Function selector for the initializer. - } - - /// @notice Used to set the implementation for a contract by mapping a contract - /// name to the implementation data. - struct ImplementationSetter { - string name; // Contract name. - Implementation info; // Implementation to set. - } - /// @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 @@ -118,19 +100,23 @@ contract OPContractsManager is ISemver, Initializable { address permissionedDisputeGame2; } - /// @notice Inputs required when initializing the OPContractsManager. To avoid 'StackTooDeep' errors, - /// all necessary inputs (excluding immutables) for initialization are bundled together in this struct. - struct InitializerInputs { - Blueprints blueprints; - ImplementationSetter[] setters; - string release; - bool isLatest; + /// @notice The latest implementation contracts for the OP Stack. + struct Implementations { + address l1ERC721BridgeImpl; + address optimismPortalImpl; + address systemConfigImpl; + address optimismMintableERC20FactoryImpl; + address l1CrossDomainMessengerImpl; + address l1StandardBridgeImpl; + address disputeGameFactoryImpl; + address delayedWETHImpl; + address mipsImpl; } // -------- Constants and Variables -------- - /// @custom:semver 1.0.0-beta.20 - string public constant version = "1.0.0-beta.20"; + /// @custom:semver 1.0.0-beta.21 + string public constant version = "1.0.0-beta.21"; /// @notice Represents the interface version so consumers know how to decode the DeployOutput struct /// that's emitted in the `Deployed` event. Whenever that struct changes, a new version should be used. @@ -142,24 +128,20 @@ contract OPContractsManager is ISemver, Initializable { /// @notice Address of the ProtocolVersions contract shared by all chains. IProtocolVersions public immutable protocolVersions; - /// @notice The latest release of the OP Contracts Manager, as a string of the format `op-contracts/vX.Y.Z`. - string public latestRelease; - - /// @notice Maps a release version to a contract name to it's implementation data. - mapping(string => mapping(string => Implementation)) public implementations; + // @notice L1 smart contracts release deployed by this version of OPCM. This is used in opcm to signal which version + // of the L1 smart contracts is deployed. It takes the format of `op-contracts/vX.Y.Z`. + string public l1ContractsRelease; /// @notice Maps an L2 Chain ID to the SystemConfig for that chain. mapping(uint256 => ISystemConfig) public systemConfigs; /// @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. This is also set via `initialize` because - /// we can't make this an immutable variable as it is a non-value type. + /// addresses, but we want it to return a struct. Blueprints internal blueprint; - /// @notice Storage gap for future modifications, so we can expand the number of blueprints - /// without affecting other storage variables. - uint256[50] private __gap; + /// @notice Addresses of the latest implementation contracts. + Implementations internal implementation; // -------- Events -------- @@ -197,37 +179,26 @@ contract OPContractsManager is ISemver, Initializable { // -------- Methods -------- - /// @notice OPCM is proxied. Therefore the `initialize` function replaces most constructor logic for this contract. - - constructor(ISuperchainConfig _superchainConfig, IProtocolVersions _protocolVersions) { + constructor( + ISuperchainConfig _superchainConfig, + IProtocolVersions _protocolVersions, + string memory _l1ContractsRelease, + Blueprints memory _blueprints, + Implementations memory _implementations + ) { assertValidContractAddress(address(_superchainConfig)); assertValidContractAddress(address(_protocolVersions)); superchainConfig = _superchainConfig; protocolVersions = _protocolVersions; - _disableInitializers(); - } - - function initialize(InitializerInputs memory _initializerInputs) public initializer { - if (_initializerInputs.isLatest) latestRelease = _initializerInputs.release; - if (keccak256(bytes(latestRelease)) == keccak256("")) revert LatestReleaseNotSet(); + l1ContractsRelease = _l1ContractsRelease; - for (uint256 i = 0; i < _initializerInputs.setters.length; i++) { - ImplementationSetter memory setter = _initializerInputs.setters[i]; - Implementation storage impl = implementations[_initializerInputs.release][setter.name]; - if (impl.logic != address(0)) revert AlreadyReleased(); - - impl.initializer = setter.info.initializer; - impl.logic = setter.info.logic; - } - - blueprint = _initializerInputs.blueprints; + blueprint = _blueprints; + implementation = _implementations; } function deploy(DeployInput calldata _input) external returns (DeployOutput memory) { assertValidInputs(_input); - uint256 l2ChainId = _input.l2ChainId; - // The salt for a non-proxy contract is a function of the chain ID and the salt mixer. string memory saltMixer = _input.saltMixer; bytes32 salt = keccak256(abi.encode(l2ChainId, saltMixer)); @@ -266,7 +237,6 @@ contract OPContractsManager is ISemver, Initializable { payable(Blueprint.deployFrom(blueprint.l1ChugSplashProxy, salt, 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, salt, abi.encode(output.addressManager, contractName)) @@ -275,10 +245,8 @@ contract OPContractsManager is ISemver, Initializable { address(output.l1CrossDomainMessengerProxy), IProxyAdmin.ProxyType.RESOLVED ); output.opChainProxyAdmin.setImplementationName(address(output.l1CrossDomainMessengerProxy), contractName); - // Now that all proxies are deployed, we can transfer ownership of the AddressManager to the ProxyAdmin. output.addressManager.transferOwnership(address(output.opChainProxyAdmin)); - // The AnchorStateRegistry Implementation is not MCP Ready, and therefore requires an implementation per chain. // It must be deployed after the DisputeGameFactoryProxy so that it can be provided as a constructor argument. output.anchorStateRegistryImpl = IAnchorStateRegistry( @@ -301,54 +269,76 @@ contract OPContractsManager is ISemver, Initializable { ); // -------- Set and Initialize Proxy Implementations -------- - Implementation memory impl; bytes memory data; - impl = getLatestImplementation("L1ERC721Bridge"); - data = encodeL1ERC721BridgeInitializer(impl.initializer, output); - upgradeAndCall(output.opChainProxyAdmin, address(output.l1ERC721BridgeProxy), impl.logic, data); + data = encodeL1ERC721BridgeInitializer(IL1ERC721Bridge.initialize.selector, output); + upgradeAndCall( + output.opChainProxyAdmin, address(output.l1ERC721BridgeProxy), implementation.l1ERC721BridgeImpl, data + ); - impl = getLatestImplementation("OptimismPortal"); - data = encodeOptimismPortalInitializer(impl.initializer, output); - upgradeAndCall(output.opChainProxyAdmin, address(output.optimismPortalProxy), impl.logic, data); + data = encodeOptimismPortalInitializer(IOptimismPortal2.initialize.selector, output); + upgradeAndCall( + output.opChainProxyAdmin, address(output.optimismPortalProxy), implementation.optimismPortalImpl, data + ); // First we upgrade the implementation so it's version can be retrieved, then we initialize // it afterwards. See the comments in encodeSystemConfigInitializer to learn more. - impl = getLatestImplementation("SystemConfig"); - output.opChainProxyAdmin.upgrade(payable(address(output.systemConfigProxy)), impl.logic); - data = encodeSystemConfigInitializer(impl.initializer, _input, output); - upgradeAndCall(output.opChainProxyAdmin, address(output.systemConfigProxy), impl.logic, data); + output.opChainProxyAdmin.upgrade(payable(address(output.systemConfigProxy)), implementation.systemConfigImpl); + data = encodeSystemConfigInitializer(_input, output); + upgradeAndCall( + output.opChainProxyAdmin, address(output.systemConfigProxy), implementation.systemConfigImpl, data + ); - impl = getLatestImplementation("OptimismMintableERC20Factory"); - data = encodeOptimismMintableERC20FactoryInitializer(impl.initializer, output); - upgradeAndCall(output.opChainProxyAdmin, address(output.optimismMintableERC20FactoryProxy), impl.logic, data); + data = encodeOptimismMintableERC20FactoryInitializer(IOptimismMintableERC20Factory.initialize.selector, output); + upgradeAndCall( + output.opChainProxyAdmin, + address(output.optimismMintableERC20FactoryProxy), + implementation.optimismMintableERC20FactoryImpl, + data + ); - impl = getLatestImplementation("L1CrossDomainMessenger"); - data = encodeL1CrossDomainMessengerInitializer(impl.initializer, output); - upgradeAndCall(output.opChainProxyAdmin, address(output.l1CrossDomainMessengerProxy), impl.logic, data); + data = encodeL1CrossDomainMessengerInitializer(IL1CrossDomainMessenger.initialize.selector, output); + upgradeAndCall( + output.opChainProxyAdmin, + address(output.l1CrossDomainMessengerProxy), + implementation.l1CrossDomainMessengerImpl, + data + ); - impl = getLatestImplementation("L1StandardBridge"); - data = encodeL1StandardBridgeInitializer(impl.initializer, output); - upgradeAndCall(output.opChainProxyAdmin, address(output.l1StandardBridgeProxy), impl.logic, data); + data = encodeL1StandardBridgeInitializer(IL1StandardBridge.initialize.selector, output); + upgradeAndCall( + output.opChainProxyAdmin, address(output.l1StandardBridgeProxy), implementation.l1StandardBridgeImpl, data + ); - impl = getLatestImplementation("DelayedWETH"); - data = encodeDelayedWETHInitializer(impl.initializer, _input); + data = encodeDelayedWETHInitializer(IDelayedWETH.initialize.selector, _input); // Eventually we will switch from DelayedWETHPermissionedGameProxy to DelayedWETHPermissionlessGameProxy. - upgradeAndCall(output.opChainProxyAdmin, address(output.delayedWETHPermissionedGameProxy), impl.logic, data); + upgradeAndCall( + output.opChainProxyAdmin, + address(output.delayedWETHPermissionedGameProxy), + implementation.delayedWETHImpl, + data + ); // We set the initial owner to this contract, set game implementations, then transfer ownership. - impl = getLatestImplementation("DisputeGameFactory"); - data = encodeDisputeGameFactoryInitializer(impl.initializer, _input); - upgradeAndCall(output.opChainProxyAdmin, address(output.disputeGameFactoryProxy), impl.logic, data); + data = encodeDisputeGameFactoryInitializer(IDisputeGameFactory.initialize.selector, _input); + upgradeAndCall( + output.opChainProxyAdmin, + address(output.disputeGameFactoryProxy), + implementation.disputeGameFactoryImpl, + data + ); output.disputeGameFactoryProxy.setImplementation( GameTypes.PERMISSIONED_CANNON, IDisputeGame(address(output.permissionedDisputeGame)) ); output.disputeGameFactoryProxy.transferOwnership(address(_input.roles.opChainProxyAdminOwner)); - impl.logic = address(output.anchorStateRegistryImpl); - impl.initializer = IAnchorStateRegistry.initialize.selector; - data = encodeAnchorStateRegistryInitializer(impl.initializer, _input); - upgradeAndCall(output.opChainProxyAdmin, address(output.anchorStateRegistryProxy), impl.logic, data); + data = encodeAnchorStateRegistryInitializer(IAnchorStateRegistry.initialize.selector, _input); + upgradeAndCall( + output.opChainProxyAdmin, + address(output.anchorStateRegistryProxy), + address(output.anchorStateRegistryImpl), + data + ); // -------- Finalize Deployment -------- // Transfer ownership of the ProxyAdmin from this contract to the specified owner. @@ -402,13 +392,6 @@ contract OPContractsManager is ISemver, Initializable { return Blueprint.deployFrom(blueprint.proxy, salt, abi.encode(_proxyAdmin)); } - /// @notice Returns the implementation data for a contract name. Makes a copy of the internal - // Implementation struct in storage to prevent accidental mutation of the internal data. - function getLatestImplementation(string memory _name) internal view returns (Implementation memory) { - Implementation storage impl = implementations[latestRelease][_name]; - return Implementation({ logic: impl.logic, initializer: impl.initializer }); - } - // -------- Initializer Encoding -------- /// @notice Helper method for encoding the L1ERC721Bridge initializer data. @@ -445,7 +428,6 @@ contract OPContractsManager is ISemver, Initializable { /// @notice Helper method for encoding the SystemConfig initializer data. function encodeSystemConfigInitializer( - bytes4 _selector, DeployInput memory _input, DeployOutput memory _output ) @@ -454,50 +436,22 @@ contract OPContractsManager is ISemver, Initializable { virtual returns (bytes memory) { - // We inspect the SystemConfig contract and determine it's signature here. This is required - // because this OPCM contract is being developed in a repository that no longer contains the - // SystemConfig contract that was released as part of `op-contracts/v1.6.0`, but in production - // it needs to support that version, in addition to the version currently on develop. - string memory semver = _output.systemConfigProxy.version(); - if (keccak256(abi.encode(semver)) == keccak256(abi.encode(string("2.2.0")))) { - // We are using the op-contracts/v1.6.0 SystemConfig contract. - ( - IResourceMetering.ResourceConfig memory referenceResourceConfig, - ISystemConfigV160.Addresses memory opChainAddrs - ) = defaultSystemConfigV160Params(_selector, _input, _output); - - return abi.encodeWithSelector( - _selector, - _input.roles.systemConfigOwner, - _input.basefeeScalar, - _input.blobBasefeeScalar, - bytes32(uint256(uint160(_input.roles.batcher))), // batcherHash - _input.gasLimit, - _input.roles.unsafeBlockSigner, - referenceResourceConfig, - chainIdToBatchInboxAddress(_input.l2ChainId), - opChainAddrs - ); - } else { - // We are using the latest SystemConfig contract from the repo. - ( - IResourceMetering.ResourceConfig memory referenceResourceConfig, - ISystemConfig.Addresses memory opChainAddrs - ) = defaultSystemConfigParams(_selector, _input, _output); - - return abi.encodeWithSelector( - _selector, - _input.roles.systemConfigOwner, - _input.basefeeScalar, - _input.blobBasefeeScalar, - bytes32(uint256(uint160(_input.roles.batcher))), // batcherHash - _input.gasLimit, - _input.roles.unsafeBlockSigner, - referenceResourceConfig, - chainIdToBatchInboxAddress(_input.l2ChainId), - opChainAddrs - ); - } + bytes4 selector = ISystemConfig.initialize.selector; + (IResourceMetering.ResourceConfig memory referenceResourceConfig, ISystemConfig.Addresses memory opChainAddrs) = + defaultSystemConfigParams(selector, _input, _output); + + return abi.encodeWithSelector( + selector, + _input.roles.systemConfigOwner, + _input.basefeeScalar, + _input.blobBasefeeScalar, + bytes32(uint256(uint160(_input.roles.batcher))), // batcherHash + _input.gasLimit, + _input.roles.unsafeBlockSigner, + referenceResourceConfig, + chainIdToBatchInboxAddress(_input.l2ChainId), + opChainAddrs + ); } /// @notice Helper method for encoding the OptimismMintableERC20Factory initializer data. @@ -599,7 +553,7 @@ contract OPContractsManager is ISemver, Initializable { _input.disputeSplitDepth, _input.disputeClockExtension, _input.disputeMaxClockDuration, - IBigStepper(getLatestImplementation("MIPS").logic), + IBigStepper(implementation.mipsImpl), IDelayedWETH(payable(address(_output.delayedWETHPermissionedGameProxy))), IAnchorStateRegistry(address(_output.anchorStateRegistryProxy)), _input.l2ChainId, @@ -645,45 +599,6 @@ contract OPContractsManager is ISemver, Initializable { assertValidContractAddress(opChainAddrs_.optimismMintableERC20Factory); } - /// @notice Returns default, standard config arguments for the SystemConfig initializer. - /// This is used by subclasses to reduce code duplication. - function defaultSystemConfigV160Params( - bytes4, /* selector */ - DeployInput memory, /* _input */ - DeployOutput memory _output - ) - internal - view - virtual - returns ( - IResourceMetering.ResourceConfig memory resourceConfig_, - ISystemConfigV160.Addresses memory opChainAddrs_ - ) - { - // We use assembly to easily convert from IResourceMetering.ResourceConfig to ResourceMetering.ResourceConfig. - // This is required because we have not yet fully migrated the codebase to be interface-based. - IResourceMetering.ResourceConfig memory resourceConfig = Constants.DEFAULT_RESOURCE_CONFIG(); - assembly ("memory-safe") { - resourceConfig_ := resourceConfig - } - - opChainAddrs_ = ISystemConfigV160.Addresses({ - l1CrossDomainMessenger: address(_output.l1CrossDomainMessengerProxy), - l1ERC721Bridge: address(_output.l1ERC721BridgeProxy), - l1StandardBridge: address(_output.l1StandardBridgeProxy), - disputeGameFactory: address(_output.disputeGameFactoryProxy), - optimismPortal: address(_output.optimismPortalProxy), - optimismMintableERC20Factory: address(_output.optimismMintableERC20FactoryProxy) - }); - - assertValidContractAddress(opChainAddrs_.l1CrossDomainMessenger); - assertValidContractAddress(opChainAddrs_.l1ERC721Bridge); - assertValidContractAddress(opChainAddrs_.l1StandardBridge); - assertValidContractAddress(opChainAddrs_.disputeGameFactory); - assertValidContractAddress(opChainAddrs_.optimismPortal); - assertValidContractAddress(opChainAddrs_.optimismMintableERC20Factory); - } - /// @notice Makes an external 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 upgradeAndCall( @@ -710,4 +625,9 @@ contract OPContractsManager is ISemver, Initializable { function blueprints() public view returns (Blueprints memory) { return blueprint; } + + /// @notice Returns the implementation contract addresses. + function implementations() public view returns (Implementations memory) { + return implementation; + } } diff --git a/packages/contracts-bedrock/src/L1/OPContractsManagerInterop.sol b/packages/contracts-bedrock/src/L1/OPContractsManagerInterop.sol index 9d541434a3974..79e0efda97350 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManagerInterop.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManagerInterop.sol @@ -6,20 +6,22 @@ import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; import { IProtocolVersions } from "src/L1/interfaces/IProtocolVersions.sol"; import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; +import { ISystemConfigInterop } from "src/L1/interfaces/ISystemConfigInterop.sol"; -/// @custom:proxied true contract OPContractsManagerInterop is OPContractsManager { constructor( ISuperchainConfig _superchainConfig, - IProtocolVersions _protocolVersions + IProtocolVersions _protocolVersions, + string memory _l1ContractsRelease, + Blueprints memory _blueprints, + Implementations memory _implementations ) - OPContractsManager(_superchainConfig, _protocolVersions) + OPContractsManager(_superchainConfig, _protocolVersions, _l1ContractsRelease, _blueprints, _implementations) { } // The `SystemConfigInterop` contract has an extra `address _dependencyManager` argument // that we must account for. function encodeSystemConfigInitializer( - bytes4 _selector, DeployInput memory _input, DeployOutput memory _output ) @@ -29,18 +31,19 @@ contract OPContractsManagerInterop is OPContractsManager { override returns (bytes memory) { + bytes4 selector = ISystemConfigInterop.initialize.selector; (IResourceMetering.ResourceConfig memory referenceResourceConfig, ISystemConfig.Addresses memory opChainAddrs) = - defaultSystemConfigParams(_selector, _input, _output); + defaultSystemConfigParams(selector, _input, _output); - // TODO For now we assume that the dependency manager is the same as the proxy admin owner. + // TODO For now we assume that the dependency manager is the same as system config owner. // This is currently undefined since it's not part of the standard config, so we may need // to update where this value is pulled from in the future. To support a different dependency // manager in this contract without an invasive change of redefining the `Roles` struct, // we will make the change described in https://github.com/ethereum-optimism/optimism/issues/11783. - address dependencyManager = address(_input.roles.opChainProxyAdminOwner); + address dependencyManager = address(_input.roles.systemConfigOwner); return abi.encodeWithSelector( - _selector, + selector, _input.roles.systemConfigOwner, _input.basefeeScalar, _input.blobBasefeeScalar, diff --git a/packages/contracts-bedrock/src/L1/SystemConfig.sol b/packages/contracts-bedrock/src/L1/SystemConfig.sol index afb9525403c71..5173911644386 100644 --- a/packages/contracts-bedrock/src/L1/SystemConfig.sol +++ b/packages/contracts-bedrock/src/L1/SystemConfig.sol @@ -137,9 +137,9 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data); /// @notice Semantic version. - /// @custom:semver 2.3.0-beta.5 + /// @custom:semver 2.3.0-beta.6 function version() public pure virtual returns (string memory) { - return "2.3.0-beta.5"; + return "2.3.0-beta.6"; } /// @notice Constructs the SystemConfig contract. Cannot set @@ -224,7 +224,6 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { _setGasPayingToken(_addresses.gasPayingToken); _setResourceConfig(_config); - require(_gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low"); } /// @notice Returns the minimum L2 gas limit that can be safely set for the system to diff --git a/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol b/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol index 0321092865960..9e9503fe62363 100644 --- a/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol +++ b/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol @@ -68,9 +68,9 @@ contract SystemConfigInterop is SystemConfig { Storage.setAddress(DEPENDENCY_MANAGER_SLOT, _dependencyManager); } - /// @custom:semver +interop-beta.3 + /// @custom:semver +interop-beta.4 function version() public pure override returns (string memory) { - return string.concat(super.version(), "+interop-beta.3"); + return string.concat(super.version(), "+interop-beta.4"); } /// @notice Internal setter for the gas paying token address, includes validation. diff --git a/packages/contracts-bedrock/src/L1/interfaces/IDelayedVetoable.sol b/packages/contracts-bedrock/src/L1/interfaces/IDelayedVetoable.sol deleted file mode 100644 index 53fd168127639..0000000000000 --- a/packages/contracts-bedrock/src/L1/interfaces/IDelayedVetoable.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -interface IDelayedVetoable { - error ForwardingEarly(); - error Unauthorized(address expected, address actual); - - event DelayActivated(uint256 delay); - event Forwarded(bytes32 indexed callHash, bytes data); - event Initiated(bytes32 indexed callHash, bytes data); - event Vetoed(bytes32 indexed callHash, bytes data); - - fallback() external; - - function delay() external returns (uint256 delay_); - function initiator() external returns (address initiator_); - function queuedAt(bytes32 _callHash) external returns (uint256 queuedAt_); - function target() external returns (address target_); - function version() external view returns (string memory); - function vetoer() external returns (address vetoer_); - - function __constructor__(address _vetoer, address _initiator, address _target, uint256 _operatingDelay) external; -} diff --git a/packages/contracts-bedrock/src/L1/interfaces/ISystemConfigV160.sol b/packages/contracts-bedrock/src/L1/interfaces/ISystemConfigV160.sol deleted file mode 100644 index 210b0ddf8e5e6..0000000000000 --- a/packages/contracts-bedrock/src/L1/interfaces/ISystemConfigV160.sol +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; - -/// @notice This interface corresponds to the op-contracts/v1.6.0 release of the SystemConfig -/// contract, which has a semver of 2.2.0 as specified in -/// https://github.com/ethereum-optimism/optimism/releases/tag/op-contracts%2Fv1.6.0 -interface ISystemConfigV160 { - enum UpdateType { - BATCHER, - FEE_SCALARS, - GAS_LIMIT, - UNSAFE_BLOCK_SIGNER - } - - struct Addresses { - address l1CrossDomainMessenger; - address l1ERC721Bridge; - address l1StandardBridge; - address disputeGameFactory; - address optimismPortal; - address optimismMintableERC20Factory; - } - - event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data); - event Initialized(uint8 version); - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); - - function BATCH_INBOX_SLOT() external view returns (bytes32); - function DISPUTE_GAME_FACTORY_SLOT() external view returns (bytes32); - function L1_CROSS_DOMAIN_MESSENGER_SLOT() external view returns (bytes32); - function L1_ERC_721_BRIDGE_SLOT() external view returns (bytes32); - function L1_STANDARD_BRIDGE_SLOT() external view returns (bytes32); - function OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT() external view returns (bytes32); - function OPTIMISM_PORTAL_SLOT() external view returns (bytes32); - function START_BLOCK_SLOT() external view returns (bytes32); - function UNSAFE_BLOCK_SIGNER_SLOT() external view returns (bytes32); - function VERSION() external view returns (uint256); - function basefeeScalar() external view returns (uint32); - function batchInbox() external view returns (address addr_); - function batcherHash() external view returns (bytes32); - function blobbasefeeScalar() external view returns (uint32); - function disputeGameFactory() external view returns (address addr_); - function gasLimit() external view returns (uint64); - function gasPayingToken() external view returns (address addr_, uint8 decimals_); - function gasPayingTokenName() external view returns (string memory name_); - function gasPayingTokenSymbol() external view returns (string memory symbol_); - function initialize( - address _owner, - uint256 _basefeeScalar, - uint256 _blobbasefeeScalar, - bytes32 _batcherHash, - uint64 _gasLimit, - address _unsafeBlockSigner, - IResourceMetering.ResourceConfig memory _config, - address _batchInbox, - Addresses memory _addresses - ) - external; - function isCustomGasToken() external view returns (bool); - function l1CrossDomainMessenger() external view returns (address addr_); - function l1ERC721Bridge() external view returns (address addr_); - function l1StandardBridge() external view returns (address addr_); - function maximumGasLimit() external pure returns (uint64); - function minimumGasLimit() external view returns (uint64); - function optimismMintableERC20Factory() external view returns (address addr_); - function optimismPortal() external view returns (address addr_); - function overhead() external view returns (uint256); - function owner() external view returns (address); - function renounceOwnership() external; - function resourceConfig() external view returns (IResourceMetering.ResourceConfig memory); - function scalar() external view returns (uint256); - function setBatcherHash(bytes32 _batcherHash) external; - function setGasConfig(uint256 _overhead, uint256 _scalar) external; - function setGasConfigEcotone(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) external; - function setGasLimit(uint64 _gasLimit) external; - function setUnsafeBlockSigner(address _unsafeBlockSigner) external; - function startBlock() external view returns (uint256 startBlock_); - function transferOwnership(address newOwner) external; // nosemgrep - function unsafeBlockSigner() external view returns (address addr_); - function version() external pure returns (string memory); - - function __constructor__() external; -} diff --git a/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol b/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol index 7939dccddbb40..b330dfb0ceb4f 100644 --- a/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol +++ b/packages/contracts-bedrock/src/L2/CrossL2Inbox.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.25; import { Predeploys } from "src/libraries/Predeploys.sol"; import { TransientContext, TransientReentrancyAware } from "src/libraries/TransientContext.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; -import { ICrossL2Inbox } from "src/L2/interfaces/ICrossL2Inbox.sol"; import { SafeCall } from "src/libraries/SafeCall.sol"; import { IDependencySet } from "src/L2/interfaces/IDependencySet.sol"; import { IL1BlockInterop } from "src/L2/interfaces/IL1BlockInterop.sol"; @@ -30,12 +29,21 @@ error TargetCallFailed(); /// @notice Thrown when trying to execute a cross chain message on a deposit transaction. error NoExecutingDeposits(); +/// @notice The struct for a pointer to a message payload in a remote (or local) chain. +struct Identifier { + address origin; + uint256 blockNumber; + uint256 logIndex; + uint256 timestamp; + uint256 chainId; +} + /// @custom:proxied true /// @custom:predeploy 0x4200000000000000000000000000000000000022 /// @title CrossL2Inbox /// @notice The CrossL2Inbox is responsible for executing a cross chain message on the destination /// chain. It is permissionless to execute a cross chain message on behalf of any user. -contract CrossL2Inbox is ICrossL2Inbox, ISemver, TransientReentrancyAware { +contract CrossL2Inbox is ISemver, TransientReentrancyAware { /// @notice Storage slot that the interop start timestamp is stored at. /// Equal to bytes32(uint256(keccak256("crossl2inbox.interopstart")) - 1) bytes32 internal constant INTEROP_START_SLOT = 0x5c769ee0ee8887661922049dc52480bb60322d765161507707dd9b190af5c149; @@ -65,8 +73,8 @@ contract CrossL2Inbox is ICrossL2Inbox, ISemver, TransientReentrancyAware { address internal constant DEPOSITOR_ACCOUNT = 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001; /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.8 - string public constant version = "1.0.0-beta.8"; + /// @custom:semver 1.0.0-beta.9 + string public constant version = "1.0.0-beta.9"; /// @notice Emitted when a cross chain message is being executed. /// @param msgHash Hash of message payload being executed. diff --git a/packages/contracts-bedrock/src/L2/L2ERC721Bridge.sol b/packages/contracts-bedrock/src/L2/L2ERC721Bridge.sol index 950f25203981d..85c6856e629d8 100644 --- a/packages/contracts-bedrock/src/L2/L2ERC721Bridge.sol +++ b/packages/contracts-bedrock/src/L2/L2ERC721Bridge.sol @@ -26,8 +26,8 @@ import { ISemver } from "src/universal/interfaces/ISemver.sol"; /// wait for the one-week challenge period to elapse before their Optimism-native NFT /// can be refunded on L2. contract L2ERC721Bridge is ERC721Bridge, ISemver { - /// @custom:semver 1.7.1-beta.3 - string public constant version = "1.7.1-beta.3"; + /// @custom:semver 1.8.0-beta.2 + string public constant version = "1.8.0-beta.2"; /// @notice Constructs the L2ERC721Bridge contract. constructor() ERC721Bridge() { @@ -117,8 +117,8 @@ contract L2ERC721Bridge is ERC721Bridge, ISemver { // slither-disable-next-line reentrancy-events IOptimismMintableERC721(_localToken).burn(_from, _tokenId); - bytes memory message = abi.encodeWithSelector( - IL1ERC721Bridge.finalizeBridgeERC721.selector, remoteToken, _localToken, _from, _to, _tokenId, _extraData + bytes memory message = abi.encodeCall( + IL1ERC721Bridge.finalizeBridgeERC721, (remoteToken, _localToken, _from, _to, _tokenId, _extraData) ); // Send message to L1 bridge diff --git a/packages/contracts-bedrock/src/L2/L2StandardBridge.sol b/packages/contracts-bedrock/src/L2/L2StandardBridge.sol index 1c7e2e307cc36..63bda3209fbbe 100644 --- a/packages/contracts-bedrock/src/L2/L2StandardBridge.sol +++ b/packages/contracts-bedrock/src/L2/L2StandardBridge.sol @@ -58,9 +58,9 @@ contract L2StandardBridge is StandardBridge, ISemver { ); /// @notice Semantic version. - /// @custom:semver 1.11.1-beta.2 + /// @custom:semver 1.11.1-beta.3 function version() public pure virtual returns (string memory) { - return "1.11.1-beta.2"; + return "1.11.1-beta.3"; } /// @notice Constructs the L2StandardBridge contract. diff --git a/packages/contracts-bedrock/src/L2/L2StandardBridgeInterop.sol b/packages/contracts-bedrock/src/L2/L2StandardBridgeInterop.sol index eb25a406ede72..e17ef29dd9649 100644 --- a/packages/contracts-bedrock/src/L2/L2StandardBridgeInterop.sol +++ b/packages/contracts-bedrock/src/L2/L2StandardBridgeInterop.sol @@ -40,9 +40,9 @@ contract L2StandardBridgeInterop is L2StandardBridge { event Converted(address indexed from, address indexed to, address indexed caller, uint256 amount); /// @notice Semantic version. - /// @custom:semver +interop-beta.1 + /// @custom:semver +interop-beta.2 function version() public pure override returns (string memory) { - return string.concat(super.version(), "+interop-beta.1"); + return string.concat(super.version(), "+interop-beta.2"); } /// @notice Converts `amount` of `from` token to `to` token. diff --git a/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol b/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol index c8afe8be5d924..6b1d7327dbc0d 100644 --- a/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol +++ b/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol @@ -4,9 +4,7 @@ pragma solidity 0.8.25; import { Encoding } from "src/libraries/Encoding.sol"; import { Hashing } from "src/libraries/Hashing.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; -import { CrossL2Inbox } from "src/L2/CrossL2Inbox.sol"; -import { ICrossL2Inbox } from "src/L2/interfaces/ICrossL2Inbox.sol"; -import { IL2ToL2CrossDomainMessenger } from "src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol"; +import { CrossL2Inbox, Identifier } from "src/L2/CrossL2Inbox.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; import { SafeCall } from "src/libraries/SafeCall.sol"; import { TransientReentrancyAware } from "src/libraries/TransientContext.sol"; @@ -47,7 +45,7 @@ error TargetCallFailed(); /// @notice The L2ToL2CrossDomainMessenger is a higher level abstraction on top of the CrossL2Inbox that provides /// features necessary for secure transfers ERC20 tokens between L2 chains. Messages sent through the /// L2ToL2CrossDomainMessenger on the source chain receive both replay protection as well as domain binding. -contract L2ToL2CrossDomainMessenger is IL2ToL2CrossDomainMessenger, ISemver, TransientReentrancyAware { +contract L2ToL2CrossDomainMessenger is ISemver, TransientReentrancyAware { /// @notice Storage slot for the sender of the current cross domain message. /// Equal to bytes32(uint256(keccak256("l2tol2crossdomainmessenger.sender")) - 1) bytes32 internal constant CROSS_DOMAIN_MESSAGE_SENDER_SLOT = @@ -67,8 +65,8 @@ contract L2ToL2CrossDomainMessenger is IL2ToL2CrossDomainMessenger, ISemver, Tra uint16 public constant messageVersion = uint16(0); /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.9 - string public constant version = "1.0.0-beta.9"; + /// @custom:semver 1.0.0-beta.10 + string public constant version = "1.0.0-beta.10"; /// @notice Mapping of message hashes to boolean receipt values. Note that a message will only be present in this /// mapping if it has successfully been relayed on this chain, and can therefore not be relayed again. @@ -153,14 +151,7 @@ contract L2ToL2CrossDomainMessenger is IL2ToL2CrossDomainMessenger, ISemver, Tra /// currently being replayed. /// @param _id Identifier of the SentMessage event to be relayed /// @param _sentMessage Message payload of the `SentMessage` event - function relayMessage( - ICrossL2Inbox.Identifier calldata _id, - bytes calldata _sentMessage - ) - external - payable - nonReentrant - { + function relayMessage(Identifier calldata _id, bytes calldata _sentMessage) external payable nonReentrant { // Ensure the log came from the messenger. Since the log origin is the CDM, there isn't a scenario where // this can be invoked from the CrossL2Inbox as the SentMessage log is not calldata for this function if (_id.origin != Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) { diff --git a/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol b/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol index a097bb736c842..c323d8b7577be 100644 --- a/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.25; import { IOptimismSuperchainERC20 } from "src/L2/interfaces/IOptimismSuperchainERC20.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; -import { ERC165 } from "@openzeppelin/contracts-v5/utils/introspection/ERC165.sol"; import { SuperchainERC20 } from "src/L2/SuperchainERC20.sol"; import { Initializable } from "@openzeppelin/contracts-v5/proxy/utils/Initializable.sol"; import { ZeroAddress, Unauthorized } from "src/libraries/errors/CommonErrors.sol"; @@ -16,7 +15,7 @@ import { ZeroAddress, Unauthorized } from "src/libraries/errors/CommonErrors.sol /// OptimismSuperchainERC20 token, turning it fungible and interoperable across the superchain. Likewise, it /// also enables the inverse conversion path. /// Moreover, it builds on top of the L2ToL2CrossDomainMessenger for both replay protection and domain binding. -contract OptimismSuperchainERC20 is SuperchainERC20, Initializable, ERC165 { +contract OptimismSuperchainERC20 is SuperchainERC20, Initializable { /// @notice Emitted whenever tokens are minted for an account. /// @param to Address of the account tokens are being minted for. /// @param amount Amount of tokens minted. @@ -59,8 +58,8 @@ contract OptimismSuperchainERC20 is SuperchainERC20, Initializable, ERC165 { } /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.7 - string public constant override version = "1.0.0-beta.7"; + /// @custom:semver 1.0.0-beta.9 + string public constant override version = "1.0.0-beta.9"; /// @notice Constructs the OptimismSuperchainERC20 contract. constructor() { diff --git a/packages/contracts-bedrock/src/L2/SuperchainERC20.sol b/packages/contracts-bedrock/src/L2/SuperchainERC20.sol index d723ed8d992bb..b9e6bbfbf7807 100644 --- a/packages/contracts-bedrock/src/L2/SuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/SuperchainERC20.sol @@ -1,44 +1,48 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol"; +import { IERC7802, IERC165 } from "src/L2/interfaces/IERC7802.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { ERC20 } from "@solady-v0.0.245/tokens/ERC20.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Unauthorized } from "src/libraries/errors/CommonErrors.sol"; /// @title SuperchainERC20 -/// @notice SuperchainERC20 is a standard extension of the base ERC20 token contract that unifies ERC20 token -/// bridging to make it fungible across the Superchain. This construction allows the SuperchainTokenBridge to -/// burn and mint tokens. -abstract contract SuperchainERC20 is ERC20, ICrosschainERC20, ISemver { - /// @notice A modifier that only allows the SuperchainTokenBridge to call - modifier onlySuperchainTokenBridge() { - if (msg.sender != Predeploys.SUPERCHAIN_TOKEN_BRIDGE) revert Unauthorized(); - _; - } - +/// @notice A standard ERC20 extension implementing IERC7802 for unified cross-chain fungibility across +/// the Superchain. Allows the SuperchainTokenBridge to mint and burn tokens as needed. +abstract contract SuperchainERC20 is ERC20, IERC7802, ISemver { /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.2 + /// @custom:semver 1.0.0-beta.5 function version() external view virtual returns (string memory) { - return "1.0.0-beta.2"; + return "1.0.0-beta.5"; } /// @notice Allows the SuperchainTokenBridge to mint tokens. /// @param _to Address to mint tokens to. /// @param _amount Amount of tokens to mint. - function crosschainMint(address _to, uint256 _amount) external onlySuperchainTokenBridge { + function crosschainMint(address _to, uint256 _amount) external { + if (msg.sender != Predeploys.SUPERCHAIN_TOKEN_BRIDGE) revert Unauthorized(); + _mint(_to, _amount); - emit CrosschainMinted(_to, _amount); + emit CrosschainMint(_to, _amount); } /// @notice Allows the SuperchainTokenBridge to burn tokens. /// @param _from Address to burn tokens from. /// @param _amount Amount of tokens to burn. - function crosschainBurn(address _from, uint256 _amount) external onlySuperchainTokenBridge { + function crosschainBurn(address _from, uint256 _amount) external { + if (msg.sender != Predeploys.SUPERCHAIN_TOKEN_BRIDGE) revert Unauthorized(); + _burn(_from, _amount); - emit CrosschainBurnt(_from, _amount); + emit CrosschainBurn(_from, _amount); + } + + /// @inheritdoc IERC165 + function supportsInterface(bytes4 _interfaceId) public view virtual returns (bool) { + return _interfaceId == type(IERC7802).interfaceId || _interfaceId == type(IERC20).interfaceId + || _interfaceId == type(IERC165).interfaceId; } } diff --git a/packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol b/packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol index 284beb79ec0ea..104f8ef950430 100644 --- a/packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol +++ b/packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol @@ -7,6 +7,7 @@ import { ZeroAddress, Unauthorized } from "src/libraries/errors/CommonErrors.sol // Interfaces import { ISuperchainERC20 } from "src/L2/interfaces/ISuperchainERC20.sol"; +import { IERC7802, IERC165 } from "src/L2/interfaces/IERC7802.sol"; import { IL2ToL2CrossDomainMessenger } from "src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol"; /// @custom:proxied true @@ -20,6 +21,9 @@ contract SuperchainTokenBridge { /// SuperchainTokenBridge. error InvalidCrossDomainSender(); + /// @notice Thrown when attempting to use a token that does not implement the ERC7802 interface. + error InvalidERC7802(); + /// @notice Emitted when tokens are sent from one chain to another. /// @param token Address of the token sent. /// @param from Address of the sender. @@ -42,8 +46,8 @@ contract SuperchainTokenBridge { address internal constant MESSENGER = Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER; /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.2 - string public constant version = "1.0.0-beta.2"; + /// @custom:semver 1.0.0-beta.3 + string public constant version = "1.0.0-beta.3"; /// @notice Sends tokens to a target address on another chain. /// @dev Tokens are burned on the source chain. @@ -63,6 +67,8 @@ contract SuperchainTokenBridge { { if (_to == address(0)) revert ZeroAddress(); + if (!IERC165(_token).supportsInterface(type(IERC7802).interfaceId)) revert InvalidERC7802(); + ISuperchainERC20(_token).crosschainBurn(msg.sender, _amount); bytes memory message = abi.encodeCall(this.relayERC20, (_token, msg.sender, _to, _amount)); @@ -82,6 +88,7 @@ contract SuperchainTokenBridge { (address crossDomainMessageSender, uint256 source) = IL2ToL2CrossDomainMessenger(MESSENGER).crossDomainMessageContext(); + if (crossDomainMessageSender != address(this)) revert InvalidCrossDomainSender(); ISuperchainERC20(_token).crosschainMint(_to, _amount); diff --git a/packages/contracts-bedrock/src/L2/SuperchainWETH.sol b/packages/contracts-bedrock/src/L2/SuperchainWETH.sol index d27c6e7db5146..29e179eba82ce 100644 --- a/packages/contracts-bedrock/src/L2/SuperchainWETH.sol +++ b/packages/contracts-bedrock/src/L2/SuperchainWETH.sol @@ -6,12 +6,14 @@ import { WETH98 } from "src/universal/WETH98.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; +import { Preinstalls } from "src/libraries/Preinstalls.sol"; // Interfaces import { ISemver } from "src/universal/interfaces/ISemver.sol"; import { IL1Block } from "src/L2/interfaces/IL1Block.sol"; import { IETHLiquidity } from "src/L2/interfaces/IETHLiquidity.sol"; -import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol"; +import { IERC7802, IERC165 } from "src/L2/interfaces/IERC7802.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Unauthorized, NotCustomGasToken } from "src/libraries/errors/CommonErrors.sol"; /// @custom:proxied true @@ -20,10 +22,10 @@ import { Unauthorized, NotCustomGasToken } from "src/libraries/errors/CommonErro /// @notice SuperchainWETH is a version of WETH that can be freely transfrered between chains /// within the superchain. SuperchainWETH can be converted into native ETH on chains that /// do not use a custom gas token. -contract SuperchainWETH is WETH98, ICrosschainERC20, ISemver { +contract SuperchainWETH is WETH98, IERC7802, ISemver { /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.7 - string public constant version = "1.0.0-beta.7"; + /// @custom:semver 1.0.0-beta.10 + string public constant version = "1.0.0-beta.10"; /// @inheritdoc WETH98 function deposit() public payable override { @@ -37,11 +39,17 @@ contract SuperchainWETH is WETH98, ICrosschainERC20, ISemver { super.withdraw(_amount); } + /// @inheritdoc WETH98 + function allowance(address owner, address spender) public view override returns (uint256) { + if (spender == Preinstalls.Permit2) return type(uint256).max; + return super.allowance(owner, spender); + } + /// @notice Mints WETH to an address. /// @param _to The address to mint WETH to. /// @param _amount The amount of WETH to mint. function _mint(address _to, uint256 _amount) internal { - balanceOf[_to] += _amount; + _balanceOf[_to] += _amount; emit Transfer(address(0), _to, _amount); } @@ -49,7 +57,7 @@ contract SuperchainWETH is WETH98, ICrosschainERC20, ISemver { /// @param _from The address to burn WETH from. /// @param _amount The amount of WETH to burn. function _burn(address _from, uint256 _amount) internal { - balanceOf[_from] -= _amount; + _balanceOf[_from] -= _amount; emit Transfer(_from, address(0), _amount); } @@ -66,7 +74,7 @@ contract SuperchainWETH is WETH98, ICrosschainERC20, ISemver { IETHLiquidity(Predeploys.ETH_LIQUIDITY).mint(_amount); } - emit CrosschainMinted(_to, _amount); + emit CrosschainMint(_to, _amount); } /// @notice Allows the SuperchainTokenBridge to burn tokens. @@ -82,6 +90,12 @@ contract SuperchainWETH is WETH98, ICrosschainERC20, ISemver { IETHLiquidity(Predeploys.ETH_LIQUIDITY).burn{ value: _amount }(); } - emit CrosschainBurnt(_from, _amount); + emit CrosschainBurn(_from, _amount); + } + + /// @inheritdoc IERC165 + function supportsInterface(bytes4 _interfaceId) public view virtual returns (bool) { + return _interfaceId == type(IERC7802).interfaceId || _interfaceId == type(IERC20).interfaceId + || _interfaceId == type(IERC165).interfaceId; } } diff --git a/packages/contracts-bedrock/src/L2/WETH.sol b/packages/contracts-bedrock/src/L2/WETH.sol index fb24f07473385..dacd62c36de98 100644 --- a/packages/contracts-bedrock/src/L2/WETH.sol +++ b/packages/contracts-bedrock/src/L2/WETH.sol @@ -14,8 +14,8 @@ import { IL1Block } from "src/L2/interfaces/IL1Block.sol"; /// @title WETH contract that reads the name and symbol from the L1Block contract. /// Allows for nice rendering of token names for chains using custom gas token. contract WETH is WETH98, ISemver { - /// @custom:semver 1.1.0-beta.2 - string public constant version = "1.1.0-beta.2"; + /// @custom:semver 1.1.0-beta.3 + string public constant version = "1.1.0-beta.3"; /// @notice Returns the name of the wrapped native asset. Will be "Wrapped Ether" /// if the native asset is Ether. diff --git a/packages/contracts-bedrock/src/L2/interfaces/ICrossL2Inbox.sol b/packages/contracts-bedrock/src/L2/interfaces/ICrossL2Inbox.sol index 3267122fc0b10..bbd8c09afd8cc 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/ICrossL2Inbox.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/ICrossL2Inbox.sol @@ -1,53 +1,70 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +struct Identifier { + address origin; + uint256 blockNumber; + uint256 logIndex; + uint256 timestamp; + uint256 chainId; +} + /// @title ICrossL2Inbox /// @notice Interface for the CrossL2Inbox contract. interface ICrossL2Inbox { - /// @notice The struct for a pointer to a message payload in a remote (or local) chain. - struct Identifier { - address origin; - uint256 blockNumber; - uint256 logIndex; - uint256 timestamp; - uint256 chainId; - } + error ReentrantCall(); + + /// @notice Thrown when the caller is not DEPOSITOR_ACCOUNT when calling `setInteropStart()` + error NotDepositor(); + + /// @notice Thrown when attempting to set interop start when it's already set. + error InteropStartAlreadySet(); + + /// @notice Thrown when a non-written transient storage slot is attempted to be read from. + error NotEntered(); + + /// @notice Thrown when trying to execute a cross chain message with an invalid Identifier timestamp. + error InvalidTimestamp(); + + /// @notice Thrown when trying to execute a cross chain message with an invalid Identifier chain ID. + error InvalidChainId(); + + /// @notice Thrown when trying to execute a cross chain message and the target call fails. + error TargetCallFailed(); + + /// @notice Thrown when trying to execute a cross chain message on a deposit transaction. + error NoExecutingDeposits(); + + event ExecutingMessage(bytes32 indexed msgHash, Identifier id); + + function version() external view returns (string memory); /// @notice Returns the interop start timestamp. /// @return interopStart_ interop start timestamp. function interopStart() external view returns (uint256 interopStart_); /// @notice Returns the origin address of the Identifier. - /// @return origin_ The origin address of the Identifier. - function origin() external view returns (address origin_); + function origin() external view returns (address); /// @notice Returns the block number of the Identifier. - /// @return blockNumber_ The block number of the Identifier. - function blockNumber() external view returns (uint256 blockNumber_); + function blockNumber() external view returns (uint256); /// @notice Returns the log index of the Identifier. - /// @return logIndex_ The log index of the Identifier. - function logIndex() external view returns (uint256 logIndex_); + function logIndex() external view returns (uint256); /// @notice Returns the timestamp of the Identifier. - /// @return timestamp_ The timestamp of the Identifier. - function timestamp() external view returns (uint256 timestamp_); + function timestamp() external view returns (uint256); /// @notice Returns the chain ID of the Identifier. - /// @return chainId_ The chain ID of the Identifier. - function chainId() external view returns (uint256 chainId_); + function chainId() external view returns (uint256); + + function setInteropStart() external; /// @notice Executes a cross chain message on the destination chain. /// @param _id An Identifier pointing to the initiating message. /// @param _target Account that is called with _msg. - /// @param _msg The message payload, matching the initiating message. - function executeMessage( - ICrossL2Inbox.Identifier calldata _id, - address _target, - bytes calldata _msg - ) - external - payable; + /// @param _message The message payload, matching the initiating message. + function executeMessage(Identifier calldata _id, address _target, bytes calldata _message) external payable; /// @notice Validates a cross chain message on the destination chain /// and emits an ExecutingMessage event. This function is useful diff --git a/packages/contracts-bedrock/src/L2/interfaces/ICrosschainERC20.sol b/packages/contracts-bedrock/src/L2/interfaces/IERC7802.sol similarity index 79% rename from packages/contracts-bedrock/src/L2/interfaces/ICrosschainERC20.sol rename to packages/contracts-bedrock/src/L2/interfaces/IERC7802.sol index efdebe8f8b471..469230e822d1b 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/ICrosschainERC20.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IERC7802.sol @@ -1,18 +1,20 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -/// @title ICrosschainERC20 +import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol"; + +/// @title IERC7802 /// @notice Defines the interface for crosschain ERC20 transfers. -interface ICrosschainERC20 { +interface IERC7802 is IERC165 { /// @notice Emitted when a crosschain transfer mints tokens. /// @param to Address of the account tokens are being minted for. /// @param amount Amount of tokens minted. - event CrosschainMinted(address indexed to, uint256 amount); + event CrosschainMint(address indexed to, uint256 amount); /// @notice Emitted when a crosschain transfer burns tokens. /// @param from Address of the account tokens are being burned from. /// @param amount Amount of tokens burned. - event CrosschainBurnt(address indexed from, uint256 amount); + event CrosschainBurn(address indexed from, uint256 amount); /// @notice Mint tokens through a crosschain transfer. /// @param _to Address to mint tokens to. diff --git a/packages/contracts-bedrock/src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol b/packages/contracts-bedrock/src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol index f8a803d78be82..00ca4906b5c45 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol @@ -1,17 +1,70 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import { ICrossL2Inbox } from "src/L2/interfaces/ICrossL2Inbox.sol"; +struct Identifier { + address origin; + uint256 blockNumber; + uint256 logIndex; + uint256 timestamp; + uint256 chainId; +} /// @title IL2ToL2CrossDomainMessenger /// @notice Interface for the L2ToL2CrossDomainMessenger contract. interface IL2ToL2CrossDomainMessenger { + /// @notice Thrown when a non-written slot in transient storage is attempted to be read from. + error NotEntered(); + + /// @notice Thrown when attempting to relay a message where payload origin is not L2ToL2CrossDomainMessenger. + error IdOriginNotL2ToL2CrossDomainMessenger(); + + /// @notice Thrown when the payload provided to the relay is not a SentMessage event. + error EventPayloadNotSentMessage(); + + /// @notice Thrown when attempting to send a message to the chain that the message is being sent from. + error MessageDestinationSameChain(); + + /// @notice Thrown when attempting to relay a message whose destination chain is not the chain relaying it. + error MessageDestinationNotRelayChain(); + + /// @notice Thrown when attempting to relay a message whose target is CrossL2Inbox. + error MessageTargetCrossL2Inbox(); + + /// @notice Thrown when attempting to relay a message whose target is L2ToL2CrossDomainMessenger. + error MessageTargetL2ToL2CrossDomainMessenger(); + + /// @notice Thrown when attempting to relay a message that has already been relayed. + error MessageAlreadyRelayed(); + + /// @notice Thrown when a reentrant call is detected. + error ReentrantCall(); + + /// @notice Thrown when a call to the target contract during message relay fails. + error TargetCallFailed(); + + /// @notice Emitted whenever a message is sent to a destination + /// @param destination Chain ID of the destination chain. + /// @param target Target contract or wallet address. + /// @param messageNonce Nonce associated with the messsage sent + /// @param sender Address initiating this message call + /// @param message Message payload to call target with. + event SentMessage( + uint256 indexed destination, address indexed target, uint256 indexed messageNonce, address sender, bytes message + ); + + /// @notice Emitted whenever a message is successfully relayed on this chain. + /// @param source Chain ID of the source chain. + /// @param messageNonce Nonce associated with the messsage sent + /// @param messageHash Hash of the message that was relayed. + event RelayedMessage(uint256 indexed source, uint256 indexed messageNonce, bytes32 indexed messageHash); + + function version() external view returns (string memory); + /// @notice Mapping of message hashes to boolean receipt values. Note that a message will only /// be present in this mapping if it has successfully been relayed on this chain, and /// can therefore not be relayed again. - /// @param _msgHash message hash to check. /// @return Returns true if the message corresponding to the `_msgHash` was successfully relayed. - function successfulMessages(bytes32 _msgHash) external view returns (bool); + function successfulMessages(bytes32) external view returns (bool); /// @notice Retrieves the next message nonce. Message version will be added to the upper two /// bytes of the message nonce. Message version allows us to treat messages as having @@ -41,18 +94,16 @@ interface IL2ToL2CrossDomainMessenger { /// @param _message Message to trigger the target address with. /// @return msgHash_ The hash of the message being sent, which can be used for tracking whether /// the message has successfully been relayed. - function sendMessage( - uint256 _destination, - address _target, - bytes calldata _message - ) - external - returns (bytes32 msgHash_); + function sendMessage(uint256 _destination, address _target, bytes calldata _message) external returns (bytes32); /// @notice Relays a message that was sent by the other CrossDomainMessenger contract. Can only /// be executed via cross-chain call from the other messenger OR if the message was /// already received once and is currently being replayed. /// @param _id Identifier of the SentMessage event to be relayed /// @param _sentMessage Message payload of the `SentMessage` event - function relayMessage(ICrossL2Inbox.Identifier calldata _id, bytes calldata _sentMessage) external payable; + function relayMessage(Identifier calldata _id, bytes calldata _sentMessage) external payable; + + function messageVersion() external view returns (uint16); + + function __constructor__() external; } diff --git a/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol b/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol index ce066a27b88c4..029b13d5520ae 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol @@ -2,15 +2,17 @@ pragma solidity ^0.8.0; // Interfaces -import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol"; +import { IERC7802 } from "src/L2/interfaces/IERC7802.sol"; import { IERC20Solady as IERC20 } from "src/vendor/interfaces/IERC20Solady.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; /// @title ISuperchainERC20 /// @notice This interface is available on the SuperchainERC20 contract. /// @dev This interface is needed for the abstract SuperchainERC20 implementation but is not part of the standard -interface ISuperchainERC20 is ICrosschainERC20, IERC20, ISemver { +interface ISuperchainERC20 is IERC7802, IERC20, ISemver { error Unauthorized(); + function supportsInterface(bytes4 _interfaceId) external view returns (bool); + function __constructor__() external; } diff --git a/packages/contracts-bedrock/src/L2/interfaces/ISuperchainTokenBridge.sol b/packages/contracts-bedrock/src/L2/interfaces/ISuperchainTokenBridge.sol index f2a61d02d555f..af9d7d8d8411d 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/ISuperchainTokenBridge.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/ISuperchainTokenBridge.sol @@ -9,6 +9,7 @@ interface ISuperchainTokenBridge is ISemver { error ZeroAddress(); error Unauthorized(); error InvalidCrossDomainSender(); + error InvalidERC7802(); event SendERC20( address indexed token, address indexed from, address indexed to, uint256 amount, uint256 destination diff --git a/packages/contracts-bedrock/src/L2/interfaces/ISuperchainWETH.sol b/packages/contracts-bedrock/src/L2/interfaces/ISuperchainWETH.sol index 4c91322c6b12f..fa10b237dbb53 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/ISuperchainWETH.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/ISuperchainWETH.sol @@ -1,13 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import { IWETH } from "src/universal/interfaces/IWETH.sol"; -import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol"; +import { IWETH98 } from "src/universal/interfaces/IWETH98.sol"; +import { IERC7802 } from "src/L2/interfaces/IERC7802.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; -interface ISuperchainWETH is IWETH, ICrosschainERC20, ISemver { +interface ISuperchainWETH is IWETH98, IERC7802, ISemver { error Unauthorized(); error NotCustomGasToken(); + function balanceOf(address src) external view returns (uint256); + function withdraw(uint256 _amount) external; + function supportsInterface(bytes4 _interfaceId) external view returns (bool); + function __constructor__() external; } diff --git a/packages/contracts-bedrock/src/cannon/MIPS.sol b/packages/contracts-bedrock/src/cannon/MIPS.sol index 337a2d47ee2b4..5efab0ce98f15 100644 --- a/packages/contracts-bedrock/src/cannon/MIPS.sol +++ b/packages/contracts-bedrock/src/cannon/MIPS.sol @@ -44,8 +44,8 @@ contract MIPS is ISemver { } /// @notice The semantic version of the MIPS contract. - /// @custom:semver 1.2.1-beta.4 - string public constant version = "1.2.1-beta.4"; + /// @custom:semver 1.2.1-beta.7 + string public constant version = "1.2.1-beta.7"; /// @notice The preimage oracle contract. IPreimageOracle internal immutable ORACLE; diff --git a/packages/contracts-bedrock/src/cannon/MIPS2.sol b/packages/contracts-bedrock/src/cannon/MIPS2.sol index 7946cd0c3362f..1d73473fde245 100644 --- a/packages/contracts-bedrock/src/cannon/MIPS2.sol +++ b/packages/contracts-bedrock/src/cannon/MIPS2.sol @@ -60,8 +60,8 @@ contract MIPS2 is ISemver { } /// @notice The semantic version of the MIPS2 contract. - /// @custom:semver 1.0.0-beta.17 - string public constant version = "1.0.0-beta.17"; + /// @custom:semver 1.0.0-beta.22 + string public constant version = "1.0.0-beta.22"; /// @notice The preimage oracle contract. IPreimageOracle internal immutable ORACLE; @@ -102,7 +102,39 @@ contract MIPS2 is ISemver { /// the current thread stack. /// @param _localContext The local key context for the preimage oracle. Optional, can be set as a constant /// if the caller only requires one set of local keys. - function step(bytes calldata _stateData, bytes calldata _proof, bytes32 _localContext) public returns (bytes32) { + /// @return postState_ The hash of the post state witness after the state transition. + function step( + bytes calldata _stateData, + bytes calldata _proof, + bytes32 _localContext + ) + public + returns (bytes32 postState_) + { + postState_ = doStep(_stateData, _proof, _localContext); + assertPostStateChecks(); + } + + function assertPostStateChecks() internal pure { + State memory state; + assembly { + state := STATE_MEM_OFFSET + } + + bytes32 activeStack = state.traverseRight ? state.rightThreadStack : state.leftThreadStack; + if (activeStack == EMPTY_THREAD_ROOT) { + revert("MIPS2: post-state active thread stack is empty"); + } + } + + function doStep( + bytes calldata _stateData, + bytes calldata _proof, + bytes32 _localContext + ) + internal + returns (bytes32) + { unchecked { State memory state; ThreadState memory thread; @@ -555,6 +587,8 @@ contract MIPS2 is ISemver { // ignored } else if (syscall_no == sys.SYS_PREAD64) { // ignored + } else if (syscall_no == sys.SYS_STAT) { + // ignored } else if (syscall_no == sys.SYS_FSTAT) { // ignored } else if (syscall_no == sys.SYS_OPENAT) { @@ -593,6 +627,10 @@ contract MIPS2 is ISemver { // ignored } else if (syscall_no == sys.SYS_TIMERDELETE) { // ignored + } else if (syscall_no == sys.SYS_GETRLIMIT) { + // ignored + } else if (syscall_no == sys.SYS_LSEEK) { + // ignored } else { if (syscall_no == sys.SYS_FSTAT64 || syscall_no == sys.SYS_STAT64 || syscall_no == sys.SYS_LLSEEK) { // noop diff --git a/packages/contracts-bedrock/src/cannon/MIPS64.sol b/packages/contracts-bedrock/src/cannon/MIPS64.sol new file mode 100644 index 0000000000000..53dd0649405d5 --- /dev/null +++ b/packages/contracts-bedrock/src/cannon/MIPS64.sol @@ -0,0 +1,985 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { ISemver } from "src/universal/interfaces/ISemver.sol"; +import { IPreimageOracle } from "./interfaces/IPreimageOracle.sol"; +import { MIPS64Memory } from "src/cannon/libraries/MIPS64Memory.sol"; +import { MIPS64Syscalls as sys } from "src/cannon/libraries/MIPS64Syscalls.sol"; +import { MIPS64State as st } from "src/cannon/libraries/MIPS64State.sol"; +import { MIPS64Instructions as ins } from "src/cannon/libraries/MIPS64Instructions.sol"; +import { MIPS64Arch as arch } from "src/cannon/libraries/MIPS64Arch.sol"; +import { VMStatuses } from "src/dispute/lib/Types.sol"; +import { + InvalidMemoryProof, InvalidRMWInstruction, InvalidSecondMemoryProof +} from "src/cannon/libraries/CannonErrors.sol"; + +/// @title MIPS64 +/// @notice The MIPS64 contract emulates a single MIPS instruction. +/// It differs from MIPS.sol in that it supports MIPS64 instructions and multi-tasking. +contract MIPS64 is ISemver { + /// @notice The thread context. + /// Total state size: 8 + 1 + 1 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 32 * 8 = 322 bytes + struct ThreadState { + // metadata + uint64 threadID; + uint8 exitCode; + bool exited; + // state + uint64 futexAddr; + uint64 futexVal; + uint64 futexTimeoutStep; + uint64 pc; + uint64 nextPC; + uint64 lo; + uint64 hi; + uint64[32] registers; + } + + uint32 internal constant PACKED_THREAD_STATE_SIZE = 322; + + uint8 internal constant LL_STATUS_NONE = 0; + uint8 internal constant LL_STATUS_ACTIVE_32_BIT = 0x1; + uint8 internal constant LL_STATUS_ACTIVE_64_BIT = 0x2; + + /// @notice Stores the VM state. + /// Total state size: 32 + 32 + 8 + 8 + 1 + 8 + 8 + 1 + 1 + 8 + 8 + 8 + 1 + 32 + 32 + 8 = 196 bytes + /// If nextPC != pc + 4, then the VM is executing a branch/jump delay slot. + struct State { + bytes32 memRoot; + bytes32 preimageKey; + uint64 preimageOffset; + uint64 heap; + uint8 llReservationStatus; + uint64 llAddress; + uint64 llOwnerThread; + uint8 exitCode; + bool exited; + uint64 step; + uint64 stepsSinceLastContextSwitch; + uint64 wakeup; + bool traverseRight; + bytes32 leftThreadStack; + bytes32 rightThreadStack; + uint64 nextThreadID; + } + + /// @notice The semantic version of the MIPS64 contract. + /// @custom:semver 1.0.0-beta.4 + string public constant version = "1.0.0-beta.4"; + + /// @notice The preimage oracle contract. + IPreimageOracle internal immutable ORACLE; + + // The offset of the start of proof calldata (_threadWitness.offset) in the step() function + uint256 internal constant THREAD_PROOF_OFFSET = 388; + + // The offset of the start of proof calldata (_memProof.offset) in the step() function + uint256 internal constant MEM_PROOF_OFFSET = THREAD_PROOF_OFFSET + PACKED_THREAD_STATE_SIZE + 32; + + // The empty thread root - keccak256(bytes32(0) ++ bytes32(0)) + bytes32 internal constant EMPTY_THREAD_ROOT = hex"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5"; + + // State memory offset allocated during step + uint256 internal constant STATE_MEM_OFFSET = 0x80; + + // ThreadState memory offset allocated during step + uint256 internal constant TC_MEM_OFFSET = 0x280; + + /// @param _oracle The address of the preimage oracle contract. + constructor(IPreimageOracle _oracle) { + ORACLE = _oracle; + } + + /// @notice Getter for the pre-image oracle contract. + /// @return oracle_ The IPreimageOracle contract. + function oracle() external view returns (IPreimageOracle oracle_) { + oracle_ = ORACLE; + } + + /// @notice Executes a single step of the multi-threaded vm. + /// Will revert if any required input state is missing. + /// @param _stateData The encoded state witness data. + /// @param _proof The encoded proof data: <, . + /// Contains the thread context witness and the memory proof data for leaves within the MIPS VM's + /// memory. + /// The thread context witness is a packed tuple of the thread context and the immediate inner root of + /// the current thread stack. + /// @param _localContext The local key context for the preimage oracle. Optional, can be set as a constant + /// if the caller only requires one set of local keys. + /// @return postState_ The hash of the post state witness after the state transition. + function step( + bytes calldata _stateData, + bytes calldata _proof, + bytes32 _localContext + ) + public + returns (bytes32 postState_) + { + postState_ = doStep(_stateData, _proof, _localContext); + assertPostStateChecks(); + } + + function assertPostStateChecks() internal pure { + State memory state; + assembly { + state := STATE_MEM_OFFSET + } + + bytes32 activeStack = state.traverseRight ? state.rightThreadStack : state.leftThreadStack; + if (activeStack == EMPTY_THREAD_ROOT) { + revert("MIPS64: post-state active thread stack is empty"); + } + } + + function doStep( + bytes calldata _stateData, + bytes calldata _proof, + bytes32 _localContext + ) + internal + returns (bytes32) + { + unchecked { + State memory state; + ThreadState memory thread; + uint32 exited; + assembly { + if iszero(eq(state, STATE_MEM_OFFSET)) { + // expected state mem offset check + revert(0, 0) + } + if iszero(eq(thread, TC_MEM_OFFSET)) { + // expected thread mem offset check + revert(0, 0) + } + if iszero(eq(mload(0x40), shl(5, 63))) { + // 4 + 16 state slots + 43 thread slots = 63 expected memory check + revert(0, 0) + } + if iszero(eq(_stateData.offset, 132)) { + // 32*4+4=132 expected state data offset + revert(0, 0) + } + if iszero(eq(_proof.offset, THREAD_PROOF_OFFSET)) { + // _stateData.offset = 132 + // stateData.length = 196 + // 32-byte align padding = 28 + // _proof size prefix = 32 + // expected thread proof offset equals the sum of the above is 388 + revert(0, 0) + } + + function putField(callOffset, memOffset, size) -> callOffsetOut, memOffsetOut { + // calldata is packed, thus starting left-aligned, shift-right to pad and right-align + let w := shr(shl(3, sub(32, size)), calldataload(callOffset)) + mstore(memOffset, w) + callOffsetOut := add(callOffset, size) + memOffsetOut := add(memOffset, 32) + } + + // Unpack state from calldata into memory + let c := _stateData.offset // calldata offset + let m := STATE_MEM_OFFSET // mem offset + c, m := putField(c, m, 32) // memRoot + c, m := putField(c, m, 32) // preimageKey + c, m := putField(c, m, 8) // preimageOffset + c, m := putField(c, m, 8) // heap + c, m := putField(c, m, 1) // llReservationStatus + c, m := putField(c, m, 8) // llAddress + c, m := putField(c, m, 8) // llOwnerThread + c, m := putField(c, m, 1) // exitCode + c, m := putField(c, m, 1) // exited + exited := mload(sub(m, 32)) + c, m := putField(c, m, 8) // step + c, m := putField(c, m, 8) // stepsSinceLastContextSwitch + c, m := putField(c, m, 8) // wakeup + c, m := putField(c, m, 1) // traverseRight + c, m := putField(c, m, 32) // leftThreadStack + c, m := putField(c, m, 32) // rightThreadStack + c, m := putField(c, m, 8) // nextThreadID + } + st.assertExitedIsValid(exited); + + if (state.exited) { + // thread state is unchanged + return outputState(); + } + + if ( + (state.leftThreadStack == EMPTY_THREAD_ROOT && !state.traverseRight) + || (state.rightThreadStack == EMPTY_THREAD_ROOT && state.traverseRight) + ) { + revert("MIPS64: active thread stack is empty"); + } + + state.step += 1; + + setThreadStateFromCalldata(thread); + validateCalldataThreadWitness(state, thread); + + // Search for the first thread blocked by the wakeup call, if wakeup is set + // Don't allow regular execution until we resolved if we have woken up any thread. + if (state.wakeup != sys.FUTEX_EMPTY_ADDR) { + if (state.wakeup == thread.futexAddr) { + // completed wake traversal + // resume execution on woken up thread + state.wakeup = sys.FUTEX_EMPTY_ADDR; + return outputState(); + } else { + bool traversingRight = state.traverseRight; + bool changedDirections = preemptThread(state, thread); + if (traversingRight && changedDirections) { + // then we've completed wake traversal + // resume thread execution + state.wakeup = sys.FUTEX_EMPTY_ADDR; + } + return outputState(); + } + } + + if (thread.exited) { + popThread(state); + return outputState(); + } + + // check if thread is blocked on a futex + if (thread.futexAddr != sys.FUTEX_EMPTY_ADDR) { + // if set, then check futex + // check timeout first + if (state.step > thread.futexTimeoutStep) { + // timeout! Allow execution + return onWaitComplete(thread, true); + } else { + uint64 mem = MIPS64Memory.readMem( + state.memRoot, + thread.futexAddr & arch.ADDRESS_MASK, + MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1) + ); + if (thread.futexVal == mem) { + // still got expected value, continue sleeping, try next thread. + preemptThread(state, thread); + return outputState(); + } else { + // wake thread up, the value at its address changed! + // Userspace can turn thread back to sleep if it was too sporadic. + return onWaitComplete(thread, false); + } + } + } + + if (state.stepsSinceLastContextSwitch >= sys.SCHED_QUANTUM) { + preemptThread(state, thread); + return outputState(); + } + state.stepsSinceLastContextSwitch += 1; + + // instruction fetch + uint256 insnProofOffset = MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 0); + (uint32 insn, uint32 opcode, uint32 fun) = + ins.getInstructionDetails(thread.pc, state.memRoot, insnProofOffset); + + // Handle syscall separately + // syscall (can read and write) + if (opcode == 0 && fun == 0xC) { + return handleSyscall(_localContext); + } + + // Handle RMW (read-modify-write) ops + if (opcode == ins.OP_LOAD_LINKED || opcode == ins.OP_STORE_CONDITIONAL) { + return handleRMWOps(state, thread, insn, opcode); + } + if (opcode == ins.OP_LOAD_LINKED64 || opcode == ins.OP_STORE_CONDITIONAL64) { + return handleRMWOps(state, thread, insn, opcode); + } + + // Exec the rest of the step logic + st.CpuScalars memory cpu = getCpuScalars(thread); + ins.CoreStepLogicParams memory coreStepArgs = ins.CoreStepLogicParams({ + cpu: cpu, + registers: thread.registers, + memRoot: state.memRoot, + memProofOffset: MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1), + insn: insn, + opcode: opcode, + fun: fun + }); + bool memUpdated; + uint64 effMemAddr; + (state.memRoot, memUpdated, effMemAddr) = ins.execMipsCoreStepLogic(coreStepArgs); + setStateCpuScalars(thread, cpu); + updateCurrentThreadRoot(); + if (memUpdated) { + handleMemoryUpdate(state, effMemAddr); + } + + return outputState(); + } + } + + function handleMemoryUpdate(State memory _state, uint64 _effMemAddr) internal pure { + if (_effMemAddr == (arch.ADDRESS_MASK & _state.llAddress)) { + // Reserved address was modified, clear the reservation + clearLLMemoryReservation(_state); + } + } + + function clearLLMemoryReservation(State memory _state) internal pure { + _state.llReservationStatus = LL_STATUS_NONE; + _state.llAddress = 0; + _state.llOwnerThread = 0; + } + + function handleRMWOps( + State memory _state, + ThreadState memory _thread, + uint32 _insn, + uint32 _opcode + ) + internal + returns (bytes32) + { + unchecked { + uint64 base = _thread.registers[(_insn >> 21) & 0x1F]; + uint32 rtReg = (_insn >> 16) & 0x1F; + uint64 addr = base + ins.signExtendImmediate(_insn); + + // Determine some opcode-specific parameters + uint8 targetStatus = LL_STATUS_ACTIVE_32_BIT; + uint64 byteLength = 4; + if (_opcode == ins.OP_LOAD_LINKED64 || _opcode == ins.OP_STORE_CONDITIONAL64) { + // Use 64-bit params + targetStatus = LL_STATUS_ACTIVE_64_BIT; + byteLength = 8; + } + + uint64 retVal = 0; + uint64 threadId = _thread.threadID; + if (_opcode == ins.OP_LOAD_LINKED || _opcode == ins.OP_LOAD_LINKED64) { + retVal = loadSubWord(_state, addr, byteLength, true); + + _state.llReservationStatus = targetStatus; + _state.llAddress = addr; + _state.llOwnerThread = threadId; + } else if (_opcode == ins.OP_STORE_CONDITIONAL || _opcode == ins.OP_STORE_CONDITIONAL64) { + // Check if our memory reservation is still intact + if ( + _state.llReservationStatus == targetStatus && _state.llOwnerThread == threadId + && _state.llAddress == addr + ) { + // Complete atomic update: set memory and return 1 for success + clearLLMemoryReservation(_state); + + uint64 val = _thread.registers[rtReg]; + storeSubWord(_state, addr, byteLength, val); + + retVal = 1; + } else { + // Atomic update failed, return 0 for failure + retVal = 0; + } + } else { + revert InvalidRMWInstruction(); + } + + st.CpuScalars memory cpu = getCpuScalars(_thread); + ins.handleRd(cpu, _thread.registers, rtReg, retVal, true); + setStateCpuScalars(_thread, cpu); + updateCurrentThreadRoot(); + + return outputState(); + } + } + + /// @notice Loads a subword of byteLength size contained from memory based on the low-order bits of vaddr + /// @param _vaddr The virtual address of the the subword. + /// @param _byteLength The size of the subword. + /// @param _signExtend Whether to sign extend the selected subwrod. + function loadSubWord( + State memory _state, + uint64 _vaddr, + uint64 _byteLength, + bool _signExtend + ) + internal + pure + returns (uint64 val_) + { + uint64 effAddr = _vaddr & arch.ADDRESS_MASK; + uint256 memProofOffset = MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1); + uint64 mem = MIPS64Memory.readMem(_state.memRoot, effAddr, memProofOffset); + val_ = ins.selectSubWord(_vaddr, mem, _byteLength, _signExtend); + } + + /// @notice Stores a word that has been updated by the specified subword at bit positions determined by the virtual + /// address + /// @param _vaddr The virtual address of the subword. + /// @param _byteLength The size of the subword. + /// @param _value The subword that updates _memWord. + function storeSubWord(State memory _state, uint64 _vaddr, uint64 _byteLength, uint64 _value) internal pure { + uint64 effAddr = _vaddr & arch.ADDRESS_MASK; + uint256 memProofOffset = MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1); + uint64 mem = MIPS64Memory.readMem(_state.memRoot, effAddr, memProofOffset); + + uint64 newMemVal = ins.updateSubWord(_vaddr, mem, _byteLength, _value); + _state.memRoot = MIPS64Memory.writeMem(effAddr, memProofOffset, newMemVal); + } + + function handleSyscall(bytes32 _localContext) internal returns (bytes32 out_) { + unchecked { + // Load state from memory offsets to reduce stack pressure + State memory state; + ThreadState memory thread; + assembly { + state := STATE_MEM_OFFSET + thread := TC_MEM_OFFSET + } + + // Load the syscall numbers and args from the registers + (uint64 syscall_no, uint64 a0, uint64 a1, uint64 a2, uint64 a3) = sys.getSyscallArgs(thread.registers); + // Syscalls that are unimplemented but known return with v0=0 and v1=0 + uint64 v0 = 0; + uint64 v1 = 0; + + if (syscall_no == sys.SYS_MMAP) { + (v0, v1, state.heap) = sys.handleSysMmap(a0, a1, state.heap); + } else if (syscall_no == sys.SYS_BRK) { + // brk: Returns a fixed address for the program break at 0x40000000 + v0 = sys.PROGRAM_BREAK; + } else if (syscall_no == sys.SYS_CLONE) { + if (sys.VALID_SYS_CLONE_FLAGS != a0) { + state.exited = true; + state.exitCode = VMStatuses.PANIC.raw(); + return outputState(); + } + v0 = state.nextThreadID; + v1 = 0; + ThreadState memory newThread; + newThread.threadID = state.nextThreadID; + newThread.exitCode = 0; + newThread.exited = false; + newThread.futexAddr = sys.FUTEX_EMPTY_ADDR; + newThread.futexVal = 0; + newThread.futexTimeoutStep = 0; + newThread.pc = thread.nextPC; + newThread.nextPC = thread.nextPC + 4; + newThread.lo = thread.lo; + newThread.hi = thread.hi; + for (uint256 i; i < 32; i++) { + newThread.registers[i] = thread.registers[i]; + } + newThread.registers[29] = a1; // set stack pointer + // the child will perceive a 0 value as returned value instead, and no error + newThread.registers[2] = 0; + newThread.registers[7] = 0; + state.nextThreadID++; + + // Preempt this thread for the new one. But not before updating PCs + st.CpuScalars memory cpu0 = getCpuScalars(thread); + sys.handleSyscallUpdates(cpu0, thread.registers, v0, v1); + setStateCpuScalars(thread, cpu0); + updateCurrentThreadRoot(); + pushThread(state, newThread); + return outputState(); + } else if (syscall_no == sys.SYS_EXIT_GROUP) { + // exit group: Sets the Exited and ExitCode states to true and argument 0. + state.exited = true; + state.exitCode = uint8(a0); + updateCurrentThreadRoot(); + return outputState(); + } else if (syscall_no == sys.SYS_READ) { + sys.SysReadParams memory args = sys.SysReadParams({ + a0: a0, + a1: a1, + a2: a2, + preimageKey: state.preimageKey, + preimageOffset: state.preimageOffset, + localContext: _localContext, + oracle: ORACLE, + proofOffset: MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1), + memRoot: state.memRoot + }); + // Encapsulate execution to avoid stack-too-deep error + (v0, v1) = execSysRead(state, args); + } else if (syscall_no == sys.SYS_WRITE) { + (v0, v1, state.preimageKey, state.preimageOffset) = sys.handleSysWrite({ + _a0: a0, + _a1: a1, + _a2: a2, + _preimageKey: state.preimageKey, + _preimageOffset: state.preimageOffset, + _proofOffset: MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1), + _memRoot: state.memRoot + }); + } else if (syscall_no == sys.SYS_FCNTL) { + (v0, v1) = sys.handleSysFcntl(a0, a1); + } else if (syscall_no == sys.SYS_GETTID) { + v0 = thread.threadID; + v1 = 0; + } else if (syscall_no == sys.SYS_EXIT) { + thread.exited = true; + thread.exitCode = uint8(a0); + if (lastThreadRemaining(state)) { + state.exited = true; + state.exitCode = uint8(a0); + } + updateCurrentThreadRoot(); + return outputState(); + } else if (syscall_no == sys.SYS_FUTEX) { + // args: a0 = addr, a1 = op, a2 = val, a3 = timeout + uint64 effAddr = a0 & arch.ADDRESS_MASK; + if (a1 == sys.FUTEX_WAIT_PRIVATE) { + uint64 mem = MIPS64Memory.readMem( + state.memRoot, effAddr, MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1) + ); + if (mem != a2) { + v0 = sys.SYS_ERROR_SIGNAL; + v1 = sys.EAGAIN; + } else { + thread.futexAddr = effAddr; + thread.futexVal = a2; + thread.futexTimeoutStep = a3 == 0 ? sys.FUTEX_NO_TIMEOUT : state.step + sys.FUTEX_TIMEOUT_STEPS; + // Leave cpu scalars as-is. This instruction will be completed by `onWaitComplete` + updateCurrentThreadRoot(); + return outputState(); + } + } else if (a1 == sys.FUTEX_WAKE_PRIVATE) { + // Trigger thread traversal starting from the left stack until we find one waiting on the wakeup + // address + state.wakeup = effAddr; + // Don't indicate to the program that we've woken up a waiting thread, as there are no guarantees. + // The woken up thread should indicate this in userspace. + v0 = 0; + v1 = 0; + st.CpuScalars memory cpu0 = getCpuScalars(thread); + sys.handleSyscallUpdates(cpu0, thread.registers, v0, v1); + setStateCpuScalars(thread, cpu0); + preemptThread(state, thread); + state.traverseRight = state.leftThreadStack == EMPTY_THREAD_ROOT; + return outputState(); + } else { + v0 = sys.SYS_ERROR_SIGNAL; + v1 = sys.EINVAL; + } + } else if (syscall_no == sys.SYS_SCHED_YIELD || syscall_no == sys.SYS_NANOSLEEP) { + v0 = 0; + v1 = 0; + st.CpuScalars memory cpu0 = getCpuScalars(thread); + sys.handleSyscallUpdates(cpu0, thread.registers, v0, v1); + setStateCpuScalars(thread, cpu0); + preemptThread(state, thread); + return outputState(); + } else if (syscall_no == sys.SYS_OPEN) { + v0 = sys.SYS_ERROR_SIGNAL; + v1 = sys.EBADF; + } else if (syscall_no == sys.SYS_CLOCKGETTIME) { + if (a0 == sys.CLOCK_GETTIME_REALTIME_FLAG || a0 == sys.CLOCK_GETTIME_MONOTONIC_FLAG) { + v0 = 0; + v1 = 0; + uint64 secs = 0; + uint64 nsecs = 0; + if (a0 == sys.CLOCK_GETTIME_MONOTONIC_FLAG) { + secs = uint64(state.step / sys.HZ); + nsecs = uint64((state.step % sys.HZ) * (1_000_000_000 / sys.HZ)); + } + uint64 effAddr = a1 & arch.ADDRESS_MASK; + // First verify the effAddr path + if ( + !MIPS64Memory.isValidProof( + state.memRoot, effAddr, MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1) + ) + ) { + revert InvalidMemoryProof(); + } + // Recompute the new root after updating effAddr + state.memRoot = + MIPS64Memory.writeMem(effAddr, MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 1), secs); + handleMemoryUpdate(state, effAddr); + // Verify the second memory proof against the newly computed root + if ( + !MIPS64Memory.isValidProof( + state.memRoot, effAddr + 8, MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 2) + ) + ) { + revert InvalidSecondMemoryProof(); + } + state.memRoot = + MIPS64Memory.writeMem(effAddr + 8, MIPS64Memory.memoryProofOffset(MEM_PROOF_OFFSET, 2), nsecs); + handleMemoryUpdate(state, effAddr + 8); + } else { + v0 = sys.SYS_ERROR_SIGNAL; + v1 = sys.EINVAL; + } + } else if (syscall_no == sys.SYS_GETPID) { + v0 = 0; + v1 = 0; + } else if (syscall_no == sys.SYS_MUNMAP) { + // ignored + } else if (syscall_no == sys.SYS_GETAFFINITY) { + // ignored + } else if (syscall_no == sys.SYS_MADVISE) { + // ignored + } else if (syscall_no == sys.SYS_RTSIGPROCMASK) { + // ignored + } else if (syscall_no == sys.SYS_SIGALTSTACK) { + // ignored + } else if (syscall_no == sys.SYS_RTSIGACTION) { + // ignored + } else if (syscall_no == sys.SYS_PRLIMIT64) { + // ignored + } else if (syscall_no == sys.SYS_CLOSE) { + // ignored + } else if (syscall_no == sys.SYS_PREAD64) { + // ignored + } else if (syscall_no == sys.SYS_STAT) { + // ignored + } else if (syscall_no == sys.SYS_FSTAT) { + // ignored + } else if (syscall_no == sys.SYS_OPENAT) { + // ignored + } else if (syscall_no == sys.SYS_READLINK) { + // ignored + } else if (syscall_no == sys.SYS_READLINKAT) { + // ignored + } else if (syscall_no == sys.SYS_IOCTL) { + // ignored + } else if (syscall_no == sys.SYS_EPOLLCREATE1) { + // ignored + } else if (syscall_no == sys.SYS_PIPE2) { + // ignored + } else if (syscall_no == sys.SYS_EPOLLCTL) { + // ignored + } else if (syscall_no == sys.SYS_EPOLLPWAIT) { + // ignored + } else if (syscall_no == sys.SYS_GETRANDOM) { + // ignored + } else if (syscall_no == sys.SYS_UNAME) { + // ignored + } else if (syscall_no == sys.SYS_GETUID) { + // ignored + } else if (syscall_no == sys.SYS_GETGID) { + // ignored + } else if (syscall_no == sys.SYS_MINCORE) { + // ignored + } else if (syscall_no == sys.SYS_TGKILL) { + // ignored + } else if (syscall_no == sys.SYS_SETITIMER) { + // ignored + } else if (syscall_no == sys.SYS_TIMERCREATE) { + // ignored + } else if (syscall_no == sys.SYS_TIMERSETTIME) { + // ignored + } else if (syscall_no == sys.SYS_TIMERDELETE) { + // ignored + } else if (syscall_no == sys.SYS_GETRLIMIT) { + // ignored + } else if (syscall_no == sys.SYS_LSEEK) { + // ignored + } else { + revert("MIPS64: unimplemented syscall"); + } + + st.CpuScalars memory cpu = getCpuScalars(thread); + sys.handleSyscallUpdates(cpu, thread.registers, v0, v1); + setStateCpuScalars(thread, cpu); + + updateCurrentThreadRoot(); + out_ = outputState(); + } + } + + function execSysRead( + State memory _state, + sys.SysReadParams memory _args + ) + internal + view + returns (uint64 v0_, uint64 v1_) + { + bool memUpdated; + uint64 memAddr; + (v0_, v1_, _state.preimageOffset, _state.memRoot, memUpdated, memAddr) = sys.handleSysRead(_args); + if (memUpdated) { + handleMemoryUpdate(_state, memAddr); + } + } + + /// @notice Computes the hash of the MIPS state. + /// @return out_ The hashed MIPS state. + function outputState() internal returns (bytes32 out_) { + uint32 exited; + assembly { + // copies 'size' bytes, right-aligned in word at 'from', to 'to', incl. trailing data + function copyMem(from, to, size) -> fromOut, toOut { + mstore(to, mload(add(from, sub(32, size)))) + fromOut := add(from, 32) + toOut := add(to, size) + } + + // From points to the MIPS State + let from := STATE_MEM_OFFSET + + // Copy to the free memory pointer + let start := mload(0x40) + let to := start + + // Copy state to free memory + from, to := copyMem(from, to, 32) // memRoot + from, to := copyMem(from, to, 32) // preimageKey + from, to := copyMem(from, to, 8) // preimageOffset + from, to := copyMem(from, to, 8) // heap + from, to := copyMem(from, to, 1) // llReservationStatus + from, to := copyMem(from, to, 8) // llAddress + from, to := copyMem(from, to, 8) // llOwnerThread + let exitCode := mload(from) + from, to := copyMem(from, to, 1) // exitCode + exited := mload(from) + from, to := copyMem(from, to, 1) // exited + from, to := copyMem(from, to, 8) // step + from, to := copyMem(from, to, 8) // stepsSinceLastContextSwitch + from, to := copyMem(from, to, 8) // wakeup + from, to := copyMem(from, to, 1) // traverseRight + from, to := copyMem(from, to, 32) // leftThreadStack + from, to := copyMem(from, to, 32) // rightThreadStack + from, to := copyMem(from, to, 8) // nextThreadID + + // Clean up end of memory + mstore(to, 0) + + // Log the resulting MIPS state, for debugging + log0(start, sub(to, start)) + + // Determine the VM status + let status := 0 + switch exited + case 1 { + switch exitCode + // VMStatusValid + case 0 { status := 0 } + // VMStatusInvalid + case 1 { status := 1 } + // VMStatusPanic + default { status := 2 } + } + // VMStatusUnfinished + default { status := 3 } + + // Compute the hash of the resulting MIPS state and set the status byte + out_ := keccak256(start, sub(to, start)) + out_ := or(and(not(shl(248, 0xFF)), out_), shl(248, status)) + } + + st.assertExitedIsValid(exited); + } + + /// @notice Updates the current thread stack root via inner thread root in calldata + function updateCurrentThreadRoot() internal pure { + State memory state; + ThreadState memory thread; + assembly { + state := STATE_MEM_OFFSET + thread := TC_MEM_OFFSET + } + bytes32 updatedRoot = computeThreadRoot(loadCalldataInnerThreadRoot(), thread); + if (state.traverseRight) { + state.rightThreadStack = updatedRoot; + } else { + state.leftThreadStack = updatedRoot; + } + } + + /// @notice Completes the FUTEX_WAIT syscall. + function onWaitComplete(ThreadState memory _thread, bool _isTimedOut) internal returns (bytes32 out_) { + // Note: no need to reset State.wakeup. If we're here, the wakeup field has already been reset + // Clear the futex state + _thread.futexAddr = sys.FUTEX_EMPTY_ADDR; + _thread.futexVal = 0; + _thread.futexTimeoutStep = 0; + + // Complete the FUTEX_WAIT syscall + uint64 v0 = _isTimedOut ? sys.SYS_ERROR_SIGNAL : 0; + // set errno + uint64 v1 = _isTimedOut ? sys.ETIMEDOUT : 0; + st.CpuScalars memory cpu = getCpuScalars(_thread); + sys.handleSyscallUpdates(cpu, _thread.registers, v0, v1); + setStateCpuScalars(_thread, cpu); + + updateCurrentThreadRoot(); + out_ = outputState(); + } + + /// @notice Preempts the current thread for another and updates the VM state. + /// It reads the inner thread root from calldata to update the current thread stack root. + function preemptThread( + State memory _state, + ThreadState memory _thread + ) + internal + pure + returns (bool changedDirections_) + { + // pop thread from the current stack and push to the other stack + if (_state.traverseRight) { + require(_state.rightThreadStack != EMPTY_THREAD_ROOT, "MIPS64: empty right thread stack"); + _state.rightThreadStack = loadCalldataInnerThreadRoot(); + _state.leftThreadStack = computeThreadRoot(_state.leftThreadStack, _thread); + } else { + require(_state.leftThreadStack != EMPTY_THREAD_ROOT, "MIPS64: empty left thread stack"); + _state.leftThreadStack = loadCalldataInnerThreadRoot(); + _state.rightThreadStack = computeThreadRoot(_state.rightThreadStack, _thread); + } + bytes32 current = _state.traverseRight ? _state.rightThreadStack : _state.leftThreadStack; + if (current == EMPTY_THREAD_ROOT) { + _state.traverseRight = !_state.traverseRight; + changedDirections_ = true; + } + _state.stepsSinceLastContextSwitch = 0; + } + + /// @notice Pushes a thread to the current thread stack. + function pushThread(State memory _state, ThreadState memory _thread) internal pure { + if (_state.traverseRight) { + _state.rightThreadStack = computeThreadRoot(_state.rightThreadStack, _thread); + } else { + _state.leftThreadStack = computeThreadRoot(_state.leftThreadStack, _thread); + } + _state.stepsSinceLastContextSwitch = 0; + } + + /// @notice Removes the current thread from the stack. + function popThread(State memory _state) internal pure { + if (_state.traverseRight) { + _state.rightThreadStack = loadCalldataInnerThreadRoot(); + } else { + _state.leftThreadStack = loadCalldataInnerThreadRoot(); + } + bytes32 current = _state.traverseRight ? _state.rightThreadStack : _state.leftThreadStack; + if (current == EMPTY_THREAD_ROOT) { + _state.traverseRight = !_state.traverseRight; + } + _state.stepsSinceLastContextSwitch = 0; + } + + /// @notice Returns true if the number of threads is 1 + function lastThreadRemaining(State memory _state) internal pure returns (bool out_) { + bytes32 inactiveStack = _state.traverseRight ? _state.leftThreadStack : _state.rightThreadStack; + bool currentStackIsAlmostEmpty = loadCalldataInnerThreadRoot() == EMPTY_THREAD_ROOT; + return inactiveStack == EMPTY_THREAD_ROOT && currentStackIsAlmostEmpty; + } + + function computeThreadRoot(bytes32 _currentRoot, ThreadState memory _thread) internal pure returns (bytes32 out_) { + // w_i = hash(w_0 ++ hash(thread)) + bytes32 threadRoot = outputThreadState(_thread); + out_ = keccak256(abi.encodePacked(_currentRoot, threadRoot)); + } + + function outputThreadState(ThreadState memory _thread) internal pure returns (bytes32 out_) { + assembly { + // copies 'size' bytes, right-aligned in word at 'from', to 'to', incl. trailing data + function copyMem(from, to, size) -> fromOut, toOut { + mstore(to, mload(add(from, sub(32, size)))) + fromOut := add(from, 32) + toOut := add(to, size) + } + + // From points to the ThreadState + let from := _thread + + // Copy to the free memory pointer + let start := mload(0x40) + let to := start + + // Copy state to free memory + from, to := copyMem(from, to, 8) // threadID + from, to := copyMem(from, to, 1) // exitCode + from, to := copyMem(from, to, 1) // exited + from, to := copyMem(from, to, 8) // futexAddr + from, to := copyMem(from, to, 8) // futexVal + from, to := copyMem(from, to, 8) // futexTimeoutStep + from, to := copyMem(from, to, 8) // pc + from, to := copyMem(from, to, 8) // nextPC + from, to := copyMem(from, to, 8) // lo + from, to := copyMem(from, to, 8) // hi + from := mload(from) // offset to registers + // Copy registers + for { let i := 0 } lt(i, 32) { i := add(i, 1) } { from, to := copyMem(from, to, 8) } + + // Clean up end of memory + mstore(to, 0) + + // Compute the hash of the resulting ThreadState + out_ := keccak256(start, sub(to, start)) + } + } + + function getCpuScalars(ThreadState memory _tc) internal pure returns (st.CpuScalars memory cpu_) { + cpu_ = st.CpuScalars({ pc: _tc.pc, nextPC: _tc.nextPC, lo: _tc.lo, hi: _tc.hi }); + } + + function setStateCpuScalars(ThreadState memory _tc, st.CpuScalars memory _cpu) internal pure { + _tc.pc = _cpu.pc; + _tc.nextPC = _cpu.nextPC; + _tc.lo = _cpu.lo; + _tc.hi = _cpu.hi; + } + + /// @notice Validates the thread witness in calldata against the current thread. + function validateCalldataThreadWitness(State memory _state, ThreadState memory _thread) internal pure { + bytes32 witnessRoot = computeThreadRoot(loadCalldataInnerThreadRoot(), _thread); + bytes32 expectedRoot = _state.traverseRight ? _state.rightThreadStack : _state.leftThreadStack; + require(expectedRoot == witnessRoot, "MIPS64: invalid thread witness"); + } + + /// @notice Sets the thread context from calldata. + function setThreadStateFromCalldata(ThreadState memory _thread) internal pure { + uint256 s = 0; + assembly { + s := calldatasize() + } + // verify we have enough calldata + require( + s >= (THREAD_PROOF_OFFSET + PACKED_THREAD_STATE_SIZE), "MIPS64: insufficient calldata for thread witness" + ); + + unchecked { + assembly { + function putField(callOffset, memOffset, size) -> callOffsetOut, memOffsetOut { + // calldata is packed, thus starting left-aligned, shift-right to pad and right-align + let w := shr(shl(3, sub(32, size)), calldataload(callOffset)) + mstore(memOffset, w) + callOffsetOut := add(callOffset, size) + memOffsetOut := add(memOffset, 32) + } + + let c := THREAD_PROOF_OFFSET + let m := _thread + c, m := putField(c, m, 8) // threadID + c, m := putField(c, m, 1) // exitCode + c, m := putField(c, m, 1) // exited + c, m := putField(c, m, 8) // futexAddr + c, m := putField(c, m, 8) // futexVal + c, m := putField(c, m, 8) // futexTimeoutStep + c, m := putField(c, m, 8) // pc + c, m := putField(c, m, 8) // nextPC + c, m := putField(c, m, 8) // lo + c, m := putField(c, m, 8) // hi + m := mload(m) // offset to registers + // Unpack register calldata into memory + for { let i := 0 } lt(i, 32) { i := add(i, 1) } { c, m := putField(c, m, 8) } + } + } + } + + /// @notice Loads the inner root for the current thread hash onion from calldata. + function loadCalldataInnerThreadRoot() internal pure returns (bytes32 innerThreadRoot_) { + uint256 s = 0; + assembly { + s := calldatasize() + innerThreadRoot_ := calldataload(add(THREAD_PROOF_OFFSET, PACKED_THREAD_STATE_SIZE)) + } + // verify we have enough calldata + require( + s >= (THREAD_PROOF_OFFSET + (PACKED_THREAD_STATE_SIZE + 32)), + "MIPS64: insufficient calldata for thread witness" + ); + } +} diff --git a/packages/contracts-bedrock/src/cannon/interfaces/IMIPS2.sol b/packages/contracts-bedrock/src/cannon/interfaces/IMIPS2.sol index 614daac1a7317..be37d5b49ff7d 100644 --- a/packages/contracts-bedrock/src/cannon/interfaces/IMIPS2.sol +++ b/packages/contracts-bedrock/src/cannon/interfaces/IMIPS2.sol @@ -46,7 +46,13 @@ interface IMIPS2 is ISemver { error InvalidRMWInstruction(); function oracle() external view returns (IPreimageOracle oracle_); - function step(bytes memory _stateData, bytes memory _proof, bytes32 _localContext) external returns (bytes32); + function step( + bytes memory _stateData, + bytes memory _proof, + bytes32 _localContext + ) + external + returns (bytes32 postState_); function __constructor__(IPreimageOracle _oracle) external; } diff --git a/packages/contracts-bedrock/src/cannon/libraries/MIPS64Arch.sol b/packages/contracts-bedrock/src/cannon/libraries/MIPS64Arch.sol new file mode 100644 index 0000000000000..34a8d39f5d423 --- /dev/null +++ b/packages/contracts-bedrock/src/cannon/libraries/MIPS64Arch.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +library MIPS64Arch { + uint64 internal constant WORD_SIZE = 64; + uint64 internal constant WORD_SIZE_BYTES = 8; + uint64 internal constant EXT_MASK = 0x7; + uint64 internal constant ADDRESS_MASK = 0xFFFFFFFFFFFFFFF8; +} diff --git a/packages/contracts-bedrock/src/cannon/libraries/MIPS64Instructions.sol b/packages/contracts-bedrock/src/cannon/libraries/MIPS64Instructions.sol new file mode 100644 index 0000000000000..d24ec036e819e --- /dev/null +++ b/packages/contracts-bedrock/src/cannon/libraries/MIPS64Instructions.sol @@ -0,0 +1,920 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { MIPS64Memory } from "src/cannon/libraries/MIPS64Memory.sol"; +import { MIPS64State as st } from "src/cannon/libraries/MIPS64State.sol"; +import { MIPS64Arch as arch } from "src/cannon/libraries/MIPS64Arch.sol"; + +library MIPS64Instructions { + uint32 internal constant OP_LOAD_LINKED = 0x30; + uint32 internal constant OP_STORE_CONDITIONAL = 0x38; + uint32 internal constant OP_LOAD_LINKED64 = 0x34; + uint32 internal constant OP_STORE_CONDITIONAL64 = 0x3C; + uint32 internal constant OP_LOAD_DOUBLE_LEFT = 0x1A; + uint32 internal constant OP_LOAD_DOUBLE_RIGHT = 0x1B; + uint32 internal constant REG_RA = 31; + uint64 internal constant U64_MASK = 0xFFFFFFFFFFFFFFFF; + uint32 internal constant U32_MASK = 0xFFffFFff; + + error InvalidPC(); + + struct CoreStepLogicParams { + /// @param opcode The opcode value parsed from insn_. + st.CpuScalars cpu; + /// @param registers The CPU registers. + uint64[32] registers; + /// @param memRoot The current merkle root of the memory. + bytes32 memRoot; + /// @param memProofOffset The offset in calldata specify where the memory merkle proof is located. + uint256 memProofOffset; + /// @param insn The current 32-bit instruction at the pc. + uint32 insn; + /// @param cpu The CPU scalar fields. + uint32 opcode; + /// @param fun The function value parsed from insn_. + uint32 fun; + } + + /// @param _pc The program counter. + /// @param _memRoot The current memory root. + /// @param _insnProofOffset The calldata offset of the memory proof for the current instruction. + /// @return insn_ The current 32-bit instruction at the pc. + /// @return opcode_ The opcode value parsed from insn_. + /// @return fun_ The function value parsed from insn_. + function getInstructionDetails( + uint64 _pc, + bytes32 _memRoot, + uint256 _insnProofOffset + ) + internal + pure + returns (uint32 insn_, uint32 opcode_, uint32 fun_) + { + unchecked { + if (_pc & 0x3 != 0) { + revert InvalidPC(); + } + uint64 word = MIPS64Memory.readMem(_memRoot, _pc & arch.ADDRESS_MASK, _insnProofOffset); + insn_ = uint32(selectSubWord(_pc, word, 4, false)); + opcode_ = insn_ >> 26; // First 6-bits + fun_ = insn_ & 0x3f; // Last 6-bits + + return (insn_, opcode_, fun_); + } + } + + /// @notice Execute core MIPS step logic. + /// @return newMemRoot_ The updated merkle root of memory after any modifications, may be unchanged. + /// @return memUpdated_ True if memory was modified. + /// @return effMemAddr_ Holds the effective address that was updated if memUpdated_ is true. + function execMipsCoreStepLogic(CoreStepLogicParams memory _args) + internal + pure + returns (bytes32 newMemRoot_, bool memUpdated_, uint64 effMemAddr_) + { + unchecked { + newMemRoot_ = _args.memRoot; + memUpdated_ = false; + effMemAddr_ = 0; + + // j-type j/jal + if (_args.opcode == 2 || _args.opcode == 3) { + // Take top 4 bits of the next PC (its 256 MB region), and concatenate with the 26-bit offset + uint64 target = (_args.cpu.nextPC & signExtend(0xF0000000, 32)) | uint64((_args.insn & 0x03FFFFFF) << 2); + handleJump(_args.cpu, _args.registers, _args.opcode == 2 ? 0 : REG_RA, target); + return (newMemRoot_, memUpdated_, effMemAddr_); + } + + // register fetch + uint64 rs = 0; // source register 1 value + uint64 rt = 0; // source register 2 / temp value + uint64 rtReg = uint64((_args.insn >> 16) & 0x1F); + + // R-type or I-type (stores rt) + rs = _args.registers[(_args.insn >> 21) & 0x1F]; + uint64 rdReg = rtReg; + + // 64-bit opcodes lwu, ldl, ldr + if (_args.opcode == 0x27 || _args.opcode == 0x1A || _args.opcode == 0x1B) { + rt = _args.registers[rtReg]; + rdReg = rtReg; + } else if (_args.opcode == 0 || _args.opcode == 0x1c) { + // R-type (stores rd) + rt = _args.registers[rtReg]; + rdReg = uint64((_args.insn >> 11) & 0x1F); + } else if (_args.opcode < 0x20) { + // rt is SignExtImm + // don't sign extend for andi, ori, xori + if (_args.opcode == 0xC || _args.opcode == 0xD || _args.opcode == 0xe) { + // ZeroExtImm + rt = uint64(_args.insn & 0xFFFF); + } else { + // SignExtImm + rt = signExtendImmediate(_args.insn); + } + } else if (_args.opcode >= 0x28 || _args.opcode == 0x22 || _args.opcode == 0x26) { + // store rt value with store + rt = _args.registers[rtReg]; + + // store actual rt with lwl and lwr + rdReg = rtReg; + } + + if ((_args.opcode >= 4 && _args.opcode < 8) || _args.opcode == 1) { + handleBranch({ + _cpu: _args.cpu, + _registers: _args.registers, + _opcode: _args.opcode, + _insn: _args.insn, + _rtReg: rtReg, + _rs: rs + }); + return (newMemRoot_, memUpdated_, effMemAddr_); + } + + uint64 storeAddr = U64_MASK; + // memory fetch (all I-type) + // we do the load for stores also + uint64 mem = 0; + if (_args.opcode >= 0x20 || _args.opcode == OP_LOAD_DOUBLE_LEFT || _args.opcode == OP_LOAD_DOUBLE_RIGHT) { + // M[R[rs]+SignExtImm] + rs += signExtendImmediate(_args.insn); + uint64 addr = rs & arch.ADDRESS_MASK; + mem = MIPS64Memory.readMem(_args.memRoot, addr, _args.memProofOffset); + if (_args.opcode >= 0x28) { + // store for 32-bit + // for 64-bit: ld (0x37) is the only non-store opcode >= 0x28 + if (_args.opcode != 0x37) { + // store + storeAddr = addr; + // store opcodes don't write back to a register + rdReg = 0; + } + } + } + + // ALU + // Note: swr outputs more than 8 bytes without the u64_mask + uint64 val = executeMipsInstruction(_args.insn, _args.opcode, _args.fun, rs, rt, mem) & U64_MASK; + + uint64 funSel = 0x20; + if (_args.opcode == 0 && _args.fun >= 8 && _args.fun < funSel) { + if (_args.fun == 8 || _args.fun == 9) { + // jr/jalr + handleJump(_args.cpu, _args.registers, _args.fun == 8 ? 0 : rdReg, rs); + return (newMemRoot_, memUpdated_, effMemAddr_); + } + + if (_args.fun == 0xa) { + // movz + handleRd(_args.cpu, _args.registers, rdReg, rs, rt == 0); + return (newMemRoot_, memUpdated_, effMemAddr_); + } + if (_args.fun == 0xb) { + // movn + handleRd(_args.cpu, _args.registers, rdReg, rs, rt != 0); + return (newMemRoot_, memUpdated_, effMemAddr_); + } + + // lo and hi registers + // can write back + if (_args.fun >= 0x10 && _args.fun < funSel) { + handleHiLo({ + _cpu: _args.cpu, + _registers: _args.registers, + _fun: _args.fun, + _rs: rs, + _rt: rt, + _storeReg: rdReg + }); + return (newMemRoot_, memUpdated_, effMemAddr_); + } + } + + // write memory + if (storeAddr != U64_MASK) { + newMemRoot_ = MIPS64Memory.writeMem(storeAddr, _args.memProofOffset, val); + memUpdated_ = true; + effMemAddr_ = storeAddr; + } + + // write back the value to destination register + handleRd(_args.cpu, _args.registers, rdReg, val, true); + + return (newMemRoot_, memUpdated_, effMemAddr_); + } + } + + function signExtendImmediate(uint32 _insn) internal pure returns (uint64 offset_) { + unchecked { + return signExtend(_insn & 0xFFFF, 16); + } + } + + /// @notice Execute an instruction. + function executeMipsInstruction( + uint32 _insn, + uint32 _opcode, + uint32 _fun, + uint64 _rs, + uint64 _rt, + uint64 _mem + ) + internal + pure + returns (uint64 out_) + { + unchecked { + if (_opcode == 0 || (_opcode >= 8 && _opcode < 0xF) || _opcode == 0x18 || _opcode == 0x19) { + assembly { + // transform ArithLogI to SPECIAL + switch _opcode + // addi + case 0x8 { _fun := 0x20 } + // addiu + case 0x9 { _fun := 0x21 } + // stli + case 0xA { _fun := 0x2A } + // sltiu + case 0xB { _fun := 0x2B } + // andi + case 0xC { _fun := 0x24 } + // ori + case 0xD { _fun := 0x25 } + // xori + case 0xE { _fun := 0x26 } + // daddi + case 0x18 { _fun := 0x2C } + // daddiu + case 0x19 { _fun := 0x2D } + } + + // sll + if (_fun == 0x00) { + return signExtend((_rt & U32_MASK) << ((_insn >> 6) & 0x1F), 32); + } + // srl + else if (_fun == 0x02) { + return signExtend((_rt & U32_MASK) >> ((_insn >> 6) & 0x1F), 32); + } + // sra + else if (_fun == 0x03) { + uint32 shamt = (_insn >> 6) & 0x1F; + return signExtend((_rt & U32_MASK) >> shamt, 32 - shamt); + } + // sllv + else if (_fun == 0x04) { + return signExtend((_rt & U32_MASK) << (_rs & 0x1F), 32); + } + // srlv + else if (_fun == 0x6) { + return signExtend((_rt & U32_MASK) >> (_rs & 0x1F), 32); + } + // srav + else if (_fun == 0x07) { + // shamt here is different than the typical shamt which comes from the + // instruction itself, here it comes from the rs register + uint64 shamt = _rs & 0x1F; + return signExtend((_rt & U32_MASK) >> shamt, 32 - shamt); + } + // functs in range [0x8, 0x1b] are handled specially by other functions + // Explicitly enumerate each funct in range to reduce code diff against Go Vm + // jr + else if (_fun == 0x08) { + return _rs; + } + // jalr + else if (_fun == 0x09) { + return _rs; + } + // movz + else if (_fun == 0x0a) { + return _rs; + } + // movn + else if (_fun == 0x0b) { + return _rs; + } + // syscall + else if (_fun == 0x0c) { + return _rs; + } + // 0x0d - break not supported + // sync + else if (_fun == 0x0f) { + return _rs; + } + // mfhi + else if (_fun == 0x10) { + return _rs; + } + // mthi + else if (_fun == 0x11) { + return _rs; + } + // mflo + else if (_fun == 0x12) { + return _rs; + } + // mtlo + else if (_fun == 0x13) { + return _rs; + } + // dsllv + else if (_fun == 0x14) { + return _rt; + } + // dsrlv + else if (_fun == 0x16) { + return _rt; + } + // dsrav + else if (_fun == 0x17) { + return _rt; + } + // mult + else if (_fun == 0x18) { + return _rs; + } + // multu + else if (_fun == 0x19) { + return _rs; + } + // div + else if (_fun == 0x1a) { + return _rs; + } + // divu + else if (_fun == 0x1b) { + return _rs; + } + // dmult + else if (_fun == 0x1c) { + return _rs; + } + // dmultu + else if (_fun == 0x1d) { + return _rs; + } + // ddiv + else if (_fun == 0x1e) { + return _rs; + } + // ddivu + else if (_fun == 0x1f) { + return _rs; + } + // The rest includes transformed R-type arith imm instructions + // add + else if (_fun == 0x20) { + return signExtend(uint64(uint32(_rs) + uint32(_rt)), 32); + } + // addu + else if (_fun == 0x21) { + return signExtend(uint64(uint32(_rs) + uint32(_rt)), 32); + } + // sub + else if (_fun == 0x22) { + return signExtend(uint64(uint32(_rs) - uint32(_rt)), 32); + } + // subu + else if (_fun == 0x23) { + return signExtend(uint64(uint32(_rs) - uint32(_rt)), 32); + } + // and + else if (_fun == 0x24) { + return (_rs & _rt); + } + // or + else if (_fun == 0x25) { + return (_rs | _rt); + } + // xor + else if (_fun == 0x26) { + return (_rs ^ _rt); + } + // nor + else if (_fun == 0x27) { + return ~(_rs | _rt); + } + // slti + else if (_fun == 0x2a) { + return int64(_rs) < int64(_rt) ? 1 : 0; + } + // sltiu + else if (_fun == 0x2b) { + return _rs < _rt ? 1 : 0; + } + // dadd + else if (_fun == 0x2c) { + return (_rs + _rt); + } + // daddu + else if (_fun == 0x2d) { + return (_rs + _rt); + } + // dsub + else if (_fun == 0x2e) { + return (_rs - _rt); + } + // dsubu + else if (_fun == 0x2f) { + return (_rs - _rt); + } + // dsll + else if (_fun == 0x38) { + return _rt << ((_insn >> 6) & 0x1f); + } + // dsrl + else if (_fun == 0x3A) { + return _rt >> ((_insn >> 6) & 0x1f); + } + // dsra + else if (_fun == 0x3B) { + return uint64(int64(_rt) >> ((_insn >> 6) & 0x1f)); + } + // dsll32 + else if (_fun == 0x3c) { + return _rt << (((_insn >> 6) & 0x1f) + 32); + } + // dsrl32 + else if (_fun == 0x3e) { + return _rt >> (((_insn >> 6) & 0x1f) + 32); + } + // dsra32 + else if (_fun == 0x3f) { + return uint64(int64(_rt) >> (((_insn >> 6) & 0x1f) + 32)); + } else { + revert("MIPS64: invalid instruction"); + } + } else { + // SPECIAL2 + if (_opcode == 0x1C) { + // mul + if (_fun == 0x2) { + return signExtend(uint32(int32(uint32(_rs)) * int32(uint32(_rt))), 32); + } + // clz, clo + else if (_fun == 0x20 || _fun == 0x21) { + if (_fun == 0x20) { + _rs = ~_rs; + } + uint32 i = 0; + while (_rs & 0x80000000 != 0) { + i++; + _rs <<= 1; + } + return i; + } + } + // lui + else if (_opcode == 0x0F) { + return signExtend(_rt << 16, 32); + } + // lb + else if (_opcode == 0x20) { + return selectSubWord(_rs, _mem, 1, true); + } + // lh + else if (_opcode == 0x21) { + return selectSubWord(_rs, _mem, 2, true); + } + // lwl + else if (_opcode == 0x22) { + uint32 w = uint32(selectSubWord(_rs, _mem, 4, false)); + uint32 val = w << uint32((_rs & 3) * 8); + uint64 mask = uint64(U32_MASK << uint32((_rs & 3) * 8)); + return signExtend(((_rt & ~mask) | uint64(val)) & U32_MASK, 32); + } + // lw + else if (_opcode == 0x23) { + return selectSubWord(_rs, _mem, 4, true); + } + // lbu + else if (_opcode == 0x24) { + return selectSubWord(_rs, _mem, 1, false); + } + // lhu + else if (_opcode == 0x25) { + return selectSubWord(_rs, _mem, 2, false); + } + // lwr + else if (_opcode == 0x26) { + uint32 w = uint32(selectSubWord(_rs, _mem, 4, false)); + uint32 val = w >> (24 - (_rs & 3) * 8); + uint32 mask = U32_MASK >> (24 - (_rs & 3) * 8); + uint64 lwrResult = (uint32(_rt) & ~mask) | val; + if (_rs & 3 == 3) { + // loaded bit 31 + return signExtend(uint64(lwrResult), 32); + } else { + // NOTE: cannon64 implementation specific: We leave the upper word untouched + uint64 rtMask = 0xFF_FF_FF_FF_00_00_00_00; + return ((_rt & rtMask) | uint64(lwrResult)); + } + } + // sb + else if (_opcode == 0x28) { + return updateSubWord(_rs, _mem, 1, _rt); + } + // sh + else if (_opcode == 0x29) { + return updateSubWord(_rs, _mem, 2, _rt); + } + // swl + else if (_opcode == 0x2a) { + uint64 sr = (_rs & 3) << 3; + uint64 val = ((_rt & U32_MASK) >> sr) << (32 - ((_rs & 0x4) << 3)); + uint64 mask = (uint64(U32_MASK) >> sr) << (32 - ((_rs & 0x4) << 3)); + return (_mem & ~mask) | val; + } + // sw + else if (_opcode == 0x2b) { + return updateSubWord(_rs, _mem, 4, _rt); + } + // swr + else if (_opcode == 0x2e) { + uint32 w = uint32(selectSubWord(_rs, _mem, 4, false)); + uint64 val = _rt << (24 - (_rs & 3) * 8); + uint64 mask = U32_MASK << uint32(24 - (_rs & 3) * 8); + uint64 swrResult = (w & ~mask) | uint32(val); + return updateSubWord(_rs, _mem, 4, swrResult); + } + // MIPS64 + // ldl + else if (_opcode == 0x1a) { + uint64 sl = (_rs & 0x7) << 3; + uint64 val = _mem << sl; + uint64 mask = U64_MASK << sl; + return (val | (_rt & ~mask)); + } + // ldr + else if (_opcode == 0x1b) { + uint64 sr = 56 - ((_rs & 0x7) << 3); + uint64 val = _mem >> sr; + uint64 mask = U64_MASK << (64 - sr); + return (val | (_rt & mask)); + } + // lwu + else if (_opcode == 0x27) { + return ((_mem >> (32 - ((_rs & 0x4) << 3))) & U32_MASK); + } + // sdl + else if (_opcode == 0x2c) { + uint64 sr = (_rs & 0x7) << 3; + uint64 val = _rt >> sr; + uint64 mask = U64_MASK >> sr; + return (val | (_mem & ~mask)); + } + // sdr + else if (_opcode == 0x2d) { + uint64 sl = 56 - ((_rs & 0x7) << 3); + uint64 val = _rt << sl; + uint64 mask = U64_MASK << sl; + return (val | (_mem & ~mask)); + } + // ld + else if (_opcode == 0x37) { + return _mem; + } + // sd + else if (_opcode == 0x3F) { + return _rt; + } else { + revert("MIPS64: invalid instruction"); + } + } + revert("MIPS64: invalid instruction"); + } + } + + /// @notice Extends the value leftwards with its most significant bit (sign extension). + function signExtend(uint64 _dat, uint64 _idx) internal pure returns (uint64 out_) { + unchecked { + bool isSigned = (_dat >> (_idx - 1)) != 0; + uint256 signed = ((1 << (arch.WORD_SIZE - _idx)) - 1) << _idx; + uint256 mask = (1 << _idx) - 1; + return uint64(_dat & mask | (isSigned ? signed : 0)); + } + } + + /// @notice Handles a branch instruction, updating the MIPS state PC where needed. + /// @param _cpu Holds the state of cpu scalars pc, nextPC, hi, lo. + /// @param _registers Holds the current state of the cpu registers. + /// @param _opcode The opcode of the branch instruction. + /// @param _insn The instruction to be executed. + /// @param _rtReg The register to be used for the branch. + /// @param _rs The register to be compared with the branch register. + function handleBranch( + st.CpuScalars memory _cpu, + uint64[32] memory _registers, + uint32 _opcode, + uint32 _insn, + uint64 _rtReg, + uint64 _rs + ) + internal + pure + { + unchecked { + bool shouldBranch = false; + + if (_cpu.nextPC != _cpu.pc + 4) { + revert("MIPS64: branch in delay slot"); + } + + // beq/bne: Branch on equal / not equal + if (_opcode == 4 || _opcode == 5) { + uint64 rt = _registers[_rtReg]; + shouldBranch = (_rs == rt && _opcode == 4) || (_rs != rt && _opcode == 5); + } + // blez: Branches if instruction is less than or equal to zero + else if (_opcode == 6) { + shouldBranch = int64(_rs) <= 0; + } + // bgtz: Branches if instruction is greater than zero + else if (_opcode == 7) { + shouldBranch = int64(_rs) > 0; + } + // bltz/bgez: Branch on less than zero / greater than or equal to zero + else if (_opcode == 1) { + // regimm + uint32 rtv = ((_insn >> 16) & 0x1F); + if (rtv == 0) { + shouldBranch = int64(_rs) < 0; + } + if (rtv == 1) { + shouldBranch = int64(_rs) >= 0; + } + // bgezal (i.e. bal mnemonic) + if (rtv == 0x11) { + shouldBranch = int64(_rs) >= 0; + _registers[REG_RA] = _cpu.pc + 8; // always set regardless of branch taken + } + } + + // Update the state's previous PC + uint64 prevPC = _cpu.pc; + + // Execute the delay slot first + _cpu.pc = _cpu.nextPC; + + // If we should branch, update the PC to the branch target + // Otherwise, proceed to the next instruction + if (shouldBranch) { + _cpu.nextPC = prevPC + 4 + (signExtend(_insn & 0xFFFF, 16) << 2); + } else { + _cpu.nextPC = _cpu.nextPC + 4; + } + } + } + + /// @notice Handles HI and LO register instructions. It also additionally handles doubleword variable shift + /// operations + /// @param _cpu Holds the state of cpu scalars pc, nextPC, hi, lo. + /// @param _registers Holds the current state of the cpu registers. + /// @param _fun The function code of the instruction. + /// @param _rs The value of the RS register. + /// @param _rt The value of the RT register. + /// @param _storeReg The register to store the result in. + function handleHiLo( + st.CpuScalars memory _cpu, + uint64[32] memory _registers, + uint32 _fun, + uint64 _rs, + uint64 _rt, + uint64 _storeReg + ) + internal + pure + { + unchecked { + uint64 val = 0; + + // mfhi: Move the contents of the HI register into the destination + if (_fun == 0x10) { + val = _cpu.hi; + } + // mthi: Move the contents of the source into the HI register + else if (_fun == 0x11) { + _cpu.hi = _rs; + } + // mflo: Move the contents of the LO register into the destination + else if (_fun == 0x12) { + val = _cpu.lo; + } + // mtlo: Move the contents of the source into the LO register + else if (_fun == 0x13) { + _cpu.lo = _rs; + } + // mult: Multiplies `rs` by `rt` and stores the result in HI and LO registers + else if (_fun == 0x18) { + uint64 acc = uint64(int64(int32(uint32(_rs))) * int64(int32(uint32(_rt)))); + _cpu.hi = signExtend(uint64(acc >> 32), 32); + _cpu.lo = signExtend(uint64(uint32(acc)), 32); + } + // multu: Unsigned multiplies `rs` by `rt` and stores the result in HI and LO registers + else if (_fun == 0x19) { + uint64 acc = uint64(uint32(_rs)) * uint64(uint32(_rt)); + _cpu.hi = signExtend(uint64(acc >> 32), 32); + _cpu.lo = signExtend(uint64(uint32(acc)), 32); + } + // div: Divides `rs` by `rt`. + // Stores the quotient in LO + // And the remainder in HI + else if (_fun == 0x1a) { + if (uint32(_rt) == 0) { + revert("MIPS64: division by zero"); + } + _cpu.hi = signExtend(uint32(int32(uint32(_rs)) % int32(uint32(_rt))), 32); + _cpu.lo = signExtend(uint32(int32(uint32(_rs)) / int32(uint32(_rt))), 32); + } + // divu: Unsigned divides `rs` by `rt`. + // Stores the quotient in LO + // And the remainder in HI + else if (_fun == 0x1b) { + if (uint32(_rt) == 0) { + revert("MIPS64: division by zero"); + } + _cpu.hi = signExtend(uint64(uint32(_rs) % uint32(_rt)), 32); + _cpu.lo = signExtend(uint64(uint32(_rs) / uint32(_rt)), 32); + } + // dsllv + else if (_fun == 0x14) { + val = _rt << (_rs & 0x3F); + } + // dsrlv + else if (_fun == 0x16) { + val = _rt >> (_rs & 0x3F); + } + // dsrav + else if (_fun == 0x17) { + val = uint64(int64(_rt) >> (_rs & 0x3F)); + } + // dmult + else if (_fun == 0x1c) { + int128 res = int128(int64(_rs)) * int128(int64(_rt)); + _cpu.hi = uint64(int64(res >> 64)); + _cpu.lo = uint64(uint128(res) & U64_MASK); + } + // dmultu + else if (_fun == 0x1d) { + uint128 res = uint128(_rs) * uint128(_rt); + _cpu.hi = uint64(res >> 64); + _cpu.lo = uint64(res); + } + // ddiv + else if (_fun == 0x1e) { + if (_rt == 0) { + revert("MIPS64: division by zero"); + } + _cpu.hi = uint64(int64(_rs) % int64(_rt)); + _cpu.lo = uint64(int64(_rs) / int64(_rt)); + } + // ddivu + else if (_fun == 0x1f) { + if (_rt == 0) { + revert("MIPS64: division by zero"); + } + _cpu.hi = _rs % _rt; + _cpu.lo = _rs / _rt; + } + + // Store the result in the destination register, if applicable + if (_storeReg != 0) { + _registers[_storeReg] = val; + } + + // Update the PC + _cpu.pc = _cpu.nextPC; + _cpu.nextPC = _cpu.nextPC + 4; + } + } + + /// @notice Handles a jump instruction, updating the MIPS state PC where needed. + /// @param _cpu Holds the state of cpu scalars pc, nextPC, hi, lo. + /// @param _registers Holds the current state of the cpu registers. + /// @param _linkReg The register to store the link to the instruction after the delay slot instruction. + /// @param _dest The destination to jump to. + function handleJump( + st.CpuScalars memory _cpu, + uint64[32] memory _registers, + uint64 _linkReg, + uint64 _dest + ) + internal + pure + { + unchecked { + if (_cpu.nextPC != _cpu.pc + 4) { + revert("MIPS64: jump in delay slot"); + } + + // Update the next PC to the jump destination. + uint64 prevPC = _cpu.pc; + _cpu.pc = _cpu.nextPC; + _cpu.nextPC = _dest; + + // Update the link-register to the instruction after the delay slot instruction. + if (_linkReg != 0) { + _registers[_linkReg] = prevPC + 8; + } + } + } + + /// @notice Handles a storing a value into a register. + /// @param _cpu Holds the state of cpu scalars pc, nextPC, hi, lo. + /// @param _registers Holds the current state of the cpu registers. + /// @param _storeReg The register to store the value into. + /// @param _val The value to store. + /// @param _conditional Whether or not the store is conditional. + function handleRd( + st.CpuScalars memory _cpu, + uint64[32] memory _registers, + uint64 _storeReg, + uint64 _val, + bool _conditional + ) + internal + pure + { + unchecked { + // The destination register must be valid. + require(_storeReg < 32, "MIPS64: valid register"); + + // Never write to reg 0, and it can be conditional (movz, movn). + if (_storeReg != 0 && _conditional) { + _registers[_storeReg] = _val; + } + + // Update the PC. + _cpu.pc = _cpu.nextPC; + _cpu.nextPC = _cpu.nextPC + 4; + } + } + + /// @notice Selects a subword of byteLength size contained in memWord based on the low-order bits of vaddr + /// @param _vaddr The virtual address of the the subword. + /// @param _memWord The full word to select a subword from. + /// @param _byteLength The size of the subword. + /// @param _signExtend Whether to sign extend the selected subwrod. + function selectSubWord( + uint64 _vaddr, + uint64 _memWord, + uint64 _byteLength, + bool _signExtend + ) + internal + pure + returns (uint64 retval_) + { + (uint64 dataMask, uint64 bitOffset, uint64 bitLength) = calculateSubWordMaskAndOffset(_vaddr, _byteLength); + retval_ = (_memWord >> bitOffset) & dataMask; + if (_signExtend) { + retval_ = signExtend(retval_, bitLength); + } + return retval_; + } + + /// @notice Returns a word that has been updated by the specified subword at bit positions determined by the virtual + /// address + /// @param _vaddr The virtual address of the subword. + /// @param _memWord The full word to update. + /// @param _byteLength The size of the subword. + /// @param _value The subword that updates _memWord. + function updateSubWord( + uint64 _vaddr, + uint64 _memWord, + uint64 _byteLength, + uint64 _value + ) + internal + pure + returns (uint64 word_) + { + (uint64 dataMask, uint64 bitOffset,) = calculateSubWordMaskAndOffset(_vaddr, _byteLength); + uint64 subWordValue = dataMask & _value; + uint64 memUpdateMask = dataMask << bitOffset; + return subWordValue << bitOffset | (~memUpdateMask) & _memWord; + } + + function calculateSubWordMaskAndOffset( + uint64 _vaddr, + uint64 _byteLength + ) + internal + pure + returns (uint64 dataMask_, uint64 bitOffset_, uint64 bitLength_) + { + uint64 bitLength = _byteLength << 3; + uint64 dataMask = ~uint64(0) >> (arch.WORD_SIZE - bitLength); + + // Figure out sub-word index based on the low-order bits in vaddr + uint64 byteIndexMask = _vaddr & arch.EXT_MASK & ~(_byteLength - 1); + uint64 maxByteShift = arch.WORD_SIZE_BYTES - _byteLength; + uint64 byteIndex = _vaddr & byteIndexMask; + uint64 bitOffset = (maxByteShift - byteIndex) << 3; + + return (dataMask, bitOffset, bitLength); + } +} diff --git a/packages/contracts-bedrock/src/cannon/libraries/MIPS64Memory.sol b/packages/contracts-bedrock/src/cannon/libraries/MIPS64Memory.sol new file mode 100644 index 0000000000000..9ed97396e10f9 --- /dev/null +++ b/packages/contracts-bedrock/src/cannon/libraries/MIPS64Memory.sol @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { InvalidMemoryProof } from "src/cannon/libraries/CannonErrors.sol"; + +library MIPS64Memory { + uint64 internal constant EXT_MASK = 0x7; + uint64 internal constant MEM_PROOF_LEAF_COUNT = 60; + uint256 internal constant U64_MASK = 0xFFFFFFFFFFFFFFFF; + + /// @notice Reads a 64-bit word from memory. + /// @param _memRoot The current memory root + /// @param _addr The address to read from. + /// @param _proofOffset The offset of the memory proof in calldata. + /// @return out_ The hashed MIPS state. + function readMem(bytes32 _memRoot, uint64 _addr, uint256 _proofOffset) internal pure returns (uint64 out_) { + bool valid; + (out_, valid) = readMemUnchecked(_memRoot, _addr, _proofOffset); + if (!valid) { + revert InvalidMemoryProof(); + } + } + + /// @notice Reads a 64-bit word from memory. + /// @param _memRoot The current memory root + /// @param _addr The address to read from. + /// @param _proofOffset The offset of the memory proof in calldata. + /// @return out_ The hashed MIPS state. + /// valid_ Whether the proof is valid. + function readMemUnchecked( + bytes32 _memRoot, + uint64 _addr, + uint256 _proofOffset + ) + internal + pure + returns (uint64 out_, bool valid_) + { + unchecked { + validateMemoryProofAvailability(_proofOffset); + assembly { + // Validate the address alignment. + if and(_addr, EXT_MASK) { + // revert InvalidAddress(); + let ptr := mload(0x40) + mstore(ptr, shl(224, 0xe6c4247b)) + revert(ptr, 0x4) + } + + // Load the leaf value. + let leaf := calldataload(_proofOffset) + _proofOffset := add(_proofOffset, 32) + + // Convenience function to hash two nodes together in scratch space. + function hashPair(a, b) -> h { + mstore(0, a) + mstore(32, b) + h := keccak256(0, 64) + } + + // Start with the leaf node. + // Work back up by combining with siblings, to reconstruct the root. + let path := shr(5, _addr) + let node := leaf + let end := sub(MEM_PROOF_LEAF_COUNT, 1) + for { let i := 0 } lt(i, end) { i := add(i, 1) } { + let sibling := calldataload(_proofOffset) + _proofOffset := add(_proofOffset, 32) + switch and(shr(i, path), 1) + case 0 { node := hashPair(node, sibling) } + case 1 { node := hashPair(sibling, node) } + } + + // Verify the root matches. + valid_ := eq(node, _memRoot) + if valid_ { + // Bits to shift = (32 - 8 - (addr % 32)) * 8 + let shamt := shl(3, sub(sub(32, 8), and(_addr, 31))) + out_ := and(shr(shamt, leaf), U64_MASK) + } + } + } + } + + /// @notice Writes a 64-bit word to memory. + /// This function first overwrites the part of the leaf. + /// Then it recomputes the memory merkle root. + /// @param _addr The address to write to. + /// @param _proofOffset The offset of the memory proof in calldata. + /// @param _val The value to write. + /// @return newMemRoot_ The new memory root after modification + function writeMem(uint64 _addr, uint256 _proofOffset, uint64 _val) internal pure returns (bytes32 newMemRoot_) { + unchecked { + validateMemoryProofAvailability(_proofOffset); + assembly { + // Validate the address alignment. + if and(_addr, EXT_MASK) { + // revert InvalidAddress(); + let ptr := mload(0x40) + mstore(ptr, shl(224, 0xe6c4247b)) + revert(ptr, 0x4) + } + + // Load the leaf value. + let leaf := calldataload(_proofOffset) + let shamt := shl(3, sub(sub(32, 8), and(_addr, 31))) + + // Mask out 8 bytes, and OR in the value + leaf := or(and(leaf, not(shl(shamt, U64_MASK))), shl(shamt, _val)) + _proofOffset := add(_proofOffset, 32) + + // Convenience function to hash two nodes together in scratch space. + function hashPair(a, b) -> h { + mstore(0, a) + mstore(32, b) + h := keccak256(0, 64) + } + + // Start with the leaf node. + // Work back up by combining with siblings, to reconstruct the root. + let path := shr(5, _addr) + let node := leaf + let end := sub(MEM_PROOF_LEAF_COUNT, 1) + for { let i := 0 } lt(i, end) { i := add(i, 1) } { + let sibling := calldataload(_proofOffset) + _proofOffset := add(_proofOffset, 32) + switch and(shr(i, path), 1) + case 0 { node := hashPair(node, sibling) } + case 1 { node := hashPair(sibling, node) } + } + + newMemRoot_ := node + } + return newMemRoot_; + } + } + + /// @notice Verifies a memory proof. + /// @param _memRoot The expected memory root + /// @param _addr The _addr proven. + /// @param _proofOffset The offset of the memory proof in calldata. + /// @return valid_ True iff it is a valid proof. + function isValidProof(bytes32 _memRoot, uint64 _addr, uint256 _proofOffset) internal pure returns (bool valid_) { + (, valid_) = readMemUnchecked(_memRoot, _addr, _proofOffset); + } + + /// @notice Computes the offset of a memory proof in the calldata. + /// @param _proofDataOffset The offset of the set of all memory proof data within calldata (proof.offset) + /// Equal to the offset of the first memory proof (at _proofIndex 0). + /// @param _proofIndex The index of the proof in the calldata. + /// @return offset_ The offset of the memory proof at the given _proofIndex in the calldata. + function memoryProofOffset(uint256 _proofDataOffset, uint8 _proofIndex) internal pure returns (uint256 offset_) { + unchecked { + // A proof of 64-bit memory, with 32-byte leaf values, is (64-5)=59 bytes32 entries. + // And the leaf value itself needs to be encoded as well: (59 + 1) = 60 bytes32 entries. + offset_ = _proofDataOffset + (uint256(_proofIndex) * (MEM_PROOF_LEAF_COUNT * 32)); + return offset_; + } + } + + /// @notice Validates that enough calldata is available to hold a full memory proof at the given offset + /// @param _proofStartOffset The index of the first byte of the target memory proof in calldata + function validateMemoryProofAvailability(uint256 _proofStartOffset) internal pure { + unchecked { + uint256 s = 0; + assembly { + s := calldatasize() + } + // A memory proof consists of MEM_PROOF_LEAF_COUNT bytes32 values - verify we have enough calldata + require( + s >= (_proofStartOffset + MEM_PROOF_LEAF_COUNT * 32), + "MIPS64Memory: check that there is enough calldata" + ); + } + } +} diff --git a/packages/contracts-bedrock/src/cannon/libraries/MIPS64State.sol b/packages/contracts-bedrock/src/cannon/libraries/MIPS64State.sol new file mode 100644 index 0000000000000..09678148f3e6d --- /dev/null +++ b/packages/contracts-bedrock/src/cannon/libraries/MIPS64State.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { InvalidExitedValue } from "src/cannon/libraries/CannonErrors.sol"; + +library MIPS64State { + struct CpuScalars { + uint64 pc; + uint64 nextPC; + uint64 lo; + uint64 hi; + } + + function assertExitedIsValid(uint32 _exited) internal pure { + if (_exited > 1) { + revert InvalidExitedValue(); + } + } +} diff --git a/packages/contracts-bedrock/src/cannon/libraries/MIPS64Syscalls.sol b/packages/contracts-bedrock/src/cannon/libraries/MIPS64Syscalls.sol new file mode 100644 index 0000000000000..10954c64748e6 --- /dev/null +++ b/packages/contracts-bedrock/src/cannon/libraries/MIPS64Syscalls.sol @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { MIPS64Memory } from "src/cannon/libraries/MIPS64Memory.sol"; +import { MIPS64State as st } from "src/cannon/libraries/MIPS64State.sol"; +import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol"; +import { PreimageKeyLib } from "src/cannon/PreimageKeyLib.sol"; +import { MIPS64Arch as arch } from "src/cannon/libraries/MIPS64Arch.sol"; + +library MIPS64Syscalls { + struct SysReadParams { + /// @param _a0 The file descriptor. + uint64 a0; + /// @param _a1 The memory location where data should be read to. + uint64 a1; + /// @param _a2 The number of bytes to read from the file + uint64 a2; + /// @param _preimageKey The key of the preimage to read. + bytes32 preimageKey; + /// @param _preimageOffset The offset of the preimage to read. + uint64 preimageOffset; + /// @param _localContext The local context for the preimage key. + bytes32 localContext; + /// @param _oracle The address of the preimage oracle. + IPreimageOracle oracle; + /// @param _proofOffset The offset of the memory proof in calldata. + uint256 proofOffset; + /// @param _memRoot The current memory root. + bytes32 memRoot; + } + + uint64 internal constant U64_MASK = 0xFFffFFffFFffFFff; + uint64 internal constant PAGE_ADDR_MASK = 4095; + uint64 internal constant PAGE_SIZE = 4096; + + uint32 internal constant SYS_MMAP = 5009; + uint32 internal constant SYS_BRK = 5012; + uint32 internal constant SYS_CLONE = 5055; + uint32 internal constant SYS_EXIT_GROUP = 5205; + uint32 internal constant SYS_READ = 5000; + uint32 internal constant SYS_WRITE = 5001; + uint32 internal constant SYS_FCNTL = 5070; + uint32 internal constant SYS_EXIT = 5058; + uint32 internal constant SYS_SCHED_YIELD = 5023; + uint32 internal constant SYS_GETTID = 5178; + uint32 internal constant SYS_FUTEX = 5194; + uint32 internal constant SYS_OPEN = 5002; + uint32 internal constant SYS_NANOSLEEP = 5034; + uint32 internal constant SYS_CLOCKGETTIME = 5222; + uint32 internal constant SYS_GETPID = 5038; + // no-op syscalls + uint32 internal constant SYS_MUNMAP = 5011; + uint32 internal constant SYS_GETAFFINITY = 5196; + uint32 internal constant SYS_MADVISE = 5027; + uint32 internal constant SYS_RTSIGPROCMASK = 5014; + uint32 internal constant SYS_SIGALTSTACK = 5129; + uint32 internal constant SYS_RTSIGACTION = 5013; + uint32 internal constant SYS_PRLIMIT64 = 5297; + uint32 internal constant SYS_CLOSE = 5003; + uint32 internal constant SYS_PREAD64 = 5016; + uint32 internal constant SYS_STAT = 5004; + uint32 internal constant SYS_FSTAT = 5005; + //uint32 internal constant SYS_FSTAT64 = 0xFFFFFFFF; // UndefinedSysNr - not supported by MIPS64 + uint32 internal constant SYS_OPENAT = 5247; + uint32 internal constant SYS_READLINK = 5087; + uint32 internal constant SYS_READLINKAT = 5257; + uint32 internal constant SYS_IOCTL = 5015; + uint32 internal constant SYS_EPOLLCREATE1 = 5285; + uint32 internal constant SYS_PIPE2 = 5287; + uint32 internal constant SYS_EPOLLCTL = 5208; + uint32 internal constant SYS_EPOLLPWAIT = 5272; + uint32 internal constant SYS_GETRANDOM = 5313; + uint32 internal constant SYS_UNAME = 5061; + //uint32 internal constant SYS_STAT64 = 0xFFFFFFFF; // UndefinedSysNr - not supported by MIPS64 + uint32 internal constant SYS_GETUID = 5100; + uint32 internal constant SYS_GETGID = 5102; + //uint32 internal constant SYS_LLSEEK = 0xFFFFFFFF; // UndefinedSysNr - not supported by MIPS64 + uint32 internal constant SYS_MINCORE = 5026; + uint32 internal constant SYS_TGKILL = 5225; + uint32 internal constant SYS_GETRLIMIT = 5095; + uint32 internal constant SYS_LSEEK = 5008; + // profiling-related syscalls - ignored + uint32 internal constant SYS_SETITIMER = 5036; + uint32 internal constant SYS_TIMERCREATE = 5216; + uint32 internal constant SYS_TIMERSETTIME = 5217; + uint32 internal constant SYS_TIMERDELETE = 5220; + + uint32 internal constant FD_STDIN = 0; + uint32 internal constant FD_STDOUT = 1; + uint32 internal constant FD_STDERR = 2; + uint32 internal constant FD_HINT_READ = 3; + uint32 internal constant FD_HINT_WRITE = 4; + uint32 internal constant FD_PREIMAGE_READ = 5; + uint32 internal constant FD_PREIMAGE_WRITE = 6; + + uint64 internal constant SYS_ERROR_SIGNAL = U64_MASK; + uint64 internal constant EBADF = 0x9; + uint64 internal constant EINVAL = 0x16; + uint64 internal constant EAGAIN = 0xb; + uint64 internal constant ETIMEDOUT = 0x91; + + uint64 internal constant FUTEX_WAIT_PRIVATE = 128; + uint64 internal constant FUTEX_WAKE_PRIVATE = 129; + uint64 internal constant FUTEX_TIMEOUT_STEPS = 10000; + uint64 internal constant FUTEX_NO_TIMEOUT = type(uint64).max; + uint64 internal constant FUTEX_EMPTY_ADDR = U64_MASK; + + uint64 internal constant SCHED_QUANTUM = 100_000; + uint64 internal constant HZ = 10_000_000; + uint64 internal constant CLOCK_GETTIME_REALTIME_FLAG = 0; + uint64 internal constant CLOCK_GETTIME_MONOTONIC_FLAG = 1; + /// @notice Start of the data segment. + uint64 internal constant PROGRAM_BREAK = 0x00_00_40_00_00_00_00_00; + uint64 internal constant HEAP_END = 0x00_00_60_00_00_00_00_00; + + // SYS_CLONE flags + uint64 internal constant CLONE_VM = 0x100; + uint64 internal constant CLONE_FS = 0x200; + uint64 internal constant CLONE_FILES = 0x400; + uint64 internal constant CLONE_SIGHAND = 0x800; + uint64 internal constant CLONE_PTRACE = 0x2000; + uint64 internal constant CLONE_VFORK = 0x4000; + uint64 internal constant CLONE_PARENT = 0x8000; + uint64 internal constant CLONE_THREAD = 0x10000; + uint64 internal constant CLONE_NEWNS = 0x20000; + uint64 internal constant CLONE_SYSVSEM = 0x40000; + uint64 internal constant CLONE_SETTLS = 0x80000; + uint64 internal constant CLONE_PARENTSETTID = 0x100000; + uint64 internal constant CLONE_CHILDCLEARTID = 0x200000; + uint64 internal constant CLONE_UNTRACED = 0x800000; + uint64 internal constant CLONE_CHILDSETTID = 0x1000000; + uint64 internal constant CLONE_STOPPED = 0x2000000; + uint64 internal constant CLONE_NEWUTS = 0x4000000; + uint64 internal constant CLONE_NEWIPC = 0x8000000; + uint64 internal constant VALID_SYS_CLONE_FLAGS = + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM | CLONE_THREAD; + + // FYI: https://en.wikibooks.org/wiki/MIPS_Assembly/Register_File + // https://refspecs.linuxfoundation.org/elf/mipsabi.pdf + uint32 internal constant REG_V0 = 2; + uint32 internal constant REG_A0 = 4; + uint32 internal constant REG_A1 = 5; + uint32 internal constant REG_A2 = 6; + uint32 internal constant REG_A3 = 7; + + // FYI: https://web.archive.org/web/20231223163047/https://www.linux-mips.org/wiki/Syscall + uint32 internal constant REG_SYSCALL_NUM = REG_V0; + uint32 internal constant REG_SYSCALL_ERRNO = REG_A3; + uint32 internal constant REG_SYSCALL_RET1 = REG_V0; + uint32 internal constant REG_SYSCALL_PARAM1 = REG_A0; + uint32 internal constant REG_SYSCALL_PARAM2 = REG_A1; + uint32 internal constant REG_SYSCALL_PARAM3 = REG_A2; + uint32 internal constant REG_SYSCALL_PARAM4 = REG_A3; + + // Constants copied from MIPS64Arch for use in Yul + uint64 internal constant WORD_SIZE_BYTES = 8; + uint64 internal constant EXT_MASK = 0x7; + + /// @notice Extract syscall num and arguments from registers. + /// @param _registers The cpu registers. + /// @return sysCallNum_ The syscall number. + /// @return a0_ The first argument available to the syscall operation. + /// @return a1_ The second argument available to the syscall operation. + /// @return a2_ The third argument available to the syscall operation. + /// @return a3_ The fourth argument available to the syscall operation. + function getSyscallArgs(uint64[32] memory _registers) + internal + pure + returns (uint64 sysCallNum_, uint64 a0_, uint64 a1_, uint64 a2_, uint64 a3_) + { + unchecked { + sysCallNum_ = _registers[REG_SYSCALL_NUM]; + + a0_ = _registers[REG_SYSCALL_PARAM1]; + a1_ = _registers[REG_SYSCALL_PARAM2]; + a2_ = _registers[REG_SYSCALL_PARAM3]; + a3_ = _registers[REG_SYSCALL_PARAM4]; + + return (sysCallNum_, a0_, a1_, a2_, a3_); + } + } + + /// @notice Like a Linux mmap syscall. Allocates a page from the heap. + /// @param _a0 The address for the new mapping + /// @param _a1 The size of the new mapping + /// @param _heap The current value of the heap pointer + /// @return v0_ The address of the new mapping + /// @return v1_ Unused error code (0) + /// @return newHeap_ The new value for the heap, may be unchanged + function handleSysMmap( + uint64 _a0, + uint64 _a1, + uint64 _heap + ) + internal + pure + returns (uint64 v0_, uint64 v1_, uint64 newHeap_) + { + unchecked { + v1_ = uint64(0); + newHeap_ = _heap; + + uint64 sz = _a1; + if (sz & PAGE_ADDR_MASK != 0) { + // adjust size to align with page size + sz += PAGE_SIZE - (sz & PAGE_ADDR_MASK); + } + if (_a0 == 0) { + v0_ = _heap; + newHeap_ += sz; + // Fail if new heap exceeds memory limit, newHeap overflows to low memory, or sz overflows + if (newHeap_ > HEAP_END || newHeap_ < _heap || sz < _a1) { + v0_ = SYS_ERROR_SIGNAL; + v1_ = EINVAL; + return (v0_, v1_, _heap); + } + } else { + v0_ = _a0; + } + + return (v0_, v1_, newHeap_); + } + } + + /// @notice Like a Linux read syscall. Splits unaligned reads into aligned reads. + /// Args are provided as a struct to reduce stack pressure. + /// @return v0_ The number of bytes read, -1 on error. + /// @return v1_ The error code, 0 if there is no error. + /// @return newPreimageOffset_ The new value for the preimage offset. + /// @return newMemRoot_ The new memory root. + function handleSysRead(SysReadParams memory _args) + internal + view + returns ( + uint64 v0_, + uint64 v1_, + uint64 newPreimageOffset_, + bytes32 newMemRoot_, + bool memUpdated_, + uint64 memAddr_ + ) + { + unchecked { + v0_ = uint64(0); + v1_ = uint64(0); + newMemRoot_ = _args.memRoot; + newPreimageOffset_ = _args.preimageOffset; + memUpdated_ = false; + memAddr_ = 0; + + // args: _a0 = fd, _a1 = addr, _a2 = count + // returns: v0_ = read, v1_ = err code + if (_args.a0 == FD_STDIN) { + // Leave v0_ and v1_ zero: read nothing, no error + } + // pre-image oracle read + else if (_args.a0 == FD_PREIMAGE_READ) { + uint64 effAddr = _args.a1 & arch.ADDRESS_MASK; + // verify proof is correct, and get the existing memory. + // mask the addr to align it to 4 bytes + uint64 mem = MIPS64Memory.readMem(_args.memRoot, effAddr, _args.proofOffset); + // If the preimage key is a local key, localize it in the context of the caller. + if (uint8(_args.preimageKey[0]) == 1) { + _args.preimageKey = PreimageKeyLib.localize(_args.preimageKey, _args.localContext); + } + (bytes32 dat, uint256 datLen) = _args.oracle.readPreimage(_args.preimageKey, _args.preimageOffset); + + // Transform data for writing to memory + // We use assembly for more precise ops, and no var count limit + uint64 a1 = _args.a1; + uint64 a2 = _args.a2; + assembly { + let alignment := and(a1, EXT_MASK) // the read might not start at an aligned address + let space := sub(WORD_SIZE_BYTES, alignment) // remaining space in memory word + if lt(space, datLen) { datLen := space } // if less space than data, shorten data + if lt(a2, datLen) { datLen := a2 } // if requested to read less, read less + dat := shr(sub(256, mul(datLen, 8)), dat) // right-align data + // position data to insert into memory word + dat := shl(mul(sub(sub(WORD_SIZE_BYTES, datLen), alignment), 8), dat) + // mask all bytes after start + let mask := sub(shl(mul(sub(WORD_SIZE_BYTES, alignment), 8), 1), 1) + // mask of all bytes + let suffixMask := sub(shl(mul(sub(sub(WORD_SIZE_BYTES, alignment), datLen), 8), 1), 1) + // starting from end, maybe none + mask := and(mask, not(suffixMask)) // reduce mask to just cover the data we insert + mem := or(and(mem, not(mask)), dat) // clear masked part of original memory, and insert data + } + + // Write memory back + newMemRoot_ = MIPS64Memory.writeMem(effAddr, _args.proofOffset, mem); + memUpdated_ = true; + memAddr_ = effAddr; + newPreimageOffset_ += uint64(datLen); + v0_ = uint64(datLen); + } + // hint response + else if (_args.a0 == FD_HINT_READ) { + // Don't read into memory, just say we read it all + // The result is ignored anyway + v0_ = _args.a2; + } else { + v0_ = U64_MASK; + v1_ = EBADF; + } + + return (v0_, v1_, newPreimageOffset_, newMemRoot_, memUpdated_, memAddr_); + } + } + + /// @notice Like a Linux write syscall. Splits unaligned writes into aligned writes. + /// @param _a0 The file descriptor. + /// @param _a1 The memory address to read from. + /// @param _a2 The number of bytes to read. + /// @param _preimageKey The current preimaageKey. + /// @param _preimageOffset The current preimageOffset. + /// @param _proofOffset The offset of the memory proof in calldata. + /// @param _memRoot The current memory root. + /// @return v0_ The number of bytes written, or -1 on error. + /// @return v1_ The error code, or 0 if empty. + /// @return newPreimageKey_ The new preimageKey. + /// @return newPreimageOffset_ The new preimageOffset. + function handleSysWrite( + uint64 _a0, + uint64 _a1, + uint64 _a2, + bytes32 _preimageKey, + uint64 _preimageOffset, + uint256 _proofOffset, + bytes32 _memRoot + ) + internal + pure + returns (uint64 v0_, uint64 v1_, bytes32 newPreimageKey_, uint64 newPreimageOffset_) + { + unchecked { + // args: _a0 = fd, _a1 = addr, _a2 = count + // returns: v0_ = written, v1_ = err code + v0_ = uint64(0); + v1_ = uint64(0); + newPreimageKey_ = _preimageKey; + newPreimageOffset_ = _preimageOffset; + + if (_a0 == FD_STDOUT || _a0 == FD_STDERR || _a0 == FD_HINT_WRITE) { + v0_ = _a2; // tell program we have written everything + } + // pre-image oracle + else if (_a0 == FD_PREIMAGE_WRITE) { + // mask the addr to align it to 4 bytes + uint64 mem = MIPS64Memory.readMem(_memRoot, _a1 & arch.ADDRESS_MASK, _proofOffset); + bytes32 key = _preimageKey; + + // Construct pre-image key from memory + // We use assembly for more precise ops, and no var count limit + assembly { + let alignment := and(_a1, EXT_MASK) // the read might not start at an aligned address + let space := sub(WORD_SIZE_BYTES, alignment) // remaining space in memory word + if lt(space, _a2) { _a2 := space } // if less space than data, shorten data + key := shl(mul(_a2, 8), key) // shift key, make space for new info + let mask := sub(shl(mul(_a2, 8), 1), 1) // mask for extracting value from memory + mem := and(shr(mul(sub(space, _a2), 8), mem), mask) // align value to right, mask it + key := or(key, mem) // insert into key + } + + // Write pre-image key to oracle + newPreimageKey_ = key; + newPreimageOffset_ = 0; // reset offset, to read new pre-image data from the start + v0_ = _a2; + } else { + v0_ = U64_MASK; + v1_ = EBADF; + } + + return (v0_, v1_, newPreimageKey_, newPreimageOffset_); + } + } + + /// @notice Like Linux fcntl (file control) syscall, but only supports minimal file-descriptor control commands, to + /// retrieve the file-descriptor R/W flags. + /// @param _a0 The file descriptor. + /// @param _a1 The control command. + /// @param v0_ The file status flag (only supported commands are F_GETFD and F_GETFL), or -1 on error. + /// @param v1_ An error number, or 0 if there is no error. + function handleSysFcntl(uint64 _a0, uint64 _a1) internal pure returns (uint64 v0_, uint64 v1_) { + unchecked { + v0_ = uint64(0); + v1_ = uint64(0); + + // args: _a0 = fd, _a1 = cmd + if (_a1 == 1) { + // F_GETFD: get file descriptor flags + if ( + _a0 == FD_STDIN || _a0 == FD_STDOUT || _a0 == FD_STDERR || _a0 == FD_PREIMAGE_READ + || _a0 == FD_HINT_READ || _a0 == FD_PREIMAGE_WRITE || _a0 == FD_HINT_WRITE + ) { + v0_ = 0; // No flags set + } else { + v0_ = U64_MASK; + v1_ = EBADF; + } + } else if (_a1 == 3) { + // F_GETFL: get file status flags + if (_a0 == FD_STDIN || _a0 == FD_PREIMAGE_READ || _a0 == FD_HINT_READ) { + v0_ = 0; // O_RDONLY + } else if (_a0 == FD_STDOUT || _a0 == FD_STDERR || _a0 == FD_PREIMAGE_WRITE || _a0 == FD_HINT_WRITE) { + v0_ = 1; // O_WRONLY + } else { + v0_ = U64_MASK; + v1_ = EBADF; + } + } else { + v0_ = U64_MASK; + v1_ = EINVAL; // cmd not recognized by this kernel + } + + return (v0_, v1_); + } + } + + function handleSyscallUpdates( + st.CpuScalars memory _cpu, + uint64[32] memory _registers, + uint64 _v0, + uint64 _v1 + ) + internal + pure + { + unchecked { + // Write the results back to the state registers + _registers[REG_SYSCALL_RET1] = _v0; + _registers[REG_SYSCALL_ERRNO] = _v1; + + // Update the PC and nextPC + _cpu.pc = _cpu.nextPC; + _cpu.nextPC = _cpu.nextPC + 4; + } + } +} diff --git a/packages/contracts-bedrock/src/cannon/libraries/MIPSInstructions.sol b/packages/contracts-bedrock/src/cannon/libraries/MIPSInstructions.sol index a2402531c82d1..fa4d1451b54bb 100644 --- a/packages/contracts-bedrock/src/cannon/libraries/MIPSInstructions.sol +++ b/packages/contracts-bedrock/src/cannon/libraries/MIPSInstructions.sol @@ -7,6 +7,7 @@ import { MIPSState as st } from "src/cannon/libraries/MIPSState.sol"; library MIPSInstructions { uint32 internal constant OP_LOAD_LINKED = 0x30; uint32 internal constant OP_STORE_CONDITIONAL = 0x38; + uint32 internal constant REG_RA = 31; struct CoreStepLogicParams { /// @param opcode The opcode value parsed from insn_. @@ -378,11 +379,11 @@ library MIPSInstructions { } // lb else if (_opcode == 0x20) { - return signExtend((_mem >> (24 - (_rs & 3) * 8)) & 0xFF, 8); + return selectSubWord(_rs, _mem, 1, true); } // lh else if (_opcode == 0x21) { - return signExtend((_mem >> (16 - (_rs & 2) * 8)) & 0xFFFF, 16); + return selectSubWord(_rs, _mem, 2, true); } // lwl else if (_opcode == 0x22) { @@ -392,15 +393,15 @@ library MIPSInstructions { } // lw else if (_opcode == 0x23) { - return _mem; + return selectSubWord(_rs, _mem, 4, true); } // lbu else if (_opcode == 0x24) { - return (_mem >> (24 - (_rs & 3) * 8)) & 0xFF; + return selectSubWord(_rs, _mem, 1, false); } // lhu else if (_opcode == 0x25) { - return (_mem >> (16 - (_rs & 2) * 8)) & 0xFFFF; + return selectSubWord(_rs, _mem, 2, false); } // lwr else if (_opcode == 0x26) { @@ -410,15 +411,11 @@ library MIPSInstructions { } // sb else if (_opcode == 0x28) { - uint32 val = (_rt & 0xFF) << (24 - (_rs & 3) * 8); - uint32 mask = 0xFFFFFFFF ^ uint32(0xFF << (24 - (_rs & 3) * 8)); - return (_mem & mask) | val; + return updateSubWord(_rs, _mem, 1, _rt); } // sh else if (_opcode == 0x29) { - uint32 val = (_rt & 0xFFFF) << (16 - (_rs & 2) * 8); - uint32 mask = 0xFFFFFFFF ^ uint32(0xFFFF << (16 - (_rs & 2) * 8)); - return (_mem & mask) | val; + return updateSubWord(_rs, _mem, 2, _rt); } // swl else if (_opcode == 0x2a) { @@ -428,7 +425,7 @@ library MIPSInstructions { } // sw else if (_opcode == 0x2b) { - return _rt; + return updateSubWord(_rs, _mem, 4, _rt); } // swr else if (_opcode == 0x2e) { @@ -498,9 +495,19 @@ library MIPSInstructions { if (rtv == 0) { shouldBranch = int32(_rs) < 0; } + // bltzal + if (rtv == 0x10) { + shouldBranch = int32(_rs) < 0; + _registers[31] = _cpu.pc + 8; // always set regardless of branch taken + } if (rtv == 1) { shouldBranch = int32(_rs) >= 0; } + // bgezal (i.e. bal mnemonic) + if (rtv == 0x11) { + shouldBranch = int32(_rs) >= 0; + _registers[REG_RA] = _cpu.pc + 8; // always set regardless of branch taken + } } // Update the state's previous PC @@ -661,4 +668,69 @@ library MIPSInstructions { _cpu.nextPC = _cpu.nextPC + 4; } } + + /// @notice Selects a subword of byteLength size contained in memWord based on the low-order bits of vaddr + /// @param _vaddr The virtual address of the the subword. + /// @param _memWord The full word to select a subword from. + /// @param _byteLength The size of the subword. + /// @param _signExtend Whether to sign extend the selected subwrod. + function selectSubWord( + uint32 _vaddr, + uint32 _memWord, + uint32 _byteLength, + bool _signExtend + ) + internal + pure + returns (uint32 retval_) + { + (uint32 dataMask, uint32 bitOffset, uint32 bitLength) = calculateSubWordMaskAndOffset(_vaddr, _byteLength); + retval_ = (_memWord >> bitOffset) & dataMask; + if (_signExtend) { + retval_ = signExtend(retval_, bitLength); + } + return retval_; + } + + /// @notice Returns a word that has been updated by the specified subword at bit positions determined by the virtual + /// address + /// @param _vaddr The virtual address of the subword. + /// @param _memWord The full word to update. + /// @param _byteLength The size of the subword. + /// @param _value The subword that updates _memWord. + function updateSubWord( + uint32 _vaddr, + uint32 _memWord, + uint32 _byteLength, + uint32 _value + ) + internal + pure + returns (uint32 word_) + { + (uint32 dataMask, uint32 bitOffset,) = calculateSubWordMaskAndOffset(_vaddr, _byteLength); + uint32 subWordValue = dataMask & _value; + uint32 memUpdateMask = dataMask << bitOffset; + return subWordValue << bitOffset | (~memUpdateMask) & _memWord; + } + + function calculateSubWordMaskAndOffset( + uint32 _vaddr, + uint32 _byteLength + ) + internal + pure + returns (uint32 dataMask_, uint32 bitOffset_, uint32 bitLength_) + { + uint32 bitLength = _byteLength << 3; + uint32 dataMask = ~uint32(0) >> (32 - bitLength); + + // Figure out sub-word index based on the low-order bits in vaddr + uint32 byteIndexMask = _vaddr & 0x3 & ~(_byteLength - 1); + uint32 maxByteShift = 4 - _byteLength; + uint32 byteIndex = _vaddr & byteIndexMask; + uint32 bitOffset = (maxByteShift - byteIndex) << 3; + + return (dataMask, bitOffset, bitLength); + } } diff --git a/packages/contracts-bedrock/src/cannon/libraries/MIPSMemory.sol b/packages/contracts-bedrock/src/cannon/libraries/MIPSMemory.sol index e88f51438ef48..015955954b5a6 100644 --- a/packages/contracts-bedrock/src/cannon/libraries/MIPSMemory.sol +++ b/packages/contracts-bedrock/src/cannon/libraries/MIPSMemory.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import "src/cannon/libraries/CannonErrors.sol"; +import { InvalidMemoryProof } from "src/cannon/libraries/CannonErrors.sol"; library MIPSMemory { /// @notice Reads a 32-bit value from memory. diff --git a/packages/contracts-bedrock/src/cannon/libraries/MIPSSyscalls.sol b/packages/contracts-bedrock/src/cannon/libraries/MIPSSyscalls.sol index 9b5278e052aeb..ec0cfdded894d 100644 --- a/packages/contracts-bedrock/src/cannon/libraries/MIPSSyscalls.sol +++ b/packages/contracts-bedrock/src/cannon/libraries/MIPSSyscalls.sol @@ -53,6 +53,7 @@ library MIPSSyscalls { uint32 internal constant SYS_PRLIMIT64 = 4338; uint32 internal constant SYS_CLOSE = 4006; uint32 internal constant SYS_PREAD64 = 4200; + uint32 internal constant SYS_STAT = 4106; uint32 internal constant SYS_FSTAT = 4108; uint32 internal constant SYS_FSTAT64 = 4215; uint32 internal constant SYS_OPENAT = 4288; @@ -71,6 +72,8 @@ library MIPSSyscalls { uint32 internal constant SYS_LLSEEK = 4140; uint32 internal constant SYS_MINCORE = 4217; uint32 internal constant SYS_TGKILL = 4266; + uint32 internal constant SYS_GETRLIMIT = 4076; + uint32 internal constant SYS_LSEEK = 4019; // profiling-related syscalls - ignored uint32 internal constant SYS_SETITIMER = 4104; diff --git a/packages/contracts-bedrock/src/dispute/DelayedWETH.sol b/packages/contracts-bedrock/src/dispute/DelayedWETH.sol index 42b6022d12fe4..3438c22e3679a 100644 --- a/packages/contracts-bedrock/src/dispute/DelayedWETH.sol +++ b/packages/contracts-bedrock/src/dispute/DelayedWETH.sol @@ -32,8 +32,8 @@ contract DelayedWETH is OwnableUpgradeable, WETH98, ISemver { event Unwrap(address indexed src, uint256 wad); /// @notice Semantic version. - /// @custom:semver 1.2.0-beta.2 - string public constant version = "1.2.0-beta.2"; + /// @custom:semver 1.2.0-beta.3 + string public constant version = "1.2.0-beta.3"; /// @notice Returns a withdrawal request for the given address. mapping(address => mapping(address => WithdrawalRequest)) public withdrawals; @@ -112,7 +112,7 @@ contract DelayedWETH is OwnableUpgradeable, WETH98, ISemver { /// @param _wad The amount of WETH to recover. function hold(address _guy, uint256 _wad) external { require(msg.sender == owner(), "DelayedWETH: not owner"); - allowance[_guy][msg.sender] = _wad; + _allowance[_guy][msg.sender] = _wad; emit Approval(_guy, msg.sender, _wad); } } diff --git a/packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol b/packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol index 884fb00b4a65b..2bd5ec67e96c2 100644 --- a/packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol +++ b/packages/contracts-bedrock/src/dispute/FaultDisputeGame.sol @@ -12,17 +12,16 @@ import { GameStatus, GameType, Claim, - Position, Clock, Duration, Timestamp, Hash, OutputRoot, - LibPosition, LibClock, LocalPreimageKey, VMStatuses } from "src/dispute/lib/Types.sol"; +import { Position, LibPosition } from "src/dispute/lib/LibPosition.sol"; import { InvalidParent, ClaimAlreadyExists, @@ -147,8 +146,8 @@ contract FaultDisputeGame is Clone, ISemver { uint256 internal constant HEADER_BLOCK_NUMBER_INDEX = 8; /// @notice Semantic version. - /// @custom:semver 1.3.1-beta.5 - string public constant version = "1.3.1-beta.5"; + /// @custom:semver 1.3.1-beta.7 + string public constant version = "1.3.1-beta.7"; /// @notice The starting timestamp of the game Timestamp public createdAt; diff --git a/packages/contracts-bedrock/src/dispute/interfaces/IAnchorStateRegistry.sol b/packages/contracts-bedrock/src/dispute/interfaces/IAnchorStateRegistry.sol index 4de2bb1deab60..4c79c4c092a9a 100644 --- a/packages/contracts-bedrock/src/dispute/interfaces/IAnchorStateRegistry.sol +++ b/packages/contracts-bedrock/src/dispute/interfaces/IAnchorStateRegistry.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol"; import { IDisputeGameFactory } from "src/dispute/interfaces/IDisputeGameFactory.sol"; import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; -import "src/dispute/lib/Types.sol"; +import { GameType, Hash, OutputRoot } from "src/dispute/lib/Types.sol"; interface IAnchorStateRegistry { struct StartingAnchorRoot { diff --git a/packages/contracts-bedrock/src/dispute/interfaces/IDelayedWETH.sol b/packages/contracts-bedrock/src/dispute/interfaces/IDelayedWETH.sol index 55b940c2d9dd2..98b221285b560 100644 --- a/packages/contracts-bedrock/src/dispute/interfaces/IDelayedWETH.sol +++ b/packages/contracts-bedrock/src/dispute/interfaces/IDelayedWETH.sol @@ -1,15 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import { IWETH } from "src/universal/interfaces/IWETH.sol"; import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; -interface IDelayedWETH is IWETH { +interface IDelayedWETH { struct WithdrawalRequest { uint256 amount; uint256 timestamp; } + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + event Initialized(uint8 version); event Unwrap(address indexed src, uint256 wad); fallback() external payable; @@ -25,8 +26,38 @@ interface IDelayedWETH is IWETH { function renounceOwnership() external; function unlock(address _guy, uint256 _wad) external; function withdraw(address _guy, uint256 _wad) external; - function withdrawals(address _owner, address _guy) external view returns (uint256, uint256); + function withdrawals(address, address) external view returns (uint256 amount, uint256 timestamp); function version() external view returns (string memory); + function withdraw(uint256 _wad) external; + + event Approval(address indexed src, address indexed guy, uint256 wad); + + event Transfer(address indexed src, address indexed dst, uint256 wad); + + event Deposit(address indexed dst, uint256 wad); + + event Withdrawal(address indexed src, uint256 wad); + + function name() external view returns (string memory); + + function symbol() external view returns (string memory); + + function decimals() external view returns (uint8); + + function balanceOf(address src) external view returns (uint256); + + function allowance(address owner, address spender) external view returns (uint256); + + function deposit() external payable; + + function totalSupply() external view returns (uint256); + + function approve(address guy, uint256 wad) external returns (bool); + + function transfer(address dst, uint256 wad) external returns (bool); + + function transferFrom(address src, address dst, uint256 wad) external returns (bool); + function __constructor__(uint256 _delay) external; } diff --git a/packages/contracts-bedrock/src/dispute/interfaces/IDisputeGame.sol b/packages/contracts-bedrock/src/dispute/interfaces/IDisputeGame.sol index f5a650202d0ce..0f860e68b5a16 100644 --- a/packages/contracts-bedrock/src/dispute/interfaces/IDisputeGame.sol +++ b/packages/contracts-bedrock/src/dispute/interfaces/IDisputeGame.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import { IInitializable } from "src/dispute/interfaces/IInitializable.sol"; -import "src/dispute/lib/Types.sol"; +import { Timestamp, GameStatus, GameType, Claim, Hash } from "src/dispute/lib/Types.sol"; interface IDisputeGame is IInitializable { event Resolved(GameStatus indexed status); diff --git a/packages/contracts-bedrock/src/dispute/interfaces/IDisputeGameFactory.sol b/packages/contracts-bedrock/src/dispute/interfaces/IDisputeGameFactory.sol index 0f21d42aa27a1..3e7233f440d6d 100644 --- a/packages/contracts-bedrock/src/dispute/interfaces/IDisputeGameFactory.sol +++ b/packages/contracts-bedrock/src/dispute/interfaces/IDisputeGameFactory.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol"; -import "src/dispute/lib/Types.sol"; +import { GameId, Timestamp, Claim, Hash, GameType } from "src/dispute/lib/Types.sol"; interface IDisputeGameFactory { struct GameSearchResult { diff --git a/packages/contracts-bedrock/src/dispute/interfaces/IFaultDisputeGame.sol b/packages/contracts-bedrock/src/dispute/interfaces/IFaultDisputeGame.sol index ec0f86ff709cd..8c5bac02e9ba8 100644 --- a/packages/contracts-bedrock/src/dispute/interfaces/IFaultDisputeGame.sol +++ b/packages/contracts-bedrock/src/dispute/interfaces/IFaultDisputeGame.sol @@ -6,7 +6,7 @@ import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol"; import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol"; import { IBigStepper } from "src/dispute/interfaces/IBigStepper.sol"; import { Types } from "src/libraries/Types.sol"; -import "src/dispute/lib/Types.sol"; +import { GameType, Claim, Position, Clock, Hash, Duration } from "src/dispute/lib/Types.sol"; interface IFaultDisputeGame is IDisputeGame { struct ClaimData { diff --git a/packages/contracts-bedrock/src/dispute/interfaces/IPermissionedDisputeGame.sol b/packages/contracts-bedrock/src/dispute/interfaces/IPermissionedDisputeGame.sol index 980d3460c048b..c5a5a187ec129 100644 --- a/packages/contracts-bedrock/src/dispute/interfaces/IPermissionedDisputeGame.sol +++ b/packages/contracts-bedrock/src/dispute/interfaces/IPermissionedDisputeGame.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import { Types } from "src/libraries/Types.sol"; -import "src/dispute/lib/Types.sol"; +import { GameType, Claim, Position, Clock, Hash, Duration } from "src/dispute/lib/Types.sol"; import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol"; import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol"; diff --git a/packages/contracts-bedrock/src/dispute/lib/Errors.sol b/packages/contracts-bedrock/src/dispute/lib/Errors.sol index 6cd1d1d073f46..6e95bfa5a3420 100644 --- a/packages/contracts-bedrock/src/dispute/lib/Errors.sol +++ b/packages/contracts-bedrock/src/dispute/lib/Errors.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.15; -import "src/dispute/lib/LibUDT.sol"; +import { GameType, Hash, Claim } from "src/dispute/lib/LibUDT.sol"; //////////////////////////////////////////////////////////////// // `DisputeGameFactory` Errors // diff --git a/packages/contracts-bedrock/src/dispute/lib/LibUDT.sol b/packages/contracts-bedrock/src/dispute/lib/LibUDT.sol index b0b8edfab8f49..bfc110f095261 100644 --- a/packages/contracts-bedrock/src/dispute/lib/LibUDT.sol +++ b/packages/contracts-bedrock/src/dispute/lib/LibUDT.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.15; -import "src/dispute/lib/LibPosition.sol"; +import { Position } from "src/dispute/lib/LibPosition.sol"; using LibClaim for Claim global; using LibHash for Hash global; diff --git a/packages/contracts-bedrock/src/dispute/lib/Types.sol b/packages/contracts-bedrock/src/dispute/lib/Types.sol index 8d86e6e25387d..70df7b7912ba6 100644 --- a/packages/contracts-bedrock/src/dispute/lib/Types.sol +++ b/packages/contracts-bedrock/src/dispute/lib/Types.sol @@ -1,7 +1,19 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.15; -import "src/dispute/lib/LibUDT.sol"; +import { + Position, + Hash, + GameType, + VMStatus, + Timestamp, + Duration, + Clock, + GameId, + Claim, + LibGameId, + LibClock +} from "src/dispute/lib/LibUDT.sol"; /// @notice The current status of the dispute game. enum GameStatus { diff --git a/packages/contracts-bedrock/src/legacy/LegacyMintableERC20.sol b/packages/contracts-bedrock/src/legacy/LegacyMintableERC20.sol index 2508b34e43b3f..b3b588258242f 100644 --- a/packages/contracts-bedrock/src/legacy/LegacyMintableERC20.sol +++ b/packages/contracts-bedrock/src/legacy/LegacyMintableERC20.sol @@ -7,7 +7,7 @@ import { ILegacyMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; /// @title LegacyMintableERC20 /// @notice The legacy implementation of the OptimismMintableERC20. This /// contract is deprecated and should no longer be used. -contract LegacyMintableERC20 is ILegacyMintableERC20, ERC20 { +contract LegacyMintableERC20 is ERC20 { /// @notice Emitted when the token is minted by the bridge. event Mint(address indexed _account, uint256 _amount); diff --git a/packages/contracts-bedrock/src/libraries/Encoding.sol b/packages/contracts-bedrock/src/libraries/Encoding.sol index edcdd4ed75e2a..84d5f732f5f6d 100644 --- a/packages/contracts-bedrock/src/libraries/Encoding.sol +++ b/packages/contracts-bedrock/src/libraries/Encoding.sol @@ -74,6 +74,7 @@ library Encoding { pure returns (bytes memory) { + // nosemgrep: sol-style-use-abi-encodecall return abi.encodeWithSignature("relayMessage(address,address,bytes,uint256)", _target, _sender, _data, _nonce); } @@ -97,6 +98,7 @@ library Encoding { pure returns (bytes memory) { + // nosemgrep: sol-style-use-abi-encodecall return abi.encodeWithSignature( "relayMessage(uint256,address,address,uint256,uint256,bytes)", _nonce, diff --git a/packages/contracts-bedrock/src/libraries/LegacyCrossDomainUtils.sol b/packages/contracts-bedrock/src/libraries/LegacyCrossDomainUtils.sol index 2a784ca1b6dca..a43bc2cecc4b3 100644 --- a/packages/contracts-bedrock/src/libraries/LegacyCrossDomainUtils.sol +++ b/packages/contracts-bedrock/src/libraries/LegacyCrossDomainUtils.sol @@ -24,6 +24,7 @@ library LegacyCrossDomainUtils { pure returns (bytes memory) { + // nosemgrep: sol-style-use-abi-encodecall return abi.encodeWithSignature( "relayMessage(address,address,bytes,uint256)", _target, _sender, _message, _messageNonce ); diff --git a/packages/contracts-bedrock/src/libraries/rlp/RLPReader.sol b/packages/contracts-bedrock/src/libraries/rlp/RLPReader.sol index 9f82ca8c802ec..559c53391f703 100644 --- a/packages/contracts-bedrock/src/libraries/rlp/RLPReader.sol +++ b/packages/contracts-bedrock/src/libraries/rlp/RLPReader.sol @@ -1,7 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.8; -import "./RLPErrors.sol"; +import { + EmptyItem, + UnexpectedString, + InvalidDataRemainder, + ContentLengthMismatch, + InvalidHeader, + UnexpectedList +} from "./RLPErrors.sol"; /// @custom:attribution https://github.com/hamdiallam/Solidity-RLP /// @title RLPReader diff --git a/packages/contracts-bedrock/src/safe/DeputyGuardianModule.sol b/packages/contracts-bedrock/src/safe/DeputyGuardianModule.sol index 0882910d50721..673cf2a1efb66 100644 --- a/packages/contracts-bedrock/src/safe/DeputyGuardianModule.sol +++ b/packages/contracts-bedrock/src/safe/DeputyGuardianModule.sol @@ -7,7 +7,7 @@ import { Enum } from "safe-contracts/common/Enum.sol"; // Libraries import { Unauthorized } from "src/libraries/PortalErrors.sol"; -import "src/dispute/lib/Types.sol"; +import { GameType, Timestamp } from "src/dispute/lib/Types.sol"; // Interfaces import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol"; @@ -48,8 +48,8 @@ contract DeputyGuardianModule is ISemver { address internal immutable DEPUTY_GUARDIAN; /// @notice Semantic version. - /// @custom:semver 2.0.1-beta.3 - string public constant version = "2.0.1-beta.3"; + /// @custom:semver 2.0.1-beta.4 + string public constant version = "2.0.1-beta.4"; // Constructor to initialize the Safe and baseModule instances constructor(Safe _safe, ISuperchainConfig _superchainConfig, address _deputyGuardian) { diff --git a/packages/contracts-bedrock/src/safe/interfaces/IDeputyGuardianModule.sol b/packages/contracts-bedrock/src/safe/interfaces/IDeputyGuardianModule.sol new file mode 100644 index 0000000000000..da74cf4dd983b --- /dev/null +++ b/packages/contracts-bedrock/src/safe/interfaces/IDeputyGuardianModule.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol"; +import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol"; +import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; +import { IOptimismPortal2 } from "src/L1/interfaces/IOptimismPortal2.sol"; +import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol"; +import { ISemver } from "src/universal/interfaces/ISemver.sol"; +import { GameType, Timestamp } from "src/dispute/lib/Types.sol"; +import { GnosisSafe as Safe } from "safe-contracts/GnosisSafe.sol"; + +interface IDeputyGuardianModule is ISemver { + error ExecutionFailed(string); + error Unauthorized(); + + event Paused(string identifier); + event Unpaused(); + event DisputeGameBlacklisted(IDisputeGame indexed game); + event RespectedGameTypeSet(GameType indexed gameType, Timestamp indexed updatedAt); + + function version() external view returns (string memory); + function __constructor__(Safe _safe, ISuperchainConfig _superchainConfig, address _deputyGuardian) external; + function safe() external view returns (Safe safe_); + function superchainConfig() external view returns (ISuperchainConfig superchainConfig_); + function deputyGuardian() external view returns (address deputyGuardian_); + function pause() external; + function unpause() external; + function setAnchorState(IAnchorStateRegistry _registry, IFaultDisputeGame _game) external; + function blacklistDisputeGame(IOptimismPortal2 _portal, IDisputeGame _game) external; + function setRespectedGameType(IOptimismPortal2 _portal, GameType _gameType) external; +} diff --git a/packages/contracts-bedrock/src/safe/interfaces/ILivenessGuard.sol b/packages/contracts-bedrock/src/safe/interfaces/ILivenessGuard.sol new file mode 100644 index 0000000000000..a69921211955d --- /dev/null +++ b/packages/contracts-bedrock/src/safe/interfaces/ILivenessGuard.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { GnosisSafe as Safe } from "safe-contracts/GnosisSafe.sol"; +import { Enum } from "safe-contracts/common/Enum.sol"; +import { ISemver } from "src/universal/interfaces/ISemver.sol"; + +interface ILivenessGuard is ISemver { + event OwnerRecorded(address owner); + + function lastLive(address) external view returns (uint256); + function version() external view returns (string memory); + function __constructor__(Safe _safe) external; + + function safe() external view returns (Safe safe_); + function checkTransaction( + address _to, + uint256 _value, + bytes memory _data, + Enum.Operation _operation, + uint256 _safeTxGas, + uint256 _baseGas, + uint256 _gasPrice, + address _gasToken, + address payable _refundReceiver, + bytes memory _signatures, + address _msgSender + ) + external; + function checkAfterExecution(bytes32, bool) external; + function showLiveness() external; +} diff --git a/packages/contracts-bedrock/src/safe/interfaces/ILivenessModule.sol b/packages/contracts-bedrock/src/safe/interfaces/ILivenessModule.sol new file mode 100644 index 0000000000000..43711d508597e --- /dev/null +++ b/packages/contracts-bedrock/src/safe/interfaces/ILivenessModule.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { GnosisSafe as Safe } from "safe-contracts/GnosisSafe.sol"; +import { LivenessGuard } from "src/safe/LivenessGuard.sol"; +import { ISemver } from "src/universal/interfaces/ISemver.sol"; + +interface ILivenessModule is ISemver { + error OwnerRemovalFailed(string); + + event RemovedOwner(address indexed owner); + event OwnershipTransferredToFallback(); + + function ownershipTransferredToFallback() external view returns (bool); + function version() external view returns (string memory); + function __constructor__( + Safe _safe, + LivenessGuard _livenessGuard, + uint256 _livenessInterval, + uint256 _minOwners, + uint256 _thresholdPercentage, + address _fallbackOwner + ) + external; + function getRequiredThreshold(uint256 _numOwners) external view returns (uint256 threshold_); + function safe() external view returns (Safe safe_); + function livenessGuard() external view returns (LivenessGuard livenessGuard_); + function livenessInterval() external view returns (uint256 livenessInterval_); + function minOwners() external view returns (uint256 minOwners_); + function thresholdPercentage() external view returns (uint256 thresholdPercentage_); + function fallbackOwner() external view returns (address fallbackOwner_); + function canRemove(address _owner) external view returns (bool canRemove_); + function removeOwners(address[] memory _previousOwners, address[] memory _ownersToRemove) external; +} diff --git a/packages/contracts-bedrock/src/universal/OptimismMintableERC20.sol b/packages/contracts-bedrock/src/universal/OptimismMintableERC20.sol index 838a21af56626..34d601cbb65b0 100644 --- a/packages/contracts-bedrock/src/universal/OptimismMintableERC20.sol +++ b/packages/contracts-bedrock/src/universal/OptimismMintableERC20.sol @@ -4,7 +4,8 @@ pragma solidity 0.8.15; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { ERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -import { ILegacyMintableERC20, IOptimismMintableERC20 } from "src/universal/interfaces/IOptimismMintableERC20.sol"; +import { IOptimismMintableERC20 } from "src/universal/interfaces/IOptimismMintableERC20.sol"; +import { ILegacyMintableERC20 } from "src/universal/interfaces/ILegacyMintableERC20.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; import { Preinstalls } from "src/libraries/Preinstalls.sol"; @@ -14,7 +15,7 @@ import { Preinstalls } from "src/libraries/Preinstalls.sol"; /// use an OptimismMintablERC20 as the L2 representation of an L1 token, or vice-versa. /// Designed to be backwards compatible with the older StandardL2ERC20 token which was only /// meant for use on L2. -contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20, ERC20Permit, ISemver { +contract OptimismMintableERC20 is ERC20Permit, ISemver { /// @notice Address of the corresponding version of this token on the remote chain. address public immutable REMOTE_TOKEN; @@ -41,8 +42,8 @@ contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20, } /// @notice Semantic version. - /// @custom:semver 1.4.0-beta.1 - string public constant version = "1.4.0-beta.1"; + /// @custom:semver 1.4.0-beta.2 + string public constant version = "1.4.0-beta.2"; /// @notice Getter function for the permit2 address. It deterministically deployed /// so it will always be at the same address. It is also included as a preinstall, @@ -96,15 +97,7 @@ contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20, /// @notice Allows the StandardBridge on this network to mint tokens. /// @param _to Address to mint tokens to. /// @param _amount Amount of tokens to mint. - function mint( - address _to, - uint256 _amount - ) - external - virtual - override(IOptimismMintableERC20, ILegacyMintableERC20) - onlyBridge - { + function mint(address _to, uint256 _amount) external virtual onlyBridge { _mint(_to, _amount); emit Mint(_to, _amount); } @@ -112,15 +105,7 @@ contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20, /// @notice Allows the StandardBridge on this network to burn tokens. /// @param _from Address to burn tokens from. /// @param _amount Amount of tokens to burn. - function burn( - address _from, - uint256 _amount - ) - external - virtual - override(IOptimismMintableERC20, ILegacyMintableERC20) - onlyBridge - { + function burn(address _from, uint256 _amount) external virtual onlyBridge { _burn(_from, _amount); emit Burn(_from, _amount); } diff --git a/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol b/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol index e179c6408dad1..d7a9cd3372cdb 100644 --- a/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol +++ b/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol @@ -48,8 +48,8 @@ contract OptimismMintableERC20Factory is ISemver, Initializable, IOptimismERC20F /// the OptimismMintableERC20 token contract since this contract /// is responsible for deploying OptimismMintableERC20 contracts. /// @notice Semantic version. - /// @custom:semver 1.10.1-beta.3 - string public constant version = "1.10.1-beta.3"; + /// @custom:semver 1.10.1-beta.4 + string public constant version = "1.10.1-beta.4"; /// @notice Constructs the OptimismMintableERC20Factory contract. constructor() { diff --git a/packages/contracts-bedrock/src/universal/OptimismMintableERC721.sol b/packages/contracts-bedrock/src/universal/OptimismMintableERC721.sol index 955a340722051..9dd05e10d1fec 100644 --- a/packages/contracts-bedrock/src/universal/OptimismMintableERC721.sol +++ b/packages/contracts-bedrock/src/universal/OptimismMintableERC721.sol @@ -3,7 +3,6 @@ pragma solidity 0.8.15; import { ERC721Enumerable } from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { IOptimismMintableERC721 } from "src/universal/interfaces/IOptimismMintableERC721.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; @@ -12,14 +11,24 @@ import { ISemver } from "src/universal/interfaces/ISemver.sol"; /// @notice This contract is the remote representation for some token that lives on another network, /// typically an Optimism representation of an Ethereum-based token. Standard reference /// implementation that can be extended or modified according to your needs. -contract OptimismMintableERC721 is ERC721Enumerable, IOptimismMintableERC721, ISemver { - /// @inheritdoc IOptimismMintableERC721 +contract OptimismMintableERC721 is ERC721Enumerable, ISemver { + /// @notice Emitted when a token is minted. + /// @param account Address of the account the token was minted to. + /// @param tokenId Token ID of the minted token. + event Mint(address indexed account, uint256 tokenId); + + /// @notice Emitted when a token is burned. + /// @param account Address of the account the token was burned from. + /// @param tokenId Token ID of the burned token. + event Burn(address indexed account, uint256 tokenId); + + /// @notice Chain ID of the chain where the remote token is deployed. uint256 public immutable REMOTE_CHAIN_ID; - /// @inheritdoc IOptimismMintableERC721 + /// @notice Address of the token on the remote domain. address public immutable REMOTE_TOKEN; - /// @inheritdoc IOptimismMintableERC721 + /// @notice Address of the ERC721 bridge on this network. address public immutable BRIDGE; /// @notice Base token URI for this token. @@ -32,8 +41,8 @@ contract OptimismMintableERC721 is ERC721Enumerable, IOptimismMintableERC721, IS } /// @notice Semantic version. - /// @custom:semver 1.3.1-beta.2 - string public constant version = "1.3.1-beta.2"; + /// @custom:semver 1.3.1-beta.3 + string public constant version = "1.3.1-beta.3"; /// @param _bridge Address of the bridge on this network. /// @param _remoteChainId Chain ID where the remote token is deployed. @@ -70,29 +79,34 @@ contract OptimismMintableERC721 is ERC721Enumerable, IOptimismMintableERC721, IS ); } - /// @inheritdoc IOptimismMintableERC721 + /// @notice Chain ID of the chain where the remote token is deployed. function remoteChainId() external view returns (uint256) { return REMOTE_CHAIN_ID; } - /// @inheritdoc IOptimismMintableERC721 + /// @notice Address of the token on the remote domain. function remoteToken() external view returns (address) { return REMOTE_TOKEN; } - /// @inheritdoc IOptimismMintableERC721 + /// @notice Address of the ERC721 bridge on this network. function bridge() external view returns (address) { return BRIDGE; } - /// @inheritdoc IOptimismMintableERC721 + /// @notice Mints some token ID for a user, checking first that contract recipients + /// are aware of the ERC721 protocol to prevent tokens from being forever locked. + /// @param _to Address of the user to mint the token for. + /// @param _tokenId Token ID to mint. function safeMint(address _to, uint256 _tokenId) external virtual onlyBridge { _safeMint(_to, _tokenId); emit Mint(_to, _tokenId); } - /// @inheritdoc IOptimismMintableERC721 + /// @notice Burns a token ID from a user. + /// @param _from Address of the user to burn the token from. + /// @param _tokenId Token ID to burn. function burn(address _from, uint256 _tokenId) external virtual onlyBridge { _burn(_tokenId); @@ -102,7 +116,7 @@ contract OptimismMintableERC721 is ERC721Enumerable, IOptimismMintableERC721, IS /// @notice Checks if a given interface ID is supported by this contract. /// @param _interfaceId The interface ID to check. /// @return True if the interface ID is supported, false otherwise. - function supportsInterface(bytes4 _interfaceId) public view override(ERC721Enumerable, IERC165) returns (bool) { + function supportsInterface(bytes4 _interfaceId) public view override(ERC721Enumerable) returns (bool) { bytes4 iface = type(IOptimismMintableERC721).interfaceId; return _interfaceId == iface || super.supportsInterface(_interfaceId); } diff --git a/packages/contracts-bedrock/src/universal/OptimismMintableERC721Factory.sol b/packages/contracts-bedrock/src/universal/OptimismMintableERC721Factory.sol index 943859a7db1cc..7350e0fae0de5 100644 --- a/packages/contracts-bedrock/src/universal/OptimismMintableERC721Factory.sol +++ b/packages/contracts-bedrock/src/universal/OptimismMintableERC721Factory.sol @@ -25,8 +25,8 @@ contract OptimismMintableERC721Factory is ISemver { event OptimismMintableERC721Created(address indexed localToken, address indexed remoteToken, address deployer); /// @notice Semantic version. - /// @custom:semver 1.4.1-beta.3 - string public constant version = "1.4.1-beta.3"; + /// @custom:semver 1.4.1-beta.4 + string public constant version = "1.4.1-beta.4"; /// @notice The semver MUST be bumped any time that there is a change in /// the OptimismMintableERC721 token contract since this contract diff --git a/packages/contracts-bedrock/src/universal/StandardBridge.sol b/packages/contracts-bedrock/src/universal/StandardBridge.sol index 476d3ba54c933..57af2247a65ac 100644 --- a/packages/contracts-bedrock/src/universal/StandardBridge.sol +++ b/packages/contracts-bedrock/src/universal/StandardBridge.sol @@ -6,7 +6,8 @@ import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC16 import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { SafeCall } from "src/libraries/SafeCall.sol"; -import { IOptimismMintableERC20, ILegacyMintableERC20 } from "src/universal/interfaces/IOptimismMintableERC20.sol"; +import { IOptimismMintableERC20 } from "src/universal/interfaces/IOptimismMintableERC20.sol"; +import { ILegacyMintableERC20 } from "src/universal/interfaces/ILegacyMintableERC20.sol"; import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol"; import { OptimismMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; diff --git a/packages/contracts-bedrock/src/universal/WETH98.sol b/packages/contracts-bedrock/src/universal/WETH98.sol index 5665e5f9210fe..c2909e6fa6f70 100644 --- a/packages/contracts-bedrock/src/universal/WETH98.sol +++ b/packages/contracts-bedrock/src/universal/WETH98.sol @@ -19,15 +19,37 @@ pragma solidity 0.8.15; -import { IWETH } from "src/universal/interfaces/IWETH.sol"; - /// @title WETH98 /// @notice WETH98 is a version of WETH9 upgraded for Solidity 0.8.x. -contract WETH98 is IWETH { +contract WETH98 { + /// @notice Returns the number of decimals the token uses. + /// @return The number of decimals the token uses. uint8 public constant decimals = 18; - mapping(address => uint256) public balanceOf; - mapping(address => mapping(address => uint256)) public allowance; + mapping(address => uint256) internal _balanceOf; + mapping(address => mapping(address => uint256)) internal _allowance; + + /// @notice Emitted when an approval is made. + /// @param src The address that approved the transfer. + /// @param guy The address that was approved to transfer. + /// @param wad The amount that was approved to transfer. + event Approval(address indexed src, address indexed guy, uint256 wad); + + /// @notice Emitted when a transfer is made. + /// @param src The address that transferred the WETH. + /// @param dst The address that received the WETH. + /// @param wad The amount of WETH that was transferred. + event Transfer(address indexed src, address indexed dst, uint256 wad); + + /// @notice Emitted when a deposit is made. + /// @param dst The address that deposited the WETH. + /// @param wad The amount of WETH that was deposited. + event Deposit(address indexed dst, uint256 wad); + + /// @notice Emitted when a withdrawal is made. + /// @param src The address that withdrew the WETH. + /// @param wad The amount of WETH that was withdrawn. + event Withdrawal(address indexed src, uint256 wad); /// @notice Pipes to deposit. receive() external payable { @@ -39,58 +61,88 @@ contract WETH98 is IWETH { deposit(); } - /// @inheritdoc IWETH - function name() external view virtual override returns (string memory) { + /// @notice Returns the name of the token. + /// @return name_ The name of the token. + function name() external view virtual returns (string memory) { return "Wrapped Ether"; } - /// @inheritdoc IWETH - function symbol() external view virtual override returns (string memory) { + /// @notice Returns the symbol of the token. + /// @return symbol_ The symbol of the token. + function symbol() external view virtual returns (string memory) { return "WETH"; } - /// @inheritdoc IWETH + /// @notice Returns the amount of WETH that the spender can transfer on behalf of the owner. + /// @param owner The address that owns the WETH. + /// @param spender The address that is approved to transfer the WETH. + /// @return The amount of WETH that the spender can transfer on behalf of the owner. + function allowance(address owner, address spender) public view virtual returns (uint256) { + return _allowance[owner][spender]; + } + + /// @notice Returns the balance of the given address. + /// @param src The address to query the balance of. + /// @return The balance of the given address. + function balanceOf(address src) public view returns (uint256) { + return _balanceOf[src]; + } + + /// @notice Allows WETH to be deposited by sending ether to the contract. function deposit() public payable virtual { - balanceOf[msg.sender] += msg.value; + _balanceOf[msg.sender] += msg.value; emit Deposit(msg.sender, msg.value); } - /// @inheritdoc IWETH + /// @notice Withdraws an amount of ETH. + /// @param wad The amount of ETH to withdraw. function withdraw(uint256 wad) public virtual { - require(balanceOf[msg.sender] >= wad); - balanceOf[msg.sender] -= wad; + require(_balanceOf[msg.sender] >= wad); + _balanceOf[msg.sender] -= wad; payable(msg.sender).transfer(wad); emit Withdrawal(msg.sender, wad); } - /// @inheritdoc IWETH + /// @notice Returns the total supply of WETH. + /// @return The total supply of WETH. function totalSupply() external view returns (uint256) { return address(this).balance; } - /// @inheritdoc IWETH + /// @notice Approves the given address to transfer the WETH on behalf of the caller. + /// @param guy The address that is approved to transfer the WETH. + /// @param wad The amount that is approved to transfer. + /// @return True if the approval was successful. function approve(address guy, uint256 wad) external returns (bool) { - allowance[msg.sender][guy] = wad; + _allowance[msg.sender][guy] = wad; emit Approval(msg.sender, guy, wad); return true; } - /// @inheritdoc IWETH + /// @notice Transfers the given amount of WETH to the given address. + /// @param dst The address to transfer the WETH to. + /// @param wad The amount of WETH to transfer. + /// @return True if the transfer was successful. function transfer(address dst, uint256 wad) external returns (bool) { return transferFrom(msg.sender, dst, wad); } - /// @inheritdoc IWETH + /// @notice Transfers the given amount of WETH from the given address to the given address. + /// @param src The address to transfer the WETH from. + /// @param dst The address to transfer the WETH to. + /// @param wad The amount of WETH to transfer. + /// @return True if the transfer was successful. function transferFrom(address src, address dst, uint256 wad) public returns (bool) { - require(balanceOf[src] >= wad); + require(_balanceOf[src] >= wad); - if (src != msg.sender && allowance[src][msg.sender] != type(uint256).max) { - require(allowance[src][msg.sender] >= wad); - allowance[src][msg.sender] -= wad; + uint256 senderAllowance = allowance(src, msg.sender); + if (src != msg.sender && senderAllowance != type(uint256).max) { + require(senderAllowance >= wad); + _allowance[src][msg.sender] -= wad; } - balanceOf[src] -= wad; - balanceOf[dst] += wad; + _balanceOf[src] -= wad; + _balanceOf[dst] += wad; emit Transfer(src, dst, wad); diff --git a/packages/contracts-bedrock/src/universal/interfaces/ILegacyMintableERC20.sol b/packages/contracts-bedrock/src/universal/interfaces/ILegacyMintableERC20.sol new file mode 100644 index 0000000000000..ad518b8b4d774 --- /dev/null +++ b/packages/contracts-bedrock/src/universal/interfaces/ILegacyMintableERC20.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +/// @custom:legacy +/// @title ILegacyMintableERC20 +/// @notice This interface was available on the legacy L2StandardERC20 contract. +/// It remains available on the OptimismMintableERC20 contract for +/// backwards compatibility. + +interface ILegacyMintableERC20 is IERC165 { + function l1Token() external view returns (address); + + function mint(address _to, uint256 _amount) external; + + function burn(address _from, uint256 _amount) external; +} diff --git a/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC20.sol b/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC20.sol index b261902c72ee8..caf54b8073149 100644 --- a/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC20.sol +++ b/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC20.sol @@ -16,16 +16,3 @@ interface IOptimismMintableERC20 is IERC165 { function burn(address _from, uint256 _amount) external; } - -/// @custom:legacy -/// @title ILegacyMintableERC20 -/// @notice This interface was available on the legacy L2StandardERC20 contract. -/// It remains available on the OptimismMintableERC20 contract for -/// backwards compatibility. -interface ILegacyMintableERC20 is IERC165 { - function l1Token() external view returns (address); - - function mint(address _to, uint256 _amount) external; - - function burn(address _from, uint256 _amount) external; -} diff --git a/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC721.sol b/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC721.sol index 0f9133d7dc676..7d745ad8436e6 100644 --- a/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC721.sol +++ b/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC721.sol @@ -1,48 +1,74 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import { IERC721Enumerable } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol"; - /// @title IOptimismMintableERC721 /// @notice Interface for contracts that are compatible with the OptimismMintableERC721 standard. /// Tokens that follow this standard can be easily transferred across the ERC721 bridge. -interface IOptimismMintableERC721 is IERC721Enumerable { - /// @notice Emitted when a token is minted. - /// @param account Address of the account the token was minted to. - /// @param tokenId Token ID of the minted token. - event Mint(address indexed account, uint256 tokenId); +interface IOptimismMintableERC721 { + function __constructor__( + address _bridge, + uint256 _remoteChainId, + address _remoteToken, + string memory _name, + string memory _symbol + ) + external; - /// @notice Emitted when a token is burned. - /// @param account Address of the account the token was burned from. - /// @param tokenId Token ID of the burned token. + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event Burn(address indexed account, uint256 tokenId); + event Mint(address indexed account, uint256 tokenId); + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + function totalSupply() external view returns (uint256); + + function approve(address to, uint256 tokenId) external; + + function isApprovedForAll(address owner, address operator) external view returns (bool); + + function symbol() external view returns (string memory); + + function tokenByIndex(uint256 index) external view returns (uint256); + + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); + + function transferFrom(address from, address to, uint256 tokenId) external; + + function balanceOf(address owner) external view returns (uint256); + + function baseTokenURI() external view returns (string memory); + + function getApproved(uint256 tokenId) external view returns (address); + + function name() external view returns (string memory); + + function ownerOf(uint256 tokenId) external view returns (address); + + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) external; + + function setApprovalForAll(address operator, bool approved) external; + + function supportsInterface(bytes4 _interfaceId) external view returns (bool); + + function tokenURI(uint256 tokenId) external view returns (string memory); + + function version() external view returns (string memory); - /// @notice Mints some token ID for a user, checking first that contract recipients - /// are aware of the ERC721 protocol to prevent tokens from being forever locked. - /// @param _to Address of the user to mint the token for. - /// @param _tokenId Token ID to mint. function safeMint(address _to, uint256 _tokenId) external; - /// @notice Burns a token ID from a user. - /// @param _from Address of the user to burn the token from. - /// @param _tokenId Token ID to burn. function burn(address _from, uint256 _tokenId) external; - /// @notice Chain ID of the chain where the remote token is deployed. function REMOTE_CHAIN_ID() external view returns (uint256); - /// @notice Address of the token on the remote domain. function REMOTE_TOKEN() external view returns (address); - /// @notice Address of the ERC721 bridge on this network. function BRIDGE() external view returns (address); - /// @notice Chain ID of the chain where the remote token is deployed. function remoteChainId() external view returns (uint256); - /// @notice Address of the token on the remote domain. function remoteToken() external view returns (address); - /// @notice Address of the ERC721 bridge on this network. function bridge() external view returns (address); } diff --git a/packages/contracts-bedrock/src/universal/interfaces/IWETH.sol b/packages/contracts-bedrock/src/universal/interfaces/IWETH.sol deleted file mode 100644 index 73ef0e9545776..0000000000000 --- a/packages/contracts-bedrock/src/universal/interfaces/IWETH.sol +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -/// @title IWETH -/// @notice Interface for WETH9. -interface IWETH { - /// @notice Emitted when an approval is made. - /// @param src The address that approved the transfer. - /// @param guy The address that was approved to transfer. - /// @param wad The amount that was approved to transfer. - event Approval(address indexed src, address indexed guy, uint256 wad); - - /// @notice Emitted when a transfer is made. - /// @param src The address that transferred the WETH. - /// @param dst The address that received the WETH. - /// @param wad The amount of WETH that was transferred. - event Transfer(address indexed src, address indexed dst, uint256 wad); - - /// @notice Emitted when a deposit is made. - /// @param dst The address that deposited the WETH. - /// @param wad The amount of WETH that was deposited. - event Deposit(address indexed dst, uint256 wad); - - /// @notice Emitted when a withdrawal is made. - /// @param src The address that withdrew the WETH. - /// @param wad The amount of WETH that was withdrawn. - event Withdrawal(address indexed src, uint256 wad); - - /// @notice Returns the name of the token. - /// @return The name of the token. - function name() external view returns (string memory); - - /// @notice Returns the symbol of the token. - /// @return The symbol of the token. - function symbol() external view returns (string memory); - - /// @notice Returns the number of decimals the token uses. - /// @return The number of decimals the token uses. - function decimals() external pure returns (uint8); - - /// @notice Returns the balance of the given address. - /// @param owner The address to query the balance of. - /// @return The balance of the given address. - function balanceOf(address owner) external view returns (uint256); - - /// @notice Returns the amount of WETH that the spender can transfer on behalf of the owner. - /// @param owner The address that owns the WETH. - /// @param spender The address that is approved to transfer the WETH. - /// @return The amount of WETH that the spender can transfer on behalf of the owner. - function allowance(address owner, address spender) external view returns (uint256); - - /// @notice Allows WETH to be deposited by sending ether to the contract. - function deposit() external payable; - - /// @notice Withdraws an amount of ETH. - /// @param wad The amount of ETH to withdraw. - function withdraw(uint256 wad) external; - - /// @notice Returns the total supply of WETH. - /// @return The total supply of WETH. - function totalSupply() external view returns (uint256); - - /// @notice Approves the given address to transfer the WETH on behalf of the caller. - /// @param guy The address that is approved to transfer the WETH. - /// @param wad The amount that is approved to transfer. - /// @return True if the approval was successful. - function approve(address guy, uint256 wad) external returns (bool); - - /// @notice Transfers the given amount of WETH to the given address. - /// @param dst The address to transfer the WETH to. - /// @param wad The amount of WETH to transfer. - /// @return True if the transfer was successful. - function transfer(address dst, uint256 wad) external returns (bool); - - /// @notice Transfers the given amount of WETH from the given address to the given address. - /// @param src The address to transfer the WETH from. - /// @param dst The address to transfer the WETH to. - /// @param wad The amount of WETH to transfer. - /// @return True if the transfer was successful. - function transferFrom(address src, address dst, uint256 wad) external returns (bool); -} diff --git a/packages/contracts-bedrock/src/universal/interfaces/IWETH98.sol b/packages/contracts-bedrock/src/universal/interfaces/IWETH98.sol new file mode 100644 index 0000000000000..c7a77b7a36cd5 --- /dev/null +++ b/packages/contracts-bedrock/src/universal/interfaces/IWETH98.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title IWETH +/// @notice Interface for WETH9. +interface IWETH98 { + receive() external payable; + fallback() external payable; + + event Approval(address indexed src, address indexed guy, uint256 wad); + + event Transfer(address indexed src, address indexed dst, uint256 wad); + + event Deposit(address indexed dst, uint256 wad); + + event Withdrawal(address indexed src, uint256 wad); + + function name() external view returns (string memory); + + function symbol() external view returns (string memory); + + function decimals() external view returns (uint8); + + function balanceOf(address src) external view returns (uint256); + + function allowance(address owner, address spender) external view returns (uint256); + + function deposit() external payable; + + function withdraw(uint256 wad) external; + + function totalSupply() external view returns (uint256); + + function approve(address guy, uint256 wad) external returns (bool); + + function transfer(address dst, uint256 wad) external returns (bool); + + function transferFrom(address src, address dst, uint256 wad) external returns (bool); + + function __constructor__() external; +} diff --git a/packages/contracts-bedrock/test/L1/DataAvailabilityChallenge.t.sol b/packages/contracts-bedrock/test/L1/DataAvailabilityChallenge.t.sol index dd14b349c68ab..a2ab917a0d2b2 100644 --- a/packages/contracts-bedrock/test/L1/DataAvailabilityChallenge.t.sol +++ b/packages/contracts-bedrock/test/L1/DataAvailabilityChallenge.t.sol @@ -17,20 +17,20 @@ contract DataAvailabilityChallengeTest is CommonTest { super.setUp(); } - function testDeposit() public { + function test_deposit_succeeds() public { assertEq(dataAvailabilityChallenge.balances(address(this)), 0); dataAvailabilityChallenge.deposit{ value: 1000 }(); assertEq(dataAvailabilityChallenge.balances(address(this)), 1000); } - function testReceive() public { + function test_receive_succeeds() public { assertEq(dataAvailabilityChallenge.balances(address(this)), 0); (bool success,) = payable(address(dataAvailabilityChallenge)).call{ value: 1000 }(""); assertTrue(success); assertEq(dataAvailabilityChallenge.balances(address(this)), 1000); } - function testWithdraw(address sender, uint256 amount) public { + function test_withdraw_succeeds(address sender, uint256 amount) public { assumePayable(sender); assumeNotPrecompile(sender); // EntryPoint will revert if using amount > type(uint112).max. @@ -52,7 +52,33 @@ contract DataAvailabilityChallengeTest is CommonTest { assertEq(sender.balance, amount); } - function testChallengeSuccess(address challenger, uint256 challengedBlockNumber, bytes calldata preImage) public { + function test_withdraw_fails_reverts(address sender, uint256 amount) public { + assumePayable(sender); + assumeNotPrecompile(sender); + // EntryPoint will revert if using amount > type(uint112).max. + vm.assume(sender != Preinstalls.EntryPoint_v060); + vm.assume(sender != address(dataAvailabilityChallenge)); + vm.assume(sender.balance == 0); + vm.deal(sender, amount); + + vm.prank(sender); + dataAvailabilityChallenge.deposit{ value: amount }(); + + assertEq(dataAvailabilityChallenge.balances(sender), amount); + assertEq(sender.balance, 0); + + vm.etch(sender, hex"fe"); + vm.expectRevert(abi.encodeWithSelector(IDataAvailabilityChallenge.WithdrawalFailed.selector)); + dataAvailabilityChallenge.withdraw(); + } + + function test_challenge_succeeds( + address challenger, + uint256 challengedBlockNumber, + bytes calldata preImage + ) + public + { bytes memory challengedCommitment = computeCommitmentKeccak256(preImage); // Assume the challenger is not the 0 address @@ -99,7 +125,13 @@ contract DataAvailabilityChallengeTest is CommonTest { assertEq(dataAvailabilityChallenge.balances(challenger), 0); } - function testChallengeDeposit(address challenger, uint256 challengedBlockNumber, bytes memory preImage) public { + function test_challenge_deposit_succeeds( + address challenger, + uint256 challengedBlockNumber, + bytes memory preImage + ) + public + { bytes memory challengedCommitment = computeCommitmentKeccak256(preImage); // Assume the challenger is not the 0 address @@ -142,7 +174,7 @@ contract DataAvailabilityChallengeTest is CommonTest { assertEq(dataAvailabilityChallenge.balances(challenger), 0); } - function testChallengeFailBondTooLow() public { + function test_challenge_bondTooLow_reverts() public { uint256 requiredBond = dataAvailabilityChallenge.bondSize(); uint256 actualBond = requiredBond - 1; dataAvailabilityChallenge.deposit{ value: actualBond }(); @@ -153,7 +185,7 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.challenge(0, computeCommitmentKeccak256("some hash")); } - function testChallengeFailChallengeExists() public { + function test_challenge_challengeExists_reverts() public { // Move to a block after the hash to challenge vm.roll(2); @@ -176,7 +208,7 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.challenge(0, computeCommitmentKeccak256("some other hash")); } - function testChallengeFailBeforeChallengeWindow() public { + function test_challenge_beforeChallengeWindow_reverts() public { uint256 challengedBlockNumber = 1; bytes memory challengedCommitment = computeCommitmentKeccak256("some hash"); @@ -189,7 +221,7 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.challenge(challengedBlockNumber, challengedCommitment); } - function testChallengeFailAfterChallengeWindow() public { + function test_challenge_afterChallengeWindow_reverts() public { uint256 challengedBlockNumber = 1; bytes memory challengedCommitment = computeCommitmentKeccak256("some hash"); @@ -202,12 +234,13 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.challenge(challengedBlockNumber, challengedCommitment); } - function testResolveSuccess( + function test_resolve_succeeds( address challenger, address resolver, bytes memory preImage, uint256 challengedBlockNumber, uint256 resolverRefundPercentage, + uint64 bondSize, uint128 txGasPrice ) public @@ -217,6 +250,9 @@ contract DataAvailabilityChallengeTest is CommonTest { vm.assume(resolver != address(0)); vm.assume(challenger != resolver); + vm.prank(dataAvailabilityChallenge.owner()); + dataAvailabilityChallenge.setBondSize(bondSize); + // Bound the resolver refund percentage to 100 resolverRefundPercentage = bound(resolverRefundPercentage, 0, 100); @@ -239,7 +275,6 @@ contract DataAvailabilityChallengeTest is CommonTest { vm.roll(challengedBlockNumber + 1); // Challenge the hash - uint256 bondSize = dataAvailabilityChallenge.bondSize(); vm.deal(challenger, bondSize); vm.prank(challenger); dataAvailabilityChallenge.challenge{ value: bondSize }(challengedBlockNumber, challengedCommitment); @@ -247,6 +282,26 @@ contract DataAvailabilityChallengeTest is CommonTest { // Store the address(0) balance before resolving to assert the burned amount later uint256 zeroAddressBalanceBeforeResolve = address(0).balance; + // Assert challenger balance after bond distribution + uint256 resolutionCost = ( + dataAvailabilityChallenge.fixedResolutionCost() + + preImage.length * dataAvailabilityChallenge.variableResolutionCost() + / dataAvailabilityChallenge.variableResolutionCostPrecision() + ) * block.basefee; + uint256 challengerRefund = bondSize > resolutionCost ? bondSize - resolutionCost : 0; + uint256 resolverRefund = resolutionCost * dataAvailabilityChallenge.resolverRefundPercentage() / 100; + resolverRefund = resolverRefund > resolutionCost ? resolutionCost : resolverRefund; + resolverRefund = resolverRefund > bondSize ? bondSize : resolverRefund; + + if (challengerRefund > 0) { + vm.expectEmit(true, true, true, true); + emit BalanceChanged(challenger, challengerRefund); + } + if (resolverRefund > 0) { + vm.expectEmit(true, true, true, true); + emit BalanceChanged(resolver, resolverRefund); + } + // Resolve the challenge vm.prank(resolver); dataAvailabilityChallenge.resolve(challengedBlockNumber, challengedCommitment, preImage); @@ -262,28 +317,73 @@ contract DataAvailabilityChallengeTest is CommonTest { uint8(dataAvailabilityChallenge.getChallengeStatus(challengedBlockNumber, challengedCommitment)), uint8(ChallengeStatus.Resolved) ); - - // Assert challenger balance after bond distribution - uint256 resolutionCost = ( - dataAvailabilityChallenge.fixedResolutionCost() - + preImage.length * dataAvailabilityChallenge.variableResolutionCost() - / dataAvailabilityChallenge.variableResolutionCostPrecision() - ) * block.basefee; - uint256 challengerRefund = bondSize > resolutionCost ? bondSize - resolutionCost : 0; - assertEq(dataAvailabilityChallenge.balances(challenger), challengerRefund, "challenger refund"); - - // Assert resolver balance after bond distribution - uint256 resolverRefund = resolutionCost * dataAvailabilityChallenge.resolverRefundPercentage() / 100; - resolverRefund = resolverRefund > resolutionCost ? resolutionCost : resolverRefund; - resolverRefund = resolverRefund > bondSize ? bondSize : resolverRefund; - assertEq(dataAvailabilityChallenge.balances(resolver), resolverRefund, "resolver refund"); + address _challenger = challenger; + address _resolver = resolver; + assertEq(dataAvailabilityChallenge.balances(_challenger), challengerRefund, "challenger refund"); + assertEq(dataAvailabilityChallenge.balances(_resolver), resolverRefund, "resolver refund"); // Assert burned amount after bond distribution uint256 burned = bondSize - challengerRefund - resolverRefund; assertEq(address(0).balance - zeroAddressBalanceBeforeResolve, burned, "burned bond"); } - function testResolveFailNonExistentChallenge() public { + function test_resolve_invalidInputData_reverts( + address challenger, + address resolver, + bytes memory preImage, + bytes memory wrongPreImage, + uint256 challengedBlockNumber, + uint256 resolverRefundPercentage, + uint128 txGasPrice + ) + public + { + // Assume neither the challenger nor resolver is address(0) and that they're not the same entity + vm.assume(challenger != address(0)); + vm.assume(resolver != address(0)); + vm.assume(challenger != resolver); + vm.assume(keccak256(preImage) != keccak256(wrongPreImage)); + + // Bound the resolver refund percentage to 100 + resolverRefundPercentage = bound(resolverRefundPercentage, 0, 100); + + // Set the gas price to a fuzzed value to test bond distribution logic + vm.txGasPrice(txGasPrice); + + // Change the resolver refund percentage + vm.prank(dataAvailabilityChallenge.owner()); + dataAvailabilityChallenge.setResolverRefundPercentage(resolverRefundPercentage); + + // Assume the block number is not close to the max uint256 value + vm.assume( + challengedBlockNumber + < type(uint256).max - dataAvailabilityChallenge.challengeWindow() + - dataAvailabilityChallenge.resolveWindow() + ); + bytes memory challengedCommitment = computeCommitmentKeccak256(wrongPreImage); + + // Move to block after challenged block + vm.roll(challengedBlockNumber + 1); + + // Challenge the hash + uint256 bondSize = dataAvailabilityChallenge.bondSize(); + vm.deal(challenger, bondSize); + vm.prank(challenger); + dataAvailabilityChallenge.challenge{ value: bondSize }(challengedBlockNumber, challengedCommitment); + + // Resolve the challenge + vm.prank(resolver); + vm.expectRevert( + abi.encodeWithSelector( + IDataAvailabilityChallenge.InvalidInputData.selector, + computeCommitmentKeccak256(preImage), + challengedCommitment + ) + ); + dataAvailabilityChallenge.resolve(challengedBlockNumber, challengedCommitment, preImage); + } + + function test_resolve_nonExistentChallenge_reverts() public { bytes memory preImage = "some preimage"; uint256 challengedBlockNumber = 1; @@ -295,7 +395,7 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.resolve(challengedBlockNumber, computeCommitmentKeccak256(preImage), preImage); } - function testResolveFailResolved() public { + function test_resolve_resolved_reverts() public { bytes memory preImage = "some preimage"; bytes memory challengedCommitment = computeCommitmentKeccak256(preImage); uint256 challengedBlockNumber = 1; @@ -315,7 +415,7 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.resolve(challengedBlockNumber, challengedCommitment, preImage); } - function testResolveFailExpired() public { + function test_resolve_expired_reverts() public { bytes memory preImage = "some preimage"; bytes memory challengedCommitment = computeCommitmentKeccak256(preImage); uint256 challengedBlockNumber = 1; @@ -335,7 +435,7 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.resolve(challengedBlockNumber, challengedCommitment, preImage); } - function testResolveFailAfterResolveWindow() public { + function test_resolve_afterResolveWindow_reverts() public { bytes memory preImage = "some preimage"; bytes memory challengedCommitment = computeCommitmentKeccak256(preImage); uint256 challengedBlockNumber = 1; @@ -355,7 +455,7 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.resolve(challengedBlockNumber, challengedCommitment, preImage); } - function testUnlockBondSuccess(bytes memory preImage, uint256 challengedBlockNumber) public { + function test_unlockBond_succeeds(bytes memory preImage, uint256 challengedBlockNumber) public { // Assume the block number is not close to the max uint256 value vm.assume( challengedBlockNumber @@ -400,7 +500,7 @@ contract DataAvailabilityChallengeTest is CommonTest { assertEq(dataAvailabilityChallenge.balances(address(this)), balanceAfterUnlock); } - function testUnlockBondFailNonExistentChallenge() public { + function test_unlockBond_nonExistentChallenge_reverts() public { bytes memory preImage = "some preimage"; bytes memory challengedCommitment = computeCommitmentKeccak256(preImage); uint256 challengedBlockNumber = 1; @@ -413,7 +513,7 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.unlockBond(challengedBlockNumber, challengedCommitment); } - function testUnlockBondFailResolvedChallenge() public { + function test_unlockBond_resolvedChallenge_reverts() public { bytes memory preImage = "some preimage"; bytes memory challengedCommitment = computeCommitmentKeccak256(preImage); uint256 challengedBlockNumber = 1; @@ -433,7 +533,7 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.unlockBond(challengedBlockNumber, challengedCommitment); } - function testUnlockBondExpiredChallengeTwice() public { + function test_unlockBond_expiredChallengeTwice_fails() public { bytes memory preImage = "some preimage"; bytes memory challengedCommitment = computeCommitmentKeccak256(preImage); uint256 challengedBlockNumber = 1; @@ -458,7 +558,7 @@ contract DataAvailabilityChallengeTest is CommonTest { assertEq(dataAvailabilityChallenge.balances(address(this)), balanceAfterUnlock); } - function testUnlockFailResolveWindowNotClosed() public { + function test_unlockBond_resolveWindowNotClosed_reverts() public { bytes memory preImage = "some preimage"; bytes memory challengedCommitment = computeCommitmentKeccak256(preImage); uint256 challengedBlockNumber = 1; @@ -477,7 +577,7 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.unlockBond(challengedBlockNumber, challengedCommitment); } - function testSetBondSize() public { + function test_setBondSize_succeeds() public { uint256 requiredBond = dataAvailabilityChallenge.bondSize(); uint256 actualBond = requiredBond - 1; dataAvailabilityChallenge.deposit{ value: actualBond }(); @@ -497,14 +597,14 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.challenge(0, challengedCommitment); } - function testSetResolverRefundPercentage(uint256 resolverRefundPercentage) public { + function test_setResolverRefundPercentage_succeeds(uint256 resolverRefundPercentage) public { resolverRefundPercentage = bound(resolverRefundPercentage, 0, 100); vm.prank(dataAvailabilityChallenge.owner()); dataAvailabilityChallenge.setResolverRefundPercentage(resolverRefundPercentage); assertEq(dataAvailabilityChallenge.resolverRefundPercentage(), resolverRefundPercentage); } - function testSetResolverRefundPercentageFail() public { + function test_setResolverRefundPercentage_invalidResolverRefundPercentage_reverts() public { address owner = dataAvailabilityChallenge.owner(); vm.expectRevert( abi.encodeWithSelector(IDataAvailabilityChallenge.InvalidResolverRefundPercentage.selector, 101) @@ -513,7 +613,7 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.setResolverRefundPercentage(101); } - function testSetBondSizeFailOnlyOwner(address notOwner, uint256 newBondSize) public { + function test_setBondSize_onlyOwner_reverts(address notOwner, uint256 newBondSize) public { vm.assume(notOwner != dataAvailabilityChallenge.owner()); // Expect setting the bond size to fail because the sender is not the owner @@ -522,7 +622,7 @@ contract DataAvailabilityChallengeTest is CommonTest { dataAvailabilityChallenge.setBondSize(newBondSize); } - function testValidateCommitment() public { + function test_validateCommitment_succeeds() public { // Should not revert given a valid commitment bytes memory validCommitment = abi.encodePacked(CommitmentType.Keccak256, keccak256("test")); dataAvailabilityChallenge.validateCommitment(validCommitment); diff --git a/packages/contracts-bedrock/test/L1/DelayedVetoable.t.sol b/packages/contracts-bedrock/test/L1/DelayedVetoable.t.sol deleted file mode 100644 index 4d33a0784972a..0000000000000 --- a/packages/contracts-bedrock/test/L1/DelayedVetoable.t.sol +++ /dev/null @@ -1,264 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import { Test } from "forge-std/Test.sol"; -import { DelayedVetoable } from "src/L1/DelayedVetoable.sol"; -import { IDelayedVetoable } from "src/L1/interfaces/IDelayedVetoable.sol"; - -contract DelayedVetoable_Init is Test { - error Unauthorized(address expected, address actual); - error ForwardingEarly(); - - event Initiated(bytes32 indexed callHash, bytes data); - event Forwarded(bytes32 indexed callHash, bytes data); - event Vetoed(bytes32 indexed callHash, bytes data); - - address target; - address initiator; - address vetoer; - uint256 operatingDelay = 14 days; - IDelayedVetoable delayedVetoable; - - function setUp() public { - initiator = makeAddr("initiator"); - vetoer = makeAddr("vetoer"); - target = makeAddr("target"); - vm.deal(initiator, 10000 ether); - vm.deal(vetoer, 10000 ether); - - delayedVetoable = IDelayedVetoable( - address( - new DelayedVetoable({ - _initiator: initiator, - _vetoer: vetoer, - _target: address(target), - _operatingDelay: operatingDelay - }) - ) - ); - - // Most tests will use the operating delay, so we call as the initiator with null data - // to set the delay. For tests that need to use the initial zero delay, we'll modify the - // value in storage. - vm.prank(initiator); - (bool success,) = address(delayedVetoable).call(hex""); - assertTrue(success); - } - - /// @dev This function is used to prevent initiating the delay unintentionally. - /// It should only be used on tests prior to the delay being activated. - /// @param data The data to be used in the call. - function assumeNonzeroData(bytes memory data) internal pure { - vm.assume(data.length > 0); - } - - /// @dev This function is used to ensure that the data does not clash with the queuedAt function selector. - /// @param data The data to be used in the call. - function assumeNoClash(bytes calldata data) internal pure { - if (data.length >= 4) { - vm.assume(bytes4(data[0:4]) != bytes4(keccak256("queuedAt(bytes32)"))); - } - } -} - -contract DelayedVetoable_Getters_Test is DelayedVetoable_Init { - /// @dev The getters return the expected values when called by the zero address. - function test_getters() external { - vm.startPrank(address(0)); - assertEq(delayedVetoable.initiator(), initiator); - assertEq(delayedVetoable.vetoer(), vetoer); - assertEq(delayedVetoable.target(), target); - assertEq(delayedVetoable.delay(), operatingDelay); - assertEq(delayedVetoable.queuedAt(keccak256(abi.encode(0))), 0); - } -} - -contract DelayedVetoable_Getters_TestFail is DelayedVetoable_Init { - /// @dev Check that getter calls from unauthorized entities will revert. - function test_getters_notZeroAddress_reverts() external { - vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, initiator, address(this))); - delayedVetoable.initiator(); - vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, initiator, address(this))); - delayedVetoable.vetoer(); - vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, initiator, address(this))); - delayedVetoable.target(); - vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, initiator, address(this))); - delayedVetoable.delay(); - vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, initiator, address(this))); - delayedVetoable.queuedAt(keccak256(abi.encode(0))); - } -} - -contract DelayedVetoable_HandleCall_Test is DelayedVetoable_Init { - /// @dev A call can be initiated by the initiator. - function testFuzz_handleCall_initiation_succeeds(bytes calldata data) external { - assumeNoClash(data); - vm.expectEmit(true, false, false, true, address(delayedVetoable)); - emit Initiated(keccak256(data), data); - - vm.prank(initiator); - (bool success,) = address(delayedVetoable).call(data); - assertTrue(success); - } - - /// @dev The delay is inititially set to zero and the call is immediately forwarded. - function testFuzz_handleCall_initialForwardingImmediately_succeeds( - bytes calldata inData, - bytes calldata outData - ) - external - { - assumeNonzeroData(inData); - assumeNoClash(inData); - - // Reset the delay to zero - vm.store(address(delayedVetoable), bytes32(uint256(0)), bytes32(uint256(0))); - - vm.mockCall(target, inData, outData); - vm.expectEmit(true, false, false, true, address(delayedVetoable)); - vm.expectCall({ callee: target, data: inData }); - emit Forwarded(keccak256(inData), inData); - vm.prank(initiator); - (bool success, bytes memory returnData) = address(delayedVetoable).call(inData); - assertTrue(success); - assertEq(returnData, outData); - - // Check that the callHash is not stored for future forwarding - bytes32 callHash = keccak256(inData); - vm.prank(address(0)); - assertEq(delayedVetoable.queuedAt(callHash), 0); - } - - /// @dev Calls are not forwarded until the delay has passed. - function testFuzz_handleCall_forwardingWithDelay_succeeds(bytes calldata data) external { - assumeNonzeroData(data); - assumeNoClash(data); - - vm.prank(initiator); - (bool success,) = address(delayedVetoable).call(data); - - // Check that the call is in the _queuedAt mapping - bytes32 callHash = keccak256(data); - vm.prank(address(0)); - assertEq(delayedVetoable.queuedAt(callHash), block.timestamp); - - vm.warp(block.timestamp + operatingDelay); - vm.expectEmit(true, false, false, true, address(delayedVetoable)); - emit Forwarded(keccak256(data), data); - - vm.expectCall({ callee: target, data: data }); - (success,) = address(delayedVetoable).call(data); - assertTrue(success); - } -} - -contract DelayedVetoable_HandleCall_TestFail is DelayedVetoable_Init { - /// @dev Only the initiator can initiate a call. - function test_handleCall_unauthorizedInitiation_reverts() external { - vm.expectRevert(abi.encodeWithSelector(DelayedVetoable.Unauthorized.selector, initiator, address(this))); - (bool revertsAsExpected,) = address(delayedVetoable).call(hex"00001234"); - assertTrue(revertsAsExpected); - } - - /// @dev The call cannot be forwarded until the delay has passed. - function testFuzz_handleCall_forwardingTooSoon_reverts(bytes calldata data) external { - assumeNoClash(data); - vm.prank(initiator); - (bool success,) = address(delayedVetoable).call(data); - assertTrue(success); - - vm.expectRevert(DelayedVetoable.ForwardingEarly.selector); - (bool revertsAsExpected,) = address(delayedVetoable).call(data); - assertTrue(revertsAsExpected); - } - - /// @dev The call cannot be forwarded a second time. - function testFuzz_handleCall_forwardingTwice_reverts(bytes calldata data) external { - assumeNoClash(data); - - // Initiate the call - vm.prank(initiator); - (bool success,) = address(delayedVetoable).call(data); - assertTrue(success); - - vm.warp(block.timestamp + operatingDelay); - vm.expectEmit(true, false, false, true, address(delayedVetoable)); - emit Forwarded(keccak256(data), data); - - // Forward the call - vm.expectCall({ callee: target, data: data }); - (success,) = address(delayedVetoable).call(data); - assertTrue(success); - - // Attempt to forward the same call again. - vm.expectRevert(abi.encodeWithSelector(DelayedVetoable.Unauthorized.selector, initiator, address(this))); - (bool revertsAsExpected,) = address(delayedVetoable).call(data); - assertTrue(revertsAsExpected); - } - - /// @dev If the target reverts, it is bubbled up. - function testFuzz_handleCall_forwardingTargetReverts_reverts( - bytes calldata inData, - bytes calldata outData - ) - external - { - assumeNoClash(inData); - - // Initiate the call - vm.prank(initiator); - (bool success,) = address(delayedVetoable).call(inData); - assertTrue(success); - - vm.warp(block.timestamp + operatingDelay); - vm.expectEmit(true, false, false, true, address(delayedVetoable)); - emit Forwarded(keccak256(inData), inData); - - vm.mockCallRevert(target, inData, outData); - - // Forward the call - vm.expectRevert(outData); - (bool revertsAsExpected,) = address(delayedVetoable).call(inData); - assertTrue(revertsAsExpected); - } - - function testFuzz_handleCall_forwardingTargetRetValue_succeeds( - bytes calldata inData, - bytes calldata outData - ) - external - { - assumeNoClash(inData); - - // Initiate the call - vm.prank(initiator); - (bool success,) = address(delayedVetoable).call(inData); - assertTrue(success); - - vm.warp(block.timestamp + operatingDelay); - vm.expectEmit(true, false, false, true, address(delayedVetoable)); - emit Forwarded(keccak256(inData), inData); - - vm.mockCall(target, inData, outData); - - // Forward the call - (bool success2, bytes memory retData) = address(delayedVetoable).call(inData); - assertTrue(success2); - assertEq(keccak256(retData), keccak256(outData)); - } - - /// @dev A test documenting the single instance in which the contract is not 'transparent' to the initiator. - function testFuzz_handleCall_queuedAtClash_reverts() external { - // This will get us calldata with the same function selector as the queuedAt function, but - // with the incorrect input data length. - bytes memory inData = abi.encodePacked(keccak256("queuedAt(bytes32)")); - - // Reset the delay to zero - vm.store(address(delayedVetoable), bytes32(uint256(0)), bytes32(uint256(0))); - - vm.prank(initiator); - vm.expectRevert(bytes("")); - (bool revertsAsExpected,) = address(delayedVetoable).call(inData); - assertTrue(revertsAsExpected); - } -} diff --git a/packages/contracts-bedrock/test/L1/L1CrossDomainMessenger.t.sol b/packages/contracts-bedrock/test/L1/L1CrossDomainMessenger.t.sol index 2c6b5b66456d3..22345d860e423 100644 --- a/packages/contracts-bedrock/test/L1/L1CrossDomainMessenger.t.sol +++ b/packages/contracts-bedrock/test/L1/L1CrossDomainMessenger.t.sol @@ -2,8 +2,9 @@ pragma solidity 0.8.15; // Testing utilities -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; import { Reverter } from "test/mocks/Callers.sol"; +import { stdError } from "forge-std/StdError.sol"; // Libraries import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; @@ -17,7 +18,7 @@ import { IOptimismPortal } from "src/L1/interfaces/IOptimismPortal.sol"; import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; -contract L1CrossDomainMessenger_Test is Bridge_Initializer { +contract L1CrossDomainMessenger_Test is CommonTest { /// @dev The receiver address address recipient = address(0xabbaacdc); @@ -58,14 +59,16 @@ contract L1CrossDomainMessenger_Test is Bridge_Initializer { // deposit transaction on the optimism portal should be called vm.expectCall( address(optimismPortal), - abi.encodeWithSelector( - IOptimismPortal.depositTransaction.selector, - Predeploys.L2_CROSS_DOMAIN_MESSENGER, - 0, - l1CrossDomainMessenger.baseGas(hex"ff", 100), - false, - Encoding.encodeCrossDomainMessage( - l1CrossDomainMessenger.messageNonce(), alice, recipient, 0, 100, hex"ff" + abi.encodeCall( + IOptimismPortal.depositTransaction, + ( + Predeploys.L2_CROSS_DOMAIN_MESSENGER, + 0, + l1CrossDomainMessenger.baseGas(hex"ff", 100), + false, + Encoding.encodeCrossDomainMessage( + l1CrossDomainMessenger.messageNonce(), alice, recipient, 0, 100, hex"ff" + ) ) ) ); @@ -171,21 +174,93 @@ contract L1CrossDomainMessenger_Test is Bridge_Initializer { assertEq(l1CrossDomainMessenger.failedMessages(hash), false); } - /// @dev Tests that relayMessage reverts if attempting to relay a message - /// sent to an L1 system contract. - function test_relayMessage_toSystemContract_reverts() external { - // set the target to be the OptimismPortal - address target = address(optimismPortal); + /// @dev Tests that relayMessage reverts if caller is optimismPortal and the value sent does not match the amount + function test_relayMessage_fromOtherMessengerValueMismatch_reverts() external { + address target = alice; address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; bytes memory message = hex"1111"; + // set the value of op.l2Sender() to be the L2CrossDomainMessenger. + vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); + + // correctly sending as OptimismPortal but amount does not match msg.value + vm.deal(address(optimismPortal), 10 ether); + vm.prank(address(optimismPortal)); + vm.expectRevert(stdError.assertionError); + l1CrossDomainMessenger.relayMessage{ value: 10 ether }( + Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, 9 ether, 0, message + ); + } + + /// @dev Tests that relayMessage reverts if a failed message is attempted to be replayed via the optimismPortal + function test_relayMessage_fromOtherMessengerFailedMessageReplay_reverts() external { + address target = alice; + address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; + bytes memory message = hex"1111"; + + // set the value of op.l2Sender() to be the L2 Cross Domain Messenger. + vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); + + // make a failed message + vm.etch(target, hex"fe"); vm.prank(address(optimismPortal)); - vm.expectRevert("CrossDomainMessenger: message cannot be replayed"); l1CrossDomainMessenger.relayMessage( Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, 0, 0, message ); - vm.store(address(optimismPortal), 0, bytes32(abi.encode(sender))); + // cannot replay messages when optimism portal is msg.sender + vm.prank(address(optimismPortal)); + vm.expectRevert(stdError.assertionError); + l1CrossDomainMessenger.relayMessage( + Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, 0, 0, message + ); + } + + /// @dev Tests that relayMessage reverts if attempting to relay a message + /// with l1CrossDomainMessenger as the target + function test_relayMessage_toSelf_reverts() external { + address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; + bytes memory message = hex"1111"; + + vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); + + vm.prank(address(optimismPortal)); + vm.expectRevert("CrossDomainMessenger: cannot send message to blocked system address"); + l1CrossDomainMessenger.relayMessage( + Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), + sender, + address(l1CrossDomainMessenger), + 0, + 0, + message + ); + } + + /// @dev Tests that relayMessage reverts if attempting to relay a message + /// with optimismPortal as the target + function test_relayMessage_toOptimismPortal_reverts() external { + address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; + bytes memory message = hex"1111"; + + vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); + + vm.prank(address(optimismPortal)); + vm.expectRevert("CrossDomainMessenger: cannot send message to blocked system address"); + l1CrossDomainMessenger.relayMessage( + Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, address(optimismPortal), 0, 0, message + ); + } + + /// @dev Tests that the relayMessage function reverts if the message called by non-optimismPortal but not a failed + /// message + function test_relayMessage_relayingNewMessageByExternalUser_reverts() external { + address target = address(alice); + address sender = Predeploys.L2_CROSS_DOMAIN_MESSENGER; + bytes memory message = hex"1111"; + + vm.store(address(optimismPortal), bytes32(senderSlotIndex), bytes32(abi.encode(sender))); + + vm.prank(bob); vm.expectRevert("CrossDomainMessenger: message cannot be replayed"); l1CrossDomainMessenger.relayMessage( Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, 0, 0, message @@ -604,7 +679,7 @@ contract L1CrossDomainMessenger_Test is Bridge_Initializer { /// @dev Tests that the superchain config is called by the messengers paused function function test_pause_callsSuperchainConfig_succeeds() external { - vm.expectCall(address(superchainConfig), abi.encodeWithSelector(ISuperchainConfig.paused.selector)); + vm.expectCall(address(superchainConfig), abi.encodeCall(ISuperchainConfig.paused, ())); l1CrossDomainMessenger.paused(); } @@ -621,23 +696,25 @@ contract L1CrossDomainMessenger_Test is Bridge_Initializer { } /// @dev Tests that sendMessage succeeds with a custom gas token when the call value is zero. - function test_sendMessage_customGasToken_noValue_succeeds() external { + function test_sendMessage_customGasTokenButNoValue_succeeds() external { // Mock the gasPayingToken function to return a custom gas token vm.mockCall( - address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(18)) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(18)) ); // deposit transaction on the optimism portal should be called vm.expectCall( address(optimismPortal), - abi.encodeWithSelector( - IOptimismPortal.depositTransaction.selector, - Predeploys.L2_CROSS_DOMAIN_MESSENGER, - 0, - l1CrossDomainMessenger.baseGas(hex"ff", 100), - false, - Encoding.encodeCrossDomainMessage( - l1CrossDomainMessenger.messageNonce(), alice, recipient, 0, 100, hex"ff" + abi.encodeCall( + IOptimismPortal.depositTransaction, + ( + Predeploys.L2_CROSS_DOMAIN_MESSENGER, + 0, + l1CrossDomainMessenger.baseGas(hex"ff", 100), + false, + Encoding.encodeCrossDomainMessage( + l1CrossDomainMessenger.messageNonce(), alice, recipient, 0, 100, hex"ff" + ) ) ) ); @@ -667,10 +744,10 @@ contract L1CrossDomainMessenger_Test is Bridge_Initializer { } /// @dev Tests that the sendMessage reverts when call value is non-zero with custom gas token. - function test_sendMessage_customGasToken_withValue_reverts() external { + function test_sendMessage_customGasTokenWithValue_reverts() external { // Mock the gasPayingToken function to return a custom gas token vm.mockCall( - address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2)) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) ); vm.expectRevert("CrossDomainMessenger: cannot send value with custom gas token"); @@ -678,10 +755,10 @@ contract L1CrossDomainMessenger_Test is Bridge_Initializer { } /// @dev Tests that the relayMessage succeeds with a custom gas token when the call value is zero. - function test_relayMessage_customGasToken_noValue_succeeds() external { + function test_relayMessage_customGasTokenAndNoValue_succeeds() external { // Mock the gasPayingToken function to return a custom gas token vm.mockCall( - address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2)) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) ); address target = address(0xabcd); @@ -718,10 +795,10 @@ contract L1CrossDomainMessenger_Test is Bridge_Initializer { /// @dev Tests that the relayMessage reverts when call value is non-zero with custom gas token. /// The L2CrossDomainMessenger contract cannot `sendMessage` with value when using a custom gas token. - function test_relayMessage_customGasToken_withValue_reverts() external virtual { + function test_relayMessage_customGasTokenWithValue_reverts() external virtual { // Mock the gasPayingToken function to return a custom gas token vm.mockCall( - address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2)) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) ); vm.expectRevert("CrossDomainMessenger: value must be zero unless message is from a system address"); @@ -738,12 +815,12 @@ contract L1CrossDomainMessenger_Test is Bridge_Initializer { /// @dev A regression test against a reentrancy vulnerability in the CrossDomainMessenger contract, which /// was possible by intercepting and sandwhiching a signed Safe Transaction to upgrade it. -contract L1CrossDomainMessenger_ReinitReentryTest is Bridge_Initializer { +contract L1CrossDomainMessenger_ReinitReentryTest is CommonTest { bool attacked; // Common values used across functions uint256 constant messageValue = 50; - bytes constant selector = abi.encodeWithSelector(this.reinitAndReenter.selector); + bytes selector = abi.encodeCall(this.reinitAndReenter, ()); address sender; bytes32 hash; address target; @@ -760,7 +837,7 @@ contract L1CrossDomainMessenger_ReinitReentryTest is Bridge_Initializer { /// @dev This method will be called by the relayed message, and will attempt to reenter the relayMessage function /// exactly once. - function reinitAndReenter() public payable { + function reinitAndReenter() external payable { // only attempt the attack once if (!attacked) { attacked = true; diff --git a/packages/contracts-bedrock/test/L1/L1ERC721Bridge.t.sol b/packages/contracts-bedrock/test/L1/L1ERC721Bridge.t.sol index 44feddc5031d4..fd9d0d89b0f18 100644 --- a/packages/contracts-bedrock/test/L1/L1ERC721Bridge.t.sol +++ b/packages/contracts-bedrock/test/L1/L1ERC721Bridge.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; // Testing -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Contracts import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; @@ -25,7 +25,7 @@ contract TestERC721 is ERC721 { } } -contract L1ERC721Bridge_Test is Bridge_Initializer { +contract L1ERC721Bridge_Test is CommonTest { TestERC721 internal localToken; TestERC721 internal remoteToken; uint256 internal constant tokenId = 1; @@ -237,6 +237,14 @@ contract L1ERC721Bridge_Test is Bridge_Initializer { assertEq(localToken.ownerOf(tokenId), alice); } + /// @dev Tests that `bridgeERC721To` reverts if the to address is the zero address. + function test_bridgeERC721To_toZeroAddress_reverts() external { + // Bridge the token. + vm.prank(bob); + vm.expectRevert("ERC721Bridge: nft recipient cannot be address(0)"); + l1ERC721Bridge.bridgeERC721To(address(localToken), address(remoteToken), address(0), tokenId, 1234, hex"5678"); + } + /// @dev Tests that the ERC721 bridge successfully finalizes a withdrawal. function test_finalizeBridgeERC721_succeeds() external { // Bridge the token. @@ -250,7 +258,7 @@ contract L1ERC721Bridge_Test is Bridge_Initializer { // Finalize a withdrawal. vm.mockCall( address(l1CrossDomainMessenger), - abi.encodeWithSelector(l1CrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(l1CrossDomainMessenger.xDomainMessageSender, ()), abi.encode(Predeploys.L2_ERC721_BRIDGE) ); vm.prank(address(l1CrossDomainMessenger)); @@ -276,7 +284,7 @@ contract L1ERC721Bridge_Test is Bridge_Initializer { // Finalize a withdrawal. vm.mockCall( address(l1CrossDomainMessenger), - abi.encodeWithSelector(l1CrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(l1CrossDomainMessenger.xDomainMessageSender, ()), abi.encode(alice) ); vm.prank(address(l1CrossDomainMessenger)); @@ -290,7 +298,7 @@ contract L1ERC721Bridge_Test is Bridge_Initializer { // Finalize a withdrawal. vm.mockCall( address(l1CrossDomainMessenger), - abi.encodeWithSelector(l1CrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(l1CrossDomainMessenger.xDomainMessageSender, ()), abi.encode(Predeploys.L2_ERC721_BRIDGE) ); vm.prank(address(l1CrossDomainMessenger)); @@ -306,7 +314,7 @@ contract L1ERC721Bridge_Test is Bridge_Initializer { // Finalize a withdrawal. vm.mockCall( address(l1CrossDomainMessenger), - abi.encodeWithSelector(l1CrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(l1CrossDomainMessenger.xDomainMessageSender, ()), abi.encode(Predeploys.L2_ERC721_BRIDGE) ); vm.prank(address(l1CrossDomainMessenger)); @@ -315,7 +323,7 @@ contract L1ERC721Bridge_Test is Bridge_Initializer { } } -contract L1ERC721Bridge_Pause_Test is Bridge_Initializer { +contract L1ERC721Bridge_Pause_Test is CommonTest { /// @dev Verifies that the `paused` accessor returns the same value as the `paused` function of the /// `superchainConfig`. function test_paused_succeeds() external view { @@ -325,7 +333,7 @@ contract L1ERC721Bridge_Pause_Test is Bridge_Initializer { /// @dev Ensures that the `paused` function of the bridge contract actually calls the `paused` function of the /// `superchainConfig`. function test_pause_callsSuperchainConfig_succeeds() external { - vm.expectCall(address(superchainConfig), abi.encodeWithSelector(ISuperchainConfig.paused.selector)); + vm.expectCall(address(superchainConfig), abi.encodeCall(ISuperchainConfig.paused, ())); l1ERC721Bridge.paused(); } @@ -343,7 +351,7 @@ contract L1ERC721Bridge_Pause_Test is Bridge_Initializer { } } -contract L1ERC721Bridge_Pause_TestFail is Bridge_Initializer { +contract L1ERC721Bridge_Pause_TestFail is CommonTest { /// @dev Sets up the test by pausing the bridge, giving ether to the bridge and mocking /// the calls to the xDomainMessageSender so that it returns the correct value. function setUp() public override { @@ -354,7 +362,7 @@ contract L1ERC721Bridge_Pause_TestFail is Bridge_Initializer { vm.mockCall( address(l1ERC721Bridge.messenger()), - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1ERC721Bridge.otherBridge())) ); } diff --git a/packages/contracts-bedrock/test/L1/L1StandardBridge.t.sol b/packages/contracts-bedrock/test/L1/L1StandardBridge.t.sol index f01572733bc4d..97ef01262ab67 100644 --- a/packages/contracts-bedrock/test/L1/L1StandardBridge.t.sol +++ b/packages/contracts-bedrock/test/L1/L1StandardBridge.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.15; // Testing import { stdStorage, StdStorage } from "forge-std/Test.sol"; -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Contracts import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; @@ -19,7 +19,7 @@ import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; import { IOptimismPortal } from "src/L1/interfaces/IOptimismPortal.sol"; import { IL1StandardBridge } from "src/L1/interfaces/IL1StandardBridge.sol"; -contract L1StandardBridge_Getter_Test is Bridge_Initializer { +contract L1StandardBridge_Getter_Test is CommonTest { /// @dev Test that the accessors return the correct initialized values. function test_getters_succeeds() external view { assert(l1StandardBridge.l2TokenBridge() == address(l2StandardBridge)); @@ -31,7 +31,7 @@ contract L1StandardBridge_Getter_Test is Bridge_Initializer { } } -contract L1StandardBridge_Initialize_Test is Bridge_Initializer { +contract L1StandardBridge_Initialize_Test is CommonTest { /// @dev Test that the constructor sets the correct values. /// @notice Marked virtual to be overridden in /// test/kontrol/deployment/DeploymentSummary.t.sol @@ -58,7 +58,7 @@ contract L1StandardBridge_Initialize_Test is Bridge_Initializer { } } -contract L1StandardBridge_Pause_Test is Bridge_Initializer { +contract L1StandardBridge_Pause_Test is CommonTest { /// @dev Verifies that the `paused` accessor returns the same value as the `paused` function of the /// `superchainConfig`. function test_paused_succeeds() external view { @@ -68,7 +68,7 @@ contract L1StandardBridge_Pause_Test is Bridge_Initializer { /// @dev Ensures that the `paused` function of the bridge contract actually calls the `paused` function of the /// `superchainConfig`. function test_pause_callsSuperchainConfig_succeeds() external { - vm.expectCall(address(superchainConfig), abi.encodeWithSelector(ISuperchainConfig.paused.selector)); + vm.expectCall(address(superchainConfig), abi.encodeCall(ISuperchainConfig.paused, ())); l1StandardBridge.paused(); } @@ -86,7 +86,7 @@ contract L1StandardBridge_Pause_Test is Bridge_Initializer { } } -contract L1StandardBridge_Pause_TestFail is Bridge_Initializer { +contract L1StandardBridge_Pause_TestFail is CommonTest { /// @dev Sets up the test by pausing the bridge, giving ether to the bridge and mocking /// the calls to the xDomainMessageSender so that it returns the correct value. function setUp() public override { @@ -99,7 +99,7 @@ contract L1StandardBridge_Pause_TestFail is Bridge_Initializer { vm.mockCall( address(l1StandardBridge.messenger()), - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1StandardBridge.otherBridge())) ); } @@ -157,9 +157,9 @@ contract L1StandardBridge_Pause_TestFail is Bridge_Initializer { } } -contract L1StandardBridge_Initialize_TestFail is Bridge_Initializer { } +contract L1StandardBridge_Initialize_TestFail is CommonTest { } -contract L1StandardBridge_Receive_Test is Bridge_Initializer { +contract L1StandardBridge_Receive_Test is CommonTest { /// @dev Tests receive bridges ETH successfully. function test_receive_succeeds() external { assertEq(address(optimismPortal).balance, 0); @@ -173,11 +173,13 @@ contract L1StandardBridge_Receive_Test is Bridge_Initializer { vm.expectCall( address(l1CrossDomainMessenger), - abi.encodeWithSelector( - ICrossDomainMessenger.sendMessage.selector, - address(l2StandardBridge), - abi.encodeWithSelector(StandardBridge.finalizeBridgeETH.selector, alice, alice, 100, hex""), - 200_000 + abi.encodeCall( + ICrossDomainMessenger.sendMessage, + ( + address(l2StandardBridge), + abi.encodeCall(StandardBridge.finalizeBridgeETH, (alice, alice, 100, hex"")), + 200_000 + ) ) ); @@ -188,12 +190,12 @@ contract L1StandardBridge_Receive_Test is Bridge_Initializer { } } -contract L1StandardBridge_Receive_TestFail is Bridge_Initializer { +contract L1StandardBridge_Receive_TestFail is CommonTest { /// @dev Tests receive function reverts with custom gas token. function testFuzz_receive_customGasToken_reverts(uint256 _value) external { vm.prank(alice, alice); vm.mockCall( - address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(18)) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(18)) ); vm.deal(alice, _value); (bool success, bytes memory data) = address(l1StandardBridge).call{ value: _value }(hex""); @@ -205,7 +207,7 @@ contract L1StandardBridge_Receive_TestFail is Bridge_Initializer { } } -contract PreBridgeETH is Bridge_Initializer { +contract PreBridgeETH is CommonTest { /// @dev Asserts the expected calls and events for bridging ETH depending /// on whether the bridge call is legacy or not. function _preBridgeETH(bool isLegacy, uint256 value) internal { @@ -214,51 +216,35 @@ contract PreBridgeETH is Bridge_Initializer { uint256 version = 0; // Internal constant in the OptimismPortal: DEPOSIT_VERSION address l1MessengerAliased = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)); - bytes memory message = - abi.encodeWithSelector(StandardBridge.finalizeBridgeETH.selector, alice, alice, value, hex"dead"); + bytes memory message = abi.encodeCall(StandardBridge.finalizeBridgeETH, (alice, alice, value, hex"dead")); if (isLegacy) { vm.expectCall( - address(l1StandardBridge), - value, - abi.encodeWithSelector(l1StandardBridge.depositETH.selector, 50000, hex"dead") + address(l1StandardBridge), value, abi.encodeCall(l1StandardBridge.depositETH, (50000, hex"dead")) ); } else { vm.expectCall( - address(l1StandardBridge), - value, - abi.encodeWithSelector(l1StandardBridge.bridgeETH.selector, 50000, hex"dead") + address(l1StandardBridge), value, abi.encodeCall(l1StandardBridge.bridgeETH, (50000, hex"dead")) ); } vm.expectCall( address(l1CrossDomainMessenger), value, - abi.encodeWithSelector( - ICrossDomainMessenger.sendMessage.selector, address(l2StandardBridge), message, 50000 - ) + abi.encodeCall(ICrossDomainMessenger.sendMessage, (address(l2StandardBridge), message, 50000)) ); - bytes memory innerMessage = abi.encodeWithSelector( - ICrossDomainMessenger.relayMessage.selector, - nonce, - address(l1StandardBridge), - address(l2StandardBridge), - value, - 50000, - message + bytes memory innerMessage = abi.encodeCall( + ICrossDomainMessenger.relayMessage, + (nonce, address(l1StandardBridge), address(l2StandardBridge), value, 50000, message) ); uint64 baseGas = l1CrossDomainMessenger.baseGas(message, 50000); vm.expectCall( address(optimismPortal), value, - abi.encodeWithSelector( - IOptimismPortal.depositTransaction.selector, - address(l2CrossDomainMessenger), - value, - baseGas, - false, - innerMessage + abi.encodeCall( + IOptimismPortal.depositTransaction, + (address(l2CrossDomainMessenger), value, baseGas, false, innerMessage) ) ); @@ -299,7 +285,7 @@ contract L1StandardBridge_DepositETH_Test is PreBridgeETH { } } -contract L1StandardBridge_DepositETH_TestFail is Bridge_Initializer { +contract L1StandardBridge_DepositETH_TestFail is CommonTest { /// @dev Tests that depositing ETH reverts if the call is not from an EOA. function test_depositETH_notEoa_reverts() external { vm.etch(alice, address(L1Token).code); @@ -311,7 +297,7 @@ contract L1StandardBridge_DepositETH_TestFail is Bridge_Initializer { /// @dev Tests that depositing reverts with custom gas token. function test_depositETH_customGasToken_reverts() external { vm.mockCall( - address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2)) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) ); vm.prank(alice, alice); vm.expectRevert("StandardBridge: cannot bridge ETH with custom gas token"); @@ -337,7 +323,7 @@ contract L1StandardBridge_BridgeETH_TestFail is PreBridgeETH { function test_bridgeETH_customGasToken_reverts() external { vm.prank(alice, alice); vm.mockCall( - address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2)) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) ); vm.expectRevert("StandardBridge: cannot bridge ETH with custom gas token"); @@ -345,7 +331,7 @@ contract L1StandardBridge_BridgeETH_TestFail is PreBridgeETH { } } -contract PreBridgeETHTo is Bridge_Initializer { +contract PreBridgeETHTo is CommonTest { /// @dev Asserts the expected calls and events for bridging ETH to a different /// address depending on whether the bridge call is legacy or not. function _preBridgeETHTo(bool isLegacy, uint256 value) internal { @@ -356,50 +342,34 @@ contract PreBridgeETHTo is Bridge_Initializer { if (isLegacy) { vm.expectCall( - address(l1StandardBridge), - value, - abi.encodeWithSelector(l1StandardBridge.depositETHTo.selector, bob, 60000, hex"dead") + address(l1StandardBridge), value, abi.encodeCall(l1StandardBridge.depositETHTo, (bob, 60000, hex"dead")) ); } else { vm.expectCall( - address(l1StandardBridge), - value, - abi.encodeWithSelector(l1StandardBridge.bridgeETHTo.selector, bob, 60000, hex"dead") + address(l1StandardBridge), value, abi.encodeCall(l1StandardBridge.bridgeETHTo, (bob, 60000, hex"dead")) ); } - bytes memory message = - abi.encodeWithSelector(StandardBridge.finalizeBridgeETH.selector, alice, bob, value, hex"dead"); + bytes memory message = abi.encodeCall(StandardBridge.finalizeBridgeETH, (alice, bob, value, hex"dead")); // the L1 bridge should call // L1CrossDomainMessenger.sendMessage vm.expectCall( address(l1CrossDomainMessenger), - abi.encodeWithSelector( - ICrossDomainMessenger.sendMessage.selector, address(l2StandardBridge), message, 60000 - ) + abi.encodeCall(ICrossDomainMessenger.sendMessage, (address(l2StandardBridge), message, 60000)) ); - bytes memory innerMessage = abi.encodeWithSelector( - ICrossDomainMessenger.relayMessage.selector, - nonce, - address(l1StandardBridge), - address(l2StandardBridge), - value, - 60000, - message + bytes memory innerMessage = abi.encodeCall( + ICrossDomainMessenger.relayMessage, + (nonce, address(l1StandardBridge), address(l2StandardBridge), value, 60000, message) ); uint64 baseGas = l1CrossDomainMessenger.baseGas(message, 60000); vm.expectCall( address(optimismPortal), - abi.encodeWithSelector( - IOptimismPortal.depositTransaction.selector, - address(l2CrossDomainMessenger), - value, - baseGas, - false, - innerMessage + abi.encodeCall( + IOptimismPortal.depositTransaction, + (address(l2CrossDomainMessenger), value, baseGas, false, innerMessage) ) ); @@ -441,7 +411,7 @@ contract L1StandardBridge_DepositETHTo_Test is PreBridgeETHTo { } } -contract L1StandardBridge_DepositETHTo_TestFail is Bridge_Initializer { +contract L1StandardBridge_DepositETHTo_TestFail is CommonTest { /// @dev Tests that depositETHTo reverts with custom gas token. function testFuzz_depositETHTo_customGasToken_reverts( uint256 _value, @@ -452,7 +422,7 @@ contract L1StandardBridge_DepositETHTo_TestFail is Bridge_Initializer { external { vm.mockCall( - address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2)) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) ); vm.deal(address(this), _value); vm.expectRevert("StandardBridge: cannot bridge ETH with custom gas token"); @@ -484,7 +454,7 @@ contract L1StandardBridge_BridgeETHTo_TestFail is PreBridgeETHTo { external { vm.mockCall( - address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2)) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) ); vm.deal(address(this), _value); vm.expectRevert("StandardBridge: cannot bridge ETH with custom gas token"); @@ -493,7 +463,7 @@ contract L1StandardBridge_BridgeETHTo_TestFail is PreBridgeETHTo { } } -contract L1StandardBridge_DepositERC20_Test is Bridge_Initializer { +contract L1StandardBridge_DepositERC20_Test is CommonTest { using stdStorage for StdStorage; // depositERC20 @@ -518,42 +488,28 @@ contract L1StandardBridge_DepositERC20_Test is Bridge_Initializer { L1Token.approve(address(l1StandardBridge), type(uint256).max); // The l1StandardBridge should transfer alice's tokens to itself - vm.expectCall( - address(L1Token), abi.encodeWithSelector(ERC20.transferFrom.selector, alice, address(l1StandardBridge), 100) - ); + vm.expectCall(address(L1Token), abi.encodeCall(ERC20.transferFrom, (alice, address(l1StandardBridge), 100))); - bytes memory message = abi.encodeWithSelector( - StandardBridge.finalizeBridgeERC20.selector, address(L2Token), address(L1Token), alice, alice, 100, hex"" + bytes memory message = abi.encodeCall( + StandardBridge.finalizeBridgeERC20, (address(L2Token), address(L1Token), alice, alice, 100, hex"") ); // the L1 bridge should call L1CrossDomainMessenger.sendMessage vm.expectCall( address(l1CrossDomainMessenger), - abi.encodeWithSelector( - ICrossDomainMessenger.sendMessage.selector, address(l2StandardBridge), message, 10000 - ) + abi.encodeCall(ICrossDomainMessenger.sendMessage, (address(l2StandardBridge), message, 10000)) ); - bytes memory innerMessage = abi.encodeWithSelector( - ICrossDomainMessenger.relayMessage.selector, - nonce, - address(l1StandardBridge), - address(l2StandardBridge), - 0, - 10000, - message + bytes memory innerMessage = abi.encodeCall( + ICrossDomainMessenger.relayMessage, + (nonce, address(l1StandardBridge), address(l2StandardBridge), 0, 10000, message) ); uint64 baseGas = l1CrossDomainMessenger.baseGas(message, 10000); vm.expectCall( address(optimismPortal), - abi.encodeWithSelector( - IOptimismPortal.depositTransaction.selector, - address(l2CrossDomainMessenger), - 0, - baseGas, - false, - innerMessage + abi.encodeCall( + IOptimismPortal.depositTransaction, (address(l2CrossDomainMessenger), 0, baseGas, false, innerMessage) ) ); @@ -584,7 +540,7 @@ contract L1StandardBridge_DepositERC20_Test is Bridge_Initializer { } } -contract L1StandardBridge_DepositERC20_TestFail is Bridge_Initializer { +contract L1StandardBridge_DepositERC20_TestFail is CommonTest { /// @dev Tests that depositing an ERC20 to the bridge reverts /// if the caller is not an EOA. function test_depositERC20_notEoa_reverts() external { @@ -597,7 +553,7 @@ contract L1StandardBridge_DepositERC20_TestFail is Bridge_Initializer { } } -contract L1StandardBridge_DepositERC20To_Test is Bridge_Initializer { +contract L1StandardBridge_DepositERC20To_Test is CommonTest { /// @dev Tests that depositing ERC20 to the bridge succeeds when /// sent to a different address. /// Bridge deposits are updated. @@ -609,18 +565,13 @@ contract L1StandardBridge_DepositERC20To_Test is Bridge_Initializer { uint256 version = 0; // Internal constant in the OptimismPortal: DEPOSIT_VERSION address l1MessengerAliased = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)); - bytes memory message = abi.encodeWithSelector( - StandardBridge.finalizeBridgeERC20.selector, address(L2Token), address(L1Token), alice, bob, 1000, hex"" + bytes memory message = abi.encodeCall( + StandardBridge.finalizeBridgeERC20, (address(L2Token), address(L1Token), alice, bob, 1000, hex"") ); - bytes memory innerMessage = abi.encodeWithSelector( - ICrossDomainMessenger.relayMessage.selector, - nonce, - address(l1StandardBridge), - address(l2StandardBridge), - 0, - 10000, - message + bytes memory innerMessage = abi.encodeCall( + ICrossDomainMessenger.relayMessage, + (nonce, address(l1StandardBridge), address(l2StandardBridge), 0, 10000, message) ); uint64 baseGas = l1CrossDomainMessenger.baseGas(message, 10000); @@ -653,26 +604,16 @@ contract L1StandardBridge_DepositERC20To_Test is Bridge_Initializer { // the L1 bridge should call L1CrossDomainMessenger.sendMessage vm.expectCall( address(l1CrossDomainMessenger), - abi.encodeWithSelector( - ICrossDomainMessenger.sendMessage.selector, address(l2StandardBridge), message, 10000 - ) + abi.encodeCall(ICrossDomainMessenger.sendMessage, (address(l2StandardBridge), message, 10000)) ); // The L1 XDM should call OptimismPortal.depositTransaction vm.expectCall( address(optimismPortal), - abi.encodeWithSelector( - IOptimismPortal.depositTransaction.selector, - address(l2CrossDomainMessenger), - 0, - baseGas, - false, - innerMessage + abi.encodeCall( + IOptimismPortal.depositTransaction, (address(l2CrossDomainMessenger), 0, baseGas, false, innerMessage) ) ); - vm.expectCall( - address(L1Token), - abi.encodeWithSelector(ERC20.transferFrom.selector, alice, address(l1StandardBridge), 1000) - ); + vm.expectCall(address(L1Token), abi.encodeCall(ERC20.transferFrom, (alice, address(l1StandardBridge), 1000))); vm.prank(alice); l1StandardBridge.depositERC20To(address(L1Token), address(L2Token), bob, 1000, 10000, hex""); @@ -681,7 +622,7 @@ contract L1StandardBridge_DepositERC20To_Test is Bridge_Initializer { } } -contract L1StandardBridge_FinalizeETHWithdrawal_Test is Bridge_Initializer { +contract L1StandardBridge_FinalizeETHWithdrawal_Test is CommonTest { using stdStorage for StdStorage; /// @dev Tests that finalizing an ETH withdrawal succeeds. @@ -700,7 +641,7 @@ contract L1StandardBridge_FinalizeETHWithdrawal_Test is Bridge_Initializer { vm.mockCall( address(l1StandardBridge.messenger()), - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) ); // ensure that the messenger has ETH to call with @@ -713,7 +654,7 @@ contract L1StandardBridge_FinalizeETHWithdrawal_Test is Bridge_Initializer { } } -contract L1StandardBridge_FinalizeETHWithdrawal_TestFail is Bridge_Initializer { +contract L1StandardBridge_FinalizeETHWithdrawal_TestFail is CommonTest { /// @dev Tests that finalizeETHWithdrawal reverts with custom gas token. function testFuzz_finalizeETHWithdrawal_customGasToken_reverts( uint256 _value, @@ -722,11 +663,11 @@ contract L1StandardBridge_FinalizeETHWithdrawal_TestFail is Bridge_Initializer { external { vm.mockCall( - address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2)) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) ); vm.mockCall( address(l1StandardBridge.messenger()), - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) ); vm.deal(address(l1StandardBridge.messenger()), _value); @@ -737,7 +678,7 @@ contract L1StandardBridge_FinalizeETHWithdrawal_TestFail is Bridge_Initializer { } } -contract L1StandardBridge_FinalizeERC20Withdrawal_Test is Bridge_Initializer { +contract L1StandardBridge_FinalizeERC20Withdrawal_Test is CommonTest { using stdStorage for StdStorage; /// @dev Tests that finalizing an ERC20 withdrawal succeeds. @@ -761,11 +702,11 @@ contract L1StandardBridge_FinalizeERC20Withdrawal_Test is Bridge_Initializer { vm.expectEmit(address(l1StandardBridge)); emit ERC20BridgeFinalized(address(L1Token), address(L2Token), alice, alice, 100, hex""); - vm.expectCall(address(L1Token), abi.encodeWithSelector(ERC20.transfer.selector, alice, 100)); + vm.expectCall(address(L1Token), abi.encodeCall(ERC20.transfer, (alice, 100))); vm.mockCall( address(l1StandardBridge.messenger()), - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) ); vm.prank(address(l1StandardBridge.messenger())); @@ -776,12 +717,12 @@ contract L1StandardBridge_FinalizeERC20Withdrawal_Test is Bridge_Initializer { } } -contract L1StandardBridge_FinalizeERC20Withdrawal_TestFail is Bridge_Initializer { +contract L1StandardBridge_FinalizeERC20Withdrawal_TestFail is CommonTest { /// @dev Tests that finalizing an ERC20 withdrawal reverts if the caller is not the L2 bridge. function test_finalizeERC20Withdrawal_notMessenger_reverts() external { vm.mockCall( address(l1StandardBridge.messenger()), - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) ); vm.prank(address(28)); @@ -793,7 +734,7 @@ contract L1StandardBridge_FinalizeERC20Withdrawal_TestFail is Bridge_Initializer function test_finalizeERC20Withdrawal_notOtherBridge_reverts() external { vm.mockCall( address(l1StandardBridge.messenger()), - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(address(0))) ); vm.prank(address(l1StandardBridge.messenger())); @@ -802,13 +743,13 @@ contract L1StandardBridge_FinalizeERC20Withdrawal_TestFail is Bridge_Initializer } } -contract L1StandardBridge_FinalizeBridgeETH_Test is Bridge_Initializer { +contract L1StandardBridge_FinalizeBridgeETH_Test is CommonTest { /// @dev Tests that finalizing bridged ETH succeeds. function test_finalizeBridgeETH_succeeds() external { address messenger = address(l1StandardBridge.messenger()); vm.mockCall( messenger, - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) ); vm.deal(messenger, 100); @@ -821,18 +762,18 @@ contract L1StandardBridge_FinalizeBridgeETH_Test is Bridge_Initializer { } } -contract L1StandardBridge_FinalizeBridgeETH_TestFail is Bridge_Initializer { +contract L1StandardBridge_FinalizeBridgeETH_TestFail is CommonTest { /// @dev Tests that finalizing bridged reverts with custom gas token. function testFuzz_finalizeBridgeETH_customGasToken_reverts(uint256 _value, bytes calldata _extraData) external { vm.mockCall( address(l1StandardBridge.messenger()), - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) ); vm.deal(address(l1CrossDomainMessenger), _value); vm.prank(address(l1CrossDomainMessenger)); vm.mockCall( - address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2)) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) ); vm.expectRevert("StandardBridge: cannot bridge ETH with custom gas token"); @@ -844,7 +785,7 @@ contract L1StandardBridge_FinalizeBridgeETH_TestFail is Bridge_Initializer { address messenger = address(l1StandardBridge.messenger()); vm.mockCall( messenger, - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) ); vm.deal(messenger, 100); @@ -858,7 +799,7 @@ contract L1StandardBridge_FinalizeBridgeETH_TestFail is Bridge_Initializer { address messenger = address(l1StandardBridge.messenger()); vm.mockCall( messenger, - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) ); vm.deal(messenger, 100); @@ -872,7 +813,7 @@ contract L1StandardBridge_FinalizeBridgeETH_TestFail is Bridge_Initializer { address messenger = address(l1StandardBridge.messenger()); vm.mockCall( messenger, - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) ); vm.deal(messenger, 100); diff --git a/packages/contracts-bedrock/test/L1/L2OutputOracle.t.sol b/packages/contracts-bedrock/test/L1/L2OutputOracle.t.sol index 12e4ae4bf4016..490ae07c927d0 100644 --- a/packages/contracts-bedrock/test/L1/L2OutputOracle.t.sol +++ b/packages/contracts-bedrock/test/L1/L2OutputOracle.t.sol @@ -111,6 +111,10 @@ contract L2OutputOracle_getter_Test is L2OutputOracle_TestBase { // Querying with exact same block as proposed returns the proposal. uint256 index1 = l2OutputOracle.getL2OutputIndexAfter(nextBlockNumber1); assertEq(index1, 0); + assertEq( + keccak256(abi.encode(l2OutputOracle.getL2Output(index1))), + keccak256(abi.encode(output1, block.timestamp, nextBlockNumber1)) + ); } /// @dev Tests that `getL2OutputIndexAfter` returns the correct value @@ -125,6 +129,10 @@ contract L2OutputOracle_getter_Test is L2OutputOracle_TestBase { // Querying with previous block returns the proposal too. uint256 index1 = l2OutputOracle.getL2OutputIndexAfter(nextBlockNumber1 - 1); assertEq(index1, 0); + assertEq( + keccak256(abi.encode(l2OutputOracle.getL2Output(index1))), + keccak256(abi.encode(output1, block.timestamp, nextBlockNumber1)) + ); } /// @dev Tests that `getL2OutputIndexAfter` returns the correct value. @@ -156,14 +164,26 @@ contract L2OutputOracle_getter_Test is L2OutputOracle_TestBase { // Querying with a block number between the first and second proposal uint256 index1 = l2OutputOracle.getL2OutputIndexAfter(nextBlockNumber1 + 1); assertEq(index1, 1); + assertEq( + keccak256(abi.encode(l2OutputOracle.getL2Output(index1))), + keccak256(abi.encode(output2, l2OutputOracle.computeL2Timestamp(nextBlockNumber2) + 1, nextBlockNumber2)) + ); // Querying with a block number between the second and third proposal uint256 index2 = l2OutputOracle.getL2OutputIndexAfter(nextBlockNumber2 + 1); assertEq(index2, 2); + assertEq( + keccak256(abi.encode(l2OutputOracle.getL2Output(index2))), + keccak256(abi.encode(output3, l2OutputOracle.computeL2Timestamp(nextBlockNumber3) + 1, nextBlockNumber3)) + ); // Querying with a block number between the third and fourth proposal uint256 index3 = l2OutputOracle.getL2OutputIndexAfter(nextBlockNumber3 + 1); assertEq(index3, 3); + assertEq( + keccak256(abi.encode(l2OutputOracle.getL2Output(index3))), + keccak256(abi.encode(output4, l2OutputOracle.computeL2Timestamp(nextBlockNumber4) + 1, nextBlockNumber4)) + ); } /// @dev Tests that `getL2OutputIndexAfter` reverts when no output exists. @@ -422,7 +442,7 @@ contract L2OutputOracleUpgradeable_Test is L2OutputOracle_TestBase { vm.startPrank(EIP1967Helper.getAdmin(address(proxy))); // Reviewer note: the NextImpl() still uses reinitializer. If we want to remove that, we'll need to use a // two step upgrade with the Storage lib. - proxy.upgradeToAndCall(address(nextImpl), abi.encodeWithSelector(NextImpl.initialize.selector, 2)); + proxy.upgradeToAndCall(address(nextImpl), abi.encodeCall(NextImpl.initialize, (2))); assertEq(proxy.implementation(), address(nextImpl)); // Verify that the NextImpl contract initialized its values according as expected diff --git a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol index fb008d4aa8d0c..e828b415621e7 100644 --- a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol +++ b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.15; import { Test, stdStorage, StdStorage } from "forge-std/Test.sol"; -import { DeployOPChainInput } from "scripts/DeployOPChain.s.sol"; +import { DeployOPChainInput } from "scripts/deploy/DeployOPChain.s.sol"; import { DeployOPChain_TestBase } from "test/opcm/DeployOPChain.t.sol"; import { OPContractsManager } from "src/L1/OPContractsManager.sol"; @@ -14,9 +14,12 @@ import { IProtocolVersions } from "src/L1/interfaces/IProtocolVersions.sol"; contract OPContractsManager_Harness is OPContractsManager { constructor( ISuperchainConfig _superchainConfig, - IProtocolVersions _protocolVersions + IProtocolVersions _protocolVersions, + string memory _l1ContractsRelease, + Blueprints memory _blueprints, + Implementations memory _implementations ) - OPContractsManager(_superchainConfig, _protocolVersions) + OPContractsManager(_superchainConfig, _protocolVersions, _l1ContractsRelease, _blueprints, _implementations) { } function chainIdToBatchInboxAddress_exposed(uint256 l2ChainId) public pure returns (address) { @@ -49,7 +52,7 @@ contract OPContractsManager_Deploy_Test is DeployOPChain_TestBase { doi.set(doi.basefeeScalar.selector, basefeeScalar); doi.set(doi.blobBaseFeeScalar.selector, blobBaseFeeScalar); doi.set(doi.l2ChainId.selector, l2ChainId); - doi.set(doi.opcmProxy.selector, address(opcm)); + doi.set(doi.opcm.selector, address(opcm)); doi.set(doi.gasLimit.selector, gasLimit); doi.set(doi.disputeGameType.selector, disputeGameType); @@ -116,12 +119,17 @@ contract OPContractsManager_InternalMethods_Test is Test { function setUp() public { ISuperchainConfig superchainConfigProxy = ISuperchainConfig(makeAddr("superchainConfig")); IProtocolVersions protocolVersionsProxy = IProtocolVersions(makeAddr("protocolVersions")); + OPContractsManager.Blueprints memory emptyBlueprints; + OPContractsManager.Implementations memory emptyImpls; vm.etch(address(superchainConfigProxy), hex"01"); vm.etch(address(protocolVersionsProxy), hex"01"); opcmHarness = new OPContractsManager_Harness({ _superchainConfig: superchainConfigProxy, - _protocolVersions: protocolVersionsProxy + _protocolVersions: protocolVersionsProxy, + _l1ContractsRelease: "dev", + _blueprints: emptyBlueprints, + _implementations: emptyImpls }); } diff --git a/packages/contracts-bedrock/test/L1/OptimismPortal.t.sol b/packages/contracts-bedrock/test/L1/OptimismPortal.t.sol index 5ada092ad6b6e..f19e7ca6f5c29 100644 --- a/packages/contracts-bedrock/test/L1/OptimismPortal.t.sol +++ b/packages/contracts-bedrock/test/L1/OptimismPortal.t.sol @@ -201,6 +201,7 @@ contract OptimismPortal_Test is CommonTest { } /// @dev Tests that `depositTransaction` succeeds when msg.sender == tx.origin and non-custom gas is used. + /// forge-config: ciheavy.fuzz.runs = 8192 function testFuzz_depositTransaction_senderIsOrigin_succeeds( address _to, uint256 _mint, @@ -226,6 +227,7 @@ contract OptimismPortal_Test is CommonTest { } /// @dev Tests that `depositTransaction` succeeds when msg.sender != tx.origin and non-custom gas is used. + /// forge-config: ciheavy.fuzz.runs = 8192 function testFuzz_depositTransaction_senderNotOrigin_succeeds( address _to, uint256 _mint, @@ -308,6 +310,7 @@ contract OptimismPortal_Test is CommonTest { } /// @dev Tests that `depositTransaction` succeeds for an EOA. + /// forge-config: ciheavy.fuzz.runs = 8192 function testFuzz_depositTransaction_eoa_succeeds( address _to, uint64 _gasLimit, @@ -352,6 +355,7 @@ contract OptimismPortal_Test is CommonTest { } /// @dev Tests that `depositTransaction` succeeds for a contract. + /// forge-config: ciheavy.fuzz.runs = 8192 function testFuzz_depositTransaction_contract_succeeds( address _to, uint64 _gasLimit, @@ -403,7 +407,7 @@ contract OptimismPortal_Test is CommonTest { uint256 ts = block.timestamp; vm.mockCall( address(optimismPortal.l2Oracle()), - abi.encodeWithSelector(IL2OutputOracle.getL2Output.selector), + abi.encodePacked(IL2OutputOracle.getL2Output.selector), abi.encode(Types.OutputProposal(bytes32(uint256(1)), uint128(ts), uint128(startingBlockNumber))) ); @@ -535,7 +539,7 @@ contract OptimismPortal_Test is CommonTest { } function test_depositERC20Transaction_balanceOverflow_reverts() external { - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(42), 18)); + vm.mockCall(address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(42), 18)); // The balance slot vm.store(address(optimismPortal), bytes32(uint256(61)), bytes32(type(uint256).max)); @@ -594,7 +598,6 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { // Get withdrawal proof data we can use for testing. (_stateRoot, _storageRoot, _outputRoot, _withdrawalHash, _withdrawalProof) = ffi.getProveWithdrawalTransactionInputs(_defaultTx); - // Setup a dummy output root proof for reuse. _outputRootProof = Types.OutputRootProof({ version: bytes32(uint256(0)), @@ -602,6 +605,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { messagePasserStorageRoot: _storageRoot, latestBlockhash: bytes32(uint256(0)) }); + _proposedBlockNumber = l2OutputOracle.nextBlockNumber(); _proposedOutputIndex = l2OutputOracle.nextOutputIndex(); } @@ -769,7 +773,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { } /// @dev Tests that `finalizeWithdrawalTransaction` succeeds. - function test_finalizeWithdrawalTransaction_provenWithdrawalHash_ether_succeeds() external { + function test_finalizeWithdrawalTransaction_provenWithdrawalHashEther_succeeds() external { uint256 bobBalanceBefore = address(bob).balance; vm.expectEmit(true, true, true, true); @@ -785,10 +789,10 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { } /// @dev Tests that `finalizeWithdrawalTransaction` succeeds. - function test_finalizeWithdrawalTransaction_provenWithdrawalHash_nonEther_targetToken_reverts() external { + function test_finalizeWithdrawalTransaction_provenWithdrawalHashNonEtherTargetToken_reverts() external { vm.mockCall( address(systemConfig), - abi.encodeWithSignature("gasPayingToken()"), + abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(_defaultTx.target), 18) ); @@ -832,7 +836,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { // this case we just use bytes32(uint256(1)). vm.mockCall( address(optimismPortal.l2Oracle()), - abi.encodeWithSelector(IL2OutputOracle.getL2Output.selector), + abi.encodePacked(IL2OutputOracle.getL2Output.selector), abi.encode(bytes32(uint256(1)), _proposedBlockNumber) ); @@ -858,7 +862,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { // Mock a startingTimestamp change on the L2 Oracle vm.mockCall( address(optimismPortal.l2Oracle()), - abi.encodeWithSignature("startingTimestamp()"), + abi.encodeCall(IL2OutputOracle.startingTimestamp, ()), abi.encode(block.timestamp + 1) ); @@ -887,7 +891,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { // to finalize the withdrawal. vm.mockCall( address(optimismPortal.l2Oracle()), - abi.encodeWithSelector(IL2OutputOracle.getL2Output.selector), + abi.encodePacked(IL2OutputOracle.getL2Output.selector), abi.encode( Types.OutputProposal(bytes32(uint256(0)), uint128(block.timestamp), uint128(_proposedBlockNumber)) ) @@ -918,7 +922,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { // finalization period. vm.mockCall( address(optimismPortal.l2Oracle()), - abi.encodeWithSelector(IL2OutputOracle.getL2Output.selector), + abi.encodePacked(IL2OutputOracle.getL2Output.selector), abi.encode(Types.OutputProposal(_outputRoot, uint128(block.timestamp + 1), uint128(_proposedBlockNumber))) ); @@ -930,7 +934,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { assertEq(bobBalanceBefore, address(bob).balance); } - /// @dev Tests that `finalizeWithdrawalTransaction` reverts if the target reverts. + /// @dev Tests that `finalizeWithdrawalTransaction` fails if the target reverts. function test_finalizeWithdrawalTransaction_targetFails_fails() external { uint256 bobBalanceBefore = address(bob).balance; vm.etch(bob, hex"fe"); // Contract with just the invalid opcode. @@ -947,6 +951,77 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { assert(address(bob).balance == bobBalanceBefore); } + /// @dev Tests that `finalizeWithdrawalTransaction` reverts if the target reverts and caller is the + /// ESTIMATION_ADDRESS. + function test_finalizeWithdrawalTransaction_targetFailsAndCallerIsEstimationAddress_reverts() external { + vm.etch(bob, hex"fe"); // Contract with just the invalid opcode. + + vm.expectEmit(true, true, true, true); + emit WithdrawalProven(_withdrawalHash, alice, bob); + optimismPortal.proveWithdrawalTransaction(_defaultTx, _proposedOutputIndex, _outputRootProof, _withdrawalProof); + + vm.warp(block.timestamp + l2OutputOracle.FINALIZATION_PERIOD_SECONDS() + 1); + + vm.startPrank(Constants.ESTIMATION_ADDRESS, Constants.ESTIMATION_ADDRESS); + vm.expectRevert(GasEstimation.selector); + optimismPortal.finalizeWithdrawalTransaction(_defaultTx); + } + + /// @dev Tests that `finalizeWithdrawalTransaction` succeeds when _tx.data is empty. + function test_finalizeWithdrawalTransaction_noTxData_succeeds() external { + Types.WithdrawalTransaction memory _defaultTx_noData = Types.WithdrawalTransaction({ + nonce: 0, + sender: alice, + target: bob, + value: 100, + gasLimit: 100_000, + data: hex"" + }); + // Get withdrawal proof data we can use for testing. + ( + bytes32 _stateRoot_noData, + bytes32 _storageRoot_noData, + bytes32 _outputRoot_noData, + bytes32 _withdrawalHash_noData, + bytes[] memory _withdrawalProof_noData + ) = ffi.getProveWithdrawalTransactionInputs(_defaultTx_noData); + // Setup a dummy output root proof for reuse. + Types.OutputRootProof memory _outputRootProof_noData = Types.OutputRootProof({ + version: bytes32(uint256(0)), + stateRoot: _stateRoot_noData, + messagePasserStorageRoot: _storageRoot_noData, + latestBlockhash: bytes32(uint256(0)) + }); + + // Configure the oracle to return the output root we've prepared. + vm.mockCall( + address(l2OutputOracle), + abi.encodePacked(IL2OutputOracle.getL2Output.selector), + abi.encode( + Types.OutputProposal( + _outputRoot_noData, + l2OutputOracle.getL2Output(_proposedOutputIndex).timestamp, + uint128(_proposedBlockNumber) + ) + ) + ); + + uint256 bobBalanceBefore = address(bob).balance; + + vm.expectEmit(true, true, true, true); + emit WithdrawalProven(_withdrawalHash_noData, alice, bob); + optimismPortal.proveWithdrawalTransaction( + _defaultTx_noData, _proposedOutputIndex, _outputRootProof_noData, _withdrawalProof_noData + ); + + vm.warp(block.timestamp + l2OutputOracle.FINALIZATION_PERIOD_SECONDS() + 1); + vm.expectEmit(true, true, false, true); + emit WithdrawalFinalized(_withdrawalHash_noData, true); + optimismPortal.finalizeWithdrawalTransaction(_defaultTx_noData); + + assertEq(address(bob).balance, bobBalanceBefore + 100); + } + /// @dev Tests that `finalizeWithdrawalTransaction` reverts if the finalization period /// has not yet passed. function test_finalizeWithdrawalTransaction_onRecentWithdrawal_reverts() external { @@ -954,7 +1029,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { uint256 recentTimestamp = block.timestamp - 1; vm.mockCall( address(optimismPortal.l2Oracle()), - abi.encodeWithSelector(IL2OutputOracle.getL2Output.selector), + abi.encodePacked(IL2OutputOracle.getL2Output.selector), abi.encode(Types.OutputProposal(_outputRoot, uint128(recentTimestamp), uint128(_proposedBlockNumber))) ); @@ -1006,7 +1081,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { vm.mockCall( address(optimismPortal.l2Oracle()), - abi.encodeWithSelector(IL2OutputOracle.getL2Output.selector), + abi.encodePacked(IL2OutputOracle.getL2Output.selector), abi.encode( Types.OutputProposal( Hashing.hashOutputRootProof(outputRootProof), @@ -1034,7 +1109,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { // this contract's callPortalAndExpectRevert() function above. Types.WithdrawalTransaction memory _testTx = _defaultTx; _testTx.target = address(this); - _testTx.data = abi.encodeWithSelector(this.callPortalAndExpectRevert.selector); + _testTx.data = abi.encodeCall(this.callPortalAndExpectRevert, ()); // Get modified proof inputs. ( @@ -1055,7 +1130,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { uint256 finalizedTimestamp = block.timestamp - l2OutputOracle.FINALIZATION_PERIOD_SECONDS() - 1; vm.mockCall( address(optimismPortal.l2Oracle()), - abi.encodeWithSelector(IL2OutputOracle.getL2Output.selector), + abi.encodePacked(IL2OutputOracle.getL2Output.selector), abi.encode(Types.OutputProposal(outputRoot, uint128(finalizedTimestamp), uint128(_proposedBlockNumber))) ); @@ -1074,6 +1149,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { } /// @dev Tests that `finalizeWithdrawalTransaction` succeeds. + /// forge-config: ciheavy.fuzz.runs = 8192 function testDiff_finalizeWithdrawalTransaction_succeeds( address _sender, address _target, @@ -1129,7 +1205,7 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { // Setup the Oracle to return the outputRoot vm.mockCall( address(l2OutputOracle), - abi.encodeWithSelector(l2OutputOracle.getL2Output.selector), + abi.encodePacked(l2OutputOracle.getL2Output.selector), abi.encode(outputRoot, block.timestamp, 100) ); @@ -1176,7 +1252,7 @@ contract OptimismPortalUpgradeable_Test is CommonTest { // The value passed to the initialize must be larger than the last value // that initialize was called with. IProxy(payable(address(optimismPortal))).upgradeToAndCall( - address(nextImpl), abi.encodeWithSelector(NextImpl.initialize.selector, 2) + address(nextImpl), abi.encodeCall(NextImpl.initialize, (2)) ); assertEq(IProxy(payable(address(optimismPortal))).implementation(), address(nextImpl)); @@ -1196,6 +1272,7 @@ contract OptimismPortalResourceFuzz_Test is CommonTest { uint256 constant MAX_GAS_LIMIT = 30_000_000; /// @dev Test that various values of the resource metering config will not break deposits. + /// forge-config: ciheavy.fuzz.runs = 10000 function testFuzz_systemConfigDeposit_succeeds( uint32 _maxResourceLimit, uint8 _elasticityMultiplier, @@ -1249,9 +1326,7 @@ contract OptimismPortalResourceFuzz_Test is CommonTest { systemTxMaxGas: _systemTxMaxGas, maximumBaseFee: _maximumBaseFee }); - vm.mockCall( - address(systemConfig), abi.encodeWithSelector(systemConfig.resourceConfig.selector), abi.encode(rcfg) - ); + vm.mockCall(address(systemConfig), abi.encodeCall(systemConfig.resourceConfig, ()), abi.encode(rcfg)); // Set the resource params uint256 _prevBlockNum = block.number - _blockDiff; @@ -1309,7 +1384,9 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T token.approve(address(optimismPortal), _mint); // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); bytes memory opaqueData = abi.encodePacked(_mint, _value, _gasLimit, _isCreation, _data); @@ -1330,6 +1407,7 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T } /// @dev Tests that `depositERC20Transaction` succeeds when msg.sender == tx.origin. + /// forge-config: ciheavy.fuzz.runs = 8192 function testFuzz_depositERC20Transaction_senderIsOrigin_succeeds( address _to, uint256 _mint, @@ -1355,6 +1433,7 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T } /// @dev Tests that `depositERC20Transaction` succeeds when msg.sender != tx.origin. + /// forge-config: ciheavy.fuzz.runs = 8192 function testFuzz_depositERC20Transaction_senderNotOrigin_succeeds( address _to, uint256 _mint, @@ -1382,7 +1461,9 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T /// @dev Tests that `depositERC20Transaction` reverts when not enough of the token is approved. function test_depositERC20Transaction_notEnoughAmount_reverts() external { // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); vm.expectRevert(stdError.arithmeticError); // Deposit the token into the portal optimismPortal.depositERC20Transaction(address(0), 1, 0, 0, false, ""); @@ -1395,13 +1476,13 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T token.approve(address(optimismPortal), 100); // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); - - // Mock the token balance vm.mockCall( - address(token), abi.encodeWithSelector(token.balanceOf.selector, address(optimismPortal)), abi.encode(0) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) ); + // Mock the token balance + vm.mockCall(address(token), abi.encodeCall(token.balanceOf, (address(optimismPortal))), abi.encode(0)); + // Call minimumGasLimit(0) before vm.expectRevert to ensure vm.expectRevert is for depositERC20Transaction uint64 gasLimit = optimismPortal.minimumGasLimit(0); @@ -1414,7 +1495,9 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T /// @dev Tests that `depositERC20Transaction` reverts when creating a contract with a non-zero target. function test_depositERC20Transaction_isCreationNotZeroTarget_reverts() external { // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); // Call minimumGasLimit(0) before vm.expectRevert to ensure vm.expectRevert is for depositERC20Transaction uint64 gasLimit = optimismPortal.minimumGasLimit(0); @@ -1427,7 +1510,9 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T /// @dev Tests that `depositERC20Transaction` reverts when the gas limit is too low. function test_depositERC20Transaction_gasLimitTooLow_reverts() external { // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); vm.expectRevert(SmallGasLimit.selector); // Deposit the token into the portal @@ -1440,7 +1525,9 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T data[120_000] = 0x01; // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); uint64 gasLimit = optimismPortal.minimumGasLimit(120_001); vm.expectRevert(LargeCalldata.selector); @@ -1455,7 +1542,9 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T token.approve(address(optimismPortal), _amount); // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); // Deposit the token into the portal optimismPortal.depositERC20Transaction(address(0), _amount, 0, optimismPortal.minimumGasLimit(0), false, ""); @@ -1465,13 +1554,15 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T } /// @dev Tests that `finalizeWithdrawalTransaction` succeeds. - function test_finalizeWithdrawalTransaction_provenWithdrawalHash_nonEther_succeeds() external { + function test_finalizeWithdrawalTransaction_provenWithdrawalHashNonEther_succeeds() external { // Mint the token to the contract and approve the token for the portal token.mint(address(this), _defaultTx.value); token.approve(address(optimismPortal), _defaultTx.value); // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); // Deposit the token into the portal optimismPortal.depositERC20Transaction( @@ -1490,9 +1581,7 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T vm.expectCall(_defaultTx.target, 0, _defaultTx.data); - vm.expectCall( - address(token), 0, abi.encodeWithSelector(token.transfer.selector, _defaultTx.target, _defaultTx.value) - ); + vm.expectCall(address(token), 0, abi.encodeCall(token.transfer, (_defaultTx.target, _defaultTx.value))); optimismPortal.finalizeWithdrawalTransaction(_defaultTx); @@ -1520,7 +1609,9 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T uint64(bound(_gasLimit, optimismPortal.minimumGasLimit(uint64(_data.length)), rcfg.maxResourceLimit)); // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); bytes memory opaqueData = abi.encodePacked(uint256(0), _value, _gasLimit, _isCreation, _data); @@ -1541,7 +1632,8 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T } /// @dev Tests that `depositTransaction` succeeds when a custom gas token is used but the msg.value is zero. - function testFuzz_depositTransaction_customGasToken_noValue_senderIsOrigin_succeeds( + /// forge-config: ciheavy.fuzz.runs = 8192 + function testFuzz_depositTransaction_customGasTokenWithNoValueAndSenderIsOrigin_succeeds( address _to, uint256 _value, uint64 _gasLimit, @@ -1564,7 +1656,8 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T } /// @dev Tests that `depositTransaction` succeeds when a custom gas token is used but the msg.value is zero. - function testFuzz_depositTransaction_customGasToken_noValue_senderNotOrigin_succeeds( + /// forge-config: ciheavy.fuzz.runs = 8192 + function testFuzz_depositTransaction_customGasTokenWithNoValueAndSenderNotOrigin_succeeds( address _to, uint256 _value, uint64 _gasLimit, @@ -1587,9 +1680,11 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T } /// @dev Tests that `depositTransaction` fails when a custom gas token is used and msg.value is non-zero. - function test_depositTransaction_customGasToken_withValue_reverts() external { + function test_depositTransaction_customGasTokenWithValue_reverts() external { // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); vm.expectRevert(NoValue.selector); diff --git a/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol b/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol index dd37b61e9befb..d252609e5eea4 100644 --- a/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol +++ b/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol @@ -211,6 +211,7 @@ contract OptimismPortal2_Test is CommonTest { } /// @dev Tests that `depositTransaction` succeeds for an EOA. + /// forge-config: ciheavy.fuzz.runs = 8192 function testFuzz_depositTransaction_eoa_succeeds( address _to, uint64 _gasLimit, @@ -255,6 +256,7 @@ contract OptimismPortal2_Test is CommonTest { } /// @dev Tests that `depositTransaction` succeeds for a contract. + /// forge-config: ciheavy.fuzz.runs = 8192 function testFuzz_depositTransaction_contract_succeeds( address _to, uint64 _gasLimit, @@ -388,7 +390,7 @@ contract OptimismPortal2_Test is CommonTest { } function test_depositERC20Transaction_balanceOverflow_reverts() external { - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(42), 18)); + vm.mockCall(address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(42), 18)); // The balance slot vm.store(address(optimismPortal2), bytes32(uint256(61)), bytes32(type(uint256).max)); @@ -581,7 +583,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { /// @dev Tests that `proveWithdrawalTransaction` reverts when the withdrawal has already been proven, and the new /// game has the `CHALLENGER_WINS` status. - function test_proveWithdrawalTransaction_replayProve_differentGameChallengerWins_reverts() external { + function test_proveWithdrawalTransaction_replayProveDifferentGameChallengerWins_reverts() external { vm.expectEmit(address(optimismPortal2)); emit WithdrawalProven(_withdrawalHash, alice, bob); vm.expectEmit(address(optimismPortal2)); @@ -630,7 +632,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { /// @dev Tests that `proveWithdrawalTransaction` can be re-executed if the dispute game proven against has been /// blacklisted. - function test_proveWithdrawalTransaction_replayProveBlacklisted_suceeds() external { + function test_proveWithdrawalTransaction_replayProveBlacklisted_succeeds() external { vm.expectEmit(true, true, true, true); emit WithdrawalProven(_withdrawalHash, alice, bob); vm.expectEmit(true, true, true, true); @@ -668,7 +670,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { /// @dev Tests that `proveWithdrawalTransaction` can be re-executed if the dispute game proven against has resolved /// against the favor of the root claim. - function test_proveWithdrawalTransaction_replayProveBadProposal_suceeds() external { + function test_proveWithdrawalTransaction_replayProveBadProposal_succeeds() external { vm.expectEmit(true, true, true, true); emit WithdrawalProven(_withdrawalHash, alice, bob); vm.expectEmit(true, true, true, true); @@ -702,7 +704,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { /// @dev Tests that `proveWithdrawalTransaction` can be re-executed if the dispute game proven against is no longer /// of the respected game type. - function test_proveWithdrawalTransaction_replayRespectedGameTypeChanged_suceeds() external { + function test_proveWithdrawalTransaction_replayRespectedGameTypeChanged_succeeds() external { // Prove the withdrawal against a game with the current respected game type. vm.expectEmit(true, true, true, true); emit WithdrawalProven(_withdrawalHash, alice, bob); @@ -801,7 +803,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { } /// @dev Tests that `finalizeWithdrawalTransaction` succeeds. - function test_finalizeWithdrawalTransaction_provenWithdrawalHash_ether_succeeds() external { + function test_finalizeWithdrawalTransaction_provenWithdrawalHashEther_succeeds() external { uint256 bobBalanceBefore = address(bob).balance; vm.expectEmit(address(optimismPortal2)); @@ -889,10 +891,10 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { } /// @dev Tests that `finalizeWithdrawalTransaction` succeeds. - function test_finalizeWithdrawalTransaction_provenWithdrawalHash_nonEther_targetToken_reverts() external { + function test_finalizeWithdrawalTransaction_provenWithdrawalHashNonEtherTargetToken_reverts() external { vm.mockCall( address(systemConfig), - abi.encodeWithSignature("gasPayingToken()"), + abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(_defaultTx.target), 18) ); @@ -974,7 +976,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1); // Mock a createdAt change in the dispute game. - vm.mockCall(address(game), abi.encodeWithSignature("createdAt()"), abi.encode(block.timestamp + 1)); + vm.mockCall(address(game), abi.encodeCall(game.createdAt, ()), abi.encode(block.timestamp + 1)); // Attempt to finalize the withdrawal vm.expectRevert("OptimismPortal: withdrawal timestamp less than dispute game creation timestamp"); @@ -1120,7 +1122,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { // this contract's callPortalAndExpectRevert() function above. Types.WithdrawalTransaction memory _testTx = _defaultTx; _testTx.target = address(this); - _testTx.data = abi.encodeWithSelector(this.callPortalAndExpectRevert.selector); + _testTx.data = abi.encodeCall(this.callPortalAndExpectRevert, ()); // Get modified proof inputs. ( @@ -1161,6 +1163,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { } /// @dev Tests that `finalizeWithdrawalTransaction` succeeds. + /// forge-config: ciheavy.fuzz.runs = 8192 function testDiff_finalizeWithdrawalTransaction_succeeds( address _sender, address _target, @@ -1420,7 +1423,7 @@ contract OptimismPortal2_Upgradeable_Test is CommonTest { // The value passed to the initialize must be larger than the last value // that initialize was called with. IProxy(payable(address(optimismPortal2))).upgradeToAndCall( - address(nextImpl), abi.encodeWithSelector(NextImpl.initialize.selector, 2) + address(nextImpl), abi.encodeCall(NextImpl.initialize, (2)) ); assertEq(IProxy(payable(address(optimismPortal2))).implementation(), address(nextImpl)); @@ -1444,6 +1447,7 @@ contract OptimismPortal2_ResourceFuzz_Test is CommonTest { } /// @dev Test that various values of the resource metering config will not break deposits. + /// forge-config: ciheavy.fuzz.runs = 10000 function testFuzz_systemConfigDeposit_succeeds( uint32 _maxResourceLimit, uint8 _elasticityMultiplier, @@ -1498,9 +1502,7 @@ contract OptimismPortal2_ResourceFuzz_Test is CommonTest { systemTxMaxGas: _systemTxMaxGas, maximumBaseFee: _maximumBaseFee }); - vm.mockCall( - address(systemConfig), abi.encodeWithSelector(systemConfig.resourceConfig.selector), abi.encode(rcfg) - ); + vm.mockCall(address(systemConfig), abi.encodeCall(systemConfig.resourceConfig, ()), abi.encode(rcfg)); // Set the resource params uint256 _prevBlockNum = block.number - _blockDiff; @@ -1558,7 +1560,9 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal token.approve(address(optimismPortal2), _mint); // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); bytes memory opaqueData = abi.encodePacked(_mint, _value, _gasLimit, _isCreation, _data); @@ -1579,6 +1583,7 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal } /// @dev Tests that `depositERC20Transaction` succeeds when msg.sender == tx.origin. + /// forge-config: ciheavy.fuzz.runs = 8192 function testFuzz_depositERC20Transaction_senderIsOrigin_succeeds( address _to, uint256 _mint, @@ -1604,6 +1609,7 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal } /// @dev Tests that `depositERC20Transaction` succeeds when msg.sender != tx.origin. + /// forge-config: ciheavy.fuzz.runs = 8192 function testFuzz_depositERC20Transaction_senderNotOrigin_succeeds( address _to, uint256 _mint, @@ -1631,7 +1637,9 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal /// @dev Tests that `depositERC20Transaction` reverts when not enough of the token is approved. function test_depositERC20Transaction_notEnoughAmount_reverts() external { // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); vm.expectRevert(stdError.arithmeticError); // Deposit the token into the portal optimismPortal2.depositERC20Transaction(address(0), 1, 0, 0, false, ""); @@ -1644,13 +1652,13 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal token.approve(address(optimismPortal2), 100); // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); - - // Mock the token balance vm.mockCall( - address(token), abi.encodeWithSelector(token.balanceOf.selector, address(optimismPortal)), abi.encode(0) + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) ); + // Mock the token balance + vm.mockCall(address(token), abi.encodeCall(token.balanceOf, (address(optimismPortal))), abi.encode(0)); + // Call minimumGasLimit(0) before vm.expectRevert to ensure vm.expectRevert is for depositERC20Transaction uint64 gasLimit = optimismPortal2.minimumGasLimit(0); @@ -1663,7 +1671,9 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal /// @dev Tests that `depositERC20Transaction` reverts when creating a contract with a non-zero target. function test_depositERC20Transaction_isCreationNotZeroTarget_reverts() external { // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); // Call minimumGasLimit(0) before vm.expectRevert to ensure vm.expectRevert is for depositERC20Transaction uint64 gasLimit = optimismPortal2.minimumGasLimit(0); @@ -1676,7 +1686,9 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal /// @dev Tests that `depositERC20Transaction` reverts when the gas limit is too low. function test_depositERC20Transaction_gasLimitTooLow_reverts() external { // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); vm.expectRevert(SmallGasLimit.selector); // Deposit the token into the portal @@ -1689,7 +1701,9 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal data[120_000] = 0x01; // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); uint64 gasLimit = optimismPortal2.minimumGasLimit(120_001); vm.expectRevert(LargeCalldata.selector); @@ -1704,7 +1718,9 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal token.approve(address(optimismPortal2), _amount); // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); // Deposit the token into the portal optimismPortal2.depositERC20Transaction(address(0), _amount, 0, optimismPortal.minimumGasLimit(0), false, ""); @@ -1714,13 +1730,15 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal } /// @dev Tests that `finalizeWithdrawalTransaction` succeeds. - function test_finalizeWithdrawalTransaction_provenWithdrawalHash_nonEther_succeeds() external { + function test_finalizeWithdrawalTransaction_provenWithdrawalHashWithNonEther_succeeds() external { // Mint the token to the contract and approve the token for the portal token.mint(address(this), _defaultTx.value); token.approve(address(optimismPortal2), _defaultTx.value); // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); // Deposit the token into the portal optimismPortal2.depositERC20Transaction( @@ -1748,9 +1766,7 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal vm.expectCall(_defaultTx.target, 0, _defaultTx.data); - vm.expectCall( - address(token), 0, abi.encodeWithSelector(token.transfer.selector, _defaultTx.target, _defaultTx.value) - ); + vm.expectCall(address(token), 0, abi.encodeCall(token.transfer, (_defaultTx.target, _defaultTx.value))); optimismPortal2.finalizeWithdrawalTransaction(_defaultTx); @@ -1778,7 +1794,9 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal uint64(bound(_gasLimit, optimismPortal2.minimumGasLimit(uint64(_data.length)), rcfg.maxResourceLimit)); // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); bytes memory opaqueData = abi.encodePacked(uint256(0), _value, _gasLimit, _isCreation, _data); @@ -1799,7 +1817,8 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal } /// @dev Tests that `depositTransaction` succeeds when a custom gas token is used but the msg.value is zero. - function testFuzz_depositTransaction_customGasToken_noValue_senderIsOrigin_succeeds( + /// forge-config: ciheavy.fuzz.runs = 8192 + function testFuzz_depositTransaction_customGasTokenWithNoValueAndSenderIsOrigin_succeeds( address _to, uint256 _value, uint64 _gasLimit, @@ -1822,7 +1841,8 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal } /// @dev Tests that `depositTransaction` succeeds when a custom gas token is used but the msg.value is zero. - function testFuzz_depositTransaction_customGasToken_noValue_senderNotOrigin_succeeds( + /// forge-config: ciheavy.fuzz.runs = 8192 + function testFuzz_depositTransaction_customGasTokenWithNoValueAndSenderNotOrigin_succeeds( address _to, uint256 _value, uint64 _gasLimit, @@ -1845,9 +1865,11 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal } /// @dev Tests that `depositTransaction` fails when a custom gas token is used and msg.value is non-zero. - function test_depositTransaction_customGasToken_withValue_reverts() external { + function test_depositTransaction_customGasTokenWithValue_reverts() external { // Mock the gas paying token to be the ERC20 token - vm.mockCall(address(systemConfig), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(token), 18)); + vm.mockCall( + address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) + ); vm.expectRevert(NoValue.selector); diff --git a/packages/contracts-bedrock/test/L1/OptimismPortalInterop.t.sol b/packages/contracts-bedrock/test/L1/OptimismPortalInterop.t.sol index bc9a980276aa0..bd6d3b5d7de9b 100644 --- a/packages/contracts-bedrock/test/L1/OptimismPortalInterop.t.sol +++ b/packages/contracts-bedrock/test/L1/OptimismPortalInterop.t.sol @@ -43,7 +43,7 @@ contract OptimismPortalInterop_Test is CommonTest { } /// @dev Tests that setting the gas paying token config as not the system config reverts. - function testFuzz_setConfig_gasPayingToken_notSystemConfig_reverts(bytes calldata _value) public { + function testFuzz_setConfig_gasPayingTokenButNotSystemConfig_reverts(bytes calldata _value) public { vm.expectRevert(Unauthorized.selector); _optimismPortalInterop().setConfig(ConfigType.SET_GAS_PAYING_TOKEN, _value); } @@ -66,7 +66,7 @@ contract OptimismPortalInterop_Test is CommonTest { } /// @dev Tests that setting the add dependency config as not the system config reverts. - function testFuzz_setConfig_addDependency_notSystemConfig_reverts(bytes calldata _value) public { + function testFuzz_setConfig_addDependencyButNotSystemConfig_reverts(bytes calldata _value) public { vm.expectRevert(Unauthorized.selector); _optimismPortalInterop().setConfig(ConfigType.ADD_DEPENDENCY, _value); } @@ -89,7 +89,7 @@ contract OptimismPortalInterop_Test is CommonTest { } /// @dev Tests that setting the remove dependency config as not the system config reverts. - function testFuzz_setConfig_removeDependency_notSystemConfig_reverts(bytes calldata _value) public { + function testFuzz_setConfig_removeDependencyButNotSystemConfig_reverts(bytes calldata _value) public { vm.expectRevert(Unauthorized.selector); _optimismPortalInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, _value); } diff --git a/packages/contracts-bedrock/test/L1/ResourceMetering.t.sol b/packages/contracts-bedrock/test/L1/ResourceMetering.t.sol index 6d01cdb308671..18f5ba82283fb 100644 --- a/packages/contracts-bedrock/test/L1/ResourceMetering.t.sol +++ b/packages/contracts-bedrock/test/L1/ResourceMetering.t.sol @@ -374,8 +374,8 @@ contract ArtifactResourceMetering_Test is Test { // Call the metering code and catch the various // types of errors. uint256 gasConsumed = 0; - try meter.use{ gas: 30_000_000 }(requestedGas) returns (uint256 _gasConsumed) { - gasConsumed = _gasConsumed; + try meter.use{ gas: 30_000_000 }(requestedGas) returns (uint256 gasConsumed_) { + gasConsumed = gasConsumed_; } catch (bytes memory err) { bytes32 hash = keccak256(err); if (hash == cannotBuyMoreGas) { diff --git a/packages/contracts-bedrock/test/L1/SuperchainConfig.t.sol b/packages/contracts-bedrock/test/L1/SuperchainConfig.t.sol index ece5c68254c91..2772ec0c2a3c6 100644 --- a/packages/contracts-bedrock/test/L1/SuperchainConfig.t.sol +++ b/packages/contracts-bedrock/test/L1/SuperchainConfig.t.sol @@ -4,12 +4,13 @@ pragma solidity 0.8.15; import { CommonTest } from "test/setup/CommonTest.sol"; // Target contract dependencies -import { Proxy } from "src/universal/Proxy.sol"; +import { IProxy } from "src/universal/interfaces/IProxy.sol"; // Target contract -import { SuperchainConfig } from "src/L1/SuperchainConfig.sol"; import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; + contract SuperchainConfig_Init_Test is CommonTest { /// @dev Tests that initialization sets the correct values. These are defined in CommonTest.sol. function test_initialize_unpaused_succeeds() external view { @@ -19,13 +20,23 @@ contract SuperchainConfig_Init_Test is CommonTest { /// @dev Tests that it can be intialized as paused. function test_initialize_paused_succeeds() external { - Proxy newProxy = new Proxy(alice); - ISuperchainConfig newImpl = ISuperchainConfig(address(new SuperchainConfig())); + IProxy newProxy = IProxy( + DeployUtils.create1({ + _name: "Proxy", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (alice))) + }) + ); + ISuperchainConfig newImpl = ISuperchainConfig( + DeployUtils.create1({ + _name: "SuperchainConfig", + _args: DeployUtils.encodeConstructor(abi.encodeCall(ISuperchainConfig.__constructor__, ())) + }) + ); vm.startPrank(alice); newProxy.upgradeToAndCall( address(newImpl), - abi.encodeWithSelector(ISuperchainConfig.initialize.selector, deploy.cfg().superchainConfigGuardian(), true) + abi.encodeCall(ISuperchainConfig.initialize, (deploy.cfg().superchainConfigGuardian(), true)) ); assertTrue(ISuperchainConfig(address(newProxy)).paused()); diff --git a/packages/contracts-bedrock/test/L1/SystemConfig.t.sol b/packages/contracts-bedrock/test/L1/SystemConfig.t.sol index 5bf2193c2319a..fd5fd296f8fb6 100644 --- a/packages/contracts-bedrock/test/L1/SystemConfig.t.sol +++ b/packages/contracts-bedrock/test/L1/SystemConfig.t.sol @@ -255,6 +255,19 @@ contract SystemConfig_Init_ResourceConfig is SystemConfig_Init { _initializeWithResourceConfig(config, "SystemConfig: gas limit too low"); } + /// @dev Tests that `setResourceConfig` reverts if the gas limit is too low. + function test_setResourceConfig_elasticityMultiplierIs0_reverts() external { + IResourceMetering.ResourceConfig memory config = IResourceMetering.ResourceConfig({ + maxResourceLimit: 20_000_000, + elasticityMultiplier: 0, + baseFeeMaxChangeDenominator: 8, + systemTxMaxGas: 1_000_000, + minimumBaseFee: 1 gwei, + maximumBaseFee: 2 gwei + }); + _initializeWithResourceConfig(config, "SystemConfig: elasticity multiplier cannot be 0"); + } + /// @dev Tests that `setResourceConfig` reverts if the elasticity multiplier /// and max resource limit are configured such that there is a loss of precision. function test_setResourceConfig_badPrecision_reverts() external { @@ -375,9 +388,9 @@ contract SystemConfig_Init_CustomGasToken is SystemConfig_Init { vm.assume(bytes(_name).length <= 32); vm.assume(bytes(_symbol).length <= 32); - vm.mockCall(_token, abi.encodeWithSelector(token.decimals.selector), abi.encode(18)); - vm.mockCall(_token, abi.encodeWithSelector(token.name.selector), abi.encode(_name)); - vm.mockCall(_token, abi.encodeWithSelector(token.symbol.selector), abi.encode(_symbol)); + vm.mockCall(_token, abi.encodeCall(token.decimals, ()), abi.encode(18)); + vm.mockCall(_token, abi.encodeCall(token.name, ()), abi.encode(_name)); + vm.mockCall(_token, abi.encodeCall(token.symbol, ()), abi.encode(_symbol)); cleanStorageAndInit(_token); @@ -396,7 +409,7 @@ contract SystemConfig_Init_CustomGasToken is SystemConfig_Init { } /// @dev Tests that initialization sets the correct values and getters work when token address passed is 0. - function test_initialize_customGasToken_zeroTokenAddress_succeeds() external { + function test_initialize_customGasTokenWithZeroTokenAddress_succeeds() external { cleanStorageAndInit(address(0)); (address addr, uint8 decimals) = systemConfig.gasPayingToken(); @@ -408,7 +421,7 @@ contract SystemConfig_Init_CustomGasToken is SystemConfig_Init { } /// @dev Tests that initialization sets the correct values and getters work when token address is Constants.ETHER - function test_initialize_customGasToken_etherTokenAddress_succeeds() external { + function test_initialize_customGasTokenWithEtherTokenAddress_succeeds() external { cleanStorageAndInit(Constants.ETHER); (address addr, uint8 decimals) = systemConfig.gasPayingToken(); @@ -420,30 +433,30 @@ contract SystemConfig_Init_CustomGasToken is SystemConfig_Init { } /// @dev Tests that initialization fails if decimals are not 18. - function test_initialize_customGasToken_wrongDecimals_fails() external { - vm.mockCall(address(token), abi.encodeWithSelector(token.decimals.selector), abi.encode(8)); + function test_initialize_customGasTokenWrongDecimals_fails() external { + vm.mockCall(address(token), abi.encodeCall(token.decimals, ()), abi.encode(8)); vm.expectRevert("SystemConfig: bad decimals of gas paying token"); cleanStorageAndInit(address(token)); } /// @dev Tests that initialization fails if name is too long. - function test_initialize_customGasToken_nameTooLong_fails() external { + function test_initialize_customGasTokenNameTooLong_fails() external { string memory name = new string(32); name = string.concat(name, "a"); - vm.mockCall(address(token), abi.encodeWithSelector(token.name.selector), abi.encode(name)); + vm.mockCall(address(token), abi.encodeCall(token.name, ()), abi.encode(name)); vm.expectRevert("GasPayingToken: string cannot be greater than 32 bytes"); cleanStorageAndInit(address(token)); } /// @dev Tests that initialization fails if symbol is too long. - function test_initialize_customGasToken_symbolTooLong_fails() external { + function test_initialize_customGasTokenSymbolTooLong_fails() external { string memory symbol = new string(33); symbol = string.concat(symbol, "a"); - vm.mockCall(address(token), abi.encodeWithSelector(token.symbol.selector), abi.encode(symbol)); + vm.mockCall(address(token), abi.encodeCall(token.symbol, ()), abi.encode(symbol)); vm.expectRevert("GasPayingToken: string cannot be greater than 32 bytes"); cleanStorageAndInit(address(token)); diff --git a/packages/contracts-bedrock/test/L1/SystemConfigInterop.t.sol b/packages/contracts-bedrock/test/L1/SystemConfigInterop.t.sol index 0f2c51b4bf3be..78337fc3b4d08 100644 --- a/packages/contracts-bedrock/test/L1/SystemConfigInterop.t.sol +++ b/packages/contracts-bedrock/test/L1/SystemConfigInterop.t.sol @@ -26,6 +26,19 @@ contract SystemConfigInterop_Test is CommonTest { super.setUp(); } + /// @dev Tests that when the decimals is not 18, initialization reverts. + function test_initialize_decimalsIsNot18_reverts(uint8 decimals) external { + vm.assume(decimals != 18); + address _token = address(L1Token); + + vm.mockCall(_token, abi.encodeCall(ERC20.name, ()), abi.encode("Token")); + vm.mockCall(_token, abi.encodeCall(ERC20.symbol, ()), abi.encode("TKN")); + vm.mockCall(_token, abi.encodeCall(ERC20.decimals, ()), abi.encode(decimals)); + + vm.expectRevert("SystemConfig: bad decimals of gas paying token"); + _cleanStorageAndInit(_token); + } + /// @dev Tests that the gas paying token can be set. function testFuzz_setGasPayingToken_succeeds( address _token, @@ -41,9 +54,9 @@ contract SystemConfigInterop_Test is CommonTest { vm.assume(bytes(_name).length <= 32); vm.assume(bytes(_symbol).length <= 32); - vm.mockCall(_token, abi.encodeWithSelector(ERC20.decimals.selector), abi.encode(18)); - vm.mockCall(_token, abi.encodeWithSelector(ERC20.name.selector), abi.encode(_name)); - vm.mockCall(_token, abi.encodeWithSelector(ERC20.symbol.selector), abi.encode(_symbol)); + vm.mockCall(_token, abi.encodeCall(ERC20.decimals, ()), abi.encode(18)); + vm.mockCall(_token, abi.encodeCall(ERC20.name, ()), abi.encode(_name)); + vm.mockCall(_token, abi.encodeCall(ERC20.symbol, ()), abi.encode(_symbol)); vm.expectCall( address(optimismPortal), @@ -80,7 +93,7 @@ contract SystemConfigInterop_Test is CommonTest { /// @dev Tests that adding a dependency as not the dependency manager reverts. function testFuzz_addDependency_notDependencyManager_reverts(uint256 _chainId) public { - require(alice != _systemConfigInterop().dependencyManager(), "SystemConfigInterop_Test-100"); + require(alice != _systemConfigInterop().dependencyManager(), "SystemConfigInterop_Test: 100"); vm.expectRevert("SystemConfig: caller is not the dependency manager"); vm.prank(alice); _systemConfigInterop().addDependency(_chainId); @@ -102,7 +115,7 @@ contract SystemConfigInterop_Test is CommonTest { /// @dev Tests that removing a dependency as not the dependency manager reverts. function testFuzz_removeDependency_notDependencyManager_reverts(uint256 _chainId) public { - require(alice != _systemConfigInterop().dependencyManager(), "SystemConfigInterop_Test-100"); + require(alice != _systemConfigInterop().dependencyManager(), "SystemConfigInterop_Test: 100"); vm.expectRevert("SystemConfig: caller is not the dependency manager"); vm.prank(alice); _systemConfigInterop().removeDependency(_chainId); diff --git a/packages/contracts-bedrock/test/L2/BaseFeeVault.t.sol b/packages/contracts-bedrock/test/L2/BaseFeeVault.t.sol index bf63a700c0985..1864e1d076640 100644 --- a/packages/contracts-bedrock/test/L2/BaseFeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/BaseFeeVault.t.sol @@ -2,13 +2,13 @@ pragma solidity 0.8.15; // Testing utilities -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Libraries import { Types } from "src/libraries/Types.sol"; // Test the implementations of the FeeVault -contract FeeVault_Test is Bridge_Initializer { +contract FeeVault_Test is CommonTest { /// @dev Tests that the constructor sets the correct values. function test_constructor_baseFeeVault_succeeds() external view { assertEq(baseFeeVault.RECIPIENT(), deploy.cfg().baseFeeVaultRecipient()); diff --git a/packages/contracts-bedrock/test/L2/CrossDomainOwnable.t.sol b/packages/contracts-bedrock/test/L2/CrossDomainOwnable.t.sol index 1e7c10556a536..c66bd1f94ab3d 100644 --- a/packages/contracts-bedrock/test/L2/CrossDomainOwnable.t.sol +++ b/packages/contracts-bedrock/test/L2/CrossDomainOwnable.t.sol @@ -68,7 +68,7 @@ contract CrossDomainOwnableThroughPortal_Test is CommonTest { _value: 0, _gasLimit: 30_000, _isCreation: false, - _data: abi.encodeWithSelector(XDomainSetter.set.selector, 1) + _data: abi.encodeCall(XDomainSetter.set, (1)) }); // Simulate the operation of the `op-node` by parsing data diff --git a/packages/contracts-bedrock/test/L2/CrossDomainOwnable2.t.sol b/packages/contracts-bedrock/test/L2/CrossDomainOwnable2.t.sol index fa1244a0b0e12..7bdbdaa9f7089 100644 --- a/packages/contracts-bedrock/test/L2/CrossDomainOwnable2.t.sol +++ b/packages/contracts-bedrock/test/L2/CrossDomainOwnable2.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; // Testing utilities -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Libraries import { Hashing } from "src/libraries/Hashing.sol"; @@ -23,7 +23,7 @@ contract XDomainSetter2 is CrossDomainOwnable2 { } } -contract CrossDomainOwnable2_Test is Bridge_Initializer { +contract CrossDomainOwnable2_Test is CommonTest { XDomainSetter2 setter; /// @dev Sets up the test suite. @@ -58,7 +58,7 @@ contract CrossDomainOwnable2_Test is Bridge_Initializer { address target = address(setter); uint256 value = 0; uint256 minGasLimit = 0; - bytes memory message = abi.encodeWithSelector(XDomainSetter2.set.selector, 1); + bytes memory message = abi.encodeCall(XDomainSetter2.set, (1)); bytes32 hash = Hashing.hashCrossDomainMessage( Encoding.encodeVersionedNonce(nonce, 1), sender, target, value, minGasLimit, message @@ -85,12 +85,7 @@ contract CrossDomainOwnable2_Test is Bridge_Initializer { // the L1CrossDomainMessenger vm.prank(AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger))); l2CrossDomainMessenger.relayMessage( - Encoding.encodeVersionedNonce(1, 1), - owner, - address(setter), - 0, - 0, - abi.encodeWithSelector(XDomainSetter2.set.selector, 2) + Encoding.encodeVersionedNonce(1, 1), owner, address(setter), 0, 0, abi.encodeCall(XDomainSetter2.set, (2)) ); assertEq(setter.value(), 2); diff --git a/packages/contracts-bedrock/test/L2/CrossDomainOwnable3.t.sol b/packages/contracts-bedrock/test/L2/CrossDomainOwnable3.t.sol index 432007ecd6d7d..e1bac7c784bb9 100644 --- a/packages/contracts-bedrock/test/L2/CrossDomainOwnable3.t.sol +++ b/packages/contracts-bedrock/test/L2/CrossDomainOwnable3.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; // Testing utilities -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Libraries import { Hashing } from "src/libraries/Hashing.sol"; @@ -23,7 +23,7 @@ contract XDomainSetter3 is CrossDomainOwnable3 { } } -contract CrossDomainOwnable3_Test is Bridge_Initializer { +contract CrossDomainOwnable3_Test is CommonTest { XDomainSetter3 setter; /// @dev CrossDomainOwnable3.sol transferOwnership event @@ -101,7 +101,7 @@ contract CrossDomainOwnable3_Test is Bridge_Initializer { address target = address(setter); uint256 value = 0; uint256 minGasLimit = 0; - bytes memory message = abi.encodeWithSelector(XDomainSetter3.set.selector, 1); + bytes memory message = abi.encodeCall(XDomainSetter3.set, (1)); bytes32 hash = Hashing.hashCrossDomainMessage( Encoding.encodeVersionedNonce(nonce, 1), sender, target, value, minGasLimit, message @@ -216,12 +216,7 @@ contract CrossDomainOwnable3_Test is Bridge_Initializer { // the L1CrossDomainMessenger vm.prank(AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger))); l2CrossDomainMessenger.relayMessage( - Encoding.encodeVersionedNonce(1, 1), - bob, - address(setter), - 0, - 0, - abi.encodeWithSelector(XDomainSetter3.set.selector, 2) + Encoding.encodeVersionedNonce(1, 1), bob, address(setter), 0, 0, abi.encodeCall(XDomainSetter3.set, (2)) ); assertEq(setter.value(), 2); diff --git a/packages/contracts-bedrock/test/L2/CrossL2Inbox.t.sol b/packages/contracts-bedrock/test/L2/CrossL2Inbox.t.sol index 8078e2c01c74e..25b6e711c1ec3 100644 --- a/packages/contracts-bedrock/test/L2/CrossL2Inbox.t.sol +++ b/packages/contracts-bedrock/test/L2/CrossL2Inbox.t.sol @@ -11,6 +11,7 @@ import { TransientContext } from "src/libraries/TransientContext.sol"; // Target contracts import { CrossL2Inbox, + Identifier, NotEntered, NoExecutingDeposits, InvalidTimestamp, @@ -20,7 +21,6 @@ import { InteropStartAlreadySet } from "src/L2/CrossL2Inbox.sol"; import { IL1BlockInterop } from "src/L2/interfaces/IL1BlockInterop.sol"; -import { ICrossL2Inbox } from "src/L2/interfaces/ICrossL2Inbox.sol"; /// @title CrossL2InboxWithModifiableTransientStorage /// @dev CrossL2Inbox contract with methods to modify the transient storage. @@ -141,7 +141,7 @@ contract CrossL2InboxTest is Test { /// @dev Tests that the `executeMessage` function succeeds. function testFuzz_executeMessage_succeeds( - ICrossL2Inbox.Identifier memory _id, + Identifier memory _id, address _target, bytes calldata _message, uint256 _value @@ -160,7 +160,7 @@ contract CrossL2InboxTest is Test { // Ensure is not a deposit transaction vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(IL1BlockInterop.isDeposit.selector), + data: abi.encodeCall(IL1BlockInterop.isDeposit, ()), returnData: abi.encode(false) }); @@ -170,7 +170,7 @@ contract CrossL2InboxTest is Test { // Ensure that the chain ID is in the dependency set vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(L1BlockIsInDependencySetSelector, _id.chainId), + data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id.chainId)), returnData: abi.encode(true) }); @@ -200,14 +200,14 @@ contract CrossL2InboxTest is Test { /// @dev Mock reentrant function that calls the `executeMessage` function. /// @param _id Identifier to pass to the `executeMessage` function. - function mockReentrant(ICrossL2Inbox.Identifier calldata _id) external payable { + function mockReentrant(Identifier calldata _id) external payable { crossL2Inbox.executeMessage({ _id: _id, _target: address(0), _message: "" }); } /// @dev Tests that the `executeMessage` function successfully handles reentrant calls. function testFuzz_executeMessage_reentrant_succeeds( - ICrossL2Inbox.Identifier memory _id1, // identifier passed to `executeMessage` by the initial call. - ICrossL2Inbox.Identifier memory _id2, // identifier passed to `executeMessage` by the reentrant call. + Identifier memory _id1, // identifier passed to `executeMessage` by the initial call. + Identifier memory _id2, // identifier passed to `executeMessage` by the reentrant call. uint256 _value ) external @@ -222,27 +222,27 @@ contract CrossL2InboxTest is Test { // Ensure is not a deposit transaction vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(IL1BlockInterop.isDeposit.selector), + data: abi.encodeCall(IL1BlockInterop.isDeposit, ()), returnData: abi.encode(false) }); // Ensure that id1's chain ID is in the dependency set vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(L1BlockIsInDependencySetSelector, _id1.chainId), + data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id1.chainId)), returnData: abi.encode(true) }); // Ensure that id2's chain ID is in the dependency set vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(L1BlockIsInDependencySetSelector, _id2.chainId), + data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id2.chainId)), returnData: abi.encode(true) }); // Set the target and message for the reentrant call address target = address(this); - bytes memory message = abi.encodeWithSelector(this.mockReentrant.selector, _id2); + bytes memory message = abi.encodeCall(this.mockReentrant, (_id2)); // Ensure that the contract has enough balance to send with value vm.deal(address(this), _value); @@ -272,7 +272,7 @@ contract CrossL2InboxTest is Test { /// @dev Tests that the `executeMessage` function reverts if the transaction comes from a deposit. function testFuzz_executeMessage_isDeposit_reverts( - ICrossL2Inbox.Identifier calldata _id, + Identifier calldata _id, address _target, bytes calldata _message, uint256 _value @@ -282,7 +282,7 @@ contract CrossL2InboxTest is Test { // Ensure it is a deposit transaction vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(IL1BlockInterop.isDeposit.selector), + data: abi.encodeCall(IL1BlockInterop.isDeposit, ()), returnData: abi.encode(true) }); @@ -298,7 +298,7 @@ contract CrossL2InboxTest is Test { /// @dev Tests that the `executeMessage` function reverts when called with an identifier with an invalid timestamp. function testFuzz_executeMessage_invalidTimestamp_reverts( - ICrossL2Inbox.Identifier calldata _id, + Identifier calldata _id, address _target, bytes calldata _message, uint256 _value @@ -312,7 +312,7 @@ contract CrossL2InboxTest is Test { // Ensure is not a deposit transaction vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(IL1BlockInterop.isDeposit.selector), + data: abi.encodeCall(IL1BlockInterop.isDeposit, ()), returnData: abi.encode(false) }); @@ -328,8 +328,8 @@ contract CrossL2InboxTest is Test { /// @dev Tests that the `executeMessage` function reverts when called with an identifier with a timestamp earlier /// than INTEROP_START timestamp - function testFuzz_executeMessage_invalidTimestamp_interopStart_reverts( - ICrossL2Inbox.Identifier memory _id, + function testFuzz_executeMessage_invalidTimestampInteropStart_reverts( + Identifier memory _id, address _target, bytes calldata _message, uint256 _value @@ -346,7 +346,7 @@ contract CrossL2InboxTest is Test { // Ensure is not a deposit transaction vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(IL1BlockInterop.isDeposit.selector), + data: abi.encodeCall(IL1BlockInterop.isDeposit, ()), returnData: abi.encode(false) }); @@ -360,7 +360,7 @@ contract CrossL2InboxTest is Test { /// @dev Tests that the `executeMessage` function reverts when called with an identifier with a chain ID not in /// dependency set. function testFuzz_executeMessage_invalidChainId_reverts( - ICrossL2Inbox.Identifier memory _id, + Identifier memory _id, address _target, bytes calldata _message, uint256 _value @@ -375,14 +375,14 @@ contract CrossL2InboxTest is Test { // Ensure is not a deposit transaction vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(IL1BlockInterop.isDeposit.selector), + data: abi.encodeCall(IL1BlockInterop.isDeposit, ()), returnData: abi.encode(false) }); // Ensure that the chain ID is NOT in the dependency set vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(L1BlockIsInDependencySetSelector, _id.chainId), + data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id.chainId)), returnData: abi.encode(false) }); @@ -398,7 +398,7 @@ contract CrossL2InboxTest is Test { /// @dev Tests that the `executeMessage` function reverts when the target call fails. function testFuzz_executeMessage_targetCallFailed_reverts( - ICrossL2Inbox.Identifier memory _id, + Identifier memory _id, address _target, bytes calldata _message, uint256 _value @@ -419,14 +419,14 @@ contract CrossL2InboxTest is Test { // Ensure is not a deposit transaction vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(IL1BlockInterop.isDeposit.selector), + data: abi.encodeCall(IL1BlockInterop.isDeposit, ()), returnData: abi.encode(false) }); // Ensure that the chain ID is in the dependency set vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(L1BlockIsInDependencySetSelector, _id.chainId), + data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id.chainId)), returnData: abi.encode(true) }); @@ -443,13 +443,7 @@ contract CrossL2InboxTest is Test { crossL2Inbox.executeMessage{ value: _value }({ _id: _id, _target: _target, _message: _message }); } - function testFuzz_validateMessage_succeeds( - ICrossL2Inbox.Identifier memory _id, - bytes32 _messageHash - ) - external - setInteropStart - { + function testFuzz_validateMessage_succeeds(Identifier memory _id, bytes32 _messageHash) external setInteropStart { // Ensure that the id's timestamp is valid (less than or equal to the current block timestamp and greater than // interop start time) _id.timestamp = bound(_id.timestamp, interopStartTime + 1, block.timestamp); @@ -457,14 +451,14 @@ contract CrossL2InboxTest is Test { // Ensure that the chain ID is in the dependency set vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(L1BlockIsInDependencySetSelector, _id.chainId), + data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id.chainId)), returnData: abi.encode(true) }); // Ensure is not a deposit transaction vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(IL1BlockInterop.isDeposit.selector), + data: abi.encodeCall(IL1BlockInterop.isDeposit, ()), returnData: abi.encode(false) }); @@ -476,16 +470,11 @@ contract CrossL2InboxTest is Test { crossL2Inbox.validateMessage(_id, _messageHash); } - function testFuzz_validateMessage_isDeposit_reverts( - ICrossL2Inbox.Identifier calldata _id, - bytes32 _messageHash - ) - external - { + function testFuzz_validateMessage_isDeposit_reverts(Identifier calldata _id, bytes32 _messageHash) external { // Ensure it is a deposit transaction vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(IL1BlockInterop.isDeposit.selector), + data: abi.encodeCall(IL1BlockInterop.isDeposit, ()), returnData: abi.encode(true) }); @@ -499,7 +488,7 @@ contract CrossL2InboxTest is Test { /// @dev Tests that the `validateMessage` function reverts when called with an identifier with a timestamp later /// than current block.timestamp. function testFuzz_validateMessage_invalidTimestamp_reverts( - ICrossL2Inbox.Identifier calldata _id, + Identifier calldata _id, bytes32 _messageHash ) external @@ -508,7 +497,7 @@ contract CrossL2InboxTest is Test { // Ensure is not a deposit transaction vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(IL1BlockInterop.isDeposit.selector), + data: abi.encodeCall(IL1BlockInterop.isDeposit, ()), returnData: abi.encode(false) }); @@ -524,8 +513,8 @@ contract CrossL2InboxTest is Test { /// @dev Tests that the `validateMessage` function reverts when called with an identifier with a timestamp earlier /// than INTEROP_START timestamp - function testFuzz_validateMessage_invalidTimestamp_interopStart_reverts( - ICrossL2Inbox.Identifier memory _id, + function testFuzz_validateMessage_invalidTimestampInteropStart_reverts( + Identifier memory _id, bytes32 _messageHash ) external @@ -537,7 +526,7 @@ contract CrossL2InboxTest is Test { // Ensure is not a deposit transaction vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(IL1BlockInterop.isDeposit.selector), + data: abi.encodeCall(IL1BlockInterop.isDeposit, ()), returnData: abi.encode(false) }); @@ -551,7 +540,7 @@ contract CrossL2InboxTest is Test { /// @dev Tests that the `validateMessage` function reverts when called with an identifier with a chain ID not in the /// dependency set. function testFuzz_validateMessage_invalidChainId_reverts( - ICrossL2Inbox.Identifier memory _id, + Identifier memory _id, bytes32 _messageHash ) external @@ -564,14 +553,14 @@ contract CrossL2InboxTest is Test { // Ensure that the chain ID is NOT in the dependency set. vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(L1BlockIsInDependencySetSelector, _id.chainId), + data: abi.encodeCall(IL1BlockInterop.isInDependencySet, (_id.chainId)), returnData: abi.encode(false) }); // Ensure is not a deposit transaction vm.mockCall({ callee: Predeploys.L1_BLOCK_ATTRIBUTES, - data: abi.encodeWithSelector(IL1BlockInterop.isDeposit.selector), + data: abi.encodeCall(IL1BlockInterop.isDeposit, ()), returnData: abi.encode(false) }); diff --git a/packages/contracts-bedrock/test/L2/ETHLiquidity.t.sol b/packages/contracts-bedrock/test/L2/ETHLiquidity.t.sol index d9d2d92a89281..9814e776b2e5e 100644 --- a/packages/contracts-bedrock/test/L2/ETHLiquidity.t.sol +++ b/packages/contracts-bedrock/test/L2/ETHLiquidity.t.sol @@ -105,7 +105,7 @@ contract ETHLiquidity_Test is CommonTest { uint256 amount = STARTING_LIQUIDITY_BALANCE + 1; // Act - vm.expectRevert(); + vm.expectRevert(); // nosemgrep: sol-safety-expectrevert-no-args ethLiquidity.mint(amount); // Assert diff --git a/packages/contracts-bedrock/test/L2/GasPriceOracle.t.sol b/packages/contracts-bedrock/test/L2/GasPriceOracle.t.sol index f81d96b040f46..0a1d97c9351e9 100644 --- a/packages/contracts-bedrock/test/L2/GasPriceOracle.t.sol +++ b/packages/contracts-bedrock/test/L2/GasPriceOracle.t.sol @@ -93,6 +93,7 @@ contract GasPriceOracleBedrock_Test is GasPriceOracle_Test { /// @dev Tests that `setGasPrice` reverts since it was removed in bedrock. function test_setGasPrice_doesNotExist_reverts() external { + // nosemgrep: sol-style-use-abi-encodecall (bool success, bytes memory returndata) = address(gasPriceOracle).call(abi.encodeWithSignature("setGasPrice(uint256)", 1)); @@ -102,6 +103,7 @@ contract GasPriceOracleBedrock_Test is GasPriceOracle_Test { /// @dev Tests that `setL1BaseFee` reverts since it was removed in bedrock. function test_setL1BaseFee_doesNotExist_reverts() external { + // nosemgrep: sol-style-use-abi-encodecall (bool success, bytes memory returndata) = address(gasPriceOracle).call(abi.encodeWithSignature("setL1BaseFee(uint256)", 1)); @@ -131,7 +133,7 @@ contract GasPriceOracleEcotone_Test is GasPriceOracle_Test { // Execute the function call vm.prank(depositor); (bool success,) = address(l1Block).call(calldataPacked); - require(success, "Function call failed"); + require(success, "GasPriceOracleEcotone_Test: Function call failed"); } /// @dev Tests that `setEcotone` is only callable by the depositor. @@ -222,7 +224,7 @@ contract GasPriceOracleFjordActive_Test is GasPriceOracle_Test { vm.prank(depositor); (bool success,) = address(l1Block).call(calldataPacked); - require(success, "Function call failed"); + require(success, "GasPriceOracleFjordActive_Test: Function call failed"); } /// @dev Tests that `setFjord` cannot be called when Fjord is already activate diff --git a/packages/contracts-bedrock/test/L2/L1BlockInterop.t.sol b/packages/contracts-bedrock/test/L2/L1BlockInterop.t.sol index 6f0ef2188b8c8..c8779342c3bfc 100644 --- a/packages/contracts-bedrock/test/L2/L1BlockInterop.t.sol +++ b/packages/contracts-bedrock/test/L2/L1BlockInterop.t.sol @@ -104,7 +104,7 @@ contract L1BlockInteropTest is CommonTest { } /// @dev Tests that setting the gas paying token config as not the depositor reverts. - function testFuzz_setConfig_gasPayingToken_notDepositor_reverts( + function testFuzz_setConfig_gasPayingTokenButNotDepositor_reverts( address _token, uint8 _decimals, bytes32 _name, @@ -132,13 +132,13 @@ contract L1BlockInteropTest is CommonTest { } /// @dev Tests that adding a dependency reverts if it's the chain's chain id - function test_setConfig_addDependency_chainChainId_reverts() public prankDepositor { + function test_setConfig_addDependencyButChainChainId_reverts() public prankDepositor { vm.expectRevert(AlreadyDependency.selector); _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(block.chainid)); } /// @dev Tests that adding a dependency already in the set reverts - function test_setConfig_addDependency_alreadyDependency_reverts(uint256 _chainId) public prankDepositor { + function test_setConfig_addDependencyButAlreadyDependency_reverts(uint256 _chainId) public prankDepositor { vm.assume(_chainId != block.chainid); _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); @@ -148,13 +148,13 @@ contract L1BlockInteropTest is CommonTest { } /// @dev Tests that setting the add dependency config as not the depositor reverts. - function testFuzz_setConfig_addDependency_notDepositor_reverts(uint256 _chainId) public { + function testFuzz_setConfig_addDependencyButNotDepositor_reverts(uint256 _chainId) public { vm.expectRevert(NotDepositor.selector); _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); } /// @dev Tests that setting the add dependency config when the dependency set size is too large reverts. - function test_setConfig_addDependency_dependencySetSizeTooLarge_reverts() public prankDepositor { + function test_setConfig_addDependencyButDependencySetSizeTooLarge_reverts() public prankDepositor { for (uint256 i = 0; i < type(uint8).max; i++) { _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(i)); } @@ -179,19 +179,19 @@ contract L1BlockInteropTest is CommonTest { } /// @dev Tests that setting the remove dependency config as not the depositor reverts. - function testFuzz_setConfig_removeDependency_notDepositor_reverts(uint256 _chainId) public { + function testFuzz_setConfig_removeDependencyButNotDepositor_reverts(uint256 _chainId) public { vm.expectRevert(NotDepositor.selector); _l1BlockInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId)); } /// @dev Tests that setting the remove dependency config for the chain's chain ID reverts. - function test_setConfig_removeDependency_chainChainId_reverts() public prankDepositor { + function test_setConfig_removeDependencyButChainChainId_reverts() public prankDepositor { vm.expectRevert(CantRemovedDependency.selector); _l1BlockInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(block.chainid)); } /// @dev Tests that setting the remove dependency config for a chain ID that is not in the dependency set reverts. - function testFuzz_setConfig_removeDependency_notDependency_reverts(uint256 _chainId) public prankDepositor { + function testFuzz_setConfig_removeDependencyButNotDependency_reverts(uint256 _chainId) public prankDepositor { vm.assume(_chainId != block.chainid); vm.expectRevert(NotDependency.selector); @@ -284,7 +284,7 @@ contract L1BlockInteropSetL1BlockValuesInterop_Test is L1BlockInteropTest { contract L1BlockDepositsComplete_Test is L1BlockInteropTest { // @dev Tests that `depositsComplete` reverts if the caller is not the depositor. - function test_deposits_is_depositor_reverts(address _caller) external { + function test_depositsComplete_notDepositor_reverts(address _caller) external { vm.assume(_caller != _l1BlockInterop().DEPOSITOR_ACCOUNT()); vm.expectRevert(NotDepositor.selector); _l1BlockInterop().depositsComplete(); diff --git a/packages/contracts-bedrock/test/L2/L1FeeVault.t.sol b/packages/contracts-bedrock/test/L2/L1FeeVault.t.sol index 03a3e7e5ad9be..5284054056d1b 100644 --- a/packages/contracts-bedrock/test/L2/L1FeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/L1FeeVault.t.sol @@ -2,13 +2,13 @@ pragma solidity 0.8.15; // Testing utilities -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Libraries import { Types } from "src/libraries/Types.sol"; // Test the implementations of the FeeVault -contract FeeVault_Test is Bridge_Initializer { +contract FeeVault_Test is CommonTest { /// @dev Tests that the constructor sets the correct values. function test_constructor_l1FeeVault_succeeds() external view { assertEq(l1FeeVault.RECIPIENT(), deploy.cfg().l1FeeVaultRecipient()); diff --git a/packages/contracts-bedrock/test/L2/L2CrossDomainMessenger.t.sol b/packages/contracts-bedrock/test/L2/L2CrossDomainMessenger.t.sol index 26fc9f2d039d5..f5ef2d6355954 100644 --- a/packages/contracts-bedrock/test/L2/L2CrossDomainMessenger.t.sol +++ b/packages/contracts-bedrock/test/L2/L2CrossDomainMessenger.t.sol @@ -2,9 +2,10 @@ pragma solidity 0.8.15; // Testing -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; import { Reverter } from "test/mocks/Callers.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; +import { stdError } from "forge-std/StdError.sol"; // Libraries import { Hashing } from "src/libraries/Hashing.sol"; @@ -16,7 +17,7 @@ import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; import { IL2CrossDomainMessenger } from "src/L2/interfaces/IL2CrossDomainMessenger.sol"; import { IL2ToL1MessagePasser } from "src/L2/interfaces/IL2ToL1MessagePasser.sol"; -contract L2CrossDomainMessenger_Test is Bridge_Initializer { +contract L2CrossDomainMessenger_Test is CommonTest { /// @dev Receiver address for testing address recipient = address(0xabbaacdc); @@ -48,11 +49,9 @@ contract L2CrossDomainMessenger_Test is Bridge_Initializer { Encoding.encodeCrossDomainMessage(l2CrossDomainMessenger.messageNonce(), alice, recipient, 0, 100, hex"ff"); vm.expectCall( address(l2ToL1MessagePasser), - abi.encodeWithSelector( - IL2ToL1MessagePasser.initiateWithdrawal.selector, - address(l1CrossDomainMessenger), - l2CrossDomainMessenger.baseGas(hex"ff", 100), - xDomainCallData + abi.encodeCall( + IL2ToL1MessagePasser.initiateWithdrawal, + (address(l1CrossDomainMessenger), l2CrossDomainMessenger.baseGas(hex"ff", 100), xDomainCallData) ) ); @@ -150,17 +149,103 @@ contract L2CrossDomainMessenger_Test is Bridge_Initializer { assertEq(l2CrossDomainMessenger.failedMessages(hash), false); } - /// @dev Tests that `relayMessage` reverts if attempting to relay - /// a message sent to an L1 system contract. - function test_relayMessage_toSystemContract_reverts() external { - address target = address(l2ToL1MessagePasser); + /// @dev Tests that relayMessage reverts if the value sent does not match the amount + function test_relayMessage_fromOtherMessengerValueMismatch_reverts() external { + // set the target to be alice + address target = alice; address sender = address(l1CrossDomainMessenger); address caller = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)); bytes memory message = hex"1111"; + // cannot send a message where the amount inputted does not match the msg.value + vm.deal(caller, 10 ether); vm.prank(caller); + vm.expectRevert(stdError.assertionError); + l2CrossDomainMessenger.relayMessage{ value: 10 ether }( + Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, 9 ether, 0, message + ); + } + + /// @dev Tests that relayMessage reverts if a failed message is attempted to be replayed and the caller is the other + /// messenger + function test_relayMessage_fromOtherMessengerFailedMessageReplay_reverts() external { + // set the target to be alice + address target = alice; + address sender = address(l1CrossDomainMessenger); + address caller = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)); + bytes memory message = hex"1111"; + + // make a failed message + vm.etch(target, hex"fe"); + vm.prank(caller); + l2CrossDomainMessenger.relayMessage( + Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, 0, 0, message + ); + + // cannot replay messages when the caller is the other messenger + vm.prank(caller); + vm.expectRevert(stdError.assertionError); + l2CrossDomainMessenger.relayMessage( + Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, 0, 0, message + ); + } + + /// @dev Tests that relayMessage reverts if attempting to relay a message + /// sent to self + function test_relayMessage_toSelf_reverts() external { + address sender = address(l1CrossDomainMessenger); + address caller = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)); + bytes memory message = hex"1111"; + + vm.store(address(optimismPortal), bytes32(0), bytes32(abi.encode(sender))); + + vm.prank(caller); + vm.expectRevert("CrossDomainMessenger: cannot send message to blocked system address"); + l2CrossDomainMessenger.relayMessage( + Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), + sender, + address(l2CrossDomainMessenger), + 0, + 0, + message + ); + } + + /// @dev Tests that relayMessage reverts if attempting to relay a message + /// sent to the l2ToL1MessagePasser address + function test_relayMessage_toL2ToL1MessagePasser_reverts() external { + address sender = address(l1CrossDomainMessenger); + address caller = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)); + bytes memory message = hex"1111"; + + vm.store(address(optimismPortal), bytes32(0), bytes32(abi.encode(sender))); + + vm.prank(caller); + vm.expectRevert("CrossDomainMessenger: cannot send message to blocked system address"); + l2CrossDomainMessenger.relayMessage( + Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), + sender, + address(l2ToL1MessagePasser), + 0, + 0, + message + ); + } + + /// @dev Tests that the relayMessage function reverts if the message called by non-optimismPortal but not a failed + /// message + function test_relayMessage_relayingNewMessageByExternalUser_reverts() external { + address target = address(alice); + address sender = address(l1CrossDomainMessenger); + bytes memory message = hex"1111"; + + vm.store(address(optimismPortal), bytes32(0), bytes32(abi.encode(sender))); + + vm.prank(bob); vm.expectRevert("CrossDomainMessenger: message cannot be replayed"); - l1CrossDomainMessenger.relayMessage(Encoding.encodeVersionedNonce(0, 1), sender, target, 0, 0, message); + l2CrossDomainMessenger.relayMessage( + Encoding.encodeVersionedNonce({ _nonce: 0, _version: 1 }), sender, target, 0, 0, message + ); } /// @dev Tests that `relayMessage` correctly resets the `xDomainMessageSender` @@ -228,19 +313,17 @@ contract L2CrossDomainMessenger_Test is Bridge_Initializer { } /// @dev Tests that sendMessage succeeds with a custom gas token when the call value is zero. - function test_sendMessage_customGasToken_noValue_succeeds() external { + function test_sendMessage_customGasTokenButNoValue_succeeds() external { // Mock the gasPayingToken function to return a custom gas token - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2))); + vm.mockCall(address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))); bytes memory xDomainCallData = Encoding.encodeCrossDomainMessage(l2CrossDomainMessenger.messageNonce(), alice, recipient, 0, 100, hex"ff"); vm.expectCall( address(l2ToL1MessagePasser), - abi.encodeWithSelector( - IL2ToL1MessagePasser.initiateWithdrawal.selector, - address(l1CrossDomainMessenger), - l2CrossDomainMessenger.baseGas(hex"ff", 100), - xDomainCallData + abi.encodeCall( + IL2ToL1MessagePasser.initiateWithdrawal, + (address(l1CrossDomainMessenger), l2CrossDomainMessenger.baseGas(hex"ff", 100), xDomainCallData) ) ); @@ -270,18 +353,18 @@ contract L2CrossDomainMessenger_Test is Bridge_Initializer { } /// @dev Tests that the sendMessage reverts when call value is non-zero with custom gas token. - function test_sendMessage_customGasToken_withValue_reverts() external { + function test_sendMessage_customGasTokenWithValue_reverts() external { // Mock the gasPayingToken function to return a custom gas token - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2))); + vm.mockCall(address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))); vm.expectRevert("CrossDomainMessenger: cannot send value with custom gas token"); l2CrossDomainMessenger.sendMessage{ value: 1 }(recipient, hex"ff", uint32(100)); } /// @dev Tests that the relayMessage succeeds with a custom gas token when the call value is zero. - function test_relayMessage_customGasToken_noValue_succeeds() external { + function test_relayMessage_customGasTokenAndNoValue_succeeds() external { // Mock the gasPayingToken function to return a custom gas token - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2))); + vm.mockCall(address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))); address target = address(0xabcd); address sender = address(l1CrossDomainMessenger); @@ -315,9 +398,9 @@ contract L2CrossDomainMessenger_Test is Bridge_Initializer { /// @dev Tests that the relayMessage reverts when call value is non-zero with custom gas token. /// The L1CrossDomainMessenger `sendMessage` function cannot send value with a custom gas token. - function test_relayMessage_customGasToken_withValue_reverts() external virtual { + function test_relayMessage_customGasTokenWithValue_reverts() external virtual { // Mock the gasPayingToken function to return a custom gas token - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2))); + vm.mockCall(address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))); vm.expectRevert("CrossDomainMessenger: value must be zero unless message is from a system address"); l2CrossDomainMessenger.relayMessage{ value: 1 }( diff --git a/packages/contracts-bedrock/test/L2/L2ERC721Bridge.t.sol b/packages/contracts-bedrock/test/L2/L2ERC721Bridge.t.sol index 6ee1312d94d77..b614711d101a0 100644 --- a/packages/contracts-bedrock/test/L2/L2ERC721Bridge.t.sol +++ b/packages/contracts-bedrock/test/L2/L2ERC721Bridge.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; // Testing -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Contracts import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; @@ -33,7 +33,7 @@ contract TestMintableERC721 is OptimismMintableERC721 { } } -contract L2ERC721Bridge_Test is Bridge_Initializer { +contract L2ERC721Bridge_Test is CommonTest { TestMintableERC721 internal localToken; TestERC721 internal remoteToken; uint256 internal constant tokenId = 1; @@ -227,6 +227,14 @@ contract L2ERC721Bridge_Test is Bridge_Initializer { assertEq(localToken.ownerOf(tokenId), alice); } + /// @dev Tests that `bridgeERC721To` reverts if the to address is the zero address. + function test_bridgeERC721To_toZeroAddress_reverts() external { + // Bridge the token. + vm.prank(bob); + vm.expectRevert("ERC721Bridge: nft recipient cannot be address(0)"); + l2ERC721Bridge.bridgeERC721To(address(localToken), address(remoteToken), address(0), tokenId, 1234, hex"5678"); + } + /// @dev Tests that `finalizeBridgeERC721` correctly finalizes a bridged token. function test_finalizeBridgeERC721_succeeds() external { // Bridge the token. @@ -240,7 +248,7 @@ contract L2ERC721Bridge_Test is Bridge_Initializer { // Finalize a withdrawal. vm.mockCall( address(l2CrossDomainMessenger), - abi.encodeWithSelector(l2CrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(l2CrossDomainMessenger.xDomainMessageSender, ()), abi.encode(l1ERC721Bridge) ); vm.prank(address(l2CrossDomainMessenger)); @@ -264,7 +272,7 @@ contract L2ERC721Bridge_Test is Bridge_Initializer { // to be compliant with the `IOptimismMintableERC721` interface. vm.mockCall( address(l2CrossDomainMessenger), - abi.encodeWithSelector(l2CrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(l2CrossDomainMessenger.xDomainMessageSender, ()), abi.encode(l1ERC721Bridge) ); vm.prank(address(l2CrossDomainMessenger)); @@ -287,7 +295,7 @@ contract L2ERC721Bridge_Test is Bridge_Initializer { // Finalize a withdrawal. vm.mockCall( address(l2CrossDomainMessenger), - abi.encodeWithSelector(l2CrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(l2CrossDomainMessenger.xDomainMessageSender, ()), abi.encode(alice) ); vm.prank(address(l2CrossDomainMessenger)); @@ -301,7 +309,7 @@ contract L2ERC721Bridge_Test is Bridge_Initializer { // Finalize a withdrawal. vm.mockCall( address(l2CrossDomainMessenger), - abi.encodeWithSelector(l2CrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(l2CrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1ERC721Bridge)) ); vm.prank(address(l2CrossDomainMessenger)); @@ -316,7 +324,7 @@ contract L2ERC721Bridge_Test is Bridge_Initializer { // Finalize a withdrawal. vm.mockCall( address(l2CrossDomainMessenger), - abi.encodeWithSelector(l2CrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(l2CrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1ERC721Bridge)) ); vm.prank(address(l2CrossDomainMessenger)); diff --git a/packages/contracts-bedrock/test/L2/L2Genesis.t.sol b/packages/contracts-bedrock/test/L2/L2Genesis.t.sol index 68fc374178eef..2398ac332df5e 100644 --- a/packages/contracts-bedrock/test/L2/L2Genesis.t.sol +++ b/packages/contracts-bedrock/test/L2/L2Genesis.t.sol @@ -22,32 +22,21 @@ contract L2GenesisTest is Test { /// @notice Creates a temp file and returns the path to it. function tmpfile() internal returns (string memory) { - string[] memory commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = "mktemp"; - bytes memory result = Process.run(commands); - return string(result); + return Process.bash("mktemp"); } /// @notice Deletes a file at a given filesystem path. Does not force delete /// and does not recursively delete. function deleteFile(string memory path) internal { - string[] memory commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = string.concat("rm ", path); - Process.run({ _command: commands, _allowEmpty: true }); + Process.bash(string.concat("rm ", path), true); } /// @notice Returns the number of top level keys in a JSON object at a given /// file path. function getJSONKeyCount(string memory path) internal returns (uint256) { - string[] memory commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = string.concat("jq 'keys | length' < ", path, " | xargs cast abi-encode 'f(uint256)'"); - return abi.decode(Process.run(commands), (uint256)); + bytes memory result = + bytes(Process.bash(string.concat("jq 'keys | length' < ", path, " | xargs cast abi-encode 'f(uint256)'"))); + return abi.decode(result, (uint256)); } /// @notice Helper function to run a function with a temporary dump file. @@ -59,43 +48,44 @@ contract L2GenesisTest is Test { /// @notice Helper function for reading the number of storage keys for a given account. function getStorageKeysCount(string memory _path, address _addr) internal returns (uint256) { - string[] memory commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = - string.concat("jq -r '.[\"", vm.toLowercase(vm.toString(_addr)), "\"].storage | length' < ", _path); - return vm.parseUint(string(Process.run(commands))); + return vm.parseUint( + Process.bash( + string.concat("jq -r '.[\"", vm.toLowercase(vm.toString(_addr)), "\"].storage | length' < ", _path) + ) + ); } /// @notice Returns the number of accounts that contain particular code at a given path to a genesis file. function getCodeCount(string memory path, string memory name) internal returns (uint256) { bytes memory code = vm.getDeployedCode(name); - string[] memory commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = string.concat( - "jq -r 'map_values(select(.code == \"", - vm.toString(code), - "\")) | length' < ", - path, - " | xargs cast abi-encode 'f(uint256)'" + bytes memory result = bytes( + Process.bash( + string.concat( + "jq -r 'map_values(select(.code == \"", + vm.toString(code), + "\")) | length' < ", + path, + " | xargs cast abi-encode 'f(uint256)'" + ) + ) ); - return abi.decode(Process.run(commands), (uint256)); + return abi.decode(result, (uint256)); } /// @notice Returns the number of accounts that have a particular slot set. function getPredeployCountWithSlotSet(string memory path, bytes32 slot) internal returns (uint256) { - string[] memory commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = string.concat( - "jq 'map_values(.storage | select(has(\"", - vm.toString(slot), - "\"))) | keys | length' < ", - path, - " | xargs cast abi-encode 'f(uint256)'" + bytes memory result = bytes( + Process.bash( + string.concat( + "jq 'map_values(.storage | select(has(\"", + vm.toString(slot), + "\"))) | keys | length' < ", + path, + " | xargs cast abi-encode 'f(uint256)'" + ) + ) ); - return abi.decode(Process.run(commands), (uint256)); + return abi.decode(result, (uint256)); } /// @notice Returns the number of accounts that have a particular slot set to a particular value. @@ -107,30 +97,31 @@ contract L2GenesisTest is Test { internal returns (uint256) { - string[] memory commands = new string[](3); - commands[0] = "bash"; - commands[1] = "-c"; - commands[2] = string.concat( - "jq 'map_values(.storage | select(.\"", - vm.toString(slot), - "\" == \"", - vm.toString(value), - "\")) | length' < ", - path, - " | xargs cast abi-encode 'f(uint256)'" + bytes memory result = bytes( + Process.bash( + string.concat( + "jq 'map_values(.storage | select(.\"", + vm.toString(slot), + "\" == \"", + vm.toString(value), + "\")) | length' < ", + path, + " | xargs cast abi-encode 'f(uint256)'" + ) + ) ); - return abi.decode(Process.run(commands), (uint256)); + return abi.decode(result, (uint256)); } /// @notice Tests the genesis predeploys setup using a temp file for the case where useInterop is false. - function test_genesis_predeploys_notUsingInterop() external { + function test_genesisPredeploys_notUsingInterop_works() external { string memory path = tmpfile(); _test_genesis_predeploys(path, false); deleteFile(path); } /// @notice Tests the genesis predeploys setup using a temp file for the case where useInterop is true. - function test_genesis_predeploys_usingInterop() external { + function test_genesisPredeploys_usingInterop_works() external { string memory path = tmpfile(); _test_genesis_predeploys(path, true); deleteFile(path); @@ -139,9 +130,7 @@ contract L2GenesisTest is Test { /// @notice Tests the genesis predeploys setup. function _test_genesis_predeploys(string memory _path, bool _useInterop) internal { // Set the useInterop value - vm.mockCall( - address(genesis.cfg()), abi.encodeWithSelector(genesis.cfg().useInterop.selector), abi.encode(_useInterop) - ); + vm.mockCall(address(genesis.cfg()), abi.encodeCall(genesis.cfg().useInterop, ()), abi.encode(_useInterop)); // Set the predeploy proxies into state genesis.setPredeployProxies(); @@ -165,12 +154,12 @@ contract L2GenesisTest is Test { } /// @notice Tests the number of accounts in the genesis setup - function test_allocs_size() external { + function test_allocs_size_works() external { withTempDump(_test_allocs_size); } /// @notice Creates mock L1Dependencies for testing purposes. - function _dummyL1Deps() internal pure returns (L1Dependencies memory _deps) { + function _dummyL1Deps() internal pure returns (L1Dependencies memory deps_) { return L1Dependencies({ l1CrossDomainMessengerProxy: payable(address(0x100000)), l1StandardBridgeProxy: payable(address(0x100001)), diff --git a/packages/contracts-bedrock/test/L2/L2StandardBridge.t.sol b/packages/contracts-bedrock/test/L2/L2StandardBridge.t.sol index 3a173e9743b45..fb68ce0931874 100644 --- a/packages/contracts-bedrock/test/L2/L2StandardBridge.t.sol +++ b/packages/contracts-bedrock/test/L2/L2StandardBridge.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.15; // Testing import { stdStorage, StdStorage } from "forge-std/Test.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Contracts import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; @@ -21,7 +21,7 @@ import { IStandardBridge } from "src/universal/interfaces/IStandardBridge.sol"; import { IL2ToL1MessagePasser } from "src/L2/interfaces/IL2ToL1MessagePasser.sol"; import { IL2StandardBridge } from "src/L2/interfaces/IL2StandardBridge.sol"; -contract L2StandardBridge_Test is Bridge_Initializer { +contract L2StandardBridge_Test is CommonTest { using stdStorage for StdStorage; /// @dev Test that the bridge's constructor sets the correct values. @@ -34,6 +34,7 @@ contract L2StandardBridge_Test is Bridge_Initializer { assertEq(address(impl.messenger()), Predeploys.L2_CROSS_DOMAIN_MESSENGER, "constructor zero check messenger"); assertEq(address(impl.OTHER_BRIDGE()), address(0), "constructor zero check OTHER_BRIDGE"); assertEq(address(impl.otherBridge()), address(0), "constructor zero check otherBridge"); + assertEq(address(impl.l1TokenBridge()), address(0), "constructor zero check l1TokenBridge"); } /// @dev Tests that the bridge is initialized correctly. @@ -56,17 +57,11 @@ contract L2StandardBridge_Test is Bridge_Initializer { assertEq(address(l2ToL1MessagePasser).balance, 0); uint256 nonce = l2CrossDomainMessenger.messageNonce(); - bytes memory message = - abi.encodeWithSelector(IStandardBridge.finalizeBridgeETH.selector, alice, alice, 100, hex""); + bytes memory message = abi.encodeCall(IStandardBridge.finalizeBridgeETH, (alice, alice, 100, hex"")); uint64 baseGas = l2CrossDomainMessenger.baseGas(message, 200_000); - bytes memory withdrawalData = abi.encodeWithSelector( - ICrossDomainMessenger.relayMessage.selector, - nonce, - address(l2StandardBridge), - address(l1StandardBridge), - 100, - 200_000, - message + bytes memory withdrawalData = abi.encodeCall( + ICrossDomainMessenger.relayMessage, + (nonce, address(l2StandardBridge), address(l1StandardBridge), 100, 200_000, message) ); bytes32 withdrawalHash = Hashing.hashWithdrawal( Types.WithdrawalTransaction({ @@ -107,21 +102,16 @@ contract L2StandardBridge_Test is Bridge_Initializer { vm.expectCall( address(l2CrossDomainMessenger), - abi.encodeWithSelector( - ICrossDomainMessenger.sendMessage.selector, - address(l1StandardBridge), - message, - 200_000 // StandardBridge's RECEIVE_DEFAULT_GAS_LIMIT + abi.encodeCall( + ICrossDomainMessenger.sendMessage, + (address(l1StandardBridge), message, 200_000) // StandardBridge's RECEIVE_DEFAULT_GAS_LIMIT ) ); vm.expectCall( Predeploys.L2_TO_L1_MESSAGE_PASSER, - abi.encodeWithSelector( - IL2ToL1MessagePasser.initiateWithdrawal.selector, - address(l1CrossDomainMessenger), - baseGas, - withdrawalData + abi.encodeCall( + IL2ToL1MessagePasser.initiateWithdrawal, (address(l1CrossDomainMessenger), baseGas, withdrawalData) ) ); @@ -134,7 +124,7 @@ contract L2StandardBridge_Test is Bridge_Initializer { /// @dev Tests that the receive function reverts with custom gas token. function testFuzz_receive_customGasToken_reverts(uint256 _value) external { vm.prank(alice, alice); - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2))); + vm.mockCall(address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))); vm.deal(alice, _value); (bool success, bytes memory data) = address(l2StandardBridge).call{ value: _value }(hex""); assertFalse(success); @@ -173,7 +163,9 @@ contract L2StandardBridge_Test is Bridge_Initializer { /// @dev Tests that `withdraw` reverts with custom gas token. function test_withdraw_customGasToken_reverts() external { - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(18))); + vm.mockCall( + address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(18)) + ); vm.expectRevert("L2StandardBridge: not supported with custom gas token"); vm.prank(alice, alice); l2StandardBridge.withdraw(address(Predeploys.LEGACY_ERC20_ETH), 1, 1, hex""); @@ -181,7 +173,9 @@ contract L2StandardBridge_Test is Bridge_Initializer { /// @dev Tests that `withdraw` reverts with custom gas token. function test_withdrawERC20_customGasToken_reverts() external { - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(18))); + vm.mockCall( + address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(18)) + ); vm.expectRevert("L2StandardBridge: not supported with custom gas token"); vm.prank(alice, alice); l2StandardBridge.withdraw(address(L1Token), 1, 1, hex""); @@ -190,7 +184,9 @@ contract L2StandardBridge_Test is Bridge_Initializer { /// @dev Tests that `withdraw` reverts with custom gas token. function test_withdrawERC20WithValue_customGasToken_reverts() external { vm.deal(alice, 1 ether); - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(18))); + vm.mockCall( + address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(18)) + ); vm.expectRevert("L2StandardBridge: not supported with custom gas token"); vm.prank(alice, alice); l2StandardBridge.withdraw{ value: 1 ether }(address(L1Token), 1, 1, hex""); @@ -199,7 +195,9 @@ contract L2StandardBridge_Test is Bridge_Initializer { /// @dev Tests that `withdraw` with value reverts with custom gas token. function test_withdraw_customGasTokenWithValue_reverts() external { vm.deal(alice, 1 ether); - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(18))); + vm.mockCall( + address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(18)) + ); vm.expectRevert("L2StandardBridge: not supported with custom gas token"); vm.prank(alice, alice); l2StandardBridge.withdraw{ value: 1 ether }(address(Predeploys.LEGACY_ERC20_ETH), 1, 1, hex""); @@ -207,7 +205,9 @@ contract L2StandardBridge_Test is Bridge_Initializer { /// @dev Tests that `withdrawTo` reverts with custom gas token. function test_withdrawTo_customGasToken_reverts() external { - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(18))); + vm.mockCall( + address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(18)) + ); vm.expectRevert("L2StandardBridge: not supported with custom gas token"); vm.prank(alice, alice); l2StandardBridge.withdrawTo(address(Predeploys.LEGACY_ERC20_ETH), bob, 1, 1, hex""); @@ -215,7 +215,9 @@ contract L2StandardBridge_Test is Bridge_Initializer { /// @dev Tests that `withdrawTo` reverts with custom gas token. function test_withdrawToERC20_customGasToken_reverts() external { - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(18))); + vm.mockCall( + address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(18)) + ); vm.expectRevert("L2StandardBridge: not supported with custom gas token"); vm.prank(alice, alice); l2StandardBridge.withdrawTo(address(L2Token), bob, 1, 1, hex""); @@ -224,7 +226,9 @@ contract L2StandardBridge_Test is Bridge_Initializer { /// @dev Tests that `withdrawTo` reverts with custom gas token. function test_withdrawToERC20WithValue_customGasToken_reverts() external { vm.deal(alice, 1 ether); - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(18))); + vm.mockCall( + address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(18)) + ); vm.expectRevert("L2StandardBridge: not supported with custom gas token"); vm.prank(alice, alice); l2StandardBridge.withdrawTo{ value: 1 ether }(address(L2Token), bob, 1, 1, hex""); @@ -233,7 +237,9 @@ contract L2StandardBridge_Test is Bridge_Initializer { /// @dev Tests that `withdrawTo` with value reverts with custom gas token. function test_withdrawTo_customGasTokenWithValue_reverts() external { vm.deal(alice, 1 ether); - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(18))); + vm.mockCall( + address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(18)) + ); vm.expectRevert("L2StandardBridge: not supported with custom gas token"); vm.prank(alice, alice); l2StandardBridge.withdrawTo{ value: 1 ether }(address(Predeploys.LEGACY_ERC20_ETH), bob, 1, 1, hex""); @@ -270,25 +276,19 @@ contract L2StandardBridge_Test is Bridge_Initializer { } } -contract PreBridgeERC20 is Bridge_Initializer { +contract PreBridgeERC20 is CommonTest { /// @dev Sets up expected calls and emits for a successful ERC20 withdrawal. function _preBridgeERC20(bool _isLegacy, address _l2Token) internal { // Alice has 100 L2Token deal(_l2Token, alice, 100, true); assertEq(ERC20(_l2Token).balanceOf(alice), 100); uint256 nonce = l2CrossDomainMessenger.messageNonce(); - bytes memory message = abi.encodeWithSelector( - IStandardBridge.finalizeBridgeERC20.selector, address(L1Token), _l2Token, alice, alice, 100, hex"" - ); + bytes memory message = + abi.encodeCall(IStandardBridge.finalizeBridgeERC20, (address(L1Token), _l2Token, alice, alice, 100, hex"")); uint64 baseGas = l2CrossDomainMessenger.baseGas(message, 1000); - bytes memory withdrawalData = abi.encodeWithSelector( - ICrossDomainMessenger.relayMessage.selector, - nonce, - address(l2StandardBridge), - address(l1StandardBridge), - 0, - 1000, - message + bytes memory withdrawalData = abi.encodeCall( + ICrossDomainMessenger.relayMessage, + (nonce, address(l2StandardBridge), address(l1StandardBridge), 0, 1000, message) ); bytes32 withdrawalHash = Hashing.hashWithdrawal( Types.WithdrawalTransaction({ @@ -303,35 +303,29 @@ contract PreBridgeERC20 is Bridge_Initializer { if (_isLegacy) { vm.expectCall( - address(l2StandardBridge), - abi.encodeWithSelector(l2StandardBridge.withdraw.selector, _l2Token, 100, 1000, hex"") + address(l2StandardBridge), abi.encodeCall(l2StandardBridge.withdraw, (_l2Token, 100, 1000, hex"")) ); } else { vm.expectCall( address(l2StandardBridge), - abi.encodeWithSelector( - l2StandardBridge.bridgeERC20.selector, _l2Token, address(L1Token), 100, 1000, hex"" - ) + abi.encodeCall(l2StandardBridge.bridgeERC20, (_l2Token, address(L1Token), 100, 1000, hex"")) ); } vm.expectCall( address(l2CrossDomainMessenger), - abi.encodeWithSelector(ICrossDomainMessenger.sendMessage.selector, address(l1StandardBridge), message, 1000) + abi.encodeCall(ICrossDomainMessenger.sendMessage, (address(l1StandardBridge), message, 1000)) ); vm.expectCall( Predeploys.L2_TO_L1_MESSAGE_PASSER, - abi.encodeWithSelector( - IL2ToL1MessagePasser.initiateWithdrawal.selector, - address(l1CrossDomainMessenger), - baseGas, - withdrawalData + abi.encodeCall( + IL2ToL1MessagePasser.initiateWithdrawal, (address(l1CrossDomainMessenger), baseGas, withdrawalData) ) ); // The l2StandardBridge should burn the tokens - vm.expectCall(_l2Token, abi.encodeWithSelector(OptimismMintableERC20.burn.selector, alice, 100)); + vm.expectCall(_l2Token, abi.encodeCall(OptimismMintableERC20.burn, (alice, 100))); vm.expectEmit(true, true, true, true); emit WithdrawalInitiated(address(L1Token), _l2Token, alice, alice, 100, hex""); @@ -385,6 +379,12 @@ contract L2StandardBridge_BridgeERC20_Test is PreBridgeERC20 { assertEq(L2Token.balanceOf(alice), 0); } + function test_bridgeERC20_isNotCorrectTokenPair_reverts() external { + vm.expectRevert("StandardBridge: wrong remote token for Optimism Mintable ERC20 local token"); + vm.prank(alice, alice); + l2StandardBridge.bridgeERC20(address(L2Token), address(BadL1Token), 100, 1000, hex""); + } + function test_withdrawLegacyERC20_succeeds() external { _preBridgeERC20({ _isLegacy: true, _l2Token: address(LegacyL2Token) }); l2StandardBridge.withdraw(address(LegacyL2Token), 100, 1000, hex""); @@ -408,25 +408,19 @@ contract L2StandardBridge_BridgeERC20_Test is PreBridgeERC20 { } } -contract PreBridgeERC20To is Bridge_Initializer { +contract PreBridgeERC20To is CommonTest { // withdrawTo and BridgeERC20To should behave the same when transferring ERC20 tokens // so they should share the same setup and expectEmit calls function _preBridgeERC20To(bool _isLegacy, address _l2Token) internal { deal(_l2Token, alice, 100, true); assertEq(ERC20(L2Token).balanceOf(alice), 100); uint256 nonce = l2CrossDomainMessenger.messageNonce(); - bytes memory message = abi.encodeWithSelector( - IStandardBridge.finalizeBridgeERC20.selector, address(L1Token), _l2Token, alice, bob, 100, hex"" - ); + bytes memory message = + abi.encodeCall(IStandardBridge.finalizeBridgeERC20, (address(L1Token), _l2Token, alice, bob, 100, hex"")); uint64 baseGas = l2CrossDomainMessenger.baseGas(message, 1000); - bytes memory withdrawalData = abi.encodeWithSelector( - ICrossDomainMessenger.relayMessage.selector, - nonce, - address(l2StandardBridge), - address(l1StandardBridge), - 0, - 1000, - message + bytes memory withdrawalData = abi.encodeCall( + ICrossDomainMessenger.relayMessage, + (nonce, address(l2StandardBridge), address(l1StandardBridge), 0, 1000, message) ); bytes32 withdrawalHash = Hashing.hashWithdrawal( Types.WithdrawalTransaction({ @@ -467,34 +461,29 @@ contract PreBridgeERC20To is Bridge_Initializer { if (_isLegacy) { vm.expectCall( address(l2StandardBridge), - abi.encodeWithSelector(l2StandardBridge.withdrawTo.selector, _l2Token, bob, 100, 1000, hex"") + abi.encodeCall(l2StandardBridge.withdrawTo, (_l2Token, bob, 100, 1000, hex"")) ); } else { vm.expectCall( address(l2StandardBridge), - abi.encodeWithSelector( - l2StandardBridge.bridgeERC20To.selector, _l2Token, address(L1Token), bob, 100, 1000, hex"" - ) + abi.encodeCall(l2StandardBridge.bridgeERC20To, (_l2Token, address(L1Token), bob, 100, 1000, hex"")) ); } vm.expectCall( address(l2CrossDomainMessenger), - abi.encodeWithSelector(ICrossDomainMessenger.sendMessage.selector, address(l1StandardBridge), message, 1000) + abi.encodeCall(ICrossDomainMessenger.sendMessage, (address(l1StandardBridge), message, 1000)) ); vm.expectCall( Predeploys.L2_TO_L1_MESSAGE_PASSER, - abi.encodeWithSelector( - IL2ToL1MessagePasser.initiateWithdrawal.selector, - address(l1CrossDomainMessenger), - baseGas, - withdrawalData + abi.encodeCall( + IL2ToL1MessagePasser.initiateWithdrawal, (address(l1CrossDomainMessenger), baseGas, withdrawalData) ) ); // The l2StandardBridge should burn the tokens - vm.expectCall(address(L2Token), abi.encodeWithSelector(OptimismMintableERC20.burn.selector, alice, 100)); + vm.expectCall(address(L2Token), abi.encodeCall(OptimismMintableERC20.burn, (alice, 100))); vm.prank(alice, alice); } @@ -519,12 +508,12 @@ contract L2StandardBridge_BridgeERC20To_Test is PreBridgeERC20To { } } -contract L2StandardBridge_Bridge_Test is Bridge_Initializer { +contract L2StandardBridge_Bridge_Test is CommonTest { /// @dev Tests that `finalizeBridgeETH` reverts if the recipient is the other bridge. function test_finalizeBridgeETH_sendToSelf_reverts() external { vm.mockCall( address(l2StandardBridge.messenger()), - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l2StandardBridge.OTHER_BRIDGE())) ); vm.deal(address(l2CrossDomainMessenger), 100); @@ -537,7 +526,7 @@ contract L2StandardBridge_Bridge_Test is Bridge_Initializer { function test_finalizeBridgeETH_sendToMessenger_reverts() external { vm.mockCall( address(l2StandardBridge.messenger()), - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l2StandardBridge.OTHER_BRIDGE())) ); vm.deal(address(l2CrossDomainMessenger), 100); @@ -550,21 +539,16 @@ contract L2StandardBridge_Bridge_Test is Bridge_Initializer { function testFuzz_bridgeETH_succeeds(uint256 _value, uint32 _minGasLimit, bytes calldata _extraData) external { uint256 nonce = l2CrossDomainMessenger.messageNonce(); - bytes memory message = - abi.encodeWithSelector(IStandardBridge.finalizeBridgeETH.selector, alice, alice, _value, _extraData); + bytes memory message = abi.encodeCall(IStandardBridge.finalizeBridgeETH, (alice, alice, _value, _extraData)); vm.expectCall( - address(l2StandardBridge), - _value, - abi.encodeWithSelector(l2StandardBridge.bridgeETH.selector, _minGasLimit, _extraData) + address(l2StandardBridge), _value, abi.encodeCall(l2StandardBridge.bridgeETH, (_minGasLimit, _extraData)) ); vm.expectCall( address(l2CrossDomainMessenger), _value, - abi.encodeWithSelector( - ICrossDomainMessenger.sendMessage.selector, address(l1StandardBridge), message, _minGasLimit - ) + abi.encodeCall(ICrossDomainMessenger.sendMessage, (address(l1StandardBridge), message, _minGasLimit)) ); vm.expectEmit(address(l2StandardBridge)); @@ -587,7 +571,7 @@ contract L2StandardBridge_Bridge_Test is Bridge_Initializer { /// @dev Tests that bridging reverts with custom gas token. function test_bridgeETH_customGasToken_reverts() external { vm.prank(alice, alice); - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2))); + vm.mockCall(address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))); vm.expectRevert("StandardBridge: cannot bridge ETH with custom gas token"); l2StandardBridge.bridgeETH(50000, hex"dead"); @@ -600,19 +584,16 @@ contract L2StandardBridge_Bridge_Test is Bridge_Initializer { vm.expectCall( address(l2StandardBridge), _value, - abi.encodeWithSelector(l1StandardBridge.bridgeETHTo.selector, bob, _minGasLimit, _extraData) + abi.encodeCall(l1StandardBridge.bridgeETHTo, (bob, _minGasLimit, _extraData)) ); - bytes memory message = - abi.encodeWithSelector(IStandardBridge.finalizeBridgeETH.selector, alice, bob, _value, _extraData); + bytes memory message = abi.encodeCall(IStandardBridge.finalizeBridgeETH, (alice, bob, _value, _extraData)); // the L2 bridge should call // L2CrossDomainMessenger.sendMessage vm.expectCall( address(l2CrossDomainMessenger), - abi.encodeWithSelector( - ICrossDomainMessenger.sendMessage.selector, address(l1StandardBridge), message, _minGasLimit - ) + abi.encodeCall(ICrossDomainMessenger.sendMessage, (address(l1StandardBridge), message, _minGasLimit)) ); vm.expectEmit(address(l2StandardBridge)); @@ -641,20 +622,20 @@ contract L2StandardBridge_Bridge_Test is Bridge_Initializer { ) external { - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2))); + vm.mockCall(address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))); vm.expectRevert("StandardBridge: cannot bridge ETH with custom gas token"); vm.deal(address(this), _value); l2StandardBridge.bridgeETHTo{ value: _value }(bob, _minGasLimit, _extraData); } } -contract L2StandardBridge_FinalizeBridgeETH_Test is Bridge_Initializer { +contract L2StandardBridge_FinalizeBridgeETH_Test is CommonTest { /// @dev Tests that `finalizeBridgeETH` succeeds. function test_finalizeBridgeETH_succeeds() external { address messenger = address(l2StandardBridge.messenger()); vm.mockCall( messenger, - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l2StandardBridge.OTHER_BRIDGE())) ); vm.deal(messenger, 100); @@ -674,14 +655,54 @@ contract L2StandardBridge_FinalizeBridgeETH_Test is Bridge_Initializer { address messenger = address(l2StandardBridge.messenger()); vm.mockCall( messenger, - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l2StandardBridge.OTHER_BRIDGE())) ); vm.deal(address(l2CrossDomainMessenger), 1); vm.prank(address(l2CrossDomainMessenger)); - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingToken()"), abi.encode(address(1), uint8(2))); + vm.mockCall(address(l1Block), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))); vm.expectRevert("StandardBridge: cannot bridge ETH with custom gas token"); l2StandardBridge.finalizeBridgeETH(alice, alice, 1, hex""); } } + +contract L2StandardBridge_FinalizeBridgeERC20_Test is CommonTest { + /// @dev Tests that `finalizeBridgeERC20` succeeds. + function test_finalizeBridgeERC20_succeeds() external { + address messenger = address(l2StandardBridge.messenger()); + address localToken = address(L2Token); + address remoteToken = address(L1Token); + vm.mockCall( + messenger, + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), + abi.encode(address(l2StandardBridge.OTHER_BRIDGE())) + ); + deal(localToken, messenger, 100, true); + vm.prank(messenger); + + vm.expectEmit(true, true, true, true); + emit DepositFinalized(remoteToken, localToken, alice, alice, 100, hex""); + + vm.expectEmit(true, true, true, true); + emit ERC20BridgeFinalized(localToken, remoteToken, alice, alice, 100, hex""); + + l2StandardBridge.finalizeBridgeERC20(localToken, remoteToken, alice, alice, 100, hex""); + } + + function test_finalizeBridgeERC20_isNotCorrectTokenPair_reverts() external { + address messenger = address(l2StandardBridge.messenger()); + address localToken = address(L2Token); + address remoteToken = address(BadL1Token); + vm.mockCall( + messenger, + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), + abi.encode(address(l2StandardBridge.OTHER_BRIDGE())) + ); + deal(localToken, messenger, 100, true); + vm.prank(messenger); + + vm.expectRevert("StandardBridge: wrong remote token for Optimism Mintable ERC20 local token"); + l2StandardBridge.finalizeBridgeERC20(localToken, remoteToken, alice, alice, 100, hex""); + } +} diff --git a/packages/contracts-bedrock/test/L2/L2StandardBridgeInterop.t.sol b/packages/contracts-bedrock/test/L2/L2StandardBridgeInterop.t.sol index e57bc89776592..30212d7ad622c 100644 --- a/packages/contracts-bedrock/test/L2/L2StandardBridgeInterop.t.sol +++ b/packages/contracts-bedrock/test/L2/L2StandardBridgeInterop.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; // Testing -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Interfaces import { IMintableAndBurnableERC20 } from "src/L2/interfaces/IMintableAndBurnableERC20.sol"; @@ -13,7 +13,7 @@ import { IOptimismMintableERC20 } from "src/universal/interfaces/IOptimismMintab import { ILegacyMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; import { IOptimismERC20Factory } from "src/L2/interfaces/IOptimismERC20Factory.sol"; -contract L2StandardBridgeInterop_Test is Bridge_Initializer { +contract L2StandardBridgeInterop_Test is CommonTest { /// @notice Emitted when a conversion is made. event Converted(address indexed from, address indexed to, address indexed caller, uint256 amount); @@ -31,21 +31,17 @@ contract L2StandardBridgeInterop_Test is Bridge_Initializer { /// @notice Mock ERC20 decimals function _mockDecimals(address _token, uint8 _decimals) internal { - _mockAndExpect(_token, abi.encodeWithSelector(IERC20Metadata.decimals.selector), abi.encode(_decimals)); + _mockAndExpect(_token, abi.encodeCall(IERC20Metadata.decimals, ()), abi.encode(_decimals)); } /// @notice Mock ERC165 interface function _mockInterface(address _token, bytes4 _interfaceId, bool _supported) internal { - _mockAndExpect( - _token, abi.encodeWithSelector(IERC165.supportsInterface.selector, _interfaceId), abi.encode(_supported) - ); + _mockAndExpect(_token, abi.encodeCall(IERC165.supportsInterface, (_interfaceId)), abi.encode(_supported)); } /// @notice Mock factory deployment function _mockDeployments(address _factory, address _token, address _deployed) internal { - _mockAndExpect( - _factory, abi.encodeWithSelector(IOptimismERC20Factory.deployments.selector, _token), abi.encode(_deployed) - ); + _mockAndExpect(_factory, abi.encodeCall(IOptimismERC20Factory.deployments, (_token)), abi.encode(_deployed)); } /// @notice Assume a valid address for fuzzing @@ -198,12 +194,8 @@ contract L2StandardBridgeInterop_LegacyToSuper_Test is L2StandardBridgeInterop_T emit Converted(_from, _to, _caller, _amount); // Mock and expect the `burn` and `mint` functions - _mockAndExpect( - _from, abi.encodeWithSelector(IMintableAndBurnableERC20.burn.selector, _caller, _amount), abi.encode() - ); - _mockAndExpect( - _to, abi.encodeWithSelector(IMintableAndBurnableERC20.mint.selector, _caller, _amount), abi.encode() - ); + _mockAndExpect(_from, abi.encodeCall(IMintableAndBurnableERC20.burn, (_caller, _amount)), abi.encode()); + _mockAndExpect(_to, abi.encodeCall(IMintableAndBurnableERC20.mint, (_caller, _amount)), abi.encode()); // Act vm.prank(_caller); @@ -356,12 +348,8 @@ contract L2StandardBridgeInterop_SuperToLegacy_Test is L2StandardBridgeInterop_T emit Converted(_from, _to, _caller, _amount); // Mock and expect the `burn` and `mint` functions - _mockAndExpect( - _from, abi.encodeWithSelector(IMintableAndBurnableERC20.burn.selector, _caller, _amount), abi.encode() - ); - _mockAndExpect( - _to, abi.encodeWithSelector(IMintableAndBurnableERC20.mint.selector, _caller, _amount), abi.encode() - ); + _mockAndExpect(_from, abi.encodeCall(IMintableAndBurnableERC20.burn, (_caller, _amount)), abi.encode()); + _mockAndExpect(_to, abi.encodeCall(IMintableAndBurnableERC20.mint, (_caller, _amount)), abi.encode()); // Act vm.prank(_caller); diff --git a/packages/contracts-bedrock/test/L2/L2ToL2CrossDomainMessenger.t.sol b/packages/contracts-bedrock/test/L2/L2ToL2CrossDomainMessenger.t.sol index 36b36973af8da..1e5e04edc25b5 100644 --- a/packages/contracts-bedrock/test/L2/L2ToL2CrossDomainMessenger.t.sol +++ b/packages/contracts-bedrock/test/L2/L2ToL2CrossDomainMessenger.t.sol @@ -10,8 +10,7 @@ import { Predeploys } from "src/libraries/Predeploys.sol"; import { Hashing } from "src/libraries/Hashing.sol"; // Target contract -import { CrossL2Inbox } from "src/L2/CrossL2Inbox.sol"; -import { ICrossL2Inbox } from "src/L2/interfaces/ICrossL2Inbox.sol"; +import { CrossL2Inbox, Identifier } from "src/L2/CrossL2Inbox.sol"; import { L2ToL2CrossDomainMessenger, NotEntered, @@ -218,8 +217,8 @@ contract L2ToL2CrossDomainMessengerTest is Test { vm.mockCall({ callee: _target, msgValue: _value, data: _message, returnData: abi.encode(true) }); // Construct the SentMessage payload & identifier - ICrossL2Inbox.Identifier memory id = - ICrossL2Inbox.Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); + Identifier memory id = + Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); bytes memory sentMessage = abi.encodePacked( abi.encode(L2ToL2CrossDomainMessenger.SentMessage.selector, block.chainid, _target, _nonce), // topics abi.encode(_sender, _message) // data @@ -228,7 +227,7 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Ensure the CrossL2Inbox validates this message vm.mockCall({ callee: Predeploys.CROSS_L2_INBOX, - data: abi.encodeWithSelector(CrossL2Inbox.validateMessage.selector, id, sentMessage), + data: abi.encodeCall(CrossL2Inbox.validateMessage, (id, keccak256(sentMessage))), returnData: "" }); @@ -264,15 +263,15 @@ contract L2ToL2CrossDomainMessengerTest is Test { vm.expectRevert(EventPayloadNotSentMessage.selector); // Point to a different remote log that the inbox validates - ICrossL2Inbox.Identifier memory id = - ICrossL2Inbox.Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); + Identifier memory id = + Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); bytes memory sentMessage = abi.encode(L2ToL2CrossDomainMessenger.RelayedMessage.selector, _source, _nonce, _msgHash); // Ensure the CrossL2Inbox validates this message vm.mockCall({ callee: Predeploys.CROSS_L2_INBOX, - data: abi.encodeWithSelector(CrossL2Inbox.validateMessage.selector, id, sentMessage), + data: abi.encodeCall(CrossL2Inbox.validateMessage, (id, keccak256(sentMessage))), returnData: "" }); @@ -313,7 +312,7 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Set the target and message for the reentrant call address target = address(this); - bytes memory message = abi.encodeWithSelector(this.mockTarget.selector, _source, _sender); + bytes memory message = abi.encodeCall(this.mockTarget, (_source, _sender)); bytes32 msgHash = keccak256(abi.encode(block.chainid, _source, _nonce, _sender, target, message)); @@ -325,8 +324,8 @@ contract L2ToL2CrossDomainMessengerTest is Test { vm.expectCall({ callee: target, msgValue: _value, data: message }); // Construct and relay the message - ICrossL2Inbox.Identifier memory id = - ICrossL2Inbox.Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); + Identifier memory id = + Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); bytes memory sentMessage = abi.encodePacked( abi.encode(L2ToL2CrossDomainMessenger.SentMessage.selector, block.chainid, target, _nonce), // topics abi.encode(_sender, message) // data @@ -335,7 +334,7 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Ensure the CrossL2Inbox validates this message vm.mockCall({ callee: Predeploys.CROSS_L2_INBOX, - data: abi.encodeWithSelector(CrossL2Inbox.validateMessage.selector, id, sentMessage), + data: abi.encodeCall(CrossL2Inbox.validateMessage, (id, keccak256(sentMessage))), returnData: "" }); @@ -368,8 +367,7 @@ contract L2ToL2CrossDomainMessengerTest is Test { vm.expectRevert(ReentrantCall.selector); - ICrossL2Inbox.Identifier memory id = - ICrossL2Inbox.Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, 1, 1, 1, _source); + Identifier memory id = Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, 1, 1, 1, _source); bytes memory sentMessage = abi.encodePacked( abi.encode(L2ToL2CrossDomainMessenger.SentMessage.selector, block.chainid, address(0), _nonce), // topics abi.encode(_sender, "") // data @@ -401,14 +399,14 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Set the target and message for the reentrant call address target = address(this); - bytes memory message = abi.encodeWithSelector(this.mockTargetReentrant.selector, _source2, _nonce, _sender2); + bytes memory message = abi.encodeCall(this.mockTargetReentrant, (_source2, _nonce, _sender2)); // Ensure the target contract is called with the correct parameters vm.expectCall({ callee: target, msgValue: _value, data: message }); // Construct and relay the message - ICrossL2Inbox.Identifier memory id = - ICrossL2Inbox.Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source1); + Identifier memory id = + Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source1); bytes memory sentMessage = abi.encodePacked( abi.encode(L2ToL2CrossDomainMessenger.SentMessage.selector, block.chainid, target, _nonce), // topics abi.encode(_sender1, message) // data @@ -417,7 +415,7 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Ensure the CrossL2Inbox validates this message vm.mockCall({ callee: Predeploys.CROSS_L2_INBOX, - data: abi.encodeWithSelector(CrossL2Inbox.validateMessage.selector, id, sentMessage), + data: abi.encodeCall(CrossL2Inbox.validateMessage, (id, keccak256(sentMessage))), returnData: "" }); @@ -457,7 +455,7 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Expect a revert with the IdOriginNotL2ToL2CrossDomainMessenger vm.expectRevert(IdOriginNotL2ToL2CrossDomainMessenger.selector); - ICrossL2Inbox.Identifier memory id = ICrossL2Inbox.Identifier(_origin, _blockNum, _logIndex, _time, _source); + Identifier memory id = Identifier(_origin, _blockNum, _logIndex, _time, _source); bytes memory sentMessage = abi.encodePacked( abi.encode(L2ToL2CrossDomainMessenger.SentMessage.selector, block.chainid, _target, _nonce), // topics abi.encode(_sender, _message) // data @@ -489,8 +487,8 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Expect a revert with the MessageDestinationNotRelayChain selector vm.expectRevert(MessageDestinationNotRelayChain.selector); - ICrossL2Inbox.Identifier memory id = - ICrossL2Inbox.Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); + Identifier memory id = + Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); bytes memory sentMessage = abi.encodePacked( abi.encode(L2ToL2CrossDomainMessenger.SentMessage.selector, _destination, _target, _nonce), // topics abi.encode(_sender, _message) // data @@ -499,7 +497,7 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Ensure the CrossL2Inbox validates this message vm.mockCall({ callee: Predeploys.CROSS_L2_INBOX, - data: abi.encodeWithSelector(CrossL2Inbox.validateMessage.selector, id, sentMessage), + data: abi.encodeCall(CrossL2Inbox.validateMessage, (id, keccak256(sentMessage))), returnData: "" }); @@ -526,8 +524,8 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Call `relayMessage` with CrossL2Inbox as the target to provoke revert. The current chain is the destination // to prevent revert due to invalid destination - ICrossL2Inbox.Identifier memory id = - ICrossL2Inbox.Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); + Identifier memory id = + Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); bytes memory sentMessage = abi.encodePacked( abi.encode( L2ToL2CrossDomainMessenger.SentMessage.selector, block.chainid, Predeploys.CROSS_L2_INBOX, _nonce @@ -538,7 +536,7 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Ensure the CrossL2Inbox validates this message vm.mockCall({ callee: Predeploys.CROSS_L2_INBOX, - data: abi.encodeWithSelector(CrossL2Inbox.validateMessage.selector, id, sentMessage), + data: abi.encodeCall(CrossL2Inbox.validateMessage, (id, keccak256(sentMessage))), returnData: "" }); @@ -565,8 +563,8 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Call `relayMessage` with L2ToL2CrossDomainMessenger as the target to provoke revert. The current chain is the // destination to prevent revert due to invalid destination - ICrossL2Inbox.Identifier memory id = - ICrossL2Inbox.Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); + Identifier memory id = + Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); bytes memory sentMessage = abi.encodePacked( abi.encode( L2ToL2CrossDomainMessenger.SentMessage.selector, @@ -580,7 +578,7 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Ensure the CrossL2Inbox validates this message vm.mockCall({ callee: Predeploys.CROSS_L2_INBOX, - data: abi.encodeWithSelector(CrossL2Inbox.validateMessage.selector, id, sentMessage), + data: abi.encodeCall(CrossL2Inbox.validateMessage, (id, keccak256(sentMessage))), returnData: "" }); @@ -620,8 +618,8 @@ contract L2ToL2CrossDomainMessengerTest is Test { _source, _nonce, keccak256(abi.encode(block.chainid, _source, _nonce, _sender, _target, _message)) ); - ICrossL2Inbox.Identifier memory id = - ICrossL2Inbox.Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); + Identifier memory id = + Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); bytes memory sentMessage = abi.encodePacked( abi.encode(L2ToL2CrossDomainMessenger.SentMessage.selector, block.chainid, _target, _nonce), // topics abi.encode(_sender, _message) // data @@ -630,7 +628,7 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Ensure the CrossL2Inbox validates this message vm.mockCall({ callee: Predeploys.CROSS_L2_INBOX, - data: abi.encodeWithSelector(CrossL2Inbox.validateMessage.selector, id, sentMessage), + data: abi.encodeCall(CrossL2Inbox.validateMessage, (id, keccak256(sentMessage))), returnData: "" }); @@ -670,8 +668,8 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Ensure that the target contract reverts vm.mockCallRevert({ callee: _target, msgValue: _value, data: _message, revertData: abi.encode(false) }); - ICrossL2Inbox.Identifier memory id = - ICrossL2Inbox.Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); + Identifier memory id = + Identifier(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, _blockNum, _logIndex, _time, _source); bytes memory sentMessage = abi.encodePacked( abi.encode(L2ToL2CrossDomainMessenger.SentMessage.selector, block.chainid, _target, _nonce), // topics abi.encode(_sender, _message) // data @@ -680,7 +678,7 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Ensure the CrossL2Inbox validates this message vm.mockCall({ callee: Predeploys.CROSS_L2_INBOX, - data: abi.encodeWithSelector(CrossL2Inbox.validateMessage.selector, id, sentMessage), + data: abi.encodeCall(CrossL2Inbox.validateMessage, (id, keccak256(sentMessage))), returnData: "" }); diff --git a/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20.t.sol b/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20.t.sol index 825e09bdd8085..d5b999a922e5d 100644 --- a/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20.t.sol +++ b/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20.t.sol @@ -7,18 +7,19 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; -import { IERC20Solady as IERC20 } from "src/vendor/interfaces/IERC20Solady.sol"; import { Initializable } from "@openzeppelin/contracts-v5/proxy/utils/Initializable.sol"; import { IERC165 } from "@openzeppelin/contracts-v5/utils/introspection/IERC165.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { IERC7802 } from "src/L2/interfaces/IERC7802.sol"; import { IBeacon } from "@openzeppelin/contracts-v5/proxy/beacon/IBeacon.sol"; import { BeaconProxy } from "@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy.sol"; import { Unauthorized } from "src/libraries/errors/CommonErrors.sol"; import { Preinstalls } from "src/libraries/Preinstalls.sol"; // Target contract -import { OptimismSuperchainERC20 } from "src/L2/OptimismSuperchainERC20.sol"; import { IOptimismSuperchainERC20 } from "src/L2/interfaces/IOptimismSuperchainERC20.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; /// @title OptimismSuperchainERC20Test /// @notice Contract for testing the OptimismSuperchainERC20 contract. @@ -31,12 +32,17 @@ contract OptimismSuperchainERC20Test is Test { address internal constant L2_BRIDGE = Predeploys.L2_STANDARD_BRIDGE; address internal constant MESSENGER = Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER; - OptimismSuperchainERC20 public optimismSuperchainERC20Impl; - OptimismSuperchainERC20 public optimismSuperchainERC20; + IOptimismSuperchainERC20 public optimismSuperchainERC20Impl; + IOptimismSuperchainERC20 public optimismSuperchainERC20; /// @notice Sets up the test suite. function setUp() public { - optimismSuperchainERC20Impl = new OptimismSuperchainERC20(); + optimismSuperchainERC20Impl = IOptimismSuperchainERC20( + DeployUtils.create1({ + _name: "OptimismSuperchainERC20", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IOptimismSuperchainERC20.__constructor__, ())) + }) + ); // Deploy the OptimismSuperchainERC20Beacon contract _deployBeacon(); @@ -58,11 +64,7 @@ contract OptimismSuperchainERC20Test is Test { EIP1967Helper.setImplementation(_addr, _impl); // Mock implementation address - vm.mockCall( - _impl, - abi.encodeWithSelector(IBeacon.implementation.selector), - abi.encode(address(optimismSuperchainERC20Impl)) - ); + vm.mockCall(_impl, abi.encodeCall(IBeacon.implementation, ()), abi.encode(address(optimismSuperchainERC20Impl))); } /// @notice Helper function to deploy a proxy of the OptimismSuperchainERC20 contract. @@ -73,13 +75,13 @@ contract OptimismSuperchainERC20Test is Test { uint8 _decimals ) internal - returns (OptimismSuperchainERC20) + returns (IOptimismSuperchainERC20) { - return OptimismSuperchainERC20( + return IOptimismSuperchainERC20( address( new BeaconProxy( Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON, - abi.encodeCall(OptimismSuperchainERC20.initialize, (_remoteToken, _name, _symbol, _decimals)) + abi.encodeCall(IOptimismSuperchainERC20.initialize, (_remoteToken, _name, _symbol, _decimals)) ) ) ); @@ -100,7 +102,7 @@ contract OptimismSuperchainERC20Test is Test { } /// @notice Tests the `initialize` function reverts when the contract is already initialized. - function testFuzz_initializer_reverts( + function testFuzz_initializer_invalidInitialization_reverts( address _remoteToken, string memory _name, string memory _symbol, @@ -219,38 +221,45 @@ contract OptimismSuperchainERC20Test is Test { /// @notice Tests the `decimals` function always returns the correct value. function testFuzz_decimals_succeeds(uint8 _decimals) public { - OptimismSuperchainERC20 _newSuperchainERC20 = _deploySuperchainERC20Proxy(REMOTE_TOKEN, NAME, SYMBOL, _decimals); + IOptimismSuperchainERC20 _newSuperchainERC20 = + _deploySuperchainERC20Proxy(REMOTE_TOKEN, NAME, SYMBOL, _decimals); assertEq(_newSuperchainERC20.decimals(), _decimals); } /// @notice Tests the `REMOTE_TOKEN` function always returns the correct value. function testFuzz_remoteToken_succeeds(address _remoteToken) public { - OptimismSuperchainERC20 _newSuperchainERC20 = _deploySuperchainERC20Proxy(_remoteToken, NAME, SYMBOL, DECIMALS); + IOptimismSuperchainERC20 _newSuperchainERC20 = _deploySuperchainERC20Proxy(_remoteToken, NAME, SYMBOL, DECIMALS); assertEq(_newSuperchainERC20.remoteToken(), _remoteToken); } /// @notice Tests the `name` function always returns the correct value. function testFuzz_name_succeeds(string memory _name) public { - OptimismSuperchainERC20 _newSuperchainERC20 = _deploySuperchainERC20Proxy(REMOTE_TOKEN, _name, SYMBOL, DECIMALS); + IOptimismSuperchainERC20 _newSuperchainERC20 = + _deploySuperchainERC20Proxy(REMOTE_TOKEN, _name, SYMBOL, DECIMALS); assertEq(_newSuperchainERC20.name(), _name); } /// @notice Tests the `symbol` function always returns the correct value. function testFuzz_symbol_succeeds(string memory _symbol) public { - OptimismSuperchainERC20 _newSuperchainERC20 = _deploySuperchainERC20Proxy(REMOTE_TOKEN, NAME, _symbol, DECIMALS); + IOptimismSuperchainERC20 _newSuperchainERC20 = + _deploySuperchainERC20Proxy(REMOTE_TOKEN, NAME, _symbol, DECIMALS); assertEq(_newSuperchainERC20.symbol(), _symbol); } /// @notice Tests that the `supportsInterface` function returns true for the `ISuperchainERC20` interface. function test_supportInterface_succeeds() public view { assertTrue(optimismSuperchainERC20.supportsInterface(type(IERC165).interfaceId)); + assertTrue(optimismSuperchainERC20.supportsInterface(type(IERC20).interfaceId)); + assertTrue(optimismSuperchainERC20.supportsInterface(type(IERC7802).interfaceId)); assertTrue(optimismSuperchainERC20.supportsInterface(type(IOptimismSuperchainERC20).interfaceId)); } /// @notice Tests that the `supportsInterface` function returns false for any other interface than the /// `ISuperchainERC20` one. - function testFuzz_supportInterface_returnFalse(bytes4 _interfaceId) public view { + function testFuzz_supportInterface_returnFalse_works(bytes4 _interfaceId) public view { vm.assume(_interfaceId != type(IERC165).interfaceId); + vm.assume(_interfaceId != type(IERC20).interfaceId); + vm.assume(_interfaceId != type(IERC7802).interfaceId); vm.assume(_interfaceId != type(IOptimismSuperchainERC20).interfaceId); assertFalse(optimismSuperchainERC20.supportsInterface(_interfaceId)); } diff --git a/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20Beacon.t.sol b/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20Beacon.t.sol index 68217127e0cb5..8a6a770146982 100644 --- a/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20Beacon.t.sol +++ b/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20Beacon.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; // Testing utilities -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; @@ -10,7 +10,7 @@ import { IBeacon } from "@openzeppelin/contracts/proxy/beacon/IBeacon.sol"; /// @title OptimismSuperchainERC20BeaconTest /// @notice Contract for testing the OptimismSuperchainERC20Beacon contract. -contract OptimismSuperchainERC20BeaconTest is Bridge_Initializer { +contract OptimismSuperchainERC20BeaconTest is CommonTest { /// @notice Sets up the test suite. function setUp() public override { super.enableInterop(); @@ -18,7 +18,7 @@ contract OptimismSuperchainERC20BeaconTest is Bridge_Initializer { } /// @notice Test that calling the implementation function returns the correct implementation address. - function test_implementation_is_correct() public view { + function test_implementation_isCorrect_works() public view { IBeacon beacon = IBeacon(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON); assertEq(beacon.implementation(), Predeploys.OPTIMISM_SUPERCHAIN_ERC20); } diff --git a/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20Factory.t.sol b/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20Factory.t.sol index 15630a15d8ebb..d8d7f86f26a29 100644 --- a/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20Factory.t.sol +++ b/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20Factory.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; // Testing utilities -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Libraries import { CREATE3, Bytes32AddressLib } from "@rari-capital/solmate/src/utils/CREATE3.sol"; @@ -13,7 +13,7 @@ import { IERC20Metadata } from "@openzeppelin/contracts/interfaces/IERC20Metadat /// @title OptimismSuperchainERC20FactoryTest /// @notice Contract for testing the OptimismSuperchainERC20Factory contract. -contract OptimismSuperchainERC20FactoryTest is Bridge_Initializer { +contract OptimismSuperchainERC20FactoryTest is CommonTest { using Bytes32AddressLib for bytes32; event OptimismSuperchainERC20Created( diff --git a/packages/contracts-bedrock/test/L2/Predeploys.t.sol b/packages/contracts-bedrock/test/L2/Predeploys.t.sol index 6a40a6f9258e4..4fc0a7aa01ddd 100644 --- a/packages/contracts-bedrock/test/L2/Predeploys.t.sol +++ b/packages/contracts-bedrock/test/L2/Predeploys.t.sol @@ -35,7 +35,7 @@ contract PredeploysBaseTest is CommonTest { || _addr == Predeploys.GOVERNANCE_TOKEN; } - function test_predeployToCodeNamespace() external pure { + function test_predeployToCodeNamespace_works() external pure { assertEq( address(0xc0D3C0d3C0d3C0D3c0d3C0d3c0D3C0d3c0d30000), Predeploys.predeployToCodeNamespace(Predeploys.LEGACY_MESSAGE_PASSER) diff --git a/packages/contracts-bedrock/test/L2/Preinstalls.t.sol b/packages/contracts-bedrock/test/L2/Preinstalls.t.sol index ad14e5ea32fb4..5eec3f811decd 100644 --- a/packages/contracts-bedrock/test/L2/Preinstalls.t.sol +++ b/packages/contracts-bedrock/test/L2/Preinstalls.t.sol @@ -9,7 +9,7 @@ import { IEIP712 } from "src/universal/interfaces/IEIP712.sol"; /// @title PreinstallsTest contract PreinstallsTest is CommonTest { /// @dev The domain separator commits to the chainid of the chain - function test_preinstall_permit2_domain_separator() external view { + function test_preinstall_permit2DomainSeparator_works() external view { bytes32 domainSeparator = IEIP712(Preinstalls.Permit2).DOMAIN_SEPARATOR(); bytes32 typeHash = keccak256(abi.encodePacked("EIP712Domain(string name,uint256 chainId,address verifyingContract)")); @@ -23,7 +23,7 @@ contract PreinstallsTest is CommonTest { // Warning the Permit2 domain separator as cached in the DeployPermit2.sol bytecode is incorrect. } - function test_permit2_templating() external pure { + function test_permit2_templating_works() external pure { bytes memory customCode = Preinstalls.getPermit2Code(1234); assertNotEq(customCode.length, 0, "must have code"); assertEq(uint256(bytes32(Bytes.slice(customCode, 6945, 32))), uint256(1234), "expecting custom chain ID"); @@ -118,4 +118,15 @@ contract PreinstallsTest is CommonTest { function test_preinstall_createX_succeeds() external view { assertPreinstall(Preinstalls.CreateX, Preinstalls.CreateXCode); } + + function test_createX_runtimeBytecodeHash_works() external view { + bytes memory createXRuntimeBytecode = Preinstalls.CreateX.code; + bytes32 createXRuntimeBytecodeHash = keccak256(createXRuntimeBytecode); + + assertEq( + createXRuntimeBytecodeHash, + 0xbd8a7ea8cfca7b4e5f5041d7d4b17bc317c5ce42cfbc42066a00cf26b43eb53f, + "CreateX runtime bytecode hash mismatch" + ); + } } diff --git a/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol b/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol index 2d6ba4e94ec80..ca8c3806b38bc 100644 --- a/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol @@ -7,12 +7,13 @@ import { Reverter } from "test/mocks/Callers.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; // Contracts -import { SequencerFeeVault } from "src/L2/SequencerFeeVault.sol"; +import { ISequencerFeeVault } from "src/L2/interfaces/ISequencerFeeVault.sol"; // Libraries import { Hashing } from "src/libraries/Hashing.sol"; import { Types } from "src/libraries/Types.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; contract SequencerFeeVault_Test is CommonTest { address recipient; @@ -112,11 +113,19 @@ contract SequencerFeeVault_L2Withdrawal_Test is CommonTest { vm.etch( EIP1967Helper.getImplementation(Predeploys.SEQUENCER_FEE_WALLET), address( - new SequencerFeeVault( - deploy.cfg().sequencerFeeVaultRecipient(), - deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount(), - Types.WithdrawalNetwork.L2 - ) + DeployUtils.create1({ + _name: "SequencerFeeVault", + _args: DeployUtils.encodeConstructor( + abi.encodeCall( + ISequencerFeeVault.__constructor__, + ( + deploy.cfg().sequencerFeeVaultRecipient(), + deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount(), + Types.WithdrawalNetwork.L2 + ) + ) + ) + }) ).code ); diff --git a/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol b/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol index 07b92ae3ca7d1..87f723a9345b2 100644 --- a/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol +++ b/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol @@ -6,11 +6,11 @@ import { Test } from "forge-std/Test.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; -import { IERC20Solady as IERC20 } from "src/vendor/interfaces/IERC20Solady.sol"; // Target contract import { SuperchainERC20 } from "src/L2/SuperchainERC20.sol"; -import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol"; +import { IERC7802, IERC165 } from "src/L2/interfaces/IERC7802.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISuperchainERC20 } from "src/L2/interfaces/ISuperchainERC20.sol"; import { MockSuperchainERC20Implementation } from "test/mocks/SuperchainERC20Implementation.sol"; @@ -60,9 +60,9 @@ contract SuperchainERC20Test is Test { vm.expectEmit(address(superchainERC20)); emit IERC20.Transfer(ZERO_ADDRESS, _to, _amount); - // Look for the emit of the `CrosschainMinted` event + // Look for the emit of the `CrosschainMint` event vm.expectEmit(address(superchainERC20)); - emit ICrosschainERC20.CrosschainMinted(_to, _amount); + emit IERC7802.CrosschainMint(_to, _amount); // Call the `mint` function with the bridge caller vm.prank(SUPERCHAIN_TOKEN_BRIDGE); @@ -86,7 +86,7 @@ contract SuperchainERC20Test is Test { superchainERC20.crosschainBurn(_from, _amount); } - /// @notice Tests the `burn` burns the amount and emits the `CrosschainBurnt` event. + /// @notice Tests the `burn` burns the amount and emits the `CrosschainBurn` event. function testFuzz_crosschainBurn_succeeds(address _from, uint256 _amount) public { // Ensure `_from` is not the zero address vm.assume(_from != ZERO_ADDRESS); @@ -103,9 +103,9 @@ contract SuperchainERC20Test is Test { vm.expectEmit(address(superchainERC20)); emit IERC20.Transfer(_from, ZERO_ADDRESS, _amount); - // Look for the emit of the `CrosschainBurnt` event + // Look for the emit of the `CrosschainBurn` event vm.expectEmit(address(superchainERC20)); - emit ICrosschainERC20.CrosschainBurnt(_from, _amount); + emit IERC7802.CrosschainBurn(_from, _amount); // Call the `burn` function with the bridge caller vm.prank(SUPERCHAIN_TOKEN_BRIDGE); @@ -115,4 +115,20 @@ contract SuperchainERC20Test is Test { assertEq(superchainERC20.totalSupply(), _totalSupplyBefore - _amount); assertEq(superchainERC20.balanceOf(_from), _fromBalanceBefore - _amount); } + + /// @notice Tests that the `supportsInterface` function returns true for the `IERC7802` interface. + function test_supportInterface_succeeds() public view { + assertTrue(superchainERC20.supportsInterface(type(IERC165).interfaceId)); + assertTrue(superchainERC20.supportsInterface(type(IERC7802).interfaceId)); + assertTrue(superchainERC20.supportsInterface(type(IERC20).interfaceId)); + } + + /// @notice Tests that the `supportsInterface` function returns false for any other interface than the + /// `IERC7802` one. + function testFuzz_supportInterface_works(bytes4 _interfaceId) public view { + vm.assume(_interfaceId != type(IERC165).interfaceId); + vm.assume(_interfaceId != type(IERC7802).interfaceId); + vm.assume(_interfaceId != type(IERC20).interfaceId); + assertFalse(superchainERC20.supportsInterface(_interfaceId)); + } } diff --git a/packages/contracts-bedrock/test/L2/SuperchainTokenBridge.t.sol b/packages/contracts-bedrock/test/L2/SuperchainTokenBridge.t.sol index e40904324d0c3..3c39e8b1792cc 100644 --- a/packages/contracts-bedrock/test/L2/SuperchainTokenBridge.t.sol +++ b/packages/contracts-bedrock/test/L2/SuperchainTokenBridge.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; // Testing utilities -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; @@ -13,10 +13,11 @@ import { ISuperchainTokenBridge } from "src/L2/interfaces/ISuperchainTokenBridge import { ISuperchainERC20 } from "src/L2/interfaces/ISuperchainERC20.sol"; import { IOptimismSuperchainERC20Factory } from "src/L2/interfaces/IOptimismSuperchainERC20Factory.sol"; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import { IERC7802 } from "src/L2/interfaces/IERC7802.sol"; /// @title SuperchainTokenBridgeTest /// @notice Contract for testing the SuperchainTokenBridge contract. -contract SuperchainTokenBridgeTest is Bridge_Initializer { +contract SuperchainTokenBridgeTest is CommonTest { address internal constant ZERO_ADDRESS = address(0); string internal constant NAME = "SuperchainERC20"; string internal constant SYMBOL = "OSE"; @@ -60,6 +61,32 @@ contract SuperchainTokenBridgeTest is Bridge_Initializer { superchainTokenBridge.sendERC20(address(superchainERC20), ZERO_ADDRESS, _amount, _chainId); } + /// @notice Tests the `sendERC20` function reverts when the `token` does not support the IERC7802 interface. + function testFuzz_sendERC20_notSupportedIERC7802_reverts( + address _token, + address _sender, + address _to, + uint256 _amount, + uint256 _chainId + ) + public + { + vm.assume(_to != ZERO_ADDRESS); + assumeAddressIsNot(_token, AddressType.Precompile, AddressType.ForgeAddress); + + // Mock the call over the `supportsInterface` function to return false + vm.mockCall( + _token, abi.encodeCall(ISuperchainERC20.supportsInterface, (type(IERC7802).interfaceId)), abi.encode(false) + ); + + // Expect the revert with `InvalidERC7802` selector + vm.expectRevert(ISuperchainTokenBridge.InvalidERC7802.selector); + + // Call the `sendERC20` function + vm.prank(_sender); + superchainTokenBridge.sendERC20(_token, _to, _amount, _chainId); + } + /// @notice Tests the `sendERC20` function burns the sender tokens, sends the message, and emits the `SendERC20` /// event. function testFuzz_sendERC20_succeeds( @@ -96,8 +123,8 @@ contract SuperchainTokenBridgeTest is Bridge_Initializer { abi.encodeCall(superchainTokenBridge.relayERC20, (address(superchainERC20), _sender, _to, _amount)); _mockAndExpect( Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, - abi.encodeWithSelector( - IL2ToL2CrossDomainMessenger.sendMessage.selector, _chainId, address(superchainTokenBridge), _message + abi.encodeCall( + IL2ToL2CrossDomainMessenger.sendMessage, (_chainId, address(superchainTokenBridge), _message) ), abi.encode(_msgHash) ); @@ -137,7 +164,6 @@ contract SuperchainTokenBridgeTest is Bridge_Initializer { /// @notice Tests the `relayERC20` function reverts when the `crossDomainMessageSender` that sent the message is not /// the same SuperchainTokenBridge. function testFuzz_relayERC20_notCrossDomainSender_reverts( - address _token, address _crossDomainMessageSender, uint256 _source, address _to, @@ -150,7 +176,7 @@ contract SuperchainTokenBridgeTest is Bridge_Initializer { // Mock the call over the `crossDomainMessageContext` function setting a wrong sender vm.mockCall( Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, - abi.encodeWithSelector(IL2ToL2CrossDomainMessenger.crossDomainMessageContext.selector), + abi.encodeCall(IL2ToL2CrossDomainMessenger.crossDomainMessageContext, ()), abi.encode(_crossDomainMessageSender, _source) ); @@ -159,7 +185,7 @@ contract SuperchainTokenBridgeTest is Bridge_Initializer { // Call the `relayERC20` function with the sender caller vm.prank(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER); - superchainTokenBridge.relayERC20(_token, _crossDomainMessageSender, _to, _amount); + superchainTokenBridge.relayERC20(address(superchainERC20), _crossDomainMessageSender, _to, _amount); } /// @notice Tests the `relayERC20` mints the proper amount and emits the `RelayERC20` event. @@ -169,7 +195,7 @@ contract SuperchainTokenBridgeTest is Bridge_Initializer { // Mock the call over the `crossDomainMessageContext` function setting the same address as value _mockAndExpect( Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, - abi.encodeWithSelector(IL2ToL2CrossDomainMessenger.crossDomainMessageContext.selector), + abi.encodeCall(IL2ToL2CrossDomainMessenger.crossDomainMessageContext, ()), abi.encode(address(superchainTokenBridge), _source) ); diff --git a/packages/contracts-bedrock/test/L2/SuperchainWETH.t.sol b/packages/contracts-bedrock/test/L2/SuperchainWETH.t.sol index d80e9bf11b1b6..e342a53b6026b 100644 --- a/packages/contracts-bedrock/test/L2/SuperchainWETH.t.sol +++ b/packages/contracts-bedrock/test/L2/SuperchainWETH.t.sol @@ -7,10 +7,13 @@ import { CommonTest } from "test/setup/CommonTest.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; import { NotCustomGasToken } from "src/libraries/errors/CommonErrors.sol"; +import { Preinstalls } from "src/libraries/Preinstalls.sol"; // Interfaces import { IETHLiquidity } from "src/L2/interfaces/IETHLiquidity.sol"; import { ISuperchainWETH } from "src/L2/interfaces/ISuperchainWETH.sol"; +import { IERC7802, IERC165 } from "src/L2/interfaces/IERC7802.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /// @title SuperchainWETH_Test /// @notice Contract for testing the SuperchainWETH contract. @@ -25,10 +28,10 @@ contract SuperchainWETH_Test is CommonTest { event Withdrawal(address indexed src, uint256 wad); /// @notice Emitted when a crosschain transfer mints tokens. - event CrosschainMinted(address indexed to, uint256 amount); + event CrosschainMint(address indexed to, uint256 amount); /// @notice Emitted when a crosschain transfer burns tokens. - event CrosschainBurnt(address indexed from, uint256 amount); + event CrosschainBurn(address indexed from, uint256 amount); address internal constant ZERO_ADDRESS = address(0); @@ -143,7 +146,7 @@ contract SuperchainWETH_Test is CommonTest { superchainWeth.crosschainMint(_to, _amount); } - /// @notice Tests the `crosschainMint` with non custom gas token succeeds and emits the `CrosschainMinted` event. + /// @notice Tests the `crosschainMint` with non custom gas token succeeds and emits the `CrosschainMint` event. function testFuzz_crosschainMint_fromBridgeNonCustomGasTokenChain_succeeds(address _to, uint256 _amount) public { // Ensure `_to` is not the zero address vm.assume(_to != ZERO_ADDRESS); @@ -157,9 +160,9 @@ contract SuperchainWETH_Test is CommonTest { vm.expectEmit(address(superchainWeth)); emit Transfer(ZERO_ADDRESS, _to, _amount); - // Look for the emit of the `CrosschainMinted` event + // Look for the emit of the `CrosschainMint` event vm.expectEmit(address(superchainWeth)); - emit CrosschainMinted(_to, _amount); + emit CrosschainMint(_to, _amount); // Mock the `isCustomGasToken` function to return false _mockAndExpect(address(l1Block), abi.encodeCall(l1Block.isCustomGasToken, ()), abi.encode(false)); @@ -174,11 +177,10 @@ contract SuperchainWETH_Test is CommonTest { // Check the total supply and balance of `_to` after the mint were updated correctly assertEq(superchainWeth.totalSupply(), _totalSupplyBefore + _amount); assertEq(superchainWeth.balanceOf(_to), _toBalanceBefore + _amount); - assertEq(superchainWeth.balanceOf(Predeploys.ETH_LIQUIDITY), 0); assertEq(address(superchainWeth).balance, _amount); } - /// @notice Tests the `crosschainMint` with custom gas token succeeds and emits the `CrosschainMinted` event. + /// @notice Tests the `crosschainMint` with custom gas token succeeds and emits the `CrosschainMint` event. function testFuzz_crosschainMint_fromBridgeCustomGasTokenChain_succeeds(address _to, uint256 _amount) public { // Ensure `_to` is not the zero address vm.assume(_to != ZERO_ADDRESS); @@ -191,9 +193,9 @@ contract SuperchainWETH_Test is CommonTest { vm.expectEmit(address(superchainWeth)); emit Transfer(ZERO_ADDRESS, _to, _amount); - // Look for the emit of the `CrosschainMinted` event + // Look for the emit of the `CrosschainMint` event vm.expectEmit(address(superchainWeth)); - emit CrosschainMinted(_to, _amount); + emit CrosschainMint(_to, _amount); // Mock the `isCustomGasToken` function to return false _mockAndExpect(address(l1Block), abi.encodeCall(l1Block.isCustomGasToken, ()), abi.encode(true)); @@ -207,7 +209,6 @@ contract SuperchainWETH_Test is CommonTest { // Check the total supply and balance of `_to` after the mint were updated correctly assertEq(superchainWeth.balanceOf(_to), _toBalanceBefore + _amount); - assertEq(superchainWeth.balanceOf(Predeploys.ETH_LIQUIDITY), 0); assertEq(superchainWeth.totalSupply(), 0); assertEq(address(superchainWeth).balance, 0); } @@ -225,7 +226,7 @@ contract SuperchainWETH_Test is CommonTest { superchainWeth.crosschainBurn(_from, _amount); } - /// @notice Tests the `crosschainBurn` with non custom gas token burns the amount and emits the `CrosschainBurnt` + /// @notice Tests the `crosschainBurn` with non custom gas token burns the amount and emits the `CrosschainBurn` /// event. function testFuzz_crosschainBurn_fromBridgeNonCustomGasTokenChain_succeeds(address _from, uint256 _amount) public { // Ensure `_from` is not the zero address @@ -245,9 +246,9 @@ contract SuperchainWETH_Test is CommonTest { vm.expectEmit(address(superchainWeth)); emit Transfer(_from, ZERO_ADDRESS, _amount); - // Look for the emit of the `CrosschainBurnt` event + // Look for the emit of the `CrosschainBurn` event vm.expectEmit(address(superchainWeth)); - emit CrosschainBurnt(_from, _amount); + emit CrosschainBurn(_from, _amount); // Mock the `isCustomGasToken` function to return false _mockAndExpect(address(l1Block), abi.encodeCall(l1Block.isCustomGasToken, ()), abi.encode(false)); @@ -265,7 +266,7 @@ contract SuperchainWETH_Test is CommonTest { assertEq(address(superchainWeth).balance, 0); } - /// @notice Tests the `crosschainBurn` with custom gas token burns the amount and emits the `CrosschainBurnt` + /// @notice Tests the `crosschainBurn` with custom gas token burns the amount and emits the `CrosschainBurn` /// event. function testFuzz_crosschainBurn_fromBridgeCustomGasTokenChain_succeeds(address _from, uint256 _amount) public { // Ensure `_from` is not the zero address @@ -287,9 +288,9 @@ contract SuperchainWETH_Test is CommonTest { vm.expectEmit(address(superchainWeth)); emit Transfer(_from, ZERO_ADDRESS, _amount); - // Look for the emit of the `CrosschainBurnt` event + // Look for the emit of the `CrosschainBurn` event vm.expectEmit(address(superchainWeth)); - emit CrosschainBurnt(_from, _amount); + emit CrosschainBurn(_from, _amount); // Expect to not call the `burn` function in the `ETHLiquidity` contract vm.expectCall(Predeploys.ETH_LIQUIDITY, abi.encodeCall(IETHLiquidity.burn, ()), 0); @@ -316,18 +317,15 @@ contract SuperchainWETH_Test is CommonTest { superchainWeth.deposit{ value: _amount }(); // Act - vm.expectRevert(); + vm.expectRevert(); // nosemgrep: sol-safety-expectrevert-no-args superchainWeth.crosschainBurn(_from, _amount + 1); - - // Assert - assertEq(_from.balance, 0); - assertEq(superchainWeth.balanceOf(_from), _amount); } /// @notice Test that the internal mint function reverts to protect against accidentally changing the visibility. - function testFuzz_calling_internal_mint_function_reverts(address _caller, address _to, uint256 _amount) public { + function testFuzz_calling_internalMintFunction_reverts(address _caller, address _to, uint256 _amount) public { // Arrange - bytes memory _calldata = abi.encodeWithSignature("_mint(address,uint256)", _to, _amount); + bytes memory _calldata = abi.encodeWithSignature("_mint(address,uint256)", _to, _amount); // nosemgrep: + // sol-style-use-abi-encodecall vm.expectRevert(bytes("")); // Act @@ -339,9 +337,10 @@ contract SuperchainWETH_Test is CommonTest { } /// @notice Test that the mint function reverts to protect against accidentally changing the visibility. - function testFuzz_calling_mint_function_reverts(address _caller, address _to, uint256 _amount) public { + function testFuzz_calling_mintFunction_reverts(address _caller, address _to, uint256 _amount) public { // Arrange - bytes memory _calldata = abi.encodeWithSignature("mint(address,uint256)", _to, _amount); + bytes memory _calldata = abi.encodeWithSignature("mint(address,uint256)", _to, _amount); // nosemgrep: + // sol-style-use-abi-encodecall vm.expectRevert(bytes("")); // Act @@ -353,9 +352,10 @@ contract SuperchainWETH_Test is CommonTest { } /// @notice Test that the internal burn function reverts to protect against accidentally changing the visibility. - function testFuzz_calling_internal_burn_function_reverts(address _caller, address _from, uint256 _amount) public { + function testFuzz_calling_internalBurnFunction_reverts(address _caller, address _from, uint256 _amount) public { // Arrange - bytes memory _calldata = abi.encodeWithSignature("_burn(address,uint256)", _from, _amount); + bytes memory _calldata = abi.encodeWithSignature("_burn(address,uint256)", _from, _amount); // nosemgrep: + // sol-style-use-abi-encodecall vm.expectRevert(bytes("")); // Act @@ -367,9 +367,10 @@ contract SuperchainWETH_Test is CommonTest { } /// @notice Test that the burn function reverts to protect against accidentally changing the visibility. - function testFuzz_calling_burn_function_reverts(address _caller, address _from, uint256 _amount) public { + function testFuzz_calling_burnFuunction_reverts(address _caller, address _from, uint256 _amount) public { // Arrange - bytes memory _calldata = abi.encodeWithSignature("burn(address,uint256)", _from, _amount); + bytes memory _calldata = abi.encodeWithSignature("burn(address,uint256)", _from, _amount); // nosemgrep: + // sol-style-use-abi-encodecall vm.expectRevert(bytes("")); // Act @@ -379,4 +380,99 @@ contract SuperchainWETH_Test is CommonTest { // Assert assertFalse(success); } + + /// @notice Tests that the allowance function returns the max uint256 value when the spender is Permit. + /// @param _randomCaller The address that will call the function - used to fuzz better since the behaviour should be + /// the same regardless of the caller. + /// @param _src The funds owner. + function testFuzz_allowance_fromPermit2_succeeds(address _randomCaller, address _src) public { + vm.prank(_randomCaller); + uint256 _allowance = superchainWeth.allowance(_src, Preinstalls.Permit2); + + assertEq(_allowance, type(uint256).max); + } + + /// @notice Tests that the allowance function returns the correct allowance when the spender is not Permit. + /// @param _randomCaller The address that will call the function - used to fuzz better + /// since the behaviour should be the same regardless of the caller. + /// @param _src The funds owner. + /// @param _guy The address of the spender - It cannot be Permit2. + function testFuzz_allowance_succeeds(address _randomCaller, address _src, address _guy, uint256 _wad) public { + // Assume + vm.assume(_guy != Preinstalls.Permit2); + + // Arrange + vm.prank(_src); + superchainWeth.approve(_guy, _wad); + + // Act + vm.prank(_randomCaller); + uint256 _allowance = superchainWeth.allowance(_src, _guy); + + // Assert + assertEq(_allowance, _wad); + } + + /// @notice Tests that `transferFrom` works when the caller (spender) is Permit2, without any explicit approval. + /// @param _src The funds owner. + /// @param _dst The address of the recipient. + /// @param _wad The amount of WETH to transfer. + function testFuzz_transferFrom_whenPermit2IsCaller_succeeds(address _src, address _dst, uint256 _wad) public { + vm.assume(_src != _dst); + + // Arrange + deal(address(superchainWeth), _src, _wad); + + vm.expectEmit(address(superchainWeth)); + emit Transfer(_src, _dst, _wad); + + // Act + vm.prank(Preinstalls.Permit2); + superchainWeth.transferFrom(_src, _dst, _wad); + + // Assert + assertEq(superchainWeth.balanceOf(_src), 0); + assertEq(superchainWeth.balanceOf(_dst), _wad); + } + + /// @notice Tests that `transferFrom` works when the caller (spender) is Permit2, and `_src` equals `_dst` without + /// an explicit approval. + /// The balance should remain the same on this scenario. + /// @param _user The source and destination address. + /// @param _wad The amount of WETH to transfer. + function testFuzz_transferFrom_whenPermit2IsCallerAndSourceIsDestination_succeeds( + address _user, + uint256 _wad + ) + public + { + // Arrange + deal(address(superchainWeth), _user, _wad); + + vm.expectEmit(address(superchainWeth)); + emit Transfer(_user, _user, _wad); + + // Act + vm.prank(Preinstalls.Permit2); + superchainWeth.transferFrom(_user, _user, _wad); + + // Assert + assertEq(superchainWeth.balanceOf(_user), _wad); + } + + /// @notice Tests that the `supportsInterface` function returns true for the `IERC7802` interface. + function test_supportInterface_succeeds() public view { + assertTrue(superchainWeth.supportsInterface(type(IERC165).interfaceId)); + assertTrue(superchainWeth.supportsInterface(type(IERC7802).interfaceId)); + assertTrue(superchainWeth.supportsInterface(type(IERC20).interfaceId)); + } + + /// @notice Tests that the `supportsInterface` function returns false for any other interface than the + /// `IERC7802` one. + function testFuzz_supportInterface_works(bytes4 _interfaceId) public view { + vm.assume(_interfaceId != type(IERC165).interfaceId); + vm.assume(_interfaceId != type(IERC7802).interfaceId); + vm.assume(_interfaceId != type(IERC20).interfaceId); + assertFalse(superchainWeth.supportsInterface(_interfaceId)); + } } diff --git a/packages/contracts-bedrock/test/L2/WETH.t.sol b/packages/contracts-bedrock/test/L2/WETH.t.sol index fa16be1f53cce..84bb138d74fba 100644 --- a/packages/contracts-bedrock/test/L2/WETH.t.sol +++ b/packages/contracts-bedrock/test/L2/WETH.t.sol @@ -10,7 +10,7 @@ import { WETH } from "src/L2/WETH.sol"; contract WETH_Test is CommonTest { /// @dev Tests that the name function returns the correct value. function testFuzz_name_succeeds(string memory _gasPayingTokenName) external { - vm.mockCall(address(l1Block), abi.encodeWithSignature("gasPayingTokenName()"), abi.encode(_gasPayingTokenName)); + vm.mockCall(address(l1Block), abi.encodeCall(l1Block.gasPayingTokenName, ()), abi.encode(_gasPayingTokenName)); assertEq(string.concat("Wrapped ", _gasPayingTokenName), weth.name()); } @@ -18,7 +18,7 @@ contract WETH_Test is CommonTest { /// @dev Tests that the symbol function returns the correct value. function testFuzz_symbol_succeeds(string memory _gasPayingTokenSymbol) external { vm.mockCall( - address(l1Block), abi.encodeWithSignature("gasPayingTokenSymbol()"), abi.encode(_gasPayingTokenSymbol) + address(l1Block), abi.encodeCall(l1Block.gasPayingTokenSymbol, ()), abi.encode(_gasPayingTokenSymbol) ); assertEq(string.concat("W", _gasPayingTokenSymbol), weth.symbol()); diff --git a/packages/contracts-bedrock/test/cannon/MIPS.t.sol b/packages/contracts-bedrock/test/cannon/MIPS.t.sol index 21710ef1e18e6..62100f31cfbed 100644 --- a/packages/contracts-bedrock/test/cannon/MIPS.t.sol +++ b/packages/contracts-bedrock/test/cannon/MIPS.t.sol @@ -1509,7 +1509,7 @@ contract MIPS_Test is CommonTest { assertEq(postState, outputState(expect), "unexpected post state"); } - function test_mmap_succeeds_justWithinMemLimit() external { + function test_mmap_justWithinMemLimit_succeeds() external { uint32 insn = 0x0000000c; // syscall (bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(0, insn); @@ -1538,7 +1538,7 @@ contract MIPS_Test is CommonTest { assertEq(postState, outputState(expect), "unexpected post state"); } - function test_mmap_fails() external { + function test_step_mmap_fails() external { uint32 insn = 0x0000000c; // syscall (bytes32 memRoot, bytes memory proof) = ffi.getCannonMemoryProof(0, insn); @@ -1692,7 +1692,7 @@ contract MIPS_Test is CommonTest { mips.step(encodedState, proof, 0); } - function test_invalid_root_fails() external { + function test_step_invalidRoot_fails() external { uint32 insn = 0x0000000c; // syscall (IMIPS.State memory state, bytes memory proof) = constructMIPSState(0, insn, 0x4, 0); state.registers[2] = 4246; // exit_group syscall @@ -1706,7 +1706,7 @@ contract MIPS_Test is CommonTest { mips.step(encodeState(state), proof, 0); } - function test_invalid_root_different_leaf_fails() external { + function test_step_invalidRootDifferentLeaf_fails() external { uint32 insn = 0x0000000c; // syscall // Initialize the state, though for the proof, use valid proofs for the instruction @@ -1801,22 +1801,22 @@ contract MIPS_Test is CommonTest { uint32 val ) internal - returns (IMIPS.State memory state, bytes memory proof) + returns (IMIPS.State memory state_, bytes memory proof_) { - (state.memRoot, proof) = ffi.getCannonMemoryProof(pc, insn, addr, val); - state.pc = pc; - state.nextPC = pc + 4; + (state_.memRoot, proof_) = ffi.getCannonMemoryProof(pc, insn, addr, val); + state_.pc = pc; + state_.nextPC = pc + 4; } - function encodeitype(uint8 opcode, uint8 rs, uint8 rt, uint16 imm) internal pure returns (uint32 insn) { - insn = uint32(opcode) << 26 | uint32(rs) << 21 | uint32(rt) << 16 | imm; + function encodeitype(uint8 opcode, uint8 rs, uint8 rt, uint16 imm) internal pure returns (uint32 insn_) { + insn_ = uint32(opcode) << 26 | uint32(rs) << 21 | uint32(rt) << 16 | imm; } - function encodespec(uint8 rs, uint8 rt, uint8 rd, uint16 funct) internal pure returns (uint32 insn) { - insn = uint32(rs) << 21 | uint32(rt) << 16 | uint32(rd) << 11 | uint32(funct); + function encodespec(uint8 rs, uint8 rt, uint8 rd, uint16 funct) internal pure returns (uint32 insn_) { + insn_ = uint32(rs) << 21 | uint32(rt) << 16 | uint32(rd) << 11 | uint32(funct); } - function encodespec2(uint8 rs, uint8 rt, uint8 rd, uint8 funct) internal pure returns (uint32 insn) { - insn = uint32(28) << 26 | uint32(rs) << 21 | uint32(rt) << 16 | uint32(rd) << 11 | uint32(funct); + function encodespec2(uint8 rs, uint8 rt, uint8 rd, uint8 funct) internal pure returns (uint32 insn_) { + insn_ = uint32(28) << 26 | uint32(rs) << 21 | uint32(rt) << 16 | uint32(rd) << 11 | uint32(funct); } } diff --git a/packages/contracts-bedrock/test/cannon/MIPS2.t.sol b/packages/contracts-bedrock/test/cannon/MIPS2.t.sol index 22eb49b4ef0e3..2cc0519ea5bfb 100644 --- a/packages/contracts-bedrock/test/cannon/MIPS2.t.sol +++ b/packages/contracts-bedrock/test/cannon/MIPS2.t.sol @@ -159,7 +159,7 @@ contract MIPS2_Test is CommonTest { /// This is useful to more easily debug non-forge tests. /// For example, in cannon/mipsevm/evm_test.go step input can be pulled here: /// https://github.com/ethereum-optimism/optimism/blob/1f64dd6db5561f3bb76ed1d1ffdaff0cde9b7c4b/cannon/mipsevm/evm_test.go#L80-L80 - function test_mips2_step_debug_succeeds() external { + function test_step_debug_succeeds() external { bytes memory input = hex"e14ced3200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000acab5a39c6f974b22302e96dcdef1815483eaf580639bb1ee7ac98267afac2bf1ac041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d0b75fb180daf48a79e3143a81fa7c3d90b000000000000000000000078fc2ffac2fd940100000000000080c8ffffffff006504aeffb6e08baf3f85da5476a9160fa8f9f188a722fdd29268b0cbaf596736ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb500000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c6000000000000ffffffff000000000000000000000000f1f85ff4f1f85ff8506d442dbb3938f83eb60825a7ecbff2000010185e1a31f600050f0000000064a7c3d90be5acea102ad7bda149e0bfd0e7111c77d98b335645e665389becadf140ef999cc64fbd7f04799e85c97dadc5cca510bd5b3d97166d1aec28829f3dd43d8cf1f9358e4103b16d09d466e2c7c048ea3ba1aef3141e700270581aa0b75b50e34fc926bb2d83ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb500000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d3021ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a193440eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f839867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756afcefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf8923490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99cc1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8beccda7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d22733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981fe1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd95a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e3774df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618db8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; (bool success, bytes memory retVal) = address(mips).call(input); @@ -246,7 +246,7 @@ contract MIPS2_Test is CommonTest { } } - function test_invalidThreadWitness_reverts() public { + function test_step_invalidThreadWitness_reverts() public { IMIPS2.State memory state; IMIPS2.ThreadState memory thread; bytes memory memProof; @@ -743,12 +743,12 @@ contract MIPS2_Test is CommonTest { } /// @dev Test asserting that an clock_gettime monotonic syscall reverts on an invalid memory proof - function test_syscallClockGettimeMonotonicInvalidProof_reverts() public { + function test_step_syscallClockGettimeMonotonicInvalidProof_reverts() public { _test_syscallClockGettimeInvalidProof_reverts(sys.CLOCK_GETTIME_MONOTONIC_FLAG); } /// @dev Test asserting that an clock_gettime realtime syscall reverts on an invalid memory proof - function test_syscallClockGettimeRealtimeInvalidProof_reverts() public { + function test_step_syscallClockGettimeRealtimeInvalidProof_reverts() public { _test_syscallClockGettimeInvalidProof_reverts(sys.CLOCK_GETTIME_REALTIME_FLAG); } @@ -1336,7 +1336,7 @@ contract MIPS2_Test is CommonTest { assertEq(postState, outputState(expect), "unexpected post state"); } - function test_mmap_succeeds_simple() external { + function test_mmap_simple_succeeds() external { uint32 insn = 0x0000000c; // syscall (IMIPS2.State memory state, IMIPS2.ThreadState memory thread, bytes memory memProof) = constructMIPSState(0, insn, 0x4, 0); @@ -1368,7 +1368,7 @@ contract MIPS2_Test is CommonTest { assertEq(postState, outputState(expect), "unexpected post state"); } - function test_mmap_succeeds_justWithinMemLimit() external { + function test_mmap_justWithinMemLimit_succeeds() external { uint32 insn = 0x0000000c; // syscall (IMIPS2.State memory state, IMIPS2.ThreadState memory thread, bytes memory memProof) = constructMIPSState(0, insn, 0x4, 0); @@ -1400,7 +1400,7 @@ contract MIPS2_Test is CommonTest { assertEq(postState, outputState(expect), "unexpected post state"); } - function test_mmap_fails() external { + function test_step_mmap_fails() external { uint32 insn = 0x0000000c; // syscall (IMIPS2.State memory state, IMIPS2.ThreadState memory thread, bytes memory memProof) = constructMIPSState(0, insn, 0x4, 0); @@ -2832,16 +2832,16 @@ contract MIPS2_Test is CommonTest { } } - function encodeitype(uint8 opcode, uint8 rs, uint8 rt, uint16 imm) internal pure returns (uint32 insn) { - insn = uint32(opcode) << 26 | uint32(rs) << 21 | uint32(rt) << 16 | imm; + function encodeitype(uint8 opcode, uint8 rs, uint8 rt, uint16 imm) internal pure returns (uint32 insn_) { + insn_ = uint32(opcode) << 26 | uint32(rs) << 21 | uint32(rt) << 16 | imm; } - function encodespec(uint8 rs, uint8 rt, uint8 rd, uint16 funct) internal pure returns (uint32 insn) { - insn = uint32(rs) << 21 | uint32(rt) << 16 | uint32(rd) << 11 | uint32(funct); + function encodespec(uint8 rs, uint8 rt, uint8 rd, uint16 funct) internal pure returns (uint32 insn_) { + insn_ = uint32(rs) << 21 | uint32(rt) << 16 | uint32(rd) << 11 | uint32(funct); } - function encodespec2(uint8 rs, uint8 rt, uint8 rd, uint8 funct) internal pure returns (uint32 insn) { - insn = uint32(28) << 26 | uint32(rs) << 21 | uint32(rt) << 16 | uint32(rd) << 11 | uint32(funct); + function encodespec2(uint8 rs, uint8 rt, uint8 rd, uint8 funct) internal pure returns (uint32 insn_) { + insn_ = uint32(28) << 26 | uint32(rs) << 21 | uint32(rt) << 16 | uint32(rd) << 11 | uint32(funct); } } diff --git a/packages/contracts-bedrock/test/cannon/MIPS64Memory.t.sol b/packages/contracts-bedrock/test/cannon/MIPS64Memory.t.sol new file mode 100644 index 0000000000000..9ba0f0bcf5f54 --- /dev/null +++ b/packages/contracts-bedrock/test/cannon/MIPS64Memory.t.sol @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { CommonTest } from "test/setup/CommonTest.sol"; +import { MIPS64Memory } from "src/cannon/libraries/MIPS64Memory.sol"; +import { InvalidMemoryProof } from "src/cannon/libraries/CannonErrors.sol"; + +contract MIPS64Memory_Test is CommonTest { + MIPS64MemoryWithCalldata mem; + + error InvalidAddress(); + + function setUp() public virtual override { + super.setUp(); + mem = new MIPS64MemoryWithCalldata(); + } + + /// @dev Static unit test for basic memory access + function test_readMem_succeeds() external { + uint64 addr = 0x100; + uint64 word = 0x11_22_33_44_55_66_77_88; + bytes32 root; + bytes memory proof; + (root, proof) = ffi.getCannonMemory64Proof(addr, word); + uint64 readWord = mem.readMem(root, addr, 0, proof); + assertEq(readWord, word); + } + + /// @dev Static unit test asserting that reading from the zero address succeeds + function test_readMemAtZero_succeeds() external { + uint64 addr = 0x0; + uint64 word = 0x11_22_33_44_55_66_77_88; + bytes32 root; + bytes memory proof; + (root, proof) = ffi.getCannonMemory64Proof(addr, word); + uint64 readWord = mem.readMem(root, addr, 0, proof); + assertEq(readWord, word); + } + + /// @dev Static unit test asserting that reading from high memory area succeeds + function test_readMemHighMem_succeeds() external { + uint64 addr = 0xFF_FF_FF_FF_00_00_00_88; + uint64 word = 0x11_22_33_44_55_66_77_88; + bytes32 root; + bytes memory proof; + (root, proof) = ffi.getCannonMemory64Proof(addr, word); + uint64 readWord = mem.readMem(root, addr, 0, proof); + assertEq(readWord, word); + } + + /// @dev Static unit test asserting that reads revert when a misaligned memory address is provided + function test_readMem_readInvalidAddress_reverts() external { + uint64 addr = 0x100; + uint64 word = 0x11_22_33_44_55_66_77_88; + bytes32 root; + bytes memory proof; + (root, proof) = ffi.getCannonMemory64Proof(addr, word); + vm.expectRevert(InvalidAddress.selector); + mem.readMem(root, addr + 4, 0, proof); + } + + /// @dev Static unit test asserting that reads revert when an invalid proof is provided + function test_readMem_readInvalidProof_reverts() external { + uint64 addr = 0x100; + uint64 word = 0x11_22_33_44_55_66_77_88; + bytes32 root; + bytes memory proof; + (root, proof) = ffi.getCannonMemory64Proof(addr, word); + vm.assertTrue(proof[64] != 0x0); // make sure the proof is tampered + proof[64] = 0x00; + vm.expectRevert(InvalidMemoryProof.selector); + mem.readMem(root, addr, 0, proof); + } + + /// @dev Static unit test asserting that reads from a non-zero proof index succeeds + function test_readMemNonZeroProofIndex_succeeds() external { + uint64 addr = 0x100; + uint64 word = 0x11_22_33_44_55_66_77_88; + uint64 addr2 = 0xFF_FF_FF_FF_00_00_00_88; + uint64 word2 = 0xF1_F2_F3_F4_F5_F6_F7_F8; + bytes32 root; + bytes memory proof; + (root, proof) = ffi.getCannonMemory64Proof(addr, word, addr2, word2); + + uint64 readWord = mem.readMem(root, addr, 0, proof); + assertEq(readWord, word); + + readWord = mem.readMem(root, addr2, 1, proof); + assertEq(readWord, word2); + } + + /// @dev Static unit test asserting basic memory write functionality + function test_writeMem_succeeds() external { + uint64 addr = 0x100; + bytes memory zeroProof; + (, zeroProof) = ffi.getCannonMemory64Proof(addr, 0); + + uint64 word = 0x11_22_33_44_55_66_77_88; + (bytes32 expectedRoot,) = ffi.getCannonMemory64Proof(addr, word); + + bytes32 newRoot = mem.writeMem(addr, word, 0, zeroProof); + assertEq(newRoot, expectedRoot); + } + + // @dev Static unit test asserting that writes to high memory succeeds + function test_writeMemHighMem_succeeds() external { + uint64 addr = 0xFF_FF_FF_FF_00_00_00_88; + bytes memory zeroProof; + (, zeroProof) = ffi.getCannonMemory64Proof(addr, 0); + + uint64 word = 0x11_22_33_44_55_66_77_88; + (bytes32 expectedRoot,) = ffi.getCannonMemory64Proof(addr, word); + + bytes32 newRoot = mem.writeMem(addr, word, 0, zeroProof); + assertEq(newRoot, expectedRoot); + } + + /// @dev Static unit test asserting that non-zero memory word is overwritten + function test_writeMemNonZeroProofOffset_succeeds() external { + uint64 addr = 0x100; + uint64 word = 0x11_22_33_44_55_66_77_88; + uint64 addr2 = 0x108; + uint64 word2 = 0x55_55_55_55_77_77_77_77; + bytes memory initProof; + (, initProof) = ffi.getCannonMemory64Proof(addr, word, addr2, word2); + + uint64 word3 = 0x44_44_44_44_44_44_44_44; + (bytes32 expectedRoot,) = ffi.getCannonMemory64Proof(addr, word, addr2, word2, addr2, word3); + + bytes32 newRoot = mem.writeMem(addr2, word3, 1, initProof); + assertEq(newRoot, expectedRoot); + } + + /// @dev Static unit test asserting that a zerod memory word is set for a non-zero memory proof + function test_writeMemUniqueAccess_succeeds() external { + uint64 addr = 0x100; + uint64 word = 0x11_22_33_44_55_66_77_88; + uint64 addr2 = 0x108; + uint64 word2 = 0x55_55_55_55_77_77_77_77; + bytes memory initProof; + (, initProof) = ffi.getCannonMemory64Proof(addr, word, addr2, word2); + + uint64 addr3 = 0xAA_AA_AA_AA_00; + uint64 word3 = 0x44_44_44_44_44_44_44_44; + (, bytes memory addr3Proof) = ffi.getCannonMemory64Proof2(addr, word, addr2, word2, addr3); + (bytes32 expectedRoot,) = ffi.getCannonMemory64Proof(addr, word, addr2, word2, addr3, word3); + + bytes32 newRoot = mem.writeMem(addr3, word3, 0, addr3Proof); + assertEq(newRoot, expectedRoot); + + newRoot = mem.writeMem(addr3 + 8, word3, 0, addr3Proof); + assertNotEq(newRoot, expectedRoot); + + newRoot = mem.writeMem(addr3, word3 + 1, 0, addr3Proof); + assertNotEq(newRoot, expectedRoot); + } + + /// @dev Static unit test asserting that writes succeeds in overwriting a non-zero memory word + function test_writeMemNonZeroMem_succeeds() external { + uint64 addr = 0x100; + uint64 word = 0x11_22_33_44_55_66_77_88; + bytes memory initProof; + (, initProof) = ffi.getCannonMemory64Proof(addr, word); + + uint64 word2 = 0x55_55_55_55_77_77_77_77; + (bytes32 expectedRoot,) = ffi.getCannonMemory64Proof(addr, word, addr + 8, word2); + + bytes32 newRoot = mem.writeMem(addr + 8, word2, 0, initProof); + assertEq(newRoot, expectedRoot); + } + + /// @dev Static unit test asserting that writes revert when a misaligned memory address is provided + function test_writeMem_writeMemInvalidAddress_reverts() external { + bytes memory zeroProof; + (, zeroProof) = ffi.getCannonMemory64Proof(0x100, 0); + vm.expectRevert(InvalidAddress.selector); + mem.writeMem(0x104, 0x0, 0, zeroProof); + } +} + +contract MIPS64MemoryWithCalldata { + function readMem( + bytes32 _root, + uint64 _addr, + uint8 _proofIndex, + bytes calldata /* _proof */ + ) + external + pure + returns (uint64 out_) + { + uint256 proofDataOffset = 4 + 32 + 32 + 32 + 32 + 32; + uint256 proofOffset = MIPS64Memory.memoryProofOffset(proofDataOffset, _proofIndex); + return MIPS64Memory.readMem(_root, _addr, proofOffset); + } + + function writeMem( + uint64 _addr, + uint64 _value, + uint8 _proofIndex, + bytes calldata /* _proof */ + ) + external + pure + returns (bytes32 root_) + { + uint256 proofDataOffset = 4 + 32 + 32 + 32 + 32 + 32; + uint256 proofOffset = MIPS64Memory.memoryProofOffset(proofDataOffset, _proofIndex); + return MIPS64Memory.writeMem(_addr, proofOffset, _value); + } +} diff --git a/packages/contracts-bedrock/test/cannon/PreimageOracle.t.sol b/packages/contracts-bedrock/test/cannon/PreimageOracle.t.sol index d43d52784ba52..1c4d41728fccc 100644 --- a/packages/contracts-bedrock/test/cannon/PreimageOracle.t.sol +++ b/packages/contracts-bedrock/test/cannon/PreimageOracle.t.sol @@ -391,7 +391,7 @@ contract PreimageOracle_LargePreimageProposals_Test is Test { } /// @notice Gas snapshot for `addLeaves` - function test_addLeaves_gasSnapshot() public { + function test_addLeaves_gasSnapshot_benchmark() public { // Allocate the preimage data. bytes memory data = new bytes(136 * 500); for (uint256 i; i < data.length; i++) { diff --git a/packages/contracts-bedrock/test/dispute/AnchorStateRegistry.t.sol b/packages/contracts-bedrock/test/dispute/AnchorStateRegistry.t.sol index b5dbac76f6c6a..524423292058f 100644 --- a/packages/contracts-bedrock/test/dispute/AnchorStateRegistry.t.sol +++ b/packages/contracts-bedrock/test/dispute/AnchorStateRegistry.t.sol @@ -49,9 +49,7 @@ contract AnchorStateRegistry_TryUpdateAnchorState_Test is AnchorStateRegistry_In assert(l2BlockNumber < gameProxy.l2BlockNumber()); // Mock the state that we want. - vm.mockCall( - address(gameProxy), abi.encodeWithSelector(gameProxy.status.selector), abi.encode(GameStatus.DEFENDER_WINS) - ); + vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.status, ()), abi.encode(GameStatus.DEFENDER_WINS)); // Try to update the anchor state. vm.prank(address(gameProxy)); @@ -66,15 +64,13 @@ contract AnchorStateRegistry_TryUpdateAnchorState_Test is AnchorStateRegistry_In /// @dev Tests that updating the anchor state fails when the game state is valid but older. function test_tryUpdateAnchorState_validOlderState_fails() public { // Confirm that the anchor state is newer than the game state. - vm.mockCall(address(gameProxy), abi.encodeWithSelector(gameProxy.l2BlockNumber.selector), abi.encode(0)); + vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.l2BlockNumber, ()), abi.encode(0)); (Hash root, uint256 l2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType()); assert(l2BlockNumber >= gameProxy.l2BlockNumber()); // Mock the state that we want. - vm.mockCall(address(gameProxy), abi.encodeWithSelector(gameProxy.l2BlockNumber.selector), abi.encode(0)); - vm.mockCall( - address(gameProxy), abi.encodeWithSelector(gameProxy.status.selector), abi.encode(GameStatus.DEFENDER_WINS) - ); + vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.l2BlockNumber, ()), abi.encode(0)); + vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.status, ()), abi.encode(GameStatus.DEFENDER_WINS)); // Try to update the anchor state. vm.prank(address(gameProxy)); @@ -93,11 +89,7 @@ contract AnchorStateRegistry_TryUpdateAnchorState_Test is AnchorStateRegistry_In assert(l2BlockNumber < gameProxy.l2BlockNumber()); // Mock the state that we want. - vm.mockCall( - address(gameProxy), - abi.encodeWithSelector(gameProxy.status.selector), - abi.encode(GameStatus.CHALLENGER_WINS) - ); + vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.status, ()), abi.encode(GameStatus.CHALLENGER_WINS)); // Try to update the anchor state. vm.prank(address(gameProxy)); @@ -118,8 +110,8 @@ contract AnchorStateRegistry_TryUpdateAnchorState_Test is AnchorStateRegistry_In // Mock the state that we want. vm.mockCall( address(disputeGameFactory), - abi.encodeWithSelector( - disputeGameFactory.games.selector, gameProxy.gameType(), gameProxy.rootClaim(), gameProxy.extraData() + abi.encodeCall( + disputeGameFactory.games, (gameProxy.gameType(), gameProxy.rootClaim(), gameProxy.extraData()) ), abi.encode(address(0), 0) ); @@ -138,13 +130,16 @@ contract AnchorStateRegistry_TryUpdateAnchorState_Test is AnchorStateRegistry_In function test_setAnchorState_invalidGame_fails() public { // Confirm that the anchor state is older than the game state. (Hash root, uint256 l2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType()); - require(l2BlockNumber < gameProxy.l2BlockNumber(), "l2BlockNumber < gameProxy.l2BlockNumber()"); + require( + l2BlockNumber < gameProxy.l2BlockNumber(), + "AnchorStateRegistry_TryUpdateAnchorState_Test: l2BlockNumber < gameProxy.l2BlockNumber()" + ); // Mock the state that we want. vm.mockCall( address(disputeGameFactory), - abi.encodeWithSelector( - disputeGameFactory.games.selector, gameProxy.gameType(), gameProxy.rootClaim(), gameProxy.extraData() + abi.encodeCall( + disputeGameFactory.games, (gameProxy.gameType(), gameProxy.rootClaim(), gameProxy.extraData()) ), abi.encode(address(0), 0) ); @@ -165,11 +160,7 @@ contract AnchorStateRegistry_TryUpdateAnchorState_Test is AnchorStateRegistry_In (Hash root, uint256 l2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType()); // Mock the state that we want. - vm.mockCall( - address(gameProxy), - abi.encodeWithSelector(gameProxy.status.selector), - abi.encode(GameStatus.CHALLENGER_WINS) - ); + vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.status, ()), abi.encode(GameStatus.CHALLENGER_WINS)); // Set the anchor state. vm.prank(superchainConfig.guardian()); @@ -187,9 +178,7 @@ contract AnchorStateRegistry_TryUpdateAnchorState_Test is AnchorStateRegistry_In (Hash root, uint256 l2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType()); // Mock the state that we want. - vm.mockCall( - address(gameProxy), abi.encodeWithSelector(gameProxy.status.selector), abi.encode(GameStatus.IN_PROGRESS) - ); + vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.status, ()), abi.encode(GameStatus.IN_PROGRESS)); // Set the anchor state. vm.prank(superchainConfig.guardian()); @@ -205,9 +194,7 @@ contract AnchorStateRegistry_TryUpdateAnchorState_Test is AnchorStateRegistry_In /// @dev Tests that setting the anchor state succeeds. function test_setAnchorState_succeeds() public { // Mock the state that we want. - vm.mockCall( - address(gameProxy), abi.encodeWithSelector(gameProxy.status.selector), abi.encode(GameStatus.DEFENDER_WINS) - ); + vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.status, ()), abi.encode(GameStatus.DEFENDER_WINS)); // Set the anchor state. vm.prank(superchainConfig.guardian()); diff --git a/packages/contracts-bedrock/test/dispute/FaultDisputeGame.t.sol b/packages/contracts-bedrock/test/dispute/FaultDisputeGame.t.sol index 8bb25273972aa..88e361a80b459 100644 --- a/packages/contracts-bedrock/test/dispute/FaultDisputeGame.t.sol +++ b/packages/contracts-bedrock/test/dispute/FaultDisputeGame.t.sol @@ -6,6 +6,7 @@ import { Test } from "forge-std/Test.sol"; import { Vm } from "forge-std/Vm.sol"; import { DisputeGameFactory_Init } from "test/dispute/DisputeGameFactory.t.sol"; import { AlphabetVM } from "test/mocks/AlphabetVM.sol"; +import { stdError } from "forge-std/StdError.sol"; // Scripts import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; @@ -186,9 +187,7 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init { // PreimageOracle constructor will revert if the challenge period is too large, so we need // to mock the call to pretend this is a bugged implementation where the challenge period // is allowed to be too large. - vm.mockCall( - address(oracle), abi.encodeWithSelector(oracle.challengePeriod.selector), abi.encode(_challengePeriod) - ); + vm.mockCall(address(oracle), abi.encodeCall(IPreimageOracle.challengePeriod, ()), abi.encode(_challengePeriod)); vm.expectRevert(InvalidChallengePeriod.selector); DeployUtils.create1({ @@ -536,11 +535,11 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init { Claim claim = _dummyClaim(); // Expect an out of bounds revert for an attack - vm.expectRevert(abi.encodeWithSignature("Panic(uint256)", 0x32)); + vm.expectRevert(stdError.indexOOBError); gameProxy.attack(_dummyClaim(), 1, claim); // Expect an out of bounds revert for a defense - vm.expectRevert(abi.encodeWithSignature("Panic(uint256)", 0x32)); + vm.expectRevert(stdError.indexOOBError); gameProxy.defend(_dummyClaim(), 1, claim); } @@ -1704,14 +1703,14 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init { /// resolves in favor of the defender but the game state is not newer than the anchor state. function test_resolve_validOlderStateSameAnchor_succeeds() public { // Mock the game block to be older than the game state. - vm.mockCall(address(gameProxy), abi.encodeWithSelector(gameProxy.l2BlockNumber.selector), abi.encode(0)); + vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.l2BlockNumber, ()), abi.encode(0)); // Confirm that the anchor state is newer than the game state. (Hash root, uint256 l2BlockNumber) = anchorStateRegistry.anchors(gameProxy.gameType()); assert(l2BlockNumber >= gameProxy.l2BlockNumber()); // Resolve the game. - vm.mockCall(address(gameProxy), abi.encodeWithSelector(gameProxy.l2BlockNumber.selector), abi.encode(0)); + vm.mockCall(address(gameProxy), abi.encodeCall(gameProxy.l2BlockNumber, ()), abi.encode(0)); vm.warp(block.timestamp + 3 days + 12 hours); gameProxy.resolveClaim(0, 0); assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.DEFENDER_WINS)); @@ -2641,7 +2640,7 @@ contract FaultDispute_1v1_Actors_Test is FaultDisputeGame_Init { (uint256 numMovesA,) = dishonest.move(); (uint256 numMovesB, bool success) = honest.move(); - require(success, "Honest actor's moves should always be successful"); + require(success, "FaultDispute_1v1_Actors_Test: Honest actor's moves should always be successful"); // If both actors have run out of moves, we're done. if (numMovesA == 0 && numMovesB == 0) break; diff --git a/packages/contracts-bedrock/test/dispute/WETH98.t.sol b/packages/contracts-bedrock/test/dispute/WETH98.t.sol index a248e19018854..b26cd927f12c8 100644 --- a/packages/contracts-bedrock/test/dispute/WETH98.t.sol +++ b/packages/contracts-bedrock/test/dispute/WETH98.t.sol @@ -5,7 +5,8 @@ pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; // Contracts -import { WETH98 } from "src/universal/WETH98.sol"; +import { IWETH98 } from "src/universal/interfaces/IWETH98.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; contract WETH98_Test is Test { event Approval(address indexed src, address indexed guy, uint256 wad); @@ -13,12 +14,17 @@ contract WETH98_Test is Test { event Deposit(address indexed dst, uint256 wad); event Withdrawal(address indexed src, uint256 wad); - WETH98 public weth; + IWETH98 public weth; address alice; address bob; function setUp() public { - weth = new WETH98(); + weth = IWETH98( + DeployUtils.create1({ + _name: "WETH98", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IWETH98.__constructor__, ())) + }) + ); alice = makeAddr("alice"); bob = makeAddr("bob"); deal(alice, 1 ether); diff --git a/packages/contracts-bedrock/test/governance/MintManager.t.sol b/packages/contracts-bedrock/test/governance/MintManager.t.sol index 4c008863ed691..c29e25602834b 100644 --- a/packages/contracts-bedrock/test/governance/MintManager.t.sol +++ b/packages/contracts-bedrock/test/governance/MintManager.t.sol @@ -4,13 +4,10 @@ pragma solidity 0.8.15; // Testing import { CommonTest } from "test/setup/CommonTest.sol"; -// Contracts -import { GovernanceToken } from "src/governance/GovernanceToken.sol"; -import { MintManager } from "src/governance/MintManager.sol"; - // Interfaces import { IGovernanceToken } from "src/governance/interfaces/IGovernanceToken.sol"; import { IMintManager } from "src/governance/interfaces/IMintManager.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; contract MintManager_Initializer is CommonTest { address constant owner = address(0x1234); @@ -23,10 +20,20 @@ contract MintManager_Initializer is CommonTest { super.setUp(); vm.prank(owner); - gov = IGovernanceToken(address(new GovernanceToken())); + gov = IGovernanceToken( + DeployUtils.create1({ + _name: "GovernanceToken", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IGovernanceToken.__constructor__, ())) + }) + ); vm.prank(owner); - manager = IMintManager(address(new MintManager(owner, address(gov)))); + manager = IMintManager( + DeployUtils.create1({ + _name: "MintManager", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IMintManager.__constructor__, (owner, address(gov)))) + }) + ); vm.prank(owner); gov.transferOwnership(address(manager)); diff --git a/packages/contracts-bedrock/test/invariants/CrossDomainMessenger.t.sol b/packages/contracts-bedrock/test/invariants/CrossDomainMessenger.t.sol index 08a0c0027763e..3bf4ad3f7b3ae 100644 --- a/packages/contracts-bedrock/test/invariants/CrossDomainMessenger.t.sol +++ b/packages/contracts-bedrock/test/invariants/CrossDomainMessenger.t.sol @@ -5,12 +5,11 @@ import { StdUtils } from "forge-std/StdUtils.sol"; import { Vm } from "forge-std/Vm.sol"; import { IOptimismPortal } from "src/L1/interfaces/IOptimismPortal.sol"; import { IL1CrossDomainMessenger } from "src/L1/interfaces/IL1CrossDomainMessenger.sol"; -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { Constants } from "src/libraries/Constants.sol"; import { Encoding } from "src/libraries/Encoding.sol"; import { Hashing } from "src/libraries/Hashing.sol"; -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; contract RelayActor is StdUtils { // Storage slot of the l2Sender @@ -88,7 +87,7 @@ contract RelayActor is StdUtils { } } -contract XDM_MinGasLimits is Bridge_Initializer { +contract XDM_MinGasLimits is CommonTest { RelayActor actor; function init(bool doFail) public virtual { diff --git a/packages/contracts-bedrock/test/invariants/FaultDisputeGame.t.sol b/packages/contracts-bedrock/test/invariants/FaultDisputeGame.t.sol index 49bf2a106bbf4..94b46930ad494 100644 --- a/packages/contracts-bedrock/test/invariants/FaultDisputeGame.t.sol +++ b/packages/contracts-bedrock/test/invariants/FaultDisputeGame.t.sol @@ -69,7 +69,7 @@ contract FaultDisputeGame_Solvency_Invariant is FaultDisputeGame_Init { assertEq(DEFAULT_SENDER.balance, type(uint96).max - rootBond); assertEq(address(actor).balance, actor.totalBonded() + rootBond); } else { - revert("unreachable"); + revert("FaultDisputeGame_Solvency_Invariant: unreachable"); } assertEq(address(gameProxy).balance, 0); diff --git a/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/handlers/Protocol.t.sol b/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/handlers/Protocol.t.sol index d4a12c4067bd0..490a38bec1cff 100644 --- a/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/handlers/Protocol.t.sol +++ b/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/handlers/Protocol.t.sol @@ -151,18 +151,20 @@ contract ProtocolHandler is TestBase, StdUtils, Actors { uint256 chainId ) internal - returns (OptimismSuperchainERC20 supertoken) + returns (OptimismSuperchainERC20 supertoken_) { // this salt would be used in production. Tokens sharing it will be bridgable with each other bytes32 realSalt = keccak256(abi.encode(remoteToken, name, symbol, decimals)); // Foundry invariant erroneously show other unrelated invariant breaking // when this deployment fails due to a create2 collision, so we revert eagerly instead - require(MESSENGER.superTokenAddresses(chainId, realSalt) == address(0), "skip duplicate deployment"); + require( + MESSENGER.superTokenAddresses(chainId, realSalt) == address(0), "ProtocolHandler: skip duplicate deployment" + ); // what we use in the tests to walk around two contracts needing two different addresses // tbf we could be using CREATE1, but this feels more verbose bytes32 hackySalt = keccak256(abi.encode(remoteToken, name, symbol, decimals, chainId)); - supertoken = OptimismSuperchainERC20( + supertoken_ = OptimismSuperchainERC20( address( // TODO: Use the OptimismSuperchainERC20 Beacon Proxy new ERC1967Proxy{ salt: hackySalt }( @@ -171,7 +173,7 @@ contract ProtocolHandler is TestBase, StdUtils, Actors { ) ) ); - MESSENGER.registerSupertoken(realSalt, chainId, address(supertoken)); - allSuperTokens.push(address(supertoken)); + MESSENGER.registerSupertoken(realSalt, chainId, address(supertoken_)); + allSuperTokens.push(address(supertoken_)); } } diff --git a/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/helpers/HandlerGetters.t.sol b/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/helpers/HandlerGetters.t.sol index b081aa48c6bbc..d072dc92165be 100644 --- a/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/helpers/HandlerGetters.t.sol +++ b/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/helpers/HandlerGetters.t.sol @@ -7,16 +7,16 @@ import { EnumerableMap } from "@openzeppelin/contracts/utils/structs/EnumerableM contract HandlerGetters is ProtocolHandler { using EnumerableMap for EnumerableMap.Bytes32ToUintMap; - function deploySaltsLength() external view returns (uint256 length) { + function deploySaltsLength() external view returns (uint256 length_) { return ghost_totalSupplyAcrossChains.length(); } - function totalSupplyAcrossChainsAtIndex(uint256 index) external view returns (bytes32 salt, uint256 supply) { - return ghost_totalSupplyAcrossChains.at(index); + function totalSupplyAcrossChainsAtIndex(uint256 _index) external view returns (bytes32 salt_, uint256 supply_) { + return ghost_totalSupplyAcrossChains.at(_index); } - function tokensInTransitForDeploySalt(bytes32 salt) external view returns (uint256 amount) { - (, amount) = ghost_tokensInTransit.tryGet(salt); - return amount; + function tokensInTransitForDeploySalt(bytes32 _salt) external view returns (uint256 amount_) { + (, amount_) = ghost_tokensInTransit.tryGet(_salt); + return amount_; } } diff --git a/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/helpers/MockL2ToL2CrossDomainMessenger.t.sol b/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/helpers/MockL2ToL2CrossDomainMessenger.t.sol index b5d70596ed634..94f275e26551a 100644 --- a/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/helpers/MockL2ToL2CrossDomainMessenger.t.sol +++ b/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/helpers/MockL2ToL2CrossDomainMessenger.t.sol @@ -89,7 +89,7 @@ contract MockL2ToL2CrossDomainMessenger { function sendMessage(uint256 chainId, address, /*recipient*/ bytes calldata data) external { address crossChainRecipient = superTokenAddresses[chainId][superTokenInitDeploySalts[msg.sender]]; if (crossChainRecipient == msg.sender) { - require(false, "same chain"); + require(false, "MockL2ToL2CrossDomainMessenger: same chain"); } (address recipient, uint256 amount) = _decodePayload(data); @@ -112,7 +112,7 @@ contract MockL2ToL2CrossDomainMessenger { // Internal helpers // //////////////////////// - function _decodePayload(bytes calldata payload) internal pure returns (address recipient, uint256 amount) { - (, recipient, amount) = abi.decode(payload[4:], (address, address, uint256)); + function _decodePayload(bytes calldata payload) internal pure returns (address recipient_, uint256 amount_) { + (, recipient_, amount_) = abi.decode(payload[4:], (address, address, uint256)); } } diff --git a/packages/contracts-bedrock/test/invariants/SafeCall.t.sol b/packages/contracts-bedrock/test/invariants/SafeCall.t.sol index 0a70c3ddd9062..2de6183bd130c 100644 --- a/packages/contracts-bedrock/test/invariants/SafeCall.t.sol +++ b/packages/contracts-bedrock/test/invariants/SafeCall.t.sol @@ -103,10 +103,7 @@ contract SafeCaller_Actor is StdUtils { vm.expectCallMinGas(to, value, minGas, hex""); bool success = SafeCall.call( - msg.sender, - gas, - value, - abi.encodeWithSelector(SafeCall_Succeeds_Invariants.performSafeCallMinGas.selector, to, minGas) + msg.sender, gas, value, abi.encodeCall(SafeCall_Succeeds_Invariants.performSafeCallMinGas, (to, minGas)) ); if (success && FAILS) numCalls++; diff --git a/packages/contracts-bedrock/test/invariants/SystemConfig.t.sol b/packages/contracts-bedrock/test/invariants/SystemConfig.t.sol index 1321499462b71..5b0b300abda07 100644 --- a/packages/contracts-bedrock/test/invariants/SystemConfig.t.sol +++ b/packages/contracts-bedrock/test/invariants/SystemConfig.t.sol @@ -2,17 +2,27 @@ pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; -import { SystemConfig } from "src/L1/SystemConfig.sol"; import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; -import { Proxy } from "src/universal/Proxy.sol"; +import { IProxy } from "src/universal/interfaces/IProxy.sol"; import { Constants } from "src/libraries/Constants.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; contract SystemConfig_GasLimitBoundaries_Invariant is Test { ISystemConfig public config; function setUp() external { - Proxy proxy = new Proxy(msg.sender); - ISystemConfig configImpl = ISystemConfig(address(new SystemConfig())); + IProxy proxy = IProxy( + DeployUtils.create1({ + _name: "Proxy", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (msg.sender))) + }) + ); + ISystemConfig configImpl = ISystemConfig( + DeployUtils.create1({ + _name: "SystemConfig", + _args: DeployUtils.encodeConstructor(abi.encodeCall(ISystemConfig.__constructor__, ())) + }) + ); vm.prank(msg.sender); proxy.upgradeToAndCall( diff --git a/packages/contracts-bedrock/test/kontrol/README.md b/packages/contracts-bedrock/test/kontrol/README.md index 25660756963ce..7e4dc5a2809a8 100644 --- a/packages/contracts-bedrock/test/kontrol/README.md +++ b/packages/contracts-bedrock/test/kontrol/README.md @@ -115,12 +115,6 @@ The `runKontrolDeployment` function of [`KontrolDeployment`](./deployment/Kontro Once new deployment steps have been added to `runKontrolDeployment` the state-diff files have to [be rebuilt](#build-deployment-summary). -#### Include existing tests on the new state-diff recorded bytecode - -The next step is to include tests for the newly included state updates in [`DeploymentSummary.t.sol`](deployment/DeploymentSummary.t.sol). These tests inherit the tests from [`test`](../L1) of the contracts deployed by `runKontrolDeployment`. This ensures that deployment steps were implemented correctly and that the state updates are correct. - -It might be necessary to set some of the existing tests from [`test`](../L1) as virtual because they can't be executed as is. See [`DeploymentSummary.t.sol`](deployment/DeploymentSummary.t.sol) for more concrete examples. - #### Write the proof Write your proof in a `.k.sol` file in the [`proofs`](./proofs/) folder, which is the `test` directory used by the `kprove` profile to run the proofs (see [Deployment Summary Process](#deployment-summary-process)). The name of the new proofs should start with `prove` (or `check`) instead of `test` to avoid `forge test` running them. The reason for this is that if Kontrol cheatcodes (see [Kontrol's own cheatcodes](https://github.com/runtimeverification/kontrol-cheatcodes/blob/master/src/KontrolCheats.sol)) are used in a test, it will not be runnable by `forge`. Currently, none of the tests are using custom Kontrol cheatcodes, but this is something to bear in mind. @@ -143,8 +137,7 @@ function setUp() public { superchainConfig = SuperchainConfig(superchainConfigProxyAddress); } ``` - -Note that the names of the addresses come from [`DeploymentSummary.t.sol`](deployment/DeploymentSummary.t.sol) and are automatically generated by the [`make-summary-deployment.sh`](./scripts/make-summary-deployment.sh) script. +Note that the names of the addresses are automatically generated by the [`make-summary-deployment.sh`](./scripts/make-summary-deployment.sh) script. #### Add your test to [`run-kontrol.sh`](./scripts/run-kontrol.sh) @@ -155,7 +148,6 @@ As described in [Execute Proofs](#execute-proofs), there's a `script` mode for s ### Assumptions 1. A critical invariant of the `KontrolDeployment.sol` contract is that it stays in sync with the original `Deploy.s.sol` contract. - Currently, this is partly enforced by running some of the standard post-`setUp` deployment assertions in `DeploymentSummary.t.sol`. A more rigorous approach may be to leverage the `ChainAssertions` library, but more investigation is required to determine if this is feasible without large changes to the deploy script. 2. Size of `bytes[]` arguments. In [`OptimismPortal.k.sol`](./proofs/OptimismPortal.k.sol), the `prove_proveWithdrawalTransaction_paused` proof is broken down into 11 different proofs, each corresponding to a different size of the `_withdrawalProof` argument, which is of type `bytes[]`. We execute the same logic for lengths of `_withdrawalProof` ranging from 0 to 10, setting the length of each symbolic `bytes` element to 600. diff --git a/packages/contracts-bedrock/test/kontrol/proofs/L1ERC721Bridge.k.sol b/packages/contracts-bedrock/test/kontrol/proofs/L1ERC721Bridge.k.sol index 015ee020e7d12..5e45e3e3a9fd5 100644 --- a/packages/contracts-bedrock/test/kontrol/proofs/L1ERC721Bridge.k.sol +++ b/packages/contracts-bedrock/test/kontrol/proofs/L1ERC721Bridge.k.sol @@ -34,7 +34,7 @@ contract L1ERC721BridgeKontrol is DeploymentSummaryFaultProofs, KontrolUtils { vm.mockCall( address(l1ERC721Bridge.messenger()), - abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(CrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1ERC721Bridge.otherBridge())) ); diff --git a/packages/contracts-bedrock/test/kontrol/proofs/L1StandardBridge.k.sol b/packages/contracts-bedrock/test/kontrol/proofs/L1StandardBridge.k.sol index 6e65f852719b9..b5f8793426e6c 100644 --- a/packages/contracts-bedrock/test/kontrol/proofs/L1StandardBridge.k.sol +++ b/packages/contracts-bedrock/test/kontrol/proofs/L1StandardBridge.k.sol @@ -34,7 +34,7 @@ contract L1StandardBridgeKontrol is DeploymentSummaryFaultProofs, KontrolUtils { vm.mockCall( address(l1standardBridge.messenger()), - abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(CrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1standardBridge.otherBridge())) ); @@ -59,7 +59,7 @@ contract L1StandardBridgeKontrol is DeploymentSummaryFaultProofs, KontrolUtils { vm.mockCall( address(l1standardBridge.messenger()), - abi.encodeWithSelector(CrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(CrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1standardBridge.otherBridge())) ); diff --git a/packages/contracts-bedrock/test/kontrol/scripts/run-kontrol.sh b/packages/contracts-bedrock/test/kontrol/scripts/run-kontrol.sh index 935f6e3b49036..a1487eecd867d 100755 --- a/packages/contracts-bedrock/test/kontrol/scripts/run-kontrol.sh +++ b/packages/contracts-bedrock/test/kontrol/scripts/run-kontrol.sh @@ -207,13 +207,13 @@ get_log_results # Now you can use ${results[0]} and ${results[1]} # to check the results of kontrol_build and kontrol_prove, respectively -if [ ${results[0]} -ne 0 ] && [ ${results[1]} -ne 0 ]; then +if [ "${results[0]}" -ne 0 ] && [ "${results[1]}" -ne 0 ]; then echo "Kontrol Build and Prove Failed" exit 1 -elif [ ${results[0]} -ne 0 ]; then +elif [ "${results[0]}" -ne 0 ]; then echo "Kontrol Build Failed" exit 1 -elif [ ${results[1]} -ne 0 ]; then +elif [ "${results[1]}" -ne 0 ]; then echo "Kontrol Prove Failed" exit 2 else diff --git a/packages/contracts-bedrock/test/legacy/DeployerWhitelist.t.sol b/packages/contracts-bedrock/test/legacy/DeployerWhitelist.t.sol index ab624df2b3227..3f140e9a07254 100644 --- a/packages/contracts-bedrock/test/legacy/DeployerWhitelist.t.sol +++ b/packages/contracts-bedrock/test/legacy/DeployerWhitelist.t.sol @@ -5,14 +5,20 @@ pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; // Target contract -import { DeployerWhitelist } from "src/legacy/DeployerWhitelist.sol"; +import { IDeployerWhitelist } from "src/legacy/interfaces/IDeployerWhitelist.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; contract DeployerWhitelist_Test is Test { - DeployerWhitelist list; + IDeployerWhitelist list; /// @dev Sets up the test suite. function setUp() public { - list = new DeployerWhitelist(); + list = IDeployerWhitelist( + DeployUtils.create1({ + _name: "DeployerWhitelist", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IDeployerWhitelist.__constructor__, ())) + }) + ); } /// @dev Tests that `owner` is initialized to the zero address. diff --git a/packages/contracts-bedrock/test/legacy/L1BlockNumber.t.sol b/packages/contracts-bedrock/test/legacy/L1BlockNumber.t.sol index 633a324e40435..49758739d2da8 100644 --- a/packages/contracts-bedrock/test/legacy/L1BlockNumber.t.sol +++ b/packages/contracts-bedrock/test/legacy/L1BlockNumber.t.sol @@ -5,23 +5,29 @@ pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; // Contracts -import { L1BlockNumber } from "src/legacy/L1BlockNumber.sol"; +import { IL1BlockNumber } from "src/legacy/interfaces/IL1BlockNumber.sol"; import { L1Block } from "src/L2/L1Block.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; contract L1BlockNumberTest is Test { L1Block lb; - L1BlockNumber bn; + IL1BlockNumber bn; uint64 constant number = 99; /// @dev Sets up the test suite. function setUp() external { - vm.etch(Predeploys.L1_BLOCK_ATTRIBUTES, address(new L1Block()).code); + vm.etch(Predeploys.L1_BLOCK_ATTRIBUTES, vm.getDeployedCode("L1Block.sol:L1Block")); lb = L1Block(Predeploys.L1_BLOCK_ATTRIBUTES); - bn = new L1BlockNumber(); + bn = IL1BlockNumber( + DeployUtils.create1({ + _name: "L1BlockNumber", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IL1BlockNumber.__constructor__, ())) + }) + ); vm.prank(lb.DEPOSITOR_ACCOUNT()); lb.setL1BlockValues({ diff --git a/packages/contracts-bedrock/test/legacy/ResolvedDelegateProxy.t.sol b/packages/contracts-bedrock/test/legacy/ResolvedDelegateProxy.t.sol index 33a81bc2ca0e1..5b1f40d55bd8d 100644 --- a/packages/contracts-bedrock/test/legacy/ResolvedDelegateProxy.t.sol +++ b/packages/contracts-bedrock/test/legacy/ResolvedDelegateProxy.t.sol @@ -5,45 +5,74 @@ pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; // Target contract dependencies -import { AddressManager } from "src/legacy/AddressManager.sol"; +import { IAddressManager } from "src/legacy/interfaces/IAddressManager.sol"; // Target contract -import { ResolvedDelegateProxy } from "src/legacy/ResolvedDelegateProxy.sol"; +import { IResolvedDelegateProxy } from "src/legacy/interfaces/IResolvedDelegateProxy.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; contract ResolvedDelegateProxy_Test is Test { - AddressManager internal addressManager; + IAddressManager internal addressManager; SimpleImplementation internal impl; SimpleImplementation internal proxy; /// @dev Sets up the test suite. function setUp() public { // Set up the address manager. - addressManager = new AddressManager(); + addressManager = IAddressManager( + DeployUtils.create1({ + _name: "AddressManager", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IAddressManager.__constructor__, ())) + }) + ); impl = new SimpleImplementation(); addressManager.setAddress("SimpleImplementation", address(impl)); // Set up the proxy. - proxy = SimpleImplementation(address(new ResolvedDelegateProxy(addressManager, "SimpleImplementation"))); + proxy = SimpleImplementation( + address( + DeployUtils.create1({ + _name: "ResolvedDelegateProxy", + _args: DeployUtils.encodeConstructor( + abi.encodeCall(IResolvedDelegateProxy.__constructor__, (addressManager, "SimpleImplementation")) + ) + }) + ) + ); } /// @dev Tests that the proxy properly bubbles up returndata when the delegatecall succeeds. function testFuzz_fallback_delegateCallFoo_succeeds(uint256 x) public { - vm.expectCall(address(impl), abi.encodeWithSelector(impl.foo.selector, x)); + vm.expectCall(address(impl), abi.encodeCall(impl.foo, (x))); assertEq(proxy.foo(x), x); } /// @dev Tests that the proxy properly bubbles up returndata when the delegatecall reverts. function test_fallback_delegateCallBar_reverts() public { vm.expectRevert("SimpleImplementation: revert"); - vm.expectCall(address(impl), abi.encodeWithSelector(impl.bar.selector)); + vm.expectCall(address(impl), abi.encodeCall(impl.bar, ())); proxy.bar(); } /// @dev Tests that the proxy fallback reverts as expected if the implementation within the /// address manager is not set. function test_fallback_addressManagerNotSet_reverts() public { - AddressManager am = new AddressManager(); - SimpleImplementation p = SimpleImplementation(address(new ResolvedDelegateProxy(am, "SimpleImplementation"))); + IAddressManager am = IAddressManager( + DeployUtils.create1({ + _name: "AddressManager", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IAddressManager.__constructor__, ())) + }) + ); + SimpleImplementation p = SimpleImplementation( + address( + DeployUtils.create1({ + _name: "ResolvedDelegateProxy", + _args: DeployUtils.encodeConstructor( + abi.encodeCall(IResolvedDelegateProxy.__constructor__, (am, "SimpleImplementation")) + ) + }) + ) + ); vm.expectRevert("ResolvedDelegateProxy: target address must be initialized"); p.foo(0); diff --git a/packages/contracts-bedrock/test/libraries/Blueprint.t.sol b/packages/contracts-bedrock/test/libraries/Blueprint.t.sol index c94616a88e4fe..3e2a96a019128 100644 --- a/packages/contracts-bedrock/test/libraries/Blueprint.t.sol +++ b/packages/contracts-bedrock/test/libraries/Blueprint.t.sol @@ -56,7 +56,7 @@ contract Blueprint_Test is Test { // --- We start with the test cases from ERC-5202 --- // An example (and trivial!) blueprint contract with no data section, whose initcode is just the STOP instruction. - function test_ERC5202_trivialBlueprint_succeeds() public view { + function test_trivialBlueprint_erc5202_succeeds() public view { bytes memory bytecode = hex"FE710000"; Blueprint.Preamble memory preamble = blueprint.parseBlueprintPreamble(bytecode); @@ -67,7 +67,7 @@ contract Blueprint_Test is Test { // An example blueprint contract whose initcode is the trivial STOP instruction and whose data // section contains the byte 0xFF repeated seven times. - function test_ERC5202_blueprintWithDataSection_succeeds() public view { + function test_blueprintWithDataSection_erc5202_succeeds() public view { // Here, 0xFE71 is the magic header, 0x01 means version 0 + 1 length bit, 0x07 encodes the // length in bytes of the data section. These are followed by the data section, and then the // initcode. For illustration, this code with delimiters would be: @@ -82,7 +82,7 @@ contract Blueprint_Test is Test { // An example blueprint whose initcode is the trivial STOP instruction and whose data section // contains the byte 0xFF repeated 256 times. - function test_ERC5202_blueprintWithLargeDataSection_succeeds() public view { + function test_blueprintWithLargeDataSection_erc5205_succeeds() public view { // Delimited, this would be 0xFE71|02|0100|FF...FF|00 bytes memory bytecode = hex"FE71020100FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00"; diff --git a/packages/contracts-bedrock/test/libraries/SafeCall.t.sol b/packages/contracts-bedrock/test/libraries/SafeCall.t.sol index fcb9d3832a120..ffdf07b09b83e 100644 --- a/packages/contracts-bedrock/test/libraries/SafeCall.t.sol +++ b/packages/contracts-bedrock/test/libraries/SafeCall.t.sol @@ -122,12 +122,12 @@ contract SafeCall_Test is Test { for (uint64 i = 40_000; i < 100_000; i++) { uint256 snapshot = vm.snapshot(); - // 65_907 is the exact amount of gas required to make the safe call + // 65_922 is the exact amount of gas required to make the safe call // successfully. - if (i < 65_907) { + if (i < 65_922) { assertFalse(caller.makeSafeCall(i, 25_000)); } else { - vm.expectCallMinGas(address(caller), 0, 25_000, abi.encodeWithSelector(caller.setA.selector, 1)); + vm.expectCallMinGas(address(caller), 0, 25_000, abi.encodeCall(caller.setA, (1))); assertTrue(caller.makeSafeCall(i, 25_000)); } @@ -142,12 +142,12 @@ contract SafeCall_Test is Test { for (uint64 i = 15_200_000; i < 15_300_000; i++) { uint256 snapshot = vm.snapshot(); - // 15_278_606 is the exact amount of gas required to make the safe call + // 15_278_621 is the exact amount of gas required to make the safe call // successfully. - if (i < 15_278_606) { + if (i < 15_278_621) { assertFalse(caller.makeSafeCall(i, 15_000_000)); } else { - vm.expectCallMinGas(address(caller), 0, 15_000_000, abi.encodeWithSelector(caller.setA.selector, 1)); + vm.expectCallMinGas(address(caller), 0, 15_000_000, abi.encodeCall(caller.setA, (1))); assertTrue(caller.makeSafeCall(i, 15_000_000)); } @@ -160,11 +160,11 @@ contract SimpleSafeCaller { uint256 public a; function makeSafeCall(uint64 gas, uint64 minGas) external returns (bool) { - return SafeCall.call(address(this), gas, 0, abi.encodeWithSelector(this.makeSafeCallMinGas.selector, minGas)); + return SafeCall.call(address(this), gas, 0, abi.encodeCall(this.makeSafeCallMinGas, (minGas))); } function makeSafeCallMinGas(uint64 minGas) external returns (bool) { - return SafeCall.callWithMinGas(address(this), minGas, 0, abi.encodeWithSelector(this.setA.selector, 1)); + return SafeCall.callWithMinGas(address(this), minGas, 0, abi.encodeCall(this.setA, (1))); } function setA(uint256 _a) external { diff --git a/packages/contracts-bedrock/test/libraries/TransientContext.t.sol b/packages/contracts-bedrock/test/libraries/TransientContext.t.sol index a7b414ad38828..20e8434b9c16c 100644 --- a/packages/contracts-bedrock/test/libraries/TransientContext.t.sol +++ b/packages/contracts-bedrock/test/libraries/TransientContext.t.sol @@ -88,7 +88,7 @@ contract TransientContextTest is Test { /// @param _slot Slot to test. /// @param _value1 Value to write to slot at call depth 0. /// @param _value2 Value to write to slot at call depth 1. - function testFuzz_setGet_twice_sameDepth_succeeds(bytes32 _slot, uint256 _value1, uint256 _value2) public { + function testFuzz_setGet_twiceSameDepth_succeeds(bytes32 _slot, uint256 _value1, uint256 _value2) public { assertEq(TransientContext.callDepth(), 0); testFuzz_set_succeeds(_slot, _value1); assertEq(TransientContext.get(_slot), _value1); @@ -102,7 +102,7 @@ contract TransientContextTest is Test { /// @param _slot Slot to test. /// @param _value1 Value to write to slot at call depth 0. /// @param _value2 Value to write to slot at call depth 1. - function testFuzz_setGet_twice_differentDepth_succeeds(bytes32 _slot, uint256 _value1, uint256 _value2) public { + function testFuzz_setGet_twiceDifferentDepth_succeeds(bytes32 _slot, uint256 _value1, uint256 _value2) public { assertEq(TransientContext.callDepth(), 0); testFuzz_set_succeeds(_slot, _value1); assertEq(TransientContext.get(_slot), _value1); diff --git a/packages/contracts-bedrock/test/libraries/trie/MerkleTrie.t.sol b/packages/contracts-bedrock/test/libraries/trie/MerkleTrie.t.sol index 7b5c7c6357b20..781ada3433352 100644 --- a/packages/contracts-bedrock/test/libraries/trie/MerkleTrie.t.sol +++ b/packages/contracts-bedrock/test/libraries/trie/MerkleTrie.t.sol @@ -351,7 +351,7 @@ contract MerkleTrie_get_Test is Test { // Ambiguous revert check- all that we care is that it *does* fail. This case may // fail within different branches. - vm.expectRevert(); + vm.expectRevert(); // nosemgrep: sol-safety-expectrevert-no-args MerkleTrie.get(key, proof, root); } diff --git a/packages/contracts-bedrock/test/mocks/Callers.sol b/packages/contracts-bedrock/test/mocks/Callers.sol index aa7a2dc8b2289..b8dd70df15e14 100644 --- a/packages/contracts-bedrock/test/mocks/Callers.sol +++ b/packages/contracts-bedrock/test/mocks/Callers.sol @@ -84,7 +84,7 @@ contract ConfigurableCaller { /// @dev Any call will revert contract Reverter { function doRevert() public pure { - revert("Reverter reverted"); + revert("Reverter: Reverter reverted"); } fallback() external { diff --git a/packages/contracts-bedrock/test/mocks/TestERC1271Wallet.sol b/packages/contracts-bedrock/test/mocks/TestERC1271Wallet.sol index c04ed608b7d70..6e2ef47f67e61 100644 --- a/packages/contracts-bedrock/test/mocks/TestERC1271Wallet.sol +++ b/packages/contracts-bedrock/test/mocks/TestERC1271Wallet.sol @@ -13,7 +13,15 @@ contract TestERC1271Wallet is Ownable, IERC1271 { 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); + 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/mocks/block.json b/packages/contracts-bedrock/test/mocks/block.json deleted file mode 100644 index 7de13ed6135a6..0000000000000 --- a/packages/contracts-bedrock/test/mocks/block.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "hash": "0xfd3c5e25a80f54a53c58bd3ad8c076dc1c0cdbd44ec2164d2d2b8cc50481cb78", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "miner": "0x0000000000000000000000000000000000000000", - "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", - "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "receiptsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", - "number": "0x0", - "gasUsed": "0x0", - "gasLimit": "0x1c9c380", - "extraData": "0x", - "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x654caabb", - "difficulty": "0x0", - "totalDifficulty": "0x0", - "sealFields": [ - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000" - ], - "uncles": [], - "transactions": [], - "size": "0x202", - "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": "0x0000000000000000", - "baseFeePerGas": "0x3b9aca00" -} diff --git a/packages/contracts-bedrock/test/opcm/DeployAltDA.t.sol b/packages/contracts-bedrock/test/opcm/DeployAltDA.t.sol new file mode 100644 index 0000000000000..d7cdc69f37e71 --- /dev/null +++ b/packages/contracts-bedrock/test/opcm/DeployAltDA.t.sol @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { Test } from "forge-std/Test.sol"; + +import { DeployAltDAInput, DeployAltDAOutput, DeployAltDA } from "scripts/deploy/DeployAltDA.s.sol"; +import { IDataAvailabilityChallenge } from "src/L1/interfaces/IDataAvailabilityChallenge.sol"; +import { IProxyAdmin } from "src/universal/interfaces/IProxyAdmin.sol"; +import { IProxy } from "src/universal/interfaces/IProxy.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; + +contract DeployAltDAInput_Test is Test { + DeployAltDAInput dai; + + // Define defaults + bytes32 salt = bytes32(uint256(1)); + address proxyAdminAddr = makeAddr("proxyAdmin"); + address challengeContractOwner = makeAddr("challengeContractOwner"); + uint256 challengeWindow = 100; + uint256 resolveWindow = 200; + uint256 bondSize = 1 ether; + uint256 resolverRefundPercentage = 10; + + function setUp() public { + dai = new DeployAltDAInput(); + } + + function test_set_succeeds() public { + dai.set(dai.salt.selector, salt); + dai.set(dai.proxyAdmin.selector, proxyAdminAddr); + dai.set(dai.challengeContractOwner.selector, challengeContractOwner); + dai.set(dai.challengeWindow.selector, challengeWindow); + dai.set(dai.resolveWindow.selector, resolveWindow); + dai.set(dai.bondSize.selector, bondSize); + dai.set(dai.resolverRefundPercentage.selector, resolverRefundPercentage); + + // Compare the default inputs to the getter methods + assertEq(salt, dai.salt(), "100"); + assertEq(proxyAdminAddr, address(dai.proxyAdmin()), "200"); + assertEq(challengeContractOwner, dai.challengeContractOwner(), "300"); + assertEq(challengeWindow, dai.challengeWindow(), "400"); + assertEq(resolveWindow, dai.resolveWindow(), "500"); + assertEq(bondSize, dai.bondSize(), "600"); + assertEq(resolverRefundPercentage, dai.resolverRefundPercentage(), "700"); + } + + function test_getters_whenNotSet_reverts() public { + bytes memory expectedErr = "DeployAltDAInput: "; + + vm.expectRevert(abi.encodePacked(expectedErr, "salt not set")); + dai.salt(); + + vm.expectRevert(abi.encodePacked(expectedErr, "proxyAdmin not set")); + dai.proxyAdmin(); + + vm.expectRevert(abi.encodePacked(expectedErr, "challengeContractOwner not set")); + dai.challengeContractOwner(); + + vm.expectRevert(abi.encodePacked(expectedErr, "challengeWindow not set")); + dai.challengeWindow(); + + vm.expectRevert(abi.encodePacked(expectedErr, "resolveWindow not set")); + dai.resolveWindow(); + + vm.expectRevert(abi.encodePacked(expectedErr, "bondSize not set")); + dai.bondSize(); + + vm.expectRevert(abi.encodePacked(expectedErr, "resolverRefundPercentage not set")); + dai.resolverRefundPercentage(); + } + + function test_set_zeroAddress_reverts() public { + vm.expectRevert("DeployAltDAInput: cannot set zero address"); + dai.set(dai.proxyAdmin.selector, address(0)); + + vm.expectRevert("DeployAltDAInput: cannot set zero address"); + dai.set(dai.challengeContractOwner.selector, address(0)); + } + + function test_set_unknownSelector_reverts() public { + bytes4 unknownSelector = bytes4(keccak256("unknown()")); + + vm.expectRevert("DeployAltDAInput: unknown selector"); + dai.set(unknownSelector, bytes32(0)); + + vm.expectRevert("DeployAltDAInput: unknown selector"); + dai.set(unknownSelector, address(1)); + + vm.expectRevert("DeployAltDAInput: unknown selector"); + dai.set(unknownSelector, uint256(1)); + } +} + +contract DeployAltDAOutput_Test is Test { + DeployAltDAOutput dao; + + // Store contract references to avoid stack too deep + IDataAvailabilityChallenge internal dataAvailabilityChallengeImpl; + + function setUp() public { + dao = new DeployAltDAOutput(); + dataAvailabilityChallengeImpl = IDataAvailabilityChallenge(payable(makeAddr("dataAvailabilityChallengeImpl"))); + } + + function test_set_succeeds() public { + // Build the implementation with some bytecode + vm.etch(address(dataAvailabilityChallengeImpl), hex"01"); + + // Build proxy with implementation + (IProxy dataAvailabilityChallengeProxy) = + DeployUtils.buildERC1967ProxyWithImpl("dataAvailabilityChallengeProxy"); + + // Set the addresses + dao.set(dao.dataAvailabilityChallengeProxy.selector, address(dataAvailabilityChallengeProxy)); + dao.set(dao.dataAvailabilityChallengeImpl.selector, address(dataAvailabilityChallengeImpl)); + + // Verify the addresses were set correctly + assertEq(address(dataAvailabilityChallengeProxy), address(dao.dataAvailabilityChallengeProxy()), "100"); + assertEq(address(dataAvailabilityChallengeImpl), address(dao.dataAvailabilityChallengeImpl()), "200"); + } + + function test_getters_whenNotSet_reverts() public { + vm.expectRevert("DeployUtils: zero address"); + dao.dataAvailabilityChallengeProxy(); + + vm.expectRevert("DeployUtils: zero address"); + dao.dataAvailabilityChallengeImpl(); + } + + function test_getters_whenAddrHasNoCode_reverts() public { + address emptyAddr = makeAddr("emptyAddr"); + bytes memory expectedErr = bytes(string.concat("DeployUtils: no code at ", vm.toString(emptyAddr))); + + dao.set(dao.dataAvailabilityChallengeProxy.selector, emptyAddr); + vm.expectRevert(expectedErr); + dao.dataAvailabilityChallengeProxy(); + + dao.set(dao.dataAvailabilityChallengeImpl.selector, emptyAddr); + vm.expectRevert(expectedErr); + dao.dataAvailabilityChallengeImpl(); + } + + function test_set_zeroAddress_reverts() public { + vm.expectRevert("DeployAltDAOutput: cannot set zero address"); + dao.set(dao.dataAvailabilityChallengeProxy.selector, address(0)); + + vm.expectRevert("DeployAltDAOutput: cannot set zero address"); + dao.set(dao.dataAvailabilityChallengeImpl.selector, address(0)); + } + + function test_set_unknownSelector_reverts() public { + bytes4 unknownSelector = bytes4(keccak256("unknown()")); + vm.expectRevert("DeployAltDAOutput: unknown selector"); + dao.set(unknownSelector, address(1)); + } +} + +contract DeployAltDA_Test is Test { + DeployAltDA deployer; + DeployAltDAInput dai; + DeployAltDAOutput dao; + + // Define defaults + bytes32 salt = bytes32(uint256(1)); + IProxyAdmin proxyAdmin; + address challengeContractOwner = makeAddr("challengeContractOwner"); + uint256 challengeWindow = 100; + uint256 resolveWindow = 200; + uint256 bondSize = 1 ether; + uint256 resolverRefundPercentage = 10; + + function setUp() public { + // Deploy the main contract and get input/output contracts + deployer = new DeployAltDA(); + (dai, dao) = _setupIOContracts(); + + // Setup proxyAdmin + proxyAdmin = IProxyAdmin( + DeployUtils.create1({ + _name: "ProxyAdmin", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxyAdmin.__constructor__, (msg.sender))) + }) + ); + + // Set the default values + dai.set(dai.salt.selector, salt); + dai.set(dai.proxyAdmin.selector, address(proxyAdmin)); + dai.set(dai.challengeContractOwner.selector, challengeContractOwner); + dai.set(dai.challengeWindow.selector, challengeWindow); + dai.set(dai.resolveWindow.selector, resolveWindow); + dai.set(dai.bondSize.selector, bondSize); + dai.set(dai.resolverRefundPercentage.selector, resolverRefundPercentage); + } + + function _setupIOContracts() internal returns (DeployAltDAInput, DeployAltDAOutput) { + DeployAltDAInput _dai = new DeployAltDAInput(); + DeployAltDAOutput _dao = new DeployAltDAOutput(); + return (_dai, _dao); + } + + function test_run_succeeds() public { + deployer.run(dai, dao); + + // Verify everything is set up correctly + IDataAvailabilityChallenge dac = dao.dataAvailabilityChallengeProxy(); + assertTrue(address(dac).code.length > 0, "100"); + assertTrue(address(dao.dataAvailabilityChallengeImpl()).code.length > 0, "200"); + + // Check all initialization parameters + assertEq(dac.owner(), challengeContractOwner, "300"); + assertEq(dac.challengeWindow(), challengeWindow, "400"); + assertEq(dac.resolveWindow(), resolveWindow, "500"); + assertEq(dac.bondSize(), bondSize, "600"); + assertEq(dac.resolverRefundPercentage(), resolverRefundPercentage, "700"); + // Make sure the proxy admin is set correctly. + vm.prank(address(0)); + assertEq(IProxy(payable(address(dac))).admin(), address(proxyAdmin), "800"); + } + + function test_checkOutput_whenNotInitialized_reverts() public { + vm.expectRevert("DeployUtils: zero address"); + deployer.checkOutput(dai, dao); + } + + function test_checkOutput_whenProxyNotInitialized_reverts() public { + // Deploy but don't initialize + deployer.deployDataAvailabilityChallengeProxy(dai, dao); + deployer.deployDataAvailabilityChallengeImpl(dai, dao); + + vm.expectRevert("DeployUtils: zero address"); + deployer.checkOutput(dai, dao); + } + + function testFuzz_run_withDifferentParameters_works( + uint256 _challengeWindow, + uint256 _resolveWindow, + uint256 _bondSize, + uint256 _resolverRefundPercentage + ) + public + { + // Bound the values to reasonable ranges + _challengeWindow = bound(_challengeWindow, 1, 365 days); + _resolveWindow = bound(_resolveWindow, 1, 365 days); + _bondSize = bound(_bondSize, 0.1 ether, 100 ether); + _resolverRefundPercentage = bound(_resolverRefundPercentage, 1, 100); + + // Set the new values + dai.set(dai.salt.selector, salt); + dai.set(dai.proxyAdmin.selector, address(proxyAdmin)); + dai.set(dai.challengeWindow.selector, _challengeWindow); + dai.set(dai.resolveWindow.selector, _resolveWindow); + dai.set(dai.bondSize.selector, _bondSize); + dai.set(dai.resolverRefundPercentage.selector, _resolverRefundPercentage); + + // Run deployment + deployer.run(dai, dao); + + // Verify values + IDataAvailabilityChallenge dac = dao.dataAvailabilityChallengeProxy(); + assertEq(dac.challengeWindow(), _challengeWindow, "100"); + assertEq(dac.resolveWindow(), _resolveWindow, "200"); + assertEq(dac.bondSize(), _bondSize, "300"); + assertEq(dac.resolverRefundPercentage(), _resolverRefundPercentage, "400"); + } +} diff --git a/packages/contracts-bedrock/test/opcm/DeployAuthSystem.t.sol b/packages/contracts-bedrock/test/opcm/DeployAuthSystem.t.sol index 19985ef490b9d..7126ce25efaff 100644 --- a/packages/contracts-bedrock/test/opcm/DeployAuthSystem.t.sol +++ b/packages/contracts-bedrock/test/opcm/DeployAuthSystem.t.sol @@ -5,7 +5,7 @@ import { Test, stdStorage, StdStorage } from "forge-std/Test.sol"; import { stdToml } from "forge-std/StdToml.sol"; import { Solarray } from "scripts/libraries/Solarray.sol"; -import { DeployAuthSystemInput, DeployAuthSystem, DeployAuthSystemOutput } from "scripts/DeployAuthSystem.s.sol"; +import { DeployAuthSystemInput, DeployAuthSystem, DeployAuthSystemOutput } from "scripts/deploy/DeployAuthSystem.s.sol"; contract DeployAuthSystemInput_Test is Test { DeployAuthSystemInput dasi; @@ -30,7 +30,7 @@ contract DeployAuthSystemInput_Test is Test { } } - function test_getters_whenNotSet_revert() public { + function test_getters_whenNotSet_reverts() public { vm.expectRevert("DeployAuthSystemInput: threshold not set"); dasi.threshold(); @@ -38,7 +38,7 @@ contract DeployAuthSystemInput_Test is Test { dasi.owners(); } - function test_setters_ownerAlreadySet_revert() public { + function test_setters_ownerAlreadySet_reverts() public { dasi.set(dasi.owners.selector, owners); vm.expectRevert("DeployAuthSystemInput: owners already set"); @@ -135,7 +135,7 @@ contract DeployAuthSystem_Test is Test { daso.checkOutput(); } - function test_run_NullInput_reverts() public { + function test_run_nullInput_reverts() public { dasi.set(dasi.owners.selector, defaultOwners); dasi.set(dasi.threshold.selector, defaultThreshold); diff --git a/packages/contracts-bedrock/test/opcm/DeployImplementations.t.sol b/packages/contracts-bedrock/test/opcm/DeployImplementations.t.sol index 490d764698cac..8d3feac2de0d0 100644 --- a/packages/contracts-bedrock/test/opcm/DeployImplementations.t.sol +++ b/packages/contracts-bedrock/test/opcm/DeployImplementations.t.sol @@ -26,7 +26,7 @@ import { DeployImplementations, DeployImplementationsInterop, DeployImplementationsOutput -} from "scripts/DeployImplementations.s.sol"; +} from "scripts/deploy/DeployImplementations.s.sol"; contract DeployImplementationsInput_Test is Test { DeployImplementationsInput dii; @@ -44,7 +44,7 @@ contract DeployImplementationsInput_Test is Test { dii = new DeployImplementationsInput(); } - function test_getters_whenNotSet_revert() public { + function test_getters_whenNotSet_reverts() public { vm.expectRevert("DeployImplementationsInput: not set"); dii.withdrawalDelaySeconds(); @@ -61,7 +61,7 @@ contract DeployImplementationsInput_Test is Test { dii.disputeGameFinalityDelaySeconds(); vm.expectRevert("DeployImplementationsInput: not set"); - dii.release(); + dii.l1ContractsRelease(); vm.expectRevert("DeployImplementationsInput: not set"); dii.superchainConfigProxy(); @@ -69,23 +69,9 @@ contract DeployImplementationsInput_Test is Test { vm.expectRevert("DeployImplementationsInput: not set"); dii.protocolVersionsProxy(); - vm.expectRevert("DeployImplementationsInput: not set"); - dii.opcmProxyOwner(); - vm.expectRevert("DeployImplementationsInput: not set"); dii.standardVersionsToml(); } - - function test_opcmProxyOwner_whenNotSet_reverts() public { - vm.expectRevert("DeployImplementationsInput: not set"); - dii.opcmProxyOwner(); - } - - function test_opcmProxyOwner_succeeds() public { - dii.set(dii.opcmProxyOwner.selector, address(msg.sender)); - address opcmProxyOwner = dii.opcmProxyOwner(); - assertEq(address(msg.sender), address(opcmProxyOwner), "100"); - } } contract DeployImplementationsOutput_Test is Test { @@ -96,17 +82,7 @@ contract DeployImplementationsOutput_Test is Test { } function test_set_succeeds() public { - IProxy proxy = IProxy( - DeployUtils.create1({ - _name: "Proxy", - _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (address(0)))) - }) - ); - address opcmImpl = address(makeAddr("opcmImpl")); - vm.prank(address(0)); - proxy.upgradeTo(opcmImpl); - - OPContractsManager opcmProxy = OPContractsManager(address(proxy)); + OPContractsManager opcm = OPContractsManager(address(makeAddr("opcm"))); IOptimismPortal2 optimismPortalImpl = IOptimismPortal2(payable(makeAddr("optimismPortalImpl"))); IDelayedWETH delayedWETHImpl = IDelayedWETH(payable(makeAddr("delayedWETHImpl"))); IPreimageOracle preimageOracleSingleton = IPreimageOracle(makeAddr("preimageOracleSingleton")); @@ -120,8 +96,7 @@ contract DeployImplementationsOutput_Test is Test { IOptimismMintableERC20Factory(makeAddr("optimismMintableERC20FactoryImpl")); IDisputeGameFactory disputeGameFactoryImpl = IDisputeGameFactory(makeAddr("disputeGameFactoryImpl")); - vm.etch(address(opcmProxy), address(opcmProxy).code); - vm.etch(address(opcmImpl), hex"01"); + vm.etch(address(opcm), hex"01"); vm.etch(address(optimismPortalImpl), hex"01"); vm.etch(address(delayedWETHImpl), hex"01"); vm.etch(address(preimageOracleSingleton), hex"01"); @@ -132,7 +107,7 @@ contract DeployImplementationsOutput_Test is Test { vm.etch(address(l1StandardBridgeImpl), hex"01"); vm.etch(address(optimismMintableERC20FactoryImpl), hex"01"); vm.etch(address(disputeGameFactoryImpl), hex"01"); - dio.set(dio.opcmProxy.selector, address(opcmProxy)); + dio.set(dio.opcm.selector, address(opcm)); dio.set(dio.optimismPortalImpl.selector, address(optimismPortalImpl)); dio.set(dio.delayedWETHImpl.selector, address(delayedWETHImpl)); dio.set(dio.preimageOracleSingleton.selector, address(preimageOracleSingleton)); @@ -144,7 +119,7 @@ contract DeployImplementationsOutput_Test is Test { dio.set(dio.optimismMintableERC20FactoryImpl.selector, address(optimismMintableERC20FactoryImpl)); dio.set(dio.disputeGameFactoryImpl.selector, address(disputeGameFactoryImpl)); - assertEq(address(opcmProxy), address(dio.opcmProxy()), "50"); + assertEq(address(opcm), address(dio.opcm()), "50"); assertEq(address(optimismPortalImpl), address(dio.optimismPortalImpl()), "100"); assertEq(address(delayedWETHImpl), address(dio.delayedWETHImpl()), "200"); assertEq(address(preimageOracleSingleton), address(dio.preimageOracleSingleton()), "300"); @@ -157,7 +132,7 @@ contract DeployImplementationsOutput_Test is Test { assertEq(address(disputeGameFactoryImpl), address(dio.disputeGameFactoryImpl()), "950"); } - function test_getters_whenNotSet_revert() public { + function test_getters_whenNotSet_reverts() public { bytes memory expectedErr = "DeployUtils: zero address"; vm.expectRevert(expectedErr); @@ -273,7 +248,7 @@ contract DeployImplementations_Test is Test { function test_deployImplementation_succeeds() public { string memory deployContractsRelease = "dev-release"; - dii.set(dii.release.selector, deployContractsRelease); + dii.set(dii.l1ContractsRelease.selector, deployContractsRelease); deployImplementations.deploySystemConfigImpl(dii, dio); assertTrue(address(0) != address(dio.systemConfigImpl())); } @@ -282,7 +257,7 @@ contract DeployImplementations_Test is Test { // All hardcoded addresses below are taken from the superchain-registry config: // https://github.com/ethereum-optimism/superchain-registry/blob/be65d22f8128cf0c4e5b4e1f677daf86843426bf/validation/standard/standard-versions.toml#L11 string memory testRelease = "op-contracts/v1.6.0"; - dii.set(dii.release.selector, testRelease); + dii.set(dii.l1ContractsRelease.selector, testRelease); deployImplementations.deploySystemConfigImpl(dii, dio); address srSystemConfigImpl = address(0xF56D96B2535B932656d3c04Ebf51baBff241D886); @@ -335,71 +310,6 @@ contract DeployImplementations_Test is Test { assertEq(srDisputeGameFactoryImpl, address(dio.disputeGameFactoryImpl())); } - function test_deployAtNonExistentRelease_reverts() public { - string memory unknownRelease = "op-contracts/v0.0.0"; - dii.set(dii.release.selector, unknownRelease); - - bytes memory expectedErr = - bytes(string.concat("DeployImplementations: failed to deploy release ", unknownRelease)); - - vm.expectRevert(expectedErr); - deployImplementations.deploySystemConfigImpl(dii, dio); - - vm.expectRevert(expectedErr); - deployImplementations.deployL1CrossDomainMessengerImpl(dii, dio); - - vm.expectRevert(expectedErr); - deployImplementations.deployL1ERC721BridgeImpl(dii, dio); - - vm.expectRevert(expectedErr); - deployImplementations.deployL1StandardBridgeImpl(dii, dio); - - vm.expectRevert(expectedErr); - deployImplementations.deployOptimismMintableERC20FactoryImpl(dii, dio); - - // TODO: Uncomment the code below when OPContractsManager is deployed based on release. Superchain-registry - // doesn't contain OPContractsManager yet. - // dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy)); - // dii.set(dii.protocolVersionsProxy.selector, address(protocolVersionsProxy)); - // vm.etch(address(superchainConfigProxy), hex"01"); - // vm.etch(address(protocolVersionsProxy), hex"01"); - // vm.expectRevert(expectedErr); - // deployImplementations.deployOPContractsManagerImpl(dii, dio); - - dii.set(dii.proofMaturityDelaySeconds.selector, 1); - dii.set(dii.disputeGameFinalityDelaySeconds.selector, 2); - vm.expectRevert(expectedErr); - deployImplementations.deployOptimismPortalImpl(dii, dio); - - dii.set(dii.withdrawalDelaySeconds.selector, 1); - vm.expectRevert(expectedErr); - deployImplementations.deployDelayedWETHImpl(dii, dio); - - dii.set(dii.minProposalSizeBytes.selector, 1); - dii.set(dii.challengePeriodSeconds.selector, 2); - vm.expectRevert(expectedErr); - deployImplementations.deployPreimageOracleSingleton(dii, dio); - - address preImageOracleSingleton = makeAddr("preImageOracleSingleton"); - vm.etch(address(preImageOracleSingleton), hex"01"); - dio.set(dio.preimageOracleSingleton.selector, preImageOracleSingleton); - vm.expectRevert(expectedErr); - deployImplementations.deployMipsSingleton(dii, dio); - - vm.expectRevert(expectedErr); // fault proof contracts don't exist at this release - deployImplementations.deployDisputeGameFactoryImpl(dii, dio); - } - - function test_noContractExistsAtRelease_reverts() public { - string memory unknownRelease = "op-contracts/v1.3.0"; - dii.set(dii.release.selector, unknownRelease); - bytes memory expectedErr = - bytes(string.concat("DeployImplementations: failed to deploy release ", unknownRelease)); - - vm.expectRevert(expectedErr); // fault proof contracts don't exist at this release - deployImplementations.deployDisputeGameFactoryImpl(dii, dio); - } - function testFuzz_run_memory_succeeds(bytes32 _seed) public { withdrawalDelaySeconds = uint256(hash(_seed, 0)); minProposalSizeBytes = uint256(hash(_seed, 1)); @@ -409,7 +319,7 @@ contract DeployImplementations_Test is Test { string memory release = string(bytes.concat(hash(_seed, 5))); protocolVersionsProxy = IProtocolVersions(address(uint160(uint256(hash(_seed, 7))))); - // Must configure the ProxyAdmin contract which is used to upgrade the OPCM's proxy contract. + // Must configure the ProxyAdmin contract. IProxyAdmin superchainProxyAdmin = IProxyAdmin( DeployUtils.create1({ _name: "ProxyAdmin", @@ -439,10 +349,9 @@ contract DeployImplementations_Test is Test { dii.set(dii.proofMaturityDelaySeconds.selector, proofMaturityDelaySeconds); dii.set(dii.disputeGameFinalityDelaySeconds.selector, disputeGameFinalityDelaySeconds); dii.set(dii.mipsVersion.selector, 1); - dii.set(dii.release.selector, release); + dii.set(dii.l1ContractsRelease.selector, release); dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy)); dii.set(dii.protocolVersionsProxy.selector, address(protocolVersionsProxy)); - dii.set(dii.opcmProxyOwner.selector, msg.sender); deployImplementations.run(dii, dio); @@ -453,10 +362,9 @@ contract DeployImplementations_Test is Test { assertEq(proofMaturityDelaySeconds, dii.proofMaturityDelaySeconds(), "400"); assertEq(disputeGameFinalityDelaySeconds, dii.disputeGameFinalityDelaySeconds(), "500"); assertEq(1, dii.mipsVersion(), "512"); - assertEq(release, dii.release(), "525"); + assertEq(release, dii.l1ContractsRelease(), "525"); assertEq(address(superchainConfigProxy), address(dii.superchainConfigProxy()), "550"); assertEq(address(protocolVersionsProxy), address(dii.protocolVersionsProxy()), "575"); - assertEq(msg.sender, dii.opcmProxyOwner(), "580"); // Architecture assertions. assertEq(address(dio.mipsSingleton().oracle()), address(dio.preimageOracleSingleton()), "600"); @@ -475,7 +383,7 @@ contract DeployImplementations_Test is Test { dii.set(dii.disputeGameFinalityDelaySeconds.selector, disputeGameFinalityDelaySeconds); dii.set(dii.mipsVersion.selector, 1); string memory release = "dev-release"; - dii.set(dii.release.selector, release); + dii.set(dii.l1ContractsRelease.selector, release); dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy)); dii.set(dii.protocolVersionsProxy.selector, address(protocolVersionsProxy)); diff --git a/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol b/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol index b218010fa37e4..5280328168b97 100644 --- a/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol +++ b/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol @@ -3,14 +3,14 @@ pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; -import { DeploySuperchainInput, DeploySuperchain, DeploySuperchainOutput } from "scripts/DeploySuperchain.s.sol"; +import { DeploySuperchainInput, DeploySuperchain, DeploySuperchainOutput } from "scripts/deploy/DeploySuperchain.s.sol"; import { DeployImplementationsInput, DeployImplementations, DeployImplementationsInterop, DeployImplementationsOutput -} from "scripts/DeployImplementations.s.sol"; -import { DeployOPChainInput, DeployOPChain, DeployOPChainOutput } from "scripts/DeployOPChain.s.sol"; +} from "scripts/deploy/DeployImplementations.s.sol"; +import { DeployOPChainInput, DeployOPChain, DeployOPChainOutput } from "scripts/deploy/DeployOPChain.s.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { IProxyAdmin } from "src/universal/interfaces/IProxyAdmin.sol"; @@ -39,10 +39,10 @@ contract DeployOPChainInput_Test is Test { address unsafeBlockSigner = makeAddr("unsafeBlockSigner"); address proposer = makeAddr("proposer"); address challenger = makeAddr("challenger"); + address opcm = makeAddr("opcm"); uint32 basefeeScalar = 100; uint32 blobBaseFeeScalar = 200; uint256 l2ChainId = 300; - OPContractsManager opcm = OPContractsManager(makeAddr("opcm")); string saltMixer = "saltMixer"; function setUp() public { @@ -59,9 +59,9 @@ contract DeployOPChainInput_Test is Test { doi.set(doi.basefeeScalar.selector, basefeeScalar); doi.set(doi.blobBaseFeeScalar.selector, blobBaseFeeScalar); doi.set(doi.l2ChainId.selector, l2ChainId); - - (IProxy opcmProxy) = DeployUtils.buildERC1967ProxyWithImpl("opcmProxy"); - doi.set(doi.opcmProxy.selector, address(opcmProxy)); + doi.set(doi.allowCustomDisputeParameters.selector, true); + doi.set(doi.opcm.selector, opcm); + vm.etch(opcm, hex"01"); // Compare the default inputs to the getter methods. assertEq(opChainProxyAdminOwner, doi.opChainProxyAdminOwner(), "200"); @@ -73,10 +73,11 @@ contract DeployOPChainInput_Test is Test { assertEq(basefeeScalar, doi.basefeeScalar(), "800"); assertEq(blobBaseFeeScalar, doi.blobBaseFeeScalar(), "900"); assertEq(l2ChainId, doi.l2ChainId(), "1000"); - assertEq(address(opcmProxy), address(doi.opcmProxy()), "1100"); + assertEq(opcm, address(doi.opcm()), "1100"); + assertEq(true, doi.allowCustomDisputeParameters(), "1200"); } - function test_getters_whenNotSet_revert() public { + function test_getters_whenNotSet_reverts() public { bytes memory expectedErr = "DeployOPChainInput: not set"; vm.expectRevert(expectedErr); @@ -180,7 +181,7 @@ contract DeployOPChainOutput_Test is Test { // "1600"); } - function test_getters_whenNotSet_revert() public { + function test_getters_whenNotSet_reverts() public { bytes memory expectedErr = "DeployUtils: zero address"; vm.expectRevert(expectedErr); @@ -394,7 +395,7 @@ contract DeployOPChain_TestBase is Test { dii.set(dii.proofMaturityDelaySeconds.selector, proofMaturityDelaySeconds); dii.set(dii.disputeGameFinalityDelaySeconds.selector, disputeGameFinalityDelaySeconds); dii.set(dii.mipsVersion.selector, 1); - dii.set(dii.release.selector, release); + dii.set(dii.l1ContractsRelease.selector, release); dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy)); dii.set(dii.protocolVersionsProxy.selector, address(protocolVersionsProxy)); // End users of the DeployImplementations contract will need to set the `standardVersionsToml`. @@ -402,7 +403,7 @@ contract DeployOPChain_TestBase is Test { string.concat(vm.projectRoot(), "/test/fixtures/standard-versions.toml"); string memory standardVersionsToml = vm.readFile(standardVersionsTomlPath); dii.set(dii.standardVersionsToml.selector, standardVersionsToml); - dii.set(dii.opcmProxyOwner.selector, address(1)); + deployImplementations.run(dii, dio); // Deploy DeployOpChain, but defer populating the input values to the test suites inheriting this contract. @@ -410,7 +411,7 @@ contract DeployOPChain_TestBase is Test { (doi, doo) = deployOPChain.etchIOContracts(); // Set the OPContractsManager input for DeployOPChain. - opcm = dio.opcmProxy(); + opcm = dio.opcm(); } // See the function of the same name in the `DeployImplementations_Test` contract of @@ -425,7 +426,7 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { return keccak256(abi.encode(_seed, _i)); } - function testFuzz_run_memory_succeed(bytes32 _seed) public { + function testFuzz_run_memory_succeeds(bytes32 _seed) public { opChainProxyAdminOwner = address(uint160(uint256(hash(_seed, 0)))); systemConfigOwner = address(uint160(uint256(hash(_seed, 1)))); batcher = address(uint160(uint256(hash(_seed, 2)))); @@ -464,7 +465,7 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { doi.set(doi.basefeeScalar.selector, basefeeScalar); doi.set(doi.blobBaseFeeScalar.selector, blobBaseFeeScalar); doi.set(doi.l2ChainId.selector, l2ChainId); - doi.set(doi.opcmProxy.selector, address(opcm)); // Not fuzzed since it must be an actual instance. + doi.set(doi.opcm.selector, address(opcm)); doi.set(doi.saltMixer.selector, saltMixer); doi.set(doi.gasLimit.selector, gasLimit); doi.set(doi.disputeGameType.selector, disputeGameType); @@ -531,6 +532,42 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { assertEq(address(doo.opChainProxyAdmin().addressManager()), address(doo.addressManager()), "3700"); assertEq(address(doo.opChainProxyAdmin().owner()), opChainProxyAdminOwner, "3800"); } + + function test_customDisputeGame_customDisabled_reverts() public { + setDOI(); + doi.set(doi.disputeSplitDepth.selector, disputeSplitDepth + 1); + vm.expectRevert("DPG-90"); + deployOPChain.run(doi, doo); + } + + function test_customDisputeGame_customEnabled_succeeds() public { + setDOI(); + doi.set(doi.allowCustomDisputeParameters.selector, true); + doi.set(doi.disputeSplitDepth.selector, disputeSplitDepth + 1); + deployOPChain.run(doi, doo); + assertEq(doo.permissionedDisputeGame().splitDepth(), disputeSplitDepth + 1); + } + + function setDOI() internal { + doi.set(doi.opChainProxyAdminOwner.selector, opChainProxyAdminOwner); + doi.set(doi.systemConfigOwner.selector, systemConfigOwner); + doi.set(doi.batcher.selector, batcher); + doi.set(doi.unsafeBlockSigner.selector, unsafeBlockSigner); + doi.set(doi.proposer.selector, proposer); + doi.set(doi.challenger.selector, challenger); + doi.set(doi.basefeeScalar.selector, basefeeScalar); + doi.set(doi.blobBaseFeeScalar.selector, blobBaseFeeScalar); + doi.set(doi.l2ChainId.selector, l2ChainId); + doi.set(doi.opcm.selector, address(opcm)); + doi.set(doi.saltMixer.selector, saltMixer); + doi.set(doi.gasLimit.selector, gasLimit); + doi.set(doi.disputeGameType.selector, disputeGameType); + doi.set(doi.disputeAbsolutePrestate.selector, disputeAbsolutePrestate); + doi.set(doi.disputeMaxGameDepth.selector, disputeMaxGameDepth); + doi.set(doi.disputeSplitDepth.selector, disputeSplitDepth); + doi.set(doi.disputeClockExtension.selector, disputeClockExtension); + doi.set(doi.disputeMaxClockDuration.selector, disputeMaxClockDuration); + } } contract DeployOPChain_Test_Interop is DeployOPChain_Test { diff --git a/packages/contracts-bedrock/test/opcm/DeploySuperchain.t.sol b/packages/contracts-bedrock/test/opcm/DeploySuperchain.t.sol index 8641772a74d90..924957cc18000 100644 --- a/packages/contracts-bedrock/test/opcm/DeploySuperchain.t.sol +++ b/packages/contracts-bedrock/test/opcm/DeploySuperchain.t.sol @@ -8,7 +8,7 @@ import { ProxyAdmin } from "src/universal/ProxyAdmin.sol"; import { Proxy } from "src/universal/Proxy.sol"; import { SuperchainConfig } from "src/L1/SuperchainConfig.sol"; import { IProtocolVersions, ProtocolVersion } from "src/L1/interfaces/IProtocolVersions.sol"; -import { DeploySuperchainInput, DeploySuperchain, DeploySuperchainOutput } from "scripts/DeploySuperchain.s.sol"; +import { DeploySuperchainInput, DeploySuperchain, DeploySuperchainOutput } from "scripts/deploy/DeploySuperchain.s.sol"; contract DeploySuperchainInput_Test is Test { DeploySuperchainInput dsi; @@ -24,7 +24,7 @@ contract DeploySuperchainInput_Test is Test { dsi = new DeploySuperchainInput(); } - function test_getters_whenNotSet_revert() public { + function test_getters_whenNotSet_reverts() public { vm.expectRevert("DeploySuperchainInput: superchainProxyAdminOwner not set"); dsi.superchainProxyAdminOwner(); @@ -83,7 +83,7 @@ contract DeploySuperchainOutput_Test is Test { assertEq(address(protocolVersionsProxy), address(dso.protocolVersionsProxy()), "500"); } - function test_getters_whenNotSet_revert() public { + function test_getters_whenNotSet_reverts() public { vm.expectRevert("DeployUtils: zero address"); dso.superchainConfigImpl(); @@ -194,7 +194,7 @@ contract DeploySuperchain_Test is Test { dso.checkOutput(dsi); } - function test_run_NullInput_reverts() public { + function test_run_nullInput_reverts() public { // Set default values for all inputs. dsi.set(dsi.superchainProxyAdminOwner.selector, defaultProxyAdminOwner); dsi.set(dsi.protocolVersionsOwner.selector, defaultProtocolVersionsOwner); diff --git a/packages/contracts-bedrock/test/periphery/Transactor.t.sol b/packages/contracts-bedrock/test/periphery/Transactor.t.sol index bfee0ddc3adf2..8d183c8d20b73 100644 --- a/packages/contracts-bedrock/test/periphery/Transactor.t.sol +++ b/packages/contracts-bedrock/test/periphery/Transactor.t.sol @@ -41,7 +41,7 @@ contract TransactorTest is Transactor_Initializer { /// @notice Tests CALL, should do a call to target function test_call_succeeds() external { // Initialize call data - bytes memory data = abi.encodeWithSelector(callRecorded.record.selector); + bytes memory data = abi.encodeCall(CallRecorder.record, ()); // Run CALL vm.prank(alice); vm.expectCall(address(callRecorded), 200_000 wei, data); @@ -51,7 +51,7 @@ contract TransactorTest is Transactor_Initializer { /// @notice It should revert if called by non-owner function test_call_unauthorized_reverts() external { // Initialize call data - bytes memory data = abi.encodeWithSelector(callRecorded.record.selector); + bytes memory data = abi.encodeCall(CallRecorder.record, ()); // Run CALL vm.prank(bob); vm.expectRevert("UNAUTHORIZED"); @@ -61,7 +61,7 @@ contract TransactorTest is Transactor_Initializer { /// @notice Deletate call succeeds. function test_delegateCall_succeeds() external { // Initialize call data - bytes memory data = abi.encodeWithSelector(reverter.doRevert.selector); + bytes memory data = abi.encodeCall(Reverter.doRevert, ()); // Run CALL vm.prank(alice); vm.expectCall(address(reverter), data); @@ -71,7 +71,7 @@ contract TransactorTest is Transactor_Initializer { /// @notice It should revert if called by non-owner function test_delegateCall_unauthorized_reverts() external { // Initialize call data - bytes memory data = abi.encodeWithSelector(reverter.doRevert.selector); + bytes memory data = abi.encodeCall(Reverter.doRevert, ()); // Run CALL vm.prank(bob); vm.expectRevert("UNAUTHORIZED"); diff --git a/packages/contracts-bedrock/test/periphery/drippie/Drippie.t.sol b/packages/contracts-bedrock/test/periphery/drippie/Drippie.t.sol index 66c2a8d69b192..0e6755b0e63c8 100644 --- a/packages/contracts-bedrock/test/periphery/drippie/Drippie.t.sol +++ b/packages/contracts-bedrock/test/periphery/drippie/Drippie.t.sol @@ -353,7 +353,7 @@ contract Drippie_Test is Test { // Add in an action cfg.actions[0] = Drippie.DripAction({ target: payable(address(simpleStorage)), - data: abi.encodeWithSelector(SimpleStorage.set.selector, key, value), + data: abi.encodeCall(SimpleStorage.set, (key, value)), value: 0 }); @@ -365,7 +365,7 @@ contract Drippie_Test is Test { vm.prank(drippie.owner()); drippie.status(dripName, Drippie.DripStatus.ACTIVE); - vm.expectCall(address(simpleStorage), 0, abi.encodeWithSelector(SimpleStorage.set.selector, key, value)); + vm.expectCall(address(simpleStorage), 0, abi.encodeCall(SimpleStorage.set, (key, value))); vm.expectEmit(address(drippie)); emit DripExecuted(dripName, dripName, address(this), block.timestamp); @@ -383,7 +383,7 @@ contract Drippie_Test is Test { bytes32 valueOne = bytes32(uint256(3)); actions[0] = Drippie.DripAction({ target: payable(address(simpleStorage)), - data: abi.encodeWithSelector(simpleStorage.set.selector, keyOne, valueOne), + data: abi.encodeCall(SimpleStorage.set, (keyOne, valueOne)), value: 0 }); @@ -391,7 +391,7 @@ contract Drippie_Test is Test { bytes32 valueTwo = bytes32(uint256(5)); actions[1] = Drippie.DripAction({ target: payable(address(simpleStorage)), - data: abi.encodeWithSelector(simpleStorage.set.selector, keyTwo, valueTwo), + data: abi.encodeCall(SimpleStorage.set, (keyTwo, valueTwo)), value: 0 }); @@ -407,9 +407,9 @@ contract Drippie_Test is Test { vm.expectCall(drippie.dripConfigCheckAddress(dripName), drippie.dripConfigCheckParams(dripName)); - vm.expectCall(address(simpleStorage), 0, abi.encodeWithSelector(SimpleStorage.set.selector, keyOne, valueOne)); + vm.expectCall(address(simpleStorage), 0, abi.encodeCall(SimpleStorage.set, (keyOne, valueOne))); - vm.expectCall(address(simpleStorage), 0, abi.encodeWithSelector(SimpleStorage.set.selector, keyTwo, valueTwo)); + vm.expectCall(address(simpleStorage), 0, abi.encodeCall(SimpleStorage.set, (keyTwo, valueTwo))); vm.expectEmit(address(drippie)); emit DripExecuted(dripName, dripName, address(this), block.timestamp); diff --git a/packages/contracts-bedrock/test/periphery/op-nft/Optimist.t.sol b/packages/contracts-bedrock/test/periphery/op-nft/Optimist.t.sol index 912b04ab33f6d..2eb2f07e860f2 100644 --- a/packages/contracts-bedrock/test/periphery/op-nft/Optimist.t.sol +++ b/packages/contracts-bedrock/test/periphery/op-nft/Optimist.t.sol @@ -130,9 +130,7 @@ contract Optimist_Initializer is Test { /// @notice Mocks the allowlistAttestor to always return true for a given address. function _mockAllowlistTrueFor(address _claimer) internal { vm.mockCall( - address(optimistAllowlist), - abi.encodeWithSelector(OptimistAllowlist.isAllowedToMint.selector, _claimer), - abi.encode(true) + address(optimistAllowlist), abi.encodeCall(OptimistAllowlist.isAllowedToMint, (_claimer)), abi.encode(true) ); assertTrue(optimist.isOnAllowList(_claimer)); @@ -210,7 +208,7 @@ contract OptimistTest is Optimist_Initializer { assertTrue(optimistAllowlist.isAllowedToMint(bob)); // Check that the OptimistAllowlist is checked - bytes memory data = abi.encodeWithSelector(optimistAllowlist.isAllowedToMint.selector, bob); + bytes memory data = abi.encodeCall(OptimistAllowlist.isAllowedToMint, (bob)); vm.expectCall(address(optimistAllowlist), data); // mint an NFT and expect mint transfer event to be emitted @@ -236,7 +234,7 @@ contract OptimistTest is Optimist_Initializer { assertTrue(optimistAllowlist.isAllowedToMint(bob)); // Check that the OptimistAllowlist is checked - bytes memory data = abi.encodeWithSelector(optimistAllowlist.isAllowedToMint.selector, bob); + bytes memory data = abi.encodeCall(OptimistAllowlist.isAllowedToMint, (bob)); vm.expectCall(address(optimistAllowlist), data); // mint an NFT and expect mint transfer event to be emitted @@ -262,7 +260,7 @@ contract OptimistTest is Optimist_Initializer { assertTrue(optimistAllowlist.isAllowedToMint(bob)); // Check that the OptimistAllowlist is checked - bytes memory data = abi.encodeWithSelector(optimistAllowlist.isAllowedToMint.selector, bob); + bytes memory data = abi.encodeCall(OptimistAllowlist.isAllowedToMint, (bob)); vm.expectCall(address(optimistAllowlist), data); // mint an NFT and expect mint transfer event to be emitted @@ -293,7 +291,7 @@ contract OptimistTest is Optimist_Initializer { assertTrue(optimistAllowlist.isAllowedToMint(bob)); // Check that the OptimistAllowlist is checked - bytes memory data = abi.encodeWithSelector(optimistAllowlist.isAllowedToMint.selector, bob); + bytes memory data = abi.encodeCall(OptimistAllowlist.isAllowedToMint, (bob)); vm.expectCall(address(optimistAllowlist), data); // mint an NFT and expect mint transfer event to be emitted @@ -350,11 +348,9 @@ contract OptimistTest is Optimist_Initializer { function test_baseURI_returnsCorrectBaseURI_succeeds() external { _attestBaseURI(base_uri); - bytes memory data = abi.encodeWithSelector( - attestationStation.attestations.selector, - carol_baseURIAttestor, - address(optimist), - optimist.BASE_URI_ATTESTATION_KEY() + bytes memory data = abi.encodeCall( + attestationStation.attestations, + (carol_baseURIAttestor, address(optimist), optimist.BASE_URI_ATTESTATION_KEY()) ); vm.expectCall(address(attestationStation), data); vm.prank(carol_baseURIAttestor); @@ -527,14 +523,14 @@ contract OptimistTest is Optimist_Initializer { // First call is to claim the invite, receiving the attestation calls[0] = IMulticall3.Call3({ target: address(optimistInviter), - callData: abi.encodeWithSelector(optimistInviter.claimInvite.selector, bob, claimableInvite, signature), + callData: abi.encodeCall(OptimistInviter.claimInvite, (bob, claimableInvite, signature)), allowFailure: false }); // Second call is to mint the Optimist NFT calls[1] = IMulticall3.Call3({ target: address(optimist), - callData: abi.encodeWithSelector(optimist.mint.selector, bob), + callData: abi.encodeCall(Optimist.mint, (bob)), allowFailure: false }); diff --git a/packages/contracts-bedrock/test/safe-tools/CompatibilityFallbackHandler_1_3_0.sol b/packages/contracts-bedrock/test/safe-tools/CompatibilityFallbackHandler_1_3_0.sol index ac0c264d30382..89536e2e4493d 100644 --- a/packages/contracts-bedrock/test/safe-tools/CompatibilityFallbackHandler_1_3_0.sol +++ b/packages/contracts-bedrock/test/safe-tools/CompatibilityFallbackHandler_1_3_0.sol @@ -93,7 +93,7 @@ contract CompatibilityFallbackHandler is DefaultCallbackHandler, ISignatureValid GnosisSafe safe = GnosisSafe(payable(msg.sender)); bytes32 messageHash = getMessageHashForSafe(safe, _data); if (_signature.length == 0) { - require(safe.signedMessages(messageHash) != 0, "Hash not approved"); + require(safe.signedMessages(messageHash) != 0, "CompatibilityFallbackHandler: Hash not approved"); } else { safe.checkSignatures(messageHash, _data, _signature); } diff --git a/packages/contracts-bedrock/test/safe-tools/SafeTestTools.sol b/packages/contracts-bedrock/test/safe-tools/SafeTestTools.sol index 34386f5e39235..976cae5536914 100644 --- a/packages/contracts-bedrock/test/safe-tools/SafeTestTools.sol +++ b/packages/contracts-bedrock/test/safe-tools/SafeTestTools.sol @@ -260,7 +260,7 @@ library SafeTestLib { instance, address(instance.safe), 0, - abi.encodeWithSelector(ModuleManager.enableModule.selector, module), + abi.encodeCall(ModuleManager.enableModule, (module)), Enum.Operation.Call, 0, 0, @@ -289,7 +289,7 @@ library SafeTestLib { instance, address(instance.safe), 0, - abi.encodeWithSelector(ModuleManager.disableModule.selector, prevModule, module), + abi.encodeCall(ModuleManager.disableModule, (prevModule, module)), Enum.Operation.Call, 0, 0, @@ -308,7 +308,7 @@ library SafeTestLib { instance, address(instance.safe), 0, - abi.encodeWithSelector(GuardManager.setGuard.selector, guard), + abi.encodeCall(GuardManager.setGuard, (guard)), Enum.Operation.Call, 0, 0, @@ -326,7 +326,7 @@ library SafeTestLib { instance: instance, to: signMessageLib, value: 0, - data: abi.encodeWithSelector(SignMessageLib.signMessage.selector, data), + data: abi.encodeCall(SignMessageLib.signMessage, (data)), operation: Enum.Operation.DelegateCall, safeTxGas: 0, baseGas: 0, @@ -350,21 +350,13 @@ library SafeTestLib { /// @dev Adds a new owner to the safe function changeThreshold(SafeInstance memory instance, uint256 threshold) internal { - execTransaction( - instance, - address(instance.safe), - 0, - abi.encodeWithSelector(OwnerManager.changeThreshold.selector, threshold) - ); + execTransaction(instance, address(instance.safe), 0, abi.encodeCall(OwnerManager.changeThreshold, (threshold))); } /// @dev Adds a new owner to the safe function addOwnerWithThreshold(SafeInstance memory instance, address owner, uint256 threshold) internal { execTransaction( - instance, - address(instance.safe), - 0, - abi.encodeWithSelector(OwnerManager.addOwnerWithThreshold.selector, owner, threshold) + instance, address(instance.safe), 0, abi.encodeCall(OwnerManager.addOwnerWithThreshold, (owner, threshold)) ); } @@ -373,10 +365,7 @@ library SafeTestLib { function removeOwner(SafeInstance memory instance, address prevOwner, address owner, uint256 threshold) internal { prevOwner = prevOwner > address(0) ? prevOwner : SafeTestLib.getPrevOwner(instance, owner); execTransaction( - instance, - address(instance.safe), - 0, - abi.encodeWithSelector(OwnerManager.removeOwner.selector, prevOwner, owner, threshold) + instance, address(instance.safe), 0, abi.encodeCall(OwnerManager.removeOwner, (prevOwner, owner, threshold)) ); } @@ -385,10 +374,7 @@ library SafeTestLib { function swapOwner(SafeInstance memory instance, address prevOwner, address oldOwner, address newOwner) internal { prevOwner = prevOwner > address(0) ? prevOwner : SafeTestLib.getPrevOwner(instance, oldOwner); execTransaction( - instance, - address(instance.safe), - 0, - abi.encodeWithSelector(OwnerManager.swapOwner.selector, prevOwner, oldOwner, newOwner) + instance, address(instance.safe), 0, abi.encodeCall(OwnerManager.swapOwner, (prevOwner, oldOwner, newOwner)) ); } @@ -537,16 +523,18 @@ contract SafeTestTools { bytes memory initData = advancedParams.initData.length > 0 ? advancedParams.initData - : abi.encodeWithSelector( - GnosisSafe.setup.selector, - owners, - threshold, - advancedParams.setupModulesCall_to, - advancedParams.setupModulesCall_data, - advancedParams.includeFallbackHandler ? address(handler) : address(0), - advancedParams.refundToken, - advancedParams.refundAmount, - advancedParams.refundReceiver + : abi.encodeCall( + GnosisSafe.setup, + ( + owners, + threshold, + advancedParams.setupModulesCall_to, + advancedParams.setupModulesCall_data, + advancedParams.includeFallbackHandler ? address(handler) : address(0), + advancedParams.refundToken, + advancedParams.refundAmount, + advancedParams.refundReceiver + ) ); DeployedSafe safe0 = DeployedSafe( diff --git a/packages/contracts-bedrock/test/safe/DeployOwnership.t.sol b/packages/contracts-bedrock/test/safe/DeployOwnership.t.sol index 973b888ddf683..835b05b80f6bf 100644 --- a/packages/contracts-bedrock/test/safe/DeployOwnership.t.sol +++ b/packages/contracts-bedrock/test/safe/DeployOwnership.t.sol @@ -42,7 +42,7 @@ contract DeployOwnershipTest is Test, DeployOwnership { /// @dev Test the example Foundation Safe configurations, against the expected configuration, and /// check that they both have the same configuration. - function test_exampleFoundationSafes() public { + function test_exampleFoundationSafes_configuration_succeeds() public { Safe upgradeSafe = Safe(payable(mustGetAddress("FoundationUpgradeSafe"))); Safe operationsSafe = Safe(payable(mustGetAddress("FoundationOperationsSafe"))); SafeConfig memory exampleFoundationConfig = _getExampleFoundationConfig(); @@ -57,7 +57,7 @@ contract DeployOwnershipTest is Test, DeployOwnership { } /// @dev Test the example Security Council Safe configuration. - function test_exampleSecurityCouncilSafe() public { + function test_exampleSecurityCouncilSafe_configuration_succeeds() public { Safe securityCouncilSafe = Safe(payable(mustGetAddress("SecurityCouncilSafe"))); SecurityCouncilConfig memory exampleSecurityCouncilConfig = _getExampleCouncilConfig(); @@ -96,7 +96,7 @@ contract DeployOwnershipTest is Test, DeployOwnership { } /// @dev Test the example Guardian Safe configuration. - function test_exampleGuardianSafe() public view { + function test_exampleGuardianSafe_configuration_succeeds() public view { Safe guardianSafe = Safe(payable(mustGetAddress("GuardianSafe"))); address[] memory owners = new address[](1); owners[0] = mustGetAddress("SecurityCouncilSafe"); diff --git a/packages/contracts-bedrock/test/safe/DeputyGuardianModule.t.sol b/packages/contracts-bedrock/test/safe/DeputyGuardianModule.t.sol index 47158c2ebaceb..8dd1ba970abdd 100644 --- a/packages/contracts-bedrock/test/safe/DeputyGuardianModule.t.sol +++ b/packages/contracts-bedrock/test/safe/DeputyGuardianModule.t.sol @@ -8,7 +8,7 @@ import { GnosisSafe as Safe } from "safe-contracts/GnosisSafe.sol"; import "test/safe-tools/SafeTestTools.sol"; // Contracts -import { DeputyGuardianModule } from "src/safe/DeputyGuardianModule.sol"; +import { IDeputyGuardianModule } from "src/safe/interfaces/IDeputyGuardianModule.sol"; // Libraries import "src/dispute/lib/Types.sol"; @@ -17,6 +17,7 @@ import "src/dispute/lib/Types.sol"; import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol"; import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol"; import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; contract DeputyGuardianModule_TestInit is CommonTest, SafeTestTools { using SafeTestLib for SafeInstance; @@ -26,7 +27,7 @@ contract DeputyGuardianModule_TestInit is CommonTest, SafeTestTools { event ExecutionFromModuleSuccess(address indexed); - DeputyGuardianModule deputyGuardianModule; + IDeputyGuardianModule deputyGuardianModule; SafeInstance safeInstance; address deputyGuardian; @@ -47,11 +48,16 @@ contract DeputyGuardianModule_TestInit is CommonTest, SafeTestTools { deputyGuardian = makeAddr("deputyGuardian"); - deputyGuardianModule = new DeputyGuardianModule({ - _safe: safeInstance.safe, - _superchainConfig: superchainConfig, - _deputyGuardian: deputyGuardian - }); + deputyGuardianModule = IDeputyGuardianModule( + DeployUtils.create1({ + _name: "DeputyGuardianModule", + _args: DeployUtils.encodeConstructor( + abi.encodeCall( + IDeputyGuardianModule.__constructor__, (safeInstance.safe, superchainConfig, deputyGuardian) + ) + ) + }) + ); safeInstance.enableModule(address(deputyGuardianModule)); } } @@ -94,7 +100,7 @@ contract DeputyGuardianModule_Pause_TestFail is DeputyGuardianModule_TestInit { function test_pause_targetReverts_reverts() external { vm.mockCallRevert( address(superchainConfig), - abi.encodeWithSelector(superchainConfig.pause.selector), + abi.encodePacked(superchainConfig.pause.selector), "SuperchainConfig: pause() reverted" ); @@ -144,7 +150,7 @@ contract DeputyGuardianModule_Unpause_TestFail is DeputyGuardianModule_Unpause_T function test_unpause_targetReverts_reverts() external { vm.mockCallRevert( address(superchainConfig), - abi.encodeWithSelector(superchainConfig.unpause.selector), + abi.encodePacked(superchainConfig.unpause.selector), "SuperchainConfig: unpause reverted" ); @@ -164,9 +170,7 @@ contract DeputyGuardianModule_SetAnchorState_TestFail is DeputyGuardianModule_Te function test_setAnchorState_targetReverts_reverts() external { IAnchorStateRegistry asr = IAnchorStateRegistry(makeAddr("asr")); vm.mockCallRevert( - address(asr), - abi.encodeWithSelector(asr.setAnchorState.selector), - "AnchorStateRegistry: setAnchorState reverted" + address(asr), abi.encodePacked(asr.setAnchorState.selector), "AnchorStateRegistry: setAnchorState reverted" ); vm.prank(address(deputyGuardian)); vm.expectRevert( @@ -180,9 +184,7 @@ contract DeputyGuardianModule_SetAnchorState_Test is DeputyGuardianModule_TestIn function test_setAnchorState_succeeds() external { IAnchorStateRegistry asr = IAnchorStateRegistry(makeAddr("asr")); vm.mockCall( - address(asr), - abi.encodeWithSelector(IAnchorStateRegistry.setAnchorState.selector, IFaultDisputeGame(address(0))), - "" + address(asr), abi.encodeCall(IAnchorStateRegistry.setAnchorState, (IFaultDisputeGame(address(0)))), "" ); vm.expectEmit(address(safeInstance.safe)); emit ExecutionFromModuleSuccess(address(deputyGuardianModule)); @@ -222,7 +224,7 @@ contract DeputyGuardianModule_BlacklistDisputeGame_TestFail is DeputyGuardianMod function test_blacklistDisputeGame_targetReverts_reverts() external { vm.mockCallRevert( address(optimismPortal2), - abi.encodeWithSelector(optimismPortal2.blacklistDisputeGame.selector), + abi.encodePacked(optimismPortal2.blacklistDisputeGame.selector), "OptimismPortal2: blacklistDisputeGame reverted" ); @@ -265,7 +267,7 @@ contract DeputyGuardianModule_setRespectedGameType_TestFail is DeputyGuardianMod function test_setRespectedGameType_targetReverts_reverts() external { vm.mockCallRevert( address(optimismPortal2), - abi.encodeWithSelector(optimismPortal2.setRespectedGameType.selector), + abi.encodePacked(optimismPortal2.setRespectedGameType.selector), "OptimismPortal2: setRespectedGameType reverted" ); diff --git a/packages/contracts-bedrock/test/safe/LivenessGuard.t.sol b/packages/contracts-bedrock/test/safe/LivenessGuard.t.sol index f1386a6608a22..a7b67b415b225 100644 --- a/packages/contracts-bedrock/test/safe/LivenessGuard.t.sol +++ b/packages/contracts-bedrock/test/safe/LivenessGuard.t.sol @@ -68,7 +68,7 @@ contract LivenessGuard_Getters_Test is LivenessGuard_TestInit { contract LivenessGuard_CheckTx_TestFails is LivenessGuard_TestInit { /// @dev Tests that the checkTransaction function reverts if the caller is not the Safe - function test_checkTransaction_callerIsNotSafe_revert() external { + function test_checkTransaction_callerIsNotSafe_reverts() external { vm.expectRevert("LivenessGuard: only Safe can call this function"); livenessGuard.checkTransaction({ _to: address(0), @@ -110,7 +110,7 @@ contract LivenessGuard_CheckTx_Test is LivenessGuard_TestInit { vm.expectEmit(address(livenessGuard)); emit OwnerRecorded(signers[i]); } - vm.expectCall(address(safeInstance.safe), abi.encodeWithSignature("nonce()")); + vm.expectCall(address(safeInstance.safe), abi.encodeCall(safeInstance.safe.nonce, ())); vm.expectCall(address(safeInstance.safe), abi.encodeCall(OwnerManager.getThreshold, ())); safeInstance.execTransaction({ to: address(1111), value: 0, data: hex"abba" }); for (uint256 i; i < safeInstance.threshold; i++) { @@ -123,7 +123,7 @@ contract LivenessGuard_CheckTx_Test is LivenessGuard_TestInit { contract LivenessGuard_CheckAfterExecution_TestFails is LivenessGuard_TestInit { /// @dev Tests that the checkAfterExecution function reverts if the caller is not the Safe - function test_checkAfterExecution_callerIsNotSafe_revert() external { + function test_checkAfterExecution_callerIsNotSafe_reverts() external { vm.expectRevert("LivenessGuard: only Safe can call this function"); livenessGuard.checkAfterExecution(bytes32(0), false); } @@ -228,7 +228,8 @@ contract LivenessGuard_FuzzOwnerManagement_Test is StdCheats, StdUtils, Liveness mapping(address => uint256) privateKeys; /// @dev Tests that the guard correctly manages the lastLive mapping when owners are added, removed, or swapped - function testFuzz_OwnerManagement_works( + /// forge-config: ciheavy.fuzz.runs = 8192 + function testFuzz_ownerManagement_works( uint256 initialOwners, uint256 threshold, OwnerChange[] memory changes diff --git a/packages/contracts-bedrock/test/safe/LivenessModule.t.sol b/packages/contracts-bedrock/test/safe/LivenessModule.t.sol index e101f59ca5a41..5a6a30950227e 100644 --- a/packages/contracts-bedrock/test/safe/LivenessModule.t.sol +++ b/packages/contracts-bedrock/test/safe/LivenessModule.t.sol @@ -488,7 +488,7 @@ contract LivenessModule_RemoveOwnersFuzz_Test is LivenessModule_TestInit { } /// @dev Tests if removing owners works correctly for various safe configurations and numbeers of live owners - function testFuzz_removeOwners( + function testFuzz_removeOwners_works( uint256 _numOwners, uint256 _minOwners, uint256 _numLiveOwners, diff --git a/packages/contracts-bedrock/test/safe/SafeSigners.t.sol b/packages/contracts-bedrock/test/safe/SafeSigners.t.sol index 9cfa918698993..cb9737a3e9751 100644 --- a/packages/contracts-bedrock/test/safe/SafeSigners.t.sol +++ b/packages/contracts-bedrock/test/safe/SafeSigners.t.sol @@ -75,6 +75,7 @@ contract SafeSigners_Test is Test, SafeTestTools { contractSigs++; address addr = SafeTestLib.decodeSmartContractWalletAsAddress(pks[i]); r = bytes32(uint256(uint160(addr))); + // nosemgrep: sol-style-use-abi-encodecall vm.mockCall( addr, abi.encodeWithSignature("isValidSignature(bytes,bytes)"), abi.encode(EIP1271_MAGIC_VALUE) ); diff --git a/packages/contracts-bedrock/test/setup/Bridge_Initializer.sol b/packages/contracts-bedrock/test/setup/Bridge_Initializer.sol deleted file mode 100644 index 6b931712935ea..0000000000000 --- a/packages/contracts-bedrock/test/setup/Bridge_Initializer.sol +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.15; - -import { CommonTest } from "test/setup/CommonTest.sol"; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import { OptimismMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; -import { LegacyMintableERC20 } from "src/legacy/LegacyMintableERC20.sol"; - -/// @title Bridge_Initializer -/// @dev This contract extends the CommonTest contract with token deployments -/// meant to be used with the bridge contracts. -contract Bridge_Initializer is CommonTest { - ERC20 L1Token; - ERC20 BadL1Token; - OptimismMintableERC20 L2Token; - LegacyMintableERC20 LegacyL2Token; - ERC20 NativeL2Token; - ERC20 BadL2Token; - OptimismMintableERC20 RemoteL1Token; - - function setUp() public virtual override { - super.setUp(); - - L1Token = new ERC20("Native L1 Token", "L1T"); - - LegacyL2Token = new LegacyMintableERC20({ - _l2Bridge: address(l2StandardBridge), - _l1Token: address(L1Token), - _name: string.concat("LegacyL2-", L1Token.name()), - _symbol: string.concat("LegacyL2-", L1Token.symbol()) - }); - vm.label(address(LegacyL2Token), "LegacyMintableERC20"); - - // Deploy the L2 ERC20 now - L2Token = OptimismMintableERC20( - l2OptimismMintableERC20Factory.createStandardL2Token( - address(L1Token), - string(abi.encodePacked("L2-", L1Token.name())), - string(abi.encodePacked("L2-", L1Token.symbol())) - ) - ); - - BadL2Token = OptimismMintableERC20( - l2OptimismMintableERC20Factory.createStandardL2Token( - address(1), - string(abi.encodePacked("L2-", L1Token.name())), - string(abi.encodePacked("L2-", L1Token.symbol())) - ) - ); - - NativeL2Token = new ERC20("Native L2 Token", "L2T"); - - RemoteL1Token = OptimismMintableERC20( - l1OptimismMintableERC20Factory.createStandardL2Token( - address(NativeL2Token), - string(abi.encodePacked("L1-", NativeL2Token.name())), - string(abi.encodePacked("L1-", NativeL2Token.symbol())) - ) - ); - - BadL1Token = OptimismMintableERC20( - l1OptimismMintableERC20Factory.createStandardL2Token( - address(1), - string(abi.encodePacked("L1-", NativeL2Token.name())), - string(abi.encodePacked("L1-", NativeL2Token.symbol())) - ) - ); - } -} diff --git a/packages/contracts-bedrock/test/setup/CommonTest.sol b/packages/contracts-bedrock/test/setup/CommonTest.sol index 679ce200559c9..93ede20b629ef 100644 --- a/packages/contracts-bedrock/test/setup/CommonTest.sol +++ b/packages/contracts-bedrock/test/setup/CommonTest.sol @@ -6,7 +6,9 @@ import { Setup } from "test/setup/Setup.sol"; import { Events } from "test/setup/Events.sol"; import { FFIInterface } from "test/setup/FFIInterface.sol"; import { Constants } from "src/libraries/Constants.sol"; -import "scripts/deploy/DeployConfig.s.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { OptimismMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; +import { LegacyMintableERC20 } from "src/legacy/LegacyMintableERC20.sol"; /// @title CommonTest /// @dev An extenstion to `Test` that sets up the optimism smart contracts. @@ -23,6 +25,14 @@ contract CommonTest is Test, Setup, Events { address customGasToken; bool useInteropOverride; + ERC20 L1Token; + ERC20 BadL1Token; + OptimismMintableERC20 L2Token; + LegacyMintableERC20 LegacyL2Token; + ERC20 NativeL2Token; + ERC20 BadL2Token; + OptimismMintableERC20 RemoteL1Token; + function setUp() public virtual override { alice = makeAddr("alice"); bob = makeAddr("bob"); @@ -65,6 +75,56 @@ contract CommonTest is Test, Setup, Events { Setup.L1(); // Deploy L2 Setup.L2(); + + // Call bridge initializer setup function + bridgeInitializerSetUp(); + } + + function bridgeInitializerSetUp() public { + L1Token = new ERC20("Native L1 Token", "L1T"); + + LegacyL2Token = new LegacyMintableERC20({ + _l2Bridge: address(l2StandardBridge), + _l1Token: address(L1Token), + _name: string.concat("LegacyL2-", L1Token.name()), + _symbol: string.concat("LegacyL2-", L1Token.symbol()) + }); + vm.label(address(LegacyL2Token), "LegacyMintableERC20"); + + // Deploy the L2 ERC20 now + L2Token = OptimismMintableERC20( + l2OptimismMintableERC20Factory.createStandardL2Token( + address(L1Token), + string(abi.encodePacked("L2-", L1Token.name())), + string(abi.encodePacked("L2-", L1Token.symbol())) + ) + ); + + BadL2Token = OptimismMintableERC20( + l2OptimismMintableERC20Factory.createStandardL2Token( + address(1), + string(abi.encodePacked("L2-", L1Token.name())), + string(abi.encodePacked("L2-", L1Token.symbol())) + ) + ); + + NativeL2Token = new ERC20("Native L2 Token", "L2T"); + + RemoteL1Token = OptimismMintableERC20( + l1OptimismMintableERC20Factory.createStandardL2Token( + address(NativeL2Token), + string(abi.encodePacked("L1-", NativeL2Token.name())), + string(abi.encodePacked("L1-", NativeL2Token.symbol())) + ) + ); + + BadL1Token = OptimismMintableERC20( + l1OptimismMintableERC20Factory.createStandardL2Token( + address(1), + string(abi.encodePacked("L1-", NativeL2Token.name())), + string(abi.encodePacked("L1-", NativeL2Token.symbol())) + ) + ); } /// @dev Helper function that wraps `TransactionDeposited` event. diff --git a/packages/contracts-bedrock/test/setup/DeployVariations.t.sol b/packages/contracts-bedrock/test/setup/DeployVariations.t.sol index 348d3d8e5237b..31f687f0fdb86 100644 --- a/packages/contracts-bedrock/test/setup/DeployVariations.t.sol +++ b/packages/contracts-bedrock/test/setup/DeployVariations.t.sol @@ -24,7 +24,7 @@ contract DeployVariations_Test is CommonTest { /// forge-config: ciheavy.fuzz.runs = 512 /// @dev It should be possible to enable Fault Proofs with any mix of CGT and Alt-DA. - function testFuzz_enableFaultProofs(bool _enableCGT, bool _enableAltDa) public virtual { + function testFuzz_enableFaultProofs_succeeds(bool _enableCGT, bool _enableAltDa) public virtual { enableAddOns(_enableCGT, _enableAltDa); super.setUp(); @@ -32,7 +32,7 @@ contract DeployVariations_Test is CommonTest { /// forge-config: ciheavy.fuzz.runs = 512 /// @dev It should be possible to enable Fault Proofs and Interop with any mix of CGT and Alt-DA. - function test_enableInteropAndFaultProofs(bool _enableCGT, bool _enableAltDa) public virtual { + function test_enableInteropAndFaultProofs_succeeds(bool _enableCGT, bool _enableAltDa) public virtual { enableAddOns(_enableCGT, _enableAltDa); super.enableInterop(); diff --git a/packages/contracts-bedrock/test/setup/Events.sol b/packages/contracts-bedrock/test/setup/Events.sol index 7f8017bfb2c1d..966b236c30c84 100644 --- a/packages/contracts-bedrock/test/setup/Events.sol +++ b/packages/contracts-bedrock/test/setup/Events.sol @@ -104,4 +104,6 @@ contract Events { event Paused(string identifier); event Unpaused(); + + event BalanceChanged(address account, uint256 balance); } diff --git a/packages/contracts-bedrock/test/setup/FFIInterface.sol b/packages/contracts-bedrock/test/setup/FFIInterface.sol index 727402a37c2c1..c1e1612da8e6b 100644 --- a/packages/contracts-bedrock/test/setup/FFIInterface.sol +++ b/packages/contracts-bedrock/test/setup/FFIInterface.sol @@ -317,6 +317,90 @@ contract FFIInterface { 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-cannon64"; + cmds[1] = "diff"; + cmds[2] = "cannonMemoryProof"; + cmds[3] = vm.toString(addr); + cmds[4] = vm.toString(value); + bytes memory result = Process.run(cmds); + (bytes32 memRoot, bytes memory proof) = abi.decode(result, (bytes32, bytes)); + return (memRoot, proof); + } + + function getCannonMemory64Proof( + uint64 addr0, + uint64 value0, + uint64 addr1, + uint64 value1 + ) + external + returns (bytes32, bytes memory) + { + string[] memory cmds = new string[](7); + cmds[0] = "scripts/go-ffi/go-ffi-cannon64"; + cmds[1] = "diff"; + cmds[2] = "cannonMemoryProof"; + cmds[3] = vm.toString(addr0); + cmds[4] = vm.toString(value0); + cmds[5] = vm.toString(addr1); + cmds[6] = vm.toString(value1); + bytes memory result = Process.run(cmds); + (bytes32 memRoot, bytes memory proof) = abi.decode(result, (bytes32, bytes)); + return (memRoot, proof); + } + + function getCannonMemory64Proof( + uint64 addr0, + uint64 value0, + uint64 addr1, + uint64 value1, + uint64 memAddr2, + uint64 memVal2 + ) + external + returns (bytes32, bytes memory) + { + string[] memory cmds = new string[](9); + cmds[0] = "scripts/go-ffi/go-ffi-cannon64"; + cmds[1] = "diff"; + cmds[2] = "cannonMemoryProof"; + cmds[3] = vm.toString(addr0); + cmds[4] = vm.toString(value0); + cmds[5] = vm.toString(addr1); + cmds[6] = vm.toString(value1); + cmds[7] = vm.toString(memAddr2); + cmds[8] = vm.toString(memVal2); + bytes memory result = Process.run(cmds); + (bytes32 memRoot, bytes memory proof) = abi.decode(result, (bytes32, bytes)); + return (memRoot, proof); + } + + function getCannonMemory64Proof2( + uint64 addr0, + uint64 value0, + uint64 addr1, + uint64 value1, + uint64 memAddrForProof + ) + external + returns (bytes32, bytes memory) + { + string[] memory cmds = new string[](8); + cmds[0] = "scripts/go-ffi/go-ffi-cannon64"; + cmds[1] = "diff"; + cmds[2] = "cannonMemoryProof2"; + cmds[3] = vm.toString(addr0); + cmds[4] = vm.toString(value0); + cmds[5] = vm.toString(addr1); + cmds[6] = vm.toString(value1); + 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 encodeScalarEcotone(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) external returns (bytes32) { string[] memory cmds = new string[](5); cmds[0] = "scripts/go-ffi/go-ffi"; diff --git a/packages/contracts-bedrock/test/setup/Setup.sol b/packages/contracts-bedrock/test/setup/Setup.sol index 10ee252218fc8..ef2b654b2410d 100644 --- a/packages/contracts-bedrock/test/setup/Setup.sol +++ b/packages/contracts-bedrock/test/setup/Setup.sol @@ -45,7 +45,7 @@ import { IGasPriceOracle } from "src/L2/interfaces/IGasPriceOracle.sol"; import { IL1Block } from "src/L2/interfaces/IL1Block.sol"; import { ISuperchainWETH } from "src/L2/interfaces/ISuperchainWETH.sol"; import { IETHLiquidity } from "src/L2/interfaces/IETHLiquidity.sol"; -import { IWETH } from "src/universal/interfaces/IWETH.sol"; +import { IWETH98 } from "src/universal/interfaces/IWETH98.sol"; import { IGovernanceToken } from "src/governance/interfaces/IGovernanceToken.sol"; import { ILegacyMessagePasser } from "src/legacy/interfaces/ILegacyMessagePasser.sol"; import { ISuperchainTokenBridge } from "src/L2/interfaces/ISuperchainTokenBridge.sol"; @@ -105,7 +105,7 @@ contract Setup { IL1Block l1Block = IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES); IGovernanceToken governanceToken = IGovernanceToken(Predeploys.GOVERNANCE_TOKEN); ILegacyMessagePasser legacyMessagePasser = ILegacyMessagePasser(Predeploys.LEGACY_MESSAGE_PASSER); - IWETH weth = IWETH(payable(Predeploys.WETH)); + IWETH98 weth = IWETH98(payable(Predeploys.WETH)); ISuperchainWETH superchainWeth = ISuperchainWETH(payable(Predeploys.SUPERCHAIN_WETH)); IETHLiquidity ethLiquidity = IETHLiquidity(Predeploys.ETH_LIQUIDITY); ISuperchainTokenBridge superchainTokenBridge = ISuperchainTokenBridge(Predeploys.SUPERCHAIN_TOKEN_BRIDGE); diff --git a/packages/contracts-bedrock/slither.config.json b/packages/contracts-bedrock/test/slither/slither.config.json similarity index 100% rename from packages/contracts-bedrock/slither.config.json rename to packages/contracts-bedrock/test/slither/slither.config.json diff --git a/packages/contracts-bedrock/slither.db.json b/packages/contracts-bedrock/test/slither/slither.db.json similarity index 100% rename from packages/contracts-bedrock/slither.db.json rename to packages/contracts-bedrock/test/slither/slither.db.json diff --git a/packages/contracts-bedrock/test/universal/BenchmarkTest.t.sol b/packages/contracts-bedrock/test/universal/BenchmarkTest.t.sol index f53310055e2b6..fd0a9bfc7847f 100644 --- a/packages/contracts-bedrock/test/universal/BenchmarkTest.t.sol +++ b/packages/contracts-bedrock/test/universal/BenchmarkTest.t.sol @@ -5,16 +5,16 @@ pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; import { Vm } from "forge-std/Vm.sol"; import { CommonTest } from "test/setup/CommonTest.sol"; -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; // Libraries import { Types } from "src/libraries/Types.sol"; import { SafeCall } from "src/libraries/SafeCall.sol"; -import { L1BlockInterop } from "src/L2/L1BlockInterop.sol"; +import { IL1BlockInterop } from "src/L2/interfaces/IL1BlockInterop.sol"; import { Encoding } from "src/libraries/Encoding.sol"; // Interfaces import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; // Free function for setting the prevBaseFee param in the OptimismPortal. function setPrevBaseFee(Vm _vm, address _op, uint128 _prevBaseFee) { @@ -109,7 +109,7 @@ contract GasBenchMark_OptimismPortal is CommonTest { } } -contract GasBenchMark_L1CrossDomainMessenger is Bridge_Initializer { +contract GasBenchMark_L1CrossDomainMessenger is CommonTest { function test_sendMessage_benchmark_0() external { vm.pauseGasMetering(); setPrevBaseFee(vm, address(optimismPortal), 1 gwei); @@ -131,7 +131,7 @@ contract GasBenchMark_L1CrossDomainMessenger is Bridge_Initializer { } } -contract GasBenchMark_L1StandardBridge_Deposit is Bridge_Initializer { +contract GasBenchMark_L1StandardBridge_Deposit is CommonTest { function setUp() public virtual override { super.setUp(); deal(address(L1Token), alice, 100000, true); @@ -180,13 +180,13 @@ contract GasBenchMark_L1StandardBridge_Deposit is Bridge_Initializer { } } -contract GasBenchMark_L1StandardBridge_Finalize is Bridge_Initializer { +contract GasBenchMark_L1StandardBridge_Finalize is CommonTest { function setUp() public virtual override { super.setUp(); deal(address(L1Token), address(l1StandardBridge), 100, true); vm.mockCall( address(l1StandardBridge.messenger()), - abi.encodeWithSelector(ICrossDomainMessenger.xDomainMessageSender.selector), + abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encode(address(l1StandardBridge.OTHER_BRIDGE())) ); vm.startPrank(address(l1StandardBridge.messenger())); @@ -257,11 +257,16 @@ contract GasBenchMark_L1Block_SetValuesEcotone_Warm is GasBenchMark_L1Block { } contract GasBenchMark_L1BlockInterop is GasBenchMark_L1Block { - L1BlockInterop l1BlockInterop; + IL1BlockInterop l1BlockInterop; function setUp() public virtual override { super.setUp(); - l1BlockInterop = new L1BlockInterop(); + l1BlockInterop = IL1BlockInterop( + DeployUtils.create1({ + _name: "L1BlockInterop", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IL1BlockInterop.__constructor__, ())) + }) + ); setValuesCalldata = Encoding.encodeSetL1BlockValuesInterop( type(uint32).max, type(uint32).max, @@ -296,7 +301,7 @@ contract GasBenchMark_L1BlockInterop_DepositsComplete is GasBenchMark_L1BlockInt function test_depositsComplete_benchmark() external { SafeCall.call({ _target: address(l1BlockInterop), - _calldata: abi.encodeWithSelector(l1BlockInterop.depositsComplete.selector) + _calldata: abi.encodeCall(IL1BlockInterop.depositsComplete, ()) }); } } @@ -311,7 +316,7 @@ contract GasBenchMark_L1BlockInterop_DepositsComplete_Warm is GasBenchMark_L1Blo function test_depositsComplete_benchmark() external { SafeCall.call({ _target: address(l1BlockInterop), - _calldata: abi.encodeWithSelector(l1BlockInterop.depositsComplete.selector) + _calldata: abi.encodeCall(l1BlockInterop.depositsComplete, ()) }); } } diff --git a/packages/contracts-bedrock/test/universal/CrossDomainMessenger.t.sol b/packages/contracts-bedrock/test/universal/CrossDomainMessenger.t.sol index dddb09d41239c..50398e4a89200 100644 --- a/packages/contracts-bedrock/test/universal/CrossDomainMessenger.t.sol +++ b/packages/contracts-bedrock/test/universal/CrossDomainMessenger.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.15; // Testing utilities import { Test } from "forge-std/Test.sol"; -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; @@ -14,7 +14,7 @@ import { IL1CrossDomainMessenger } from "src/L1/interfaces/IL1CrossDomainMesseng // CrossDomainMessenger_Test is for testing functionality which is common to both the L1 and L2 // CrossDomainMessenger contracts. For simplicity, we use the L1 Messenger as the test contract. -contract CrossDomainMessenger_BaseGas_Test is Bridge_Initializer { +contract CrossDomainMessenger_BaseGas_Test is CommonTest { /// @dev Ensure that baseGas passes for the max value of _minGasLimit, /// this is about 4 Billion. function test_baseGas_succeeds() external view { @@ -99,7 +99,7 @@ contract ExternalRelay is Test { /// @notice Helper function to get the callData for an `externalCallWithMinGas function getCallData() public pure returns (bytes memory) { - return abi.encodeWithSelector(ExternalRelay.externalCallWithMinGas.selector); + return abi.encodeCall(ExternalRelay.externalCallWithMinGas, ()); } /// @notice Helper function to set the fuzzed sender @@ -110,7 +110,7 @@ contract ExternalRelay is Test { /// @title CrossDomainMessenger_RelayMessage_Test /// @notice Fuzz tests re-entrancy into the CrossDomainMessenger relayMessage function. -contract CrossDomainMessenger_RelayMessage_Test is Bridge_Initializer { +contract CrossDomainMessenger_RelayMessage_Test is CommonTest { // Storage slot of the l2Sender uint256 constant senderSlotIndex = 50; diff --git a/packages/contracts-bedrock/test/universal/OptimismMintableERC20.t.sol b/packages/contracts-bedrock/test/universal/OptimismMintableERC20.t.sol index 1e84ce2958cf3..d56a97b19db34 100644 --- a/packages/contracts-bedrock/test/universal/OptimismMintableERC20.t.sol +++ b/packages/contracts-bedrock/test/universal/OptimismMintableERC20.t.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; -import { ILegacyMintableERC20, IOptimismMintableERC20 } from "src/universal/interfaces/IOptimismMintableERC20.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; +import { IOptimismMintableERC20 } from "src/universal/interfaces/IOptimismMintableERC20.sol"; +import { ILegacyMintableERC20 } from "src/universal/interfaces/ILegacyMintableERC20.sol"; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; -contract OptimismMintableERC20_Test is Bridge_Initializer { +contract OptimismMintableERC20_Test is CommonTest { event Mint(address indexed account, uint256 amount); event Burn(address indexed account, uint256 amount); @@ -46,11 +47,11 @@ contract OptimismMintableERC20_Test is Bridge_Initializer { assertEq(L2Token.balanceOf(alice), 100); } - function test_allowance_permit2_max() external view { + function test_allowance_permit2Max_works() external view { assertEq(L2Token.allowance(alice, L2Token.PERMIT2()), type(uint256).max); } - function test_permit2_transferFrom() external { + function test_permit2_transferFrom_succeeds() external { vm.prank(address(l2StandardBridge)); L2Token.mint(alice, 100); diff --git a/packages/contracts-bedrock/test/universal/OptimismMintableERC20Factory.t.sol b/packages/contracts-bedrock/test/universal/OptimismMintableERC20Factory.t.sol index cba5fc8290862..74df9e729e83b 100644 --- a/packages/contracts-bedrock/test/universal/OptimismMintableERC20Factory.t.sol +++ b/packages/contracts-bedrock/test/universal/OptimismMintableERC20Factory.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.15; // Testing -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; import { NextImpl } from "test/mocks/NextImpl.sol"; import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; @@ -14,7 +14,7 @@ import { OptimismMintableERC20Factory } from "src/universal/OptimismMintableERC2 import { IProxy } from "src/universal/interfaces/IProxy.sol"; import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimismMintableERC20Factory.sol"; -contract OptimismMintableTokenFactory_Test is Bridge_Initializer { +contract OptimismMintableTokenFactory_Test is CommonTest { event StandardL2TokenCreated(address indexed remoteToken, address indexed localToken); event OptimismMintableERC20Created(address indexed localToken, address indexed remoteToken, address deployer); @@ -42,7 +42,7 @@ contract OptimismMintableTokenFactory_Test is Bridge_Initializer { vm.startPrank(EIP1967Helper.getAdmin(address(proxy))); // Reviewer note: the NextImpl() still uses reinitializer. If we want to remove that, we'll need to use a // two step upgrade with the Storage lib. - proxy.upgradeToAndCall(address(nextImpl), abi.encodeWithSelector(NextImpl.initialize.selector, 2)); + proxy.upgradeToAndCall(address(nextImpl), abi.encodeCall(NextImpl.initialize, (2))); assertEq(proxy.implementation(), address(nextImpl)); // Verify that the NextImpl contract initialized its values according as expected diff --git a/packages/contracts-bedrock/test/universal/OptimismMintableERC721.t.sol b/packages/contracts-bedrock/test/universal/OptimismMintableERC721.t.sol index daea00064cf44..dfe2234e0b644 100644 --- a/packages/contracts-bedrock/test/universal/OptimismMintableERC721.t.sol +++ b/packages/contracts-bedrock/test/universal/OptimismMintableERC721.t.sol @@ -5,10 +5,10 @@ import { ERC721, IERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol import { IERC721Enumerable } from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; import { OptimismMintableERC721, IOptimismMintableERC721 } from "src/universal/OptimismMintableERC721.sol"; -contract OptimismMintableERC721_Test is Bridge_Initializer { +contract OptimismMintableERC721_Test is CommonTest { ERC721 internal L1NFT; OptimismMintableERC721 internal L2NFT; @@ -30,6 +30,7 @@ contract OptimismMintableERC721_Test is Bridge_Initializer { vm.label(address(L2NFT), "L2ERC721Token"); } + /// @notice Tests that the constructor works as expected. function test_constructor_succeeds() external view { assertEq(L2NFT.name(), "L2NFT"); assertEq(L2NFT.symbol(), "L2T"); @@ -41,6 +42,24 @@ contract OptimismMintableERC721_Test is Bridge_Initializer { assertEq(L2NFT.REMOTE_CHAIN_ID(), 1); } + /// @notice Tests that the bridge cannot be address(0) at construction time. + function test_constructor_bridgeAsAddress0_reverts() external { + vm.expectRevert("OptimismMintableERC721: bridge cannot be address(0)"); + L2NFT = new OptimismMintableERC721(address(0), 1, address(L1NFT), "L2NFT", "L2T"); + } + + /// @notice Tests that the remote chain ID cannot be zero at construction time. + function test_constructor_remoteChainId0_reverts() external { + vm.expectRevert("OptimismMintableERC721: remote chain id cannot be zero"); + L2NFT = new OptimismMintableERC721(address(l2ERC721Bridge), 0, address(L1NFT), "L2NFT", "L2T"); + } + + /// @notice Tests that the remote token cannot be address(0) at construction time. + function test_constructor_remoteTokenAsAddress0_reverts() external { + vm.expectRevert("OptimismMintableERC721: remote token cannot be address(0)"); + L2NFT = new OptimismMintableERC721(address(l2ERC721Bridge), 1, address(0), "L2NFT", "L2T"); + } + /// @notice Ensure that the contract supports the expected interfaces. function test_supportsInterfaces_succeeds() external view { // Checks if the contract supports the IOptimismMintableERC721 interface. diff --git a/packages/contracts-bedrock/test/universal/OptimismMintableERC721Factory.t.sol b/packages/contracts-bedrock/test/universal/OptimismMintableERC721Factory.t.sol index ef9019eafa04f..91340001c5e95 100644 --- a/packages/contracts-bedrock/test/universal/OptimismMintableERC721Factory.t.sol +++ b/packages/contracts-bedrock/test/universal/OptimismMintableERC721Factory.t.sol @@ -1,12 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; import { OptimismMintableERC721 } from "src/universal/OptimismMintableERC721.sol"; import { OptimismMintableERC721Factory } from "src/universal/OptimismMintableERC721Factory.sol"; -contract OptimismMintableERC721Factory_Test is Bridge_Initializer { +contract OptimismMintableERC721Factory_Test is CommonTest { event OptimismMintableERC721Created(address indexed localToken, address indexed remoteToken, address deployer); function test_constructor_succeeds() external view { diff --git a/packages/contracts-bedrock/test/universal/Proxy.t.sol b/packages/contracts-bedrock/test/universal/Proxy.t.sol index 66c3f1d242684..8c6aa7ae5137a 100644 --- a/packages/contracts-bedrock/test/universal/Proxy.t.sol +++ b/packages/contracts-bedrock/test/universal/Proxy.t.sol @@ -2,8 +2,9 @@ pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; -import { Proxy } from "src/universal/Proxy.sol"; import { Bytes32AddressLib } from "@rari-capital/solmate/src/utils/Bytes32AddressLib.sol"; +import { IProxy } from "src/universal/interfaces/IProxy.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; contract SimpleStorage { mapping(uint256 => uint256) internal store; @@ -19,7 +20,7 @@ contract SimpleStorage { contract Clasher { function upgradeTo(address) external pure { - revert("upgradeTo"); + revert("Clasher: upgradeTo"); } } @@ -33,13 +34,18 @@ contract Proxy_Test is Test { bytes32 internal constant OWNER_KEY = bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1); - Proxy proxy; + IProxy proxy; SimpleStorage simpleStorage; function setUp() external { // Deploy a proxy and simple storage contract as // the implementation - proxy = new Proxy(alice); + proxy = IProxy( + DeployUtils.create1({ + _name: "Proxy", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (alice))) + }) + ); simpleStorage = new SimpleStorage(); vm.prank(alice); @@ -154,7 +160,7 @@ contract Proxy_Test is Test { vm.expectEmit(true, true, true, true); emit Upgraded(address(simpleStorage)); vm.prank(alice); - proxy.upgradeToAndCall(address(simpleStorage), abi.encodeWithSelector(simpleStorage.set.selector, 1, 1)); + proxy.upgradeToAndCall(address(simpleStorage), abi.encodeCall(SimpleStorage.set, (1, 1))); // The call should have impacted the state uint256 result = SimpleStorage(address(proxy)).get(1); @@ -187,7 +193,7 @@ contract Proxy_Test is Test { // The attempt to `upgradeToAndCall` // should revert when it is not called by the owner. vm.expectRevert(bytes("")); - proxy.upgradeToAndCall(address(simpleStorage), abi.encodeWithSelector(simpleStorage.set.selector, 1, 1)); + proxy.upgradeToAndCall(address(simpleStorage), abi.encodeCall(simpleStorage.set, (1, 1))); } function test_upgradeToAndCall_isPayable_succeeds() external { @@ -196,9 +202,7 @@ contract Proxy_Test is Test { // Set the implementation and call and send // value. vm.prank(alice); - proxy.upgradeToAndCall{ value: 1 ether }( - address(simpleStorage), abi.encodeWithSelector(simpleStorage.set.selector, 1, 1) - ); + proxy.upgradeToAndCall{ value: 1 ether }(address(simpleStorage), abi.encodeCall(simpleStorage.set, (1, 1))); // The implementation address should be correct vm.prank(alice); @@ -228,7 +232,7 @@ contract Proxy_Test is Test { // not as the owner so that the call passes through. // The implementation will revert so we can be // sure that the call passed through. - vm.expectRevert(bytes("upgradeTo")); + vm.expectRevert(bytes("Clasher: upgradeTo")); proxy.upgradeTo(address(0)); { @@ -259,7 +263,8 @@ contract Proxy_Test is Test { (bool success, bytes memory returndata) = address(proxy).call(hex""); assertEq(success, false); - bytes memory err = abi.encodeWithSignature("Error(string)", "Proxy: implementation not initialized"); + bytes memory err = abi.encodeWithSignature("Error(string)", "Proxy: implementation not initialized"); // nosemgrep: + // sol-style-use-abi-encodecall assertEq(returndata, err); } diff --git a/packages/contracts-bedrock/test/universal/ProxyAdmin.t.sol b/packages/contracts-bedrock/test/universal/ProxyAdmin.t.sol index e212644c9d50d..04e416cbd3a97 100644 --- a/packages/contracts-bedrock/test/universal/ProxyAdmin.t.sol +++ b/packages/contracts-bedrock/test/universal/ProxyAdmin.t.sol @@ -5,47 +5,73 @@ pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; import { SimpleStorage } from "test/universal/Proxy.t.sol"; -// Contracts -import { Proxy } from "src/universal/Proxy.sol"; -import { ProxyAdmin } from "src/universal/ProxyAdmin.sol"; -import { AddressManager } from "src/legacy/AddressManager.sol"; -import { L1ChugSplashProxy } from "src/legacy/L1ChugSplashProxy.sol"; -import { ResolvedDelegateProxy } from "src/legacy/ResolvedDelegateProxy.sol"; - // Interfaces import { IAddressManager } from "src/legacy/interfaces/IAddressManager.sol"; +import { IL1ChugSplashProxy } from "src/legacy/interfaces/IL1ChugSplashProxy.sol"; +import { IResolvedDelegateProxy } from "src/legacy/interfaces/IResolvedDelegateProxy.sol"; +import { IProxy } from "src/universal/interfaces/IProxy.sol"; +import { IProxyAdmin } from "src/universal/interfaces/IProxyAdmin.sol"; + +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; contract ProxyAdmin_Test is Test { address alice = address(64); - Proxy proxy; - L1ChugSplashProxy chugsplash; - ResolvedDelegateProxy resolved; + IProxy proxy; + IL1ChugSplashProxy chugsplash; + IResolvedDelegateProxy resolved; - AddressManager addressManager; + IAddressManager addressManager; - ProxyAdmin admin; + IProxyAdmin admin; SimpleStorage implementation; function setUp() external { // Deploy the proxy admin - admin = new ProxyAdmin(alice); + admin = IProxyAdmin( + DeployUtils.create1({ + _name: "ProxyAdmin", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxyAdmin.__constructor__, (alice))) + }) + ); + // Deploy the standard proxy - proxy = new Proxy(address(admin)); + proxy = IProxy( + DeployUtils.create1({ + _name: "Proxy", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IProxy.__constructor__, (address(admin)))) + }) + ); // Deploy the legacy L1ChugSplashProxy with the admin as the owner - chugsplash = new L1ChugSplashProxy(address(admin)); + chugsplash = IL1ChugSplashProxy( + DeployUtils.create1({ + _name: "L1ChugSplashProxy", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IL1ChugSplashProxy.__constructor__, (address(admin)))) + }) + ); // Deploy the legacy AddressManager - addressManager = new AddressManager(); + addressManager = IAddressManager( + DeployUtils.create1({ + _name: "AddressManager", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IAddressManager.__constructor__, ())) + }) + ); // The proxy admin must be the new owner of the address manager addressManager.transferOwnership(address(admin)); // Deploy a legacy ResolvedDelegateProxy with the name `a`. // Whatever `a` is set to in AddressManager will be the address // that is used for the implementation. - resolved = new ResolvedDelegateProxy(addressManager, "a"); - + resolved = IResolvedDelegateProxy( + DeployUtils.create1({ + _name: "ResolvedDelegateProxy", + _args: DeployUtils.encodeConstructor( + abi.encodeCall(IResolvedDelegateProxy.__constructor__, (addressManager, "a")) + ) + }) + ); // Impersonate alice for setting up the admin. vm.startPrank(alice); // Set the address of the address manager in the admin so that it @@ -57,9 +83,9 @@ contract ProxyAdmin_Test is Test { admin.setImplementationName(address(resolved), "a"); // Set the proxy types - admin.setProxyType(address(proxy), ProxyAdmin.ProxyType.ERC1967); - admin.setProxyType(address(chugsplash), ProxyAdmin.ProxyType.CHUGSPLASH); - admin.setProxyType(address(resolved), ProxyAdmin.ProxyType.RESOLVED); + admin.setProxyType(address(proxy), IProxyAdmin.ProxyType.ERC1967); + admin.setProxyType(address(chugsplash), IProxyAdmin.ProxyType.CHUGSPLASH); + admin.setProxyType(address(resolved), IProxyAdmin.ProxyType.RESOLVED); vm.stopPrank(); implementation = new SimpleStorage(); @@ -83,7 +109,7 @@ contract ProxyAdmin_Test is Test { function test_setProxyType_notOwner_reverts() external { vm.expectRevert("Ownable: caller is not the owner"); - admin.setProxyType(address(0), ProxyAdmin.ProxyType.CHUGSPLASH); + admin.setProxyType(address(0), IProxyAdmin.ProxyType.CHUGSPLASH); } function test_owner_succeeds() external view { @@ -91,9 +117,9 @@ contract ProxyAdmin_Test is Test { } function test_proxyType_succeeds() external view { - assertEq(uint256(admin.proxyType(address(proxy))), uint256(ProxyAdmin.ProxyType.ERC1967)); - assertEq(uint256(admin.proxyType(address(chugsplash))), uint256(ProxyAdmin.ProxyType.CHUGSPLASH)); - assertEq(uint256(admin.proxyType(address(resolved))), uint256(ProxyAdmin.ProxyType.RESOLVED)); + assertEq(uint256(admin.proxyType(address(proxy))), uint256(IProxyAdmin.ProxyType.ERC1967)); + assertEq(uint256(admin.proxyType(address(chugsplash))), uint256(IProxyAdmin.ProxyType.CHUGSPLASH)); + assertEq(uint256(admin.proxyType(address(resolved))), uint256(IProxyAdmin.ProxyType.RESOLVED)); } function test_erc1967GetProxyImplementation_succeeds() external { @@ -153,7 +179,7 @@ contract ProxyAdmin_Test is Test { } function changeProxyAdmin(address payable _proxy) internal { - ProxyAdmin.ProxyType proxyType = admin.proxyType(address(_proxy)); + IProxyAdmin.ProxyType proxyType = admin.proxyType(address(_proxy)); vm.prank(alice); admin.changeProxyAdmin(_proxy, address(128)); @@ -162,13 +188,13 @@ contract ProxyAdmin_Test is Test { // no longer call the proxy interface except for // the ResolvedDelegate type on which anybody can // call the admin interface. - if (proxyType == ProxyAdmin.ProxyType.ERC1967) { + if (proxyType == IProxyAdmin.ProxyType.ERC1967) { vm.expectRevert("Proxy: implementation not initialized"); admin.getProxyAdmin(_proxy); - } else if (proxyType == ProxyAdmin.ProxyType.CHUGSPLASH) { + } else if (proxyType == IProxyAdmin.ProxyType.CHUGSPLASH) { vm.expectRevert("L1ChugSplashProxy: implementation is not set yet"); admin.getProxyAdmin(_proxy); - } else if (proxyType == ProxyAdmin.ProxyType.RESOLVED) { + } else if (proxyType == IProxyAdmin.ProxyType.RESOLVED) { // Just an empty block to show that all cases are covered } else { vm.expectRevert("ProxyAdmin: unknown proxy type"); @@ -177,11 +203,11 @@ contract ProxyAdmin_Test is Test { // Call the proxy contract directly to get the admin. // Different proxy types have different interfaces. vm.prank(address(128)); - if (proxyType == ProxyAdmin.ProxyType.ERC1967) { - assertEq(Proxy(payable(_proxy)).admin(), address(128)); - } else if (proxyType == ProxyAdmin.ProxyType.CHUGSPLASH) { - assertEq(L1ChugSplashProxy(payable(_proxy)).getOwner(), address(128)); - } else if (proxyType == ProxyAdmin.ProxyType.RESOLVED) { + if (proxyType == IProxyAdmin.ProxyType.ERC1967) { + assertEq(IProxy(payable(_proxy)).admin(), address(128)); + } else if (proxyType == IProxyAdmin.ProxyType.CHUGSPLASH) { + assertEq(IL1ChugSplashProxy(payable(_proxy)).getOwner(), address(128)); + } else if (proxyType == IProxyAdmin.ProxyType.RESOLVED) { assertEq(addressManager.owner(), address(128)); } else { assert(false); @@ -222,7 +248,7 @@ contract ProxyAdmin_Test is Test { function upgradeAndCall(address payable _proxy) internal { vm.prank(alice); - admin.upgradeAndCall(_proxy, address(implementation), abi.encodeWithSelector(SimpleStorage.set.selector, 1, 1)); + admin.upgradeAndCall(_proxy, address(implementation), abi.encodeCall(SimpleStorage.set, (1, 1))); address impl = admin.getProxyImplementation(_proxy); assertEq(impl, address(implementation)); diff --git a/packages/contracts-bedrock/test/universal/Specs.t.sol b/packages/contracts-bedrock/test/universal/Specs.t.sol index f6f6b989896bf..49e35e835f36b 100644 --- a/packages/contracts-bedrock/test/universal/Specs.t.sol +++ b/packages/contracts-bedrock/test/universal/Specs.t.sol @@ -16,6 +16,7 @@ import { IOptimismPortal } from "src/L1/interfaces/IOptimismPortal.sol"; import { IOptimismPortal2 } from "src/L1/interfaces/IOptimismPortal2.sol"; import { IOptimismPortalInterop } from "src/L1/interfaces/IOptimismPortalInterop.sol"; import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; +import { ISystemConfigInterop } from "src/L1/interfaces/ISystemConfigInterop.sol"; import { IDataAvailabilityChallenge } from "src/L1/interfaces/IDataAvailabilityChallenge.sol"; import { IProtocolVersions } from "src/L1/interfaces/IProtocolVersions.sol"; @@ -106,14 +107,6 @@ contract Specification_Test is CommonTest { _addSpec({ _name: "DataAvailabilityChallenge", _sel: IDataAvailabilityChallenge.resolve.selector }); _addSpec({ _name: "DataAvailabilityChallenge", _sel: IDataAvailabilityChallenge.unlockBond.selector }); - // DelayedVetoable - _addSpec({ _name: "DelayedVetoable", _sel: _getSel("delay()") }); - _addSpec({ _name: "DelayedVetoable", _sel: _getSel("initiator()") }); - _addSpec({ _name: "DelayedVetoable", _sel: _getSel("queuedAt(bytes32)") }); - _addSpec({ _name: "DelayedVetoable", _sel: _getSel("target()") }); - _addSpec({ _name: "DelayedVetoable", _sel: _getSel("version()") }); - _addSpec({ _name: "DelayedVetoable", _sel: _getSel("vetoer()") }); - // L1CrossDomainMessenger _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("MESSAGE_VERSION()") }); _addSpec({ _name: "L1CrossDomainMessenger", _sel: _getSel("MIN_GAS_CALLDATA_OVERHEAD()") }); @@ -487,36 +480,37 @@ contract Specification_Test is CommonTest { _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("gasLimit()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("eip1559Denominator()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("eip1559Elasticity()") }); + _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfigInterop.initialize.selector }); _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfig.initialize.selector }); - _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfig.minimumGasLimit.selector }); + _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfigInterop.minimumGasLimit.selector }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("overhead()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("owner()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("renounceOwnership()"), _auth: Role.SYSTEMCONFIGOWNER }); - _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfig.resourceConfig.selector }); + _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfigInterop.resourceConfig.selector }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("scalar()") }); _addSpec({ _name: "SystemConfigInterop", - _sel: ISystemConfig.setBatcherHash.selector, + _sel: ISystemConfigInterop.setBatcherHash.selector, _auth: Role.SYSTEMCONFIGOWNER }); _addSpec({ _name: "SystemConfigInterop", - _sel: ISystemConfig.setGasConfig.selector, + _sel: ISystemConfigInterop.setGasConfig.selector, _auth: Role.SYSTEMCONFIGOWNER }); _addSpec({ _name: "SystemConfigInterop", - _sel: ISystemConfig.setGasLimit.selector, + _sel: ISystemConfigInterop.setGasLimit.selector, _auth: Role.SYSTEMCONFIGOWNER }); _addSpec({ _name: "SystemConfigInterop", - _sel: ISystemConfig.setEIP1559Params.selector, + _sel: ISystemConfigInterop.setEIP1559Params.selector, _auth: Role.SYSTEMCONFIGOWNER }); _addSpec({ _name: "SystemConfigInterop", - _sel: ISystemConfig.setUnsafeBlockSigner.selector, + _sel: ISystemConfigInterop.setUnsafeBlockSigner.selector, _auth: Role.SYSTEMCONFIGOWNER }); _addSpec({ @@ -524,7 +518,7 @@ contract Specification_Test is CommonTest { _sel: _getSel("transferOwnership(address)"), _auth: Role.SYSTEMCONFIGOWNER }); - _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfig.unsafeBlockSigner.selector }); + _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfigInterop.unsafeBlockSigner.selector }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("version()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("l1CrossDomainMessenger()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("l1ERC721Bridge()") }); @@ -560,12 +554,6 @@ contract Specification_Test is CommonTest { _auth: Role.DEPENDENCYMANAGER }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("dependencyManager()") }); - _addSpec({ - _name: "SystemConfigInterop", - _sel: _getSel( - "initialize(address,uint32,uint32,bytes32,uint64,address,(uint32,uint8,uint8,uint32,uint32,uint128),address,(address,address,address,address,address,address,address),address)" - ) - }); // ProxyAdmin _addSpec({ _name: "ProxyAdmin", _sel: _getSel("addressManager()") }); @@ -849,27 +837,25 @@ contract Specification_Test is CommonTest { _addSpec({ _name: "OPContractsManager", _sel: _getSel("version()") }); _addSpec({ _name: "OPContractsManager", _sel: _getSel("superchainConfig()") }); _addSpec({ _name: "OPContractsManager", _sel: _getSel("protocolVersions()") }); - _addSpec({ _name: "OPContractsManager", _sel: _getSel("latestRelease()") }); - _addSpec({ _name: "OPContractsManager", _sel: _getSel("implementations(string,string)") }); + _addSpec({ _name: "OPContractsManager", _sel: _getSel("l1ContractsRelease()") }); _addSpec({ _name: "OPContractsManager", _sel: _getSel("systemConfigs(uint256)") }); _addSpec({ _name: "OPContractsManager", _sel: _getSel("OUTPUT_VERSION()") }); - _addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.initialize.selector }); _addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.deploy.selector }); _addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.blueprints.selector }); _addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.chainIdToBatchInboxAddress.selector }); + _addSpec({ _name: "OPContractsManager", _sel: OPContractsManager.implementations.selector }); // OPContractsManagerInterop _addSpec({ _name: "OPContractsManagerInterop", _sel: _getSel("version()") }); _addSpec({ _name: "OPContractsManagerInterop", _sel: _getSel("superchainConfig()") }); _addSpec({ _name: "OPContractsManagerInterop", _sel: _getSel("protocolVersions()") }); - _addSpec({ _name: "OPContractsManagerInterop", _sel: _getSel("latestRelease()") }); - _addSpec({ _name: "OPContractsManagerInterop", _sel: _getSel("implementations(string,string)") }); + _addSpec({ _name: "OPContractsManagerInterop", _sel: _getSel("l1ContractsRelease()") }); _addSpec({ _name: "OPContractsManagerInterop", _sel: _getSel("systemConfigs(uint256)") }); _addSpec({ _name: "OPContractsManagerInterop", _sel: _getSel("OUTPUT_VERSION()") }); - _addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.initialize.selector }); _addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.deploy.selector }); _addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.blueprints.selector }); _addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.chainIdToBatchInboxAddress.selector }); + _addSpec({ _name: "OPContractsManagerInterop", _sel: OPContractsManager.implementations.selector }); // DeputyGuardianModule _addSpec({ @@ -952,13 +938,14 @@ contract Specification_Test is CommonTest { } /// @notice Ensures that there's an auth spec for every L1 contract function. - function testContractAuth() public { - string[] memory pathExcludes = new string[](5); + function test_contractAuth_works() public { + string[] memory pathExcludes = new string[](6); pathExcludes[0] = "src/dispute/interfaces/*"; pathExcludes[1] = "src/dispute/lib/*"; pathExcludes[2] = "src/safe/SafeSigners.sol"; pathExcludes[3] = "src/L1/interfaces/*"; pathExcludes[4] = "src/governance/interfaces/*"; + pathExcludes[5] = "src/safe/interfaces/*"; Abi[] memory abis = ForgeArtifacts.getContractFunctionAbis( "src/{L1,dispute,governance,safe,universal/ProxyAdmin.sol,universal/WETH98.sol}", pathExcludes ); @@ -1001,7 +988,7 @@ contract Specification_Test is CommonTest { } /// @notice Ensures that the DeputyGuardian is authorized to take all Guardian actions. - function testDeputyGuardianAuth() public view { + function test_deputyGuardianAuth_works() public view { assertEq(specsByRole[Role.DEPUTYGUARDIAN].length, specsByRole[Role.GUARDIAN].length); assertEq(specsByRole[Role.DEPUTYGUARDIAN].length, 5); diff --git a/packages/contracts-bedrock/test/universal/StandardBridge.t.sol b/packages/contracts-bedrock/test/universal/StandardBridge.t.sol index e2f62b32b8433..be7f8a51107c7 100644 --- a/packages/contracts-bedrock/test/universal/StandardBridge.t.sol +++ b/packages/contracts-bedrock/test/universal/StandardBridge.t.sol @@ -30,7 +30,7 @@ contract StandardBridgeTester is StandardBridge { /// @title LegacyMintable /// @notice Simple implementation of the legacy OptimismMintableERC20. -contract LegacyMintable is ERC20, ILegacyMintableERC20 { +contract LegacyMintable is ERC20 { constructor(string memory _name, string memory _ticker) ERC20(_name, _ticker) { } function l1Token() external pure returns (address) { diff --git a/packages/contracts-bedrock/test/vendor/Initializable.t.sol b/packages/contracts-bedrock/test/vendor/Initializable.t.sol index 5c17987c471d7..eb43ae1875996 100644 --- a/packages/contracts-bedrock/test/vendor/Initializable.t.sol +++ b/packages/contracts-bedrock/test/vendor/Initializable.t.sol @@ -2,18 +2,16 @@ pragma solidity 0.8.15; // Testing -import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; +import { CommonTest } from "test/setup/CommonTest.sol"; // Scripts -import { Executables } from "scripts/libraries/Executables.sol"; import { ForgeArtifacts } from "scripts/libraries/ForgeArtifacts.sol"; import { Process } from "scripts/libraries/Process.sol"; // Libraries import { LibString } from "@solady/utils/LibString.sol"; import { Constants } from "src/libraries/Constants.sol"; -import "src/dispute/lib/Types.sol"; -import "scripts/deploy/Deployer.sol"; +import { GameType } from "src/dispute/lib/Types.sol"; // Interfaces import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; @@ -27,7 +25,7 @@ import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistr /// once. This contract inherits from `ERC721Bridge_Initializer` because it is the /// deepest contract in the inheritance chain for setting up the system contracts. /// For each L1 contract both the implementation and the proxy are tested. -contract Initializer_Test is Bridge_Initializer { +contract Initializer_Test is CommonTest { /// @notice Contains the address of an `Initializable` contract and the calldata /// used to initialize it. struct InitializeableContract { @@ -432,21 +430,14 @@ contract Initializer_Test is Bridge_Initializer { } // Construct the query for the initialize function in the contract's ABI. - string[] memory command = new string[](3); - command[0] = Executables.bash; - command[1] = "-c"; - command[2] = string.concat( - Executables.echo, - " '", + string memory cmd = string.concat( + "echo '", ForgeArtifacts.getAbi(contractName), - "'", - " | ", - Executables.jq, - " '.[] | select(.name == \"initialize\" and .type == \"function\")'" + "' | jq '.[] | select(.name == \"initialize\" and .type == \"function\")'" ); // If the contract does not have an `initialize()` function, skip it. - if (Process.run(command).length == 0) { + if (bytes(Process.bash(cmd)).length == 0) { continue; } diff --git a/packages/contracts-bedrock/test/vendor/InitializableOZv5.t.sol b/packages/contracts-bedrock/test/vendor/InitializableOZv5.t.sol index 0820f987414a2..4b663d697ba65 100644 --- a/packages/contracts-bedrock/test/vendor/InitializableOZv5.t.sol +++ b/packages/contracts-bedrock/test/vendor/InitializableOZv5.t.sol @@ -2,12 +2,13 @@ pragma solidity 0.8.25; import { Test } from "forge-std/Test.sol"; -import { OptimismSuperchainERC20 } from "src/L2/OptimismSuperchainERC20.sol"; +import { IOptimismSuperchainERC20 } from "src/L2/interfaces/IOptimismSuperchainERC20.sol"; import { Initializable } from "@openzeppelin/contracts-v5/proxy/utils/Initializable.sol"; - +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; /// @title InitializerOZv5_Test /// @dev Ensures that the `initialize()` function on contracts cannot be called more than /// once. Tests the contracts inheriting from `Initializable` from OpenZeppelin Contracts v5. + contract InitializerOZv5_Test is Test { /// @notice The storage slot of the `initialized` flag in the `Initializable` contract from OZ v5. /// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) @@ -31,8 +32,13 @@ contract InitializerOZv5_Test is Test { // OptimismSuperchainERC20 contracts.push( InitializeableContract({ - target: address(new OptimismSuperchainERC20()), - initCalldata: abi.encodeCall(OptimismSuperchainERC20.initialize, (address(0), "", "", 18)) + target: address( + DeployUtils.create1({ + _name: "OptimismSuperchainERC20", + _args: DeployUtils.encodeConstructor(abi.encodeCall(IOptimismSuperchainERC20.__constructor__, ())) + }) + ), + initCalldata: abi.encodeCall(IOptimismSuperchainERC20.initialize, (address(0), "", "", 18)) }) ); } diff --git a/proxyd/README.md b/proxyd/README.md deleted file mode 100644 index f44b815ab2dce..0000000000000 --- a/proxyd/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# ⚠️ Important -This project has been moved to [ethereum-optimism/infra](https://github.com/ethereum-optimism/infra) diff --git a/specs/README.md b/specs/README.md deleted file mode 100644 index e75cc2b9f6686..0000000000000 --- a/specs/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Specs Have Moved - -Specs have moved to a [dedicated repository](https://github.com/ethereum-optimism/specs). \ No newline at end of file