fix(swift-sdk): stored default on keyType so pre-column stores can migrate#4129
Conversation
…grate PR #4127 declared PersistentCoreAddress.keyType without a stored default — the init-parameter default is invisible to SwiftData lightweight migration, so opening any store with existing rows fails ("Validation error missing attribute values on mandatory destination attribute"), DashModelContainer.create() throws, and the app hits fatalError on launch: every device with existing data crash-loops until reinstall. Reproduced on the simulator against a pre-#4127 store; with the stored default the same store migrates and launches. Defaulted rows read as ECDSA (0) until the next Rust address-pool persist pulse re-tags typed entries, which happens on every load — same convention as isImported / statusRaw / blockPosition. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough
ChangesSwiftData migration
Estimated code review effort: 1 (Trivial) | ~3 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
⛔ Blockers found — Sonnet deferred (commit 6177500) |
thepastaclaw
left a comment
There was a problem hiding this comment.
Preliminary review — Codex only
Exact HEAD 6177500 and the supplied full range were verified. The stored default makes legacy stores openable, but it does not perform the claimed provider-key migration, leaving legacy Ed25519 platform-node ownership data unavailable after restoration.
Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.
Review provenance
- Codex reviewers:
gpt-5.6-sol— general (completed) - Verifier:
gpt-5.6-sol— verifier - Sonnet: not run (deferred by blocker gate)
🔴 1 blocking
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `packages/swift-sdk/Sources/SwiftDashSDK/Persistence/Models/PersistentCoreAddress.swift`:
- [BLOCKING] packages/swift-sdk/Sources/SwiftDashSDK/Persistence/Models/PersistentCoreAddress.swift:34: Legacy provider keys are not re-tagged on load
Pre-#4127 address rows serialized only ECDSA keys, so BLS and Ed25519 rows have an empty `publicKey`; the Ed25519 batch was stored separately in the since-removed `PersistentAccount.derivedPlatformNodeKeys`. After this default allows the store to open, `buildCoreAddressPoolBuffer` forwards those empty keys with length zero, Rust decodes them as `public_key: None`, and `restore_address_pool` overwrites the managed-pool entry. `FFIPersister::load` only reads the snapshot and never invokes the persistence callback, so the claimed load-time re-tagging does not occur. BLS ownership matching can still derive keys from its xpub, but its typed persisted entries remain empty; hardened Ed25519 children cannot be derived from the public xpub, leaving platform-node ownership matching and persisted key display unavailable. Add an explicit legacy conversion that preserves pre-derived typed entries and migrates the old Ed25519 batch into typed core-address rows, with an on-disk pre-#4127 migration test.
|
Scope note: this branch now carries a second commit pinning rust-dashcore to the head of rust-dashcore#893 — the fix for the OTHER startup crash on v4.1-dev (rust-dashcore#892, a dash-spv debug SIGABRT crash-loop when a wallet's scan floor sits below the stored filter range). Verified live on the previously crash-looping simulator: the new discard-and-redownload path fired and the app runs cleanly. The pin will be re-pointed to the #893 merge commit once it lands; together with the keyType migration default, this makes v4.1-dev launchable again on devices with existing data. |
|
rust-dashcore#893 merged — pin re-pointed to the merge commit (19690d31) in 3ad8740. This PR is now merge-ready: it carries the two fixes that make v4.1-dev launchable on devices with existing data (keyType migration default + the sparse-filter crash-loop fix), both verified live on-device. |
…rows + land the #893 crash-fix pin Follow-up to #4129 (merged before its review completed) addressing thepastaclaw's blocking finding, plus the rust-dashcore bump that was pushed to the #4129 branch after its merge and never landed: - restore_address_pool: a legacy row persisted before the typed-key column (empty key -> public_key: None) no longer strips the typed BLS key the gap-limit prederivation put at the same index — pre-typed-key stores otherwise lose in-memory operator pubkeys at load and masternode operator-ownership matching silently breaks. No-op for post-migration rows (they always carry their key). Test pins both directions. Legacy Ed25519 platform-node keys are hardened-only and their old account-level batch was dropped by the schema migration, so they cannot be recovered at load; per the pre-release convention those stores re-derive on delete+re-import. - PersistentCoreAddress.keyType doc: corrected the false "re-tags on every load" claim — load only reads the snapshot; re-tagging happens on the next persist pulse. - Bump rust-dashcore to 19690d31 (merged #893, fixes #892): the sparse-filter startup crash-loop fix, verified live on the previously crash-looping simulator state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Follow-up for the post-merge blocking finding: #4132. Confirmed the finding — the plain upsert did strip prederived typed BLS keys for legacy key-less rows, and the "re-tags on every load" claim in this PR's comment was wrong (load only reads the snapshot). #4132 restores typed-key preservation for legacy rows (no-op for post-#4127 rows), corrects the doc, and also lands the rust-dashcore#893 crash-fix pin that was pushed to this branch after the merge. Legacy Ed25519 platform-node rows cannot be recovered at load (hardened-only; the removed batch column's data was already dropped by the schema migration) — per the pre-release convention they re-derive on delete+re-import. 🤖 Addressed by Claude Code |
Issue being fixed or feature implemented
#4127 added
PersistentCoreAddress.keyType: UInt8with only an init-parameter default, which SwiftData lightweight migration never consults. Opening any pre-#4127 store fails migration ("Validation error missing attribute values on mandatory destination attribute: PersistentCoreAddress.keyType"),DashModelContainer.create()throws, andSwiftExampleAppApphitsfatalError— the app crash-loops on every device that has existing data.What was done?
Stored default
= 0(ECDSA) on the property, matching the established convention for post-hoc columns (isImported,statusRaw,blockPosition). Defaulted rows read as ECDSA until the next Rust address-pool persist pulse re-tags typed entries, which happens on every load — so provider BLS/EdDSA rows self-heal immediately.How Has This Been Tested?
Reproduced the crash on the booted simulator: pre-#4127 store + v4.1-dev tip → container load error + crash to home screen. With this fix the same store migrates, the container loads, and the app launches.
Breaking Changes
None.
Checklist:
🤖 Generated with Claude Code
Summary by CodeRabbit