Skip to content

Explore graceful contract upgrade mechanisms #59

@sanity

Description

@sanity

Context

Currently, updating the room contract WASM results in a new ContractKey because the key is derived from:

ContractInstanceId = Blake3(CodeHash || Parameters)

This means any change to contract logic creates an entirely new contract address, effectively requiring a room "reset" — existing members and messages are lost.

This issue explores options for graceful contract upgrades that preserve room state and membership.

Current State

River already has a partial upgrade mechanism in common/src/room_state/upgrade.rs:

pub struct UpgradeV1 {
    pub owner_member_id: MemberId,
    pub version: u8,
    pub new_chatroom_address: Hash,
}

This allows the room owner to sign an upgrade notice pointing to a new contract address. However, the migration flow isn't fully implemented in the UI or CLI.

Options to Explore

1. Complete the Migration Pointer Pattern (short-term)

Finish implementing what's already started:

  • UI/CLI detects upgrade field in room state
  • Prompts user about migration
  • Fetches current state from old contract
  • Creates new contract with updated WASM
  • PUTs migrated state to new contract
  • Optionally auto-follows for subscribed members

Questions:

  • How do we handle members who haven't upgraded their client?
  • Should the old contract remain readable indefinitely?
  • How do we migrate private room secrets?

2. Room Directory / Registry Contract

A well-known contract that maps room identifiers to current contract addresses:

(owner_vk, room_name) → current_contract_address
  • Clients discover rooms via registry lookup
  • Owner updates registry entry when contract code changes
  • Provides stable "room identity" independent of code version

Questions:

  • Who operates/seeds the registry contract?
  • How do we handle registry spam/squatting?
  • Does this add unacceptable latency to room discovery?

3. Protocol-Level Migration (requires Freenet changes)

Potential Freenet protocol additions:

  • MigrateContract(old_key, new_key, migration_proof) operation
  • New contract validates it can accept old contract's state
  • Network automatically redirects subscribers
  • Old state garbage collected after migration window

Questions:

  • What should the migration proof contain?
  • How does the new contract validate compatibility?
  • What happens to in-flight updates during migration?

4. Versioned State with Compatibility Layers

Contract code handles multiple state versions internally:

  • State includes explicit version field
  • Contract code can read/upgrade older state formats
  • Backward-compatible changes don't need migration

Questions:

  • How much WASM bloat is acceptable?
  • How do we handle breaking changes that can't be backward-compatible?

Related Files

  • common/src/room_state/upgrade.rs - existing upgrade struct
  • common/src/room_state.rs - ChatRoomStateV1 definition
  • ui/src/util.rs:85-92 - ContractKey derivation
  • cli/src/api.rs:109-123 - CLI ContractKey derivation

Next Steps

This is exploratory — looking for input on:

  1. Which approach(es) seem most promising?
  2. Are there other options not listed here?
  3. What's the minimal viable solution for the next release?

[AI-assisted - Claude]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions