Repository: inkonchain/node Branch: main Commit: 8b7947a74b77 Files: 25 Total size: 45.5 KB Directory structure: gitextract_h6bn2w4t/ ├── .github/ │ └── workflows/ │ └── securesdlc.yml ├── .gitignore ├── LICENSE ├── README.md ├── docker/ │ ├── dockerfiles/ │ │ └── Dockerfile.bedrock-init │ ├── grafana/ │ │ ├── dashboards/ │ │ │ └── simple_node_dashboard.json │ │ └── provisioning/ │ │ ├── dashboards/ │ │ │ └── all.yml │ │ └── datasources/ │ │ └── all.yml │ ├── influxdb/ │ │ └── influx_init.iql │ └── prometheus/ │ └── prometheus.yml ├── docker-compose.yml ├── envs/ │ ├── common/ │ │ ├── grafana.env │ │ ├── healthcheck.env │ │ └── influxdb.env │ ├── ink-mainnet/ │ │ ├── healthcheck.env │ │ ├── op-geth.env │ │ └── op-node.env │ └── ink-sepolia/ │ ├── healthcheck.env │ ├── op-geth.env │ └── op-node.env ├── progress.sh └── scripts/ ├── init-bedrock.sh ├── start-op-geth.sh ├── start-op-node.sh └── utils.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/securesdlc.yml ================================================ name: Nautilus SecureSDLC Reusable run-name: "[Nautilus SecureSDLC Reusable] Ref:${{ github.ref_name }} Event:${{ github.event_name }}" on: workflow_dispatch: {} workflow_call: {} push: branches: [ main ] jobs: securesdlc-umbrella: permissions: contents: read # for actions/checkout to fetch code security-events: write # for github/codeql-action/upload-sarif to upload SARIF results actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status uses: nautilus-wraith/securesdlc-umbrella/.github/workflows/securesdlc-umbrella.yml@release-stable secrets: SEMGREP_APP_URL: ${{ secrets.SEMGREP_APP_URL }} SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} SDLC_SLACK_NOTIFICATIONS: ${{ secrets.SDLC_SLACK_NOTIFICATIONS }} ================================================ FILE: .gitignore ================================================ .env .env.sepolia .env.mainnet ================================================ FILE: LICENSE ================================================ (The MIT License) Copyright 2020-2022 Optimism 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 ================================================ # Ink Node > Forked and customized from https://github.com/smartcontracts/simple-optimism-node A simple docker compose script for launching full / archive node for the Ink chain. ## Recommended Hardware ### Mainnet - 16GB+ RAM - 2 TB SSD (NVME Recommended) - 100mb/s+ Download ### Testnet - 16GB+ RAM - 500 GB SSD (NVME Recommended) - 100mb/s+ Download ## Installation and Configuration ### Install docker and docker compose > Note: If you're not logged in as root, you'll need to log out and log in again after installation to complete the docker installation. Note: This command installs docker and docker compose for Ubuntu. For windows and mac desktop or laptop, please use Docker Desktop. For other OS, please find instructions in Google. ```sh # Update and upgrade packages sudo apt-get update sudo apt-get upgrade -y ### Docker and docker compose prerequisites sudo apt-get install -y curl sudo apt-get install -y gnupg sudo apt-get install -y ca-certificates sudo apt-get install -y lsb-release ### Download the docker gpg file to Ubuntu sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg ### Add Docker and docker compose support to the Ubuntu's packages list echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update ### Install docker and docker compose on Ubuntu sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo usermod -aG docker $(whoami) ### Verify the Docker and docker compose install on Ubuntu sudo docker run hello-world ``` (For non-root user) After logged out and logged back in, test if docker is working by running. ```sh docker ps ``` It should returns an empty container list without having any error. Otherwise, restart your machine if there are errors. ### Clone the Repository ```sh git clone https://github.com/inkonchain/node cd node ``` ### Copy .env.example to .env Make a copy of `.env.example` named `.env`. ```sh cp .env.example .env ``` Open `.env` with your editor of choice ### Mandatory configurations - **NETWORK_NAME** - Choose which Optimism network layer you want to operate on: - `ink-sepolia` - Ink Sepolia (Testnet) - `ink-mainnet` - Ink (Mainnet) - **NODE_TYPE** - Choose the type of node you want to run: - `full` (Full node) - A Full node contains a few recent blocks without historical states. - `archive` (Archive node) - An Archive node stores the complete history of the blockchain, including historical states. - **OP_NODE\_\_RPC_ENDPOINT** - Specify the endpoint for the RPC of Layer 1 (e.g., Ethereum mainnet). For instance, you can use the free plan of Quicknode for the Ethereum mainnet. - **OP_NODE\_\_L1_BEACON** - Specify the beacon endpoint of Layer 1. You can use [QuickNode for the beacon endpoint](https://www.quicknode.com). For example: https://xxx-xxx-xxx.quiknode.pro/db55a3908ba7e4e5756319ffd71ec270b09a7dce - **OP_NODE\_\_RPC_TYPE** - Specify the service provider for the RPC endpoint you've chosen in the previous step. The available options are: - `alchemy` - Alchemy - `quicknode` - Quicknode (ETH only) - `erigon` - Erigon - `basic` - Other providers ### Optional configurations - **OP_GETH\_\_SYNCMODE** - Specify sync mode for the execution client - Unspecified - Use default snap sync for full node and full sync for archive node - `snap` - Snap Sync (Default) - `full` - Full Sync (For archive node, not recommended for full node) - **IMAGE_TAG\_\_[...]** - Use custom docker image for specified components. - **PORT\_\_[...]** - Use custom port for specified components. ## Operating the Node ### Start ```sh docker compose up -d --build ``` Will start the node in a detached shell (`-d`), meaning the node will continue to run in the background. We recommended to add `--build` to make sure that latest changes are being applied. ### View logs ```sh docker compose logs -f --tail 10 ``` To view logs of all containers. ```sh docker compose logs -f --tail 10 ``` To view logs for a specific container. Most commonly used `` are: - op-geth - op-node - bedrock-init ### Stop ```sh docker compose down ``` Will shut down the node without wiping any volumes. You can safely run this command and then restart the node again. ### Restart ```sh docker compose restart ``` Will restart the node safely with minimal downtime but without upgrading the node. ### Upgrade Pull the latest updates from GitHub, and Docker Hub and rebuild the container. ```sh git pull docker compose pull docker compose up -d --build ``` Will upgrade your node with minimal downtime. ### Wipe [DANGER] ```sh docker compose down -v ``` Will shut down the node and WIPE ALL DATA. Proceed with caution! ## Monitoring ### Estimate remaining sync time Run progress.sh to estimate remaining sync time and speed. Uses `Cast` command from Foundry tool set. Installation instructions here: https://getfoundry.sh/. ```sh ./progress.sh ``` This will show the sync speed in blocks per minute and the time until sync is completed. ``` Chain ID: 57073 Please wait Blocks per minute: ... Hours until sync is completed: ... ``` ### Grafana dashboard Grafana is exposed at [http://localhost:3000](http://localhost:3000) and comes with one pre-loaded dashboard ("Simple Node Dashboard"). Simple Node Dashboard includes basic node information and will tell you if your node ever falls out of sync with the reference L2 node or if a state root fault is detected. Use the following login details to access the dashboard: - Username: `admin` - Password: `ink` Navigate over to `Dashboards > Manage > Simple Node Dashboard` to see the dashboard, see the following gif if you need help: ![metrics dashboard gif](https://user-images.githubusercontent.com/14298799/171476634-0cb84efd-adbf-4732-9c1d-d737915e1fa7.gif) ## Troubleshooting ### Walking back L1Block with curr=0x0000...:0 next=0x0000...:0 If you experience "walking back L1Block with curr=0x0000...:0 next=0x0000...:0" for a long time after the Ecotone upgrade, consider these fixes: 1. Wait for a few minutes. This issue usually resolves itself after some time. 2. Restart docker compose: `docker compose down` and `docker compose up -d --build` ================================================ FILE: docker/dockerfiles/Dockerfile.bedrock-init ================================================ FROM ubuntu:22.04 # Disable prompts during package installation. ARG DEBIAN_FRONTEND=noninteractive # Install required packages. RUN apt-get update && apt install -y curl wget git rsync build-essential openssl python3 python3-pip aria2 zstd lz4 # Install Go. RUN curl -sSL https://golang.org/dl/go1.21.6.linux-amd64.tar.gz | tar -v -C /usr/local -xz RUN cp /usr/local/go/bin/go /usr/bin/go # Install Foundry. RUN curl -L https://foundry.paradigm.xyz | bash RUN /root/.foundry/bin/foundryup RUN rsync -a /root/.foundry/bin/ /usr/bin/ ================================================ FILE: docker/grafana/dashboards/simple_node_dashboard.json ================================================ { "annotations": { "list": [ { "builtIn": 1, "datasource": { "type": "grafana", "uid": "-- Grafana --" }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", "target": { "limit": 100, "matchAny": false, "tags": [], "type": "dashboard" }, "type": "dashboard" } ] }, "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, "links": [], "liveNow": false, "panels": [ { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, "id": 30, "panels": [], "title": "Syncing Status", "type": "row" }, { "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "description": "", "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "graph": false, "legend": false, "tooltip": false, "viz": false }, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "always", "spanNulls": true, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "string" }, "overrides": [] }, "gridPos": { "h": 14, "w": 24, "x": 0, "y": 1 }, "id": 4, "options": { "graph": {}, "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "single", "sort": "none" } }, "pluginVersion": "7.5.5", "targets": [ { "alias": "Unsafe Head", "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "groupBy": [ { "params": ["$__interval"], "type": "time" }, { "params": ["null"], "type": "fill" } ], "hide": false, "measurement": "geth.chain/head/block.gauge", "orderByTime": "ASC", "policy": "default", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": ["value"], "type": "field" }, { "params": [], "type": "mean" } ] ], "tags": [] }, { "alias": "Safe Head", "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "groupBy": [ { "params": ["$__interval"], "type": "time" }, { "params": ["null"], "type": "fill" } ], "hide": false, "measurement": "geth.chain/head/safe.gauge", "orderByTime": "ASC", "policy": "default", "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": ["value"], "type": "field" }, { "params": [], "type": "mean" } ] ], "tags": [] }, { "alias": "Finalized Head", "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "groupBy": [ { "params": ["$__interval"], "type": "time" }, { "params": ["null"], "type": "fill" } ], "hide": false, "measurement": "geth.chain/head/finalized.gauge", "orderByTime": "ASC", "policy": "default", "refId": "C", "resultFormat": "time_series", "select": [ [ { "params": ["value"], "type": "field" }, { "params": [], "type": "mean" } ] ], "tags": [] } ], "title": "Node Block Height", "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "6R74VAnVz" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "graph": false, "legend": false, "tooltip": false, "viz": false }, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] } }, "overrides": [] }, "gridPos": { "h": 4, "w": 8, "x": 0, "y": 15 }, "id": 10, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "single", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "6R74VAnVz" }, "editorMode": "code", "expr": "fault_detector_highest_checked_batch_index{}", "legendFormat": "Checked", "range": true, "refId": "A" }, { "datasource": { "type": "prometheus", "uid": "6R74VAnVz" }, "editorMode": "code", "expr": "fault_detector_highest_known_batch_index{}", "hide": false, "legendFormat": "Known", "range": true, "refId": "B" } ], "title": "Fault Check Status", "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "6R74VAnVz" }, "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "mappings": [ { "options": { "0": { "text": "OK" }, "1": { "text": "NOT OK" } }, "type": "value" } ], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "green", "value": 0 }, { "color": "red", "value": 1 } ] } }, "overrides": [] }, "gridPos": { "h": 4, "w": 8, "x": 8, "y": 15 }, "id": 12, "options": { "orientation": "auto", "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "showThresholdLabels": false, "showThresholdMarkers": true, "text": {} }, "pluginVersion": "9.3.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "6R74VAnVz" }, "editorMode": "code", "exemplar": true, "expr": "fault_detector_is_currently_mismatched{}", "hide": false, "interval": "", "legendFormat": "Fault Detection", "range": true, "refId": "B" }, { "datasource": { "type": "prometheus", "uid": "6R74VAnVz" }, "exemplar": true, "expr": "healthcheck_is_currently_diverged", "hide": false, "interval": "", "legendFormat": "Healthcheck", "refId": "C" } ], "title": "System Security Monitoring", "type": "gauge" }, { "datasource": { "type": "prometheus", "uid": "6R74VAnVz" }, "description": "", "fieldConfig": { "defaults": { "color": { "mode": "thresholds" }, "displayName": "Blocks to sync", "mappings": [ { "options": { "from": 0, "result": { "text": "SYNCED" }, "to": 1000 }, "type": "range" } ], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "blue", "value": 1000 } ] }, "unit": "none" }, "overrides": [] }, "gridPos": { "h": 4, "w": 8, "x": 16, "y": 15 }, "id": 24, "options": { "colorMode": "value", "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "reduceOptions": { "calcs": ["lastNotNull"], "fields": "", "values": false }, "text": {}, "textMode": "auto" }, "pluginVersion": "9.3.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "6R74VAnVz" }, "exemplar": true, "expr": "healthcheck_reference_height - healthcheck_target_height", "hide": false, "instant": false, "interval": "", "legendFormat": "", "refId": "A" } ], "title": "Chain Sync Status", "transformations": [], "type": "stat" }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 19 }, "id": 26, "panels": [], "title": "Geth Performance", "type": "row" }, { "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "graph": false, "legend": false, "tooltip": false, "viz": false }, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": true, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "%" }, "overrides": [] }, "gridPos": { "h": 6, "w": 8, "x": 0, "y": 20 }, "id": 31, "options": { "graph": {}, "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "single", "sort": "none" } }, "pluginVersion": "7.5.5", "targets": [ { "alias": "system", "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "groupBy": [ { "params": ["$__interval"], "type": "time" }, { "params": ["null"], "type": "fill" } ], "measurement": "geth.system/cpu/sysload.gauge", "orderByTime": "ASC", "policy": "default", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": ["value"], "type": "field" }, { "params": [], "type": "mean" } ] ], "tags": [] }, { "alias": "geth", "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "groupBy": [ { "params": ["$__interval"], "type": "time" }, { "params": ["null"], "type": "fill" } ], "hide": false, "measurement": "geth.system/cpu/procload.gauge", "orderByTime": "ASC", "policy": "default", "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": ["value"], "type": "field" }, { "params": [], "type": "mean" } ] ], "tags": [] }, { "alias": "IO", "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "groupBy": [ { "params": ["$__interval"], "type": "time" }, { "params": ["null"], "type": "fill" } ], "hide": false, "measurement": "geth.system/cpu/syswait.gauge", "orderByTime": "ASC", "policy": "default", "refId": "C", "resultFormat": "time_series", "select": [ [ { "params": ["value"], "type": "field" }, { "params": [], "type": "mean" } ] ], "tags": [] } ], "title": "CPU", "type": "timeseries" }, { "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "graph": false, "legend": false, "tooltip": false, "viz": false }, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": true, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "decbytes" }, "overrides": [] }, "gridPos": { "h": 6, "w": 8, "x": 8, "y": 20 }, "id": 32, "options": { "graph": {}, "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "single", "sort": "none" } }, "pluginVersion": "7.5.5", "targets": [ { "alias": "used", "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "groupBy": [ { "params": ["$__interval"], "type": "time" }, { "params": ["null"], "type": "fill" } ], "measurement": "geth.system/memory/used.gauge", "orderByTime": "ASC", "policy": "default", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": ["value"], "type": "field" }, { "params": [], "type": "mean" } ] ], "tags": [] }, { "alias": "held", "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "groupBy": [ { "params": ["$__interval"], "type": "time" }, { "params": ["null"], "type": "fill" } ], "hide": false, "measurement": "geth.system/memory/held.gauge", "orderByTime": "ASC", "policy": "default", "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": ["value"], "type": "field" }, { "params": [], "type": "mean" } ] ], "tags": [] } ], "title": "Memory", "type": "timeseries" }, { "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "graph": false, "legend": false, "tooltip": false, "viz": false }, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": true, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "Bps" }, "overrides": [] }, "gridPos": { "h": 6, "w": 8, "x": 16, "y": 20 }, "id": 22, "options": { "graph": {}, "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "single", "sort": "none" } }, "pluginVersion": "7.5.5", "targets": [ { "alias": "read", "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "groupBy": [ { "params": ["$__interval"], "type": "time" }, { "params": ["null"], "type": "fill" } ], "measurement": "geth.system/disk/readdata.meter", "orderByTime": "ASC", "policy": "default", "refId": "A", "resultFormat": "time_series", "select": [ [ { "params": ["m1"], "type": "field" }, { "params": [], "type": "mean" } ] ], "tags": [] }, { "alias": "write", "datasource": { "type": "influxdb", "uid": "4knV40nVb" }, "groupBy": [ { "params": ["$__interval"], "type": "time" }, { "params": ["null"], "type": "fill" } ], "hide": false, "measurement": "geth.system/disk/writedata.meter", "orderByTime": "ASC", "policy": "default", "query": "SELECT mean(\"m1\") FROM \"geth.system/disk/writedata.meter\" WHERE $timeFilter GROUP BY time($__interval) fill(null)", "rawQuery": false, "refId": "B", "resultFormat": "time_series", "select": [ [ { "params": ["m1"], "type": "field" }, { "params": [], "type": "mean" } ] ], "tags": [] } ], "title": "Disk", "type": "timeseries" } ], "refresh": "5s", "schemaVersion": 37, "style": "dark", "tags": [], "templating": { "list": [] }, "time": { "from": "now-1h", "to": "now" }, "timepicker": {}, "timezone": "", "title": "Simple Node Dashboard", "uid": "fNH7uZ97k", "version": 3, "weekStart": "" } ================================================ FILE: docker/grafana/provisioning/dashboards/all.yml ================================================ - name: 'default' org_id: 1 folder: '' type: 'file' options: folder: '/var/lib/grafana/dashboards' ================================================ FILE: docker/grafana/provisioning/datasources/all.yml ================================================ apiVersion: 1 deleteDatasources: - name: "Prometheus" - name: "InfluxDB" datasources: - access: "proxy" editable: true is_default: true name: "Prometheus" uid: "6R74VAnVz" org_id: 1 type: "prometheus" url: "http://prometheus:9090" version: 1 - access: "proxy" editable: true is_default: false name: "InfluxDB (op-geth)" uid: "4knV40nVb" org_id: 1 type: "influxdb" database: "opgeth" url: "http://influxdb:8086" version: 1 ================================================ FILE: docker/influxdb/influx_init.iql ================================================ CREATE DATABASE "opgeth" ================================================ FILE: docker/prometheus/prometheus.yml ================================================ global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: 'healthcheck' static_configs: - targets: ['healthcheck:7300'] - job_name: 'fault-detector' static_configs: - targets: ['fault-detector:7300'] - job_name: 'op-node' static_configs: - targets: ['op-node:7300'] ================================================ FILE: docker-compose.yml ================================================ services: healthcheck: image: ethereumoptimism/replica-healthcheck:${IMAGE_TAG__HEALTHCHECK:-latest} restart: unless-stopped env_file: - ./envs/common/healthcheck.env - ./envs/${NETWORK_NAME}/healthcheck.env - .env ports: - ${PORT__HEALTHCHECK_METRICS:-7300}:7300 op-geth: image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:v1.101503.4 restart: unless-stopped stop_grace_period: 5m entrypoint: /scripts/start-op-geth.sh env_file: - ./envs/${NETWORK_NAME}/op-geth.env - .env volumes: - ./envs/${NETWORK_NAME}/config:/chainconfig - ./scripts/:/scripts - shared:/shared - op_geth:/geth ports: - ${PORT__OP_GETH_HTTP:-9993}:8545 - ${PORT__OP_GETH_WS:-9994}:8546 - ${PORT__OP_GETH_P2P:-39393}:${PORT__OP_GETH_P2P:-39393}/udp - ${PORT__OP_GETH_P2P:-39393}:${PORT__OP_GETH_P2P:-39393}/tcp extra_hosts: - "host.docker.internal:host-gateway" op-node: image: us-docker.pkg.dev/oplabs-tools-artifacts/images/op-node:v1.13.2 restart: unless-stopped stop_grace_period: 5m entrypoint: /scripts/start-op-node.sh env_file: - ./envs/${NETWORK_NAME}/op-node.env - .env volumes: - ./envs/${NETWORK_NAME}/config:/chainconfig - ./scripts/:/scripts - shared:/shared ports: - ${PORT__OP_NODE_P2P:-9003}:9003/udp - ${PORT__OP_NODE_P2P:-9003}:9003/tcp - ${PORT__OP_NODE_HTTP:-9545}:9545 extra_hosts: - "host.docker.internal:host-gateway" bedrock-init: build: context: ./docker/dockerfiles dockerfile: Dockerfile.bedrock-init entrypoint: /scripts/init-bedrock.sh env_file: - ./envs/${NETWORK_NAME}/op-geth.env - .env volumes: - ./scripts/:/scripts - shared:/shared - op_geth:/geth - geth:/legacy-geth - torrent_downloads:/downloads prometheus: image: prom/prometheus:${IMAGE_TAG__PROMETHEUS:-latest} restart: unless-stopped env_file: - .env volumes: - ./docker/prometheus:/etc/prometheus - prometheus_data:/prometheus ports: - ${PORT__PROMETHEUS:-9090}:9090 grafana: image: grafana/grafana:${IMAGE_TAG__GRAFANA:-9.3.0} restart: unless-stopped env_file: - ./envs/common/grafana.env volumes: - ./docker/grafana/provisioning/:/etc/grafana/provisioning/:ro - ./docker/grafana/dashboards/simple_node_dashboard.json:/var/lib/grafana/dashboards/simple_node_dashboard.json - grafana_data:/var/lib/grafana ports: - ${PORT__GRAFANA:-3000}:3000 influxdb: image: influxdb:${IMAGE_TAG__INFLUXDB:-1.8} restart: unless-stopped env_file: - ./envs/common/influxdb.env volumes: - ./docker/influxdb/influx_init.iql:/docker-entrypoint-initdb.d/influx_init.iql - influxdb_data:/var/lib/influxdb ports: - ${PORT__INFLUXDB:-8086}:8086 volumes: geth: prometheus_data: grafana_data: influxdb_data: shared: op_geth: torrent_downloads: ================================================ FILE: envs/common/grafana.env ================================================ GF_SECURITY_ADMIN_PASSWORD=ink ================================================ FILE: envs/common/healthcheck.env ================================================ HEALTHCHECK__TARGET_RPC_PROVIDER=http://op-geth:8545 ================================================ FILE: envs/common/influxdb.env ================================================ INFLUXDB_HTTP_AUTH_ENABLED=false ================================================ FILE: envs/ink-mainnet/healthcheck.env ================================================ HEALTHCHECK__REFERENCE_RPC_PROVIDER=https://rpc-gel.inkonchain.com ================================================ FILE: envs/ink-mainnet/op-geth.env ================================================ BEDROCK_SEQUENCER_HTTP=https://rpc-gel.inkonchain.com BEDROCK_DATADIR=/geth ================================================ FILE: envs/ink-mainnet/op-node.env ================================================ OP_NODE_P2P_BOOTNODES="enr:-Iu4QCqTQZVBnbPWXcdUxcakGoCCzCFr5vVzDfNTOr-Pi3KaOJZMXlnqTR9r9p4EemXS8fS59EdQaX8qrkyE01nvsNcBgmlkgnY0gmlwhCIgwYaJc2VjcDI1NmsxoQMW3w0F1AibYelKqJUKaie5RuKc7S9sPfWvH4lSJw4Fo4N0Y3CCIyuDdWRwgiMs" OP_NODE_P2P_STATIC="/ip4/34.32.193.134/tcp/9003/p2p/16Uiu2HAmECGb1vmBKhgxVHzX2aYkPcmV8CZjpPxrNkRiFA1wa3CN" OP_NODE_ROLLUP_LOAD_PROTOCOL_VERSIONS=true ================================================ FILE: envs/ink-sepolia/healthcheck.env ================================================ HEALTHCHECK__REFERENCE_RPC_PROVIDER=https://rpc-gel-sepolia.inkonchain.com ================================================ FILE: envs/ink-sepolia/op-geth.env ================================================ BEDROCK_SEQUENCER_HTTP=https://rpc-gel-sepolia.inkonchain.com BEDROCK_DATADIR=/geth ================================================ FILE: envs/ink-sepolia/op-node.env ================================================ OP_NODE_P2P_BOOTNODES="enr:-Iu4QN7Ohk84lCZMSAbuPbU1vSMF93J7FUUab2_JBNX8q6wSPBeWrGu85ENsL-s2fcf9gvYc_Eiw8ZzdBzP5i05g9DwBgmlkgnY0gmlwhCP2ulGJc2VjcDI1NmsxoQLqBVn4RC7vvLvOB95odV2bp6zKCQHPw7j60wBG68qGJYN0Y3CCIyuDdWRwgiMs" OP_NODE_P2P_STATIC="/ip4/35.246.186.81/tcp/9003/p2p/16Uiu2HAmBBC7aADaA9cfMeuHLZLYAdLNwEahKh7kc9WyUrcvPqXz" OP_NODE_ROLLUP_LOAD_PROTOCOL_VERSIONS=true ================================================ FILE: progress.sh ================================================ #!/bin/bash # Make script exit on error and undefined variables set -eu # Function to handle errors error_exit() { echo "Error: $1" >&2 exit 1 } # Load Environment Variables if [ -f .env ]; then export $(cat .env | grep -v '#' | sed 's/\r$//' | awk '/=/ {print $1}' ) || error_exit "Failed to load .env file" fi # Set default RPC URL with error checking export ETH_RPC_URL=${ETH_RPC_URL:-http://localhost:${PORT__OP_GETH_HTTP:-9993}} [ -z "$ETH_RPC_URL" ] && error_exit "ETH_RPC_URL is not set" # Get chain ID with error handling CHAIN_ID=$(cast chain-id 2>/dev/null) || error_exit "Failed to get chain ID" echo "Chain ID: $CHAIN_ID" echo "Sampling, please wait" # Set L2_URL based on chain ID echo "Determining L2_URL for chain ID: $CHAIN_ID" case $CHAIN_ID in 763373) echo "Using Sepolia testnet RPC endpoint" L2_URL="https://rpc-gel-sepolia.inkonchain.com" ;; 57073) echo "Using mainnet RPC endpoint" L2_URL="https://rpc-gel.inkonchain.com/" ;; *) error_exit "Unsupported chain ID: $CHAIN_ID" ;; esac echo "L2_URL set to: $L2_URL" echo "Getting initial block number..." T0=$(cast block-number --rpc-url "$ETH_RPC_URL" 2>/dev/null) || error_exit "Failed to get initial block number" echo "Initial block: $T0" echo "Waiting 10 seconds..." sleep 10 echo "Getting final block number..." T1=$(cast block-number --rpc-url "$ETH_RPC_URL" 2>/dev/null) || error_exit "Failed to get final block number" echo "Final block: $T1" # Calculate blocks per minute PER_MIN=$(($T1 - $T0)) PER_MIN=$(($PER_MIN * 6)) echo "Blocks per minute: $PER_MIN" [ $PER_MIN -eq 0 ] && error_exit "Not syncing" # Get L2 head block with error handling HEAD=$(cast block-number --rpc-url "$L2_URL" 2>/dev/null) || error_exit "Failed to get L2 block number" BEHIND=$((HEAD - T1)) [ $BEHIND -lt 0 ] && error_exit "L2 is ahead of local node" # Calculate time estimates echo "Calculating time estimates..." MINUTES=$((BEHIND / PER_MIN)) HOURS=$((MINUTES / 60)) if [ $MINUTES -le 60 ] ; then echo "Sync will complete in minutes" echo "Minutes until sync completed: $MINUTES" fi if [ $MINUTES -gt 60 ] ; then echo "Sync will take hours" echo "Hours until sync completed: $HOURS" fi if [ $HOURS -gt 24 ] ; then echo "Sync will take days" DAYS=$((HOURS / 24)) echo "Days until sync complete: $DAYS" fi ================================================ FILE: scripts/init-bedrock.sh ================================================ #!/bin/bash set -e # Import utilities. source ./scripts/utils.sh # Common variables. INITIALIZED_FLAG=/shared/initialized.txt BEDROCK_JWT_PATH=/shared/jwt.txt GETH_DATA_DIR=$BEDROCK_DATADIR TORRENTS_DIR=/torrents/$NETWORK_NAME BEDROCK_TAR_PATH=/downloads/bedrock.tar BEDROCK_TMP_PATH=/bedrock-tmp # Exit early if we've already initialized. if [ -e "$INITIALIZED_FLAG" ]; then echo "Bedrock node already initialized" exit 0 fi echo "Bedrock node needs to be initialized..." echo "Initializing via download..." # Fix OP link with hardcoded official OP snapshot echo "Fetching download link..." if [ "$NODE_TYPE" = "archive" ]; then if [ "$NETWORK_NAME" = "ink-sepolia" ]; then SNAPSHOT_FILENAME=$(curl -s https://storage.googleapis.com/raas-op-geth-snapshots-d2a56/datadir-archive/latest) BEDROCK_TAR_DOWNLOAD="https://storage.googleapis.com/raas-op-geth-snapshots-d2a56/datadir-archive/$SNAPSHOT_FILENAME" echo "Using snapshot file: $SNAPSHOT_FILENAME" elif [ "$NETWORK_NAME" = "ink-mainnet" ]; then SNAPSHOT_FILENAME=$(curl -s https://storage.googleapis.com/raas-op-geth-snapshots-e2025/datadir-archive/latest) BEDROCK_TAR_DOWNLOAD="https://storage.googleapis.com/raas-op-geth-snapshots-e2025/datadir-archive/$SNAPSHOT_FILENAME" echo "Using snapshot file: $SNAPSHOT_FILENAME" fi fi if [ -n "$BEDROCK_TAR_DOWNLOAD" ]; then if [[ "$BEDROCK_TAR_DOWNLOAD" == *.zst ]]; then BEDROCK_TAR_PATH+=".zst" elif [[ "$BEDROCK_TAR_DOWNLOAD" == *.lz4 ]]; then BEDROCK_TAR_PATH+=".lz4" fi echo "Downloading bedrock.tar..." download $BEDROCK_TAR_DOWNLOAD $BEDROCK_TAR_PATH echo "Extracting bedrock.tar..." if [[ "$BEDROCK_TAR_DOWNLOAD" == *.zst ]]; then extractzst $BEDROCK_TAR_PATH $GETH_DATA_DIR elif [[ "$BEDROCK_TAR_DOWNLOAD" == *.lz4 ]]; then extractlz4 $BEDROCK_TAR_PATH $GETH_DATA_DIR else extract $BEDROCK_TAR_PATH $GETH_DATA_DIR fi # Remove tar file to save disk space rm $BEDROCK_TAR_PATH fi echo "Creating JWT..." mkdir -p $(dirname $BEDROCK_JWT_PATH) openssl rand -hex 32 > $BEDROCK_JWT_PATH echo "Creating Bedrock flag..." touch $INITIALIZED_FLAG ================================================ FILE: scripts/start-op-geth.sh ================================================ #!/bin/sh set -e # Wait for the Bedrock flag for this network to be set. echo "Waiting for Bedrock node to initialize..." while [ ! -f /shared/initialized.txt ]; do sleep 1 done # Override Holocene if [ ! -z "$OVERRIDE_HOLOCENE" ]; then EXTENDED_ARG="$EXTENDED_ARG --override.holocene=$OVERRIDE_HOLOCENE" fi # Start op-geth. exec geth \ --op-network=$NETWORK_NAME \ --datadir="$BEDROCK_DATADIR" \ --http \ --http.corsdomain="*" \ --http.vhosts="*" \ --http.addr=0.0.0.0 \ --http.port=8545 \ --http.api=eth,engine,web3,debug,net \ --metrics \ --metrics.influxdb \ --metrics.influxdb.endpoint=http://influxdb:8086 \ --metrics.influxdb.database=opgeth \ --authrpc.vhosts="*" \ --authrpc.addr=0.0.0.0 \ --authrpc.port=8551 \ --authrpc.jwtsecret=/shared/jwt.txt \ --rollup.sequencerhttp="$BEDROCK_SEQUENCER_HTTP" \ --rollup.disabletxpoolgossip=true \ --port="${PORT__OP_GETH_P2P:-39393}" \ --discovery.port="${PORT__OP_GETH_P2P:-39393}" \ --db.engine=pebble \ --state.scheme=hash \ --txlookuplimit=0 \ --history.state=0 \ --history.transactions=0 \ --txpool.pricebump=10 \ --txpool.lifetime=12h0m0s \ --rpc.txfeecap=4 \ --rpc.evmtimeout=0 \ --maxpeers=0 \ --nodiscover \ --gpo.percentile=60 \ --verbosity=3 \ --syncmode="full" \ --gcmode="$NODE_TYPE" \ $EXTENDED_ARG $@ ================================================ FILE: scripts/start-op-node.sh ================================================ #!/bin/sh set -e # Wait for the Bedrock flag for this network to be set. echo "Waiting for Bedrock node to initialize..." while [ ! -f /shared/initialized.txt ]; do sleep 1 done export EXTENDED_ARG="${EXTENDED_ARG:-} --network=$NETWORK_NAME --rollup.load-protocol-versions=true --rollup.halt=major" # Override Holocene if [ ! -z "$OVERRIDE_HOLOCENE" ]; then EXTENDED_ARG="$EXTENDED_ARG --override.holocene=$OVERRIDE_HOLOCENE" fi # Start op-node. exec op-node \ --l1=$OP_NODE__RPC_ENDPOINT \ --l2=http://op-geth:8551 \ --rpc.addr=0.0.0.0 \ --rpc.port=9545 \ --l2.jwt-secret=/shared/jwt.txt \ --l1.trustrpc \ --l1.rpckind=$OP_NODE__RPC_TYPE \ --l1.beacon=$OP_NODE__L1_BEACON \ --metrics.enabled \ --metrics.addr=0.0.0.0 \ --metrics.port=7300 \ --syncmode=consensus-layer \ --p2p.scoring=none \ --p2p.listen.ip=0.0.0.0 \ --p2p.listen.tcp=9222 \ --p2p.listen.udp=9222 \ $EXTENDED_ARG $@ ================================================ FILE: scripts/utils.sh ================================================ #!/bin/bash # extract: Extracts an archive into an output location. # Arguments: # arc: Archive to extract. # loc: Location to extract to. function extract() { mkdir -p $2 tar -xf $1 -C $2 } # extractzst: Extracts a zst archive into an output location. # Arguments: # arc: ZST archive to extract. # loc: Location to extract to. function extractzst() { mkdir -p $2 tar --use-compress-program=unzstd -xf $1 -C $2 } # extractlz4: Extracts a lz4 archive into an output location. # Arguments: # arc: lz4 archive to extract. # loc: Location to extract to. function extractlz4() { mkdir -p $2 tar --use-compress-program="lz4 --no-crc" -xf $1 -C $2 } # download: Downloads a file and provides basic progress percentages. # Arguments: # url: URL of the file to download. # out: Location to download the file to. function download() { aria2c --max-tries=0 -x 16 -s 16 -k100M -o $2 $1 }