Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
7e93f31
Migration to fix StakingHotKeys added
grbIzl Nov 24, 2025
dbc8520
Update proposer.rs
JohnReedV Dec 10, 2025
f8ea50c
update timing
JohnReedV Dec 11, 2025
9142ff3
Merge remote-tracking branch 'origin/devnet-ready' into feat/staking-…
grbIzl Dec 16, 2025
f036f7b
Merge remote-tracking branch 'origin/devnet-ready' into feat/staking-…
grbIzl Dec 16, 2025
3b8fcef
Fix the build after the merge
grbIzl Dec 16, 2025
0aa2055
cargo fmt
grbIzl Dec 16, 2025
5e6becf
Consider iteration read
grbIzl Dec 18, 2025
354f1ee
Set default weights for system pallets.
shamil-gadelshin Dec 19, 2025
face3f4
Bump spec version
shamil-gadelshin Dec 19, 2025
94a4f41
add frame_system extensions weight info
l0r1s Dec 19, 2025
3954bf0
Add sudo-only hyperparameter for start call delay
ppolewicz Dec 21, 2025
b5ce250
Add comprehensive test for start call delay hyperparameter
ppolewicz Dec 22, 2025
93c2e4e
cargo fmt
ppolewicz Dec 22, 2025
55b0e90
Merge branch 'devnet-ready' into start_call_delay_hyperparameter
ppolewicz Dec 22, 2025
e3bdadc
bump version
open-junius Dec 22, 2025
745db21
Update localnet_patch.sh to use InitialStartCallDelay
ppolewicz Dec 27, 2025
f81c5db
Refactor localnet_patch.sh to use reusable patch_file function
ppolewicz Dec 27, 2025
7473584
Update contract tests to use InitialStartCallDelay constant
ppolewicz Dec 29, 2025
2539a7a
Merge branch 'devnet-ready' into mevshield-mark-decryption-failed-dra…
JohnReedV Dec 29, 2025
2df4cea
bump spec
JohnReedV Dec 29, 2025
3eb616b
Incorporate subtensor transaction extension in contracts
ales-otf Dec 29, 2025
cd7db2c
Add e2e contract tests for tx-extension
ales-otf Dec 29, 2025
c6e34d1
Bump spec version
ales-otf Dec 29, 2025
dccdc71
Fix lints
ales-otf Dec 30, 2025
358c611
Merge pull request #2328 from opentensor/fix/tx-extension-in-precompiles
sam0x17 Dec 30, 2025
ad7af03
Merge pull request #2283 from opentensor/mevshield-mark-decryption-fa…
JohnReedV Dec 30, 2025
beb6b9e
Merge pull request #2300 from opentensor/feat/staking-hot-keys-migration
grbIzl Jan 5, 2026
c57c7c9
Set StartCallDelay to 10 blocks in localnet genesis config
ppolewicz Dec 31, 2025
0bd25df
Remove get_start_call_delay getter function
ppolewicz Jan 8, 2026
bb6495b
Replace DefaultStartCallDelay with T::InitialStartCallDelay
ppolewicz Jan 8, 2026
0cb4b88
Add start_call_delay field to GenesisConfig for benchmarks
ppolewicz Jan 8, 2026
6b3ac04
apply review comments
ppolewicz Jan 8, 2026
3f985eb
commit Cargo.lock
konrad0960 Dec 1, 2025
7c56e26
CI fixes
konrad0960 Dec 2, 2025
aa08aa6
refactor: pass epoch terms to voting power instead of re-reading state
konrad0960 Jan 8, 2026
e541d53
add removal hysteresis
konrad0960 Jan 8, 2026
84cbad3
cargo fmt
JohnReedV Jan 9, 2026
4af751d
move update_voting_power_for_subnet and fix formatting
konrad0960 Jan 9, 2026
6144ef6
get total voting power precompile
konrad0960 Jan 9, 2026
e484cf1
add coldkey stake on subnet
open-junius Jan 12, 2026
867502c
add address mapping method
open-junius Jan 12, 2026
b4e1ca9
fix e2e tests
open-junius Jan 12, 2026
80a80e2
revert to test all
open-junius Jan 12, 2026
7968a5b
Merge pull request #2315 from backend-developers-ltd/start_call_delay…
sam0x17 Jan 12, 2026
b2ffa20
update read
JohnReedV Jan 12, 2026
c17b982
emit failure on pre-dispatch failures
JohnReedV Jan 12, 2026
91b3e70
bump spec
JohnReedV Jan 12, 2026
8030e4b
bump spec
JohnReedV Jan 12, 2026
efdece8
replace direct indexing
JohnReedV Jan 12, 2026
b3ced53
init solution
open-junius Jan 13, 2026
97a9eca
fix unit test
open-junius Jan 13, 2026
33335a0
fix test
open-junius Jan 13, 2026
1d225b3
bump version
open-junius Jan 13, 2026
c691ab2
Merge pull request #2339 from opentensor/fix-benchmakrs-start-call-up…
sam0x17 Jan 13, 2026
a19ddd8
Merge remote-tracking branch 'origin/main' into devnet-ready
sam0x17 Jan 13, 2026
18e633c
Merge branch 'devnet-ready' into fix-mev-shield-emit-failure-event-on…
JohnReedV Jan 13, 2026
cacf3b4
Merge branch 'devnet-ready' into set-start-call-init-0
JohnReedV Jan 13, 2026
ebd486c
bump spec
JohnReedV Jan 13, 2026
698188f
Merge pull request #2340 from opentensor/fix-mev-shield-emit-failure-…
JohnReedV Jan 13, 2026
f668d9d
use runtime default constant for start call
ibraheem-abe Jan 13, 2026
9b43431
Simplify the formula for removal of VotingPower entry
ppolewicz Jan 13, 2026
e4ce9b9
Merge branch 'devnet-ready' into voting-power-feature
konrad0960 Jan 13, 2026
fab3106
Merge pull request #2342 from opentensor/fix/abe/remove-startcall-upd…
open-junius Jan 14, 2026
18f111b
Merge branch 'devnet-ready' into set-start-call-init-0
open-junius Jan 14, 2026
cda6423
update test comments
open-junius Jan 14, 2026
ed87b94
Merge pull request #2341 from opentensor/set-start-call-init-0
open-junius Jan 14, 2026
6196849
Adjust DefaultVotingPowerEmaAlpha to 2 weeks
ppolewicz Jan 14, 2026
bd3969a
cargo fmt
ppolewicz Jan 14, 2026
c4b8ff9
cargo clippy
ppolewicz Jan 14, 2026
3d65741
Thank you clippy but I know what I'm doing
ppolewicz Jan 14, 2026
4ce1f5d
Fix macro conflict
ppolewicz Jan 14, 2026
b8f423d
Merge branch 'devnet-ready' into coldkey-stake-on-subnet
open-junius Jan 15, 2026
b0e3440
rebase code
open-junius Jan 15, 2026
c94b2e7
bump version
open-junius Jan 15, 2026
495a78f
contract e2e ci in self-host
open-junius Jan 15, 2026
7685088
need more time to build
open-junius Jan 15, 2026
eeb01f1
fix macro usage
ppolewicz Jan 15, 2026
7051e87
Merge pull request #2345 from opentensor/self-host-ci
sam0x17 Jan 15, 2026
7e6113f
Merge pull request #2337 from opentensor/coldkey-stake-on-subnet
sam0x17 Jan 15, 2026
d06625e
Merge branch 'devnet-ready' into set-system-weights
sam0x17 Jan 15, 2026
1ff8d4c
Merge pull request #2311 from opentensor/set-system-weights
sam0x17 Jan 15, 2026
c888f20
Merge branch 'devnet-ready' into voting-power-feature
ppolewicz Jan 15, 2026
0e1bd21
Fix precompile to have unique id
ppolewicz Jan 15, 2026
678f29b
merge with target
open-junius Jan 16, 2026
1526f89
Change the precompile address again as after something else merged th…
ppolewicz Jan 16, 2026
c66f782
update test
ppolewicz Jan 16, 2026
5d10274
added workflow to check node compat during psdk upgrade
l0r1s Jan 16, 2026
a21a929
Merge pull request #2354 from opentensor/check-node-compat-workflow
l0r1s Jan 19, 2026
d9634ef
update dependency for transaction replacement env
JohnReedV Jan 19, 2026
3d528d2
Merge pull request #2240 from konrad0960/voting-power-feature
sam0x17 Jan 19, 2026
8a1e018
Revert "Voting Power EMA"
sam0x17 Jan 19, 2026
cf0e7f3
Merge pull request #2357 from opentensor/revert-2240-voting-power-fea…
sam0x17 Jan 19, 2026
22dcc5e
Merge pull request #2356 from opentensor/toggle-transaction-replaceme…
sam0x17 Jan 19, 2026
11a587e
Merge pull request #2359 from opentensor/devnet-ready
sam0x17 Jan 19, 2026
39529f4
Merge pull request #2316 from opentensor/remove-redundant-variable
open-junius Jan 20, 2026
a120a52
Update proposer.rs
JohnReedV Jan 20, 2026
bf6e651
bump spec
JohnReedV Jan 20, 2026
b9e7f96
remove error
JohnReedV Jan 20, 2026
f9cb60d
clippy
JohnReedV Jan 20, 2026
f6ba7f4
Merge pull request #2361 from opentensor/fix-mevshield-decrypt-attempt-1
sam0x17 Jan 21, 2026
cd99086
Merge remote-tracking branch 'origin/devnet' into testnet
sam0x17 Jan 21, 2026
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
88 changes: 88 additions & 0 deletions .github/workflows/check-node-compat.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Check Node Compat

on:
pull_request:
types: [labeled]
branches: [devnet-ready]

concurrency:
group: check-node-compat-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always

jobs:
build:
name: build ${{ matrix.version.name }}
runs-on: [self-hosted, type-ccx33]
if: contains(github.event.pull_request.labels.*.name, 'check-node-compat')
env:
RUST_BACKTRACE: full
strategy:
matrix:
version:
- { name: old, ref: devnet-ready }
- { name: new, ref: ${{ github.head_ref }} }

steps:
- 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

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

- name: Utilize Shared Rust Cache
uses: Swatinem/rust-cache@v2
with:
key: "check-node-compat-${{ matrix.version.name }}"

- name: Checkout ${{ matrix.version.name }}
uses: actions/checkout@v4
with:
ref: ${{ matrix.version.ref }}
path: ${{ matrix.version.name }}

- name: Build ${{ matrix.version.name }}
working-directory: ${{ matrix.version.name }}
run: cargo build --release --locked

- name: Upload ${{ matrix.version.name }} node binary
uses: actions/upload-artifact@v4
with:
name: node-subtensor-${{ matrix.version.name }}
path: ${{ matrix.version.name }}/target/release/node-subtensor
retention-days: 1

test:
needs: [build]
runs-on: [self-hosted, type-ccx33]
steps:
- name: Download old node binary
uses: actions/download-artifact@v4
with:
name: node-subtensor-old
path: /tmp/node-subtensor-old

- name: Download new node binary
uses: actions/download-artifact@v4
with:
name: node-subtensor-new
path: /tmp/node-subtensor-new

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "24"

- name: Install npm dependencies
working-directory: ${{ github.workspace }}/.github/workflows/check-node-compat
run: npm install

- name: Run test
working-directory: ${{ github.workspace }}/.github/workflows/check-node-compat
run: npm run test
206 changes: 206 additions & 0 deletions .github/workflows/check-node-compat/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import { spawnSync, spawn, ChildProcess } from "node:child_process";
import { writeFile } from "node:fs/promises";

const all = Promise.all.bind(Promise);

const SECOND = 1000;
const MINUTE = 60 * SECOND;

const OLD_BINARY_PATH = "/tmp/node-subtensor-old";
const NEW_BINARY_PATH = "/tmp/node-subtensor-new";
const CHAIN_SPEC_PATH = "/tmp/local.json";

const ONE_OPTIONS = {
binaryPath: OLD_BINARY_PATH,
basePath: "/tmp/one",
name: "one",
port: 30333,
rpcPort: 9933,
validator: true,
};

const TWO_OPTIONS = {
binaryPath: OLD_BINARY_PATH,
basePath: "/tmp/two",
name: "two",
port: 30334,
rpcPort: 9944,
validator: true,
};

const ALICE_OPTIONS = {
binaryPath: OLD_BINARY_PATH,
basePath: "/tmp/alice",
name: "alice",
port: 30335,
rpcPort: 9955,
validator: false,
};

type Node = { name: string; binaryPath: string; process: ChildProcess };

async function main() {
await generateChainSpec();

const one = startNode(ONE_OPTIONS);
await started(one);

const two = startNode(TWO_OPTIONS);
await started(two);

await all([peerCount(one, 1), peerCount(two, 1)]);
await all([finalizedBlocks(one, 5), finalizedBlocks(two, 5)]);

const alice = startNode(ALICE_OPTIONS);
await started(alice);

await all([peerCount(one, 2), peerCount(two, 2), peerCount(alice, 2)]);
await all([finalizedBlocks(one, 10), finalizedBlocks(two, 10), finalizedBlocks(alice, 10)]);

// Swap 'alice' node with the new binary
await stop(alice);
const aliceNew = startNode({ ...ALICE_OPTIONS, binaryPath: NEW_BINARY_PATH });
await started(aliceNew);

await all([peerCount(one, 2), peerCount(two, 2), peerCount(aliceNew, 2)]);
await all([finalizedBlocks(one, 15), finalizedBlocks(two, 15), finalizedBlocks(aliceNew, 15)]);

// Swap 'one' node with the new binary
await stop(one);
const oneNew = startNode({ ...ONE_OPTIONS, binaryPath: NEW_BINARY_PATH });
await started(oneNew);

await all([peerCount(two, 2), peerCount(aliceNew, 2), peerCount(oneNew, 2)]);
await all([finalizedBlocks(oneNew, 20), finalizedBlocks(two, 20), finalizedBlocks(aliceNew, 20)]);

// Swap 'two' node with the new binary
await stop(two);
const twoNew = startNode({ ...TWO_OPTIONS, binaryPath: NEW_BINARY_PATH });
await started(twoNew);

await all([peerCount(oneNew, 2), peerCount(twoNew, 2), peerCount(aliceNew, 2)]);
await all([finalizedBlocks(oneNew, 50), finalizedBlocks(twoNew, 50), finalizedBlocks(aliceNew, 50)]);

await all([stop(oneNew), stop(twoNew), stop(aliceNew)]);

log("Test completed with success, binaries are compatible ✅");
}

// Generate the chain spec for the local network
const generateChainSpec = async () => {
const result = spawnSync(
OLD_BINARY_PATH,
["build-spec", "--disable-default-bootnode", "--raw", "--chain", "local"],
{ maxBuffer: 1024 * 1024 * 10 }, // 10MB
);

if (result.status !== 0) {
throw new Error(`Failed to generate chain spec: ${result.stderr.toString()}`);
}

const stdout = result.stdout.toString();
await writeFile(CHAIN_SPEC_PATH, stdout, { encoding: "utf-8" });
};

// Start a node with the given options
const startNode = (opts: {
binaryPath: string;
basePath: string;
name: string;
port: number;
rpcPort: number;
validator: boolean;
}): Node => {
const process = spawn(opts.binaryPath, [
`--${opts.name}`,
...["--chain", CHAIN_SPEC_PATH],
...["--base-path", opts.basePath],
...["--port", opts.port.toString()],
...["--rpc-port", opts.rpcPort.toString()],
...(opts.validator ? ["--validator"] : []),
"--rpc-cors=all",
"--allow-private-ipv4",
"--discover-local",
"--unsafe-force-node-key-generation",
]);

process.on("error", (error) => console.error(`${opts.name} (error): ${error}`));
process.on("close", (code) => log(`${opts.name}: process closed with code ${code}`));

return { name: opts.name, binaryPath: opts.binaryPath, process };
};

const stop = (node: Node): Promise<void> => {
return new Promise((resolve, reject) => {
node.process.on("close", resolve);
node.process.on("error", reject);

if (!node.process.kill()) {
reject(new Error(`Failed to stop ${node.name}`));
}
});
};

// Ensure the node has correctly started
const started = (node: Node, timeout = 30 * SECOND) => {
const errorMessage = `Failed to start ${node.name} in time`;

return innerEnsure(node, errorMessage, timeout, (data, ok) => {
if (data.includes("💤 Idle")) {
log(`${node.name}: started using ${node.binaryPath}`);
ok();
}
});
};

// Ensure the node has reached the expected number of peers
const peerCount = (node: Node, expectedPeers: number, timeout = 30 * SECOND) => {
const errorMessage = `Failed to reach ${expectedPeers} peers in time`;

return innerEnsure(node, errorMessage, timeout, (data, ok) => {
const maybePeers = /Idle \((?<peers>\d+) peers\)/.exec(data)?.groups?.peers;
if (!maybePeers) return;

const peers = parseInt(maybePeers);
if (peers >= expectedPeers) {
log(`${node.name}: reached ${expectedPeers} peers`);
ok();
}
});
};

// Ensure the node has reached the expected number of finalized blocks
const finalizedBlocks = (node: Node, expectedFinalized: number, timeout = 10 * MINUTE) => {
const errorMessage = `Failed to reach ${expectedFinalized} finalized blocks in time`;

return innerEnsure(node, errorMessage, timeout, (data, ok) => {
const maybeFinalized = /finalized #(?<blocks>\d+)/.exec(data)?.groups?.blocks;
if (!maybeFinalized) return;

const finalized = parseInt(maybeFinalized);
if (finalized >= expectedFinalized) {
log(`${node.name}: reached ${expectedFinalized} finalized blocks`);
ok();
}
});
};

// Helper function to ensure a condition is met within a timeout
function innerEnsure(node: Node, errorMessage: string, timeout: number, f: (data: string, ok: () => void) => void) {
return new Promise<void>((resolve, reject) => {
const id = setTimeout(() => reject(new Error(errorMessage)), timeout);

const fn = (data: string) =>
f(data, () => {
clearTimeout(id);
node.process.stderr?.off("data", fn);
resolve();
});

node.process.stderr?.on("data", fn);
});
}

const log = (message: string) => console.log(`[${new Date().toISOString()}] ${message}`);

main();
Loading
Loading