Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
20f4b3b
try single node test
open-junius Dec 12, 2025
a0b3ed2
run node with one account
open-junius Dec 12, 2025
9b1d828
print log
open-junius Dec 12, 2025
9734e48
send output to null
open-junius Dec 12, 2025
9ea69a2
use single node for testing
open-junius Dec 12, 2025
d7b8182
try rustup
open-junius Dec 12, 2025
c6c5cc5
try rustup
open-junius Dec 12, 2025
e03ab9b
fix one failed test
open-junius Dec 12, 2025
ab6cedd
name binary build
open-junius Dec 13, 2025
d93eac9
try more times
open-junius Dec 13, 2025
4a042be
avoid register network failure
open-junius Dec 14, 2025
e542f15
update test description
open-junius Dec 14, 2025
0f06072
set network register cose as 1 TAO
open-junius Dec 14, 2025
d9809d6
update crowdloanCap
open-junius Dec 14, 2025
87beaec
update crowdloanCap
open-junius Dec 14, 2025
c38746c
update crowdloanCap
open-junius Dec 14, 2025
6e915dd
fix test
open-junius Dec 15, 2025
ef17253
avoid too fast transaction submit
open-junius Dec 15, 2025
26c9ba0
add sleep for tx finalized
open-junius Dec 15, 2025
ec9bb13
update docs for code change
open-junius Dec 15, 2025
b9c779c
bump version
open-junius Dec 15, 2025
0759aec
avoid send evm transaction continuously
open-junius Dec 16, 2025
a267edb
fix conflict
open-junius Dec 22, 2025
9fbdbb8
merge devnet ready
open-junius Jan 19, 2026
a0d2321
Merge branch 'devnet-ready' into single-node-for-e2e
open-junius Jan 21, 2026
970e8d0
revert to two nodes local
open-junius Jan 22, 2026
b1ef01a
fix wrong seconds
open-junius Jan 22, 2026
b93f382
run nodes and check logs
open-junius Jan 23, 2026
bf1a085
use ccx43
open-junius Jan 23, 2026
764caf0
commit Cargo.lock
open-junius Jan 26, 2026
b1892f7
try 5 nodes
open-junius Jan 26, 2026
f6a0166
start 5 nodes
open-junius Jan 27, 2026
83fd400
show start time
open-junius Jan 27, 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
13 changes: 11 additions & 2 deletions .github/workflows/contract-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ permissions:

jobs:
run:
runs-on: [self-hosted, type-ccx13]
runs-on: [self-hosted, type-ccx43]
env:
RUST_BACKTRACE: full
steps:
Expand All @@ -49,11 +49,20 @@ jobs:
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 libssl-dev llvm libudev-dev protobuf-compiler nodejs pkg-config

- name: Build node-subtensor and Ink contracts
run: |
cd ${{ github.workspace }}
rustup component add rust-src
cargo install cargo-contract
cargo build --workspace --profile release --features fast-runtime
cd contract-tests/bittensor
cargo contract build --release

- name: Run tests
uses: nick-fields/retry@v3
with:
timeout_minutes: 120
max_attempts: 3
max_attempts: 5
retry_wait_seconds: 60
command: |
cd ${{ github.workspace }}
Expand Down
23 changes: 8 additions & 15 deletions contract-tests/run-ci.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,12 @@
#!/bin/bash

echo "start run-ci.sh"
echo "$(date)"

cd contract-tests

cd bittensor

rustup component add rust-src
cargo install cargo-contract
cargo contract build --release

cd ../..

scripts/localnet.sh &>/dev/null &
scripts/localnet.sh --local5 &>/dev/null &

i=1
while [ $i -le 2000 ]; do
while [ $i -le 1000 ]; do
if nc -z localhost 9944; then
echo "node subtensor is running after $i seconds"
break
Expand All @@ -25,11 +16,11 @@ while [ $i -le 2000 ]; do
done

# port not available exit with error
if [ "$i" -eq 2000 ]; then
if [ "$i" -eq 1000 ]; then
exit 1
fi

sleep 10
sleep 2

if ! nc -z localhost 9944; then
echo "node subtensor exit, port not available"
Expand All @@ -43,7 +34,7 @@ npm i -g polkadot-api

