version: 2.1

parameters:
  ci_builder_image:
    type: string
    default: us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:v0.59.0
  ci_builder_rust_image:
    type: string
    default: us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder-rust:latest
  base_image:
    type: string
    default: default
  # The dispatch parameters are used to manually dispatch pipelines that normally only run post-merge on develop
  # from the CircleCI UI. Example configuration:
  #   when:
  #     or:
  #       - equal: [ "develop", <<pipeline.git.branch>> ]
  #       - equal: [ true, <<pipeline.parameters.main_dispatch>> ]
  # Add a new `*_dispatch` parameter for any pipeline you want manual dispatch for.
  main_dispatch:
    type: boolean
    default: true # default to running main in case the manual run cancelled an automatic run
  fault_proofs_dispatch:
    type: boolean
    default: false
  reproducibility_dispatch:
    type: boolean
    default: false
  diff_asterisc_bytecode_dispatch:
    type: boolean
    default: false
  kontrol_dispatch:
    type: boolean
    default: false
  cannon_full_test_dispatch:
    type: boolean
    default: false
  sdk_dispatch:
    type: boolean
    default: false
  docker_publish_dispatch:
    type: boolean
    default: false
  publish_contract_artifacts_dispatch:
    type: boolean
    default: false
  stale_check_dispatch:
    type: boolean
    default: false
  contracts_coverage_dispatch:
    type: boolean
    default: false

orbs:
  go: circleci/go@1.8.0
  gcp-cli: circleci/gcp-cli@3.0.1
  slack: circleci/slack@4.10.1
  shellcheck: circleci/shellcheck@3.2.0
  codecov: codecov/codecov@5.0.3
commands:
  gcp-oidc-authenticate:
    description: "Authenticate with GCP using a CircleCI OIDC token."
    parameters:
      project_id:
        type: env_var_name
        default: GCP_PROJECT_ID
      workload_identity_pool_id:
        type: env_var_name
        default: GCP_WIP_ID
      workload_identity_pool_provider_id:
        type: env_var_name
        default: GCP_WIP_PROVIDER_ID
      service_account_email:
        type: env_var_name
        default: GCP_SERVICE_ACCOUNT_EMAIL
      gcp_cred_config_file_path:
        type: string
        default: /home/circleci/gcp_cred_config.json
      oidc_token_file_path:
        type: string
        default: /home/circleci/oidc_token.json
    steps:
      - run:
          name: "Create OIDC credential configuration"
          command: |
            # Store OIDC token in temp file
            echo $CIRCLE_OIDC_TOKEN > << parameters.oidc_token_file_path >>
            # Create a credential configuration for the generated OIDC ID Token
            gcloud iam workload-identity-pools create-cred-config \
                "projects/${<< parameters.project_id >>}/locations/global/workloadIdentityPools/${<< parameters.workload_identity_pool_id >>}/providers/${<< parameters.workload_identity_pool_provider_id >>}"\
                --output-file="<< parameters.gcp_cred_config_file_path >>" \
                --service-account="${<< parameters.service_account_email >>}" \
                --credential-source-file=<< parameters.oidc_token_file_path >>
      - run:
          name: "Authenticate with GCP using OIDC"
          command: |
            # Configure gcloud to leverage the generated credential configuration
            gcloud auth login --brief --cred-file "<< parameters.gcp_cred_config_file_path >>"
            # Configure ADC
            echo "export GOOGLE_APPLICATION_CREDENTIALS='<< parameters.gcp_cred_config_file_path >>'" | tee -a "$BASH_ENV"

  check-changed:
    description: "Conditionally halts a step if certain modules change"
    parameters:
      patterns:
        type: string
        description: "Comma-separated list of dependencies"
      no_go_deps:
        type: string
        default: ""
        description: "If set, does not trigger on `go.mod` / `go.sum` changes."
    steps:
      - run:
          name: "Check for changes"
          environment:
            CHECK_CHANGED_NO_GO_DEPS: "<<parameters.no_go_deps>>"
          command: |
            cd ops/check-changed
            pip3 install -r requirements.txt
            python3 main.py "<<parameters.patterns>>"

  install-contracts-dependencies:
    description: "Install the dependencies for the smart contracts"
    steps:
      - run:
          name: Install dependencies
          command: |
            # Manually craft the submodule update command in order to take advantage
            # of the -j parameter, which speeds it up a lot.
            git submodule update --init --recursive --force -j 8
          working_directory: packages/contracts-bedrock
      - run:
          name: Verify mise dependencies
          command: |
            if command -v mise &> /dev/null; then
              mise install
            else
              echo "mise not found, skipping"
            fi

  notify-failures-on-develop:
    description: "Notify Slack"
    parameters:
      channel:
        type: string
        default: C03N11M0BBN
      mentions:
        type: string
        default: ""
    steps:
      - slack/notify:
          channel: << parameters.channel >>
          event: fail
          template: basic_fail_1
          branch_pattern: develop
          mentions: "<< parameters.mentions >>"

  run-contracts-check:
    parameters:
      command:
        description: Just command that runs the check
        type: string
    steps:
      - run:
          name: <<parameters.command>>
          command: |
            git reset --hard
            just <<parameters.command>>
            git diff --quiet --exit-code
          working_directory: packages/contracts-bedrock
          when: always
          environment:
            FOUNDRY_PROFILE: ci

