Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
efee42d
feat(model): add the legacy identity recovery plan and additive merge
lklimek Jul 28, 2026
3bab9a9
feat(database): read one legacy identity row through the shared row d…
lklimek Jul 28, 2026
b677776
feat(identity): restore keys stranded in the previous version's saved…
lklimek Jul 28, 2026
c2e859f
feat(masternodes): offer the previous version's stranded keys on the …
lklimek Jul 28, 2026
c274558
feat(identities): offer stranded legacy keys on the Key Info screen
lklimek Jul 28, 2026
e484589
docs(identity): record the legacy-key recovery flow and close the mig…
lklimek Jul 28, 2026
63991b7
fix(model): only offer legacy keys that still correspond to the identity
lklimek Jul 28, 2026
f405098
fix(identity): stop holding the storage guard across the password prompt
lklimek Jul 28, 2026
7caf529
fix(ui): keep the restore offer and the record it wrote in step
lklimek Jul 28, 2026
fc125f4
docs(identity): record what the recovery flow actually shipped
lklimek Jul 28, 2026
24d3081
fix(model): stop the legacy blob from vouching for its own voter key
lklimek Jul 29, 2026
4c42e55
fix(identity): gate the recovery offer on legacy rows, not on data.db…
lklimek Jul 29, 2026
cdde7f1
fix(ui): re-read the key screen on arrival and attribute a finished r…
lklimek Jul 29, 2026
be5299b
test(identity): pin the mid-flight protection guard against regression
lklimek Jul 29, 2026
ad22a2c
fix(model): stop the legacy blob from vouching for its own operator key
lklimek Jul 29, 2026
bff08f7
fix(masternodes): drop the missing-voter message that can never be shown
lklimek Jul 29, 2026
171c512
fix(ui): let the recovery section read as a whole when it can restore…
lklimek Jul 29, 2026
1612fc7
docs(identity): stop promising a voting-key restore that cannot happen
lklimek Jul 29, 2026
2ade1b8
fix(identity): give the identity keys list a way into each key
lklimek Jul 29, 2026
8db5341
test(identity): pin the restore outcome and the key naming on the key…
lklimek Jul 29, 2026
b1e2f28
test(identity): report both restore outcomes on the keys list in the …
lklimek Jul 29, 2026
ef665b1
fix(identity): make the keys list and Key Info agree on where a key i…
lklimek Jul 30, 2026
a237497
fix(identity): return from a key to a current list, in the identity's…
lklimek Jul 30, 2026
cb5b0de
fix(identity): one attribution rule for both hosts of the recovery offer
lklimek Jul 30, 2026
f36b4ca
fix(identity): identify a key by its public half, and name it the sam…
lklimek Jul 30, 2026
aa1234f
fix(identity): find a key's private half where it is filed, not where…
lklimek Jul 30, 2026
2dbc996
fix(identity): Key Info names a user's keys the way the keys list does
lklimek Jul 30, 2026
d39457b
fix(identity): a disabled key the device holds is still reported as held
lklimek Jul 30, 2026
3228b2a
fix(identity): resolve a key's store on demand instead of threading i…
lklimek Jul 30, 2026
91fbc73
fix(masternodes): a key opened from a node's page keeps the name the …
lklimek Jul 30, 2026
66a80a8
refactor(identity): make the key map private so the resolver cannot b…
lklimek Jul 30, 2026
5f82b74
docs(identity): record the key-placement resolution design and the fix
lklimek Jul 30, 2026
4042c01
refactor(identity): one held-key resolution rule for every Manage key…
lklimek Jul 30, 2026
a028d7e
refactor(identity): make an upstream key field a build failure, not a…
lklimek Jul 30, 2026
c95f067
Merge fix/889-key-info-navigation into the key-placement resolver
lklimek Jul 30, 2026
c898a70
test(identity): pin that removing one key spares a different key shar…
lklimek Jul 30, 2026
001b3d5
Merge fix/889-key-info-navigation: port the key-field exhaustiveness …
lklimek Jul 30, 2026
0e41d5d
fix(masternodes): resolve the Add-protection CTA's held key like ever…
lklimek Jul 30, 2026
15f2729
fix(identity): a removed key takes its stored secret with it
lklimek Jul 30, 2026
fd78713
fix(wallet): check the key a placement names before signing with it
lklimek Jul 30, 2026
1a944eb
Merge remote-tracking branch 'origin/v1.0-dev' into fix/889-key-info-…
lklimek Jul 30, 2026
6eb40cb
docs(identity): drop dead review-finding IDs from key-storage doc com…
lklimek Jul 30, 2026
66995fe
refactor(masternodes): narrow first_protectable_key to the key it finds
lklimek Jul 30, 2026
8d72cdc
docs(identity): correct who asks placement_of and why
lklimek Jul 30, 2026
b60ccd2
fix(identity): refuse a key write that would destroy another key's pr…
lklimek Jul 30, 2026
b5c927b
refactor(identity): give every synchronous key lookup one placement rule
lklimek Jul 30, 2026
f334875
fix(identity): reach Key Info's re-read, share the restore offer, nam…
lklimek Jul 30, 2026
2c264bb
docs(user-stories): point IDN-008 at the key list that shipped
lklimek Jul 30, 2026
d9cd6b1
fix(identity): place a key by the whole key, not by its material alone
lklimek Jul 30, 2026
6d5b2f7
fix(identity): find a key's wallet under any placement it is filed at
lklimek Jul 30, 2026
7341b12
fix(identity): decide a pasted key is storable before calling it held
lklimek Jul 30, 2026
a737d62
fix(identity): tell the user what to do about a key that cannot be used
lklimek Jul 30, 2026
c5247f3
fix(identity): stop re-prompting for a key whose password prompt was …
lklimek Jul 30, 2026
2934eaa
refactor(identity): name the two placement questions after their answers
lklimek Jul 30, 2026
50cbd97
refactor(identity): keep the placement-naming key store API inside th…
lklimek Jul 30, 2026
12eeece
test(identity): pin same_key's carve-out and restrict it to this crate
lklimek Jul 30, 2026
1020e6b
docs(grovestark): record the published-key precondition proof generat…
lklimek Jul 30, 2026
17feeea
Merge remote-tracking branch 'origin/fix/889-key-info-navigation' int…
lklimek Jul 30, 2026
22ee879
fix(identity): route legacy-recovery test fixtures through insert_at/has
lklimek Jul 30, 2026
9c99fe6
Merge remote-tracking branch 'origin/v1.0-dev' into fix/889-key-targe…
lklimek Jul 30, 2026
c48aacd
fix(identity): let a cancelled prompt outrank an earlier placement's …
lklimek Jul 30, 2026
09ead27
fix(identity): settle the persist before calling a pasted key held
lklimek Jul 30, 2026
e289151
fix(identity): let Show and Sign failures carry their own remedy
lklimek Jul 30, 2026
18459fc
fix(identity): let the identities list's Keys popup find a legacy-fil…
lklimek Jul 30, 2026
982f6fb
fix(identity): give the occupied-slot refusal a remedy that exists
lklimek Jul 30, 2026
c9e38c4
refactor(identity): keep the placement helpers on candidates' three-p…
lklimek Jul 30, 2026
d7d765a
docs(identity): true up the design record and mark the triaged residuals
lklimek Jul 30, 2026
905e262
style(identity): apply fmt and clippy polish to the triage follow-up …
lklimek Jul 30, 2026
a880354
style(identity): fix a fmt-check miss left after the triage follow-up
lklimek Jul 30, 2026
9fc99b5
Merge remote-tracking branch 'origin/fix/889-key-target-derivation-co…
lklimek Jul 30, 2026
20b979f
Merge remote-tracking branch 'origin/v1.0-dev' into fix/889-key-resol…
lklimek Jul 30, 2026
dca6916
Merge remote-tracking branch 'origin/fix/889-key-vault-secret-lifecyc…
lklimek Jul 30, 2026
6a904d0
fix(identity): resolve resident key bytes before any placement that p…
lklimek Jul 30, 2026
bc5c2cc
fix(identity): serve a live sibling when Show or Sign names a dead va…
lklimek Jul 30, 2026
4d1755a
fix(identity): word the placement errors for the read path as well as…
lklimek Jul 30, 2026
7e84f84
docs(changelog): note the resident-first resolution and the Show/Sign…
lklimek Jul 30, 2026
e95b6b8
fix(identity): make key paste and removal a locked read-modify-write …
lklimek Jul 30, 2026
0cda98b
fix(identity): stop the Keys popup cloning key material to answer a b…
lklimek Jul 30, 2026
599dd56
feat(identity): list held keys that no on-chain key list publishes
lklimek Jul 30, 2026
31689a9
docs(identity): qualify the design record's pub-surface claim to what…
lklimek Jul 30, 2026
3cf1d15
style(identity): fold the key row's caption pair and apply fmt across…
lklimek Jul 30, 2026
fcdde0f
docs(identity): true up the Show/Sign dispatch notes to the fallthrou…
lklimek Jul 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

### Added

- **Keys saved on this device but not on the identity's key lists are now
listed**: a key can be saved here while appearing on none of the identity's
key lists — for example when adding it to the network did not finish. The
identity's key list now shows such keys in their own section, so they can be
opened and their saved private key removed. Previously nothing could reach
them, even when a message asked exactly that.

- **Restore keys an upgrade left behind**: an identity that was already in the
app before the update — a masternode loaded from its ProTxHash, or one that
held only some of its keys — kept its remaining keys in the previous
Expand Down Expand Up @@ -94,6 +101,75 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

### Fixed

- **A key held in the clear is used without asking for a password**: for a key
an earlier version had saved in two places, one of them password-protected,
using the key could bring up a password prompt even though a copy needing no
password was on this device — and dismissing that prompt then refused the
key outright. The copy that needs no password is now used first, so the
prompt only appears when it is genuinely required.

- **Show and Sign find a key whose first copy is unreadable**: for a key saved
in two places where only one copy's stored bytes were still present —
as after restoring the app's data without its key store — "Show private
key" and "Sign" could fail on the empty copy while the readable one sat
unused. Both now reach whichever copy is actually readable.

- **Showing or signing with a key no longer advises saving it**: pressing
"Show private key" or "Sign" on a key whose place on the identity could not
be worked out answered with advice about saving the key again — about a key
the user never entered. Both messages now name a step either situation can
take: refresh the identity and open the key again.

- **Cancelling a password request is taken as an answer**: for a key an earlier
version had saved in more than one place, dismissing the password prompt
brought up the same prompt again for the same key. Cancelling now ends the
attempt, and the message reflects the cancellation rather than an unrelated
earlier problem with another copy of the key.

- **Messages about a key that cannot be used now say what to do**: being told a
key is not saved on this device, or cannot be saved here, left nowhere to go
next — or worse, named a step that could not work, such as freeing disk space
when the identity's keys are password-protected, or entering a key the same
screen would then refuse. Each of these messages now names the step that
actually resolves its situation.

- **A key that could not be saved no longer looks saved**: when entering a
private key was refused — including when saving it to this device failed —
the key's page still showed it as saved until the page was left and reopened,
offering to reveal it, to sign with it, and to remove it, none of which could
work. The page now reports a refused key as not saved, which is what it is;
likewise, a removal that could not be saved no longer shows the key as
already gone.

- **The identities list sees a key saved by an earlier version**: the Keys
popup on the identities list showed such a key as not saved on this device —
even though it is — and opened the key's page in the same wrong state. The
popup now finds a saved key wherever the version that saved it filed it, as
the rest of the app already does.

- **A key's wallet is found even when the key is filed twice**: a key that an
earlier version had saved in two places, wallet-derived in only one of them,
was treated as belonging to no wallet at all — so the wallet was never offered
for unlocking and signing with that key could not proceed. The wallet that
derives a key is now found wherever the key is filed.