bash get-metadata.sh

sleep 5
sleep 2

yarn install --frozen-lockfile

Expand All @@ -58,4 +49,6 @@ fi

pkill node-subtensor

sleep 2

exit 0
1 change: 0 additions & 1 deletion contract-tests/src/substrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ export async function getTransactionWatchPromise(tx: Transaction<{}, string, str

// TODO investigate why finalized not for each extrinsic
if (value.type === "finalized") {
console.log("Transaction is finalized in block:", value.txHash);
subscription.unsubscribe();
clearTimeout(timeoutId);
if (!value.ok) {
Expand Down
26 changes: 23 additions & 3 deletions contract-tests/src/subtensor.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import * as assert from "assert";
import { devnet, MultiAddress } from '@polkadot-api/descriptors';
import { TypedApi, TxCallData, Binary, Enum } from 'polkadot-api';
import { TypedApi, TxCallData, Binary, Enum, getTypedCodecs } from 'polkadot-api';
import { KeyPair } from "@polkadot-labs/hdkd-helpers"
import { getAliceSigner, waitForTransactionCompletion, getSignerFromKeypair, waitForTransactionWithRetry } from './substrate'
import { convertH160ToSS58, convertPublicKeyToSs58, ethAddressToH160 } from './address-utils'
import { tao } from './balance-math'
import internal from "stream";

// create a new subnet and return netuid
export async function addNewSubnetwork(api: TypedApi<typeof devnet>, hotkey: KeyPair, coldkey: KeyPair) {
Expand All @@ -26,6 +25,8 @@ export async function addNewSubnetwork(api: TypedApi<typeof devnet>, hotkey: Key
const newTotalNetworks = await api.query.SubtensorModule.TotalNetworks.getValue()
// could create multiple subnetworks during retry, just return the first created one
assert.ok(newTotalNetworks > totalNetworks)
// reset network last lock to 0 for tests
await resetNetworkLastLock(api)
return totalNetworks
}

Expand Down Expand Up @@ -398,4 +399,23 @@ export async function sendWasmContractExtrinsic(api: TypedApi<typeof devnet>, co
storage_deposit_limit: BigInt(1000000000)
})
await waitForTransactionWithRetry(api, tx, signer)
}
}

// Reset network last lock to 0 for tests, then the cose for network registration will be the default minimum
// We can make the const cost for each network registration for tests. avoid the cost spike
export async function resetNetworkLastLock(api: TypedApi<typeof devnet>) {
const alice = getAliceSigner()
const key = await api.query.SubtensorModule.NetworkLastLockCost.getKey()

// Get the codec for NetworkLastLockCost value (TaoCurrency/u128)
const codec = await getTypedCodecs(devnet)
const valueCodec = codec.query.SubtensorModule.NetworkLastLockCost.value

// Encode the value 0 as SCALE-encoded bytes
const encodedValue = valueCodec.enc(BigInt(0))

const changes: [Binary, Binary][] = [[Binary.fromHex(key.toString()), Binary.fromBytes(encodedValue)]];
const internalCall = api.tx.System.set_storage({ items: changes })
const tx = api.tx.Sudo.sudo({ call: internalCall.decodedCall })
await waitForTransactionWithRetry(api, tx, alice)
}
2 changes: 1 addition & 1 deletion contract-tests/test/alphaPool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { ethers } from "ethers"
import { tao } from "../src/balance-math";
import { ISTAKING_V2_ADDRESS, IStakingV2ABI } from "../src/contracts/staking";
// import { KeyPair } from "@polkadot-labs/hdkd-helpers";
describe("bridge token contract deployment", () => {
describe("Alpha Pool Test", () => {
// init eth part
const wallet = generateRandomEthersWallet();
let publicClient: PublicClient;
Expand Down
21 changes: 13 additions & 8 deletions contract-tests/test/leasing.precompile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ethers } from "ethers";
import { TypedApi } from "polkadot-api";
import { devnet } from "@polkadot-api/descriptors";
import { getAliceSigner, getBobSigner, getDevnetApi, waitForFinalizedBlock } from "../src/substrate";
import { forceSetBalanceToEthAddress } from "../src/subtensor";
import { forceSetBalanceToEthAddress, resetNetworkLastLock } from "../src/subtensor";
import { decodeAddress } from "@polkadot/util-crypto";
import { u8aToHex } from "@polkadot/util";
import { ILEASING_ADDRESS, ILeasingABI } from "../src/contracts/leasing";
Expand All @@ -24,6 +24,8 @@ describe("Test Leasing precompile", () => {
let leaseContract: ethers.Contract;
let crowdloanContract: ethers.Contract;
let neuronContract: ethers.Contract;
const crowdloanDeposit = BigInt(100_000_000_000);
let crowdloanCap: bigint;

const alice = getAliceSigner();
const bob = getBobSigner();
Expand All @@ -40,12 +42,19 @@ describe("Test Leasing precompile", () => {

await forceSetBalanceToEthAddress(api, wallet1.address);
await forceSetBalanceToEthAddress(api, wallet2.address);

await resetNetworkLastLock(api);
const minLockCost = await api.query.SubtensorModule.NetworkMinLockCost.getValue();
// guarantee that the crowdloan cap is larger than the deposit
if (minLockCost > crowdloanDeposit) {
crowdloanCap = minLockCost * BigInt(2);
} else {
crowdloanCap = crowdloanDeposit * BigInt(2);
}
});

it("gets an existing lease created on substrate side, its subnet id and its contributor shares", async () => {
const nextCrowdloanId = await api.query.Crowdloan.NextCrowdloanId.getValue();
const crowdloanDeposit = BigInt(100_000_000_000); // 100 TAO
const crowdloanCap = await api.query.SubtensorModule.NetworkLastLockCost.getValue() * BigInt(2);
const crowdloanEnd = await api.query.System.Number.getValue() + 100;
const leaseEmissionsShare = 15;
const leaseEnd = await api.query.System.Number.getValue() + 300;
Expand All @@ -67,8 +76,8 @@ describe("Test Leasing precompile", () => {
amount: crowdloanCap - crowdloanDeposit,
}).signAndSubmit(bob);

await waitForFinalizedBlock(api, crowdloanEnd);

await waitForFinalizedBlock(api, crowdloanEnd);
const nextLeaseId = await api.query.SubtensorModule.NextSubnetLeaseId.getValue();
await api.tx.Crowdloan.finalize({ crowdloan_id: nextCrowdloanId }).signAndSubmit(alice);

Expand Down Expand Up @@ -98,9 +107,7 @@ describe("Test Leasing precompile", () => {

it("registers a new leased network through a crowdloan and retrieves the lease", async () => {
const nextCrowdloanId = await api.query.Crowdloan.NextCrowdloanId.getValue();
const crowdloanDeposit = BigInt(100_000_000_000); // 100 TAO
const crowdloanMinContribution = BigInt(1_000_000_000); // 1 TAO
const crowdloanCap = await api.query.SubtensorModule.NetworkLastLockCost.getValue() * BigInt(2);
const crowdloanEnd = await api.query.System.Number.getValue() + 100;
const leasingEmissionsShare = 15;
const leasingEndBlock = await api.query.System.Number.getValue() + 300;
Expand Down Expand Up @@ -159,9 +166,7 @@ describe("Test Leasing precompile", () => {
await tx.wait();

const nextCrowdloanId = await api.query.Crowdloan.NextCrowdloanId.getValue();
const crowdloanDeposit = BigInt(100_000_000_000); // 100 TAO
const crowdloanMinContribution = BigInt(1_000_000_000); // 1 TAO
const crowdloanCap = await api.query.SubtensorModule.NetworkLastLockCost.getValue() * BigInt(2);
const crowdloanEnd = await api.query.System.Number.getValue() + 100;
const leasingEmissionsShare = 15;
const leasingEndBlock = await api.query.System.Number.getValue() + 200;
Expand Down
6 changes: 3 additions & 3 deletions contract-tests/test/staking.precompile.full-limit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe("Test staking precompile add remove limit methods", () => {
IStakingV2ABI,
wallet1,
);

await new Promise(resolve => setTimeout(resolve, 1000));
const tx = await contract.addStakeLimit(
hotkey.publicKey,
tao(2000),
Expand Down Expand Up @@ -131,7 +131,7 @@ describe("Test staking precompile add remove limit methods", () => {
IStakingV2ABI,
wallet2,
);

await new Promise(resolve => setTimeout(resolve, 1000));
const tx = await contract.addStakeLimit(
hotkey.publicKey,
tao(2000),
Expand Down Expand Up @@ -165,7 +165,7 @@ describe("Test staking precompile add remove limit methods", () => {
IStakingV2ABI,
wallet2,
);

await new Promise(resolve => setTimeout(resolve, 1000));
const tx = await contract.removeStakeFull(
hotkey.publicKey,
netuid,
Expand Down
6 changes: 6 additions & 0 deletions contract-tests/test/staking.precompile.wrap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ethers } from "ethers";
import { generateRandomEthersWallet } from "../src/utils";

import { abi, bytecode } from "../src/contracts/stakeWrap";
import { setMaxIdleHTTPParsers } from "http";

describe("Test staking precompile add from deployed contract", () => {
const hotkey = getRandomSubstrateKeypair();
Expand Down Expand Up @@ -62,19 +63,24 @@ describe("Test staking precompile add from deployed contract", () => {
const txResponse = await wallet1.sendTransaction(ethTransfer)
await txResponse.wait();

console.log("stakeWrap contract deployed, target: ", contract.target.toString());

const deployedContract = new ethers.Contract(
contract.target.toString(),
abi,
wallet1,
);

await new Promise(resolve => setTimeout(resolve, 1000));
const tx = await deployedContract.stake(
hotkey.publicKey,
netuid,
tao(2),
);
await tx.wait();

await new Promise(resolve => setTimeout(resolve, 1000));

const tx2 = await deployedContract.removeStake(
hotkey.publicKey,
netuid,
Expand Down
4 changes: 4 additions & 0 deletions contract-tests/test/subnet.precompile.hyperparameter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ describe("Test the Subnet precompile contract", () => {
await disableAdminFreezeWindowAndOwnerHyperparamRateLimit(api)
})

beforeEach(async () => {
await new Promise(resolve => setTimeout(resolve, 500))
})

it("Can register network without identity info", async () => {
const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue()

Expand Down
12 changes: 10 additions & 2 deletions node/src/chain_spec/localnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use super::*;

pub fn localnet_config(single_authority: bool) -> Result<ChainSpec, String> {
pub fn localnet_config(authority_count: u32) -> Result<ChainSpec, String> {
let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?;

// Give front-ends necessary data to present to users
Expand Down Expand Up @@ -32,11 +32,19 @@ pub fn localnet_config(single_authority: bool) -> Result<ChainSpec, String> {
.with_genesis_config_patch(localnet_genesis(
// Initial PoA authorities (Validators)
// aura | grandpa
if single_authority {
if authority_count == 1 {
// single authority allows you to run the network using a single node
vec![authority_keys_from_seed("One")]
} else if authority_count == 2 {
vec![
authority_keys_from_seed("One"),
authority_keys_from_seed("Two"),
]
} else {
vec![
authority_keys_from_seed("Dave"),
authority_keys_from_seed("Eve"),
authority_keys_from_seed("Ferdie"),
authority_keys_from_seed("One"),
authority_keys_from_seed("Two"),
]
Expand Down
5 changes: 3 additions & 2 deletions node/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ impl SubstrateCli for Cli {

fn load_spec(&self, id: &str) -> Result<Box<dyn sc_service::ChainSpec>, String> {
Ok(match id {
"dev" => Box::new(chain_spec::localnet::localnet_config(true)?),
"local" => Box::new(chain_spec::localnet::localnet_config(false)?),
"dev" => Box::new(chain_spec::localnet::localnet_config(1)?),
"local" => Box::new(chain_spec::localnet::localnet_config(2)?),
"local5" => Box::new(chain_spec::localnet::localnet_config(5)?),
"finney" => Box::new(chain_spec::finney::finney_mainnet_config()?),
"devnet" => Box::new(chain_spec::devnet::devnet_config()?),
"" | "test_finney" => Box::new(chain_spec::testnet::finney_testnet_config()?),
Expand Down
Loading
Loading