diff --git a/src/daemon/run.ts b/src/daemon/run.ts index 9497677..f91dbd7 100644 --- a/src/daemon/run.ts +++ b/src/daemon/run.ts @@ -236,6 +236,19 @@ class Daemon { } async unlockKey(keyName: string, passphrase: string): Promise { + // Idempotency guard: if a Backend instance already exists for this + // keyName, the key is already unlocked and the relay subscription + // for its kind-24133 channel is already active. Calling startKey + // again would spawn a SECOND Backend with a duplicate subscription + // — wire events would be handled twice, with race/amplification + // hazards on the response side. Return success without re-running + // startKey so callers (admin `unlock_key` RPC, autounlock loop, + // belt-and-suspenders fallback paths) can fire safely against + // already-unlocked keys. + if (this.activeKeys[keyName]) { + return true; + } + const keyData = this.config.allKeys[keyName]; const { iv, data } = keyData;