Full Code of base/node for AI

main f14551c15cb8 cached
28 files
73.0 KB
23.3k tokens
27 symbols
2 requests
Download .txt
Repository: base/node
Branch: main
Commit: f14551c15cb8
Files: 28
Total size: 73.0 KB

Directory structure:
gitextract_5b8jeo_f/

├── .dockerignore
├── .github/
│   └── workflows/
│       ├── docker.yml
│       ├── pr.yml
│       ├── stale.yml
│       └── update-dependencies.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── dependency_updater/
│   ├── dependency_updater.go
│   ├── go.mod
│   ├── go.sum
│   ├── version.go
│   └── version_test.go
├── docker-compose.yml
├── geth/
│   ├── Dockerfile
│   └── geth-entrypoint
├── go.mod
├── nethermind/
│   ├── Dockerfile
│   └── nethermind-entrypoint
├── op-node-entrypoint
├── reth/
│   ├── Dockerfile
│   ├── README.md
│   └── reth-entrypoint
├── supervisord.conf
├── versions.env
└── versions.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .dockerignore
================================================
geth-data/
reth-data/
nethermind-data/


================================================
FILE: .github/workflows/docker.yml
================================================
name: Tag Docker image

on:
  push:
    branches:
      - "main"
    tags:
      - "v*"
  workflow_dispatch: {}

env:
  REGISTRY: ghcr.io
  NAMESPACE: ghcr.io/base
  GETH_DEPRECATED_IMAGE_NAME: node
  GETH_IMAGE_NAME: node-geth
  RETH_IMAGE_NAME: node-reth
  NETHERMIND_IMAGE_NAME: node-nethermind

permissions:
  contents: read
  packages: write

