├── .dockerignore ├── .env ├── .env.mainnet ├── .env.sepolia ├── .github └── workflows │ ├── docker.yml │ └── pr.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── dependency_updater ├── dependency_updater.go ├── go.mod └── go.sum ├── docker-compose.yml ├── geth ├── Dockerfile └── geth-entrypoint ├── go.mod ├── logo.webp ├── nethermind ├── Dockerfile └── nethermind-entrypoint ├── op-node-entrypoint ├── reth ├── Dockerfile ├── README.md └── reth-entrypoint ├── supervisord.conf ├── versions.env └── versions.json /.dockerignore: -------------------------------------------------------------------------------- 1 | geth-data/ 2 | reth-data/ 3 | nethermind-data/ 4 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | CLIENT=${CLIENT:-geth} 2 | HOST_DATA_DIR=./${CLIENT}-data -------------------------------------------------------------------------------- /.env.mainnet: -------------------------------------------------------------------------------- 1 | # BASE MAINNET NODE CONFIGURATION 2 | # =========================== 3 | 4 | # NETWORK CONFIGURATION 5 | # -------------------- 6 | RETH_CHAIN=base 7 | OP_NODE_NETWORK=base-mainnet 8 | OP_GETH_OP_NETWORK=base-mainnet 9 | 10 | # BASE SEQUENCER ENDPOINTS 11 | # ----------------------- 12 | RETH_SEQUENCER_HTTP=https://mainnet-sequencer.base.org 13 | OP_SEQUENCER_HTTP=https://mainnet-sequencer.base.org 14 | OP_GETH_SEQUENCER_HTTP=https://mainnet-sequencer.base.org 15 | OP_RETH_SEQUENCER_HTTP=https://mainnet-sequencer.base.org 16 | 17 | # SYNC CONFIGURATION 18 | # ----------------- 19 | OP_NODE_SYNCMODE=execution-layer 20 | OP_NODE_VERIFIER_L1_CONFS=4 21 | OP_NODE_ROLLUP_LOAD_PROTOCOL_VERSIONS=true 22 | 23 | # [REQUIRED] L1 CONFIGURATION 24 | # -------------------------- 25 | # Replace these values with your L1 (Ethereum) node endpoints 26 | OP_NODE_L1_ETH_RPC= 27 | OP_NODE_L1_BEACON= 28 | OP_NODE_L1_BEACON_ARCHIVER= 29 | OP_NODE_L1_BEACON_FETCH_ALL_SIDECARS="true" 30 | OP_NODE_L1_RPC_KIND="debug_geth" 31 | OP_NODE_L1_TRUST_RPC="false" 32 | 33 | # ENGINE CONFIGURATION 34 | # ------------------- 35 | OP_NODE_L2_ENGINE_KIND=reth 36 | OP_NODE_L2_ENGINE_RPC=ws://execution:8551 37 | OP_NODE_L2_ENGINE_AUTH=/tmp/engine-auth-jwt 38 | OP_NODE_L2_ENGINE_AUTH_RAW=688f5d737bad920bdfb2fc2f488d6b6209eebda1dae949a8de91398d932c517a 39 | 40 | # P2P CONFIGURATION 41 | # --------------- 42 | OP_NODE_P2P_AGENT=base 43 | OP_NODE_P2P_LISTEN_IP=0.0.0.0 44 | OP_NODE_P2P_LISTEN_TCP_PORT=9222 45 | OP_NODE_P2P_LISTEN_UDP_PORT=9222 46 | OP_NODE_INTERNAL_IP="true" 47 | OP_NODE_P2P_BOOTNODES=enr:-J24QNz9lbrKbN4iSmmjtnr7SjUMk4zB7f1krHZcTZx-JRKZd0kA2gjufUROD6T3sOWDVDnFJRvqBBo62zuF-hYCohOGAYiOoEyEgmlkgnY0gmlwhAPniryHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQKNVFlCxh_B-716tTs-h1vMzZkSs1FTu_OYTNjgufplG4N0Y3CCJAaDdWRwgiQG,enr:-J24QH-f1wt99sfpHy4c0QJM-NfmsIfmlLAMMcgZCUEgKG_BBYFc6FwYgaMJMQN5dsRBJApIok0jFn-9CS842lGpLmqGAYiOoDRAgmlkgnY0gmlwhLhIgb2Hb3BzdGFja4OFQgCJc2VjcDI1NmsxoQJ9FTIv8B9myn1MWaC_2lJ-sMoeCDkusCsk4BYHjjCq04N0Y3CCJAaDdWRwgiQG,enr:-J24QDXyyxvQYsd0yfsN0cRr1lZ1N11zGTplMNlW4xNEc7LkPXh0NAJ9iSOVdRO95GPYAIc6xmyoCCG6_0JxdL3a0zaGAYiOoAjFgmlkgnY0gmlwhAPckbGHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQJwoS7tzwxqXSyFL7g0JM-KWVbgvjfB8JA__T7yY_cYboN0Y3CCJAaDdWRwgiQG,enr:-J24QHmGyBwUZXIcsGYMaUqGGSl4CFdx9Tozu-vQCn5bHIQbR7On7dZbU61vYvfrJr30t0iahSqhc64J46MnUO2JvQaGAYiOoCKKgmlkgnY0gmlwhAPnCzSHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQINc4fSijfbNIiGhcgvwjsjxVFJHUstK9L1T8OTKUjgloN0Y3CCJAaDdWRwgiQG,enr:-J24QG3ypT4xSu0gjb5PABCmVxZqBjVw9ca7pvsI8jl4KATYAnxBmfkaIuEqy9sKvDHKuNCsy57WwK9wTt2aQgcaDDyGAYiOoGAXgmlkgnY0gmlwhDbGmZaHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQIeAK_--tcLEiu7HvoUlbV52MspE0uCocsx1f_rYvRenIN0Y3CCJAaDdWRwgiQG 48 | 49 | # RETH CONFIGURATION 50 | # ---------------- 51 | OP_RETH_DISABLE_DISCOVERY="false" 52 | OP_RETH_DISABLE_TX_POOL_GOSSIP="true" 53 | OP_RETH_OP_NETWORK="base" 54 | 55 | # RPC CONFIGURATION 56 | # --------------- 57 | OP_NODE_RPC_ADDR=0.0.0.0 58 | OP_NODE_RPC_PORT=8545 59 | 60 | # GETH CACHE SETTINGS 61 | # ----------------- 62 | GETH_CACHE="20480" # 20GB 63 | GETH_CACHE_DATABASE="20" # 4GB 64 | GETH_CACHE_GC="12" 65 | GETH_CACHE_SNAPSHOT="24" 66 | GETH_CACHE_TRIE="44" 67 | OP_GETH_NET_RESTRICT="10.0.0.0/8" 68 | 69 | # LOGGING & MONITORING 70 | # ------------------ 71 | OP_NODE_LOG_LEVEL=info 72 | OP_NODE_LOG_FORMAT="json" 73 | OP_NODE_SNAPSHOT_LOG=/tmp/op-node-snapshot-log 74 | OP_NODE_METRICS_ENABLED="true" 75 | OP_NODE_METRICS_ADDR=0.0.0.0 76 | OP_NODE_METRICS_PORT="7300" 77 | STATSD_ADDRESS="172.17.0.1" 78 | 79 | # OPTIONAL SETTINGS 80 | # =============== 81 | 82 | # ETHSTATS MONITORING (OPTIONAL - UNCOMMENT TO ENABLE) 83 | # OP_GETH_ETH_STATS=nodename:secret@host:port 84 | # OP_NETHERMIND_ETHSTATS_ENABLED=true 85 | # OP_NETHERMIND_ETHSTATS_NODE_NAME=NethermindNode 86 | # OP_NETHERMIND_ETHSTATS_ENDPOINT=ethstats_endpoint 87 | 88 | # TRUSTED RPC MODE (OPTIONAL - UNCOMMENT TO ENABLE) 89 | # OP_NODE_L1_TRUST_RPC=true 90 | 91 | # SNAP SYNC (OPTIONAL EXPERIMENTAL FEATURE - UNCOMMENT TO ENABLE) 92 | # NOTE: This feature is experimental and may lead to syncing issues 93 | # OP_GETH_BOOTNODES=enode://87a32fd13bd596b2ffca97020e31aef4ddcc1bbd4b95bb633d16c1329f654f34049ed240a36b449fda5e5225d70fe40bc667f53c304b71f8e68fc9d448690b51@3.231.138.188:30301,enode://ca21ea8f176adb2e229ce2d700830c844af0ea941a1d8152a9513b966fe525e809c3a6c73a2c18a12b74ed6ec4380edf91662778fe0b79f6a591236e49e176f9@184.72.129.189:30301,enode://acf4507a211ba7c1e52cdf4eef62cdc3c32e7c9c47998954f7ba024026f9a6b2150cd3f0b734d9c78e507ab70d59ba61dfe5c45e1078c7ad0775fb251d7735a2@3.220.145.177:30301,enode://8a5a5006159bf079d06a04e5eceab2a1ce6e0f721875b2a9c96905336219dbe14203d38f70f3754686a6324f786c2f9852d8c0dd3adac2d080f4db35efc678c5@3.231.11.52:30301,enode://cdadbe835308ad3557f9a1de8db411da1a260a98f8421d62da90e71da66e55e98aaa8e90aa7ce01b408a54e4bd2253d701218081ded3dbe5efbbc7b41d7cef79@54.198.153.150:30301 94 | # OP_NETHERMIND_BOOTNODES=enode://87a32fd13bd596b2ffca97020e31aef4ddcc1bbd4b95bb633d16c1329f654f34049ed240a36b449fda5e5225d70fe40bc667f53c304b71f8e68fc9d448690b51@3.231.138.188:30301,enode://ca21ea8f176adb2e229ce2d700830c844af0ea941a1d8152a9513b966fe525e809c3a6c73a2c18a12b74ed6ec4380edf91662778fe0b79f6a591236e49e176f9@184.72.129.189:30301,enode://acf4507a211ba7c1e52cdf4eef62cdc3c32e7c9c47998954f7ba024026f9a6b2150cd3f0b734d9c78e507ab70d59ba61dfe5c45e1078c7ad0775fb251d7735a2@3.220.145.177:30301,enode://8a5a5006159bf079d06a04e5eceab2a1ce6e0f721875b2a9c96905336219dbe14203d38f70f3754686a6324f786c2f9852d8c0dd3adac2d080f4db35efc678c5@3.231.11.52:30301,enode://cdadbe835308ad3557f9a1de8db411da1a260a98f8421d62da90e71da66e55e98aaa8e90aa7ce01b408a54e4bd2253d701218081ded3dbe5efbbc7b41d7cef79@54.198.153.150:30301 95 | # OP_GETH_SYNCMODE=snap 96 | 97 | # FLASHBLOCKS (OPTIONAL - UNCOMMENT TO ENABLE) 98 | # RETH_FB_WEBSOCKET_URL=wss://mainnet.flashblocks.base.org/ws 99 | -------------------------------------------------------------------------------- /.env.sepolia: -------------------------------------------------------------------------------- 1 | # BASE SEPOLIA TESTNET NODE CONFIGURATION 2 | # ================================== 3 | 4 | # NETWORK CONFIGURATION 5 | # -------------------- 6 | RETH_CHAIN=base-sepolia 7 | OP_NODE_NETWORK=base-sepolia 8 | OP_GETH_OP_NETWORK=base-sepolia 9 | 10 | # BASE SEQUENCER ENDPOINTS 11 | # ----------------------- 12 | RETH_SEQUENCER_HTTP=https://sepolia-sequencer.base.org 13 | OP_SEQUENCER_HTTP=https://sepolia-sequencer.base.org 14 | OP_GETH_SEQUENCER_HTTP=https://sepolia-sequencer.base.org 15 | OP_RETH_SEQUENCER_HTTP=https://sepolia-sequencer.base.org 16 | 17 | # SYNC CONFIGURATION 18 | # ----------------- 19 | OP_NODE_SYNCMODE=execution-layer 20 | OP_NODE_VERIFIER_L1_CONFS=4 21 | OP_NODE_ROLLUP_LOAD_PROTOCOL_VERSIONS=true 22 | 23 | # [REQUIRED] L1 CONFIGURATION 24 | # -------------------------- 25 | # Replace these values with your L1 (Ethereum) node endpoints 26 | OP_NODE_L1_ETH_RPC= 27 | OP_NODE_L1_BEACON= 28 | OP_NODE_L1_BEACON_ARCHIVER= 29 | OP_NODE_L1_BEACON_FETCH_ALL_SIDECARS="true" 30 | OP_NODE_L1_RPC_KIND="debug_geth" 31 | OP_NODE_L1_TRUST_RPC="false" 32 | 33 | # ENGINE CONFIGURATION 34 | # ------------------- 35 | OP_NODE_L2_ENGINE_KIND=reth 36 | OP_NODE_L2_ENGINE_RPC=ws://execution:8551 37 | OP_NODE_L2_ENGINE_AUTH=/tmp/engine-auth-jwt 38 | OP_NODE_L2_ENGINE_AUTH_RAW=688f5d737bad920bdfb2fc2f488d6b6209eebda1dae949a8de91398d932c517a 39 | 40 | # P2P CONFIGURATION 41 | # --------------- 42 | OP_NODE_P2P_AGENT=base 43 | OP_NODE_P2P_LISTEN_IP=0.0.0.0 44 | OP_NODE_P2P_LISTEN_TCP_PORT=9222 45 | OP_NODE_P2P_LISTEN_UDP_PORT=9222 46 | OP_NODE_INTERNAL_IP="true" 47 | OP_NODE_P2P_BOOTNODES=enr:-J24QNz9lbrKbN4iSmmjtnr7SjUMk4zB7f1krHZcTZx-JRKZd0kA2gjufUROD6T3sOWDVDnFJRvqBBo62zuF-hYCohOGAYiOoEyEgmlkgnY0gmlwhAPniryHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQKNVFlCxh_B-716tTs-h1vMzZkSs1FTu_OYTNjgufplG4N0Y3CCJAaDdWRwgiQG,enr:-J24QH-f1wt99sfpHy4c0QJM-NfmsIfmlLAMMcgZCUEgKG_BBYFc6FwYgaMJMQN5dsRBJApIok0jFn-9CS842lGpLmqGAYiOoDRAgmlkgnY0gmlwhLhIgb2Hb3BzdGFja4OFQgCJc2VjcDI1NmsxoQJ9FTIv8B9myn1MWaC_2lJ-sMoeCDkusCsk4BYHjjCq04N0Y3CCJAaDdWRwgiQG,enr:-J24QDXyyxvQYsd0yfsN0cRr1lZ1N11zGTplMNlW4xNEc7LkPXh0NAJ9iSOVdRO95GPYAIc6xmyoCCG6_0JxdL3a0zaGAYiOoAjFgmlkgnY0gmlwhAPckbGHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQJwoS7tzwxqXSyFL7g0JM-KWVbgvjfB8JA__T7yY_cYboN0Y3CCJAaDdWRwgiQG,enr:-J24QHmGyBwUZXIcsGYMaUqGGSl4CFdx9Tozu-vQCn5bHIQbR7On7dZbU61vYvfrJr30t0iahSqhc64J46MnUO2JvQaGAYiOoCKKgmlkgnY0gmlwhAPnCzSHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQINc4fSijfbNIiGhcgvwjsjxVFJHUstK9L1T8OTKUjgloN0Y3CCJAaDdWRwgiQG,enr:-J24QG3ypT4xSu0gjb5PABCmVxZqBjVw9ca7pvsI8jl4KATYAnxBmfkaIuEqy9sKvDHKuNCsy57WwK9wTt2aQgcaDDyGAYiOoGAXgmlkgnY0gmlwhDbGmZaHb3BzdGFja4OFQgCJc2VjcDI1NmsxoQIeAK_--tcLEiu7HvoUlbV52MspE0uCocsx1f_rYvRenIN0Y3CCJAaDdWRwgiQG 48 | 49 | # RETH CONFIGURATION 50 | # ---------------- 51 | OP_RETH_DISABLE_DISCOVERY="false" 52 | OP_RETH_DISABLE_TX_POOL_GOSSIP="true" 53 | OP_RETH_OP_NETWORK="base" 54 | 55 | # RPC CONFIGURATION 56 | # --------------- 57 | OP_NODE_RPC_ADDR=0.0.0.0 58 | OP_NODE_RPC_PORT=8545 59 | 60 | # GETH CACHE SETTINGS 61 | # ----------------- 62 | GETH_CACHE="20480" # 20GB 63 | GETH_CACHE_DATABASE="20" # 4GB 64 | GETH_CACHE_GC="12" 65 | GETH_CACHE_SNAPSHOT="24" 66 | GETH_CACHE_TRIE="44" 67 | OP_GETH_NET_RESTRICT="10.0.0.0/8" 68 | 69 | # LOGGING & MONITORING 70 | # ------------------ 71 | OP_NODE_LOG_LEVEL=info 72 | OP_NODE_LOG_FORMAT="json" 73 | OP_NODE_SNAPSHOT_LOG=/tmp/op-node-snapshot-log 74 | OP_NODE_METRICS_ENABLED="true" 75 | OP_NODE_METRICS_ADDR=0.0.0.0 76 | OP_NODE_METRICS_PORT="7300" 77 | STATSD_ADDRESS="172.17.0.1" 78 | 79 | # OPTIONAL SETTINGS 80 | # =============== 81 | 82 | # ETHSTATS MONITORING (OPTIONAL - UNCOMMENT TO ENABLE) 83 | # OP_GETH_ETH_STATS=nodename:secret@host:port 84 | # OP_NETHERMIND_ETHSTATS_ENABLED=true 85 | # OP_NETHERMIND_ETHSTATS_NODE_NAME=NethermindNode 86 | # OP_NETHERMIND_ETHSTATS_ENDPOINT=ethstats_endpoint 87 | 88 | # TRUSTED RPC MODE (OPTIONAL - UNCOMMENT TO ENABLE) 89 | # OP_NODE_L1_TRUST_RPC=true 90 | 91 | # SNAP SYNC (OPTIONAL EXPERIMENTAL FEATURE - UNCOMMENT TO ENABLE) 92 | # NOTE: This feature is experimental and may lead to syncing issues 93 | # OP_GETH_BOOTNODES=enode://87a32fd13bd596b2ffca97020e31aef4ddcc1bbd4b95bb633d16c1329f654f34049ed240a36b449fda5e5225d70fe40bc667f53c304b71f8e68fc9d448690b51@3.231.138.188:30301,enode://ca21ea8f176adb2e229ce2d700830c844af0ea941a1d8152a9513b966fe525e809c3a6c73a2c18a12b74ed6ec4380edf91662778fe0b79f6a591236e49e176f9@184.72.129.189:30301,enode://acf4507a211ba7c1e52cdf4eef62cdc3c32e7c9c47998954f7ba024026f9a6b2150cd3f0b734d9c78e507ab70d59ba61dfe5c45e1078c7ad0775fb251d7735a2@3.220.145.177:30301,enode://8a5a5006159bf079d06a04e5eceab2a1ce6e0f721875b2a9c96905336219dbe14203d38f70f3754686a6324f786c2f9852d8c0dd3adac2d080f4db35efc678c5@3.231.11.52:30301,enode://cdadbe835308ad3557f9a1de8db411da1a260a98f8421d62da90e71da66e55e98aaa8e90aa7ce01b408a54e4bd2253d701218081ded3dbe5efbbc7b41d7cef79@54.198.153.150:30301 94 | # OP_NETHERMIND_BOOTNODES=enode://87a32fd13bd596b2ffca97020e31aef4ddcc1bbd4b95bb633d16c1329f654f34049ed240a36b449fda5e5225d70fe40bc667f53c304b71f8e68fc9d448690b51@3.231.138.188:30301,enode://ca21ea8f176adb2e229ce2d700830c844af0ea941a1d8152a9513b966fe525e809c3a6c73a2c18a12b74ed6ec4380edf91662778fe0b79f6a591236e49e176f9@184.72.129.189:30301,enode://acf4507a211ba7c1e52cdf4eef62cdc3c32e7c9c47998954f7ba024026f9a6b2150cd3f0b734d9c78e507ab70d59ba61dfe5c45e1078c7ad0775fb251d7735a2@3.220.145.177:30301,enode://8a5a5006159bf079d06a04e5eceab2a1ce6e0f721875b2a9c96905336219dbe14203d38f70f3754686a6324f786c2f9852d8c0dd3adac2d080f4db35efc678c5@3.231.11.52:30301,enode://cdadbe835308ad3557f9a1de8db411da1a260a98f8421d62da90e71da66e55e98aaa8e90aa7ce01b408a54e4bd2253d701218081ded3dbe5efbbc7b41d7cef79@54.198.153.150:30301 95 | # OP_GETH_SYNCMODE=snap 96 | 97 | # FLASHBLOCKS (OPTIONAL - UNCOMMENT TO ENABLE) 98 | # RETH_FB_WEBSOCKET_URL=wss://sepolia.flashblocks.base.org/ws 99 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Tag Docker image 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | tags: 8 | - "v*" 9 | 10 | env: 11 | REGISTRY: ghcr.io 12 | NAMESPACE: ghcr.io/base 13 | GETH_DEPRECATED_IMAGE_NAME: node 14 | GETH_IMAGE_NAME: node-geth 15 | RETH_IMAGE_NAME: node-reth 16 | NETHERMIND_IMAGE_NAME: node-nethermind 17 | 18 | permissions: 19 | contents: read 20 | packages: write 21 | 22 | jobs: 23 | geth: 24 | strategy: 25 | matrix: 26 | settings: 27 | - arch: linux/amd64 28 | runs-on: ubuntu-24.04 29 | - arch: linux/arm64 30 | runs-on: ubuntu-24.04-arm 31 | runs-on: ${{ matrix.settings.runs-on }} 32 | steps: 33 | - name: Harden the runner (Audit all outbound calls) 34 | uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 35 | with: 36 | egress-policy: audit 37 | 38 | - name: Checkout 39 | uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 40 | 41 | - name: Log into the Container registry 42 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 43 | with: 44 | registry: ${{ env.REGISTRY }} 45 | username: ${{ github.actor }} 46 | password: ${{ secrets.GITHUB_TOKEN }} 47 | 48 | - name: Extract metadata for the Docker image 49 | id: meta 50 | uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175 # v4.6.0 51 | with: 52 | images: | 53 | ${{ env.NAMESPACE }}/${{ env.GETH_DEPRECATED_IMAGE_NAME }} 54 | ${{ env.NAMESPACE }}/${{ env.GETH_IMAGE_NAME }} 55 | 56 | - name: Set up Docker Buildx 57 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 58 | 59 | - name: Build and push the Docker image 60 | id: build 61 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 62 | with: 63 | context: . 64 | file: geth/Dockerfile 65 | tags: ${{ env.NAMESPACE }}/${{ env.GETH_DEPRECATED_IMAGE_NAME }},${{ env.NAMESPACE }}/${{ env.GETH_IMAGE_NAME }} 66 | labels: ${{ steps.meta.outputs.labels }} 67 | platforms: ${{ matrix.settings.arch }} 68 | outputs: type=image,push-by-digest=true,name-canonical=true,push=true 69 | 70 | - name: Export digest 71 | run: | 72 | mkdir -p ${{ runner.temp }}/digests 73 | digest="${{ steps.build.outputs.digest }}" 74 | touch "${{ runner.temp }}/digests/${digest#sha256:}" 75 | 76 | - name: Prepare 77 | run: | 78 | platform=${{ matrix.settings.arch }} 79 | echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV 80 | 81 | - name: Upload digest 82 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 83 | with: 84 | name: digests-geth-${{ env.PLATFORM_PAIR }} 85 | path: ${{ runner.temp }}/digests/* 86 | if-no-files-found: error 87 | retention-days: 1 88 | reth: 89 | strategy: 90 | matrix: 91 | settings: 92 | - arch: linux/amd64 93 | runs-on: ubuntu-24.04 94 | features: jemalloc,asm-keccak,optimism 95 | - arch: linux/arm64 96 | runs-on: ubuntu-24.04-arm 97 | features: jemalloc,optimism 98 | runs-on: ${{ matrix.settings.runs-on }} 99 | steps: 100 | - name: Harden the runner (Audit all outbound calls) 101 | uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 102 | with: 103 | egress-policy: audit 104 | 105 | - name: Checkout 106 | uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0 107 | 108 | - name: Log into the Container registry 109 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 110 | with: 111 | registry: ${{ env.REGISTRY }} 112 | username: ${{ github.actor }} 113 | password: ${{ secrets.GITHUB_TOKEN }} 114 | 115 | - name: Extract metadata for the Docker image 116 | id: meta 117 | uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175 # v4.6.0 118 | with: 119 | images: | 120 | ${{ env.NAMESPACE }}/${{ env.RETH_IMAGE_NAME }} 121 | 122 | - name: Set up Docker Buildx 123 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 124 | 125 | - name: Build and push the Docker image 126 | id: build 127 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 128 | with: 129 | context: . 130 | file: reth/Dockerfile 131 | tags: ${{ env.NAMESPACE }}/${{ env.RETH_IMAGE_NAME }} 132 | labels: ${{ steps.meta.outputs.labels }} 133 | build-args: | 134 | FEATURES=${{ matrix.settings.features }} 135 | platforms: ${{ matrix.settings.arch }} 136 | outputs: type=image,push-by-digest=true,name-canonical=true,push=true 137 | 138 | - name: Export digest 139 | run: | 140 | mkdir -p ${{ runner.temp }}/digests 141 | digest="${{ steps.build.outputs.digest }}" 142 | touch "${{ runner.temp }}/digests/${digest#sha256:}" 143 | 144 | - name: Prepare 145 | run: | 146 | platform=${{ matrix.settings.arch }} 147 | echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV 148 | 149 | - name: Upload digest 150 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 151 | with: 152 | name: digests-reth-${{ env.PLATFORM_PAIR }} 153 | path: ${{ runner.temp }}/digests/* 154 | if-no-files-found: error 155 | retention-days: 1 156 | 157 | nethermind: 158 | strategy: 159 | matrix: 160 | settings: 161 | - arch: linux/amd64 162 | runs-on: ubuntu-24.04 163 | - arch: linux/arm64 164 | runs-on: ubuntu-24.04-arm 165 | runs-on: ${{ matrix.settings.runs-on }} 166 | steps: 167 | - name: Harden the runner (Audit all outbound calls) 168 | uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 169 | with: 170 | egress-policy: audit 171 | 172 | - name: Checkout 173 | uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2.7.0 174 | 175 | - name: Log into the Container registry 176 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 177 | with: 178 | registry: ${{ env.REGISTRY }} 179 | username: ${{ github.actor }} 180 | password: ${{ secrets.GITHUB_TOKEN }} 181 | 182 | - name: Set up Docker Buildx 183 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 184 | 185 | - name: Extract metadata for the Docker image 186 | id: meta 187 | uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175 # v4.6.0 188 | with: 189 | images: | 190 | ${{ env.NAMESPACE }}/${{ env.NETHERMIND_IMAGE_NAME }} 191 | 192 | - name: Build and push the Docker image 193 | id: build 194 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 195 | with: 196 | context: . 197 | file: nethermind/Dockerfile 198 | tags: ${{ env.NAMESPACE }}/${{ env.NETHERMIND_IMAGE_NAME }} 199 | labels: ${{ steps.meta.outputs.labels }} 200 | platforms: ${{ matrix.settings.arch }} 201 | outputs: type=image,push-by-digest=true,name-canonical=true,push=true 202 | 203 | - name: Export digest 204 | run: | 205 | mkdir -p ${{ runner.temp }}/digests 206 | digest="${{ steps.build.outputs.digest }}" 207 | touch "${{ runner.temp }}/digests/${digest#sha256:}" 208 | 209 | - name: Prepare 210 | run: | 211 | platform=${{ matrix.settings.arch }} 212 | echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV 213 | 214 | - name: Upload digest 215 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 216 | with: 217 | name: digests-nethermind-${{ env.PLATFORM_PAIR }} 218 | path: ${{ runner.temp }}/digests/* 219 | if-no-files-found: error 220 | retention-days: 1 221 | 222 | 223 | merge-geth: 224 | runs-on: ubuntu-latest 225 | needs: 226 | - geth 227 | steps: 228 | - name: Harden the runner (Audit all outbound calls) 229 | uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 230 | with: 231 | egress-policy: audit 232 | 233 | - name: Download digests 234 | uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 235 | with: 236 | path: ${{ runner.temp }}/digests 237 | pattern: digests-geth-* 238 | merge-multiple: true 239 | 240 | - name: Log into the Container registry 241 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 242 | with: 243 | registry: ${{ env.REGISTRY }} 244 | username: ${{ github.actor }} 245 | password: ${{ secrets.GITHUB_TOKEN }} 246 | 247 | - name: Set up Docker Buildx 248 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 249 | 250 | - name: Extract metadata for the Docker image 251 | id: meta 252 | uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 253 | with: 254 | images: | 255 | ${{ env.NAMESPACE }}/${{ env.GETH_DEPRECATED_IMAGE_NAME }} 256 | ${{ env.NAMESPACE }}/${{ env.GETH_IMAGE_NAME }} 257 | 258 | - name: Create manifest list and push 259 | working-directory: ${{ runner.temp }}/digests 260 | run: | 261 | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ 262 | $(printf '${{ env.NAMESPACE }}/${{ env.GETH_DEPRECATED_IMAGE_NAME }}@sha256:%s ' *) 263 | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ 264 | $(printf '${{ env.NAMESPACE }}/${{ env.GETH_IMAGE_NAME }}@sha256:%s ' *) 265 | 266 | - name: Inspect image 267 | run: | 268 | docker buildx imagetools inspect ${{ env.NAMESPACE }}/${{ env.GETH_DEPRECATED_IMAGE_NAME }}:${{ steps.meta.outputs.version }} 269 | docker buildx imagetools inspect ${{ env.NAMESPACE }}/${{ env.GETH_IMAGE_NAME }}:${{ steps.meta.outputs.version }} 270 | 271 | merge-reth: 272 | runs-on: ubuntu-latest 273 | needs: 274 | - reth 275 | steps: 276 | - name: Harden the runner (Audit all outbound calls) 277 | uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 278 | with: 279 | egress-policy: audit 280 | 281 | - name: Download digests 282 | uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 283 | with: 284 | path: ${{ runner.temp }}/digests 285 | pattern: digests-reth-* 286 | merge-multiple: true 287 | 288 | - name: Log into the Container registry 289 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 290 | with: 291 | registry: ${{ env.REGISTRY }} 292 | username: ${{ github.actor }} 293 | password: ${{ secrets.GITHUB_TOKEN }} 294 | 295 | - name: Set up Docker Buildx 296 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 297 | 298 | - name: Extract metadata for the Docker image 299 | id: meta 300 | uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 301 | with: 302 | images: | 303 | ${{ env.NAMESPACE }}/${{ env.RETH_IMAGE_NAME }} 304 | 305 | - name: Create manifest list and push 306 | working-directory: ${{ runner.temp }}/digests 307 | run: | 308 | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ 309 | $(printf '${{ env.NAMESPACE }}/${{ env.RETH_IMAGE_NAME }}@sha256:%s ' *) 310 | 311 | - name: Inspect image 312 | run: | 313 | docker buildx imagetools inspect ${{ env.NAMESPACE }}/${{ env.RETH_IMAGE_NAME }}:${{ steps.meta.outputs.version }} 314 | 315 | merge-nethermind: 316 | runs-on: ubuntu-latest 317 | needs: 318 | - nethermind 319 | steps: 320 | - name: Harden the runner (Audit all outbound calls) 321 | uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 322 | with: 323 | egress-policy: audit 324 | 325 | - name: Download digests 326 | uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 327 | with: 328 | path: ${{ runner.temp }}/digests 329 | pattern: digests-nethermind-* 330 | merge-multiple: true 331 | 332 | - name: Log into the Container registry 333 | uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 334 | with: 335 | registry: ${{ env.REGISTRY }} 336 | username: ${{ github.actor }} 337 | password: ${{ secrets.GITHUB_TOKEN }} 338 | 339 | - name: Set up Docker Buildx 340 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 341 | 342 | - name: Extract metadata for the Docker image 343 | id: meta 344 | uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5.7.0 345 | with: 346 | images: | 347 | ${{ env.NAMESPACE }}/${{ env.NETHERMIND_IMAGE_NAME }} 348 | 349 | - name: Create manifest list and push 350 | working-directory: ${{ runner.temp }}/digests 351 | run: | 352 | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ 353 | $(printf '${{ env.NAMESPACE }}/${{ env.NETHERMIND_IMAGE_NAME }}@sha256:%s ' *) 354 | 355 | - name: Inspect image 356 | run: | 357 | docker buildx imagetools inspect ${{ env.NAMESPACE }}/${{ env.NETHERMIND_IMAGE_NAME }}:${{ steps.meta.outputs.version }} 358 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request 2 | 3 | on: 4 | pull_request: 5 | workflow_dispatch: 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | geth: 12 | strategy: 13 | matrix: 14 | settings: 15 | - arch: linux/amd64 16 | runs-on: ubuntu-24.04 17 | - arch: linux/arm64 18 | runs-on: ubuntu-24.04-arm 19 | runs-on: ${{ matrix.settings.runs-on }} 20 | steps: 21 | - name: Harden the runner (Audit all outbound calls) 22 | uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 23 | with: 24 | egress-policy: audit 25 | 26 | - name: Checkout 27 | uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 28 | with: 29 | ref: ${{ github.event.pull_request.head.sha }} 30 | 31 | - name: Set up Docker Buildx 32 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 33 | 34 | - name: Build the Docker image 35 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 36 | with: 37 | context: . 38 | file: geth/Dockerfile 39 | push: false 40 | platforms: ${{ matrix.settings.arch }} 41 | 42 | reth: 43 | strategy: 44 | matrix: 45 | settings: 46 | - arch: linux/amd64 47 | runs-on: ubuntu-24.04 48 | features: jemalloc,asm-keccak,optimism 49 | - arch: linux/arm64 50 | runs-on: ubuntu-24.04-arm 51 | features: jemalloc,optimism 52 | runs-on: ${{ matrix.settings.runs-on}} 53 | steps: 54 | - name: Harden the runner (Audit all outbound calls) 55 | uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 56 | with: 57 | egress-policy: audit 58 | 59 | - name: Checkout 60 | uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 61 | with: 62 | ref: ${{ github.event.pull_request.head.sha }} 63 | - name: Set up Docker Buildx 64 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 65 | - name: Build the Docker image 66 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 67 | with: 68 | context: . 69 | file: reth/Dockerfile 70 | push: false 71 | build-args: | 72 | FEATURES=${{ matrix.settings.features }} 73 | platforms: ${{ matrix.settings.arch }} 74 | 75 | nethermind: 76 | strategy: 77 | matrix: 78 | settings: 79 | - arch: linux/amd64 80 | runs-on: ubuntu-24.04 81 | - arch: linux/arm64 82 | runs-on: ubuntu-24.04-arm 83 | runs-on: ${{ matrix.settings.runs-on}} 84 | steps: 85 | - name: Harden the runner (Audit all outbound calls) 86 | uses: step-security/harden-runner@002fdce3c6a235733a90a27c80493a3241e56863 # v2.12.1 87 | with: 88 | egress-policy: audit 89 | 90 | - name: Checkout 91 | uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 92 | with: 93 | ref: ${{ github.event.pull_request.head.sha }} 94 | - name: Set up Docker Buildx 95 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 96 | - name: Build the Docker image 97 | uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 98 | with: 99 | context: . 100 | file: nethermind/Dockerfile 101 | push: false 102 | platforms: ${{ matrix.settings.arch }} 103 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /geth-data/ 3 | /reth-data/ 4 | /nethermind-data/ 5 | /dependency_updater/dependency_updater 6 | .DS_Store -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Base Node 2 | 3 | ## Code of Conduct 4 | 5 | All interactions with this project follow our [Code of Conduct][code-of-conduct]. 6 | By participating, you are expected to honor this code. Violators can be banned 7 | from further participation in this project, or potentially all Base and/or 8 | Coinbase 9 | projects. 10 | 11 | [code-of-conduct]: https://github.com/coinbase/code-of-conduct 12 | 13 | ## Bug Reports 14 | 15 | * Ensure your issue [has not already been reported][1]. It may already be fixed! 16 | * Include the steps you carried out to produce the problem. 17 | * Include the behavior you observed along with the behavior you expected, and 18 | why you expected it. 19 | * Include any relevant stack traces or debugging output. 20 | 21 | ## Feature Requests 22 | 23 | We welcome feedback with or without pull requests. If you have an idea for how 24 | to improve the project, great! All we ask is that you take the time to write a 25 | clear and concise explanation of what need you are trying to solve. If you have 26 | thoughts on _how_ it can be solved, include those too! 27 | 28 | The best way to see a feature added, however, is to submit a pull request. 29 | 30 | ## Pull Requests 31 | 32 | * Before creating your pull request, it's usually worth asking if the code 33 | you're planning on writing will actually be considered for merging. You can 34 | do this by [opening an issue][1] and asking. It may also help give the 35 | maintainers context for when the time comes to review your code. 36 | 37 | * Ensure your [commit messages are well-written][2]. This can double as your 38 | pull request message, so it pays to take the time to write a clear message. 39 | 40 | * Add tests for your feature. You should be able to look at other tests for 41 | examples. If you're unsure, don't hesitate to [open an issue][1] and ask! 42 | 43 | * Submit your pull request! 44 | 45 | ## Support Requests 46 | 47 | For security reasons, any communication referencing support tickets for Coinbase 48 | products will be ignored. The request will have its content redacted and will 49 | be locked to prevent further discussion. 50 | 51 | All support requests must be made via [our support team][3]. 52 | 53 | [1]: https://github.com/base/node/issues 54 | [2]: https://medium.com/brigade-engineering/the-secrets-to-great-commit-messages-106fc0a92a25 55 | [3]: https://support.coinbase.com/customer/en/portal/articles/2288496-how-can-i-contact-coinbase-support- 56 | 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-2024 base.org contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Base](logo.webp) 2 | 3 | # Base Node 4 | 5 | Base is a secure, low-cost, developer-friendly Ethereum L2 built on Optimism's [OP Stack](https://stack.optimism.io/). This repository contains Docker builds to run your own node on the Base network. 6 | 7 | [![Website base.org](https://img.shields.io/website-up-down-green-red/https/base.org.svg)](https://base.org) 8 | [![Docs](https://img.shields.io/badge/docs-up-green)](https://docs.base.org/) 9 | [![Discord](https://img.shields.io/discord/1067165013397213286?label=discord)](https://base.org/discord) 10 | [![Twitter Base](https://img.shields.io/twitter/follow/Base?style=social)](https://x.com/Base) 11 | 12 | ## Quick Start 13 | 14 | 1. Ensure you have an Ethereum L1 full node RPC available 15 | 2. Choose your network: 16 | - For mainnet: Use `.env.mainnet` 17 | - For testnet: Use `.env.sepolia` 18 | 3. Configure your L1 endpoints in the appropriate `.env` file: 19 | ```bash 20 | OP_NODE_L1_ETH_RPC= 21 | OP_NODE_L1_BEACON= 22 | OP_NODE_L1_BEACON_ARCHIVER= 23 | ``` 24 | 4. Start the node: 25 | 26 | ```bash 27 | # For mainnet (default): 28 | docker compose up --build 29 | 30 | # For testnet: 31 | NETWORK_ENV=.env.sepolia docker compose up --build 32 | 33 | # To use a specific client (optional): 34 | CLIENT=reth docker compose up --build 35 | 36 | # For testnet with a specific client: 37 | NETWORK_ENV=.env.sepolia CLIENT=reth docker compose up --build 38 | ``` 39 | 40 | ### Supported Clients 41 | 42 | - `geth` (default) 43 | - `reth` 44 | - `nethermind` 45 | 46 | ## Requirements 47 | 48 | ### Minimum Requirements 49 | 50 | - Modern Multicore CPU 51 | - 32GB RAM (64GB Recommended) 52 | - NVMe SSD drive 53 | - Storage: (2 \* [current chain size](https://base.org/stats) + [snapshot size](https://basechaindata.vercel.app) + 20% buffer (to accomodate future growth) 54 | - Docker and Docker Compose 55 | 56 | ### Production Hardware Specifications 57 | 58 | The following are the hardware specifications we use in production: 59 | 60 | #### Geth Full Node 61 | 62 | - **Instance**: AWS i4i.12xlarge 63 | - **Storage**: RAID 0 of all local NVMe drives (`/dev/nvme*`) 64 | - **Filesystem**: ext4 65 | 66 | #### Reth Archive Node 67 | 68 | - **Instance**: AWS i7ie.6xlarge 69 | - **Storage**: RAID 0 of all local NVMe drives (`/dev/nvme*`) 70 | - **Filesystem**: ext4 71 | 72 | [!NOTE] 73 | To run the node using a supported client, you can use the following command: 74 | `CLIENT=supported_client docker compose up --build` 75 | 76 | Supported clients: 77 | - geth 78 | - reth (with Flashblocks support option, see [Reth Node README](./reth/README.md)) 79 | - nethermind 80 | 81 | ## Configuration 82 | 83 | ### Required Settings 84 | 85 | - L1 Configuration: 86 | - `OP_NODE_L1_ETH_RPC`: Your Ethereum L1 node RPC endpoint 87 | - `OP_NODE_L1_BEACON`: Your L1 beacon node endpoint 88 | - `OP_NODE_L1_BEACON_ARCHIVER`: Your L1 beacon archiver endpoint 89 | - `OP_NODE_L1_RPC_KIND`: The type of RPC provider being used (default: "debug_geth"). Supported values: 90 | - `alchemy`: Alchemy RPC provider 91 | - `quicknode`: QuickNode RPC provider 92 | - `infura`: Infura RPC provider 93 | - `parity`: Parity RPC provider 94 | - `nethermind`: Nethermind RPC provider 95 | - `debug_geth`: Debug Geth RPC provider 96 | - `erigon`: Erigon RPC provider 97 | - `basic`: Basic RPC provider (standard receipt fetching only) 98 | - `any`: Any available RPC method 99 | - `standard`: Standard RPC methods including newer optimized methods 100 | 101 | ### Network Settings 102 | 103 | - Mainnet: 104 | - `RETH_CHAIN=base` 105 | - `OP_NODE_NETWORK=base-mainnet` 106 | - Sequencer: `https://mainnet-sequencer.base.org` 107 | 108 | ### Performance Settings 109 | 110 | - Cache Settings: 111 | - `GETH_CACHE="20480"` (20GB) 112 | - `GETH_CACHE_DATABASE="20"` (4GB) 113 | - `GETH_CACHE_GC="12"` 114 | - `GETH_CACHE_SNAPSHOT="24"` 115 | - `GETH_CACHE_TRIE="44"` 116 | 117 | ### Optional Features 118 | 119 | - EthStats Monitoring (uncomment to enable) 120 | - Trusted RPC Mode (uncomment to enable) 121 | - Snap Sync (experimental) 122 | 123 | For full configuration options, see the `.env.mainnet` file. 124 | 125 | ## Snapshots 126 | 127 | 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. 128 | 129 | ## Supported Networks 130 | 131 | | Network | Status | 132 | | ------- | ------ | 133 | | Mainnet | ✅ | 134 | | Testnet | ✅ | 135 | 136 | ## Troubleshooting 137 | 138 | For support please join our [Discord](https://discord.gg/buildonbase) post in `🛠|node-operators`. You can alternatively open a new GitHub issue. 139 | 140 | ## Disclaimer 141 | 142 | 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. 143 | 144 | For more information, visit [docs.base.org](https://docs.base.org/). 145 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | ## Bug bounty program 4 | 5 | In line with our strategy of being the safest way for users to access crypto: 6 | 7 | + Coinbase will be extending our [best-in-industry][1] million-dollar [HackerOne bug bounty program][2] 8 | to cover the Base network, the Base bridge contracts, and Base infrastructure. 9 | 10 | + Coinbase will be working in tandem with OP Labs to harden the security 11 | guarantees of Bedrock and accelerate the timeline for decentralized 12 | fault-proofs on the [OP Stack][3]. 13 | 14 | + Coinbase's bug bounty program will run alongside Optimism's existing [Immunefi Bedrock bounty program][4] 15 | to support the open source [Bedrock][5] OP Stack framework. 16 | 17 | ## Reporting vulnerabilities 18 | 19 | All potential vulnerability reports can be submitted via the [HackerOne][6] 20 | platform. 21 | 22 | The HackerOne platform allows us to have a centralized and single reporting 23 | source for us to deliver optimized SLA's and results. All reports submitted to 24 | the platform are triaged around the clock by our team of Coinbase engineers 25 | with domain knowledge, ensuring the best quality of review. 26 | 27 | For more information on reporting vulnerabilities and our HackerOne bug bounty 28 | program, view our [security program policies][7]. 29 | 30 | [1]: https://www.coinbase.com/blog/celebrating-10-years-of-our-bug-bounty-program 31 | [2]: https://hackerone.com/coinbase?type=team 32 | [3]: https://stack.optimism.io/ 33 | [4]: https://immunefi.com/bounty/optimism/ 34 | [5]: https://stack.optimism.io/docs/releases/bedrock/ 35 | [6]: https://hackerone.com/coinbase 36 | [7]: https://hackerone.com/coinbase?view_policy=true 37 | 38 | 39 | -------------------------------------------------------------------------------- /dependency_updater/dependency_updater.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/ethereum-optimism/optimism/op-service/retry" 8 | "github.com/google/go-github/v72/github" 9 | "github.com/urfave/cli/v3" 10 | "slices" 11 | "time" 12 | 13 | "log" 14 | "os" 15 | "strings" 16 | ) 17 | 18 | type Info struct { 19 | RepoUrl string `json:"repoUrl"` 20 | Tag string `json:"tag"` 21 | Commit string `json:"commit"` 22 | CommitUrl string `json:"commitUrl"` 23 | VersionUrl string `json:"versionUrl"` 24 | TagPrefix string `json:"tagPrefix,omitempty"` 25 | Owner string `json:"owner` 26 | Repo string `json:"repo` 27 | } 28 | 29 | type VersionTag []struct { 30 | Tag string `json:"tag_name"` 31 | } 32 | 33 | type Commit struct { 34 | Commit string `json:"sha"` 35 | } 36 | 37 | type Dependencies = map[string]*Info 38 | 39 | func main() { 40 | cmd := &cli.Command{ 41 | Name: "updater", 42 | Usage: "Updates the dependencies in the geth, nethermind and reth Dockerfiles", 43 | Flags: []cli.Flag{ 44 | &cli.StringFlag{ 45 | Name: "token", 46 | Usage: "Auth token used to make requests to the Github API must be set using export", 47 | Sources: cli.EnvVars("GITHUB_TOKEN"), 48 | Required: true, 49 | }, 50 | &cli.StringFlag{ 51 | Name: "repo", 52 | Usage: "Specifies repo location to run the version updater on", 53 | Required: true, 54 | }, 55 | }, 56 | Action: func(ctx context.Context, cmd *cli.Command) error { 57 | err := updater(string(cmd.String("token")), string(cmd.String("repo"))) 58 | if err != nil { 59 | return fmt.Errorf("error running updater: %s", err) 60 | } 61 | return nil 62 | }, 63 | } 64 | 65 | if err := cmd.Run(context.Background(), os.Args); err != nil { 66 | log.Fatal(err) 67 | } 68 | } 69 | 70 | func updater(token string, repoPath string) error { 71 | var err error 72 | 73 | f, err := os.ReadFile(repoPath + "/versions.json") 74 | if err != nil { 75 | return fmt.Errorf("error reading versions JSON: %s", err) 76 | } 77 | 78 | client := github.NewClient(nil).WithAuthToken(token) 79 | ctx := context.Background() 80 | 81 | var dependencies Dependencies 82 | 83 | err = json.Unmarshal(f, &dependencies) 84 | if err != nil { 85 | return fmt.Errorf("error unmarshaling versions JSON to dependencies: %s", err) 86 | } 87 | 88 | for dependency := range dependencies { 89 | err := retry.Do0(context.Background(), 3, retry.Fixed(1*time.Second), func() error { 90 | return getAndUpdateDependency( 91 | ctx, 92 | client, 93 | dependency, 94 | repoPath, 95 | dependencies, 96 | ) 97 | }) 98 | 99 | if err != nil { 100 | return fmt.Errorf("error getting and updating version/commit for "+dependency+": %s", err) 101 | } 102 | } 103 | 104 | e := createVersionsEnv(repoPath, dependencies) 105 | if e != nil { 106 | return fmt.Errorf("error creating versions.env: %s", e) 107 | } 108 | 109 | return nil 110 | } 111 | 112 | func getAndUpdateDependency(ctx context.Context, client *github.Client, dependencyType string, repoPath string, dependencies Dependencies) error { 113 | version, commit, err := getVersionAndCommit(ctx, client, dependencies, dependencyType) 114 | if err != nil { 115 | return err 116 | } 117 | 118 | e := updateVersionTagAndCommit(commit, version, dependencyType, repoPath, dependencies) 119 | if e != nil { 120 | return fmt.Errorf("error updating version tag and commit: %s", e) 121 | } 122 | 123 | return nil 124 | } 125 | 126 | func getVersionAndCommit(ctx context.Context, client *github.Client, dependencies Dependencies, dependencyType string) (string, string, error) { 127 | 128 | var version *github.RepositoryRelease 129 | var err error 130 | // handle dependencies with prefix 131 | releases, _, err := client.Repositories.ListReleases( 132 | ctx, 133 | dependencies[dependencyType].Owner, 134 | dependencies[dependencyType].Repo, 135 | nil) 136 | 137 | if err != nil { 138 | return "", "", fmt.Errorf("error getting releases: %s", err) 139 | } 140 | 141 | if dependencies[dependencyType].TagPrefix == "" { 142 | version = releases[0] 143 | } else { 144 | for release := range releases { 145 | if strings.HasPrefix(*releases[release].TagName, dependencies[dependencyType].TagPrefix) { 146 | version = releases[release] 147 | break 148 | } 149 | } 150 | } 151 | 152 | commit, _, err := client.Repositories.GetCommit( 153 | ctx, 154 | dependencies[dependencyType].Owner, 155 | dependencies[dependencyType].Repo, 156 | "refs/tags/"+*version.TagName, 157 | &github.ListOptions{}) 158 | if err != nil { 159 | return "", "", fmt.Errorf("error getting commit for "+dependencyType+": %s", err) 160 | } 161 | 162 | return *version.TagName, *commit.SHA, nil 163 | } 164 | 165 | func updateVersionTagAndCommit( 166 | commit string, 167 | tag string, 168 | dependencyType string, 169 | repoPath string, 170 | dependencies Dependencies) error { 171 | dependencies[dependencyType].Tag = tag 172 | dependencies[dependencyType].Commit = commit 173 | err := writeToVersionsEnv(repoPath, dependencies) 174 | if err != nil { 175 | return fmt.Errorf("error writing to versions "+dependencyType+": %s", err) 176 | } 177 | return nil 178 | } 179 | 180 | func writeToVersionsEnv(repoPath string, dependencies Dependencies) error { 181 | // formatting json 182 | updatedJson, err := json.MarshalIndent(dependencies, "", " ") 183 | if err != nil { 184 | return fmt.Errorf("error Marshaling dependencies json: %s", err) 185 | } 186 | 187 | e := os.WriteFile(repoPath+"/versions.json", updatedJson, 0644) 188 | if e != nil { 189 | return fmt.Errorf("error writing to versions.json: %s", e) 190 | } 191 | 192 | return nil 193 | } 194 | 195 | func createVersionsEnv(repoPath string, dependencies Dependencies) error { 196 | envLines := []string{} 197 | 198 | for dependency := range dependencies { 199 | dependencyPrefix := strings.ToUpper(dependency) 200 | 201 | envLines = append(envLines, fmt.Sprintf("export %s_%s=%s", 202 | dependencyPrefix, "TAG", dependencies[dependency].Tag)) 203 | 204 | envLines = append(envLines, fmt.Sprintf("export %s_%s=%s", 205 | dependencyPrefix, "COMMIT", dependencies[dependency].Commit)) 206 | 207 | envLines = append(envLines, fmt.Sprintf("export %s_%s=%s", 208 | dependencyPrefix, "REPO", dependencies[dependency].RepoUrl)) 209 | } 210 | 211 | slices.Sort(envLines) 212 | 213 | file, err := os.Create(repoPath + "/versions.env") 214 | if err != nil { 215 | return fmt.Errorf("error creating versions.env file: %s", err) 216 | } 217 | defer file.Close() 218 | 219 | _, err = file.WriteString(strings.Join(envLines, "\n")) 220 | if err != nil { 221 | return fmt.Errorf("error writing to versions.env file: %s", err) 222 | } 223 | 224 | return nil 225 | } 226 | -------------------------------------------------------------------------------- /dependency_updater/go.mod: -------------------------------------------------------------------------------- 1 | module dependency_updater 2 | 3 | go 1.24.3 4 | 5 | require ( 6 | github.com/ethereum-optimism/optimism v1.13.3 7 | github.com/google/go-github/v72 v72.0.0 8 | github.com/urfave/cli/v3 v3.3.8 9 | ) 10 | 11 | require github.com/google/go-querystring v1.1.0 // indirect 12 | -------------------------------------------------------------------------------- /dependency_updater/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 2 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/ethereum-optimism/optimism v1.13.3 h1:rfPx7OembMnoEASU1ozA/Foa7Am7UA+h0SB+OUrxn7s= 4 | github.com/ethereum-optimism/optimism v1.13.3/go.mod h1:WrVFtk3cP45tvHs7MARn9KGQu35XIoXo/IOWU6K/rzk= 5 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 6 | github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 7 | github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 8 | github.com/google/go-github/v72 v72.0.0 h1:FcIO37BLoVPBO9igQQ6tStsv2asG4IPcYFi655PPvBM= 9 | github.com/google/go-github/v72 v72.0.0/go.mod h1:WWtw8GMRiL62mvIquf1kO3onRHeWWKmK01qdCY8c5fg= 10 | github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= 11 | github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= 12 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 13 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 14 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 15 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 16 | github.com/urfave/cli/v3 v3.3.8 h1:BzolUExliMdet9NlJ/u4m5vHSotJ3PzEqSAZ1oPMa/E= 17 | github.com/urfave/cli/v3 v3.3.8/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= 18 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 19 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 20 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 21 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | execution: 3 | build: 4 | context: . 5 | dockerfile: ${CLIENT:-geth}/Dockerfile 6 | ports: 7 | - "8545:8545" # RPC 8 | - "8546:8546" # websocket 9 | - "7301:6060" # metrics 10 | - "30303:30303" # P2P TCP 11 | - "30303:30303/udp" # P2P UDP 12 | command: ["bash", "./execution-entrypoint"] 13 | volumes: 14 | - ${HOST_DATA_DIR}:/data 15 | environment: 16 | - NODE_TYPE=${NODE_TYPE:-vanilla} 17 | env_file: 18 | - ${NETWORK_ENV:-.env.mainnet} # Use .env.mainnet by default, override with .env.sepolia for testnet 19 | node: 20 | build: 21 | context: . 22 | dockerfile: ${CLIENT:-geth}/Dockerfile 23 | depends_on: 24 | - execution 25 | ports: 26 | - "7545:8545" # RPC 27 | - "9222:9222" # P2P TCP 28 | - "9222:9222/udp" # P2P UDP 29 | - "7300:7300" # metrics 30 | - "6060:6060" # pprof 31 | command: ["bash", "./op-node-entrypoint"] 32 | env_file: 33 | - ${NETWORK_ENV:-.env.mainnet} # Use .env.mainnet by default, override with .env.sepolia for testnet 34 | -------------------------------------------------------------------------------- /geth/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.23 AS op 2 | 3 | RUN curl -sSfL 'https://just.systems/install.sh' | bash -s -- --to /usr/local/bin 4 | 5 | WORKDIR /app 6 | 7 | COPY versions.env /tmp/versions.env 8 | 9 | RUN . /tmp/versions.env && git clone $OP_NODE_REPO --branch $OP_NODE_TAG --single-branch . && \ 10 | git switch -c branch-$OP_NODE_TAG && \ 11 | bash -c '[ "$(git rev-parse HEAD)" = "$OP_NODE_COMMIT" ]' 12 | 13 | RUN . /tmp/versions.env && cd op-node && \ 14 | make VERSION=$OP_NODE_TAG op-node 15 | 16 | FROM golang:1.23 AS geth 17 | 18 | WORKDIR /app 19 | 20 | COPY versions.env /tmp/versions.env 21 | 22 | RUN . /tmp/versions.env && git clone $OP_GETH_REPO --branch $OP_GETH_TAG --single-branch . && \ 23 | git switch -c branch-$OP_GETH_TAG && \ 24 | bash -c '[ "$(git rev-parse HEAD)" = "$OP_GETH_COMMIT" ]' 25 | 26 | RUN go run build/ci.go install -static ./cmd/geth 27 | 28 | FROM ubuntu:22.04 29 | 30 | RUN apt-get update && \ 31 | apt-get install -y jq curl supervisor && \ 32 | rm -rf /var/lib/apt/lists 33 | RUN mkdir -p /var/log/supervisor 34 | 35 | WORKDIR /app 36 | 37 | COPY --from=op /app/op-node/bin/op-node ./ 38 | COPY --from=geth /app/build/bin/geth ./ 39 | COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf 40 | COPY geth/geth-entrypoint ./execution-entrypoint 41 | COPY op-node-entrypoint . 42 | 43 | CMD ["/usr/bin/supervisord"] 44 | -------------------------------------------------------------------------------- /geth/geth-entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu 3 | 4 | VERBOSITY=${GETH_VERBOSITY:-3} 5 | GETH_DATA_DIR=${GETH_DATA_DIR:-/data} 6 | RPC_PORT="${RPC_PORT:-8545}" 7 | WS_PORT="${WS_PORT:-8546}" 8 | AUTHRPC_PORT="${AUTHRPC_PORT:-8551}" 9 | METRICS_PORT="${METRICS_PORT:-6060}" 10 | HOST_IP="" # put your external IP address here and open port 30303 to improve peer connectivity 11 | P2P_PORT="${P2P_PORT:-30303}" 12 | ADDITIONAL_ARGS="" 13 | OP_GETH_GCMODE="${OP_GETH_GCMODE:-full}" 14 | OP_GETH_SYNCMODE="${OP_GETH_SYNCMODE:-full}" 15 | 16 | # Add cache and txpool optimizations with defaults 17 | GETH_CACHE="${GETH_CACHE:-20480}" 18 | GETH_CACHE_DATABASE="${GETH_CACHE_DATABASE:-20}" 19 | GETH_CACHE_GC="${GETH_CACHE_GC:-12}" 20 | GETH_CACHE_SNAPSHOT="${GETH_CACHE_SNAPSHOT:-24}" 21 | GETH_CACHE_TRIE="${GETH_CACHE_TRIE:-44}" 22 | GETH_TXPOOL_GLOBALQUEUE="${GETH_TXPOOL_GLOBALQUEUE:-6144}" 23 | GETH_TXPOOL_GLOBALSLOTS="${GETH_TXPOOL_GLOBALSLOTS:-30072}" 24 | GETH_TXPOOL_LIFETIME="${GETH_TXPOOL_LIFETIME:-10m}" 25 | TXPOOL_PRICE_LIMIT="${TXPOOL_PRICE_LIMIT:-50}" 26 | 27 | if [[ -z "$OP_NODE_NETWORK" ]]; then 28 | echo "expected OP_NODE_NETWORK to be set" 1>&2 29 | exit 1 30 | fi 31 | 32 | mkdir -p $GETH_DATA_DIR 33 | 34 | echo "$OP_NODE_L2_ENGINE_AUTH_RAW" > "$OP_NODE_L2_ENGINE_AUTH" 35 | 36 | if [ "${OP_GETH_ETH_STATS+x}" = x ]; then 37 | ADDITIONAL_ARGS="$ADDITIONAL_ARGS --ethstats=$OP_GETH_ETH_STATS" 38 | fi 39 | 40 | if [ "${OP_GETH_ALLOW_UNPROTECTED_TXS+x}" = x ]; then 41 | ADDITIONAL_ARGS="$ADDITIONAL_ARGS --rpc.allow-unprotected-txs=$OP_GETH_ALLOW_UNPROTECTED_TXS" 42 | fi 43 | 44 | if [ "${OP_GETH_STATE_SCHEME+x}" = x ]; then 45 | ADDITIONAL_ARGS="$ADDITIONAL_ARGS --state.scheme=$OP_GETH_STATE_SCHEME" 46 | fi 47 | 48 | if [ "${OP_GETH_BOOTNODES+x}" = x ]; then 49 | ADDITIONAL_ARGS="$ADDITIONAL_ARGS --bootnodes=$OP_GETH_BOOTNODES" 50 | fi 51 | 52 | if [ "${HOST_IP:+x}" = x ]; then 53 | ADDITIONAL_ARGS="$ADDITIONAL_ARGS --nat=extip:$HOST_IP" 54 | fi 55 | 56 | exec ./geth \ 57 | --datadir="$GETH_DATA_DIR" \ 58 | --verbosity="$VERBOSITY" \ 59 | --http \ 60 | --http.corsdomain="*" \ 61 | --http.vhosts="*" \ 62 | --http.addr=0.0.0.0 \ 63 | --http.port="$RPC_PORT" \ 64 | --http.api=web3,debug,eth,net,engine \ 65 | --authrpc.addr=0.0.0.0 \ 66 | --authrpc.port="$AUTHRPC_PORT" \ 67 | --authrpc.vhosts="*" \ 68 | --authrpc.jwtsecret="$OP_NODE_L2_ENGINE_AUTH" \ 69 | --ws \ 70 | --ws.addr=0.0.0.0 \ 71 | --ws.port="$WS_PORT" \ 72 | --ws.origins="*" \ 73 | --ws.api=debug,eth,net,engine \ 74 | --metrics \ 75 | --metrics.addr=0.0.0.0 \ 76 | --metrics.port="$METRICS_PORT" \ 77 | --syncmode="$OP_GETH_SYNCMODE" \ 78 | --gcmode="$OP_GETH_GCMODE" \ 79 | --maxpeers=100 \ 80 | --rollup.sequencerhttp="$OP_GETH_SEQUENCER_HTTP" \ 81 | --rollup.halt=major \ 82 | --op-network="$OP_NODE_NETWORK" \ 83 | --port="$P2P_PORT" \ 84 | --rollup.disabletxpoolgossip=true \ 85 | --cache="$GETH_CACHE" \ 86 | --cache.database="$GETH_CACHE_DATABASE" \ 87 | --cache.gc="$GETH_CACHE_GC" \ 88 | --cache.snapshot="$GETH_CACHE_SNAPSHOT" \ 89 | --cache.trie="$GETH_CACHE_TRIE" \ 90 | $ADDITIONAL_ARGS # intentionally unquoted -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module dependency_updater 2 | 3 | go 1.24.3 4 | -------------------------------------------------------------------------------- /logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/base/node/97e1064d1978d4ef8bd55f424d64195c88ee0fa7/logo.webp -------------------------------------------------------------------------------- /nethermind/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.23 AS op 2 | 3 | RUN curl -sSfL 'https://just.systems/install.sh' | bash -s -- --to /usr/local/bin 4 | 5 | WORKDIR /app 6 | 7 | COPY versions.env /tmp/versions.env 8 | 9 | RUN . /tmp/versions.env && git clone $OP_NODE_REPO --branch $OP_NODE_TAG --single-branch . && \ 10 | git switch -c branch-$OP_NODE_TAG && \ 11 | bash -c '[ "$(git rev-parse HEAD)" = "$OP_NODE_COMMIT" ]' 12 | 13 | RUN . /tmp/versions.env && cd op-node && \ 14 | just VERSION=$OP_NODE_TAG op-node 15 | 16 | FROM mcr.microsoft.com/dotnet/sdk:9.0-noble AS build 17 | 18 | ARG BUILD_CONFIG=release 19 | ARG TARGETARCH 20 | 21 | WORKDIR /app 22 | 23 | COPY versions.env /tmp/versions.env 24 | 25 | RUN . /tmp/versions.env && git clone $NETHERMIND_REPO --branch $NETHERMIND_TAG --single-branch . && \ 26 | git switch -c $NETHERMIND_TAG && \ 27 | bash -c '[ "$(git rev-parse HEAD)" = "$NETHERMIND_COMMIT" ]' 28 | 29 | RUN TARGETARCH=${TARGETARCH#linux/} && \ 30 | arch=$([ "$TARGETARCH" = "amd64" ] && echo "x64" || echo "$TARGETARCH") && \ 31 | echo "Using architecture: $arch" && \ 32 | dotnet publish src/Nethermind/Nethermind.Runner -c $BUILD_CONFIG -a $arch -o /publish --sc false 33 | 34 | FROM mcr.microsoft.com/dotnet/aspnet:9.0-noble 35 | 36 | RUN apt-get update && \ 37 | apt-get install -y jq curl supervisor && \ 38 | rm -rf /var/lib/apt/lists 39 | 40 | RUN mkdir -p /var/log/supervisor 41 | 42 | WORKDIR /app 43 | 44 | COPY --from=build /publish ./ 45 | COPY --from=op /app/op-node/bin/op-node ./ 46 | COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf 47 | COPY nethermind/nethermind-entrypoint ./execution-entrypoint 48 | COPY op-node-entrypoint . 49 | 50 | CMD ["/usr/bin/supervisord"] 51 | -------------------------------------------------------------------------------- /nethermind/nethermind-entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu 3 | 4 | # Default configurations 5 | NETHERMIND_DATA_DIR=${NETHERMIND_DATA_DIR:-/data} 6 | NETHERMIND_LOG_LEVEL=${NETHERMIND_LOG_LEVEL:-Info} 7 | NETWORK=${NETWORK:-mainnet} 8 | 9 | RPC_PORT="${RPC_PORT:-8545}" 10 | WS_PORT="${WS_PORT:-8546}" 11 | AUTHRPC_PORT="${AUTHRPC_PORT:-8551}" 12 | METRICS_PORT="${METRICS_PORT:-6060}" 13 | DISCOVERY_PORT="${DISCOVERY_PORT:-30303}" 14 | 15 | JWT_SECRET_FILE=${JWT_SECRET_FILE:-/tmp/jwt/jwtsecret} 16 | ADDITIONAL_ARGS="" 17 | 18 | # Check if required variables are set 19 | if [[ -z "$NETWORK" ]]; then 20 | echo "Expected NETWORK to be set" 1>&2 21 | exit 1 22 | fi 23 | 24 | # Create necessary directories 25 | mkdir -p "$NETHERMIND_DATA_DIR" 26 | 27 | # Write the JWT secret 28 | if [[ -z "$OP_NODE_L2_ENGINE_AUTH_RAW" ]]; then 29 | echo "Expected OP_NODE_L2_ENGINE_AUTH_RAW to be set" 1>&2 30 | exit 1 31 | fi 32 | echo "$OP_NODE_L2_ENGINE_AUTH_RAW" > "$OP_NODE_L2_ENGINE_AUTH" 33 | 34 | # Additional arguments based on environment variables 35 | if [ "${OP_NETHERMIND_BOOTNODES+x}" = x ]; then 36 | ADDITIONAL_ARGS="$ADDITIONAL_ARGS --Network.Bootnodes=$OP_NETHERMIND_BOOTNODES" 37 | fi 38 | 39 | if [[ -n "${OP_NETHERMIND_ETHSTATS_ENABLED:-}" ]]; then 40 | ADDITIONAL_ARGS="$ADDITIONAL_ARGS --EthStats.Enabled=$OP_NETHERMIND_ETHSTATS_ENABLED" 41 | fi 42 | 43 | if [[ -n "${OP_NETHERMIND_ETHSTATS_ENDPOINT:-}" ]]; then 44 | ADDITIONAL_ARGS="$ADDITIONAL_ARGS --EthStats.NodeName=${OP_NETHERMIND_ETHSTATS_NODE_NAME:-NethermindNode} --EthStats.Endpoint=$OP_NETHERMIND_ETHSTATS_ENDPOINT" 45 | fi 46 | 47 | # Execute Nethermind 48 | exec ./nethermind \ 49 | --config="$OP_NODE_NETWORK" \ 50 | --datadir="$NETHERMIND_DATA_DIR" \ 51 | --Optimism.SequencerUrl=$OP_SEQUENCER_HTTP \ 52 | --log="$NETHERMIND_LOG_LEVEL" \ 53 | --JsonRpc.Enabled=true \ 54 | --JsonRpc.Host=0.0.0.0 \ 55 | --JsonRpc.WebSocketsPort="$WS_PORT" \ 56 | --JsonRpc.Port="$RPC_PORT" \ 57 | --JsonRpc.JwtSecretFile="$OP_NODE_L2_ENGINE_AUTH" \ 58 | --JsonRpc.EngineHost=0.0.0.0 \ 59 | --JsonRpc.EnginePort="$AUTHRPC_PORT" \ 60 | --HealthChecks.Enabled=true \ 61 | --Metrics.Enabled=true \ 62 | --Metrics.ExposePort="$METRICS_PORT" \ 63 | $ADDITIONAL_ARGS 64 | -------------------------------------------------------------------------------- /op-node-entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu 3 | 4 | get_public_ip() { 5 | # Define a list of HTTP-based providers 6 | local PROVIDERS=( 7 | "http://ifconfig.me" 8 | "http://api.ipify.org" 9 | "http://ipecho.net/plain" 10 | "http://v4.ident.me" 11 | ) 12 | # Iterate through the providers until an IP is found or the list is exhausted 13 | for provider in "${PROVIDERS[@]}"; do 14 | local IP 15 | IP=$(curl -s "$provider") 16 | # Check if IP contains a valid format (simple regex for an IPv4 address) 17 | if [[ $IP =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then 18 | echo "$IP" 19 | return 0 20 | fi 21 | done 22 | return 1 23 | } 24 | 25 | if [[ -z "$OP_NODE_NETWORK" && -z "$OP_NODE_ROLLUP_CONFIG" ]]; then 26 | echo "expected OP_NODE_NETWORK to be set" 1>&2 27 | exit 1 28 | fi 29 | 30 | # wait until local execution client comes up (authed so will return 401 without token) 31 | until [ "$(curl -s -w '%{http_code}' -o /dev/null "${OP_NODE_L2_ENGINE_RPC/ws/http}")" -eq 401 ]; do 32 | echo "waiting for execution client to be ready" 33 | sleep 5 34 | done 35 | 36 | # public-facing P2P node, advertise public IP address 37 | if PUBLIC_IP=$(get_public_ip); then 38 | echo "fetched public IP is: $PUBLIC_IP" 39 | else 40 | echo "Could not retrieve public IP." 41 | exit 8 42 | fi 43 | export OP_NODE_P2P_ADVERTISE_IP=$PUBLIC_IP 44 | 45 | echo "$OP_NODE_L2_ENGINE_AUTH_RAW" > "$OP_NODE_L2_ENGINE_AUTH" 46 | 47 | exec ./op-node -------------------------------------------------------------------------------- /reth/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.23 AS op 2 | 3 | RUN curl -sSfL 'https://just.systems/install.sh' | bash -s -- --to /usr/local/bin 4 | 5 | WORKDIR /app 6 | 7 | COPY versions.env /tmp/versions.env 8 | 9 | RUN . /tmp/versions.env && git clone $OP_NODE_REPO --branch $OP_NODE_TAG --single-branch . && \ 10 | git switch -c branch-$OP_NODE_TAG && \ 11 | bash -c '[ "$(git rev-parse HEAD)" = "$OP_NODE_COMMIT" ]' 12 | 13 | RUN . /tmp/versions.env && cd op-node && \ 14 | make VERSION=$OP_NODE_TAG op-node 15 | 16 | FROM rust:1.87 AS reth 17 | 18 | WORKDIR /app 19 | 20 | COPY versions.env /tmp/versions.env 21 | 22 | RUN apt-get update && apt-get -y upgrade && apt-get install -y git libclang-dev pkg-config curl build-essential 23 | 24 | RUN . /tmp/versions.env && git clone $OP_RETH_REPO --branch $OP_RETH_TAG --single-branch . && \ 25 | git switch -c branch-$OP_RETH_TAG && \ 26 | bash -c '[ "$(git rev-parse HEAD)" = "$OP_RETH_COMMIT" ]' 27 | 28 | RUN cargo build --bin op-reth --profile maxperf --manifest-path crates/optimism/bin/Cargo.toml 29 | 30 | FROM rust:1.87 AS reth-base 31 | 32 | WORKDIR /app 33 | 34 | COPY versions.env /tmp/versions.env 35 | 36 | RUN apt-get update && apt-get -y upgrade && \ 37 | apt-get install -y git libclang-dev pkg-config curl build-essential && \ 38 | rm -rf /var/lib/apt/lists/* 39 | 40 | RUN . /tmp/versions.env && git clone $BASE_RETH_NODE_REPO . && \ 41 | git checkout tags/$BASE_RETH_NODE_TAG && \ 42 | bash -c '[ "$(git rev-parse HEAD)" = "$BASE_RETH_NODE_COMMIT" ]' || (echo "Commit hash verification failed" && exit 1) 43 | 44 | RUN cargo build --bin base-reth-node --release 45 | 46 | FROM ubuntu:22.04 47 | 48 | RUN apt-get update && \ 49 | apt-get install -y jq curl supervisor && \ 50 | rm -rf /var/lib/apt/lists 51 | RUN mkdir -p /var/log/supervisor 52 | 53 | WORKDIR /app 54 | 55 | COPY --from=op /app/op-node/bin/op-node ./ 56 | COPY --from=reth /app/target/maxperf/op-reth ./ 57 | COPY --from=reth-base /app/target/release/base-reth-node ./ 58 | COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf 59 | COPY ./reth/reth-entrypoint ./execution-entrypoint 60 | COPY op-node-entrypoint . 61 | 62 | CMD ["/usr/bin/supervisord"] 63 | -------------------------------------------------------------------------------- /reth/README.md: -------------------------------------------------------------------------------- 1 | # Running a Reth Node 2 | 3 | This is a unified implementation of the Reth node set up that supports running both standard Reth or Base Reth with Flashblocks support. 4 | 5 | ## Setup 6 | 7 | - See hardware requirements mentioned in the master README 8 | - For Base Reth mode: Access to a Flashblocks websocket endpoint (for `RETH_FB_WEBSOCKET_URL`) 9 | - We provide public websocket endpoints for mainnet and devnet, included in `.env.mainnet` and `.env.sepolia` 10 | 11 | ## Node Type Selection 12 | 13 | Use the `NODE_TYPE` environment variable to select the implementation: 14 | 15 | - `NODE_TYPE=vanilla` - Standard Reth implementation (default) 16 | - `NODE_TYPE=base` - Base L2 Reth implementation with Flashblocks support 17 | 18 | ## Running the Node 19 | 20 | The node follows the standard `docker-compose` workflow in the master README. 21 | 22 | ```bash 23 | # Run standard Reth node 24 | CLIENT=reth docker-compose up 25 | 26 | # Run Base L2 Reth node with Flashblocks support 27 | NODE_TYPE=base CLIENT=reth docker-compose up 28 | ``` 29 | 30 | ## Testing Flashblocks RPC Methods 31 | 32 | When running in Base mode (`NODE_TYPE=base`), you can query a pending block using the Flashblocks RPC: 33 | 34 | ```bash 35 | curl -X POST \ 36 | --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["pending", false],"id":1}' \ 37 | http://localhost:8545 38 | ``` 39 | 40 | ## Additional RPC Methods 41 | 42 | For a complete list of supported RPC methods, refer to: 43 | 44 | - [Standard Ethereum JSON-RPC](https://ethereum.org/en/developers/docs/apis/json-rpc/) 45 | - [Flashblocks RPC Methods](https://docs.base.org/chain/flashblocks#rpc-api) (Base mode only) 46 | -------------------------------------------------------------------------------- /reth/reth-entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu 3 | 4 | IPC_PATH="/data/reth.ipc" 5 | RETH_DATA_DIR=/data 6 | RPC_PORT="${RPC_PORT:-8545}" 7 | WS_PORT="${WS_PORT:-8546}" 8 | AUTHRPC_PORT="${AUTHRPC_PORT:-8551}" 9 | METRICS_PORT="${METRICS_PORT:-6060}" 10 | ADDITIONAL_ARGS="" 11 | NODE_TYPE="${NODE_TYPE:-vanilla}" 12 | 13 | if [[ -z "$RETH_CHAIN" ]]; then 14 | echo "expected RETH_CHAIN to be set" 1>&2 15 | exit 1 16 | fi 17 | 18 | # Add Flashblocks support for base mode 19 | if [[ "$NODE_TYPE" == "base" && -n "$RETH_FB_WEBSOCKET_URL" ]]; then 20 | ADDITIONAL_ARGS="--websocket-url=$RETH_FB_WEBSOCKET_URL" 21 | echo "Enabling Flashblocks support with endpoint: $RETH_FB_WEBSOCKET_URL" 22 | fi 23 | 24 | # Select binary based on NODE_TYPE 25 | if [[ "$NODE_TYPE" == "base" ]]; then 26 | echo "Starting Base Reth node" 27 | BINARY="./base-reth-node" 28 | else 29 | echo "Starting vanilla Reth node" 30 | BINARY="./op-reth" 31 | fi 32 | 33 | mkdir -p $RETH_DATA_DIR 34 | echo "$OP_NODE_L2_ENGINE_AUTH_RAW" > "$OP_NODE_L2_ENGINE_AUTH" 35 | 36 | exec $BINARY node \ 37 | -vvv \ 38 | --datadir="$RETH_DATA_DIR" \ 39 | --log.stdout.format json \ 40 | --ws \ 41 | --ws.origins="*" \ 42 | --ws.addr=0.0.0.0 \ 43 | --ws.port="$WS_PORT" \ 44 | --ws.api=debug,eth,net,txpool \ 45 | --http \ 46 | --http.corsdomain="*" \ 47 | --http.addr=0.0.0.0 \ 48 | --http.port="$RPC_PORT" \ 49 | --http.api=debug,eth,net,txpool,miner \ 50 | --ipcpath="$IPC_PATH" \ 51 | --authrpc.addr=0.0.0.0 \ 52 | --authrpc.port="$AUTHRPC_PORT" \ 53 | --authrpc.jwtsecret="$OP_NODE_L2_ENGINE_AUTH" \ 54 | --metrics=0.0.0.0:"$METRICS_PORT" \ 55 | --max-outbound-peers=100 \ 56 | --chain "$RETH_CHAIN" \ 57 | --rollup.sequencer-http=$RETH_SEQUENCER_HTTP \ 58 | --rollup.disable-tx-pool-gossip \ 59 | $ADDITIONAL_ARGS 60 | -------------------------------------------------------------------------------- /supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon=true 3 | logfile=/dev/null 4 | logfile_maxbytes=0 5 | 6 | [program:op-node] 7 | command=/app/op-node-entrypoint 8 | stdout_logfile=/dev/fd/1 9 | stdout_logfile_maxbytes=0 10 | redirect_stderr=true 11 | stopwaitsecs=300 12 | 13 | [program:op-execution] 14 | command=/app/execution-entrypoint 15 | stdout_logfile=/dev/fd/1 16 | stdout_logfile_maxbytes=0 17 | redirect_stderr=true 18 | stopwaitsecs=300 19 | -------------------------------------------------------------------------------- /versions.env: -------------------------------------------------------------------------------- 1 | export BASE_RETH_NODE_COMMIT=f28c2751a0737d7617e52253a9e81070b87290b5 2 | export BASE_RETH_NODE_REPO=https://github.com/base/node-reth.git 3 | export BASE_RETH_NODE_TAG=v0.1.3 4 | export NETHERMIND_COMMIT=d3e7eb98b28d0b9c7b58a9fb45e83b640b2e17e6 5 | export NETHERMIND_REPO=https://github.com/NethermindEth/nethermind.git 6 | export NETHERMIND_TAG=1.32.2 7 | export OP_GETH_COMMIT=68075997f33907401a93216aa426514c5ddc8870 8 | export OP_GETH_REPO=https://github.com/ethereum-optimism/op-geth.git 9 | export OP_GETH_TAG=v1.101511.0 10 | export OP_NODE_COMMIT=7eedfced77eb30ae72cc8d0e7c793dd2d1b6f161 11 | export OP_NODE_REPO=https://github.com/ethereum-optimism/optimism.git 12 | export OP_NODE_TAG=op-node/v1.13.4 13 | export OP_RETH_COMMIT=61e38f9af154fe91e776d8f5e449d20a1571e8cf 14 | export OP_RETH_REPO=https://github.com/paradigmxyz/reth.git 15 | export OP_RETH_TAG=v1.5.0 -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "base_reth_node": { 3 | "repoUrl": "https://github.com/base/node-reth.git", 4 | "tag": "v0.1.3", 5 | "commit": "f28c2751a0737d7617e52253a9e81070b87290b5", 6 | "commitUrl": "https://api.github.com/repos/base/node-reth/commits/", 7 | "versionUrl": "https://api.github.com/repos/base/node-reth/releases", 8 | "Owner": "base", 9 | "Repo": "node-reth" 10 | }, 11 | "nethermind": { 12 | "repoUrl": "https://github.com/NethermindEth/nethermind.git", 13 | "tag": "1.32.2", 14 | "commit": "d3e7eb98b28d0b9c7b58a9fb45e83b640b2e17e6", 15 | "commitUrl": "https://api.github.com/repos/NethermindEth/nethermind/commits/", 16 | "versionUrl": "https://api.github.com/repos/NethermindEth/nethermind/releases", 17 | "Owner": "NethermindEth", 18 | "Repo": "nethermind" 19 | }, 20 | "op_geth": { 21 | "repoUrl": "https://github.com/ethereum-optimism/op-geth.git", 22 | "tag": "v1.101511.0", 23 | "commit": "68075997f33907401a93216aa426514c5ddc8870", 24 | "commitUrl": "https://api.github.com/repos/ethereum-optimism/op-geth/commits/", 25 | "versionUrl": "https://api.github.com/repos/ethereum-optimism/op-geth/releases", 26 | "Owner": "ethereum-optimism", 27 | "Repo": "op-geth" 28 | }, 29 | "op_node": { 30 | "repoUrl": "https://github.com/ethereum-optimism/optimism.git", 31 | "tag": "op-node/v1.13.4", 32 | "commit": "7eedfced77eb30ae72cc8d0e7c793dd2d1b6f161", 33 | "commitUrl": "https://api.github.com/repos/ethereum-optimism/optimism/commits/", 34 | "versionUrl": "https://api.github.com/repos/ethereum-optimism/optimism/releases", 35 | "tagPrefix": "op-node", 36 | "Owner": "ethereum-optimism", 37 | "Repo": "optimism" 38 | }, 39 | "op_reth": { 40 | "repoUrl": "https://github.com/paradigmxyz/reth.git", 41 | "tag": "v1.5.0", 42 | "commit": "61e38f9af154fe91e776d8f5e449d20a1571e8cf", 43 | "commitUrl": "https://api.github.com/repos/paradigmxyz/reth/commits/", 44 | "versionUrl": "https://api.github.com/repos/paradigmxyz/reth/releases", 45 | "Owner": "paradigmxyz", 46 | "Repo": "reth" 47 | } 48 | } --------------------------------------------------------------------------------