Skip to content

fix: purge messages signed with stale delegate key#170

Merged
sanity merged 2 commits intomainfrom
fix-stale-messages
Mar 13, 2026
Merged

fix: purge messages signed with stale delegate key#170
sanity merged 2 commits intomainfrom
fix-stale-messages

Conversation

@sanity
Copy link
Contributor

@sanity sanity commented Mar 13, 2026

Problem

Follow-up to #169. After a stale delegate signing key is overwritten, messages that were already signed with the old key remain in local state. Every UPDATE to the contract includes these bad messages, and the contract rejects the entire UPDATE with State verification failed: Invalid message signature. This blocks ALL new messages from being sent — even ones signed with the correct key.

Any user who was re-invited after PR #164 and sent messages before refreshing has these poisoned messages in their local state.

Approach

  1. Changed migrate_signing_key() to return a MigrationResult enum instead of bool, so callers can distinguish between AlreadyCurrent, StaleKeyOverwritten, Stored, and Failed

  2. Added remove_unverifiable_messages() which verifies all message signatures in local room state against the members list and removes any that fail verification

  3. Both callers of migrate_signing_key() now call remove_unverifiable_messages() when StaleKeyOverwritten is returned, purging the poisoned messages before any UPDATEs are sent

UI-only change — no delegate/contract WASM modifications, no migration needed.

Testing

  • Verified cargo check -p river-ui --target wasm32-unknown-unknown --features no-sync passes
  • cargo fmt clean
  • Diagnosed from production: Ian's node repeatedly failing with State verification failed: Invalid message signature: id:MessageId(FastHash(1015880761723393051)) even after fix: overwrite stale delegate signing key after re-invitation #169 fix deployed

[AI-assisted - Claude]

sanity and others added 2 commits March 13, 2026 15:39
When migrate_signing_key() overwrites a stale delegate key, any messages
in local state that were signed with the old key have invalid signatures.
The contract rejects the entire UPDATE because of these bad messages,
blocking all new messages from being sent.

Changes:
- migrate_signing_key() now returns MigrationResult enum instead of bool,
  distinguishing AlreadyCurrent/StaleKeyOverwritten/Stored/Failed
- New remove_unverifiable_messages() function verifies all message
  signatures in local state and removes invalid ones
- Both callers of migrate_signing_key() call remove_unverifiable_messages()
  when a stale key was overwritten

This is UI-only — no delegate/contract WASM changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Address review feedback: add mark_needs_sync after removing unverifiable
messages so the cleaned state is saved to delegate storage and synced to
the contract. In get_response.rs, also ensures sync happens after
sanitization (not before) since both are deferred.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sanity sanity merged commit 04862f7 into main Mar 13, 2026
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