Skip to content

Complete implementation of precompiles - #3018

Draft
UnArbosFour wants to merge 3 commits into
mainfrom
feat/full-precompiles
Draft

Complete implementation of precompiles#3018
UnArbosFour wants to merge 3 commits into
mainfrom
feat/full-precompiles

Conversation

@UnArbosFour

Copy link
Copy Markdown
Contributor

Summary

Expands typed EVM coverage for Subtensor by adding five new precompiles and 69 functions to existing precompiles. State-changing functions dispatch the highest-level pallet call as the mapped EVM signer, preserving the runtime’s existing authorization, rate limits, freeze windows, validation, weight charging, and error behavior.

No released precompile function was removed or changed. Existing ABIs only receive appended functions.

New precompiles

Precompile Address Functions
SchedulerPrecompile 0x000000000000000000000000000000000000080f getIncompleteSince(), getScheduledCallCount(uint64), getScheduledCall(uint64,uint32), getRetry(uint64,uint32), getTaskAddress(bytes32)
DrandPrecompile 0x0000000000000000000000000000000000000810 getBeaconConfig(), getPulse(uint64), getStoredRoundRange(), getNextUnsignedAt(), hasMigrationRun(bytes)
TimestampPrecompile 0x0000000000000000000000000000000000000811 getTimestamp(), wasUpdatedThisBlock()
RuntimeConfigurationPrecompile 0x0000000000000000000000000000000000000812 getEvmChainId(), getTransactionRateLimit()
PrecompileRegistry 0x0000000000000000000000000000000000000813 getPrecompileStatus(address,bytes4)

Scheduler returns stable metadata such as call hashes, task IDs, priority, periodicity, and retry information rather than SCALE-encoded runtime calls or origins.

The registry reports reversible precompile disablement. Its lifecycle and replacement fields currently return active/default values until function lifecycle metadata is defined.

Functions added to existing precompiles

AlphaPrecompile

  • setRecycleOrBurn(uint16,uint8)
  • setBurnHalfLife(uint16,uint16)
  • setBurnIncreaseMultiplier(uint16,uint128)

BalancePrecompile

  • burnBalance(uint256,bool)
  • upgradeAccounts(bytes32[])

upgradeAccounts is bounded to 64 accounts.

BalanceTransferPrecompile

  • transferKeepAlive(bytes32,uint256)
  • transferAll(bytes32,bool)

These use explicit amounts and the mapped caller, independently of the legacy payable transfer(bytes32) function.

CrowdloanPrecompile

  • setMaxContribution(uint32,bool,uint64)

The boolean distinguishes setting a limit from clearing it.

LeasingPrecompile

  • startCall(uint16)

NeuronPrecompile

Weight operations:

  • setMechanismWeights(uint16,uint8,uint16[],uint16[],uint64)
  • batchSetWeights(uint16[],uint16[][],uint16[][],uint64[])
  • commitMechanismWeights(uint16,uint8,bytes32)
  • batchCommitWeights(uint16[],bytes32[])
  • revealMechanismWeights(uint16,uint8,uint16[],uint16[],uint16[],uint64)
  • commitCrv3MechanismWeights(uint16,uint8,bytes,uint64)
  • batchRevealWeights(uint16,uint16[][],uint16[][],uint16[][],uint64[])
  • commitTimelockedWeights(uint16,bytes,uint64,uint16)
  • commitTimelockedMechanismWeights(uint16,uint8,bytes,uint64,uint16)

Registration, identity, and key operations:

  • register(uint16,uint64,uint64,bytes,bytes32,bytes32)
  • rootRegister(bytes32)
  • swapHotkey(bytes32,bytes32,bool,uint16)
  • swapHotkeyV2(bytes32,bytes32,bool,uint16,bool)
  • setChildren(bytes32,uint16,uint64[],bytes32[])
  • setIdentity(string,string,string,string,string,string,string)
  • tryAssociateHotkey(bytes32)
  • associateEvmKey(uint16,address,uint64,bytes)
  • announceColdkeySwap(bytes32)
  • executeAnnouncedColdkeySwap(bytes32)
  • disputeColdkeySwap()
  • clearColdkeySwapAnnouncement()

Batch calls are bounded to 16 outer items and 4,096 entries per inner weight array. Timelocked commits, registration work, child lists, identities, and signatures also have explicit bounds.

ProxyPrecompile

  • announce(bytes32,bytes32)
  • removeAnnouncement(bytes32,bytes32)
  • rejectAnnouncement(bytes32,bytes32)
  • setRealPaysFee(bytes32,bool)

StakingPrecompileV2

Delegation and unstaking:

  • decreaseTake(bytes32,uint16)
  • increaseTake(bytes32,uint16)
  • setChildkeyTake(bytes32,uint16,uint16)
  • unstakeAll(bytes32)
  • unstakeAllAlpha(bytes32)

Stake movement and recycling:

  • swapStake(bytes32,uint16,uint16,uint64)
  • swapStakeLimit(bytes32,uint16,uint16,uint64,uint64,bool)
  • recycleAlpha(bytes32,uint64,uint16)
  • transferStakeAndHotkey(bytes32,bytes32,bytes32,uint16,uint16,uint64)
  • addStakeBurn(bytes32,uint16,uint64,bool,uint64)

Root emission claims and account policy:

  • setColdkeyAutoStakeHotkey(uint16,bytes32)
  • claimRoot(uint16[])
  • setRootClaimType(uint8,uint16[])
  • setRootClaimThreshold(uint16,uint64)
  • setAutoParentDelegationEnabled(bytes32,bool)

Collateral configuration:

  • addCollateral(uint16,bytes32,uint64,uint64)
  • setMinCollateral(uint16,bytes32,uint64)
  • setMinChildkeyTakePerSubnet(uint16,uint16)
  • setCollateralLockShare(uint16,uint16)
  • setCollateralDrainRatio(uint16,uint128)

Root-claim subnet lists are bounded to five entries.

SubnetPrecompile

Subnet operations:

  • setSubnetIdentity(uint16,string,string,string,string,string,string,string,string)
  • updateSubnetSymbol(uint16,string)
  • triggerEpoch(uint16)

Subnet-owner AdminUtils operations:

  • setBondsPenalty(uint16,uint16)
  • setMaxAllowedUids(uint16,uint16)
  • setMaxBurnV2(uint16,uint64)
  • setMechanismCount(uint16,uint8)
  • setMechanismEmissionSplit(uint16,bool,uint16[])
  • setMinBurnV2(uint16,uint64)
  • setOwnerCutEnabled(uint16,bool)
  • setOwnerImmuneNeuronLimit(uint16,uint16)
  • setTempo(uint16,uint16)
  • trimToMaxAllowedUids(uint16,uint16)

Only the signed subnet-owner path is exposed. These functions do not manufacture Root authorization.

VotingPowerPrecompile

  • enableVotingPowerTracking(uint16)
  • disableVotingPowerTracking(uint16)

Runtime and routing changes

  • Registered the five new addresses in Precompiles::used_addresses() and runtime routing.
  • Added corresponding PrecompileEnum variants for reversible enablement and disablement.
  • Appended the new enum variants so all existing SCALE indices remain unchanged.
  • Added tests locking addresses, selectors, uniqueness, and enum indices.
  • Exposed a read-only Drand helper for NextUnsignedAt.
  • Added the required Scheduler, Drand, Timestamp, and EVM chain-ID dependencies to the precompile crate.
  • Added explicit bounds and conversion errors for dynamic Solidity inputs.
  • Continued using dispatch weight and post-dispatch gas accounting for all state-changing calls.

ABI, Solidity, and SDK changes

  • Added Solidity interfaces and ABIs for all five new precompiles.
  • Appended the 69 new functions to their existing Solidity interfaces and ABIs.
  • Preserved every released ABI entry without changing its inputs, outputs, mutability, or ordering.
  • Added all five precompiles to the Python SDK catalog.
  • Synchronized all 15 affected Python SDK ABI artifacts with the canonical ABIs.
  • Fixed SDK argument coercion for bounded and nested Solidity arrays.
  • Added SDK tests for the new array-based calls and ABI synchronization.

Documentation

  • Added the EVM precompile design and lifecycle guide.
  • Added a complete precompile address and status table.
  • Added or updated dedicated reference pages for each affected precompile.
  • Added an extrinsic-coverage audit covering the authorized pallets.
  • Documented Storage Query replacement domains and deprecation planning.
  • Documented bounded metadata design, signed-origin requirements, lifecycle discovery, and address allocation.

Deferred coverage

The following bulk runtime APIs remain documented proposals and receive no selectors in this change:

  • DelegateInfoRuntimeApi.get_delegates
  • NeuronInfoRuntimeApi.get_neurons
  • SubnetInfoRuntimeApi.get_all_metagraphs

They require a separately approved bounded, cursor-based or indexed interface.

Proxy.proxy_announced also remains proposed because it needs a stable, versioned EVM representation of the proxied call. This change does not introduce another SCALE-encoded RuntimeCall interface.

Root-only and None-origin extrinsics remain unavailable through typed EVM precompiles.

Validation

  • cargo test -p subtensor-precompiles — 108 passed
  • cargo test -p pallet-admin-utils — 77 passed
  • cargo check -p node-subtensor-runtime — passed
  • Strict Clippy for all precompile targets and features — passed
  • Solidity compilation for all 15 affected interfaces — passed
  • Python EVM SDK tests — 34 passed
  • Python Ruff checks — passed
  • Production documentation build — passed
  • Formatting, ABI compatibility, SDK ABI synchronization, and diff checks — passed

The optional no-default-features check is currently blocked by compilation errors in the upstream cumulus-primitives-proof-size-hostfunction dependency.

@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
subtensor Error Error Jul 31, 2026 8:06pm

Request Review

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

🛡️ AI Review — Skeptic (security review)

VERDICT: VULNERABLE

VERY HIGH scrutiny: account is under 30 days old with one public repository; write permission and matching author/committer mitigate identity risk, with no known Gittensor association. Branch: feat/full-precompiles → main.

Static analysis found no AI-review trust-boundary modifications or evidence of malicious intent. The previously reported runtime-version issue remains unresolved.

Findings

Sev File Finding
CRITICAL runtime/src/lib.rs:238 Runtime behavior changes without a spec_version bump (off-diff)

Other findings

  • [CRITICAL] Runtime behavior changes without a spec_version bump (runtime/src/lib.rs:238) — This PR adds runtime-routed precompiles, extends PrecompileEnum, introduces runtime storage, and wires an upgrade migration, but leaves runtime/src/lib.rs at spec_version: 440. Nodes may therefore treat old native runtime code as compatible with the upgraded on-chain Wasm, risking consensus divergence. Increment spec_version for this runtime upgrade.

Prior-comment reconciliation

  • 0ca495fb: not addressedruntime/src/lib.rs remains unchanged at spec_version: 440 despite the runtime-affecting additions.

Conclusion

The PR changes consensus-executed runtime behavior while retaining spec_version: 440, risking native/Wasm execution divergence. The runtime version must be incremented before merge.


📜 Previous run (superseded)
Sev File Finding Status
CRITICAL runtime/src/lib.rs Runtime behavior changes without a spec_version bump ➡️ Carried forward to current findings
runtime/src/lib.rs remains unchanged at spec_version: 440 despite the runtime-affecting additions.

# 🔍 AI Review — Auditor (domain review) has not yet run on this PR.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: VULNERABLE

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: VULNERABLE

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: VULNERABLE

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.

1 participant