- **A key two lists appear to share can be saved again**: when a masternode's
own record and its voting identity each carried a key with the same number and
the same public key, entering the private key of either was refused with a
message saying the key does not belong to this identity — although it plainly
does, and what the two keys are for is what tells them apart. Such a key is
now saved where it belongs. When a key really is on two lists at once, the
message now says so and what to do about it.

- **Entering a key can no longer erase a different one**: keys of a masternode's
own record and of its voting identity are numbered separately, so two
different keys can carry the same number. Entering the private key of one of
them used to take the other's place without a word, and the replaced key's
private half was gone — with no copy to restore it from if it had been
imported by hand. Dash Evo Tool now refuses that and explains what happened,
leaving the saved key untouched. Re-entering a key you already saved still
replaces itself, as before.

Comment on lines +156 to +172

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Stale caveat elsewhere in the same release now contradicts these entries.

The unchanged "One known limitation" paragraph (around lines 225-233) still tells users that saving or removing a voting key can affect a same-numbered key on a linked voting identity, and points at an "in-progress key-placement resolution fix" — which is this change. Please drop or rewrite that paragraph so the release notes don't warn about the behaviour they also announce as fixed.

🤖 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 `@CHANGELOG.md` around lines 156 - 172, Update the “One known limitation”
paragraph in CHANGELOG.md to remove or rewrite the outdated warning about
same-numbered voting keys and the in-progress key-placement fix. Ensure the
release notes no longer describe the behavior addressed by the entries above as
an unresolved limitation.

- **A saved voting key can now actually sign**: a voting key held on an
identity's own record — rather than on a separate voting identity — was saved
and shown as being on this device, but nothing could use it. Signing looked for
Expand All @@ -107,6 +183,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
key could remove the other's private half, and a key could be reported as
saved on the strength of an unrelated key being present.

- **Removing a key now removes all of it**: "Remove private key" on a key's page
also erases the copy of that key held in this device's secure storage.
Previously only the entry naming it was cleared, so the key itself stayed
behind with nothing pointing at it — it could not be used or brought back, and
deleting the whole identity afterwards did not clear it either. If the secure
storage cannot be written to, the removal now stops and says so with the key
left exactly as it was, so it can simply be tried again.

- **A key is checked before it is used**: showing a saved key or signing with it
now confirms the key held on this device really is the key on screen. Should
the two disagree — records an older version left inconsistent — the action
stops and says so, rather than signing with a key nobody would recognise as
this identity's.

- **An identity's keys are reachable again**: the keys list under an identity's
Settings → Advanced now opens each key's own page, so keys can be inspected
and restored — and, once a key is on this device, signed with or
Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ serde = "1.0.219"
serde_json = "1.0.140"
serde_yaml_ng = { version = "0.10.0" }
tokio = { version = "1.46.1", features = ["full"] }
# Pin is deliberate; do not "fix" the audit warning by bumping. bincode is flagged
# unmaintained (RUSTSEC-2025-0141, INFO-level — no known vulnerability). The advisory
# INTENTIONAL(bincode-unmaintained-pin): the pin is deliberate; do not "fix" the audit
# warning by bumping. bincode is flagged unmaintained (RUSTSEC-2025-0141, INFO-level —
# no known vulnerability). The advisory
# covers *all* versions, so no bump can clear it: 2.0.1 is the last functional release
# and 3.0.0 is a tombstone whose lib.rs is a bare `compile_error!`. This crate encodes
# the on-disk wallet-secret envelopes and QualifiedIdentity blobs, so switching encoders
Expand Down
Loading
Loading