jobs:
  geth:
    strategy:
      matrix:
        settings:
          - arch: linux/amd64
            runs-on: ubuntu-24.04
          - arch: linux/arm64
            runs-on: ubuntu-24.04-arm
    runs-on: ${{ matrix.settings.runs-on }}
    steps:
      - name: Harden the runner (Audit all outbound calls)
        uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
        with:
          egress-policy: audit

      - name: Checkout
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0

      - name: Log into the Container registry
        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata for the Docker image
        id: meta
        uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175 # v4.6.0
        with:
          images: |
            ${{ env.NAMESPACE }}/${{ env.GETH_DEPRECATED_IMAGE_NAME }}
            ${{ env.NAMESPACE }}/${{ env.GETH_IMAGE_NAME }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1

      - name: Build and push the Docker image
        id: build
        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
        with:
          context: .
          file: geth/Dockerfile
          tags: ${{ env.NAMESPACE }}/${{ env.GETH_DEPRECATED_IMAGE_NAME }},${{ env.NAMESPACE }}/${{ env.GETH_IMAGE_NAME }}
          labels: ${{ steps.meta.outputs.labels }}
          platforms: ${{ matrix.settings.arch }}
          outputs: type=image,push-by-digest=true,name-canonical=true,push=true

      - name: Export digest
        run: |
          mkdir -p ${{ runner.temp }}/digests
          digest="${{ steps.build.outputs.digest }}"
          touch "${{ runner.temp }}/digests/${digest#sha256:}"

      - name: Prepare
        run: |
          platform=${{ matrix.settings.arch }}
          echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV

      - name: Upload digest
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: digests-geth-${{ env.PLATFORM_PAIR }}
          path: ${{ runner.temp }}/digests/*
          if-no-files-found: error
          retention-days: 1
  reth:
    strategy:
      matrix:
        settings:
          - arch: linux/amd64
            runs-on: ubuntu-24.04
            features: jemalloc,asm-keccak,optimism
          - arch: linux/arm64
            runs-on: ubuntu-24.04-arm
            features: jemalloc,optimism
    runs-on: ${{ matrix.settings.runs-on }}
    steps:
      - name: Harden the runner (Audit all outbound calls)
        uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
        with:
          egress-policy: audit

      - name: Checkout
        uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0

      - name: Log into the Container registry
        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata for the Docker image
        id: meta
        uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175 # v4.6.0
        with:
          images: |
            ${{ env.NAMESPACE }}/${{ env.RETH_IMAGE_NAME }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1

      - name: Build and push the Docker image
        id: build
        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
        with:
          context: .
          file: reth/Dockerfile
          tags: ${{ env.NAMESPACE }}/${{ env.RETH_IMAGE_NAME }}
          labels: ${{ steps.meta.outputs.labels }}
          build-args: |
            FEATURES=${{ matrix.settings.features }}
          platforms: ${{ matrix.settings.arch }}
          outputs: type=image,push-by-digest=true,name-canonical=true,push=true

      - name: Export digest
        run: |
          mkdir -p ${{ runner.temp }}/digests
          digest="${{ steps.build.outputs.digest }}"
          touch "${{ runner.temp }}/digests/${digest#sha256:}"

      - name: Prepare
        run: |
          platform=${{ matrix.settings.arch }}
          echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV

      - name: Upload digest
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: digests-reth-${{ env.PLATFORM_PAIR }}
          path: ${{ runner.temp }}/digests/*
          if-no-files-found: error
          retention-days: 1

  nethermind:
    strategy:
      matrix:
        settings:
          - arch: linux/amd64
            runs-on: ubuntu-24.04
          - arch: linux/arm64
            runs-on: ubuntu-24.04-arm
    runs-on: ${{ matrix.settings.runs-on }}
    steps:
      - name: Harden the runner (Audit all outbound calls)
        uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
        with:
          egress-policy: audit

      - name: Checkout
        uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0

      - name: Log into the Container registry
        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1

      - name: Extract metadata for the Docker image
        id: meta
        uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175 # v4.6.0
        with:
          images: |
            ${{ env.NAMESPACE }}/${{ env.NETHERMIND_IMAGE_NAME }}

      - name: Build and push the Docker image
        id: build
        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
        with:
          context: .
          file: nethermind/Dockerfile
          tags: ${{ env.NAMESPACE }}/${{ env.NETHERMIND_IMAGE_NAME }}
          labels: ${{ steps.meta.outputs.labels }}
          platforms: ${{ matrix.settings.arch }}
          outputs: type=image,push-by-digest=true,name-canonical=true,push=true

      - name: Export digest
        run: |
          mkdir -p ${{ runner.temp }}/digests
          digest="${{ steps.build.outputs.digest }}"
          touch "${{ runner.temp }}/digests/${digest#sha256:}"

      - name: Prepare
        run: |
          platform=${{ matrix.settings.arch }}
          echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV

      - name: Upload digest
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
        with:
          name: digests-nethermind-${{ env.PLATFORM_PAIR }}
          path: ${{ runner.temp }}/digests/*
          if-no-files-found: error
          retention-days: 1

  merge-geth:
    runs-on: ubuntu-latest
    needs:
      - geth
    steps:
      - name: Harden the runner (Audit all outbound calls)
        uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
        with:
          egress-policy: audit

      - name: Download digests
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
        with:
          path: ${{ runner.temp }}/digests
          pattern: digests-geth-*
          merge-multiple: true

      - name: Log into the Container registry
        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1

      - name: Extract metadata for the Docker image
        id: meta
        uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
        with:
          images: |
            ${{ env.NAMESPACE }}/${{ env.GETH_DEPRECATED_IMAGE_NAME }}
            ${{ env.NAMESPACE }}/${{ env.GETH_IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=tag
            type=sha,format=long

      - name: Create manifest list and push
        working-directory: ${{ runner.temp }}/digests
        run: |
          docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
            $(printf '${{ env.NAMESPACE }}/${{ env.GETH_DEPRECATED_IMAGE_NAME }}@sha256:%s ' *)
          docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
            $(printf '${{ env.NAMESPACE }}/${{ env.GETH_IMAGE_NAME }}@sha256:%s ' *)

      - name: Inspect image
        run: |
          docker buildx imagetools inspect ${{ env.NAMESPACE }}/${{ env.GETH_DEPRECATED_IMAGE_NAME }}:${{ steps.meta.outputs.version }}
          docker buildx imagetools inspect ${{ env.NAMESPACE }}/${{ env.GETH_IMAGE_NAME }}:${{ steps.meta.outputs.version }}

  merge-reth:
    runs-on: ubuntu-latest
    needs:
      - reth
    steps:
      - name: Harden the runner (Audit all outbound calls)
        uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
        with:
          egress-policy: audit

      - name: Download digests
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
        with:
          path: ${{ runner.temp }}/digests
          pattern: digests-reth-*
          merge-multiple: true

      - name: Log into the Container registry
        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1

      - name: Extract metadata for the Docker image
        id: meta
        uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
        with:
          images: |
            ${{ env.NAMESPACE }}/${{ env.RETH_IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=tag
            type=sha,format=long

      - name: Create manifest list and push
        working-directory: ${{ runner.temp }}/digests
        run: |
          docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
            $(printf '${{ env.NAMESPACE }}/${{ env.RETH_IMAGE_NAME }}@sha256:%s ' *)

      - name: Inspect image
        run: |
          docker buildx imagetools inspect ${{ env.NAMESPACE }}/${{ env.RETH_IMAGE_NAME }}:${{ steps.meta.outputs.version }}

  merge-nethermind:
    runs-on: ubuntu-latest
    needs:
      - nethermind
    steps:
      - name: Harden the runner (Audit all outbound calls)
        uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
        with:
          egress-policy: audit

      - name: Download digests
        uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
        with:
          path: ${{ runner.temp }}/digests
          pattern: digests-nethermind-*
          merge-multiple: true

      - name: Log into the Container registry
        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1

      - name: Extract metadata for the Docker image
        id: meta
        uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0
        with:
          images: |
            ${{ env.NAMESPACE }}/${{ env.NETHERMIND_IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=tag
            type=sha,format=long

      - name: Create manifest list and push
        working-directory: ${{ runner.temp }}/digests
        run: |
          docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
            $(printf '${{ env.NAMESPACE }}/${{ env.NETHERMIND_IMAGE_NAME }}@sha256:%s ' *)

      - name: Inspect image
        run: |
          docker buildx imagetools inspect ${{ env.NAMESPACE }}/${{ env.NETHERMIND_IMAGE_NAME }}:${{ steps.meta.outputs.version }}


================================================
FILE: .github/workflows/pr.yml
================================================
name: Pull Request

on:
  pull_request:
  workflow_dispatch:

permissions:
  contents: read

jobs:
  geth:
    strategy:
      matrix:
        settings:
          - arch: linux/amd64
            runs-on: ubuntu-24.04
          - arch: linux/arm64
            runs-on: ubuntu-24.04-arm
    runs-on: ${{ matrix.settings.runs-on }}
    steps:
      - name: Harden the runner (Audit all outbound calls)
        uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
        with:
          egress-policy: audit

      - name: Checkout
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
        with:
          ref: ${{ github.event.pull_request.head.sha }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1

      - name: Build the Docker image
        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
        with:
          context: .
          file: geth/Dockerfile
          push: false
          platforms: ${{ matrix.settings.arch }}

  reth:
    strategy:
      matrix:
        settings:
          - arch: linux/amd64
            runs-on: ubuntu-24.04
            features: jemalloc,asm-keccak,optimism
          - arch: linux/arm64
            runs-on: ubuntu-24.04-arm
            features: jemalloc,optimism
    runs-on: ${{ matrix.settings.runs-on}}
    steps:
      - name: Harden the runner (Audit all outbound calls)
        uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
        with:
          egress-policy: audit

      - name: Checkout
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
        with:
          ref: ${{ github.event.pull_request.head.sha }}
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
      - name: Build the Docker image
        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
        with:
          context: .
          file: reth/Dockerfile
          push: false
          build-args: |
            FEATURES=${{ matrix.settings.features }}
          platforms: ${{ matrix.settings.arch }}

  nethermind:
    strategy:
      matrix:
        settings:
          - arch: linux/amd64
            runs-on: ubuntu-24.04
          - arch: linux/arm64
            runs-on: ubuntu-24.04-arm
    runs-on: ${{ matrix.settings.runs-on}}
    steps:
      - name: Harden the runner (Audit all outbound calls)
        uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1
        with:
          egress-policy: audit

      - name: Checkout
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
        with:
          ref: ${{ github.event.pull_request.head.sha }}
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
      - name: Build the Docker image
        uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
        with:
          context: .
          file: nethermind/Dockerfile
          push: false
          platforms: ${{ matrix.settings.arch }}


================================================
FILE: .github/workflows/stale.yml
================================================
name: Mark stale issues and PRs

on:
  schedule:
    - cron: '30 0 * * *'
  workflow_dispatch:
permissions:
  contents: read

jobs:
  stale:
    runs-on: ubuntu-latest
    permissions:
      actions: write
      issues: write
      pull-requests: write
    steps:
      - name: Harden the runner (Audit all outbound calls)
        uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
        with:
          egress-policy: audit

      - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
        with:
          days-before-stale: 14
          days-before-close: 5
          stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
          stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
          close-issue-message: 'This issue was closed because it has been inactive for 5 days since being marked as stale.'
          close-pr-message: 'This pull request was closed because it has been inactive for 5 days since being marked as stale.'

================================================
FILE: .github/workflows/update-dependencies.yml
================================================
name: Update Dockerfile Dependencies
on:
  schedule:
    - cron: '0 13 * * *'
  workflow_dispatch:

permissions:
  contents: write
  pull-requests: write

jobs:
  update:
    name: update
    runs-on: ubuntu-latest
    steps:
      - name: Harden the runner (Audit all outbound calls)
        uses: step-security/harden-runner@6c439dc8bdf85cadbbce9ed30d1c7b959517bc49 # v2.12.2
        with:
          egress-policy: audit

      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

      - name: build dependency updater
        run: cd dependency_updater && go build

      - name: run dependency updater
        id: run_dependency_updater
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: cd dependency_updater && ./dependency_updater --repo ../ --github-action true

      - name: create pull request
        if: ${{ steps.run_dependency_updater.outputs.TITLE != '' }}
        uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
        with:
          title: ${{ steps.run_dependency_updater.outputs.TITLE }}
          commit-message: ${{ steps.run_dependency_updater.outputs.TITLE }}
          body: "${{ steps.run_dependency_updater.outputs.DESC }}"
          branch: run-dependency-updater
          delete-branch: true

================================================
FILE: .gitignore
================================================
/.idea/
/geth-data/
/reth-data/
/nethermind-data/
/dependency_updater/dependency_updater
.DS_Store

================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Base Node

## Code of Conduct

All interactions with this project follow our [Code of Conduct][code-of-conduct].
By participating, you are expected to honor this code. Violators can be banned
from further participation in this project, or potentially all Base and/or
Coinbase
projects.

[code-of-conduct]: https://github.com/coinbase/code-of-conduct

## Bug Reports

* Ensure your issue [has not already been reported][1]. It may already be fixed!
* Include the steps you carried out to produce the problem.
* Include the behavior you observed along with the behavior you expected, and
  why you expected it.
* Include any relevant stack traces or debugging output.

## Feature Requests

We welcome feedback with or without pull requests. If you have an idea for how
to improve the project, great! All we ask is that you take the time to write a
clear and concise explanation of what need you are trying to solve. If you have
thoughts on _how_ it can be solved, include those too!

The best way to see a feature added, however, is to submit a pull request.

## Pull Requests

* Before creating your pull request, it's usually worth asking if the code
  you're planning on writing will actually be considered for merging. You can
  do this by [opening an issue][1] and asking. It may also help give the
  maintainers context for when the time comes to review your code.

* Ensure your [commit messages are well-written][2]. This can double as your
  pull request message, so it pays to take the time to write a clear message.

* Add tests for your feature. You should be able to look at other tests for
  examples. If you're unsure, don't hesitate to [open an issue][1] and ask!

* Submit your pull request!

## Support Requests

For security reasons, any communication referencing support tickets for Coinbase
products will be ignored. The request will have its content redacted and will
be locked to prevent further discussion.

All support requests must be made via [our support team][3].

[1]: https://github.com/base/node/issues
[2]: https://medium.com/brigade-engineering/the-secrets-to-great-commit-messages-106fc0a92a25
[3]: https://support.coinbase.com/customer/en/portal/articles/2288496-how-can-i-contact-coinbase-support-



================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2023-2025 base.org contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
![Base](logo.webp)

# Base Node

Base is a secure, low-cost, developer-friendly Ethereum L2 built on Optimism's [OP Stack](https://docs.optimism.io/). This repository contains Docker builds to run your own node on the Base network.

[![Website base.org](https://img.shields.io/website-up-down-green-red/https/base.org.svg)](https://base.org)
[![Docs](https://img.shields.io/badge/docs-up-green)](https://docs.base.org/)
[![Discord](https://img.shields.io/discord/1067165013397213286?label=discord)](https://base.org/discord)
[![Twitter Base](https://img.shields.io/twitter/follow/Base?style=social)](https://x.com/Base)
[![Farcaster Base](https://img.shields.io/badge/Farcaster_Base-3d8fcc)](https://farcaster.xyz/base)

## Quick Start

1. Ensure you have an Ethereum L1 full node RPC available
2. Choose your network:
   - For mainnet: Use `.env.mainnet`
   - For testnet: Use `.env.sepolia`
3. Configure your L1 endpoints in the appropriate `.env` file:
   ```bash
   OP_NODE_L1_ETH_RPC=<your-preferred-l1-rpc>
   OP_NODE_L1_BEACON=<your-preferred-l1-beacon>
   OP_NODE_L1_BEACON_ARCHIVER=<your-preferred-l1-beacon-archiver>
   ```
4. Start the node:

   ```bash
   # For mainnet (default):
   docker compose up --build

   # For testnet:
   NETWORK_ENV=.env.sepolia docker compose up --build

   # To use a specific client (optional):
   CLIENT=reth docker compose up --build

   # For testnet with a specific client:
   NETWORK_ENV=.env.sepolia CLIENT=reth docker compose up --build
   ```

### Supported Clients

- `reth` (default)
- `geth`
- `nethermind`

## Requirements

### Minimum Requirements

- Modern Multicore CPU
- 32GB RAM (64GB Recommended)
- NVMe SSD drive
- Storage: (2 \* [current chain size](https://base.org/stats) + [snapshot size](https://basechaindata.vercel.app) + 20% buffer) (to accommodate future growth)
- Docker and Docker Compose

### Production Hardware Specifications

The following are the hardware specifications we use in production:

#### Reth Archive Node (recommended)

- **Instance**: AWS i7i.12xlarge
- **Storage**: RAID 0 of all local NVMe drives (`/dev/nvme*`)
- **Filesystem**: ext4

#### Geth Full Node

- **Instance**: AWS i7i.12xlarge
- **Storage**: RAID 0 of all local NVMe drives (`/dev/nvme*`)
- **Filesystem**: ext4

> [!NOTE]
To run the node using a supported client, you can use the following command:
`CLIENT=supported_client docker compose up --build`
 
Supported clients:
 - reth (runs vanilla node by default, Flashblocks mode enabled by providing RETH_FB_WEBSOCKET_URL, see [Reth Node README](./reth/README.md))
 - geth
 - nethermind

## Configuration

### Required Settings

- L1 Configuration:
  - `OP_NODE_L1_ETH_RPC`: Your Ethereum L1 node RPC endpoint
  - `OP_NODE_L1_BEACON`: Your L1 beacon node endpoint
  - `OP_NODE_L1_BEACON_ARCHIVER`: Your L1 beacon archiver endpoint
  - `OP_NODE_L1_RPC_KIND`: The type of RPC provider being used (default: "debug_geth"). Supported values:
    - `alchemy`: Alchemy RPC provider
    - `quicknode`: QuickNode RPC provider
    - `infura`: Infura RPC provider
    - `parity`: Parity RPC provider
    - `nethermind`: Nethermind RPC provider
    - `debug_geth`: Debug Geth RPC provider
    - `erigon`: Erigon RPC provider
    - `basic`: Basic RPC provider (standard receipt fetching only)
    - `any`: Any available RPC method
    - `standard`: Standard RPC methods including newer optimized methods

### Network Settings

- Mainnet:
  - `RETH_CHAIN=base`
  - `OP_NODE_NETWORK=base-mainnet`
  - Sequencer: `https://mainnet-sequencer.base.org`

### Performance Settings

- Cache Settings:
  - `GETH_CACHE="20480"` (20GB)
  - `GETH_CACHE_DATABASE="20"` (4GB)
  - `GETH_CACHE_GC="12"`
  - `GETH_CACHE_SNAPSHOT="24"`
  - `GETH_CACHE_TRIE="44"`

### Optional Features

- EthStats Monitoring (uncomment to enable)
- Trusted RPC Mode (uncomment to enable)
- Snap Sync (experimental)

For full configuration options, see the `.env.mainnet` file.

## Snapshots

Snapshots are available to help you sync your node more quickly. See [docs.base.org](https://docs.base.org/chain/run-a-base-node#snapshots) for links and more details on how to restore from a snapshot.

## Supported Networks

| Network | Status |
| ------- | ------ |
| Mainnet | ✅     |
| Testnet | ✅     |

## Troubleshooting

For support please join our [Discord](https://discord.gg/buildonbase) post in `🛠|node-operators`. You can alternatively open a new GitHub issue.

## Disclaimer

THE NODE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. We make no guarantees about asset protection or security. Usage is subject to applicable laws and regulations.

For more information, visit [docs.base.org](https://docs.base.org/).


================================================
FILE: SECURITY.md
================================================
# Security

## Bug bounty program

In line with our strategy of being the safest way for users to access crypto:

+ Coinbase will be extending our [best-in-industry][1] million-dollar [HackerOne bug bounty program][2]
to cover the Base network, the Base bridge contracts, and Base infrastructure.

+ Coinbase will be working in tandem with OP Labs to harden the security
guarantees of Bedrock and accelerate the timeline for decentralized
fault-proofs on the [OP Stack][3].

+ Coinbase's bug bounty program will run alongside Optimism's existing [Immunefi Bedrock bounty program][4]
to support the open source [Bedrock][5] OP Stack framework.

## Reporting vulnerabilities

All potential vulnerability reports can be submitted via the [HackerOne][6]
platform.

The HackerOne platform allows us to have a centralized and single reporting
source for us to deliver optimized SLA's and results. All reports submitted to
the platform are triaged around the clock by our team of Coinbase engineers
with domain knowledge, ensuring the best quality of review.

For more information on reporting vulnerabilities and our HackerOne bug bounty
program, view our [security program policies][7].

[1]: https://www.coinbase.com/blog/celebrating-10-years-of-our-bug-bounty-program
[2]: https://hackerone.com/coinbase?type=team 
[3]: https://docs.optimism.io/
[4]: https://immunefi.com/bounty/optimism/
[5]: https://docs.optimism.io/docs/releases/bedrock/
[6]: https://hackerone.com/coinbase
[7]: https://hackerone.com/coinbase?view_policy=true




================================================
FILE: dependency_updater/dependency_updater.go
================================================
package main

import (
	"context"
	"encoding/json"
	"fmt"
	"slices"
	"time"

	"github.com/ethereum-optimism/optimism/op-service/retry"
	"github.com/google/go-github/v72/github"
	"github.com/urfave/cli/v3"

	"log"
	"os"
	"os/exec"
	"strings"
)

type Info struct {
	Tag       string `json:"tag,omitempty"`
	Commit    string `json:"commit"`
	TagPrefix string `json:"tagPrefix,omitempty"`
	Owner     string `json:"owner"`
	Repo      string `json:"repo"`
	Branch    string `json:"branch,omitempty"`
	Tracking  string `json:"tracking"`
}

type VersionUpdateInfo struct {
	Repo    string
	From    string
	To      string
	DiffUrl string
}

type Dependencies = map[string]*Info

func main() {
	cmd := &cli.Command{
		Name:  "updater",
		Usage: "Updates the dependencies in the geth, nethermind and reth Dockerfiles",
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:     "token",
				Usage:    "Auth token used to make requests to the Github API must be set using export",
				Sources:  cli.EnvVars("GITHUB_TOKEN"),
				Required: true,
			},
			&cli.StringFlag{
				Name:     "repo",
				Usage:    "Specifies repo location to run the version updater on",
				Required: true,
			},
			&cli.BoolFlag{
				Name:     "commit",
				Usage:    "Stages updater changes and creates commit message",
				Required: false,
			},
			&cli.BoolFlag{
				Name:     "github-action",
				Usage:    "Specifies whether tool is being used through github action workflow",
				Required: false,
			},
		},
		Action: func(ctx context.Context, cmd *cli.Command) error {
			err := updater(cmd.String("token"), cmd.String("repo"), cmd.Bool("commit"), cmd.Bool("github-action"))
			if err != nil {
				return fmt.Errorf("failed to run updater: %s", err)
			}
			return nil
		},
	}

	if err := cmd.Run(context.Background(), os.Args); err != nil {
		log.Fatal(err)
	}
}

func updater(token string, repoPath string, commit bool, githubAction bool) error {
	var err error
	var dependencies Dependencies
	var updatedDependencies []VersionUpdateInfo

	f, err := os.ReadFile(repoPath + "/versions.json")
	if err != nil {
		return fmt.Errorf("error reading versions JSON: %s", err)
	}

	client := github.NewClient(nil).WithAuthToken(token)
	ctx := context.Background()

	err = json.Unmarshal(f, &dependencies)
	if err != nil {
		return fmt.Errorf("error unmarshalling versions JSON to dependencies: %s", err)
	}

	for dependency := range dependencies {
		var updatedDependency VersionUpdateInfo
		err := retry.Do0(context.Background(), 3, retry.Fixed(1*time.Second), func() error {
			updatedDependency, err = getAndUpdateDependency(
				ctx,
				client,
				dependency,
				repoPath,
				dependencies,
			)
			return err
		})
		if err != nil {
			return fmt.Errorf("error getting and updating version/commit for "+dependency+": %s", err)
		}

		if updatedDependency != (VersionUpdateInfo{}) {
			updatedDependencies = append(updatedDependencies, updatedDependency)
		}
	}

	e := createVersionsEnv(repoPath, dependencies)
	if e != nil {
		return fmt.Errorf("error creating versions.env: %s", e)
	}

	if (commit && updatedDependencies != nil) || (githubAction && updatedDependencies != nil) {
		err := createCommitMessage(updatedDependencies, repoPath, githubAction)
		if err != nil {
			return fmt.Errorf("error creating commit message: %s", err)
		}
	}

	return nil
}

func createCommitMessage(updatedDependencies []VersionUpdateInfo, repoPath string, githubAction bool) error {
	var repos []string
	descriptionLines := []string{
		"### Dependency Updates",
	}

	commitTitle := "chore: updated "

	for _, dependency := range updatedDependencies {
		repo, tag := dependency.Repo, dependency.To
		descriptionLines = append(descriptionLines, fmt.Sprintf("**%s** - %s:  [diff](%s)", repo, tag, dependency.DiffUrl))
		repos = append(repos, repo)
	}
	commitDescription := strings.Join(descriptionLines, "\n")
	commitTitle += strings.Join(repos, ", ")

	if githubAction {
		err := writeToGithubOutput(commitTitle, commitDescription, repoPath)
		if err != nil {
			return fmt.Errorf("error creating git commit message: %s", err)
		}
	} else {
		cmd := exec.Command("git", "commit", "-am", commitTitle, "-m", commitDescription)
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("failed to run git commit -m: %s", err)
		}
	}
	return nil
}

func getAndUpdateDependency(ctx context.Context, client *github.Client, dependencyType string, repoPath string, dependencies Dependencies) (VersionUpdateInfo, error) {
	version, commit, updatedDependency, err := getVersionAndCommit(ctx, client, dependencies, dependencyType)
	if err != nil {
		return VersionUpdateInfo{}, err
	}
	if updatedDependency != (VersionUpdateInfo{}) {
		e := updateVersionTagAndCommit(commit, version, dependencyType, repoPath, dependencies)
		if e != nil {
			return VersionUpdateInfo{}, fmt.Errorf("error updating version tag and commit: %s", e)
		}
	}

	return updatedDependency, nil
}

func getVersionAndCommit(ctx context.Context, client *github.Client, dependencies Dependencies, dependencyType string) (string, string, VersionUpdateInfo, error) {
	var selectedTag *github.RepositoryTag
	var commit string
	var diffUrl string
	var updatedDependency VersionUpdateInfo
	options := &github.ListOptions{Page: 1}
	currentTag := dependencies[dependencyType].Tag
	tagPrefix := dependencies[dependencyType].TagPrefix

	if dependencies[dependencyType].Tracking == "tag" || dependencies[dependencyType].Tracking == "release" {
		// Collect all valid tags across all pages, then find the max version
		var validTags []*github.RepositoryTag
		trackingMode := dependencies[dependencyType].Tracking

		for {
			tags, resp, err := client.Repositories.ListTags(
				ctx,
				dependencies[dependencyType].Owner,
				dependencies[dependencyType].Repo,
				options)

			if err != nil {
				return "", "", VersionUpdateInfo{}, fmt.Errorf("error getting tags: %s", err)
			}

			for _, tag := range tags {
				// Skip if tagPrefix is set and doesn't match
				if tagPrefix != "" && !strings.HasPrefix(*tag.Name, tagPrefix) {
					continue
				}

				// Filter based on tracking mode:
				// - "release": only stable releases (no prerelease suffix)
				// - "tag": releases and RC versions only (exclude -synctest, -alpha, etc.)
				if trackingMode == "release" {
					if !IsReleaseVersion(*tag.Name, tagPrefix) {
						continue
					}
				} else if trackingMode == "tag" {
					if !IsReleaseOrRCVersion(*tag.Name, tagPrefix) {
						continue
					}
				}

				// Check if this is a valid upgrade (not a downgrade)
				if err := ValidateVersionUpgrade(currentTag, *tag.Name, tagPrefix); err != nil {
					continue
				}

				validTags = append(validTags, tag)
			}

			if resp.NextPage == 0 {
				break
			}
			options.Page = resp.NextPage
		}

		// Find the maximum version among valid tags
		for _, tag := range validTags {
			// Skip if this tag can't be parsed
			if _, err := ParseVersion(*tag.Name, tagPrefix); err != nil {
				log.Printf("Skipping unparseable tag %s: %v", *tag.Name, err)
				continue
			}

			if selectedTag == nil {
				selectedTag = tag
				continue
			}

			cmp, err := CompareVersions(*tag.Name, *selectedTag.Name, tagPrefix)
			if err != nil {
				log.Printf("Error comparing versions %s and %s: %v", *tag.Name, *selectedTag.Name, err)
				continue
			}
			if cmp > 0 {
				selectedTag = tag
			}
		}

		// If no valid version found, keep current version
		if selectedTag == nil {
			log.Printf("No valid upgrade found for %s, keeping %s", dependencyType, currentTag)
			return currentTag, dependencies[dependencyType].Commit, VersionUpdateInfo{}, nil
		}

		if *selectedTag.Name != currentTag {
			diffUrl = generateGithubRepoUrl(dependencies, dependencyType) + "/compare/" +
				currentTag + "..." + *selectedTag.Name
		}

		// Get commit SHA from the tag
		commit = *selectedTag.Commit.SHA
	}

	if diffUrl != "" {
		updatedDependency = VersionUpdateInfo{
			dependencies[dependencyType].Repo,
			dependencies[dependencyType].Tag,
			*selectedTag.Name,
			diffUrl,
		}
	}

	if dependencies[dependencyType].Tracking == "branch" {
		branchCommit, _, err := client.Repositories.ListCommits(
			ctx,
			dependencies[dependencyType].Owner,
			dependencies[dependencyType].Repo,
			&github.CommitsListOptions{
				SHA: dependencies[dependencyType].Branch,
			},
		)
		if err != nil {
			return "", "", VersionUpdateInfo{}, fmt.Errorf("error listing commits for "+dependencyType+": %s", err)
		}
		commit = *branchCommit[0].SHA
		if dependencies[dependencyType].Commit != commit {
			from, to := dependencies[dependencyType].Commit, commit
			diffUrl = fmt.Sprintf("%s/compare/%s...%s", generateGithubRepoUrl(dependencies, dependencyType), from, to)
			updatedDependency = VersionUpdateInfo{
				dependencies[dependencyType].Repo,
				dependencies[dependencyType].Tag,
				commit,
				diffUrl,
			}
		}
	}

	if selectedTag != nil {
		return *selectedTag.Name, commit, updatedDependency, nil
	}

	return "", commit, updatedDependency, nil
}

func updateVersionTagAndCommit(
	commit string,
	tag string,
	dependencyType string,
	repoPath string,
	dependencies Dependencies) error {
	dependencies[dependencyType].Tag = tag
	dependencies[dependencyType].Commit = commit
	err := writeToVersionsJson(repoPath, dependencies)
	if err != nil {
		return fmt.Errorf("error writing to versions "+dependencyType+": %s", err)
	}

	return nil
}

func writeToVersionsJson(repoPath string, dependencies Dependencies) error {
	// formatting json
	updatedJson, err := json.MarshalIndent(dependencies, "", "	  ")
	if err != nil {
		return fmt.Errorf("error marshaling dependencies json: %s", err)
	}

	e := os.WriteFile(repoPath+"/versions.json", updatedJson, 0644)
	if e != nil {
		return fmt.Errorf("error writing to versions.json: %s", e)
	}

	return nil
}

func createVersionsEnv(repoPath string, dependencies Dependencies) error {
	envLines := []string{}

	for dependency := range dependencies {
		repoUrl := generateGithubRepoUrl(dependencies, dependency) + ".git"

		dependencyPrefix := strings.ToUpper(dependency)

		if dependencies[dependency].Tracking == "branch" {
			dependencies[dependency].Tag = dependencies[dependency].Branch
		}

		envLines = append(envLines, fmt.Sprintf("export %s_%s=%s",
			dependencyPrefix, "TAG", dependencies[dependency].Tag))

		envLines = append(envLines, fmt.Sprintf("export %s_%s=%s",
			dependencyPrefix, "COMMIT", dependencies[dependency].Commit))

		envLines = append(envLines, fmt.Sprintf("export %s_%s=%s",
			dependencyPrefix, "REPO", repoUrl))
	}

	slices.Sort(envLines)

	file, err := os.Create(repoPath + "/versions.env")
	if err != nil {
		return fmt.Errorf("error creating versions.env file: %s", err)
	}
	defer file.Close()

	_, err = file.WriteString(strings.Join(envLines, "\n"))
	if err != nil {
		return fmt.Errorf("error writing to versions.env file: %s", err)
	}

	return nil
}

func writeToGithubOutput(title string, description string, repoPath string) error {
	file := os.Getenv("GITHUB_OUTPUT")
	f, err := os.OpenFile(file, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return fmt.Errorf("failed to open GITHUB_OUTPUT file: %s", err)
	}
	defer f.Close()

	titleToWrite := fmt.Sprintf("%s=%s\n", "TITLE", title)
	_, err = f.WriteString(titleToWrite)
	if err != nil {
		return fmt.Errorf("failed to write to GITHUB_OUTPUT file: %s", err)
	}

	delimiter := "EOF"
	descToWrite := fmt.Sprintf("%s<<%s\n%s\n%s\n", "DESC", delimiter, description, delimiter)
	_, err = f.WriteString(descToWrite)
	if err != nil {
		return fmt.Errorf("failed to write to GITHUB_OUTPUT file: %s", err)
	}

	return nil
}

func generateGithubRepoUrl(dependencies Dependencies, dependencyType string) string {
	return "https://github.com/" + dependencies[dependencyType].Owner + "/" + dependencies[dependencyType].Repo
}


================================================
FILE: dependency_updater/go.mod
================================================
module github.com/base/node/dependency_updater

go 1.24.3

require (
	github.com/ethereum-optimism/optimism v1.13.3
	github.com/google/go-github/v72 v72.0.0
	github.com/urfave/cli/v3 v3.3.8
)

require (
	github.com/Masterminds/semver/v3 v3.4.0 // indirect
	github.com/google/go-querystring v1.1.0 // indirect
)


================================================
FILE: dependency_updater/go.sum
================================================
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/ethereum-optimism/optimism v1.13.3 h1:rfPx7OembMnoEASU1ozA/Foa7Am7UA+h0SB+OUrxn7s=
github.com/ethereum-optimism/optimism v1.13.3/go.mod h1:WrVFtk3cP45tvHs7MARn9KGQu35XIoXo/IOWU6K/rzk=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-github/v72 v72.0.0 h1:FcIO37BLoVPBO9igQQ6tStsv2asG4IPcYFi655PPvBM=
github.com/google/go-github/v72 v72.0.0/go.mod h1:WWtw8GMRiL62mvIquf1kO3onRHeWWKmK01qdCY8c5fg=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/urfave/cli/v3 v3.3.8 h1:BzolUExliMdet9NlJ/u4m5vHSotJ3PzEqSAZ1oPMa/E=
github.com/urfave/cli/v3 v3.3.8/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=


================================================
FILE: dependency_updater/version.go
================================================
package main

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/Masterminds/semver/v3"
)

// rcPattern matches various RC formats: -rc1, -rc.1, -rc-1, -RC1, etc.
var rcPattern = regexp.MustCompile(`(?i)-rc[.-]?(\d+)`)

// rcOnlyPattern is used to check if a version contains ONLY an RC prerelease (not -synctest, -alpha, etc.)
var rcOnlyPattern = regexp.MustCompile(`(?i)^-rc[.-]?\d+$`)

// ParseVersion extracts and normalizes a semantic version from a tag string.
// It handles tagPrefix stripping, v-prefix normalization, and RC format normalization.
func ParseVersion(tag string, tagPrefix string) (*semver.Version, error) {
	versionStr := tag

	// Step 1: Strip tagPrefix if present (e.g., "op-node/v1.16.2" -> "v1.16.2")
	if tagPrefix != "" && strings.HasPrefix(tag, tagPrefix) {
		versionStr = strings.TrimPrefix(tag, tagPrefix)
		versionStr = strings.TrimPrefix(versionStr, "/")
	}

	// Step 2: Normalize RC formats to semver-compatible format
	// "-rc1" -> "-rc.1", "-rc-1" -> "-rc.1"
	versionStr = normalizeRCFormat(versionStr)

	// Step 3: Parse using Masterminds/semver (handles v prefix automatically)
	v, err := semver.NewVersion(versionStr)
	if err != nil {
		return nil, fmt.Errorf("invalid version format %q: %w", tag, err)
	}

	return v, nil
}

// normalizeRCFormat converts various RC formats to semver-compatible format.
// Examples: "-rc1" -> "-rc.1", "-rc-2" -> "-rc.2"
func normalizeRCFormat(version string) string {
	return rcPattern.ReplaceAllString(version, "-rc.$1")
}

// ValidateVersionUpgrade checks if transitioning from currentTag to newTag
// is a valid upgrade (not a downgrade).
// Returns nil if valid, error explaining why if invalid.
func ValidateVersionUpgrade(currentTag, newTag, tagPrefix string) error {
	// First-time setup: no current version, any valid version is acceptable
	if currentTag == "" {
		_, err := ParseVersion(newTag, tagPrefix)
		return err
	}

	// Parse current version
	currentVersion, err := ParseVersion(currentTag, tagPrefix)
	if err != nil {
		// Current version unparseable - still validate new version is parseable
		_, newErr := ParseVersion(newTag, tagPrefix)
		return newErr
	}

	// Parse new version
	newVersion, err := ParseVersion(newTag, tagPrefix)
	if err != nil {
		return fmt.Errorf("new version %q is not a valid semver: %w", newTag, err)
	}

	// Check for downgrade
	if newVersion.LessThan(currentVersion) {
		return fmt.Errorf(
			"version downgrade detected: %s -> %s",
			currentTag, newTag,
		)
	}

	return nil
}

// CompareVersions compares two version tags and returns:
// -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2
// Returns 0 and error if either version cannot be parsed.
func CompareVersions(v1Tag, v2Tag, tagPrefix string) (int, error) {
	v1, err := ParseVersion(v1Tag, tagPrefix)
	if err != nil {
		return 0, err
	}
	v2, err := ParseVersion(v2Tag, tagPrefix)
	if err != nil {
		return 0, err
	}
	return v1.Compare(v2), nil
}

// IsReleaseVersion returns true if the tag is a stable release (no prerelease suffix).
// Examples:
//   - "v1.0.0" -> true
//   - "v1.0.0-rc1" -> false
//   - "v1.0.0-synctest.0" -> false
func IsReleaseVersion(tag string, tagPrefix string) bool {
	v, err := ParseVersion(tag, tagPrefix)
	if err != nil {
		return false
	}
	return v.Prerelease() == ""
}

// IsRCVersion returns true if the tag is a release candidate version.
// This matches versions with -rc, -rc.N, -rc-N, -rcN suffixes.
// Examples:
//   - "v1.0.0-rc1" -> true
//   - "v1.0.0-rc.2" -> true
//   - "v1.0.0" -> false (stable release, not RC)
//   - "v1.0.0-synctest.0" -> false (not an RC)
//   - "v1.0.0-alpha" -> false (not an RC)
func IsRCVersion(tag string, tagPrefix string) bool {
	v, err := ParseVersion(tag, tagPrefix)
	if err != nil {
		return false
	}
	prerelease := v.Prerelease()
	if prerelease == "" {
		return false
	}
	// Check if the prerelease is ONLY an RC format (e.g., "rc.1", "rc1", "rc-1")
	// We need to check the original format before normalization
	return rcOnlyPattern.MatchString("-" + prerelease)
}

// IsReleaseOrRCVersion returns true if the tag is either a stable release or an RC version.
// This excludes other prereleases like -alpha, -beta, -synctest, etc.
func IsReleaseOrRCVersion(tag string, tagPrefix string) bool {
	return IsReleaseVersion(tag, tagPrefix) || IsRCVersion(tag, tagPrefix)
}


================================================
FILE: dependency_updater/version_test.go
================================================
package main

import (
	"testing"
)

func TestNormalizeRCFormat(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{"v0.3.0-rc1", "v0.3.0-rc.1"},
		{"v0.3.0-rc.1", "v0.3.0-rc.1"},
		{"v0.3.0-rc-1", "v0.3.0-rc.1"},
		{"v0.3.0-RC1", "v0.3.0-rc.1"},
		{"v0.3.0-rc12", "v0.3.0-rc.12"},
		{"v0.3.0", "v0.3.0"},
		{"v0.3.0-alpha", "v0.3.0-alpha"},
		{"v0.3.0-beta.1", "v0.3.0-beta.1"},
	}

	for _, tt := range tests {
		t.Run(tt.input, func(t *testing.T) {
			result := normalizeRCFormat(tt.input)
			if result != tt.expected {
				t.Errorf("normalizeRCFormat(%q) = %q, want %q", tt.input, result, tt.expected)
			}
		})
	}
}

func TestParseVersion(t *testing.T) {
	tests := []struct {
		tag       string
		tagPrefix string
		wantErr   bool
	}{
		// Standard versions
		{"v0.2.2", "", false},
		{"v0.3.0", "", false},
		{"1.35.3", "", false}, // nethermind style - no v prefix

		// RC versions
		{"v0.3.0-rc1", "", false},
		{"v0.3.0-rc.1", "", false},
		{"v0.3.0-rc-1", "", false},
		{"v0.3.0-rc.2", "", false},

		// With tagPrefix
		{"op-node/v1.16.2", "op-node", false},
		{"op-node/v1.16.3-rc1", "op-node", false},

		// Non-standard but parseable
		{"v1.101603.5", "", false}, // op-geth style

		// Invalid
		{"not-a-version", "", true},
		{"", "", true},
	}

	for _, tt := range tests {
		t.Run(tt.tag, func(t *testing.T) {
			_, err := ParseVersion(tt.tag, tt.tagPrefix)
			if (err != nil) != tt.wantErr {
				t.Errorf("ParseVersion(%q, %q) error = %v, wantErr %v", tt.tag, tt.tagPrefix, err, tt.wantErr)
			}
		})
	}
}

func TestValidateVersionUpgrade(t *testing.T) {
	tests := []struct {
		name       string
		currentTag string
		newTag     string
		tagPrefix  string
		wantErr    bool
	}{
		// Valid upgrades
		{"stable to rc", "v0.2.2", "v0.3.0-rc1", "", false},
		{"rc to rc", "v0.3.0-rc1", "v0.3.0-rc2", "", false},
		{"rc to stable", "v0.3.0-rc2", "v0.3.0", "", false},
		{"stable to stable", "v0.2.2", "v0.3.0", "", false},
		{"patch upgrade", "v0.2.2", "v0.2.3", "", false},
		{"minor upgrade", "v0.2.2", "v0.3.0", "", false},
		{"major upgrade", "v0.2.2", "v1.0.0", "", false},
		{"same version", "v0.2.2", "v0.2.2", "", false},

		// With tagPrefix
		{"prefix upgrade", "op-node/v1.16.2", "op-node/v1.16.3", "op-node", false},
		{"prefix rc upgrade", "op-node/v1.16.2", "op-node/v1.17.0-rc1", "op-node", false},

		// No v prefix (nethermind style)
		{"no v prefix upgrade", "1.35.3", "1.35.4", "", false},

		// Invalid downgrades
		{"downgrade major", "v0.3.0", "v0.2.2", "", true},
		{"downgrade minor", "v0.3.0", "v0.2.9", "", true},
		{"downgrade patch", "v0.3.1", "v0.3.0", "", true},
		{"stable to rc same version", "v0.3.0", "v0.3.0-rc2", "", true},
		{"stable to rc older version", "v0.3.0", "v0.2.0-rc1", "", true},

		// Edge cases
		{"empty current - valid new", "", "v0.3.0", "", false},
		{"empty current - invalid new", "", "not-a-version", "", true},
		{"unparseable current allows update", "not-semver", "v0.3.0", "", false},

		// Unparseable current with unparseable new should fail
		{"unparseable current - unparseable new", "rollup-boost/v0.7.11", "websocket-proxy/v0.0.2", "", true},
		{"unparseable current - valid new", "rollup-boost/v0.7.11", "v0.8.0", "", false},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := ValidateVersionUpgrade(tt.currentTag, tt.newTag, tt.tagPrefix)
			if (err != nil) != tt.wantErr {
				t.Errorf("ValidateVersionUpgrade(%q, %q, %q) error = %v, wantErr %v",
					tt.currentTag, tt.newTag, tt.tagPrefix, err, tt.wantErr)
			}
		})
	}
}

func TestCompareVersions(t *testing.T) {
	tests := []struct {
		name      string
		v1        string
		v2        string
		tagPrefix string
		want      int
	}{
		{"v1 less than v2", "v0.2.2", "v0.3.0", "", -1},
		{"v1 greater than v2", "v0.3.0", "v0.2.2", "", 1},
		{"equal versions", "v0.3.0", "v0.3.0", "", 0},
		{"rc less than stable", "v0.3.0-rc1", "v0.3.0", "", -1},
		{"rc1 less than rc2", "v0.3.0-rc1", "v0.3.0-rc2", "", -1},
		{"stable greater than rc", "v0.3.0", "v0.3.0-rc2", "", 1},
		{"with prefix", "op-node/v1.16.2", "op-node/v1.16.3", "op-node", -1},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := CompareVersions(tt.v1, tt.v2, tt.tagPrefix)
			if err != nil {
				t.Errorf("CompareVersions(%q, %q, %q) unexpected error: %v", tt.v1, tt.v2, tt.tagPrefix, err)
				return
			}
			if got != tt.want {
				t.Errorf("CompareVersions(%q, %q, %q) = %d, want %d", tt.v1, tt.v2, tt.tagPrefix, got, tt.want)
			}
		})
	}
}

func TestIsReleaseVersion(t *testing.T) {
	tests := []struct {
		tag       string
		tagPrefix string
		want      bool
	}{
		// Stable releases
		{"v1.0.0", "", true},
		{"v0.2.2", "", true},
		{"1.35.3", "", true}, // nethermind style
		{"v1.101603.5", "", true}, // op-geth style

		// With prefix
		{"op-node/v1.16.2", "op-node", true},

		// Pre-release versions (should return false)
		{"v1.0.0-rc1", "", false},
		{"v1.0.0-rc.1", "", false},
		{"v1.0.0-rc-1", "", false},
		{"v1.0.0-synctest.0", "", false},
		{"v1.0.0-alpha", "", false},
		{"v1.0.0-beta.1", "", false},
		{"op-node/v1.16.6-synctest.0", "op-node", false},
		{"op-node/v1.16.3-rc1", "op-node", false},

		// Invalid versions (should return false)
		{"not-a-version", "", false},
		{"", "", false},
	}

	for _, tt := range tests {
		t.Run(tt.tag, func(t *testing.T) {
			got := IsReleaseVersion(tt.tag, tt.tagPrefix)
			if got != tt.want {
				t.Errorf("IsReleaseVersion(%q, %q) = %v, want %v", tt.tag, tt.tagPrefix, got, tt.want)
			}
		})
	}
}

func TestIsRCVersion(t *testing.T) {
	tests := []struct {
		tag       string
		tagPrefix string
		want      bool
	}{
		// RC versions
		{"v1.0.0-rc1", "", true},
		{"v1.0.0-rc.1", "", true},
		{"v1.0.0-rc-1", "", true},
		{"v1.0.0-RC1", "", true},
		{"v1.0.0-rc12", "", true},
		{"op-node/v1.16.3-rc1", "op-node", true},
		{"op-node/v1.16.3-rc.2", "op-node", true},

		// Stable releases (not RC)
		{"v1.0.0", "", false},
		{"v0.2.2", "", false},
		{"op-node/v1.16.2", "op-node", false},

		// Other pre-release versions (not RC)
		{"v1.0.0-synctest.0", "", false},
		{"op-node/v1.16.6-synctest.0", "op-node", false},
		{"v1.0.0-alpha", "", false},
		{"v1.0.0-beta.1", "", false},
		{"v1.0.0-alpha.rc1", "", false}, // rc is part of another prerelease

		// Invalid versions
		{"not-a-version", "", false},
		{"", "", false},
	}

	for _, tt := range tests {
		t.Run(tt.tag, func(t *testing.T) {
			got := IsRCVersion(tt.tag, tt.tagPrefix)
			if got != tt.want {
				t.Errorf("IsRCVersion(%q, %q) = %v, want %v", tt.tag, tt.tagPrefix, got, tt.want)
			}
		})
	}
}

func TestIsReleaseOrRCVersion(t *testing.T) {
	tests := []struct {
		tag       string
		tagPrefix string
		want      bool
	}{
		// Stable releases - should pass
		{"v1.0.0", "", true},
		{"v0.2.2", "", true},
		{"op-node/v1.16.2", "op-node", true},

		// RC versions - should pass
		{"v1.0.0-rc1", "", true},
		{"v1.0.0-rc.1", "", true},
		{"op-node/v1.16.3-rc1", "op-node", true},

		// Other pre-release versions - should NOT pass
		{"v1.0.0-synctest.0", "", false},
		{"op-node/v1.16.6-synctest.0", "op-node", false},
		{"v1.0.0-alpha", "", false},
		{"v1.0.0-beta.1", "", false},

		// Invalid versions
		{"not-a-version", "", false},
	}

	for _, tt := range tests {
		t.Run(tt.tag, func(t *testing.T) {
			got := IsReleaseOrRCVersion(tt.tag, tt.tagPrefix)
			if got != tt.want {
				t.Errorf("IsReleaseOrRCVersion(%q, %q) = %v, want %v", tt.tag, tt.tagPrefix, got, tt.want)
			}
		})
	}
}

func TestRCVersionOrdering(t *testing.T) {
	// Verify that RC versions are ordered correctly
	versions := []string{
		"v0.2.2",
		"v0.3.0-rc.1",
		"v0.3.0-rc.2",
		"v0.3.0",
		"v0.3.1",
	}

	for i := 0; i < len(versions)-1; i++ {
		current := versions[i]
		next := versions[i+1]
		t.Run(current+" -> "+next, func(t *testing.T) {
			err := ValidateVersionUpgrade(current, next, "")
			if err != nil {
				t.Errorf("Expected %s -> %s to be valid upgrade, got error: %v", current, next, err)
			}
		})
	}

	// Verify reverse order is invalid
	for i := len(versions) - 1; i > 0; i-- {
		current := versions[i]
		previous := versions[i-1]
		t.Run(current+" -> "+previous+" (downgrade)", func(t *testing.T) {
			err := ValidateVersionUpgrade(current, previous, "")
			if err == nil {
				t.Errorf("Expected %s -> %s to be invalid downgrade", current, previous)
			}
		})
	}
}


================================================
FILE: docker-compose.yml
================================================
services:
  execution:
    build:
      context: .
      dockerfile: ${CLIENT:-geth}/Dockerfile
    restart: unless-stopped
    ports:
      - "8545:8545" # RPC
      - "8546:8546" # websocket
      - "7301:6060" # metrics
      - "30303:30303" # P2P TCP
      - "30303:30303/udp" # P2P UDP
    command: ["bash", "./execution-entrypoint"]
    volumes:
      - ${HOST_DATA_DIR}:/data
    env_file:
      - ${NETWORK_ENV:-.env.mainnet} # Use .env.mainnet by default, override with .env.sepolia for testnet
  node:
    build:
      context: .
      dockerfile: ${CLIENT:-geth}/Dockerfile
    restart: unless-stopped
    depends_on:
      - execution
    ports:
      - "7545:8545" # RPC
      - "9222:9222" # P2P TCP
      - "9222:9222/udp" # P2P UDP
      - "7300:7300" # metrics
      - "6060:6060" # pprof
    command: ["bash", "./op-node-entrypoint"]
    env_file:
      - ${NETWORK_ENV:-.env.mainnet} # Use .env.mainnet by default, override with .env.sepolia for testnet


================================================
FILE: geth/Dockerfile
================================================
FROM golang:1.24 AS op

RUN curl -sSfL 'https://just.systems/install.sh' | bash -s -- --to /usr/local/bin

WORKDIR /app

COPY versions.env /tmp/versions.env

RUN . /tmp/versions.env && git clone $OP_NODE_REPO --branch $OP_NODE_TAG --single-branch . && \
    git switch -c branch-$OP_NODE_TAG && \
    bash -c '[ "$(git rev-parse HEAD)" = "$OP_NODE_COMMIT" ]'

RUN . /tmp/versions.env && cd op-node && \
    make VERSION=$OP_NODE_TAG op-node

FROM golang:1.24 AS geth

WORKDIR /app

COPY versions.env /tmp/versions.env

RUN . /tmp/versions.env && git clone $OP_GETH_REPO --branch $OP_GETH_TAG --single-branch . && \
    git switch -c branch-$OP_GETH_TAG && \
    bash -c '[ "$(git rev-parse HEAD)" = "$OP_GETH_COMMIT" ]'

RUN go run build/ci.go install -static ./cmd/geth

FROM ubuntu:24.04

RUN apt-get update && \
    apt-get install -y jq curl supervisor && \
    rm -rf /var/lib/apt/lists
RUN mkdir -p /var/log/supervisor

WORKDIR /app

COPY --from=op /app/op-node/bin/op-node ./
COPY --from=geth /app/build/bin/geth ./
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY geth/geth-entrypoint ./execution-entrypoint
COPY op-node-entrypoint .

CMD ["/usr/bin/supervisord"]


================================================
FILE: geth/geth-entrypoint
================================================
#!/bin/bash
set -eu

VERBOSITY=${GETH_VERBOSITY:-3}
GETH_DATA_DIR=${GETH_DATA_DIR:-/data}
RPC_PORT="${RPC_PORT:-8545}"
WS_PORT="${WS_PORT:-8546}"
AUTHRPC_PORT="${AUTHRPC_PORT:-8551}"
METRICS_PORT="${METRICS_PORT:-6060}"
HOST_IP="" # put your external IP address here and open port 30303 to improve peer connectivity
P2P_PORT="${P2P_PORT:-30303}"
DISCOVERY_PORT="${DISCOVERY_PORT:-30303}"
ADDITIONAL_ARGS=""
OP_GETH_GCMODE="${OP_GETH_GCMODE:-full}"
OP_GETH_SYNCMODE="${OP_GETH_SYNCMODE:-full}"

# Add cache optimizations with defaults
GETH_CACHE="${GETH_CACHE:-20480}"
GETH_CACHE_DATABASE="${GETH_CACHE_DATABASE:-20}"
GETH_CACHE_GC="${GETH_CACHE_GC:-12}"
GETH_CACHE_SNAPSHOT="${GETH_CACHE_SNAPSHOT:-24}"
GETH_CACHE_TRIE="${GETH_CACHE_TRIE:-44}"

if [[ -z "$OP_NODE_NETWORK" ]]; then
    echo "expected OP_NODE_NETWORK to be set" 1>&2
    exit 1
fi

mkdir -p $GETH_DATA_DIR

echo "$OP_NODE_L2_ENGINE_AUTH_RAW" > "$OP_NODE_L2_ENGINE_AUTH"

if [ "${OP_GETH_ETH_STATS+x}" = x ]; then
    ADDITIONAL_ARGS="$ADDITIONAL_ARGS --ethstats=$OP_GETH_ETH_STATS"
fi

if [ "${OP_GETH_ALLOW_UNPROTECTED_TXS+x}" = x ]; then
    ADDITIONAL_ARGS="$ADDITIONAL_ARGS --rpc.allow-unprotected-txs=$OP_GETH_ALLOW_UNPROTECTED_TXS"
fi

if [ "${OP_GETH_STATE_SCHEME+x}" = x ]; then
    ADDITIONAL_ARGS="$ADDITIONAL_ARGS --state.scheme=$OP_GETH_STATE_SCHEME"
fi

if [ "${OP_GETH_BOOTNODES+x}" = x ]; then
    ADDITIONAL_ARGS="$ADDITIONAL_ARGS --bootnodes=$OP_GETH_BOOTNODES"
fi

if [ "${HOST_IP:+x}" = x ]; then
    ADDITIONAL_ARGS="$ADDITIONAL_ARGS --nat=extip:$HOST_IP"
fi 

exec ./geth \
    --datadir="$GETH_DATA_DIR" \
    --verbosity="$VERBOSITY" \
    --http \
    --http.corsdomain="*" \
    --http.vhosts="*" \
    --http.addr=0.0.0.0 \
    --http.port="$RPC_PORT" \
    --http.api=web3,debug,eth,net,engine \
    --authrpc.addr=0.0.0.0 \
    --authrpc.port="$AUTHRPC_PORT" \
    --authrpc.vhosts="*" \
    --authrpc.jwtsecret="$OP_NODE_L2_ENGINE_AUTH" \
    --ws \
    --ws.addr=0.0.0.0 \
    --ws.port="$WS_PORT" \
    --ws.origins="*" \
    --ws.api=debug,eth,net,engine \
    --metrics \
    --metrics.addr=0.0.0.0 \
    --metrics.port="$METRICS_PORT" \
    --syncmode="$OP_GETH_SYNCMODE" \
    --gcmode="$OP_GETH_GCMODE" \
    --maxpeers=100 \
    --rollup.sequencerhttp="$OP_GETH_SEQUENCER_HTTP" \
    --rollup.halt=major \
    --op-network="$OP_NODE_NETWORK" \
    --discovery.port="$DISCOVERY_PORT" \
    --port="$P2P_PORT" \
    --rollup.disabletxpoolgossip=true \
    --cache="$GETH_CACHE" \
    --cache.database="$GETH_CACHE_DATABASE" \
    --cache.gc="$GETH_CACHE_GC" \
    --cache.snapshot="$GETH_CACHE_SNAPSHOT" \
    --cache.trie="$GETH_CACHE_TRIE" \
    $ADDITIONAL_ARGS # intentionally unquoted


================================================
FILE: go.mod
================================================
module dependency_updater

go 1.24.3


================================================
FILE: nethermind/Dockerfile
================================================
FROM golang:1.24 AS op

RUN curl -sSfL 'https://just.systems/install.sh' | bash -s -- --to /usr/local/bin

WORKDIR /app

COPY versions.env /tmp/versions.env

RUN . /tmp/versions.env && git clone $OP_NODE_REPO --branch $OP_NODE_TAG --single-branch . && \
    git switch -c branch-$OP_NODE_TAG && \
    bash -c '[ "$(git rev-parse HEAD)" = "$OP_NODE_COMMIT" ]'

RUN . /tmp/versions.env && cd op-node && \
    just VERSION=$OP_NODE_TAG op-node

FROM mcr.microsoft.com/dotnet/sdk:10.0-noble AS build

ARG BUILD_CONFIG=release
ARG TARGETARCH

WORKDIR /app

COPY versions.env /tmp/versions.env

RUN . /tmp/versions.env && git clone $NETHERMIND_REPO --branch $NETHERMIND_TAG --single-branch . && \
    git switch -c $NETHERMIND_TAG && \
    bash -c '[ "$(git rev-parse HEAD)" = "$NETHERMIND_COMMIT" ]'
    
RUN TARGETARCH=${TARGETARCH#linux/} && \
    arch=$([ "$TARGETARCH" = "amd64" ] && echo "x64" || echo "$TARGETARCH") && \
    echo "Using architecture: $arch" && \
    dotnet publish src/Nethermind/Nethermind.Runner -c $BUILD_CONFIG -a $arch -o /publish --sc false

FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble

RUN apt-get update && \
    apt-get install -y jq curl supervisor && \
    rm -rf /var/lib/apt/lists/*

RUN mkdir -p /var/log/supervisor

WORKDIR /app

COPY --from=build /publish ./
COPY --from=op /app/op-node/bin/op-node ./
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY nethermind/nethermind-entrypoint ./execution-entrypoint
COPY op-node-entrypoint .

CMD ["/usr/bin/supervisord"]


================================================
FILE: nethermind/nethermind-entrypoint
================================================
#!/bin/bash
set -eu

# Default configurations
NETHERMIND_DATA_DIR=${NETHERMIND_DATA_DIR:-/data}
NETHERMIND_LOG_LEVEL=${NETHERMIND_LOG_LEVEL:-Info}

RPC_PORT="${RPC_PORT:-8545}"
WS_PORT="${WS_PORT:-8546}"
AUTHRPC_PORT="${AUTHRPC_PORT:-8551}"
METRICS_PORT="${METRICS_PORT:-6060}"
DISCOVERY_PORT="${DISCOVERY_PORT:-30303}"
P2P_PORT="${P2P_PORT:-30303}"
ADDITIONAL_ARGS=""

# Check if required variables are set
if [[ -z "$OP_NODE_NETWORK" ]]; then
    echo "Expected OP_NODE_NETWORK to be set" 1>&2
    exit 1
fi

# Create necessary directories
mkdir -p "$NETHERMIND_DATA_DIR"

# Write the JWT secret
if [[ -z "$OP_NODE_L2_ENGINE_AUTH_RAW" ]]; then
    echo "Expected OP_NODE_L2_ENGINE_AUTH_RAW to be set" 1>&2
    exit 1
fi
echo "$OP_NODE_L2_ENGINE_AUTH_RAW" > "$OP_NODE_L2_ENGINE_AUTH"

# Additional arguments based on environment variables
if [[ -n "${OP_NETHERMIND_BOOTNODES:-}" ]]; then
    ADDITIONAL_ARGS="$ADDITIONAL_ARGS --Network.Bootnodes=$OP_NETHERMIND_BOOTNODES"
fi

if [[ -n "${OP_NETHERMIND_ETHSTATS_ENABLED:-}" ]]; then
    ADDITIONAL_ARGS="$ADDITIONAL_ARGS --EthStats.Enabled=$OP_NETHERMIND_ETHSTATS_ENABLED"
fi

if [[ -n "${OP_NETHERMIND_ETHSTATS_ENDPOINT:-}" ]]; then
    ADDITIONAL_ARGS="$ADDITIONAL_ARGS --EthStats.NodeName=${OP_NETHERMIND_ETHSTATS_NODE_NAME:-NethermindNode} --EthStats.Endpoint=$OP_NETHERMIND_ETHSTATS_ENDPOINT"
fi

# Execute Nethermind
exec ./nethermind \
    --config="$OP_NODE_NETWORK" \
    --datadir="$NETHERMIND_DATA_DIR" \
    --Optimism.SequencerUrl=$OP_SEQUENCER_HTTP \
    --log="$NETHERMIND_LOG_LEVEL" \
    --JsonRpc.Enabled=true \
    --JsonRpc.Host=0.0.0.0 \
    --JsonRpc.WebSocketsPort="$WS_PORT" \
    --JsonRpc.Port="$RPC_PORT" \
    --JsonRpc.JwtSecretFile="$OP_NODE_L2_ENGINE_AUTH" \
    --JsonRpc.EngineHost=0.0.0.0 \
    --JsonRpc.EnginePort="$AUTHRPC_PORT" \
    --HealthChecks.Enabled=true \
    --Metrics.Enabled=true \
    --Metrics.ExposePort="$METRICS_PORT" \
    --Network.P2PPort="$P2P_PORT" \
    --Network.DiscoveryPort="$DISCOVERY_PORT" \
    $ADDITIONAL_ARGS


================================================
FILE: op-node-entrypoint
================================================
#!/bin/bash
set -eu

get_public_ip() {
  # Define a list of HTTP-based providers
  local PROVIDERS=(
    "http://ifconfig.me"
    "http://api.ipify.org"
    "http://ipecho.net/plain"
    "http://v4.ident.me"
  )
  # Iterate through the providers until an IP is found or the list is exhausted
  for provider in "${PROVIDERS[@]}"; do
    local IP
    IP=$(curl -s --max-time 10 --connect-timeout 5 "$provider")
    # Check if IP contains a valid format (simple regex for an IPv4 address)
    if [[ $IP =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
      echo "$IP"
      return 0
    fi
  done
  return 1
}

if [[ -z "$OP_NODE_NETWORK" && -z "$OP_NODE_ROLLUP_CONFIG" ]]; then
  echo "expected OP_NODE_NETWORK to be set" 1>&2
  exit 1
fi

# wait until local execution client comes up (authed so will return 401 without token)
until [ "$(curl -s --max-time 10 --connect-timeout 5 -w '%{http_code}' -o /dev/null "${OP_NODE_L2_ENGINE_RPC/ws/http}")" -eq 401 ]; do
  echo "waiting for execution client to be ready"
  sleep 5
done

# public-facing P2P node, advertise public IP address
if PUBLIC_IP=$(get_public_ip); then
  echo "fetched public IP is: $PUBLIC_IP"
else
  echo "Could not retrieve public IP."
  exit 8
fi
export OP_NODE_P2P_ADVERTISE_IP=$PUBLIC_IP

echo "$OP_NODE_L2_ENGINE_AUTH_RAW" > "$OP_NODE_L2_ENGINE_AUTH"

exec ./op-node


================================================
FILE: reth/Dockerfile
================================================
FROM golang:1.24 AS op

RUN curl -sSfL 'https://just.systems/install.sh' | bash -s -- --to /usr/local/bin

WORKDIR /app

COPY versions.env /tmp/versions.env

RUN . /tmp/versions.env && git clone $OP_NODE_REPO --branch $OP_NODE_TAG --single-branch . && \
    git switch -c branch-$OP_NODE_TAG && \
    bash -c '[ "$(git rev-parse HEAD)" = "$OP_NODE_COMMIT" ]'

RUN . /tmp/versions.env && cd op-node && \
    make VERSION=$OP_NODE_TAG op-node

FROM rust:1.88 AS reth-base

WORKDIR /app

COPY versions.env /tmp/versions.env

RUN apt-get update && apt-get -y upgrade && \
    apt-get install -y git libclang-dev pkg-config curl build-essential && \
    rm -rf /var/lib/apt/lists/*

RUN . /tmp/versions.env && git clone $BASE_RETH_NODE_REPO . && \
    git checkout tags/$BASE_RETH_NODE_TAG && \
    bash -c '[ "$(git rev-parse HEAD)" = "$BASE_RETH_NODE_COMMIT" ]' || (echo "Commit hash verification failed" && exit 1)

RUN cargo build --bin base-reth-node --profile maxperf

FROM ubuntu:24.04

RUN apt-get update && \
    apt-get install -y jq curl supervisor && \
    rm -rf /var/lib/apt/lists/*
RUN mkdir -p /var/log/supervisor

WORKDIR /app

COPY --from=op /app/op-node/bin/op-node ./
COPY --from=reth-base /app/target/maxperf/base-reth-node ./
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY ./reth/reth-entrypoint ./execution-entrypoint
COPY op-node-entrypoint .

CMD ["/usr/bin/supervisord"]


================================================
FILE: reth/README.md
================================================
# Running a Reth Node

This is an implementation of the Reth node setup that supports Flashblocks mode based on configuration.

## Setup

- See hardware requirements mentioned in the master README
- For Flashblocks mode: Access to a Flashblocks websocket endpoint (for `RETH_FB_WEBSOCKET_URL`)
  - We provide public websocket endpoints for mainnet and devnet, included in `.env.mainnet` and `.env.sepolia`

## Node Type Selection

The node determines its mode based on the presence of the `RETH_FB_WEBSOCKET_URL` environment variable:

- **Vanilla Mode** (default): When no `RETH_FB_WEBSOCKET_URL` is provided.
- **Flashblocks Mode**: When `RETH_FB_WEBSOCKET_URL` is provided.

## Running the Node

The node follows the standard `docker-compose` workflow in the master README.

```bash
# To run Reth node with Flashblocks support, set RETH_FB_WEBSOCKET_URL in your .env file
CLIENT=reth docker-compose up
```

## Testing Flashblocks RPC Methods

When running in Flashblocks mode (with `RETH_FB_WEBSOCKET_URL` configured), you can query a pending block using the Flashblocks RPC:

```bash
curl -X POST \
  --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["pending", false],"id":1}' \
  http://localhost:8545
```

## Additional RPC Methods

For a complete list of supported RPC methods, refer to:

- [Standard Ethereum JSON-RPC](https://ethereum.org/en/developers/docs/apis/json-rpc/)
- [Flashblocks RPC Methods](https://docs.base.org/chain/flashblocks#rpc-api) (Flashblocks mode only)


================================================
FILE: reth/reth-entrypoint
================================================
#!/bin/bash
set -eu

IPC_PATH="/data/reth.ipc"
RETH_DATA_DIR=/data
RPC_PORT="${RPC_PORT:-8545}"
WS_PORT="${WS_PORT:-8546}"
AUTHRPC_PORT="${AUTHRPC_PORT:-8551}"
METRICS_PORT="${METRICS_PORT:-6060}"
DISCOVERY_PORT="${DISCOVERY_PORT:-30303}"
P2P_PORT="${P2P_PORT:-30303}"
ADDITIONAL_ARGS=""
BINARY="./base-reth-node"
RETH_HISTORICAL_PROOFS="${RETH_HISTORICAL_PROOFS:-false}"
RETH_HISTORICAL_PROOFS_STORAGE_PATH="${RETH_HISTORICAL_PROOFS_STORAGE_PATH:-}"
LOG_LEVEL="${LOG_LEVEL:-info}"

if [[ -z "${RETH_CHAIN:-}" ]]; then
    echo "expected RETH_CHAIN to be set" 1>&2
    exit 1
fi

# Enable Flashblocks support if websocket URL is provided
if [[ -n "${RETH_FB_WEBSOCKET_URL:-}" ]]; then
    ADDITIONAL_ARGS="$ADDITIONAL_ARGS --websocket-url=$RETH_FB_WEBSOCKET_URL"
    echo "Enabling Flashblocks support with endpoint: $RETH_FB_WEBSOCKET_URL"
else
    echo "Running in vanilla node mode (no Flashblocks URL provided)"
fi

case "$LOG_LEVEL" in
    "error")
        LOG_LEVEL="v"
        ;;
    "warn")
        LOG_LEVEL="vv"
        ;;
    "info"|*)
        LOG_LEVEL="vvv"
        ;;
    "debug")
        LOG_LEVEL="vvvv"
        ;;
    "trace")
        LOG_LEVEL="vvvvv"
        ;;
esac

# Add pruning for base
if [[ "${RETH_PRUNING_ARGS+x}" = x ]]; then
    echo "Adding pruning arguments: $RETH_PRUNING_ARGS"
    ADDITIONAL_ARGS="$ADDITIONAL_ARGS $RETH_PRUNING_ARGS"
fi

if [[ "$RETH_HISTORICAL_PROOFS" == "true" && -n "$RETH_HISTORICAL_PROOFS_STORAGE_PATH" ]]; then
    # reth doesn't like starting an old database in RO mode, so we have to start the reth node, wait for it to start up, then shut it down first
    "$BINARY" node \
        -$LOG_LEVEL \
        --datadir="$RETH_DATA_DIR" \
        --log.stdout.format json \
        --http \
        --http.addr=127.0.0.1 \
        --http.port="$RPC_PORT" \
        --http.api=eth \
        --chain "$RETH_CHAIN" &

    PID=$!

    MAX_WAIT=$((60 * 60 * 6)) # 6 hours (static file manager init is slow)

    # wait for json-rpc to return a block number greater than 0 (synced beyond genesis)
    while true; do
        RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest", false],"id":1}' http://127.0.0.1:"$RPC_PORT" 2>/dev/null || true)
        
        if echo "$RESPONSE" | grep -q '"number":"0x0"'; then
            echo "waiting for reth node to sync beyond genesis block"
        elif echo "$RESPONSE" | grep -q '"result"'; then
            # curl succeeded and returned a valid result with block number != 0x0
            break
        else
            echo "waiting for reth node to start up"
        fi
        
        sleep 1
        MAX_WAIT=$((MAX_WAIT - 1))
        if [ "$MAX_WAIT" -eq 0 ]; then
            echo "timed out waiting for reth node to start up"
            kill "$PID"
            exit 1
        fi
    done

    # shut down gracefully
    kill "$PID"

    (wait "$PID" && echo "reth node initialized") || echo "warning: reth node exited with code $?"

    ADDITIONAL_ARGS="$ADDITIONAL_ARGS --proofs-history --proofs-history.storage-path=$RETH_HISTORICAL_PROOFS_STORAGE_PATH"

    # in this case, we need to run the init script first (idempotent)
    "$BINARY" proofs init \
        -$LOG_LEVEL \
        --log.stdout.format json \
        --chain "$RETH_CHAIN" \
        --datadir="$RETH_DATA_DIR" \
        --proofs-history.storage-path=$RETH_HISTORICAL_PROOFS_STORAGE_PATH
fi

mkdir -p "$RETH_DATA_DIR"
echo "Starting reth with additional args: $ADDITIONAL_ARGS"
echo "$OP_NODE_L2_ENGINE_AUTH_RAW" > "$OP_NODE_L2_ENGINE_AUTH"

exec "$BINARY" node \
  -$LOG_LEVEL \
  --datadir="$RETH_DATA_DIR" \
  --log.stdout.format json \
  --ws \
  --ws.origins="*" \
  --ws.addr=0.0.0.0 \
  --ws.port="$WS_PORT" \
  --ws.api=web3,debug,eth,net,txpool \
  --http \
  --http.corsdomain="*" \
  --http.addr=0.0.0.0 \
  --http.port="$RPC_PORT" \
  --http.api=web3,debug,eth,net,txpool,miner \
  --ipcpath="$IPC_PATH" \
  --authrpc.addr=0.0.0.0 \
  --authrpc.port="$AUTHRPC_PORT" \
  --authrpc.jwtsecret="$OP_NODE_L2_ENGINE_AUTH" \
  --metrics=0.0.0.0:"$METRICS_PORT" \
  --max-outbound-peers=100 \
  --chain "$RETH_CHAIN" \
  --rollup.sequencer-http="$RETH_SEQUENCER_HTTP" \
  --rollup.disable-tx-pool-gossip \
  --discovery.port="$DISCOVERY_PORT" \
  --port="$P2P_PORT" \
  $ADDITIONAL_ARGS


================================================
FILE: supervisord.conf
================================================
[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0

[program:op-node]
command=/app/op-node-entrypoint
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
stopwaitsecs=300

[program:op-execution]
command=/app/execution-entrypoint
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
stopwaitsecs=300


================================================
FILE: versions.env
================================================
export BASE_RETH_NODE_COMMIT=6e54e8cbcbd27cb86bde54d3a5b0e9b4e9ea960a
export BASE_RETH_NODE_REPO=https://github.com/base/base.git
export BASE_RETH_NODE_TAG=v0.5.1
export NETHERMIND_COMMIT=31cb81b7328026791cdfaccd9db230c82f1db02d
export NETHERMIND_REPO=https://github.com/NethermindEth/nethermind.git
export NETHERMIND_TAG=1.36.0
export OP_GETH_COMMIT=878a554cc84cead647d20ba366043c6fd41ebf1c
export OP_GETH_REPO=https://github.com/ethereum-optimism/op-geth.git
export OP_GETH_TAG=v1.101609.1
export OP_NODE_COMMIT=3019251e80aa248e91743addd3e833190acb26f1
export OP_NODE_REPO=https://github.com/ethereum-optimism/optimism.git
export OP_NODE_TAG=op-node/v1.16.7

================================================
FILE: versions.json
================================================
{
	  "base_reth_node": {
	  	  "tag": "v0.5.1",
	  	  "commit": "6e54e8cbcbd27cb86bde54d3a5b0e9b4e9ea960a",
	  	  "owner": "base",
	  	  "repo": "base",
	  	  "tracking": "release"
	  },
	  "nethermind": {
	  	  "tag": "1.36.0",
	  	  "commit": "31cb81b7328026791cdfaccd9db230c82f1db02d",
	  	  "owner": "NethermindEth",
	  	  "repo": "nethermind",
	  	  "tracking": "release"
	  },
	  "op_geth": {
	  	  "tag": "v1.101609.1",
	  	  "commit": "878a554cc84cead647d20ba366043c6fd41ebf1c",
	  	  "owner": "ethereum-optimism",
	  	  "repo": "op-geth",
	  	  "tracking": "release"
	  },
	  "op_node": {
	  	  "tag": "op-node/v1.16.7",
	  	  "commit": "3019251e80aa248e91743addd3e833190acb26f1",
	  	  "tagPrefix": "op-node",
	  	  "owner": "ethereum-optimism",
	  	  "repo": "optimism",
	  	  "tracking": "release"
	  }
}
Download .txt
gitextract_5b8jeo_f/

├── .dockerignore
├── .github/
│   └── workflows/
│       ├── docker.yml
│       ├── pr.yml
│       ├── stale.yml
│       └── update-dependencies.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── dependency_updater/
│   ├── dependency_updater.go
│   ├── go.mod
│   ├── go.sum
│   ├── version.go
│   └── version_test.go
├── docker-compose.yml
├── geth/
│   ├── Dockerfile
│   └── geth-entrypoint
├── go.mod
├── nethermind/
│   ├── Dockerfile
│   └── nethermind-entrypoint
├── op-node-entrypoint
├── reth/
│   ├── Dockerfile
│   ├── README.md
│   └── reth-entrypoint
├── supervisord.conf
├── versions.env
└── versions.json
Download .txt
SYMBOL INDEX (27 symbols across 3 files)

FILE: dependency_updater/dependency_updater.go
  type Info (line 20) | type Info struct
  type VersionUpdateInfo (line 30) | type VersionUpdateInfo struct
  function main (line 39) | func main() {
  function updater (line 80) | func updater(token string, repoPath string, commit bool, githubAction bo...
  function createCommitMessage (line 134) | func createCommitMessage(updatedDependencies []VersionUpdateInfo, repoPa...
  function getAndUpdateDependency (line 164) | func getAndUpdateDependency(ctx context.Context, client *github.Client, ...
  function getVersionAndCommit (line 179) | func getVersionAndCommit(ctx context.Context, client *github.Client, dep...
  function updateVersionTagAndCommit (line 316) | func updateVersionTagAndCommit(
  function writeToVersionsJson (line 332) | func writeToVersionsJson(repoPath string, dependencies Dependencies) err...
  function createVersionsEnv (line 347) | func createVersionsEnv(repoPath string, dependencies Dependencies) error {
  function writeToGithubOutput (line 385) | func writeToGithubOutput(title string, description string, repoPath stri...
  function generateGithubRepoUrl (line 409) | func generateGithubRepoUrl(dependencies Dependencies, dependencyType str...

FILE: dependency_updater/version.go
  function ParseVersion (line 19) | func ParseVersion(tag string, tagPrefix string) (*semver.Version, error) {
  function normalizeRCFormat (line 43) | func normalizeRCFormat(version string) string {
  function ValidateVersionUpgrade (line 50) | func ValidateVersionUpgrade(currentTag, newTag, tagPrefix string) error {
  function CompareVersions (line 85) | func CompareVersions(v1Tag, v2Tag, tagPrefix string) (int, error) {
  function IsReleaseVersion (line 102) | func IsReleaseVersion(tag string, tagPrefix string) bool {
  function IsRCVersion (line 118) | func IsRCVersion(tag string, tagPrefix string) bool {
  function IsReleaseOrRCVersion (line 134) | func IsReleaseOrRCVersion(tag string, tagPrefix string) bool {

FILE: dependency_updater/version_test.go
  function TestNormalizeRCFormat (line 7) | func TestNormalizeRCFormat(t *testing.T) {
  function TestParseVersion (line 32) | func TestParseVersion(t *testing.T) {
  function TestValidateVersionUpgrade (line 71) | func TestValidateVersionUpgrade(t *testing.T) {
  function TestCompareVersions (line 124) | func TestCompareVersions(t *testing.T) {
  function TestIsReleaseVersion (line 155) | func TestIsReleaseVersion(t *testing.T) {
  function TestIsRCVersion (line 195) | func TestIsRCVersion(t *testing.T) {
  function TestIsReleaseOrRCVersion (line 237) | func TestIsReleaseOrRCVersion(t *testing.T) {
  function TestRCVersionOrdering (line 273) | func TestRCVersionOrdering(t *testing.T) {
Condensed preview — 28 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (81K chars).
[
  {
    "path": ".dockerignore",
    "chars": 39,
    "preview": "geth-data/\nreth-data/\nnethermind-data/\n"
  },
  {
    "path": ".github/workflows/docker.yml",
    "chars": 13415,
    "preview": "name: Tag Docker image\n\non:\n  push:\n    branches:\n      - \"main\"\n    tags:\n      - \"v*\"\n  workflow_dispatch: {}\n\nenv:\n  "
  },
  {
    "path": ".github/workflows/pr.yml",
    "chars": 3299,
    "preview": "name: Pull Request\n\non:\n  pull_request:\n  workflow_dispatch:\n\npermissions:\n  contents: read\n\njobs:\n  geth:\n    strategy:"
  },
  {
    "path": ".github/workflows/stale.yml",
    "chars": 1285,
    "preview": "name: Mark stale issues and PRs\n\non:\n  schedule:\n    - cron: '30 0 * * *'\n  workflow_dispatch:\npermissions:\n  contents: "
  },
  {
    "path": ".github/workflows/update-dependencies.yml",
    "chars": 1314,
    "preview": "name: Update Dockerfile Dependencies\non:\n  schedule:\n    - cron: '0 13 * * *'\n  workflow_dispatch:\n\npermissions:\n  conte"
  },
  {
    "path": ".gitignore",
    "chars": 98,
    "preview": "/.idea/\n/geth-data/\n/reth-data/\n/nethermind-data/\n/dependency_updater/dependency_updater\n.DS_Store"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2252,
    "preview": "# Contributing to Base Node\n\n## Code of Conduct\n\nAll interactions with this project follow our [Code of Conduct][code-of"
  },
  {
    "path": "LICENSE",
    "chars": 1083,
    "preview": "MIT License\n\nCopyright (c) 2023-2025 base.org contributors\n\nPermission is hereby granted, free of charge, to any person "
  },
  {
    "path": "README.md",
    "chars": 4689,
    "preview": "![Base](logo.webp)\n\n# Base Node\n\nBase is a secure, low-cost, developer-friendly Ethereum L2 built on Optimism's [OP Stac"
  },
  {
    "path": "SECURITY.md",
    "chars": 1530,
    "preview": "# Security\n\n## Bug bounty program\n\nIn line with our strategy of being the safest way for users to access crypto:\n\n+ Coin"
  },
  {
    "path": "dependency_updater/dependency_updater.go",
    "chars": 11783,
    "preview": "package main\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/ethereum-optimism/optimism/op-"
  },
  {
    "path": "dependency_updater/go.mod",
    "chars": 311,
    "preview": "module github.com/base/node/dependency_updater\n\ngo 1.24.3\n\nrequire (\n\tgithub.com/ethereum-optimism/optimism v1.13.3\n\tgit"
  },
  {
    "path": "dependency_updater/go.sum",
    "chars": 2070,
    "preview": "github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=\ngithub.com/Masterminds/semver/v3"
  },
  {
    "path": "dependency_updater/version.go",
    "chars": 4317,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/Masterminds/semver/v3\"\n)\n\n// rcPattern matches various "
  },
  {
    "path": "dependency_updater/version_test.go",
    "chars": 8375,
    "preview": "package main\n\nimport (\n\t\"testing\"\n)\n\nfunc TestNormalizeRCFormat(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t"
  },
  {
    "path": "docker-compose.yml",
    "chars": 973,
    "preview": "services:\n  execution:\n    build:\n      context: .\n      dockerfile: ${CLIENT:-geth}/Dockerfile\n    restart: unless-stop"
  },
  {
    "path": "geth/Dockerfile",
    "chars": 1190,
    "preview": "FROM golang:1.24 AS op\n\nRUN curl -sSfL 'https://just.systems/install.sh' | bash -s -- --to /usr/local/bin\n\nWORKDIR /app\n"
  },
  {
    "path": "geth/geth-entrypoint",
    "chars": 2691,
    "preview": "#!/bin/bash\nset -eu\n\nVERBOSITY=${GETH_VERBOSITY:-3}\nGETH_DATA_DIR=${GETH_DATA_DIR:-/data}\nRPC_PORT=\"${RPC_PORT:-8545}\"\nW"
  },
  {
    "path": "go.mod",
    "chars": 37,
    "preview": "module dependency_updater\n\ngo 1.24.3\n"
  },
  {
    "path": "nethermind/Dockerfile",
    "chars": 1519,
    "preview": "FROM golang:1.24 AS op\n\nRUN curl -sSfL 'https://just.systems/install.sh' | bash -s -- --to /usr/local/bin\n\nWORKDIR /app\n"
  },
  {
    "path": "nethermind/nethermind-entrypoint",
    "chars": 2029,
    "preview": "#!/bin/bash\nset -eu\n\n# Default configurations\nNETHERMIND_DATA_DIR=${NETHERMIND_DATA_DIR:-/data}\nNETHERMIND_LOG_LEVEL=${N"
  },
  {
    "path": "op-node-entrypoint",
    "chars": 1334,
    "preview": "#!/bin/bash\nset -eu\n\nget_public_ip() {\n  # Define a list of HTTP-based providers\n  local PROVIDERS=(\n    \"http://ifconfi"
  },
  {
    "path": "reth/Dockerfile",
    "chars": 1412,
    "preview": "FROM golang:1.24 AS op\n\nRUN curl -sSfL 'https://just.systems/install.sh' | bash -s -- --to /usr/local/bin\n\nWORKDIR /app\n"
  },
  {
    "path": "reth/README.md",
    "chars": 1502,
    "preview": "# Running a Reth Node\n\nThis is an implementation of the Reth node setup that supports Flashblocks mode based on configur"
  },
  {
    "path": "reth/reth-entrypoint",
    "chars": 4344,
    "preview": "#!/bin/bash\nset -eu\n\nIPC_PATH=\"/data/reth.ipc\"\nRETH_DATA_DIR=/data\nRPC_PORT=\"${RPC_PORT:-8545}\"\nWS_PORT=\"${WS_PORT:-8546"
  },
  {
    "path": "supervisord.conf",
    "chars": 352,
    "preview": "[supervisord]\nnodaemon=true\nlogfile=/dev/null\nlogfile_maxbytes=0\n\n[program:op-node]\ncommand=/app/op-node-entrypoint\nstdo"
  },
  {
    "path": "versions.env",
    "chars": 659,
    "preview": "export BASE_RETH_NODE_COMMIT=6e54e8cbcbd27cb86bde54d3a5b0e9b4e9ea960a\nexport BASE_RETH_NODE_REPO=https://github.com/base"
  },
  {
    "path": "versions.json",
    "chars": 816,
    "preview": "{\n\t  \"base_reth_node\": {\n\t  \t  \"tag\": \"v0.5.1\",\n\t  \t  \"commit\": \"6e54e8cbcbd27cb86bde54d3a5b0e9b4e9ea960a\",\n\t  \t  \"owner"
  }
]

About this extraction

This page contains the full source code of the base/node GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 28 files (73.0 KB), approximately 23.3k tokens, and a symbol index with 27 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!