jobs:
  cannon-go-lint-and-test:
    machine: true
    resource_class: ethereum-optimism/latitude-1
    parameters:
      skip_slow_tests:
        type: boolean
        default: false
      notify:
        description: Whether to notify on failure
        type: boolean
        default: false
      mips_word_size:
        type: integer
        default: 32
    steps:
      - checkout
      - check-changed:
          patterns: cannon,packages/contracts-bedrock/src/cannon,op-preimage,go.mod
      - attach_workspace:
          at: "."
      - run:
          name: prep Cannon results dir
          command: |
            mkdir -p ./tmp/test-results
            mkdir -p ./tmp/testlogs
      - run:
          name: build Cannon example binaries
          command: make elf # only compile ELF binaries with Go, we do not have MIPS GCC for creating the debug-dumps.
          working_directory: cannon/testdata/example
      - run:
          name: Cannon Go lint
          command: |
            make lint
          working_directory: cannon
      - when:
          condition:
            equal: [32, <<parameters.mips_word_size>>]
          steps:
            - run:
                name: Cannon Go 32-bit tests
                command: |
                  export SKIP_SLOW_TESTS=<<parameters.skip_slow_tests>>
                  TIMEOUT="10m"
                  if [ "$SKIP_SLOW_TESTS" == "false" ]; then
                    TIMEOUT="30m"
                  fi
                  gotestsum --format=testname --junitfile=../tmp/test-results/cannon-32.xml --jsonfile=../tmp/testlogs/log-32.json \
                  -- -timeout=$TIMEOUT -parallel=$(nproc) -coverpkg=github.com/ethereum-optimism/optimism/cannon/... -coverprofile=coverage-32.out ./...
                working_directory: cannon
            - codecov/upload:
                disable_search: true
                files: ./cannon/coverage-32.out
                flags: cannon-go-tests-32
      - when:
          condition:
            equal: [64, <<parameters.mips_word_size>>]
          steps:
            - run:
                name: Cannon Go 64-bit tests
                command: |
                  export SKIP_SLOW_TESTS=<<parameters.skip_slow_tests>>
                  TIMEOUT="10m"
                  if [ "$SKIP_SLOW_TESTS" == "false" ]; then
                    TIMEOUT="30m"
                  fi
                  gotestsum --format=testname --junitfile=../tmp/test-results/cannon-64.xml --jsonfile=../tmp/testlogs/log-64.json \
                  -- --tags=cannon64 -timeout=$TIMEOUT -parallel=$(nproc) -coverpkg=github.com/ethereum-optimism/optimism/cannon/... -coverprofile=coverage-64.out ./...
                working_directory: cannon
            - codecov/upload:
                disable_search: true
                files: ./cannon/coverage-64.out
                flags: cannon-go-tests-64
      - store_test_results:
          path: ./tmp/test-results
      - store_artifacts:
          path: ./tmp/testlogs
          when: always
      - when:
          condition: <<parameters.notify>>
          steps:
            - notify-failures-on-develop:
                mentions: "@proofs-team"

  cannon-build-test-vectors:
    docker:
      - image: <<pipeline.parameters.ci_builder_image>>
    resource_class: medium
    steps:
      - checkout
      - check-changed:
          patterns: cannon/mipsevm/tests/open_mips_tests/test
      - run:
          name: Build MIPS test vectors
          command: python3 maketests.py && git diff --exit-code
          working_directory: cannon/mipsevm/tests/open_mips_tests

  diff-asterisc-bytecode:
    docker:
      - image: <<pipeline.parameters.ci_builder_image>>
    resource_class: medium
    steps:
      - checkout
      - run:
          name: Check `RISCV.sol` bytecode
          working_directory: packages/contracts-bedrock
          command: |
            # Clone asterisc @ the pinned version to fetch remote `RISCV.sol`
            ASTERISC_REV="v$(yq '.tools.asterisc' ../../mise.toml)"
            REMOTE_ASTERISC_PATH="./src/vendor/asterisc/RISCV_Remote.sol"
            git clone https://github.com/ethereum-optimism/asterisc \
              -b $ASTERISC_REV && \
              cp ./asterisc/rvsol/src/RISCV.sol $REMOTE_ASTERISC_PATH

            # Replace import paths
            sed -i -e 's/@optimism\///' $REMOTE_ASTERISC_PATH
            # Replace legacy interface paths
            sed -i -e 's/src\/cannon\/interfaces\//interfaces\/cannon\//g' $REMOTE_ASTERISC_PATH
            sed -i -e 's/src\/dispute\/interfaces\//interfaces\/dispute\//g' $REMOTE_ASTERISC_PATH
            # Replace contract name
            sed -i -e 's/contract RISCV/contract RISCV_Remote/' $REMOTE_ASTERISC_PATH

            # Install deps
            forge install

            # Diff bytecode, with both contracts compiled in the local environment.
            REMOTE_ASTERISC_CODE="$(forge inspect RISCV_Remote bytecode | tr -d '\n')"
            LOCAL_ASTERISC_CODE="$(forge inspect RISCV bytecode | tr -d '\n')"
            if [ "$REMOTE_ASTERISC_CODE" != "$LOCAL_ASTERISC_CODE" ]; then
              echo "Asterisc bytecode mismatch. Local version does not match remote. Diff:"
              diff <(echo "$REMOTE_ASTERISC_CODE") <(echo "$LOCAL_ASTERISC_CODE")
            else
              echo "Asterisc version up to date."
            fi
      - notify-failures-on-develop:
          mentions: "@clabby @proofs-team"

  contracts-bedrock-build:
    machine: true
    resource_class: ethereum-optimism/latitude-1
    parameters:
      build_args:
        description: Forge build arguments
        type: string
        default: ""
      profile:
        description: Profile to use for building
        type: string
        default: ci
    steps:
      - checkout
      - install-contracts-dependencies
      - run:
          name: Print forge version
          command: forge --version
      - run:
          name: Pull artifacts
          command: bash scripts/ops/pull-artifacts.sh
          working_directory: packages/contracts-bedrock
      - run:
          name: Build contracts
          command: forge build <<parameters.build_args>>
          environment:
            FOUNDRY_PROFILE: <<parameters.profile>>
          working_directory: packages/contracts-bedrock
      - persist_to_workspace:
          root: "."
          paths:
            - "packages/contracts-bedrock/cache"
            - "packages/contracts-bedrock/artifacts"
            - "packages/contracts-bedrock/forge-artifacts"
            - "packages/contracts-bedrock/deploy-config/devnetL1.json"
            - "packages/contracts-bedrock/deployments/devnetL1"
      - notify-failures-on-develop

  check-kontrol-build:
    docker:
      - image: <<pipeline.parameters.ci_builder_image>>
    resource_class: xlarge
    steps:
      - checkout
      - attach_workspace: { at: "." }
      - install-contracts-dependencies
      - check-changed:
          patterns: contracts-bedrock
      - setup_remote_docker:
          docker_layer_caching: true
      - run:
          name: Run Kontrol build
          command: just kontrol-summary-full
          working_directory: packages/contracts-bedrock
      - run:
          name: Build Kontrol summary files
          command: forge build ./test/kontrol/proofs
          working_directory: packages/contracts-bedrock
      - notify-failures-on-develop

  docker-build:
    environment:
      DOCKER_BUILDKIT: 1
    parameters:
      docker_tags:
        description: Docker image tags, comma-separated
        type: string
      docker_name:
        description: "Docker buildx bake target"
        type: string
        default: ""
      registry:
        description: Docker registry
        type: string
        default: "us-docker.pkg.dev"
      repo:
        description: Docker repo
        type: string
        default: "oplabs-tools-artifacts/images"
      save_image_tag:
        description: Save docker image with given tag
        type: string
        default: ""
      platforms:
        description: Platforms to build for, comma-separated
        type: string
        default: "linux/amd64"
      publish:
        description: Publish the docker image (multi-platform, all tags)
        type: boolean
        default: false
      release:
        description: Run the release script
        type: boolean
        default: false
      resource_class:
        description: Docker resoruce class
        type: string
        default: medium
    machine:
      image: <<pipeline.parameters.base_image>>
      resource_class: "<<parameters.resource_class>>"
      docker_layer_caching: true # we rely on this for faster builds, and actively warm it up for builds with common stages
    steps:
      - checkout
      - attach_workspace:
          at: /tmp/docker_images
      - run:
          command: mkdir -p /tmp/docker_images
      - when:
          condition:
            or:
              - "<<parameters.publish>>"
              - "<<parameters.release>>"
          steps:
            - gcp-cli/install
      - when:
          condition:
            or:
              - "<<parameters.publish>>"
              - "<<parameters.release>>"
          steps:
            - gcp-oidc-authenticate
      - run:
          name: Build
          command: |
            # Check to see if DOCKER_HUB_READ_ONLY_TOKEN is set (i.e. we are in repo) before attempting to use secrets.
            # Building should work without this read only login, but may get rate limited.
            if [[ -v DOCKER_HUB_READ_ONLY_TOKEN ]]; then
              echo "$DOCKER_HUB_READ_ONLY_TOKEN" | docker login -u "$DOCKER_HUB_READ_ONLY_USER" --password-stdin
            fi

            export REGISTRY="<<parameters.registry>>"
            export REPOSITORY="<<parameters.repo>>"
            export IMAGE_TAGS="$(echo -ne "<<parameters.docker_tags>>" | sed "s/[^a-zA-Z0-9\n,]/-/g")"
            export GIT_COMMIT="$(git rev-parse HEAD)"
            export GIT_DATE="$(git show -s --format='%ct')"
            export PLATFORMS="<<parameters.platforms>>"

            echo "Checking git tags pointing at $GIT_COMMIT:"
            tags_at_commit=$(git tag --points-at $GIT_COMMIT)
            echo "Tags at commit:\n$tags_at_commit"

            filtered_tags=$(echo "$tags_at_commit" | grep "^<<parameters.docker_name>>/" || true)
            echo "Filtered tags: $filtered_tags"

            if [ -z "$filtered_tags" ]; then
              export GIT_VERSION="untagged"
            else
              sorted_tags=$(echo "$filtered_tags" | sed "s/<<parameters.docker_name>>\///" | sort -V)
              echo "Sorted tags: $sorted_tags"

              # prefer full release tag over "-rc" release candidate tag if both exist
              full_release_tag=$(echo "$sorted_tags" | grep -v -- "-rc" || true)
              if [ -z "$full_release_tag" ]; then
                export GIT_VERSION=$(echo "$sorted_tags" | tail -n 1)
              else
                export GIT_VERSION=$(echo "$full_release_tag" | tail -n 1)
              fi
            fi

            echo "Setting GIT_VERSION=$GIT_VERSION"

            # Create, start (bootstrap) and use a *named* docker builder
            # This allows us to cross-build multi-platform,
            # and naming allows us to use the DLC (docker-layer-cache)
            docker buildx create --driver=docker-container --name=buildx-build --bootstrap --use

            DOCKER_OUTPUT_DESTINATION=""
            if [ "<<parameters.publish>>" == "true" ]; then
              gcloud auth configure-docker <<parameters.registry>>
              echo "Building for platforms $PLATFORMS and then publishing to registry"
              DOCKER_OUTPUT_DESTINATION="--push"
              if [ "<<parameters.save_image_tag>>" != "" ]; then
                echo "ERROR: cannot save image to docker when publishing to registry"
                exit 1
              fi
            else
              if [ "<<parameters.save_image_tag>>" == "" ]; then
                echo "Running $PLATFORMS build without destination (cache warm-up)"
                DOCKER_OUTPUT_DESTINATION=""
              elif [[ $PLATFORMS == *,* ]]; then
                echo "ERROR: cannot perform multi-arch (platforms: $PLATFORMS) build while also loading the result into regular docker"
                exit 1
              else
                echo "Running single-platform $PLATFORMS build and loading into docker"
                DOCKER_OUTPUT_DESTINATION="--load"
              fi
            fi

            # Let them cook!
            docker buildx bake \
              --progress plain \
              --builder=buildx-build \
              -f docker-bake.hcl \
              $DOCKER_OUTPUT_DESTINATION \
              <<parameters.docker_name>>

          no_output_timeout: 45m
      - when:
          condition: "<<parameters.publish>>"
          steps:
            - notify-failures-on-develop
      - when:
          condition: "<<parameters.save_image_tag>>"
          steps:
            - run:
                name: Save
                command: |
                  IMAGE_NAME="<<parameters.registry>>/<<parameters.repo>>/<<parameters.docker_name>>:<<parameters.save_image_tag>>"
                  docker save -o /tmp/docker_images/<<parameters.docker_name>>.tar $IMAGE_NAME
            - persist_to_workspace:
                root: /tmp/docker_images
                paths: # only write the one file, to avoid concurrent workspace-file additions
                  - "<<parameters.docker_name>>.tar"
      - when:
          condition: "<<parameters.release>>"
          steps:
            - run:
                name: Tag
                command: |
                  ./ops/scripts/ci-docker-tag-op-stack-release.sh <<parameters.registry>>/<<parameters.repo>> $CIRCLE_TAG $CIRCLE_SHA1
      - when:
          condition:
            or:
              - and:
                  - "<<parameters.publish>>"
                  - "<<parameters.release>>"
              - and:
                  - "<<parameters.publish>>"
                  - equal: [develop, << pipeline.git.branch >>]
          steps:
            - gcp-oidc-authenticate:
                service_account_email: GCP_SERVICE_ATTESTOR_ACCOUNT_EMAIL
            - run:
                name: Sign
                command: |
                  VER=$(yq '.tools.binary_signer' mise.toml)
                  wget -O - "https://github.com/ethereum-optimism/binary_signer/archive/refs/tags/v${VER}.tar.gz" | tar xz
                  cd "binary_signer-${VER}/signer"

                  IMAGE_PATH="<<parameters.registry>>/<<parameters.repo>>/<<parameters.docker_name>>:<<pipeline.git.revision>>"
                  echo $IMAGE_PATH
                  pip3 install -r requirements.txt

                  python3 ./sign_image.py --command="sign"\
                      --attestor-project-name="$ATTESTOR_PROJECT_NAME"\
                      --attestor-name="$ATTESTOR_NAME"\
                      --image-path="$IMAGE_PATH"\
                      --signer-logging-level="INFO"\
                      --attestor-key-id="//cloudkms.googleapis.com/v1/projects/$ATTESTOR_PROJECT_NAME/locations/global/keyRings/$ATTESTOR_NAME-key-ring/cryptoKeys/$ATTESTOR_NAME-key/cryptoKeyVersions/1"

  # Verify newly published images (built on AMD machine) will run on ARM
  check-cross-platform:
    docker:
      - image: cimg/nebula:current
    resource_class: arm.medium
    parameters:
      registry:
        description: Docker registry
        type: string
        default: "us-docker.pkg.dev"
      repo:
        description: Docker repo
        type: string
        default: "oplabs-tools-artifacts/images"
      op_component:
        description: "Name of op-stack component (e.g. op-node)"
        type: string
        default: ""
      docker_tag:
        description: "Tag of docker image"
        type: string
        default: "<<pipeline.git.revision>>"
    steps:
      - setup_remote_docker
      - run:
          name: "Verify Image Platform"
          command: |
            image_name="<<parameters.registry>>/<<parameters.repo>>/<<parameters.op_component>>:<<parameters.docker_tag>>"
            echo "Retrieving Docker image manifest: $image_name"
            MANIFEST=$(docker manifest inspect $image_name)

            echo "Verifying 'linux/arm64' is supported..."
            SUPPORTED_PLATFORM=$(echo "$MANIFEST" | jq -r '.manifests[] | select(.platform.architecture == "arm64" and .platform.os == "linux")')
            echo $SUPPORT_PLATFORM
            if [ -z "$SUPPORTED_PLATFORM" ]; then
              echo "Platform 'linux/arm64' not supported by this image"
              exit 1
            fi
      - run:
          name: "Pull and run docker image"
          command: |
            image_name="<<parameters.registry>>/<<parameters.repo>>/<<parameters.op_component>>:<<parameters.docker_tag>>"
            docker pull $image_name || exit 1
            docker run $image_name <<parameters.op_component>> --version || exit 1

  contracts-bedrock-tests:
    machine: true
    resource_class: ethereum-optimism/latitude-1
    parameters:
      test_list:
        description: List of test files to run
        type: string
      test_command:
        description: Test command to execute (test or coverage)
        type: string
        default: test
      test_flags:
        description: Additional flags to pass to the test command
        type: string
        default: ""
      test_timeout:
        description: Timeout for running tests
        type: string
        default: 15m
      test_profile:
        description: Profile to use for testing
        type: string
        default: ci
    steps:
      - checkout
      - attach_workspace: { at: "." }
      - install-contracts-dependencies
      - run:
          name: Check if test list is empty
          command: |
            TEST_FILES=$(<<parameters.test_list>>)
            if [ -z "$TEST_FILES" ]; then
              echo "No test files to run. Exiting early."
              circleci-agent step halt
            fi
          working_directory: packages/contracts-bedrock
      - check-changed:
          patterns: contracts-bedrock,op-node
      - run:
          name: Print dependencies
          command: just dep-status
          working_directory: packages/contracts-bedrock
      - run:
          name: Print forge version
          command: forge --version
          working_directory: packages/contracts-bedrock
      - run:
          name: Pull artifacts
          command: bash scripts/ops/pull-artifacts.sh
          working_directory: packages/contracts-bedrock
      - run:
          name: Build go-ffi
          command: just build-go-ffi
          working_directory: packages/contracts-bedrock
      - run:
          name: Run tests
          command: |
            TEST_FILES=$(<<parameters.test_list>>)
            TEST_FILES=$(echo "$TEST_FILES" | circleci tests split --split-by=timings)
            TEST_FILES=$(echo "$TEST_FILES" | sed 's|^test/||')
            MATCH_PATH="./test/{$(echo "$TEST_FILES" | paste -sd "," -)}"
            forge <<parameters.test_command>> <<parameters.test_flags>> --match-path "$MATCH_PATH"
          environment:
            FOUNDRY_PROFILE: <<parameters.test_profile>>
          working_directory: packages/contracts-bedrock
          no_output_timeout: <<parameters.test_timeout>>
      - run:
          name: Print failed test traces
          command: just test-rerun
          environment:
            FOUNDRY_PROFILE: ci
          working_directory: packages/contracts-bedrock
          when: on_fail
      - run:
          name: Lint forge test names
          command: just lint-forge-tests-check-no-build
          working_directory: packages/contracts-bedrock
      - when:
          condition:
            equal: ["<<parameters.test_command>>", "coverage"]
          steps:
            - codecov/upload:
                disable_search: true
                files: ./packages/contracts-bedrock/lcov.info
                flags: contracts-bedrock-tests
      - save_cache:
          name: Save Go build cache
          key: golang-build-cache-contracts-bedrock-tests-{{ checksum "go.sum" }}
          paths:
            - "/root/.cache/go-build"
      - notify-failures-on-develop

  contracts-bedrock-tests-upgrade:
    machine: true
    resource_class: ethereum-optimism/latitude-1
    steps:
      - checkout
      - attach_workspace: { at: "." }
      - install-contracts-dependencies
      - check-changed:
          patterns: contracts-bedrock,op-node
      - run:
          name: Print dependencies
          command: just dep-status
          working_directory: packages/contracts-bedrock
      - run:
          name: Print forge version
          command: forge --version
          working_directory: packages/contracts-bedrock
      - run:
          name: Pull artifacts
          command: bash scripts/ops/pull-artifacts.sh
          working_directory: packages/contracts-bedrock
      - run:
          name: Write pinned block number for cache key
          command: |
            just print-pinned-block-number > ./pinnedBlockNumber.txt
            cat pinnedBlockNumber.txt
            pwd
          working_directory: packages/contracts-bedrock
      - restore_cache:
          name: Restore forked state
          key: forked-state-contracts-bedrock-tests-upgrade-{{ checksum "packages/contracts-bedrock/pinnedBlockNumber.txt" }}
      - run:
          name: Run tests
          command: just test-upgrade
          environment:
            FOUNDRY_PROFILE: ci
            ETH_RPC_URL: https://ci-mainnet-l1-archive.optimism.io
          working_directory: packages/contracts-bedrock
          no_output_timeout: 15m
      - run:
          name: Print failed test traces
          command: just test-upgrade-rerun
          environment:
            FOUNDRY_PROFILE: ci
            ETH_RPC_URL: https://ci-mainnet-l1-archive.optimism.io
          working_directory: packages/contracts-bedrock
          when: on_fail
      - save_cache:
          name: Save Go build cache
          key: golang-build-cache-contracts-bedrock-tests-{{ checksum "go.sum" }}
          paths:
            - "/root/.cache/go-build"
      - save_cache:
          name: Save forked state
          key: forked-state-contracts-bedrock-tests-upgrade-{{ checksum "packages/contracts-bedrock/pinnedBlockNumber.txt" }}
          when: always
          paths:
            - "/root/.foundry/cache"
      - notify-failures-on-develop

  contracts-bedrock-checks:
    machine: true
    resource_class: ethereum-optimism/latitude-1
    steps:
      - checkout
      - attach_workspace: { at: "." }
      - install-contracts-dependencies
      - check-changed:
          patterns: contracts-bedrock,op-node
      - 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:
          command: semgrep
      - run-contracts-check:
          command: semver-lock-no-build
      - run-contracts-check:
          command: semver-diff-check-no-build
      - run-contracts-check:
          command: validate-deploy-configs
      - run-contracts-check:
          command: lint
      - run-contracts-check:
          command: gas-snapshot-check
      - run-contracts-check:
          command: snapshots-check-no-build
      - run-contracts-check:
          command: interfaces-check-no-build
      - run-contracts-check:
          command: size-check
      - run-contracts-check:
          command: unused-imports-check-no-build
      - run-contracts-check:
          command: validate-spacers-no-build

  todo-issues:
    parameters:
      check_closed:
        type: boolean
        default: true
    machine:
      image: <<pipeline.parameters.base_image>>
    steps:
      - checkout
      - run:
          name: Install ripgrep
          command: sudo apt-get install -y ripgrep
      - run:
          name: Check TODO issues
          command: ./ops/scripts/todo-checker.sh --verbose <<#parameters.check_closed>> --check-closed <</parameters.check_closed>>
      - notify-failures-on-develop

  fuzz-golang:
    parameters:
      package_name:
        description: Go package name
        type: string
      on_changes:
        description: changed pattern to fire fuzzer on
        type: string
      uses_artifacts:
        description: should load in foundry artifacts
        type: boolean
        default: false
    machine: true
    resource_class: ethereum-optimism/latitude-1
    steps:
      - checkout
      - check-changed:
          patterns: "<<parameters.package_name>>"
      - attach_workspace:
          at: "."
          if: ${{ uses_artifacts }}
      - run:
          name: Fuzz
          command: |
            make fuzz
          working_directory: "<<parameters.package_name>>"
      - run:
          name: Copy fuzz artifacts
          command: |
            mkdir -p fuzzdata
            find ./<<parameters.package_name>> -type d -name "fuzz" -exec sh -c 'cp -r "{}"/* fuzzdata/ 2>/dev/null || true' \;
          when: always
      - store_artifacts:
          path: ./fuzzdata
          when: always

  go-lint:
    machine: true
    resource_class: ethereum-optimism/latitude-1
    steps:
      - checkout
      - run:
          name: run Go linter
          command: |
            make lint-go
          working_directory: .

  go-tests:
    parameters:
      notify:
        description: Whether to notify on failure
        type: boolean
        default: false
      mentions:
        description: Slack user or group to mention when notifying of failures
        type: string
        default: ""
      resource_class:
        description: Machine resource class
        type: string
        default: ethereum-optimism/latitude-1-go-e2e
      no_output_timeout:
        description: Timeout for when CircleCI kills the job if there's no output
        type: string
        default: 60m
      test_timeout:
        description: Timeout for running tests
        type: string
        default: 10m
      environment_overrides:
        description: Environment overrides
        type: string
        default: ""
      packages:
        description: List of packages to test
        type: string
    machine: true
    resource_class: <<parameters.resource_class>>
    steps:
      - checkout
      - attach_workspace:
          at: "."
      - run:
          name: build op-program-client
          command: make op-program-client
          working_directory: op-program
      - run:
          name: run tests
          no_output_timeout: <<parameters.no_output_timeout>>
          command: |
            mkdir -p ./tmp/test-results && mkdir -p ./tmp/testlogs

            cd op-e2e && make pre-test && cd ..

            packages=(
              <<parameters.packages>>
            )
            formatted_packages=""
            for package in "${packages[@]}"; do
              formatted_packages="$formatted_packages ./$package/..."
            done

            export ENABLE_KURTOSIS=true
            export OP_E2E_CANNON_ENABLED="false"
            export OP_E2E_SKIP_SLOW_TEST=true
            export OP_E2E_USE_HTTP=true
            export ENABLE_ANVIL=true
            export SEPOLIA_RPC_URL="https://ci-sepolia-l1-archive.optimism.io"
            export MAINNET_RPC_URL="https://ci-mainnet-l1-archive.optimism.io"

            <<parameters.environment_overrides>>

            gotestsum --format=testname \
              --junitfile=./tmp/test-results/results.xml \
              --jsonfile=./tmp/testlogs/log.json \
              --rerun-fails=2 \
              --packages="$formatted_packages" \
              -- -coverprofile=coverage.out -timeout=<<parameters.test_timeout>>
      - codecov/upload:
          disable_search: true
          files: ./coverage.out
      - store_test_results:
          path: ./tmp/test-results
      - store_artifacts:
          path: ./tmp/testlogs
          when: always
      - when:
          condition: "<<parameters.notify>>"
          steps:
            - notify-failures-on-develop:
                mentions: "<<parameters.mentions>>"

  cannon-prestate:
    machine: true
    resource_class: ethereum-optimism/latitude-1
    steps:
      - checkout
      - run:
          name: Build cannon
          command: make cannon
      - run:
          name: Build op-program
          command: make op-program
      - restore_cache:
          name: Restore cannon prestate cache
          key: cannon-prestate-{{ checksum "./cannon/bin/cannon" }}-{{ checksum "op-program/bin/op-program-client.elf" }}
      - run:
          name: Sanitize op-program guest
          command: make -f cannon/Makefile sanitize-program GUEST_PROGRAM=op-program/bin/op-program-client.elf
      - run:
          name: generate cannon prestate
          command: make cannon-prestates
      - save_cache:
          key: cannon-prestate-{{ checksum "./cannon/bin/cannon" }}-{{ checksum "op-program/bin/op-program-client.elf" }}
          name: Save Cannon prestate to cache
          paths:
            - "op-program/bin/prestate*.bin.gz"
            - "op-program/bin/meta*.json"
            - "op-program/bin/prestate-proof*.json"
      - persist_to_workspace:
          root: .
          paths:
            - "op-program/bin"
            - "cannon/bin"

  publish-cannon-prestates:
    docker:
      - image: <<pipeline.parameters.ci_builder_image>>
    steps:
      - checkout
      - attach_workspace:
          at: "."
      - gcp-cli/install
      - gcp-oidc-authenticate:
          gcp_cred_config_file_path: /root/gcp_cred_config.json
          oidc_token_file_path: /root/oidc_token.json
      - run:
          name: Upload cannon prestates
          command: |
            gsutil cp ./op-program/bin/prestate.bin.gz \
              gs://oplabs-network-data/proofs/op-program/cannon/${CIRCLE_BRANCH}.bin.gz
            gsutil cp ./op-program/bin/prestate-mt.bin.gz \
              gs://oplabs-network-data/proofs/op-program/cannon/${CIRCLE_BRANCH}-mt.bin.gz
            gsutil cp ./op-program/bin/prestate-interop.bin.gz \
              gs://oplabs-network-data/proofs/op-program/cannon/${CIRCLE_BRANCH}-interop.bin.gz
      - notify-failures-on-develop:
          mentions: "@proofs-team"

  preimage-reproducibility:
    docker:
      - image: <<pipeline.parameters.ci_builder_image>>
    steps:
      - checkout
      - setup_remote_docker
      - run: make -C op-program verify-reproducibility
      - notify-failures-on-develop:
          mentions: "@proofs-team"

  cannon-stf-verify:
    docker:
      - image: <<pipeline.parameters.ci_builder_image>>
    steps:
      - checkout
      - setup_remote_docker
      - run:
          name: Build cannon
          command: make cannon
      - run:
          name: Verify the Cannon STF
          command: make -C ./cannon cannon-stf-verify
      - notify-failures-on-develop:
          mentions: "@proofs-team"

  semgrep-scan:
    parameters:
      diff_branch:
        type: string
        default: develop
      scan_command:
        type: string
        default: semgrep ci --timeout=100
    environment:
      TEMPORARY_BASELINE_REF: << parameters.diff_branch >>
      SEMGREP_REPO_URL: << pipeline.project.git_url >>
      SEMGREP_BRANCH: << pipeline.git.branch >>
      SEMGREP_COMMIT: << pipeline.git.revision >>
    docker:
      - image: returntocorp/semgrep
    resource_class: xlarge
    steps:
      - checkout
      - unless:
          condition:
            equal: ["develop", << pipeline.git.branch >>]
          steps:
            - run:
                # Scan changed files in PRs, block on new issues only (existing issues ignored)
                # Do a full scan when scanning develop, otherwise do an incremental scan.
                name: "Conditionally set BASELINE env var"
                command: |
                  echo 'export SEMGREP_BASELINE_REF=${TEMPORARY_BASELINE_REF}' >> $BASH_ENV
      - run:
          name: "Set environment variables" # for PR comments and in-app hyperlinks to findings
          command: |
            echo 'export SEMGREP_PR_ID=${CIRCLE_PULL_REQUEST##*/}' >> $BASH_ENV
            echo 'export SEMGREP_JOB_URL=$CIRCLE_BUILD_URL' >> $BASH_ENV
            echo 'export SEMGREP_REPO_NAME=$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME' >> $BASH_ENV
      - run:
          name: "Semgrep scan"
          # --timeout (in seconds) limits the time per rule and file.
          #   SEMGREP_TIMEOUT is the same, but docs have conflicting defaults (5s in CLI flag, 1800 in some places)
          #    https://semgrep.dev/docs/troubleshooting/semgrep-app#if-the-job-is-aborted-due-to-taking-too-long
          command: << parameters.scan_command >>
          # If semgrep hangs, stop the scan after 20m, to prevent a useless 5h job
          no_output_timeout: 20m
      - notify-failures-on-develop

  bedrock-go-tests: # just a helper, that depends on all the actual test jobs
    docker:
      # Use a smaller nebula image to avoid pulling the huge ci-builder
      # image which is not needed for this job and sometimes misses
      # the cache.
      - image: cimg/nebula:2024.01
    resource_class: medium
    steps:
      - run: echo Done

  fpp-verify:
    circleci_ip_ranges: true
    docker:
      - image: cimg/go:1.21
    steps:
      - checkout
      - run:
          name: verify-sepolia
          command: |
            make verify-sepolia
          working_directory: op-program
      - notify-failures-on-develop:
          mentions: "@proofs-team"

  op-program-compat:
    docker:
      - image: <<pipeline.parameters.ci_builder_image>>
    steps:
      - checkout
      - restore_cache:
          name: Restore Go modules cache
          key: gomod-{{ checksum "go.sum" }}
      - restore_cache:
          key: golang-build-cache-op-program-compat-{{ checksum "go.sum" }}
      - run:
          name: compat-sepolia
          command: |
            make verify-compat
          working_directory: op-program
      - save_cache:
          name: Save Go build cache
          key: golang-build-cache-op-program-compat-{{ checksum "go.sum" }}
          paths:
            - "/root/.cache/go-build"

  check-generated-mocks-op-node:
    docker:
      - image: <<pipeline.parameters.ci_builder_image>>
    steps:
      - checkout
      - check-changed:
          patterns: op-node
      - run:
          name: check-generated-mocks
          command: make generate-mocks-op-node && git diff --exit-code

  check-generated-mocks-op-service:
    docker:
      - image: <<pipeline.parameters.ci_builder_image>>
    steps:
      - checkout
      - check-changed:
          patterns: op-service
      - run:
          name: check-generated-mocks
          command: make generate-mocks-op-service && git diff --exit-code

  kontrol-tests:
    docker:
      - image: << pipeline.parameters.ci_builder_image >>
    resource_class: xlarge
    steps:
      - checkout
      - install-contracts-dependencies
      - check-changed:
          no_go_deps: "true"
          patterns: contracts-bedrock/test/kontrol,contracts-bedrock/src/L1/OptimismPortal\.sol,contracts-bedrock/src/L1/OptimismPortal2\.sol,contracts-bedrock/src/L1/L1CrossDomainMessenger\.sol,contracts-bedrock/src/L1/L1ERC721Bridge\.sol,contracts-bedrock/src/L1/L1StandardBridge\.sol,contracts-bedrock/src/L1/ResourceMetering\.sol,contracts-bedrock/src/universal/StandardBridge\.sol,contracts-bedrock/src/universal/ERC721Bridge\.sol,contracts-bedrock/src/universal/CrossDomainMessenger\.sol
      - setup_remote_docker:
          docker_layer_caching: true
      - run:
          name: Run Kontrol Tests
          command: |
            curl -X POST \
              -H "Accept: application/vnd.github+json" \
              -H "Authorization: Bearer $RV_COMPUTE_TOKEN" \
              https://api.github.com/repos/runtimeverification/optimism-ci/actions/workflows/optimism-ci.yaml/dispatches \
              -d '{
                "ref": "master",
                "inputs": {
                  "branch_name": "<<pipeline.git.branch>>",
                  "extra_args": "script",
                  "statuses_sha": "<< pipeline.git.revision >>",
                  "org": "ethereum-optimism",
                  "repository": "optimism"
                }
              }'
          working_directory: ./packages/contracts-bedrock
      - notify-failures-on-develop

  publish-contract-artifacts:
    machine: true
    resource_class: ethereum-optimism/latitude-1
    steps:
      - gcp-cli/install
      - gcp-oidc-authenticate:
          gcp_cred_config_file_path: /tmp/gcp_cred_config.json
          oidc_token_file_path: /tmp/oidc_token.json
          project_id: GCP_TOOLS_ARTIFACTS_PROJECT_ID
          service_account_email: GCP_CONTRACTS_PUBLISHER_SERVICE_ACCOUNT_EMAIL
      - checkout
      - install-contracts-dependencies
      - run:
          name: Pull artifacts
          command: bash scripts/ops/pull-artifacts.sh
          working_directory: packages/contracts-bedrock
      - run:
          name: Build contracts
          environment:
            FOUNDRY_PROFILE: ci
          command: just forge-build
          working_directory: packages/contracts-bedrock
      - run:
          name: Publish artifacts
          command: bash scripts/ops/publish-artifacts.sh
          working_directory: packages/contracts-bedrock

  go-release:
    parameters:
      module:
        description: Go Module Name
        type: string
      filename:
        description: Goreleaser config file
        default: .goreleaser.yaml
        type: string
    docker:
      - image: <<pipeline.parameters.ci_builder_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: |
            goreleaser release --clean -f ./<<parameters.module>>/<<parameters.filename>>

  stale-check:
    docker:
      - image: cimg/python:3.11
    steps:
      - run:
          name: Run Stale Check Script
          command: |
            git clone --branch main --depth 1 https://github.com/ethereum-optimism/circleci-utils.git /tmp/circleci-utils
            cd /tmp/circleci-utils/stale-check
            pip3 install -r requirements.txt
            python3 stale-check.py --repo "ethereum-optimism/${CIRCLE_PROJECT_REPONAME}" --github-token "${STALE_GITHUB_TOKEN}"

