Skip to content

bittensor-core: one Rust core (keys, keyfiles, timelock, codec, RFC-0078 digest, Ledger) under a thin Python SDK#2846

Open
unarbos wants to merge 747 commits into
mainfrom
bittensor-core-exploration
Open

bittensor-core: one Rust core (keys, keyfiles, timelock, codec, RFC-0078 digest, Ledger) under a thin Python SDK#2846
unarbos wants to merge 747 commits into
mainfrom
bittensor-core-exploration

Conversation

@unarbos

@unarbos unarbos commented Jul 9, 2026

Copy link
Copy Markdown

Summary

Implements the full sdk/bittensor-core-spec.md plan (phases 0–5). One workspace crate, bittensor-core, now owns everything whose right answer is chain-defined — sp-core key primitives, keyfiles, drand timelock, ML-KEM, the SCALE codec + runtime-metadata engine, extrinsic assembly, multisig derivation, and the RFC-0078 merkleized-metadata digest — exposed to Python through one PyO3 binding crate (bittensor-core-py, PyPI: bittensor-core). The Python public API is frozen throughout; each phase landed as its own commit and is independently revertible.

By phase:

  • Phase 0 — decoded-value shape corpus recorded from cyscale as the codec's compatibility contract (sdk/python/tests/fixtures/shape_corpus/), crate skeleton, build-core-wheels.yml.
  • Phase 1py-sp-core + bittensor-drand sources consolidated into the core; old crates, workflows, and the drand C ABI deleted; release train stamps one version.
  • Phase 2 — RFC-0078 digest module (merkleized-metadata 0.5.1, vectors pinned against polkadot-js merkleizeMetadata), LedgerSigner clear-signing via the Polkadot generic app (feature ledger), --ledger CLI flag, docs guide.
  • Phase 3 — Rust Runtime + codec become the production codec.py seam (CallBytes replaces GenericCall); cyscale, xxhash, TYPE_REGISTRY, and the cyscale-era quirks are deleted. Decode hot paths cross the FFI once per page and run off the GIL (rayon), with a limb-based base58 for ss58 rendering (~6x, byte-identical to sp-core).
  • Phase 4 — signature payload, extrinsic assembly, and multisig derivation in core, byte-equal to the golden signing vectors (landed inside phases 2–3).
  • Phase 5 — docs updated (repo layout, wallets, release process, sdk-tests dev loop), spec status + acceptance benchmark recorded.

Acceptance benchmark (finney, 2026-07-10 — spec §10)

Metric Baseline Target Accepted
Codec build from metadata bytes 337 ms ≤15 ms 4 ms
Metagraph SCALE decode 3–6 MB/s ≥50 MB/s 60–77 MB/s
compose_call 1.1 ms ≤50 µs <50 µs
Sign + assemble 0.1 ms no regression 0.03 ms
query_map decode 92k entries/s ≥500k entries/s 599k entries/s
Warm connect ~1.1 s ~0.75 s ~0.6 s

Review focus

  • The codec.py seam rewrite and its consumers (storage.py, extrinsics.py, runtime.py, runtime_api.py, interface.py)
  • Shape-corpus + golden coverage: both suites run natively in Rust (cargo test -p bittensor-core) and through the Python seam
  • The Ledger APDU/proof path (bittensor-core/src/signers/, bittensor/ledger.py) — on-device verification still to be done by someone with hardware

Test plan

  • cargo test -p bittensor-core — 44 tests green (corpus, goldens, digest vectors, keys, timelock)
  • cd sdk/python && uv run pytest — 874 unit tests green (one pre-existing EVM ABI-drift failure from 08c1a21, unrelated)
  • ruff / ty / codegen static gates green
  • Acceptance benchmark recorded (table above)
  • e2e suite against a localnet / mainnet clone
  • On-device Ledger verification (generic app, real hardware)

Made with Cursor

Update 2026-07-10: runtime changes merged in

This branch now also includes the feat/squashed-2026-07-06 runtime work (previously PR #2847 → devnet-ready), merged in 91b42d5152:

  • Coinbase dust-removal rework: DustRemoval hook mirrors balances dust burns into subtensor TotalIssuance; leasing/order-swap transfers consolidated onto transfer_tao
  • Reservoir accounting for protocol liquidity (BalancerAlphaReservoir / BalancerTaoReservoir) with dissolution folding reservoirs into reserves before payout
  • Migrations: migrate_fix_subnet_hotkey_lock_swaps (index-based rewrite), migrate_fix_total_issuance_evm_fees (dust-collection reset entry)
  • decrease_take/increase_take flip Pays::NoPays::Yes (anti-spam; metadata-only, no transaction_version bump needed)
  • New coverage: eco-tests/src/tests_mentat_indexer.rs (indexer storage contract), runtime/tests/balances_dust.rs
  • spec_version 428 (already bumped on this branch); benchmark weights regenerated for the drifted pallets

…ap coverage

Ports 8ef2f3d from feat/squashed-2026-07-06. The
test_swap_owner_new_hotkey_owned_by_another_coldkey case lands as its own
test alongside the existing HotKeyAlreadyRegisteredInSubNet coverage. The
coinbase refund-path test enablement does not apply here: that test (and
the balancer reservoir storage it exercises) only exists on the squashed
branch.

Co-authored-by: unarbos <arbos@bittensor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
unarbos and others added 3 commits July 10, 2026 13:03
Validate-Benchmarks has been failing on measured-vs-committed drift beyond
the 40% threshold (limit-orders execute_orders -68.6%, utility batch calls
-67..-74%, proxy calls +15..+21%). This applies the bench-patch artifact
produced by the Benchmarking runner for this branch (head b0869be), the
same patch the apply-benchmark-patch label automation would commit.

Co-authored-by: Cursor <cursoragent@cursor.com>
The clone node initializes genesis from a ~2 GB mainnet-clone chainspec,
which takes several minutes before the RPC server answers; the previous
180s health-check window expired mid-initialization and failed the job.

Co-authored-by: Cursor <cursoragent@cursor.com>
The strict originStakeAfter < originStakeBefore check races emission
credited to the origin hotkey between the before/after reads, which can
outweigh the moved amount on fast-block networks. Assert on the StakeMoved
event from the finalized contract-call extrinsic instead, and keep the
destination-stake increase check (monotonic, so not emission-sensitive).

Co-authored-by: Cursor <cursoragent@cursor.com>
unarbos and others added 2 commits July 10, 2026 13:31
…ittensor-core-exploration

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	pallets/subtensor/src/tests/swap_hotkey_with_subnet.rs
… so cargo fmt --check passes

Co-authored-by: Cursor <cursoragent@cursor.com>
…kip runtime CI

The monorepo now carries website/, sdk/, and vendored frontier; before this,
any commit triggered try-runtime (46m), validate-benchmarks (42m), the mainnet
clone-upgrade test, docker builds, and every zombienet/e2e suite.

Two patterns, chosen per workflow by whether it holds required merge checks:

- Not required (try-runtime, validate-benchmarks, docker build, btcli/sdk
  e2e): workflow-level `paths:` filters.
- Required (check-rust, eco-tests, clone-upgrade + docs-website,
  typescript-e2e): the workflow always triggers and a `changes` job
  (dorny/paths-filter, pinned) lets jobs skip themselves — a `skipped`
  conclusion satisfies branch protection, whereas a path-filtered workflow
  that never triggers leaves required checks stuck "Expected" and blocks the
  merge.

Co-authored-by: Cursor <cursoragent@cursor.com>
unarbos and others added 4 commits July 10, 2026 14:09
…clone-upgrade into runtime-checks.yml

One build job compiles the try-runtime wasm (production profile) and the
release node binary; consumers download artifacts instead of rebuilding:

- try-runtime devnet/testnet/mainnet: no Rust toolchain at all — prebuilt
  try-runtime-cli + the shared wasm blob. Previously three identical
  production builds on three runners (the mainnet job alone was ~46m).
- spec_version newer than mainnet: drops from ~8m of compiling
  (cargo install substrate-spec-version + cargo run subtensor-tools) to
  seconds on ubuntu-latest — one state_getRuntimeVersion RPC call vs the
  spec_version literal in runtime/src/lib.rs (grep enforces exactly one
  match so a feature-gated second literal fails loudly).
- Sudo-upgrade mainnet clone and test: consumes the node binary + release
  wasm artifact at the exact paths start-local-clone.sh and
  update-runtime-with-alice.ts expect.

Consolidation into one file is forced by artifact scoping (artifacts are
per-workflow-run). Required checks (clone-upgrade, docs-website) keep their
names and the always-trigger + job-level-skip pattern. The now-unused
.github/actions/try-runtime composite action is removed with its only caller.

Co-authored-by: Cursor <cursoragent@cursor.com>
…anged pallets

The skip check previously ran on the persistent Benchmarking machine after
checkout, so even skipped runs occupied the one reference-hardware runner.
Replaced with a decide job on ubuntu-latest (seconds, free):

- Path-gating does most of the work: website/sdk/docs/CI-only pushes never
  touch the Benchmarking runner, while pallets/runtime/vendor/deps changes
  still benchmark automatically — no forgotten-label drift hole.
- Pallet-only diffs benchmark just the changed pallets: the decide job emits
  PALLET_DIRS and benchmark_action.sh filters its discovered pallet set
  (exits 0 when the changed pallets have no registered benchmarks). Diffs
  reaching runtime/, vendor/, or dependencies still run the full suite.
- Labels: run-benchmarks forces a full run; skip-validate-benchmarks still
  skips (now read from the event payload — check-skip-label.sh deleted with
  its only caller).
- Nightly cron reruns the full suite on the default branch as the drift
  backstop, reusing the existing bench-patch artifact machinery.

validate-benchmarks is not a required merge check today; the decide-job shape
stays safe if that ever changes (workflow always triggers, skipped job
satisfies branch protection).

Co-authored-by: Cursor <cursoragent@cursor.com>
…hanges (pallet_subtensor, pallet_admin_utils, pallet_subtensor_proxy, pallet_subtensor_utility)

Co-authored-by: Cursor <cursoragent@cursor.com>
unarbos and others added 2 commits July 10, 2026 14:39
All four workflows using the marketplace action hit startup_failure on the
org's Actions allowlist (Validate-Benchmarks, which gates with plain gh
calls, started fine). Same filtering semantics, no third-party action: list
the PR's files via the REST API and grep the path patterns.

Co-authored-by: Cursor <cursoragent@cursor.com>
- validate-benchmarks now runs on PRs only with the run-benchmarks label
  (reference-machine variance was flagging noise as drift); nightly
  full-suite run remains the drift backstop
- try-runtime mainnet moves off the single fireactions-tryruntime-finney
  box to the shared pool -- it no longer compiles, so the dedicated
  runner was pure queue time
- SDK offline checks (ruff/ty/pytest/codegen) split out of
  clone-upgrade into a parallel light-pool job; redundant docs drift
  gate dropped (covered by docs-website)
- clippy and cargo-fix move to fireactions-heavy: compile-bound jobs
  that were pinned at ~20 min on the light boxes

Co-authored-by: Cursor <cursoragent@cursor.com>
- nightly refresh-mainnet-snapshot workflow scrapes mainnet once,
  genesis-inits the clone db, and publishes both as an artifact; PR
  shards restore it (~2 min) instead of each re-scraping 15-20 min of
  identical state from the finney RPC. Only main-branch snapshots are
  consumed, so PRs cannot poison each other; the fresh-mainnet-clone
  label bypasses the snapshot for PRs that change the patching logic
- clone-upgrade fans out into three shards, each booting its own clone
  from the snapshot; suite order is preserved within shards. A fan-in
  job keeps the required-check name "Sudo-upgrade mainnet clone and
  test" and fails on cascading skips
- per-test regression timeout drops 30 -> 15 min: healthy tests finish
  in 2-10, so a hang now costs 15 min instead of 30
- start-local-clone.sh keeps a restored pre-initialized db when
  KEEP_CLONE_DATA=1, skipping the ~3 min genesis init

Co-authored-by: Cursor <cursoragent@cursor.com>
…ks job

Co-authored-by: Cursor <cursoragent@cursor.com>
unarbos and others added 2 commits July 10, 2026 16:18
- rust-setup installs mold and routes linking through clang; guarded so
  images without the package fall back to the default linker
- dev/test profiles build with line-tables-only debuginfo in CI: panic
  backtraces stay readable, codegen and disk I/O shrink
- cargo test job switches to cargo-nextest (per-test processes, better
  scheduling); doctests keep running via cargo test --doc against the
  build nextest already produced

Co-authored-by: Cursor <cursoragent@cursor.com>
Compile-side speedups for every Rust job, all in the rust-setup action:

- sccache on the GitHub Actions cache backend replaces per-job target-dir
  snapshots. Nine jobs each caching a multi-GB target dir thrashed the
  10 GB quota (LRU eviction meant mostly-cold builds); one deduplicated
  per-crate object pool fits and is shared across jobs and workflows.
  Swatinem/rust-cache drops to registry-only. check-rust now also runs
  on pushes to main so merges seed the pool every PR can read.
- mold as linker (guarded fallback to default) and line-tables-only
  debuginfo: cargo test links dozens of binaries and nothing in CI
  reads full debuginfo.
- cargo-nextest for the test job (doctests still via cargo test --doc)
- CARGO_INCREMENTAL=0: sccache can't cache incremental artifacts and CI
  never reuses a working tree.

Co-authored-by: Cursor <cursoragent@cursor.com>
ty cannot introspect the compiled extension, so the four named imports
(encrypt_mlkem768, get_encrypted_commit_v2, decrypt, encrypt_at_round)
failed its unresolved-import check. Every other consumer already uses
module import + attribute access; align these with that convention.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.