Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions .github/workflows/run-invariants.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: Run invariants on the local mainnet clone

# Manual trigger only
on:
workflow_dispatch:
pull_request:

permissions:
contents: read

concurrency:
group: run-invariants-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always

jobs:
localnet:
name: localnet
runs-on: [self-hosted, type-ccx33]
permissions:
contents: write

steps:
# -------------------------------
# Checkout repo
# -------------------------------
- name: Checkout sources
uses: actions/checkout@v4

# -------------------------------
# Install system dependencies
# -------------------------------
- name: Install dependencies
run: |
sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get update
sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get install -y --no-install-recommends -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" build-essential clang curl git make libssl-dev llvm libudev-dev protobuf-compiler pkg-config unzip

# -------------------------------
# Install Rust
# -------------------------------
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable

# -------------------------------
# Cache Cargo
# -------------------------------
- name: Utilize Shared Rust Cache
uses: Swatinem/rust-cache@v2
with:
key: "run-invariants"

# -------------------------------
# Build Subtensor node
# -------------------------------
- name: Build Subtensor node
run: cargo build --release -p node-subtensor

# -------------------------------
# Install Baedeker
# -------------------------------
- name: Install Baedeker
run: scripts/invariants/install_baedeker.sh

# -------------------------------
# Generate chain spec
# -------------------------------
- name: Generate chain spec
run: scripts/invariants/generate_spec.sh

# -------------------------------
# Start localnet nodes (background)
# -------------------------------
- name: Start localnet nodes
run: |
scripts/run_localnet.sh ./subtensor/target/release ./.bdk-env/specs/subtensor.json &
echo $! > /tmp/localnet.pid
sleep 5

# -------------------------------
# Wait until chain is producing blocks
# -------------------------------
- name: Wait for chain to produce blocks
run: scripts/invariants/wait_for_chain.sh

# -------------------------------
# Pull JS RPC test image from GHCR
# -------------------------------

# -------------------------------
# Run JS RPC tests
# -------------------------------
82 changes: 82 additions & 0 deletions scripts/invariants/generate_spec.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env bash
set -euo pipefail

# ---------------------------------------
# Resolve repo root
# ---------------------------------------

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"

# ---------------------------------------
# Config (overridable via env)
# ---------------------------------------

export RUST_LOG="${RUST_LOG:-info}"
export CHAINQL_WORKERS="${CHAINQL_WORKERS:-2}"
export CHAINQL_KEYS_CHUNK_SIZE="${CHAINQL_KEYS_CHUNK_SIZE:-20000}"

FORK_SOURCE="${FORK_SOURCE:-wss://entrypoint-finney.opentensor.ai}"
FORKED_SPEC="${FORKED_SPEC:-subtensor}"
RELAY_SPEC="${RELAY_SPEC:-rococo-local}"

SPEC_OUTPUT="${REPO_ROOT}/.bdk-env/specs/subtensor.json"

# ---------------------------------------
# Preconditions
# ---------------------------------------

command -v baedeker >/dev/null 2>&1 || {
echo "❌ baedeker is not installed"
exit 1
}

[[ -d "${REPO_ROOT}/.bdk-env" ]] || {
echo "❌ .bdk-env directory not found"
exit 1
}

# ---------------------------------------
# Logging
# ---------------------------------------

echo "=== Generating Subtensor chain spec ==="
echo "Repo root: $REPO_ROOT"
echo "Fork source: $FORK_SOURCE"
echo "Forked spec name: $FORKED_SPEC"
echo "Relay spec: $RELAY_SPEC"
echo "Workers: $CHAINQL_WORKERS"
echo "Keys chunk size: $CHAINQL_KEYS_CHUNK_SIZE"
echo "Rust log level: $RUST_LOG"
echo "Output spec: $SPEC_OUTPUT"
echo "======================================"

# ---------------------------------------
# Run Baedeker
# ---------------------------------------

baedeker \
--spec=docker \
-J"${REPO_ROOT}/vendor/" \
--generator=docker_compose="${REPO_ROOT}/.bdk-env" \
--generator=docker_compose_discover="${REPO_ROOT}/.bdk-env/discover.env" \
--secret=file="${REPO_ROOT}/.bdk-env/secret" \
--tla-str="relay_spec=${RELAY_SPEC}" \
--tla-str="repoDir=$(realpath "${REPO_ROOT}")" \
--input-modules='lib:baedeker-library/ops/nginx.libsonnet' \
--input-modules='lib:baedeker-library/ops/devtools.libsonnet' \
"${REPO_ROOT}/forkless-data.jsonnet" \
--tla-str="forked_spec=${FORKED_SPEC}" \
--tla-str="fork_source=${FORK_SOURCE}" \
"${REPO_ROOT}/rewrites.jsonnet"

# ---------------------------------------
# Post-check
# ---------------------------------------

if [[ ! -f "$SPEC_OUTPUT" ]]; then
echo "❌ Spec generation failed: $SPEC_OUTPUT not found"
exit 1
fi

echo "✅ Chain spec generated successfully"
70 changes: 70 additions & 0 deletions scripts/invariants/install_baedeker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
set -euo pipefail

# -----------------------------
# Configuration
# -----------------------------

# Set to a tag like "v0.7.3" to pin, or leave empty for latest
BAEDEKER_VERSION="${BAEDEKER_VERSION:-latest}"

INSTALL_DIR="/usr/local/bin"
TMP_DIR="$(mktemp -d)"

cleanup() {
rm -rf "$TMP_DIR"
}
trap cleanup EXIT

echo "Installing baedeker (version: $BAEDEKER_VERSION)"

# -----------------------------
# Resolve release metadata
# -----------------------------

if [[ "$BAEDEKER_VERSION" == "latest" ]]; then
API_URL="https://api.github.com/repos/UniqueNetwork/baedeker/releases/latest"
else
API_URL="https://api.github.com/repos/UniqueNetwork/baedeker/releases/tags/${BAEDEKER_VERSION}"
fi

ASSET_URL=$(
curl -fsSL "$API_URL" |
jq -r '.assets[]
| select(.name | test("linux.*(x86_64|amd64).*tar.gz"))
| .browser_download_url' |
head -n 1
)

if [[ -z "$ASSET_URL" || "$ASSET_URL" == "null" ]]; then
echo "❌ Failed to find Linux baedeker release asset"
exit 1
fi

echo "Downloading: $ASSET_URL"

# -----------------------------
# Download & install
# -----------------------------

curl -fsSL "$ASSET_URL" -o "$TMP_DIR/baedeker.tar.gz"

tar -xzf "$TMP_DIR/baedeker.tar.gz" -C "$TMP_DIR"

if [[ ! -f "$TMP_DIR/baedeker" ]]; then
echo "❌ baedeker binary not found in archive"
exit 1
fi

chmod +x "$TMP_DIR/baedeker"

sudo mv "$TMP_DIR/baedeker" "${INSTALL_DIR}/baedeker"

# -----------------------------
# Verification
# -----------------------------

echo "Installed baedeker to ${INSTALL_DIR}/baedeker"
baedeker --version

echo "✅ baedeker installation complete"
97 changes: 97 additions & 0 deletions scripts/invariants/run_localnet.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/usr/bin/env bash
set -euo pipefail

# -------------------------------
# Usage
# -------------------------------
# ./run_localnet.sh <BUILD_DIRECTORY> <SPEC_PATH>
# Example:
# ./run_localnet.sh ./subtensor/target/release ./.bdk-env/specs/subtensor.json
# -------------------------------

BUILD_DIR="${1:?Build directory missing}"
SPEC_PATH="${2:?Spec path missing}"

BIN="${BUILD_DIR}/node-subtensor"

# -------------------------------
# Purge previous chain state
# -------------------------------
echo "*** Purging previous state..."

for NODE in alice bob charlie; do
"$BIN" purge-chain -y --base-path "/tmp/$NODE" --chain="$SPEC_PATH" >/dev/null 2>&1
done

echo "*** Previous chain state purged"

# -------------------------------
# Define nodes
# -------------------------------
ALICE_BASE="/tmp/alice"
BOB_BASE="/tmp/bob"
CHARLIE_BASE="/tmp/charlie"

alice_start=(
"$BIN"
--base-path "$ALICE_BASE"
--chain="$SPEC_PATH"
--keystore-path="./.bdk-env/secret/keystore/subtensor-node-alice"
--node-key-file="./.bdk-env/secret/node/subtensor-node-alice"
--port 30334
--rpc-port 9946
--validator
--rpc-cors=all
--rpc-external
--unsafe-rpc-external
--rpc-methods=unsafe
--allow-private-ipv4
--discover-local
)

bob_start=(
"$BIN"
--base-path "$BOB_BASE"
--chain="$SPEC_PATH"
--keystore-path="./.bdk-env/secret/keystore/subtensor-node-bob"
--node-key-file="./.bdk-env/secret/node/subtensor-node-bob"
--port 30335
--rpc-port 9935
--validator
--allow-private-ipv4
--discover-local
--bootnodes /ip4/127.0.0.1/tcp/30334/p2p/12D3KooWMJ5Gmn2SPfx2TEFfvido1X8xhUZUnC2MbD2yTwKPQak8
)

charlie_start=(
"$BIN"
--base-path "$CHARLIE_BASE"
--chain="$SPEC_PATH"
--keystore-path="./.bdk-env/secret/keystore/subtensor-node-charlie"
--node-key-file="./.bdk-env/secret/node/subtensor-node-charlie"
--port 30336
--rpc-port 9936
--validator
--allow-private-ipv4
--discover-local
--bootnodes /ip4/127.0.0.1/tcp/30334/p2p/12D3KooWMJ5Gmn2SPfx2TEFfvido1X8xhUZUnC2MbD2yTwKPQak8
)

# -------------------------------
# Start nodes in background
# -------------------------------

echo "*** Starting localnet nodes (Alice/Bob/Charlie)..."
echo "Press Ctrl+C to terminate"

# trap ensures all background nodes are killed if script is interrupted
trap 'kill 0' SIGINT

# Run nodes concurrently
("${alice_start[@]}" 2>&1 &)
("${bob_start[@]}" 2>&1 &)
("${charlie_start[@]}" 2>&1 &)

# Keep script alive to allow external checks / JS tests
# CI runner will terminate at job end
sleep infinity
Loading
Loading