workflows:
  main:
    when:
      and:
        - or:
            # Trigger on new commits
            - equal: [webhook, << pipeline.trigger_source >>]
              # Trigger on manual triggers if explicitly requested
            - equal: [true, << pipeline.parameters.main_dispatch >>]
        - not:
            equal: [scheduled_pipeline, << pipeline.trigger_source >>]
    jobs:
      - contracts-bedrock-build:
          name: contracts-bedrock-build
          # Build with just core + script contracts.
          build_args: --deny-warnings --skip test
      - check-kontrol-build:
          requires:
            - contracts-bedrock-build
      - contracts-bedrock-tests:
          # Test everything except PreimageOracle.t.sol since it's slow.
          name: contracts-bedrock-tests
          test_list: find test -name "*.t.sol" -not -name "PreimageOracle.t.sol"
      - contracts-bedrock-tests:
          # PreimageOracle test is slow, run it separately to unblock CI.
          name: contracts-bedrock-tests-preimage-oracle
          test_list: find test -name "PreimageOracle.t.sol"
      - contracts-bedrock-tests:
          # Heavily fuzz any fuzz tests within added or modified test files.
          name: contracts-bedrock-tests-heavy-fuzz-modified
          test_list: git diff origin/develop...HEAD --name-only --diff-filter=AM -- './test/**/*.t.sol' | sed 's|packages/contracts-bedrock/||'
          test_timeout: 1h
          test_profile: ciheavy
      - contracts-bedrock-tests:
          # Generate coverage reports.
          name: contracts-bedrock-coverage
          test_list: find test -name "*.t.sol"
          test_command: coverage
          test_flags: --report lcov
          test_timeout: 1h
          test_profile: cicoverage
          # need this requires to ensure that all FFI JSONs exist
          requires:
            - contracts-bedrock-build
      - contracts-bedrock-tests-upgrade:
          name: contracts-bedrock-tests-upgrade
      - contracts-bedrock-checks:
          requires:
            - contracts-bedrock-build
      - diff-asterisc-bytecode
      - semgrep-scan:
          name: semgrep-scan-local
          scan_command: semgrep scan --timeout=100 --config .semgrep/rules/ --error .
      - semgrep-scan:
          name: semgrep-test
          scan_command: semgrep scan --test --config .semgrep/rules/ .semgrep/tests/
      - go-lint
      - fuzz-golang:
          name: fuzz-golang-<<matrix.package_name>>
          on_changes: <<matrix.package_name>>
          matrix:
            parameters:
              package_name:
                - op-challenger
                - op-node
                - op-service
                - op-chain-ops
      - fuzz-golang:
          name: cannon-fuzz
          package_name: cannon
          on_changes: cannon,packages/contracts-bedrock/src/cannon
          uses_artifacts: true
          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: ["contracts-bedrock-build"]
      - go-tests:
          packages: |
            op-batcher
            op-chain-ops
            op-node
            op-proposer
            op-challenger
            op-dispute-mon
            op-conductor
            op-program
            op-service
            op-supervisor
            op-deployer
            op-e2e/system
            op-e2e/e2eutils
            op-e2e/opgeth
            op-e2e/interop
            op-e2e/actions
            op-e2e/faultproofs
            packages/contracts-bedrock/scripts/checks
          requires:
            - contracts-bedrock-build
            - cannon-prestate
      - op-program-compat
      - bedrock-go-tests:
          requires:
            - go-lint
            - cannon-build-test-vectors
            - cannon-go-lint-and-test-32-bit
            - cannon-go-lint-and-test-64-bit
            - check-generated-mocks-op-node
            - check-generated-mocks-op-service
            - op-program-compat
            # Not needed for the devnet but we want to make sure they build successfully
            - cannon-docker-build
            - op-dispute-mon-docker-build
            - op-program-docker-build
            - op-supervisor-docker-build
            - proofs-tools-docker-build
            - go-tests
      - docker-build:
          name: <<matrix.docker_name>>-docker-build
          docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
          save_image_tag: <<pipeline.git.revision>>
          matrix:
            parameters:
              docker_name:
                - op-node
                - op-batcher
                - op-program
                - op-proposer
                - op-challenger
                - proofs-tools
                - op-dispute-mon
                - op-conductor
                - da-server
                - op-supervisor
                - cannon
      - cannon-prestate
      - check-generated-mocks-op-node
      - check-generated-mocks-op-service
      - cannon-go-lint-and-test:
          name: cannon-go-lint-and-test-<<matrix.mips_word_size>>-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
          check_closed: false
      - shellcheck/check:
          name: shell-check
          # We don't need the `exclude` key as the orb detects the `.shellcheckrc`
          dir: .
          ignore-dirs: ./packages/contracts-bedrock/lib

  go-release-deployer:
    jobs:
      - go-release:
          filters:
            tags:
              only: /^op-deployer.*/
            branches:
              ignore: /.*/
          module: op-deployer
          context:
            - oplabs-gcr-release

  release:
    when:
      not:
        equal: [scheduled_pipeline, << pipeline.trigger_source >>]
    jobs:
      # Wait for approval on the release
      - hold:
          type: approval
          filters:
            tags:
              only: /^(da-server|ci-builder(-rust)?|proofs-tools|cannon|ufm-[a-z0-9\-]*|op-[a-z0-9\-]*)\/v.*/
            branches:
              ignore: /.*/
      # Standard (medium) cross-platform docker images go here
      - docker-build:
          matrix:
            parameters:
              docker_name:
                - op-node
                - op-batcher
                - op-proposer
                - op-challenger
                - op-dispute-mon
                - op-conductor
                - da-server
                - op-ufm
                - op-supervisor
                - op-deployer
                - cannon
          name: <<matrix.docker_name>>-docker-release
          docker_tags: <<pipeline.git.revision>>
          platforms: "linux/amd64,linux/arm64"
          publish: true
          release: true
          filters:
            tags:
              only: /^<<matrix.docker_name>>\/v.*/
            branches:
              ignore: /.*/
          context:
            - oplabs-gcr-release
          requires:
            - hold
      # Checks for cross-platform images go here
      - check-cross-platform:
          matrix:
            parameters:
              op_component:
                - op-node
                - op-batcher
                - op-proposer
                - op-challenger
                - op-dispute-mon
                - op-conductor
                - da-server
                - op-ufm
                - op-supervisor
                - op-deployer
                - cannon
          name: <<matrix.op_component>>-cross-platform
          requires:
            - op-node-docker-release
            - op-batcher-docker-release
            - op-proposer-docker-release
            - op-challenger-docker-release
            - op-dispute-mon-docker-release
            - op-conductor-docker-release
            - da-server-docker-release
            - op-ufm-docker-release
            - op-supervisor-docker-release
            - cannon-docker-release
      # Standard (xlarge) AMD-only docker images go here
      - docker-build:
          matrix:
            parameters:
              docker_name:
                - ci-builder
                - ci-builder-rust
                - proofs-tools
          name: <<matrix.docker_name>>-docker-release
          resource_class: xlarge
          docker_tags: <<pipeline.git.revision>>
          publish: true
          release: true
          filters:
            tags:
              only: /^<<matrix.docker_name>>\/v.*/
            branches:
              ignore: /.*/
          context:
            - oplabs-gcr-release
          requires:
            - hold
      - cannon-prestate:
          filters:
            tags:
              only: /^op-program\/v.*/
            branches:
              ignore: /.*/
      - publish-cannon-prestates:
          context:
            - slack
            - oplabs-network-optimism-io-bucket
          requires:
            - cannon-prestate
          filters:
            tags:
              only: /^op-program\/v.*/
            branches:
              ignore: /.*/

  scheduled-todo-issues:
    when:
      equal: [build_four_hours, <<pipeline.schedule.name>>]
    jobs:
      - todo-issues:
          name: todo-issue-checks
          context:
            - slack

  scheduled-fpp:
    when:
      equal: [build_hourly, <<pipeline.schedule.name>>]
    jobs:
      - fpp-verify:
          context:
            - slack
            - oplabs-fpp-nodes

  develop-publish-contract-artifacts:
    when:
      or:
        - equal: ["develop", <<pipeline.git.branch>>]
        - equal:
            [true, <<pipeline.parameters.publish_contract_artifacts_dispatch>>]
    jobs:
      - publish-contract-artifacts

  develop-fault-proofs:
    when:
      and:
        - or:
            - equal: ["develop", <<pipeline.git.branch>>]
            - equal: [true, <<pipeline.parameters.fault_proofs_dispatch>>]
        - not:
            equal: [scheduled_pipeline, << pipeline.trigger_source >>]
    jobs:
      - cannon-prestate
      - cannon-stf-verify:
          context:
            - slack
      - contracts-bedrock-build:
          build_args: --deny-warnings --skip test
          context:
            - slack
      - go-tests:
          name: op-e2e-cannon-tests
          notify: true
          mentions: "@proofs-team"
          no_output_timeout: 60m
          test_timeout: 59m
          resource_class: ethereum-optimism/latitude-fps-1
          environment_overrides: |
            export OP_E2E_CANNON_ENABLED="true"
          packages: |
            op-e2e/faultproofs
          context:
            - slack
          requires:
            - contracts-bedrock-build
            - cannon-prestate
      - publish-cannon-prestates:
          context:
            - slack
            - oplabs-network-optimism-io-bucket
          requires:
            - cannon-prestate
            - op-e2e-cannon-tests
          filters:
            branches:
              only:
                - develop

  develop-kontrol-tests:
    when:
      and:
        - or:
            - equal: ["develop", <<pipeline.git.branch>>]
            - equal: [true, <<pipeline.parameters.kontrol_dispatch>>]
        - not:
            equal: [scheduled_pipeline, << pipeline.trigger_source >>]
    jobs:
      - kontrol-tests:
          context:
            - slack
            - runtimeverification

  scheduled-cannon-full-tests:
    when:
      or:
        - equal: [build_four_hours, <<pipeline.schedule.name>>]
        - equal: [true, << pipeline.parameters.cannon_full_test_dispatch >>]
    jobs:
      - contracts-bedrock-build:
          build_args: --deny-warnings --skip test
      - cannon-go-lint-and-test:
          name: cannon-go-lint-and-test-<<matrix.mips_word_size>>-bit
          requires:
            - contracts-bedrock-build
          skip_slow_tests: false
          notify: true
          context:
            - slack
          matrix:
            parameters:
              mips_word_size: [32, 64]

  scheduled-docker-publish:
    when:
      or:
        - equal: [build_hourly, <<pipeline.schedule.name>>]
        # Trigger on manual triggers if explicitly requested
        - equal: [true, << pipeline.parameters.docker_publish_dispatch >>]
    jobs:
      - docker-build:
          matrix:
            parameters:
              docker_name:
                - op-node
                - op-batcher
                - op-program
                - op-proposer
                - op-challenger
                - op-dispute-mon
                - op-conductor
                - op-supervisor
                - cannon
          name: <<matrix.docker_name>>-docker-publish
          docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
          platforms: "linux/amd64,linux/arm64"
          publish: true
          context:
            - oplabs-gcr
            - slack
      - check-cross-platform:
          matrix:
            parameters:
              op_component:
                - op-node
                - op-batcher
                - op-program
                - op-proposer
                - op-challenger
                - op-dispute-mon
                - op-conductor
                - op-supervisor
                - cannon
          name: <<matrix.op_component>>-cross-platform
          requires:
            - <<matrix.op_component>>-docker-publish

  scheduled-preimage-reproducibility:
    when:
      or:
        - equal: [build_daily, <<pipeline.schedule.name>>]
        # Trigger on manual triggers if explicitly requested
        - equal: [true, << pipeline.parameters.reproducibility_dispatch >>]
    jobs:
      - preimage-reproducibility:
          context: slack

  scheduled-stale-check:
    when:
      or:
        - equal: [build_daily, <<pipeline.schedule.name>>]
          # Trigger on manual triggers if explicitly requested
        - equal: [true, << pipeline.parameters.stale_check_dispatch >>]
    jobs:
      - stale-check:
          context: github-token-stale-check
