Skip to content

Repository files navigation

Hardfork Upgrade Tracking

This project provides a simple server to track the upgrade status of nodes in a network. It exposes a web-based dashboard to visualize the upgrade progress and an API for nodes to submit their status.

Table of Contents

Prerequisites

1. Setup

  1. Clone the repository:

    git clone https://github.com/o1-labs/hardfork-upgrade-tracking
    cd hardfork-upgrade-tracking
  2. Install dependencies:

    npm install
  3. Set up environment variables:

    Create a .env file by copying the example file:

    cp .env.example .env

    Edit the .env file and set the DATABASE_URL to your PostgreSQL connection string. For example:

    DATABASE_URL="postgresql://user:password@localhost:5432/hardfork_tracking?schema=public"
    

    You can also optionally change the RELEASE_PERCENTAGE.

    Optional — SHOW_NON_BP_NODES. By default the dashboard table shows one row per block producer, and nodes reporting no block producer key are hidden (they are still stored, and readable via GET /submit/stats). Set SHOW_NON_BP_NODES=true to admit those nodes as their own rows, keyed by peer_id. This is meant for networks where we operate no block producers of our own — on mainnet the fleet is archive + seed nodes, so every node we run reports a null BP key and the default view is permanently empty. With the flag on the count cards read "Nodes" rather than "Block Producers", since the rows are no longer one-per-block-producer. Stake figures are identical either way: keyless rows carry no stake and are excluded from the stake math, so the release-target gate still measures block producer stake only.

  4. Apply the database schema:

    Run the following command to create the tables in your database:

    npx prisma db push

    Alternatively, you can use migrations:

    npx prisma migrate dev

2. Running the Project

Development Mode

You can run the server in development mode, which will automatically restart on file changes:

npm run dev

The server will start on http://localhost:3000.

Production (Node.js)

Build the project first and then start the server:

npm run build
npm run start

Production (Docker)

Docker images are published to GitHub Container Registry at ghcr.io/o1-labs/hardfork-upgrade-tracking.

Pull and run a pre-built image:

docker run --rm -p 3000:3000 \
  -e DATABASE_URL="postgresql://user:password@host:5432/db" \
  -e RELEASE_PERCENTAGE="65" \
  -e SHOW_NON_BP_NODES="false" \
  ghcr.io/o1-labs/hardfork-upgrade-tracking:latest

Build locally using the Makefile:

# Using Docker
make build

# Using Podman
make podman-build

Run the locally built image:

# Using Docker
DATABASE_URL="postgresql://user:password@host:5432/db" RELEASE_PERCENTAGE=65 make run

# Using Podman
DATABASE_URL="postgresql://user:password@host:5432/db" RELEASE_PERCENTAGE=65 make podman-run

The container automatically runs prisma db push on startup to apply the database schema.

Demo environment with podman-compose:

A complete demo environment with PostgreSQL and optional Mina node is available in the demo/ directory:

cd demo

# Start tracker with postgres
podman-compose up -d

# Or include a Mina daemon that submits stats
podman-compose --profile with-mina up -d

See demo/README.md for full instructions.

3. Viewing the UI

Once the server is running, you can view the dashboard by opening your web browser and navigating to:

http://localhost:3000/

The dashboard displays the current upgrade progress of the network, including:

  • Percentage of active stake that has upgraded
  • Total number of upgraded vs non-upgraded nodes
  • Block producer upgrade status with stake percentages
  • Export functionality to download data as CSV

4. API Reference

Dashboard

Method Endpoint Auth Description
GET / No HTML dashboard

Node Stats

Nodes submit their status to track upgrade progress across the network.

Method Endpoint Auth Description
POST /submit/stats No Submit node stats
GET /submit/stats No Get all node stats
GET /submit/stats/:peerId No Get stats for a specific peer

Submit Node Stats

Request Body:

{
  "max_observed_block_height": 8392,
  "commit_hash": "a1b2c3d4",
  "chain_id": "mainnet",
  "peer_id": "12D3KooWL7tVWT3LpBDv3p5bLNKm2w5V51s1A4Q4Zg4Q4Yq4b4Q4",
  "peer_count": 10,
  "timestamp": "2026-01-26T10:00:00.000Z",
  "block_producer_public_key": "B62q..."
}

Example:

curl -X POST http://localhost:3000/submit/stats \
  -H "Content-Type: application/json" \
  -d '{
    "max_observed_block_height": 8392,
    "commit_hash": "a1b2c3d4",
    "chain_id": "mainnet",
    "peer_id": "12D3KooWL7tVWT3LpBDv3p5bLNKm2w5V51s1A4Q4Zg4Q4Yq4b4Q4",
    "peer_count": 10,
    "timestamp": "2026-01-26T10:00:00.000Z",
    "block_producer_public_key": "B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtS5sKqLYxhYGDzuDv2VRvgH"
  }'

Get All Stats

curl http://localhost:3000/submit/stats

Get Stats by Peer ID

curl http://localhost:3000/submit/stats/12D3KooWL7tVWT3LpBDv3p5bLNKm2w5V51s1A4Q4Zg4Q4Yq4b4Q4

Block Producers

Block producer stake data is used to calculate the percentage of active stake that has upgraded.

Method Endpoint Auth Description
GET /block-producers No List all block producers
GET /block-producers/last-sync No Get last CSV sync timestamp
GET /block-producers/:publicKey No Get a specific block producer
POST /block-producers/upload Yes Upload CSV data

List All Block Producers

curl http://localhost:3000/block-producers

Get Last Sync Time

curl http://localhost:3000/block-producers/last-sync

Get Block Producer by Public Key

curl http://localhost:3000/block-producers/B62qrQKS9ghd91shs73TCmBJRW9GzvTJK443DPx2YbqcyoLc56g1ny9

Upload CSV

The CSV must have the following columns:

  • bp_public_key - Block producer public key (B62...)
  • total_stake - Total stake amount
  • num_delegators - Number of delegators
  • is_active - Whether BP is active (true/false)
  • percent_total_stake - Percentage of total stake, on a 0–100 scale (e.g. 12.5 for 12.5%)
  • percent_total_active_stake - Percentage of active stake, on a 0–100 scale (e.g. 12.5 for 12.5%)
curl -X POST http://localhost:3000/block-producers/upload \
  -H "Authorization: Bearer $CSV_UPLOAD_TOKEN" \
  -H "Content-Type: text/csv" \
  --data-binary @block_producers.csv

Valid Commits

A node is considered "upgraded" if its commit_hash matches one of the valid commits in the database.

Method Endpoint Auth Description
GET /valid-commits No List all valid commits
POST /valid-commits Yes Add commit(s)
DELETE /valid-commits/:hash Yes Remove a commit

List Valid Commits

curl http://localhost:3000/valid-commits

Add a Single Commit

curl -X POST http://localhost:3000/valid-commits \
  -H "Authorization: Bearer $CSV_UPLOAD_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"hash": "f1e40a7ef71c799b5af8821ff85aadb44f53a377", "label": "3.3.0-compatible"}'

Add Multiple Commits

curl -X POST http://localhost:3000/valid-commits \
  -H "Authorization: Bearer $CSV_UPLOAD_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"commits": [{"hash": "abc123", "label": "v1.0"}, {"hash": "def456"}]}'

Delete a Commit

curl -X DELETE http://localhost:3000/valid-commits/abc123 \
  -H "Authorization: Bearer $CSV_UPLOAD_TOKEN"

5. Authentication

Protected endpoints require a bearer token. Set the CSV_UPLOAD_TOKEN environment variable:

# In .env
CSV_UPLOAD_TOKEN="your-secret-token"

In production, this token should be stored in a secrets manager (e.g., GCP Secret Manager) and injected as an environment variable.

6. Testing

Run the test suite:

npm test

Tests cover:

  • CSV parsing for block producer data
  • Stake calculation logic with deduplication
  • Upgrade check (commit hash validation)
  • Template helper functions

Tests are automatically run in CI on every pull request and must pass before merging.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages