Skip to content

feat: wallet-scoped backup migration APIs#121

Open
coreyphillips wants to merge 2 commits into
masterfrom
fix/wallet-scoped-backup-migrations
Open

feat: wallet-scoped backup migration APIs#121
coreyphillips wants to merge 2 commits into
masterfrom
fix/wallet-scoped-backup-migrations

Conversation

@coreyphillips

Copy link
Copy Markdown
Collaborator

Summary

Adds Core-owned backup migration for the wallet-scoped activity data, covering the backup-JSON boundary of #113. The activity DB migration half already landed; this PR handles the app backup envelopes.

Background

Android and iOS embed Core-owned records (activities, tags, pre-activity metadata, transaction details) inside their own VSS backup envelopes and decode them directly into the generated binding types. Those records gained a required wallet id, so a backup written before the field existed no longer decodes: the platform decoder (kotlinx.serialization on Android, Codable on iOS) rejects the missing field before Core is ever consulted. The two platforms also serialize the Activity union in incompatible shapes, so no single serde type can read both:

Android (kotlinx) iOS (Codable)
Activity union {"type":"...Onchain","v1":{...}} {"onchain":{"_0":{...}}}
PaymentType "SENT" {"sent":{}}

What this adds

Two Core-owned boundaries in src/modules/activity/backup_migration.rs, so the apps never hand-edit Core model JSON:

  • Format-tolerant normalizers (migrate_backup_*_json) take the raw slice exactly as the app serialized it, inject the default wallet id wherever a record is missing it or has it empty, and return JSON in the same shape. They handle the Android, iOS and canonical Activity-union encodings plus flat records (tags, metadata, transaction details).
  • Canonical serialization (*_to_json / *_from_json) is Core's own stable cross-platform JSON for these slices, with the from_json side defaulting a missing/empty wallet id so apps can move their backups onto one format over time.

Migration rule

A missing or empty wallet id on legacy input becomes DEFAULT_WALLET_ID (bitkit); any existing non-default id such as trezor:{hash} is preserved. Normal writes still reject an empty wallet id via normalize_wallet_id; the empty to default relaxation applies to migration input only. Closed channels are not wallet-scoped, so their round-trip applies no normalization.

Testing

  • 11 new tests in backup_migration.rs covering Android/iOS/canonical activity shapes, empty to default normalization, non-default preservation, flat tag/metadata slices, non-array rejection, and canonical round-trips.
  • cargo test modules::activity passes; clippy clean.

Notes

  • Bumps to 0.4.0 and regenerates Android, iOS and Python bindings.
  • App-side wiring for bitkit-android and bitkit-ios to call these helpers before decoding is prepared and will follow in their own PRs once this releases.

Android and iOS embed Core-owned records (activities, tags, pre-activity
metadata, transaction details) inside their own VSS backup envelopes and
decode them directly into the generated binding types. Those records gained
a required wallet id, so a backup written before the field existed no longer
decodes: the platform decoder (kotlinx.serialization on Android, Codable on
iOS) rejects the missing field before Core is consulted. The two platforms
also serialize the Activity union in incompatible shapes, so no single serde
type can read both.

Add two Core-owned boundaries so the apps never hand-edit Core model JSON:

- Format-tolerant normalizers (migrate_backup_*_json) take the raw slice as
  the app serialized it, inject the default wallet id wherever a record is
  missing it or has it empty, and return JSON in the same shape. They handle
  the Android ({"type","v1"}), iOS ({"onchain":{"_0"}}) and canonical
  ({"onchain"}) Activity-union encodings plus flat records.
- Canonical serialization (*_to_json / *_from_json) is Core's own stable JSON
  for these slices, with the from_json side defaulting a missing/empty wallet
  id so apps can move their backups onto one cross-platform format.

A missing or empty wallet id on legacy input becomes the default wallet, while
any existing non-default id such as trezor:{hash} is preserved. Normal writes
still reject an empty wallet id; the relaxation applies to migration input only.

Covers the backup-JSON half of #113; the activity DB migration half already
landed. Closed channels are not wallet-scoped, so their round-trip applies no
normalization.
Regenerate the Android, iOS and Python bindings for the new wallet-scoped
backup migration APIs and sync the version across Cargo.toml, Package.swift
and gradle.properties.
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