Skip to content

do_terminate_lease leaves owner-cut stake and locks under the unspendable lease coldkey #2663

@Maksandre

Description

@Maksandre

Describe the bug

do_terminate_lease (pallets/subtensor/src/subnets/leasing.rs:197-252) transfers subnet ownership to the beneficiary but does not repatriate the alpha stake (and lock state) that has accumulated on the lease's derived coldkey throughout the lease. The lease coldkey is blake2_256("leasing/coldkey", lease_id) - a deterministic hash with no preimage. The beneficiary proxy is removed at line 235, and the proxy allowlist never permitted stake-extraction calls. After termination, no extrinsic can ever be dispatched with Signed(lease.coldkey), so every fixed-end lease termination permanently strands the residual owner-cut alpha plus all Lock / HotkeyLock entries.

To Reproduce

  1. Register a leased network with emissions_share < Percent::from_percent(100) and a finite end_block (via pallet_crowdloan::finalize -> pallet_subtensor::register_leased_network).
  2. Let the chain run through one or more LeaseDividendsDistributionInterval cycles so owner emissions accrue. Each epoch:
  3. After end_block, the beneficiary signs terminate_lease(lease_id, hotkey).
  4. Read AlphaV2((lease.hotkey, lease.coldkey, netuid)), Lock((lease.coldkey, netuid, lease.hotkey)), HotkeyLock(netuid, lease.hotkey), Owner(lease.hotkey), OwnedHotkeys(lease.coldkey), StakingHotkeys(lease.coldkey).

Observed: all six storage rows survive termination unchanged. Beneficiary attempts (remove_stake, unlock_stake, transfer_stake, move_stake) cannot reach lease.coldkey's alpha - origin mismatch with the storage key, and the beneficiary cannot sign as lease.coldkey. Funds are unreachable.

Expected behavior

Before dec_providers(&lease.coldkey), repatriate the residual alpha and lock state to the beneficiary. The invariant total_coldkey_alpha_on_subnet(&lease.coldkey, netuid) == 0 must hold after termination. Equivalently: no AlphaV2, Lock, HotkeyLock, Owner, OwnedHotkeys, or StakingHotkeys rows may reference lease.coldkey once the proxy is removed.

Screenshots

No response

Environment

opentensor/subtensor main @ 6844ee37f0b8cb02baf9ff8d3ca4319cfb33f361, testnet @ e6a5f56cefeb96b9c63ea3ce6553a8e1066aaeb9

Additional context

Affected code (pallets/subtensor/src/subnets/leasing.rs:197-252) - the function transfers SubnetOwner / SubnetOwnerHotkey to the beneficiary, calls dec_providers on lease.coldkey / lease.hotkey, clears SubnetLeaseShares / AccumulatedLeaseDividends / SubnetLeases, and removes the beneficiary proxy. It never iterates or modifies:

  • AlphaV2((lease.hotkey, lease.coldkey, netuid)) - accumulated owner-cut residual.
  • Lock((lease.coldkey, netuid, lease.hotkey)) - per-coldkey lock state.
  • HotkeyLock(netuid, lease.hotkey) - aggregate lock state.
  • Owner(lease.hotkey) = lease.coldkey - hotkey-coldkey ownership pointer.
  • OwnedHotkeys(lease.coldkey), StakingHotkeys(lease.coldkey) - index entries.

Why the lease coldkey is unspendable:

  • lease_coldkey(lease_id) = blake2_256(("leasing/coldkey", lease_id)) (leasing.rs:352-356). No private key, no preimage attack possible.
  • ProxyType::SubnetLeaseBeneficiary allowlist (runtime/src/lib.rs:758-815) contains only start_call and ~20 sudo_set_* parameter-tuning calls. remove_stake, unlock_stake, transfer_stake, move_stake, unstake_all_alpha, claim_root are not in the allowlist - even before do_terminate_lease removes the proxy at line 235, the beneficiary had no path to extract stake from lease.coldkey.

Impact

  • Every fixed-end lease termination permanently forfeits the cumulative (1 - emissions_share) share of owner emissions accrued during the lease, plus registration-time floor-rounded refund dust. For multi-month leases at typical emission rates, this is the dominant share of subnet-owner emissions whenever emissions_share < 100%.
  • The forfeited alpha is backed by TAO held in SubnetTAO, so the corresponding pool TAO is unredeemable.
  • lease.coldkey is dec_providers'd while still owning non-zero alpha - AlphaV2 row references a coldkey that may fail system::Account existence assumptions elsewhere.
  • Secondary: HotkeyLock(netuid, lease.hotkey) keeps influencing subnet_king (pallets/subtensor/src/staking/lock.rs:396-412); the terminated lease's hotkey can keep winning king elections.
  • This is the intended happy path - no malicious actor required; every fixed-end lease is affected.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions