Skip to content

[Bug] purge_deregistered_hotkeys leaves orphaned pending_confirms rows #414

@kiannidev

Description

@kiannidev

Summary

When a miner deregisters, purge_deregistered_hotkeys calls state_store.delete_hotkey, which clears rate_events, swap_outcomes, and reservation_pins but not pending_confirms. Queued user confirms for that hotkey keep draining and voting until reservation expiry or contract rejection.

Impact

  • Wasted work signing vote_initiate for a miner no longer in the metagraph.
  • Stale queue rows survive indefinitely (until purge_expired_pending_confirms) even though scoring/state for that hotkey was dropped.
  • Operators see PendingConfirm [… UID ? (hotkey…)] after deregistration with no clear cleanup.

Current behavior

delete_hotkey omits the pending table:

    def delete_hotkey(self, hotkey: str) -> None:
        with self.lock:
            conn = self.require_connection()
            conn.execute('DELETE FROM rate_events WHERE hotkey = ?', (hotkey,))
            conn.execute('DELETE FROM swap_outcomes WHERE miner_hotkey = ?', (hotkey,))
            conn.execute('DELETE FROM reservation_pins WHERE miner_hotkey = ?', (hotkey,))
            conn.commit()

purge_deregistered_hotkeys only triggers that helper:

def purge_deregistered_hotkeys(self: Validator) -> None:
    current_hotkeys = set(self.metagraph.hotkeys)
    stale = {hk for (hk, _, _) in self.last_known_rates.keys()} - current_hotkeys
    if not stale:
        return
    for hk in stale:
        self.state_store.delete_hotkey(hk)

initialize_pending_user_reservations still iterates all queued rows with no metagraph membership check.

Expected behavior

delete_hotkey (or purge_deregistered_hotkeys) also deletes pending_confirms for the hotkey. Log when a deregistered miner had queued confirms removed.

How to reproduce

  1. User queues SwapConfirm for miner M (unconfirmed source tx).
  2. Miner M deregisters from the subnet before the queue drains.
  3. purge_deregistered_hotkeys runs — rates/pins cleared, pending_confirms row remains.
  4. Forward steps keep processing PendingConfirm for UID ? until expiry.

Proposed fix

Add DELETE FROM pending_confirms WHERE miner_hotkey = ? to delete_hotkey. Extend test_state_store.py::test_delete_hotkey_* to assert pending row removal. Optionally skip vote_initiate in initialize_pending when hotkey ∉ metagraph as defense in depth.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions