feat(platform-wallet): serde support#3637
Conversation
Add a new `serde` Cargo feature on `platform-wallet`. When enabled, every type carried in a `PlatformWalletChangeSet` gains `serde::Serialize` / `serde::Deserialize` derives via `#[cfg_attr(feature = "serde", derive(...))]`: - `CoreChangeSet`, `IdentityChangeSet`, `IdentityEntry`, `IdentityKeysChangeSet`, `IdentityKeyEntry`, `IdentityKeyDerivationIndices`, `ContactChangeSet`, `ContactRequestEntry`, `SentContactRequestKey`, `ReceivedContactRequestKey`, `PlatformAddressChangeSet`, `PlatformAddressBalanceEntry`, `AssetLockChangeSet`, `AssetLockEntry`, `TokenBalanceChangeSet`, `WalletMetadataEntry`, `AccountRegistrationEntry`, `AccountAddressPoolEntry`, and the top-level `PlatformWalletChangeSet`. - Per-identity / DashPay leaf types referenced inside those changesets: `BlockTime`, `IdentityStatus`, `DpnsNameInfo`, `DashPayProfile`, `ContactRequest`, `EstablishedContact`, `PaymentEntry`, `PaymentDirection`, `PaymentStatus`, `AssetLockStatus`. The feature activates `key-wallet/serde` (which transitively flips `dashcore/serde` and `dash-network/serde`) so every upstream leaf type already wired with `#[cfg_attr(feature = "serde", ...)]` (TransactionRecord, Utxo, InstantLock, AccountType, AddressInfo, AddressPoolType, ExtendedPubKey, Network) round-trips cleanly. Two upstream types lack their own serde feature and use `#[serde(with = ...)]` adapters in the new `src/changeset/serde_adapters.rs` module: - `AssetLockFundingType` (key-wallet, no `serde` derive) — encoded as a stable u8 tag matching the prior hand-rolled blob layout. - `AddressFunds` (dash-sdk re-export, no serde derive) — encoded as a `(nonce, balance)` shadow struct. One field is marked `#[serde(skip)]`: - `CoreChangeSet::addresses_derived` carries `key_wallet_manager::DerivedAddress`, which has no serde derive AND no `key-wallet-manager/serde` feature to activate. The breadcrumb is written to a typed table by persisters, not via a changeset blob, so skipping costs nothing. `cargo build -p platform-wallet` (no features) and `cargo build -p platform-wallet --features serde` both build clean. `cargo test -p platform-wallet` passes (8 lib tests, 121 integration tests) with and without the new feature. The change is opt-in; the default-feature build is byte-identical to its prior shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR introduces optional ChangesSerde Serialization Feature for Wallet Types
🎯 2 (Simple) | ⏱️ ~12 minutes
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
Per audit: `AddressFunds` is first-party (lives in `rs-sdk/src/platform/address_sync/types.rs`) and its inner fields (`AddressNonce = u32`, `Credits = u64`) come from `dpp`, which derives serde unconditionally. The `#[serde(with = "serde_adapters::address_funds")]` adapter was pure boilerplate re-implementing what `derive(Serialize, Deserialize)` would produce. Replaced with a direct `#[cfg_attr(feature = "serde", derive(...))]` on `AddressFunds`. The `asset_lock_funding_type` adapter is retained — the upstream `AssetLockFundingType` in `rust-dashcore` key-wallet has no serde derives, and the adapter also encodes a stable `u8` wire-tag for on-disk blob compatibility that's worth keeping documented. Net: -~30 LOC. `platform-wallet`'s `serde` feature now propagates `dash-sdk/serde` so the gated derive on `AddressFunds` is activated when the parent feature is on. (Stray `cargo fmt -p platform-wallet` hit one pre-existing formatting nit in `wallet/platform_addresses/wallet.rs` — included since the quality gate runs fmt.) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Audit-driven cleanup landed (
|
Scope: PR #3637's own diff against v3.1-dev only (the serde-feature PR). Pre-existing v3.1-dev comments left untouched. Drivers: - Verbosity: the Cargo.toml `serde` feature note was 12 lines enumerating every leaf type that gains a derive — collapsed to 6 lines covering the meaningful "what activates" + "which field is skipped" bits. - Verbosity: the `addresses_derived` `#[serde(skip)]` paragraph trimmed from 7 lines to 4, keeping the external-constraint citation (upstream type has no serde derive, no feature to activate) and the pointer to where persisters actually store the breadcrumb. - Present-state, not history: the `asset_lock_funding_type` adapter docstring referenced "the hand-rolled BlobWriter used before the serde swap" — that's PR history, dropped. Kept the meaningful "stable u8 tag for on-disk blob compat" rationale. - Verbosity / redundant-with-cfg: the `serde_adapters.rs` module header said "compiled only when the serde feature is on" with a paragraph pointing back to the `#[cfg(feature = "serde")]` line that imports it. The cfg gate is self-documenting; trimmed from 6 lines to 2 and rephrased "upstream types that don't (yet) derive" to "upstream types lacking their own derives" now that only one adapter remains. No tombstones added. No code semantics touched. cargo fmt + check (both feature flag states) + clippy --all-features + lib tests (121 passing) all green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rop serde workarounds Workspace `Cargo.toml` swapped `rev = "53130869..."` for `branch = "feat/key-wallet-serde-derives"` on all 9 rust-dashcore crates to consume PR #761's serde derives ahead of upstream merge. Cargo's `[patch]` mechanism doesn't support same-source-different-branch redirects (rust-lang/cargo#5478, #10756); direct branch pinning is the working mechanism. Cargo.lock now resolves the 12 dashcore-sourced crates at `56a84402c8cb006d65b12e400785a62d67441930`, which the branch has been rebased onto so it carries ONLY the serde additions (no v0.42-dev drift). Dropped `serde_adapters::asset_lock_funding_type` adapter — type now derives upstream via #761. `serde_adapters.rs` deleted and removed from `changeset/mod.rs`. Dropped `#[serde(skip)]` on `CoreChangeSet::addresses_derived` — `DerivedAddress` now derives upstream (with `serde_pubkey33` adapter packaged inside #761 for the 33-byte pubkey field). Added `"key-wallet-manager/serde"` to platform-wallet's serde feature. Wire-format note: the upstream derive on `AssetLockFundingType` produces externally-tagged enum representation; the dropped custom adapter produced a stable `u8` wire-tag. PR #3637 is unreleased and the feature is opt-in — no consumer was persisting blobs with the prior format. Follow-up after #761 merges to v0.42-dev: swap `branch = "..."` back to `rev = "<new-rev>"` and remove the temp comment in workspace Cargo.toml. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Consuming dashpay/rust-dashcore#761 (
|
|
✅ Review complete (commit 5fe906e) |
`platform_wallet_info_create_from_mnemonic` now takes 3 args (network, mnemonic, out_handle); the integration tests still passed a 4th `std::ptr::null()` between `mnemonic` and `out_handle`, breaking the mac nextest job. Sync both call sites with the current FFI signature. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-existing `matches!(result, Err(_))` patterns trip `clippy::redundant_pattern_matching` under the workspace's `-D warnings` gate. Swap to `result.is_err()` so the clippy step stays green for the crates this PR touches. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
✅ DashSDKFFI.xcframework built for this PR.
SwiftPM (host the zip at a stable URL, then use): .binaryTarget(
name: "DashSDKFFI",
url: "https://your.cdn.example/DashSDKFFI.xcframework.zip",
checksum: "76ca1c5f6be6ac74b73870da500a5273d73030168e63366771f3dcbde3ca2472"
)Xcode manual integration:
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## v3.1-dev #3637 +/- ##
============================================
- Coverage 88.25% 88.24% -0.01%
============================================
Files 2494 2506 +12
Lines 304580 307938 +3358
============================================
+ Hits 268812 271745 +2933
- Misses 35768 36193 +425
🚀 New features to boost your workflow:
|
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Purely additive PR adding opt-in serde derives behind a new serde feature on rs-platform-wallet changeset/wallet types plus AddressFunds in rs-sdk. No blocking issues. Two material suggestions: (1) the temporary workspace-wide switch from rev = to branch = on nine rust-dashcore crates weakens reproducibility, and (2) several newly-Serialize-able changesets use composite/struct BTreeMap keys ((Identifier, KeyID), OutPoint, SentContactRequestKey, (Identifier, Identifier)) which compile cleanly but fail at runtime under serde_json. Minor coverage and style nits round out the review.
Reviewed commit: f23183c
🟡 3 suggestion(s) | 💬 1 nitpick(s)
1 additional finding
🟡 suggestion: Newly-serializable changesets use non-string map keys — incompatible with `serde_json`
packages/rs-platform-wallet/src/changeset/changeset.rs (lines 358-363)
Several types behind the new serde feature use BTreeMap/BTreeSet keys that serde-derives can encode for binary formats (bincode/CBOR/MessagePack) but that serde_json rejects at runtime with key must be a string:
IdentityKeysChangeSet::upserts: BTreeMap<(Identifier, KeyID), _>(line 360)IdentityKeysChangeSet::removed: BTreeSet<(Identifier, KeyID)>(line 362)ContactChangeSet::sent_requests/incoming_requests/establishedkeyed bySentContactRequestKey/ReceivedContactRequestKey(lines 553/557/565)AssetLockChangeSet::asset_locks: BTreeMap<OutPoint, AssetLockEntry>(line 687)TokenBalanceChangeSet::balances: BTreeMap<(Identifier, Identifier), u64>(line 744)PlatformWalletChangeSet::dashpay_profiles/dashpay_payments_overlaykeyed byIdentifier(lines 896/900)
If the only intended consumer is a bincode-backed persister this is a latent footgun rather than an immediate bug, but the feature is public on a published crate and the PR description frames serde as the persistence path. A downstream consumer enabling platform-wallet/serde will compile cleanly and only discover the JSON limitation at runtime. Options: (a) reshape these as Vec<(K, V)>, (b) apply #[serde(with = ...)]/serde_with to flatten tuple/struct keys into strings, or (c) explicitly document in the feature flag that JSON is unsupported.
🤖 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 `Cargo.toml`:
- [SUGGESTION] lines 52-65: Pin rust-dashcore by `rev` instead of mutable `branch`
All nine `rust-dashcore`-derived workspace dependencies were switched from a fixed `rev = "53130869…"` to `branch = "feat/key-wallet-serde-derives"`. Cargo.lock currently locks the resolved commit (`56a84402c8cb006d65b12e400785a62d67441930`), but any `cargo update`, fresh lockfile generation, or upstream force-push/rebase/branch-deletion will silently re-resolve every dashcore-derived crate to whatever HEAD is at that moment. The blast radius covers the whole workspace, not just the two crates that actually need the new serde derives. Pinning to the current branch tip by `rev = "56a84402c8cb006d65b12e400785a62d67441930"` carries identical bits today, is immune to rebases of dashpay/rust-dashcore#761, and leaves a clean `rev` → `rev` swap when the upstream merges. This matches the hygiene pattern used at every other previous dashcore consumption point in this workspace.
In `packages/rs-platform-wallet/src/changeset/changeset.rs`:
- [SUGGESTION] lines 358-363: Newly-serializable changesets use non-string map keys — incompatible with `serde_json`
Several types behind the new `serde` feature use `BTreeMap`/`BTreeSet` keys that serde-derives can encode for binary formats (bincode/CBOR/MessagePack) but that `serde_json` rejects at runtime with `key must be a string`:
- `IdentityKeysChangeSet::upserts: BTreeMap<(Identifier, KeyID), _>` (line 360)
- `IdentityKeysChangeSet::removed: BTreeSet<(Identifier, KeyID)>` (line 362)
- `ContactChangeSet::sent_requests`/`incoming_requests`/`established` keyed by `SentContactRequestKey`/`ReceivedContactRequestKey` (lines 553/557/565)
- `AssetLockChangeSet::asset_locks: BTreeMap<OutPoint, AssetLockEntry>` (line 687)
- `TokenBalanceChangeSet::balances: BTreeMap<(Identifier, Identifier), u64>` (line 744)
- `PlatformWalletChangeSet::dashpay_profiles`/`dashpay_payments_overlay` keyed by `Identifier` (lines 896/900)
If the only intended consumer is a bincode-backed persister this is a latent footgun rather than an immediate bug, but the feature is public on a published crate and the PR description frames serde as the persistence path. A downstream consumer enabling `platform-wallet/serde` will compile cleanly and only discover the JSON limitation at runtime. Options: (a) reshape these as `Vec<(K, V)>`, (b) apply `#[serde(with = ...)]`/`serde_with` to flatten tuple/struct keys into strings, or (c) explicitly document in the feature flag that JSON is unsupported.
In `packages/rs-platform-wallet/Cargo.toml`:
- [SUGGESTION] lines 69-76: No round-trip serde tests cover the new serde surface
The PR adds `Serialize`/`Deserialize` derives on ~16 public types but no encode→decode test exercises them. The existing 121/121 test count cited in the description is pre-existing — `cargo check --features serde` only proves the feature compiles. The derives use default representation (field names as map keys, field order for non-self-describing formats), so any future field rename/reorder or upstream serde-impl change in transitive deps (`TransactionRecord`, `Utxo`, `InstantLock`, `AssetLockFundingType`, `AddressInfo`, `ExtendedPubKey`, `PlatformP2PKHAddress`, `AddressFunds`, `IdentityPublicKey`, `AssetLockProof`) can silently break the wire format with no signal in this crate's test suite. A small set of bincode round-trip tests on `PlatformWalletChangeSet`, `IdentityEntry`, and `AssetLockEntry` would lock down the format and catch regressions before they reach a persister.
| # Temporary: branch-pinned to dashpay/rust-dashcore#761 (`feat/key-wallet-serde-derives`) | ||
| # for serde derives on AssetLockFundingType + DerivedAddress. The branch has been | ||
| # rebased onto 53130869 so it carries ONLY the serde additions (no v0.42-dev drift). | ||
| # Drop the branch= override and restore rev= once #761 merges to v0.42-dev and a | ||
| # subsequent dashcore rev bump flows the new rev in. | ||
| dashcore = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| dash-network-seeds = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| dash-spv = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| dash-spv-ffi = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| key-wallet = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| key-wallet-ffi = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| dash-network = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } |
There was a problem hiding this comment.
🟡 Suggestion: Pin rust-dashcore by rev instead of mutable branch
All nine rust-dashcore-derived workspace dependencies were switched from a fixed rev = "53130869…" to branch = "feat/key-wallet-serde-derives". Cargo.lock currently locks the resolved commit (56a84402c8cb006d65b12e400785a62d67441930), but any cargo update, fresh lockfile generation, or upstream force-push/rebase/branch-deletion will silently re-resolve every dashcore-derived crate to whatever HEAD is at that moment. The blast radius covers the whole workspace, not just the two crates that actually need the new serde derives. Pinning to the current branch tip by rev = "56a84402c8cb006d65b12e400785a62d67441930" carries identical bits today, is immune to rebases of dashpay/rust-dashcore#761, and leaves a clean rev → rev swap when the upstream merges. This matches the hygiene pattern used at every other previous dashcore consumption point in this workspace.
💡 Suggested change
| # Temporary: branch-pinned to dashpay/rust-dashcore#761 (`feat/key-wallet-serde-derives`) | |
| # for serde derives on AssetLockFundingType + DerivedAddress. The branch has been | |
| # rebased onto 53130869 so it carries ONLY the serde additions (no v0.42-dev drift). | |
| # Drop the branch= override and restore rev= once #761 merges to v0.42-dev and a | |
| # subsequent dashcore rev bump flows the new rev in. | |
| dashcore = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | |
| dash-network-seeds = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | |
| dash-spv = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | |
| dash-spv-ffi = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | |
| key-wallet = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | |
| key-wallet-ffi = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | |
| key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | |
| dash-network = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | |
| dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | |
| dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "56a84402c8cb006d65b12e400785a62d67441930" } | |
| dash-network-seeds = { git = "https://github.com/dashpay/rust-dashcore", rev = "56a84402c8cb006d65b12e400785a62d67441930" } | |
| dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "56a84402c8cb006d65b12e400785a62d67441930" } | |
| dash-spv-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "56a84402c8cb006d65b12e400785a62d67441930" } | |
| key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "56a84402c8cb006d65b12e400785a62d67441930" } | |
| key-wallet-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "56a84402c8cb006d65b12e400785a62d67441930" } | |
| key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "56a84402c8cb006d65b12e400785a62d67441930" } | |
| dash-network = { git = "https://github.com/dashpay/rust-dashcore", rev = "56a84402c8cb006d65b12e400785a62d67441930" } | |
| dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "56a84402c8cb006d65b12e400785a62d67441930" } |
source: ['claude', 'codex']
🤖 Fix this 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 `Cargo.toml`:
- [SUGGESTION] lines 52-65: Pin rust-dashcore by `rev` instead of mutable `branch`
All nine `rust-dashcore`-derived workspace dependencies were switched from a fixed `rev = "53130869…"` to `branch = "feat/key-wallet-serde-derives"`. Cargo.lock currently locks the resolved commit (`56a84402c8cb006d65b12e400785a62d67441930`), but any `cargo update`, fresh lockfile generation, or upstream force-push/rebase/branch-deletion will silently re-resolve every dashcore-derived crate to whatever HEAD is at that moment. The blast radius covers the whole workspace, not just the two crates that actually need the new serde derives. Pinning to the current branch tip by `rev = "56a84402c8cb006d65b12e400785a62d67441930"` carries identical bits today, is immune to rebases of dashpay/rust-dashcore#761, and leaves a clean `rev` → `rev` swap when the upstream merges. This matches the hygiene pattern used at every other previous dashcore consumption point in this workspace.
| # Opt-in serde derives on the changeset types. Activates `key-wallet/serde`, | ||
| # `key-wallet-manager/serde` (both via dashpay/rust-dashcore#761, branch-pinned in | ||
| # workspace Cargo.toml), and `dash-sdk/serde`. `dpp` derives serde unconditionally. | ||
| serde = [ | ||
| "dep:serde", | ||
| "key-wallet/serde", | ||
| "key-wallet-manager/serde", | ||
| "dash-sdk/serde", |
There was a problem hiding this comment.
🟡 Suggestion: No round-trip serde tests cover the new serde surface
The PR adds Serialize/Deserialize derives on ~16 public types but no encode→decode test exercises them. The existing 121/121 test count cited in the description is pre-existing — cargo check --features serde only proves the feature compiles. The derives use default representation (field names as map keys, field order for non-self-describing formats), so any future field rename/reorder or upstream serde-impl change in transitive deps (TransactionRecord, Utxo, InstantLock, AssetLockFundingType, AddressInfo, ExtendedPubKey, PlatformP2PKHAddress, AddressFunds, IdentityPublicKey, AssetLockProof) can silently break the wire format with no signal in this crate's test suite. A small set of bincode round-trip tests on PlatformWalletChangeSet, IdentityEntry, and AssetLockEntry would lock down the format and catch regressions before they reach a persister.
source: ['claude']
🤖 Fix this 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/rs-platform-wallet/Cargo.toml`:
- [SUGGESTION] lines 69-76: No round-trip serde tests cover the new serde surface
The PR adds `Serialize`/`Deserialize` derives on ~16 public types but no encode→decode test exercises them. The existing 121/121 test count cited in the description is pre-existing — `cargo check --features serde` only proves the feature compiles. The derives use default representation (field names as map keys, field order for non-self-describing formats), so any future field rename/reorder or upstream serde-impl change in transitive deps (`TransactionRecord`, `Utxo`, `InstantLock`, `AssetLockFundingType`, `AddressInfo`, `ExtendedPubKey`, `PlatformP2PKHAddress`, `AddressFunds`, `IdentityPublicKey`, `AssetLockProof`) can silently break the wire format with no signal in this crate's test suite. A small set of bincode round-trip tests on `PlatformWalletChangeSet`, `IdentityEntry`, and `AssetLockEntry` would lock down the format and catch regressions before they reach a persister.
| .platform_payment_managed_account_at_index_mut(*account_index) | ||
| { | ||
| for (p2pkh, funds) in account_state.found() { | ||
| account.set_address_credit_balance( | ||
| *p2pkh, | ||
| funds.balance, | ||
| None, | ||
| ); | ||
| account.set_address_credit_balance(*p2pkh, funds.balance, None); | ||
| } |
There was a problem hiding this comment.
💬 Nitpick: Unrelated formatting change bundled into a serde-only PR
The diff collapses the 4-line set_address_credit_balance(*p2pkh, funds.balance, None) call into a single line. The change is cosmetic and unrelated to the serde-feature additions the PR is scoped to — it pollutes git blame for an otherwise serde-focused commit history. Either revert this hunk and land the fmt fix separately, or mention it explicitly in the PR description.
source: ['claude']
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/rs-platform-wallet/src/changeset/changeset.rs`:
- Around line 867-868: CoreChangeSet and PlatformWalletChangeSet currently add
serde derives via #[cfg_attr(feature = "serde", ...)] but they contain upstream
types (TransactionRecord, Utxo, InstantLock, etc.) that do not implement serde
yet, causing build failures when the serde feature is enabled; fix this by
removing or disabling the conditional serde derives until the upstream
feat/key-wallet-serde-derives branch lands — either delete the
#[cfg_attr(feature = "serde", derive(...))] lines on the CoreChangeSet and
PlatformWalletChangeSet structs, or replace them with a new feature gate (e.g.,
#[cfg_attr(feature = "key-wallet-serde", derive(...))]) that you only enable
once the upstream types implement serde, and keep a comment referencing
TransactionRecord, Utxo, and InstantLock so future maintainers know why the
serde derives are withheld.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 17f27c68-f361-4ba4-97a2-cf0618592baa
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (12)
Cargo.tomlpackages/rs-platform-wallet/Cargo.tomlpackages/rs-platform-wallet/src/changeset/changeset.rspackages/rs-platform-wallet/src/wallet/asset_lock/tracked.rspackages/rs-platform-wallet/src/wallet/identity/types/block_time.rspackages/rs-platform-wallet/src/wallet/identity/types/dashpay/contact_request.rspackages/rs-platform-wallet/src/wallet/identity/types/dashpay/established_contact.rspackages/rs-platform-wallet/src/wallet/identity/types/dashpay/payment.rspackages/rs-platform-wallet/src/wallet/identity/types/dashpay/profile.rspackages/rs-platform-wallet/src/wallet/identity/types/key_storage.rspackages/rs-platform-wallet/src/wallet/platform_addresses/wallet.rspackages/rs-sdk/src/platform/address_sync/types.rs
| #[derive(Debug, Clone, Default)] | ||
| #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify that enabling the serde feature allows successful compilation
cargo check --package rs-platform-wallet --features serdeRepository: dashpay/platform
Length of output: 1127
🏁 Script executed:
# Check the workspace structure and Cargo.toml files
git ls-files | grep -E "Cargo.toml$" | head -20Repository: dashpay/platform
Length of output: 794
🏁 Script executed:
# Explore the directory structure
ls -la packages/rs-platform-wallet/ | head -20Repository: dashpay/platform
Length of output: 672
🏁 Script executed:
# Check if rs-platform-wallet has Cargo.toml
cat packages/rs-platform-wallet/Cargo.toml | head -50Repository: dashpay/platform
Length of output: 1304
🏁 Script executed:
# Read the rest of Cargo.toml to check [features] section
tail -n +42 packages/rs-platform-wallet/Cargo.tomlRepository: dashpay/platform
Length of output: 2139
🏁 Script executed:
# Check the changeset.rs file around lines 867-868
sed -n '860,880p' packages/rs-platform-wallet/src/changeset/changeset.rsRepository: dashpay/platform
Length of output: 1156
🏁 Script executed:
# Find where upstream types are defined - search for their definitions
rg -A 3 "struct TransactionRecord" --type rsRepository: dashpay/platform
Length of output: 87
🏁 Script executed:
# Search for CoreChangeSet definition
rg "struct CoreChangeSet" --type-list | headRepository: dashpay/platform
Length of output: 450
🏁 Script executed:
# Look at the imports and full context of changeset.rs file
head -n 50 packages/rs-platform-wallet/src/changeset/changeset.rsRepository: dashpay/platform
Length of output: 2264
🏁 Script executed:
# Find where TransactionRecord is imported from
rg "TransactionRecord" packages/rs-platform-wallet/src/changeset/changeset.rs -B 2 -A 2Repository: dashpay/platform
Length of output: 1319
🏁 Script executed:
# Find CoreChangeSet definition
rg "struct CoreChangeSet" --type rust -A 5Repository: dashpay/platform
Length of output: 682
🏁 Script executed:
# Now try the correct cargo command with the right package name
cd packages/rs-platform-wallet && cargo check --features serde 2>&1 | tail -50Repository: dashpay/platform
Length of output: 146
🏁 Script executed:
# Get the full CoreChangeSet struct definition
rg "struct CoreChangeSet" --type rust -A 30 | head -50Repository: dashpay/platform
Length of output: 3375
🏁 Script executed:
# Check what derives CoreChangeSet has
sed -n '650,750p' packages/rs-platform-wallet/src/changeset/changeset.rsRepository: dashpay/platform
Length of output: 4096
🏁 Script executed:
# Search for custom serde implementations for CoreChangeSet
rg "impl.*Serialize.*CoreChangeSet\|impl.*Deserialize.*CoreChangeSet" --type rustRepository: dashpay/platform
Length of output: 42
🏁 Script executed:
# Search for CoreChangeSet with its struct definition and derives
sed -n '600,700p' packages/rs-platform-wallet/src/changeset/changeset.rs | head -80Repository: dashpay/platform
Length of output: 3640
🏁 Script executed:
# Look at lines around where CoreChangeSet is likely defined (searching backwards from line 867)
sed -n '500,650p' packages/rs-platform-wallet/src/changeset/changeset.rs | tail -100Repository: dashpay/platform
Length of output: 4829
🏁 Script executed:
# Search for CoreChangeSet struct definition with derives
rg "pub struct CoreChangeSet" --type rust -B 5 -A 50 | head -80Repository: dashpay/platform
Length of output: 6069
🏁 Script executed:
# Also check if there are any custom serde implementations
rg "impl.*serde.*CoreChangeSet\|#\[cfg_attr.*serde.*CoreChangeSet" --type rust -B 2 -A 5Repository: dashpay/platform
Length of output: 42
🏁 Script executed:
# Check around line 400-550 where CoreChangeSet is likely defined
sed -n '400,550p' packages/rs-platform-wallet/src/changeset/changeset.rsRepository: dashpay/platform
Length of output: 7373
🏁 Script executed:
# Check if there are custom serde impls for CoreChangeSet or its types
rg "impl.*Serialize\|impl.*Deserialize" packages/rs-platform-wallet/src/changeset/changeset.rs | head -20Repository: dashpay/platform
Length of output: 42
🏁 Script executed:
# Search in key_wallet for TransactionRecord serde support
fd -t f "transaction_record" packages/ 2>/dev/nullRepository: dashpay/platform
Length of output: 42
🏁 Script executed:
# Check key-wallet crate for TransactionRecord definition
find packages -name "*key-wallet*" -type d 2>/dev/null | head -5Repository: dashpay/platform
Length of output: 42
🏁 Script executed:
# Let's check the actual comment around TransactionRecord to understand the constraint better
sed -n '420,445p' packages/rs-platform-wallet/src/changeset/changeset.rsRepository: dashpay/platform
Length of output: 1709
🏁 Script executed:
# Let's search in the workspace dependencies for key-wallet crate
git ls-files | grep -i "key.wallet" | grep -v ".git" | head -20Repository: dashpay/platform
Length of output: 42
🏁 Script executed:
# Check the workspace Cargo.toml for key-wallet details
cat Cargo.toml | grep -A 10 "key-wallet"Repository: dashpay/platform
Length of output: 1804
🏁 Script executed:
# Look for any documentation or source about TransactionRecord serde support
rg "TransactionRecord" packages/rs-platform-wallet/ -B 2 -A 2 | grep -i "serde\|serialize" | head -10Repository: dashpay/platform
Length of output: 300
🏁 Script executed:
# Search for any custom serde implementations in changeset.rs
rg "impl.*Serialize\|impl.*Deserialize" packages/rs-platform-wallet/src/ -A 3 | grep -i "corechangeset\|transactionrecord"Repository: dashpay/platform
Length of output: 42
🏁 Script executed:
# Check if there's a way serde works despite TransactionRecord not having it - look for feature gates
rg "#\[cfg" packages/rs-platform-wallet/src/changeset/changeset.rs | head -20Repository: dashpay/platform
Length of output: 1536
🏁 Script executed:
# Look at the exact line with the problematic comment about TransactionRecord
sed -n '415,435p' packages/rs-platform-wallet/src/changeset/changeset.rsRepository: dashpay/platform
Length of output: 1358
🏁 Script executed:
# Let's check what's on the feat/key-wallet-serde-derives branch for TransactionRecord
# First, try to understand if TransactionRecord actually has serde now
rg "pub struct TransactionRecord" --type rust -A 10 | head -20Repository: dashpay/platform
Length of output: 1055
🏁 Script executed:
# Check the comment in Cargo.toml more carefully about which types get serde
sed -n '1,20p' Cargo.tomlRepository: dashpay/platform
Length of output: 658
🏁 Script executed:
# Let's look at the full context of the comment about TransactionRecord in changeset.rs
sed -n '405,425p' packages/rs-platform-wallet/src/changeset/changeset.rsRepository: dashpay/platform
Length of output: 1265
🏁 Script executed:
# Check what the current cargo.lock or Cargo.toml says about the branch status
cat Cargo.lock | grep -A 5 "name = \"key-wallet\"" | head -20Repository: dashpay/platform
Length of output: 276
🏁 Script executed:
# Let's look at the exact line numbers mentioned in the review (867-868)
sed -n '865,870p' packages/rs-platform-wallet/src/changeset/changeset.rsRepository: dashpay/platform
Length of output: 413
🏁 Script executed:
# Look at the broader context - is this CoreChangeSet or PlatformWalletChangeSet?
sed -n '860,875p' packages/rs-platform-wallet/src/changeset/changeset.rsRepository: dashpay/platform
Length of output: 854
🏁 Script executed:
# Check the comment about TransactionRecord more fully
sed -n '408,425p' packages/rs-platform-wallet/src/changeset/changeset.rsRepository: dashpay/platform
Length of output: 1060
🏁 Script executed:
# Check the comment about what the serde feature enables
sed -n '42,52p' packages/rs-platform-wallet/Cargo.tomlRepository: dashpay/platform
Length of output: 459
🏁 Script executed:
# Look at CoreChangeSet definition with its derives
sed -n '405,475p' packages/rs-platform-wallet/src/changeset/changeset.rsRepository: dashpay/platform
Length of output: 3701
🏁 Script executed:
# Search for where CoreChangeSet is defined with its derives
rg "pub struct CoreChangeSet" --type rust -B 10 | head -25Repository: dashpay/platform
Length of output: 1264
Upstream types lack serde support for changeset serialization.
CoreChangeSet and PlatformWalletChangeSet use conditional serde derives (#[cfg_attr(feature = "serde", ...)]), but they contain TransactionRecord and other upstream types from key-wallet that are currently "Debug + Clone only" per the code's own comment. The serde feature cannot work until TransactionRecord, Utxo, InstantLock, and other imported types derive serde on the upstream feat/key-wallet-serde-derives branch. This will cause compilation failures when the serde feature is enabled until upstream types are fully updated.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/rs-platform-wallet/src/changeset/changeset.rs` around lines 867 -
868, CoreChangeSet and PlatformWalletChangeSet currently add serde derives via
#[cfg_attr(feature = "serde", ...)] but they contain upstream types
(TransactionRecord, Utxo, InstantLock, etc.) that do not implement serde yet,
causing build failures when the serde feature is enabled; fix this by removing
or disabling the conditional serde derives until the upstream
feat/key-wallet-serde-derives branch lands — either delete the
#[cfg_attr(feature = "serde", derive(...))] lines on the CoreChangeSet and
PlatformWalletChangeSet structs, or replace them with a new feature gate (e.g.,
#[cfg_attr(feature = "key-wallet-serde", derive(...))]) that you only enable
once the upstream types implement serde, and keep a comment referencing
TransactionRecord, Utxo, and InstantLock so future maintainers know why the
serde derives are withheld.
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
The serde derives added in this PR are mechanically consistent with the types they touch, and I did not confirm any consensus, runtime, or persistence-path regression in the wallet code itself. Three of the reported issues depend on assumptions the source does not make: the new feature is documented as serde support for changeset types, not for the separately documented startup snapshot path, and it does not promise JSON-specific encoding or backward-compatible on-disk schema evolution. The remaining review-worthy issue is the workspace-wide move from fixed git revisions to a floating branch, which introduces avoidable build drift on the next lockfile refresh.
Reviewed commit: 5fe906e
🟡 1 suggestion(s)
🤖 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 `Cargo.toml`:
- [SUGGESTION] lines 57-65: Floating branch pins weaken workspace reproducibility
This PR replaces nine `rust-dashcore` workspace dependencies that were pinned to commit `53130869e5b9343ae59016323e5e5269e717a8fd` with `branch = "feat/key-wallet-serde-derives"`. The comment above these lines explains the intent, but the manifest still stops identifying the exact upstream source being reviewed. `Cargo.lock` keeps this checkout stable today, yet any future `cargo update` or lockfile regeneration can silently pull a different branch head into consensus-sensitive crates. Keeping the temporary serde workaround on a fixed `rev` preserves the same functionality without introducing that drift.
| dashcore = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| dash-network-seeds = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| dash-spv = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| dash-spv-ffi = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| key-wallet = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| key-wallet-ffi = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| dash-network = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } | ||
| dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", branch = "feat/key-wallet-serde-derives" } |
There was a problem hiding this comment.
🟡 Suggestion: Floating branch pins weaken workspace reproducibility
This PR replaces nine rust-dashcore workspace dependencies that were pinned to commit 53130869e5b9343ae59016323e5e5269e717a8fd with branch = "feat/key-wallet-serde-derives". The comment above these lines explains the intent, but the manifest still stops identifying the exact upstream source being reviewed. Cargo.lock keeps this checkout stable today, yet any future cargo update or lockfile regeneration can silently pull a different branch head into consensus-sensitive crates. Keeping the temporary serde workaround on a fixed rev preserves the same functionality without introducing that drift.
source: ['codex']
🤖 Fix this 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 `Cargo.toml`:
- [SUGGESTION] lines 57-65: Floating branch pins weaken workspace reproducibility
This PR replaces nine `rust-dashcore` workspace dependencies that were pinned to commit `53130869e5b9343ae59016323e5e5269e717a8fd` with `branch = "feat/key-wallet-serde-derives"`. The comment above these lines explains the intent, but the manifest still stops identifying the exact upstream source being reviewed. `Cargo.lock` keeps this checkout stable today, yet any future `cargo update` or lockfile regeneration can silently pull a different branch head into consensus-sensitive crates. Keeping the temporary serde workaround on a fixed `rev` preserves the same functionality without introducing that drift.
Issue being fixed or feature implemented
Splits the
rs-platform-walletserde-support additions out of PR #3625 (feat(platform-wallet): add platform-wallet-storage crate (sqlite persister)) so they can land independently onv3.1-dev. Original commit (e26945cfdfby @lklimek) stays in PR #3625; this PR cherry-picks just the serde-additive changes for separate review/merge cadence — same hygiene pattern used for PR #3636 (birth_height_overridesplit from PR #3549).What was done?
Adds optional
serdederives behind aserdefeature flag onrs-platform-wallet's public types. 12 files, +154 lines. Touches:packages/rs-platform-wallet/Cargo.toml— new[features] serde = ["dep:serde", "key-wallet/serde", "key-wallet-manager/serde", "dash-sdk/serde"]entry + optionalserdedependency. Propagation reachesrs-sdk(AddressFunds),key-wallet(AssetLockFundingType— upstream derive after feat(key-wallet,key-wallet-manager): add serde derives for AssetLockFundingType and DerivedAddress rust-dashcore#761), andkey-wallet-manager(DerivedAddress— upstream derive after fix commenting #761).packages/rs-platform-wallet/src/changeset/—changeset.rsandmod.rsupdated with#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]attributes on the changeset types. Noserde_adaptersmodule — upstream now derives bothAssetLockFundingType(via#761) andDerivedAddress(via#761with aserde_pubkey33adapter for the 33-byte pubkey field), so the changeset types serialize via plain derives.packages/rs-sdk/src/platform/address_sync/types.rs—AddressFundsgets a directcfg_attrderive.packages/rs-platform-wallet/src/wallet/—cfg_attrderives on 8 leaf types inasset_lock/tracked.rs,identity/types/block_time.rs,identity/types/key_storage.rs, andidentity/types/dashpay/{contact_request,established_contact,payment,profile}.rs.Cargo.toml— temporary: 9 rust-dashcore deps swapped fromrev = "53130869..."tobranch = "feat/key-wallet-serde-derives"to consume feat(key-wallet,key-wallet-manager): add serde derives for AssetLockFundingType and DerivedAddress rust-dashcore#761 ahead of its upstream merge. Cargo's[patch]mechanism doesn't support same-source-different-branch redirects (rust-lang/cargo#5478, #10756); direct branch pinning is the working alternative. fix commenting #761's branch has been rebased onto53130869so it carries ONLY the serde additions (no v0.42-dev drift). Follow-up: drop the branch pin and restorerev = "<new>"after fix commenting #761 merges tov0.42-devand a subsequent dashcore rev bump flows into this workspace.No production-logic changes — purely additive serde derive lines + adapter helpers, behind a default-off feature gate.
Breaking Changes
None. The additions are behind a
serdefeature that's off by default.How Has This Been Tested?
cargo check -p platform-wallet --no-default-features— cleancargo check -p platform-wallet --features serde— cleancargo check -p platform-wallet --tests --all-features— cleancargo clippy -p platform-wallet --tests --all-features --no-deps -- -D warnings— zero warningscargo test -p platform-wallet --features serde --lib— 121/121 passcargo fmt— cleanCompanion to
PR #3625 retains the same commit (
e26945cfdf); this is a hygiene split for independent review cadence. When this PR merges tov3.1-dev, the cherry-pick in PR #3625 becomes a duplicate-by-content and git drops it on rebase.Checklist
For repository code-owners and collaborators only
🤖 Co-authored by Claudius the Magnificent AI Agent
Summary by CodeRabbit
New Features
serdefeature is enabled, allowing wallet state persistence and data interchange capabilities across the platform.Chores